def hello $greeted += 1 # in Ruby, a variable beginning with $ is global (can be any type of course) puts "hi there!" end # We need to initialize $greeted before it can be used, because "+=" is waiting a Numeric object $greeted = 0 hello # note that appending () is optional to function calls with no parameters |
# In Ruby, parameters are named anyway def hypotenuse(side1, side2) Math.sqrt(side1**2 + side2**2) # the sqrt function comes from the Math module end diag = hypotenuse(3, 4) puts hypotenuse(3, 4) a = [3, 4] print hypotenuse(*a) # the star operator will magically convert an Array into a "tuple" both = men + women # In Ruby, all objects are references, so the same problem arises; we then return a new object nums = [1.4, 3.5, 6.7] def int_all(n) n.collect { |v| v.to_i } end ints = int_all(nums) nums = [1.4, 3.5, 6.7] def trunc_em(n) n.collect! { |v| v.to_i } # the bang-version of collect modifies the object end trunc_em(nums) # Ruby has two chomp version: # ``chomp'' chomps the record separator and returns what's expected # ``chomp!'' does the same but also modifies the parameter object |
def somefunc variable = something # variable is local by default end name, age = ARGV start = fetch_time a, b = pair # will succeed if pair is an Array object (like ARGV is) c = fetch_time # In ruby, run_check can't access a, b, or c until they are # explicitely defined global (using leading $), even if they are # both defined in the same scope def check_x(x) y = "whatever" run_check if $condition puts "got $x" end end # The following will keep a reference to the array, though the # results will be slightly different from perl: the last element # of $global_array will be itself an array def save_array(ary) $global_array << ary end # The following gives the same results as in Perl for $global_array, # though it doesn't illustrate anymore the way to keep a reference # to an object: $global_array is extended with the elements of ary def save_array(ary) $global_array += ary end |
# In Ruby, AFAIK a method cannot access "local variables" defined # upper scope; mostly because everything is an object, so you'll # do the same by defining an attribute or a static attribute # In Ruby the BEGIN also exists: BEGIN { puts "hello from BEGIN" } puts "hello from main" BEGIN { puts "hello from 2nd BEGIN" } # gives: # hello from BEGIN # hello from 2nd BEGIN # hello from main # In Ruby, it can be written as a static method and a static # variable class Counter @@counter = 0 def Counter.next_counter; @@counter += 1; end end # There is no need of BEGIN since the variable will get # initialized when parsing class Counter @@counter = 42 def Counter.next_counter; @@counter += 1; end def Counter.prev_counter; @@counter -= 1; end end |
# You can either get the whole trace as an array of strings, each # string telling which file, line and method is calling: caller # ...or only the last caller caller[0] # We need to extract just the method name of the backtrace: def whoami; caller()[0] =~ /in `([^']+)'/ ? $1 : '(anonymous)'; end def whowasi; caller()[1] =~ /in `([^']+)'/ ? $1 : '(anonymous)'; end |
# In Ruby, every value is a reference on an object, thus there is # no such problem array_diff(array1, array2) def add_vecpair(a1, a2) results = [] a1.each_index { |i| results << (a1[i] + a2[i]) } results end a = [1, 2] b = [5, 8] c = add_vecpair(a, b) p c # Add this to the beginning of the function to check if we were # given two arrays a1.type == Array && a2.type == Array or raise "usage: add_vecpair array1 array2 (was used with: #{a1.type} #{a2.type})" |
# There is no return context in Ruby |
# Like in Perl, we need to fake with a hash, but it's dirty :-( def thefunc(param_args) args = { 'INCREMENT' => '10s', 'FINISH' => '0', 'START' => 0 } args.update(param_args) if (args['INCREMENT'] =~ /m$/ ) # ..... end end thefunc({ 'INCREMENT' => '20s', 'START' => '+5m', 'FINISH' => '+30m' }) thefunc({}) |
# there is no "undef" direct equivalent but there is the slice equiv: a, c = func.indexes(0, 2) |
# Ruby has no such limitation: def somefunc ary = [] hash = {} # ... return ary, hash end arr, dict = somefunc array_of_hashes = fn h1, h2, h3 = fn |
return # or (equivalent) return nil |
# You can't prototype in Ruby regarding types :-( # Though, you can force the number of arguments: def func_with_no_arg; end def func_with_no_arg(); end def func_with_one_arg(a1); end def func_with_two_args(a1, a2); end def func_with_any_number_of_args(*args); end |
raise "some message" # raise exception begin val = func rescue Exception => msg $stderr.puts "func raised an exception: #{msg}" end # In Ruby the rescue statement uses an exception class, every # exception which is not matched is still continuing begin val = func rescue FullMoonError ... end |
# Saving Global Values # Of course we can just save the value and restore it later: def print_age puts "Age is #{$age}" end $age = 18 # global variable print_age() if condition safeage = $age $age = 23 print_age() $age = safeage end # We can also use a method that saves the global variable and # restores it automatically when the block is left: def local(var) eval("save = #{var.id2name}") begin result = yield ensure # we want to call this even if we got an exception eval("#{var.id2name} = save") end result end condition = true $age = 18 print_age() if condition local(:$age) { $age = 23 print_age() } end print_age() # There is no need to use local() for filehandles or directory # handles in ruby because filehandles are normal objects. |
# In Ruby you may redefine a method [but not overload it :-(] # just by defining again with the same name. def foo; puts 'foo'; end def foo; puts 'bar'; end foo #=> bar # You can also take a reference to an existing method before # redefining a new one, using the `alias' keyword def foo; puts 'foo'; end alias foo_orig foo def foo; puts 'bar'; end foo_orig foo #=> foo #=> bar # AFAIK, there is no direct way to create a new method whose name # comes from a variable, so use "eval" colors = %w(red blue green yellow orange purple violet) colors.each { |c| eval <<-EOS def #{c}(*a) "<FONT COLOR='#{c}'>" + a.to_s + "</FONT>" end EOS } |
def method_missing(name, *args) "<FONT COLOR='#{name}'>" + args.join(' ') + "</FONT>" end puts chartreuse("stuff") |
def outer(arg) x = arg + 35 inner = proc { x * 19 } x + inner.call() end |
#!/usr/bin/ruby -w # mailsort - sort mbox by different criteria require 'English' require 'Date' # Objects of class Mail represent a single mail. class Mail attr_accessor :no attr_accessor :subject attr_accessor :fulltext attr_accessor :date def initialize @fulltext = "" @subject = "" end def append(para) @fulltext << para end # this is called if you call puts(mail) def to_s @fulltext end end # represents a list of mails. class Mailbox < Array Subjectpattern = Regexp.new('Subject:\s*(?:Re:\s*)*(.*)\n') Datepattern = Regexp.new('Date:\s*(.*)\n') # reads mails from open file and stores them def read(file) $INPUT_RECORD_SEPARATOR = '' # paragraph reads msgno = -1 file.each { |para| if para =~ /^From/ mail = Mail.new mail.no = (msgno += 1) md = Subjectpattern.match(para) if md mail.subject = md[1] end md = Datepattern.match(para) if md mail.date = DateTime.parse(md[1]) else mail.date = DateTime.now end self.push(mail) end mail.append(para) if mail } end def sort_by_subject_and_no self.sort_by { |m| [m.subject, m.no] } end # sorts by a list of attributs of mail, given as symbols def sort_by_attributs(*attrs) # you can sort an Enumerable by an array of # values, they would be compared # from ary[0] to ary[n]t, say: # ['b',1] > ['a',10] > ['a',9] self.sort_by { |elem| attrs.map { |attr| elem.send(attr) } } end end mailbox = Mailbox.new mailbox.read(ARGF) # print only subjects sorted by subject and number for m in mailbox.sort_by_subject_and_no puts(m.subject) end # print complete mails sorted by date, then subject, then number for m in mailbox.sort_by_attributs(:date, :subject) puts(m) end |