Computer Science Canada

Ruby Questions.

Author:  TokenHerbz [ Sat Dec 04, 2010 6:51 am ]
Post subject:  Ruby Questions.

I'm not fully understanding why i can't compact my block of code thats spread out, into a line...

code:

1.upto(10) {
  |x| print "#{x} "
  if x == 1 or x == 3 or x == 6
    puts
  end
}


I try to put this into one line,
code:

1.upto(10) {|x| print x} #So far so good....  prints it out, but i want that puts to make my numbers ordered better!


code:

1.upto(10) {|x| print "#{x} " if x == 2 puts end} #doesn't matter what i try, with/without end, commas, outsdie the block, it just wont work...


any ideas to why? I don't think i understand ruby's "block" formats yet, explaining it to me would be nice.

Also some other quick questions.

code:

name = gets #this gets "Name\n"
name = gets.chomp #this gets "Name"
name = gets.strip  #What does STRIP do?


I read about ARGF.each, It seems to always be stuck in a loop, and if i try to use gets instead its pretty problematic, I managed to get it to work but it only does it once, how do i get it do it loops only a certain amount of times that i want?


And i keep failing at DO. i cant ever get it to work on my own even tho i read about it, can someone explain how this works?
I need something to use for my loops, figured do would be best.
-------
Also I would love a few simple ideas for me to tackle that strenghtens me ruby skills and knowledge. I picked this up not to long ago, and its really a language i'm going to get into. Tired of turings lack of everything, So this will be my new, dedicated language to learn.

Thanks for help/tips that come. /cheers.

Author:  DtY [ Sat Dec 04, 2010 8:35 am ]
Post subject:  RE:Ruby Questions.

The reason you can't condense that into a single line is that if...end are not blocks, they must have line breaks (I'm pretty sure). There is the alternate inline mode of if, rather than doing
code:
if condition
    dothis
end

You would do:
code:
dothis if condition


If you really want to condense this down to one line, I would suggest using inline if to conditionally insert a newline character.

code:
1.upto(10){|x| print "#{x} #{"\n" if x==1 or x==3 or x==6}"}


Re: blocks
In Ruby, functions are not first class data, so you cannot pass them as arguments to functions or return them from functions. This makes doing a lot of loopy stuff really inconvenient because only the internal control stuff would be possible (if, for, while, loop), whereas other languages have functions that can call other functions over and over and do stuff with it (functions like map, filter, reduce), which makes programming a lot easier. Rather than making functions first class data, Ruby decided to go for another type that it kinda like functions: procs (or procedures). Procedures are like functions, except that you need to call proc#call to execute them, because they're objects.

Ruby blocks are just a special syntax for creating a proc and then passing it directly to a function. This will be familiar if you've done any functional programming.

Re: String#split
gets is a function, so when you call gets.chomp, it will call gets, and then call chomp on the string it returns. This is important to keep in mind when you are looking for information about a method, chomp is not gets' method, it is string's. Split splits a string into an array at a given identifier. More information on String#split

I don't have time to answer your other questions right now, but I will hopefully later today, if no one does before me. I probably did a pretty bad job explaining blocks, so if someone else can elaborate on it, that'd be great.

Author:  jcollins1991 [ Sat Dec 04, 2010 9:17 am ]
Post subject:  Re: Ruby Questions.

You can do a one line if-else, you just need to use THEN (or use the "blah if cond" thing).

Ruby:

a = 1
if a then puts 'good' else puts 'bad' end


If by a do loop you mean do-while, I don't believe Ruby has that. If you want to do something a certain number of times just do

Ruby:

n = 10
n.times do |a|
  puts a
end


Or if you want to do the more familiar loops like while and for check out http://www.tutorialspoint.com/ruby/ruby_loops.htm

If you want to get a good understanding of Ruby I'd suggest reading http://mislav.uniqpath.com/poignant-guide/, it gives a really nice overview and has random yet awesome comics.

Author:  wtd [ Sat Dec 04, 2010 11:13 am ]
Post subject:  Re: Ruby Questions.

jcollins1991 @ Sat Dec 04, 2010 10:17 pm wrote:
You can do a one line if-else, you just need to use THEN (or use the "blah if cond" thing).

Ruby:

a = 1
if a then puts 'good' else puts 'bad' end


If by a do loop you mean do-while, I don't believe Ruby has that.


Why not?

Ruby has this:

code:
something while some_condition


So naturally, we can replace something with some block of code.:

code:
begin .... end while some_condition

Author:  wtd [ Sat Dec 04, 2010 11:16 am ]
Post subject:  Re: Ruby Questions.

TokenHerbz @ Sat Dec 04, 2010 7:51 pm wrote:
I'm not fully understanding why i can't compact my block of code thats spread out, into a line...

code:

1.upto(10) {
  |x| print "#{x} "
  if x == 1 or x == 3 or x == 6
    puts
  end
}


The semi-colon ninja strikes again!

code:
1.upto(10) { |x| print "#{x} "; if x == 1 or x == 3 or x == 6 then puts end }

Author:  wtd [ Sat Dec 04, 2010 11:20 am ]
Post subject:  RE:Ruby Questions.

Also...

code:
puts (1..10).collect { |x| case x when 1,3,6 then "#{x}\n" else "#{x} " end }.join

Author:  TokenHerbz [ Sat Dec 04, 2010 12:46 pm ]
Post subject:  RE:Ruby Questions.

could you explain collect and join.

i know case is a simplar if/elseif/else thing.

Author:  wtd [ Sat Dec 04, 2010 12:51 pm ]
Post subject:  RE:Ruby Questions.

code:
irb(main):248:0> (1..10).collect { |x| case x when 1,3,6 then "#{x}\n" else "#{x} " end }
=> ["#x\n", "2 ", "#x\n", "4 ", "5 ", "#x\n", "7 ", "8 ", "9 ", "10 "]

Author:  jcollins1991 [ Sat Dec 04, 2010 12:52 pm ]
Post subject:  Re: RE:Ruby Questions.

TokenHerbz @ Sat Dec 04, 2010 12:46 pm wrote:
could you explain collect and join.

i know case is a simplar if/elseif/else thing.


Collect goes through each element of an array and returns an item in the same spot with whatever you return in the block. In your case, it'd return an array of elements that are either "#{x}\n" or "#{x}" (with proper numbers in of course). Then join is just a simple function that takes an array and joins the elements into a string.

Author:  TokenHerbz [ Sat Dec 04, 2010 12:55 pm ]
Post subject:  RE:Ruby Questions.

awesome

Author:  Insectoid [ Sat Dec 04, 2010 12:59 pm ]
Post subject:  RE:Ruby Questions.

collect runs the block and returns an array of the output.

ie ["a", "b", "c"].collect {|x| x+"!"} returns ["a!", "b!", "c!"]

join converts an array to a string.

So, what wtd's code is doing is creating an array of #{x}'s and #{x}\n's, then converting it to a string, then printing it.

EDIT: Damn.

For future reference.

Author:  TokenHerbz [ Sun Dec 05, 2010 9:28 am ]
Post subject:  RE:Ruby Questions.

Continuation:

In Turing your able to get a users input and change the output as the user types, example would be collecting the string "TESTERS" and having the program output a "*******" per char the user types.

the gets in ruby seems pretty limiting to that aspect since i always see what im typing, unless there is some hidden ".replace" thing i cant find on the internet.

Thanks! I'm trying to get a "password" program creator thinggy going, and its problematic to see the password being typed in this case...

Author:  Insectoid [ Sun Dec 05, 2010 9:43 am ]
Post subject:  RE:Ruby Questions.

You might try googling around a bit.

Author:  TokenHerbz [ Sun Dec 05, 2010 9:57 am ]
Post subject:  RE:Ruby Questions.

I'd prefer the answer without a library or gem to add and use. I want to know how to do it raw. thx for links tho.

Edit to Add: Iv'e been googleing hard!

Author:  jcollins1991 [ Sun Dec 05, 2010 10:29 am ]
Post subject:  Re: Ruby Questions.

Well if you're just using the command line I'm not sure if there's anything you can do. I'm sure Turing must be using their own proprietary stuff for user input so you can do stuff like that, with Ruby you're using whatever your operating system offers (command prompt, x11, etc) so you don't have as much freedom. Also, try actually reading through the libraries Insectoid offered you, they have perfectly good (and easily readable) source code you can read if they happen to have the features you're looking for.

Author:  Tony [ Sun Dec 05, 2010 6:11 pm ]
Post subject:  RE:Ruby Questions.

Turing's "no echo" is build in; Ruby could run in many different terminals, so it's a bit more work to set up the right config options. The libraries do that, and you should take a look at their source to see what exactly they do.

Author:  TokenHerbz [ Mon Dec 06, 2010 4:49 am ]
Post subject:  Re: Ruby Questions.

Continuation of Questions: AGAIN! (cause i don't wanna spam making new posts)

I have a peice of code that gets a string from user, and then it changes the strings vowels to "*" and numbers to "#".
however, in order for it to work, this has to be changed into an array, and i have to check each element of the array, and change it one by one.

In my example, here ill post to show you.

code:

def getName
  puts "Please enter your name: " #for ex put "Derek523" for both voul/numbers
  result = gets.chomp #users input
end
name = getName

def removeVowels (name_) #gets name
  if name_ =~ /a|e|i|o|u/ #if name (all of it) has a voul
    name_ = name_.sub(/a|e|i|o|u/, "*") #we replace that voul
  end
  return name_  #only replaces ONE voul tho,does it have to be array to check?
end

name = removeVowels(name) #only changes one vowel?
puts name #test and see

def removeNumbers (name_) #test 2, we get the name
  x = 0 #counter set to zero, don't know how to loop in ruby without it
  name_ = name_.split(//) #name_ turn into an array
  while x <= name_.length #this loops threw our array
    if name_[x] =~ /1|2|3|4|5|6|7|8|9|0/ #check for numbers
      name_[x] = name_[x].sub(/1|2|3|4|5|6|7|8|9|0/, "#") #replace our numbers
    end
    x += 1 #move threw the array
  end
  return name_.join #returns to us our modified array .join to make it string
end

name = removeNumbers(name) #the test works
puts name


My questions is: Does the =~ check the whole string for a match, or does it just skip down when it finds the first match. and also, Why doesn't the .sub (vowels, "*") work in a string. I would think it should look at the whole string and sub everything in that string but it seems to only do the first one it comes across, and im forced to change everything by makeing my string an array and doing it like the "numbers" in my example.

A few more questions to my example. I know theres gotta be a better way then to use my loop in there, but could you recommend me one to use, or maybe a read on it. All the reads i come across isn't clear at explaining how things work, Such as do.

furthermore, i try to create a variable out of existance such as |x| to use as a counter, but it never works, does such a variable need to be set with a value? |x=0| doesn't work, nor makes sense to have that in a code resetting the counter so im at a loss with such things, where im also unable to find a good read on it. I see examples of codes without explinations on how and why it works, And would love someone like wtd or other knowledgable person to explain. thanks. //ALSO, does the YEILD work just like return?


EDIT TO ADD: I was testing around with sub and i came across something i dont get. Using the .sub inside an if works but it doesn't work outside the if. why? I would think the if only directs a path to the .sub, but the path isn't really needed since if the .sub isn't meeting a requirement to change a letter, then it wouldn't change anything and move on, or am i wrong? the example is below, it wont work without the if statement, and i would think it should since if letter doesn't = the sub requirments its just ignored.
code:

puts ("Enter a string of letters/numbers and i'll make magic!")
myString = gets.chomp.split(//) #array of chars
x = 0
while x <= myString.length #0 up to upper array length
  if myString[x] =~ (/1|2|3|4|5|6|7|8|9|0|a|e|i|o|u|/) #does ruby really need this to sub???
    myString[x] = myString[x].sub(/a|e|i|o|u/, "*") #cant call SUB without the if =~? statement
    myString[x] = myString[x].sub(/0|1|2|3|4|5|6|7|8|9/, "#") #will error, but why???
  end
  x += 1
end
myString.join
puts "Magic Complete: #{myString}"

Author:  Insectoid [ Mon Dec 06, 2010 9:04 am ]
Post subject:  RE:Ruby Questions.

You could use an each loop to go over the string and add that letter (modified or no) to an array.

string.each do {|i| #stuff }

|x| is used in blocks to pass a parameter in. If you run an each loop, it pass each element of the array/list/string/etc. into the block. Similarly,

n.times do {|n| } will act as a for loop, passing incrementing values up to n into the block. If you want a regular for loop similar to Java or C, Ruby supports that syntax as well (though it's very rarely used).

Author:  TokenHerbz [ Mon Dec 06, 2010 10:55 am ]
Post subject:  RE:Ruby Questions.

Thanks, FYI (for wtd or someone) i have questions on above posts still to be answered...

And some new ones here.... WITH FREAKING RAND!

so i really try not to compare turing with ruby but i think im fixated on turing "Rand.Int(x,y)" crap... cause....

ruby "num = rand(x)" works good right, But I want a number between x and y.. and that for some reason, seems really problematic....

code:

num = [rand(10) .. rand(15)]
#get 2 numbers, 1 range 0-9 // 2 range 0-14
num = {rand(10), rand(15)}
#get 1 number range 02 -- 913 on tests -WTF?
num = (rand(5),rand(10)) #ERRORS
num = (rand(5) .. rand(10))
#puts 2 numbers x .. y range within numbers
# so i failed at making a random number from #value X to value Y sigh


As you can see, the results i expected to see are non existant... I can maybe get where ruby's coming from with the x .. y using 2 values, but i havn't a clue how it outputs a freaking 913 on the first code you see there..

Anyways i've been unsuccessful at obchieveing my results even tho i can read from this what seems to be simple.

***the READ:***
rand rand( max=0 ) -> aNumber
Converts max to an integer using max1 = max.to_i.abs. If the result is zero, returns a pseudorandom floating point number greater than or equal to 0.0 and less than 1.0. Otherwise, returns a pseudorandom integer greater than or equal to zero and less than max1. Kernel::srand may be used to ensure repeatable sequences of random numbers between different runs of the program.

Author:  jcollins1991 [ Mon Dec 06, 2010 11:32 am ]
Post subject:  Re: Ruby Questions.

Assuming x < y:

Ruby:
rand(y - x + 1) + x


+ 1 so you get x -> y endpoints inclusive

Author:  Insectoid [ Mon Dec 06, 2010 12:02 pm ]
Post subject:  RE:Ruby Questions.

Alternatively (and this can be used in almost any language) you can use

code:

rand(2)*(a-b)+b


This does not rely on knowing that a < b.

Since rand(2) returns 0 or 1, you can apply math to that function to return one of any 2 numbers.

ie, to return either 5 or 8,
0*(5-8)=0, 0+8 = 8
1*(5-8)=-3, -3+8 = 5

Often basic math is better than complicated algorithms. It just requires a different way of thinking.

Author:  wtd [ Mon Dec 06, 2010 12:53 pm ]
Post subject:  Re: Ruby Questions.

TokenHerbz @ Mon Dec 06, 2010 5:49 pm wrote:
code:

puts ("Enter a string of letters/numbers and i'll make magic!")
myString = gets.chomp.split(//) #array of chars
x = 0
while x <= myString.length #0 up to upper array length
  if myString[x] =~ (/1|2|3|4|5|6|7|8|9|0|a|e|i|o|u|/) #does ruby really need this to sub???
    myString[x] = myString[x].sub(/a|e|i|o|u/, "*") #cant call SUB without the if =~? statement
    myString[x] = myString[x].sub(/0|1|2|3|4|5|6|7|8|9/, "#") #will error, but why???
  end
  x += 1
end
myString.join
puts "Magic Complete: #{myString}"


This is making my eyes bleed.

What's wrong with the following?

Ruby:
puts "Enter a string of letters/numbers and i'll make magic!"

my_string = gets.chomp
my_string.gsub! /[aeiou]/, '*'
my_string.gsub! /\d/, '#'

puts "Magic Complete: #{my_string}"

Author:  TokenHerbz [ Mon Dec 06, 2010 1:22 pm ]
Post subject:  RE:Ruby Questions.

ooohh awesome, yeah i guess that '!' rewrites it eh. i gotta remember that.

why do you use .gsub over .sub dont they do the same thing?

Author:  jcollins1991 [ Mon Dec 06, 2010 1:31 pm ]
Post subject:  Re: RE:Ruby Questions.

TokenHerbz @ Mon Dec 06, 2010 1:22 pm wrote:
ooohh awesome, yeah i guess that '!' rewrites it eh. i gotta remember that.

why do you use .gsub over .sub dont they do the same thing?


Have you bothered googling anything before posting questions here? First response from google: http://ruby.about.com/od/advancedruby/a/gsub.htm

Quote:
Whereas sub only replaces the first instance, gsub method replaces every instance of the pattern with the replacement. In addition, both sub and gsub have sub! and gsub! counterparts. Remember, methods in Ruby that end in an exclamation point alter the variable in place, instead of returning a modified copy.


Note not all functions have a "!" counterpart.

Author:  TokenHerbz [ Mon Dec 06, 2010 1:49 pm ]
Post subject:  RE:Ruby Questions.

yes i google that i must of missed. i got lots of info reading threw it but sometimes the definitions i come across arn't very clear and the examples are to say the least, pitiful...

Author:  Tony [ Mon Dec 06, 2010 4:01 pm ]
Post subject:  RE:Ruby Questions.

And you can also concat it all together
Ruby:

puts "Enter a string of letters/numbers and i'll make magic!"
puts "Magic Complete: #{gets.chomp.gsub(/[aeiou]/, '*').gsub(/\d/, '#')}"


Note that since we are not persisting the result, we're using #gsub instead of #gsub!

Author:  TokenHerbz [ Thu Dec 09, 2010 12:26 pm ]
Post subject:  Re: Ruby Questions.

ANOTHER QUESTION!: (I figured I would post it here so the forums aren't spammed.

Arrays!: The 2D kind...


So I been playing with the arrays a lot and trying to use it as a 2D array, I don't get it.. To me it makes perfect sense and i can't find anything about even decalaring a 2D array like Turing, so easy right, array 1 .. x 1 .. y and use it as array(x,y) // But hmm, A little help on this? I been googling like crazy to and im starting to think there is no 2D arrays...
Ruby:

ROWS, COLUMNS = 5, 5  #constants for the 2D array.
MINE_PERCENTAGE = 0.10 #10% for mine spawn

mine_tile = Array.new(ROWS) {Array.new(COLUMNS)}#2D array
#array name = array.new 5 values of (new array with 5 values) 1 array space should have 5 values?
mine_amount = (MINE_PERCENTAGE * (ROWS * COLUMNS)).round #amount of mines to be used

#init the array with '*' FOR MINES or '.' FOR EMPTY SPACE
0.upto(ROWS) {|rows| 0.upto(COLUMNS){|columns| mine_tile[rows][columns] = "."}}
#we want to add the correct amount of mines randomly into our 2D array.
0.upto(mine_amount){|mines| mine_tile[rand(ROWS)][rand(COLUMNS)] = "*"}
#Code doesn't RUN? array should have values and everything looks right...

Author:  wtd [ Thu Dec 09, 2010 1:29 pm ]
Post subject:  RE:Ruby Questions.

There's no specific 2D array type. You can have an array of arrays, though.

Or, you could create your own class to accomplish the same.

code:
class Array2D
   # ...

   def [](x, y)
      # ...
   end
end


: