Introduction to Ruby, part I April 20, 205 Output # evaluate expression and prints result. >> 4 + 5 => 9 >> 7 * 3 => 2 >> Hello, world! => "Hello, world!" # print text on standard output >> puts Hello, world! Hello, world! 2 Dynamically typed variables >> v = nil # Creates a new variable v on the stack holding # a reference to an instance of NilClass. >> v = 42 # Updates the v variable with a reference to an => 42 # a Fixnum object, with value 42. >> s = Hello # Creates a new variable s on the stack holding a => "Hello" # reference to a String object with value Hello. >> v + s # Invokes the +-method on the Hello String # object referenced by the s variable. This will # raise a TypeError as the String object does not # know how to add a Fixnum to a String. >> v + s # + is invoked on the Fixnum, resulting in a # TypeError as String cannot automaticly be
# converted to Fixnum. >> v.to_s # The to_s-method returns a printable string => "42" # representation of the object. In this case # "42". >> s + v.to_s # Returns the concatenated string "Hello42" => "Hello42" >> s.methods # Returns an array of the methods defined for the => ["upcase!",...] # object referenced by s. >> s, v = v, s # Multiple assignment: Swaps the values of v and s. => [42, "Hello"] 3 Lists >> l = [v, s] # Creates a list(array) containing Hello and 42. => ["Hello", 42] >> l << 3.0 # All kinds of types may be mixed in a list. => ["Hello", 42, 3.0] >> l.pop # Removes and returns the last element in list. => 3.0 # Can pop multiple values, i.e. l.pop(2) returns # a list of the last two elements. >> r =..4 # Creates a new instance of the Range class =>..4 # Useful when looping. x..y is inclusive the # last element, x...y is exclusive. >> l = r.to_a # Creates a new array from the range => [, 2, 3, 4] >> l = l + [5, 6] # Concatenation of lists => [, 2, 3, 4, 5, 6] # Loop over each element in the list l and summarise in sum. >> l.each do element?> the_sum += element # Above loop will crash as the_sum is unassigned, and therefore # considered nil. NameError is raised as nil has no + method. >> the_sum = 0 >> l.each do element 2
?> the_sum += element => [,2,3,4,5,6] # iteration returns the iterated object >> puts the_sum 2 # Alternate loop syntax >> l.each { element the_sum += element } 4 List access and slicing >> lst = [ a, b, c ] # Creates a new list from literal => ["a", "b", "c"] # representation >> lst = Array.new() # Creates a new list by calling => [] # constructor of the Array class # The index method [] takes one or two arguments. # The first is which index to retrieve, negative index means # count backwards from the end of the list. Second argument # is how many consecutive elements to returns as a new list. >> lst[] # Returns b as is the second position in list. => "b" >> lst[-] # Returns the last element of the list. => "c" >> lst[7] # Indexing outside of the list returns nil. # To make sure indexing outside the array results in errors, # one may use fetch instead. >> lst.fetch(7) IndexError: index 7 outside of array bounds: -4...4 from (irb):59:in fetch from (irb):59 from /usr/local/bin/irb:2:in <main> >> lst[,] # Returns a new list containing "b", [start, length]. => ["b"] >> lst[0,3] # Returns 3 elements from index 0, [start, length]. => ["a","b","c"] >> lst.dup # Returns a copy of the list. => ["a", "b", "c"] 3
>> lst.reverse # Returns a copy of the list reversed. ["c", "b", "a"] 5 Associative arrays (Hashes/Dictionaries/Maps?) # Create a new Hash, with unordered mappings. >> h = { one =>, two =>2, three =>3, four =>4 } => {"three"=>3, "two"=>2, "one"=>, "four"=>4} >> h["one"] # Update hash, key "three" refers the same value as # key "four". >> h["three"] = h["four"] => 4 # Print string representation of the contents of the Hash. >> puts h.inspect {"three"=>4, "two"=>2, "one"=>, "four"=>4} >> h.keys => ["three", "two", "one", "four"] >> h.has_key? "four" >> h.has_value? 4 # Is this one of the values? # Iterate over the key/value-pairs and print each. >> h.each { key, value puts "#{key} => #{value}" } three => 4 two => 2 one => four => 4 => {"three"=>4, "two"=>2, "one"=>, "four"=>4} Control Structures, iteration, ranges again # The Ruby if-statement begins with "if" and a conditional (no do) # and ends with "end" >> if nil >> print "nil is true" 4
>> if false >> print "false is true" # "nil" and "false" evaluates to false in Ruby, everything else # (including 0) eveluates to true >> if 0 >> print "0 is true" 0 is true # Only nil and false are false # Logical operators ("and" and "or") can be used to combine # conditionals >> if 0 and [] and {} and >> puts "0 and [] and {} and are true" (irb):5: warning: string literal in condition 0 and [] and {} and are true # If-statements can be combined using "elsif". The "else" clause # will be run if none of the conditionals above evaluated to # true. >> name = "Yukihiro" => "Yukihiro" >> if name == "Yukihiro" >> puts "Ruby" >> elsif name == "Guido" >> puts "Python" >> else?> puts "None of the above" Ruby # "or" and "and" will be evaluated as boolean true/false but # will also always return one of the objects in the expression >> names = { "Yukihiro" => "Ruby",?> "Guido" => "Python",?> } => {"Yukihiro"=>"Ruby", "Guido"=>"Python"} >> puts names[name] or "None of the above" Ruby 5
=> "None of the above" >> puts (names[name] or "None of the above") Ruby >> result = (false or Beatrice or false) => "Beatrice" >> if result >> puts result Beatrice >> result = ( Beatrice and [] and Isak ) => "Isak" >> if result >> puts result Isak # Negation of boolean values is done using "not". >> not false >> (not true) == false # The true and false values are represented by objects, and there # is only one true object and one false object >> (not true) === false >> (not true).object_id == false.object_id # The Ruby while-loop starts with "while" and a conditional and # ends with end >> i = 0 => 0 >> while i < 0 >> puts i >> i += 0. 6
. 8 9 # Several other ways of looping exists, e.g. the "each" iterator # in the Range class. >> lst =..0 =>..0 >> lst.each { i puts i} 2.. 8 9 0 =>..0 # Or a for loop on the range class. >> for i in..4 >> puts i 2 3 4 =>..4 # Below we see an example of operations that we could do with # lists. Using the "zip" method from the Array class we create a # new list containing lists of the elements from the original # lists that were found on the same index. >> cs = [ a, b, c ] => ["a", "b", "c"] >> ns = [,2,3] => [, 2, 3] >> zip = cs.zip(ns) => [["a", ], ["b", 2], ["c", 3]] # The list of lists is looped over using the "each" operator and # the elements of the lists inside the list are printed out. >> zip.each do ch, no?> puts "#{ch} #{no}" 7
a b 2 c 3 => [["a", ], ["b", 2], ["c", 3]] # The "collect" iterator will loop over the list collecting all # elements from the original list for which the conditional in the # code block evaluates to true. In this case, the code block # contains no conditional and all elements will be collected. >> chars = zip.collect { c, n c} => ["A", "b", "c"] >> nums = zip.collect { c, n n} => [, 2, 3] A first simple program # Let s say we have a file named "words.txt" with the following # words stored in it: # alpha # bravo # charlie # delta # echo # foxtrot # golf # hotel # india # juliet # kilo # lima # mike # november # oscar # papa # quebec # romeo # sierra # tango # uniform # victor # whiskey # xray # yankee # zulu 8
# The following code returns a list of words starting with a # (lowercase) vowel. >> matches = [] => [] >> vowels = "aoueiy".chars.to_a => ["a", "o", "u", "e", "i", "y"] >> f = open( words.txt ) => #<File:words.txt> >> f.each do line?> matches << line.strip if vowels.include? line.strip.chars.first => #<File:words.txt> >> matches => ["alpha", "echo", "india", "oscar", "uniform", "yankee"] 9