Variable/optional parameter methods, symbols and ruby

First if you want only for optional parameter in a method, just see the next two examples :

 

 

def foo(bar=:hello)
  puts bar
end

foo     #=> hello
foo bye #=> bye

The second example :

 

 

def add_book(title=>"no title")
  arg={:, :author=>"anonymous", :language=>"esperanto"}
  arg.merge! p_argirb(main):020:1>
end

add_book :title=>"El Qujote", :author=>"Miguel De Cervantes", :language=>"spanish"
=> {:language=>"spanish", :title=>"El Qujote", :author=>"Miguel De Cervantes"}

add_book :title=>"El Qujote", :author=>"Miguel De Cervantes"
=> {:language=>"esperanto", :title=>"El Qujote", :author=>"Miguel De Cervantes"}

add_book :title=>"El Qujote", :author=>"Miguel De Cervantes" :foo=>:Bar
=> {:language=>"esperanto", :title=>"El Qujote", :author=>"Miguel De Cervantes"}

Sometimes is usefull to have an optional/variable parameters method, . In a recent domain specific languages (DSL) design i have to implement a object that have some optional parameters.

For example we want to add a book to our database, But we don’t want to write every single attribute, is the attribute is not present then is initialize with a default value. The properties are

add_book :title=>"El quijote", :author=> "Miguel de Cervantes"
add_book :title=>"El quijote", :author=> "Miguel de Cervantes", :tag=>"novel"
add_book :title=>"El quijote"
add_book :title=>"hogehoge", :language=>"Japanese" # => raise ArgumentError

Asking in the ruby list, Hidetoshi NAGAI, teach me how to use symbols, variable parameter methods (varargs), to create this clean example. The main idea is use a hash for parameter value preinitializate and check is the parameter is in the list. BTW, he also override the method_missing method to emulate all the getters and setters for the object.

 

 

class Book
  def initialize(properties = {})
      @props = {
          'title' => '',
          'author' => '',
          'tag' => nil,
          'price' => nil,
          'ISBN' => nil,
      }

      properties.each{|k, v|
          k = k.to_s
          raise ArgumentError, "unknown property: #{k}" unless @props.key?(k)
          @props[k] = v
      }
  end

  def method_missing(id, *args)
      prop = id.id2name
      case args.length
      when 1

          if prop[-1] == ?= # it will be a setter
              self[prop[0..-2]] = args[0]
              args[0]
          else # Else it will be "self.property(val)".
                                  # Then call "self[] = val"
              self[prop] = args[0]
              self
          end
      when 0 # the getter
          self[prop]
      else #continue the search
          super(id, *args)
      end
  end

  def [](prop)
      prop = prop.to_s
      raise ArgumentError, "unknown property: #{prop}" unless @props.key?(prop)
      @props[prop]
  end

  def []=(prop, val)
      prop = prop.to_s
      raise ArgumentError, "unknown property: #{prop}" unless @props.key?(prop)
      @props[prop] = val
  end
end

def add_book(props)
  book = Book.new(props)
  puts "case1: title : #{book.title} -- Author : #{book.author}"
  puts "case2: title : #{book[:title]} -- Author : #{book[:author]}"
  puts "case3: title : #{book['title']} -- Author : #{book['author']}"
  book
end

In a next post i explain ho to to improve the optinal parameter using meta-programming.

Advertisements

1 comment so far

  1. anonymous on

    thanks, this was helpful today 😉


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: