Forum: Ruby Methods and :parameters

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Pedro D. (Guest)
on 2007-02-26 03:58
(Received via mailing list)
Hi all,

I've a question about the :parameter notation.
I want to write a method that can hold several optional paramters

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"

and i had  write the add_book mehod like this :

class Book
   attr_writer :title, :author
end

def add_book (book )
   puts "title : #{book.title} -- Author : #{book.author}"
end

but the interpreter said : ./bibliom.rb:7:in `add_book': undefined
method `title' for {:title=>"El quijote", :author=>"Miguel de
Cervantes"}:Hash (NoMethodError)

I also try to put a hash object in the incoming parameter, like that :

def add_book (book=[])  .... end

My question is how can i wirte a method with several optional
parameter and then acces they inside of the mehotd ?

Thanks


--
-------------------------------------
Pedro Del G.

Email              :   removed_email_address@domain.invalid
Raj S. (Guest)
on 2007-02-26 05:11
(Received via mailing list)
Pedro Del G. wrote:
> I've a question about the :parameter notation.
> I want to write a method that can hold several optional paramters
>
> 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"
To have a method with optional variables, assign them to nil in the
declaration.  If they aren't included in the method call, they will be
set to nil.

def add_book(title, author = nil, tag = nil)
> but the interpreter said : ./bibliom.rb:7:in `add_book': undefined
> method `title' for {:title=>"El quijote", :author=>"Miguel de
> Cervantes"}:Hash (NoMethodError)
It gives you this error because you are using attr_writer, which is
equivalent to a def attr= method.  In order to simply return a value,
you should use attr_reader, or in case you want both, attr_accessor.

I think what you want is along the lines of:

class Book
    attr_accessor :title, :author, :tag

    def initialize(title, author = nil, tag = nil)
       self.title = title
       self.author = author
       self.tag = tag
    end

    def add_book
       puts "title: #{self.title} -- Author: #{self.author}"
    end
end
Daniel -. (Guest)
on 2007-02-26 05:13
(Received via mailing list)
On 2/26/07, Pedro Del G. <removed_email_address@domain.invalid> wrote:
>
> Hi all,
>
> I've a question about the :parameter notation.
> I want to write a method that can hold several optional paramters
>
> 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"


When you use this kind of argument for a method it is encapulated into
an
anonymous hash.  It's like writing
add_book( { :title=>"El quijote", :author=> "Miguel de Cervantes",
:tag=>"novel" } )


and i had  write the add_book mehod like this :
>
> class Book
>    attr_writer :title, :author
> end
>
> def add_book (book )
>    puts "title : #{book.title} -- Author : #{book.author}"
> end



You've added the attr_writer, but you may want to make it into an

attr_accessor

so that you have both reader and writer


Your add_book should look something like, can't give it to you exactly.
sorri no ruby at work :(

def add_book( book )
  title = book[:title] || nil
  author = book[:author] || nil
  puts "title : #{title} -- Author : #{author}"
end

Since book is an Hash, you need to access it as book[:title].  You need
to
assign the book[:title] given to the book object to its own title, the
one
you made the accessor for.

I must say though that I don't quite understand how you can add_book to
a
book.  I would expect to see this as part of an initialize method
instead.
That way you would write

book = Book.new( :title => 'bla', :author => 'author' )

But that's just me.

but the interpreter said : ./bibliom.rb:7:in `add_book': undefined
> method `title' for {:title=>"El quijote", :author=>"Miguel de
> Cervantes"}:Hash (NoMethodError)
>
> I also try to put a hash object in the incoming parameter, like that :
>
> def add_book (book=[])  .... end


What this does is sets the local variable book, inside the add_book
method
to an empty array by default.  ie if there is no parameter passed then
you
can rely on it being an empty array.
Hidetoshi NAGAI (Guest)
on 2007-02-26 07:06
(Received via mailing list)
From: "Pedro Del G." <removed_email_address@domain.invalid>
Subject: Methods and :parameters
Date: Mon, 26 Feb 2007 10:57:59 +0900
Message-ID:
<removed_email_address@domain.invalid>
> My question is how can i wirte a method with several optional
> parameter and then acces they inside of the mehotd ?

For example,
-------------------------------------------------------------------
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] == ?=
        self[prop[0..-2]] = args[0]
        args[0]
      else
        self[prop] = args[0]
        self
      end
    when 0
      self[prop]
    else
      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

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
Pedro D. (Guest)
on 2007-02-26 15:03
(Received via mailing list)
Wow ... thats exactly what i was looking for :). Can you explain me
how this override of the method_missing works? im a little bit lost
right after the when statament begin ...

>       end
>     when 0
>       self[prop]
>     else
>       super(id, *args)
>     end
>   end
>

Thanks again.

--
-------------------------------------
Pedro Del G.

Email              :   removed_email_address@domain.invalid
Hidetoshi NAGAI (Guest)
on 2007-02-26 16:13
(Received via mailing list)
From: "Pedro Del G." <removed_email_address@domain.invalid>
Subject: Re: Methods and :parameters
Date: Mon, 26 Feb 2007 22:02:56 +0900
Message-ID:
<removed_email_address@domain.invalid>
>  Wow ... thats exactly what i was looking for :). Can you explain me
> how this override of the method_missing works? im a little bit lost
> right after the when statament begin ...
>
> >   def method_missing(id, *args)
              # Expect the unknown method as accessing to a property.
> >     prop = id.id2name
              # Get the method name string.
> >     case args.length
              # Check the number of arguments.
> >     when 1
              # If one argument, it will be a setter method.
> >       if prop[-1] == ?=
              # Is it "<property>="? (e.g. "self.property = val")
              # If so, call "self[<property>] = val".
> >         self[prop[0..-2]] = args[0]
> >         args[0]
> >       else
              # Else it will be "self.property(val)".
              # Then call "self[<property>] = val".
> >         self[prop] = args[0]
> >         self
> >       end
> >     when 0
              # If no argument, it will be a getter method.
> >       self[prop]
> >     else
              # If more than one argument, it will not a setter or
getter.
              # So use "method_missing" of the super class.
> >       super(id, *args)
> >     end
> >   end

Are those OK?
Ken B. (Guest)
on 2007-02-26 17:10
(Received via mailing list)
On Mon, 26 Feb 2007 10:57:59 +0900, Pedro Del G. wrote:

>
> Cervantes"}:Hash (NoMethodError)
>
> I also try to put a hash object in the incoming parameter, like that :
>
> def add_book (book=[])  .... end
>
> My question is how can i wirte a method with several optional parameter
> and then acces they inside of the mehotd ?


def add_book (book )
   puts "title : #{book[:title]} -- Author : #{book[:author]}"
end

When using the named parameter idiom, all of the named parameters are
lumped together into a single hash which is passed as the last
parameter.
There's no point in defining the Book class -- it won't be used by this
idiom.

If you want to access the parameters as members, then you can construct
an OpenStruct inside the method, like so

require 'ostruct'

def add_book book
  book=OpenStruct.new(book)
  puts "title : #{book.title} -- Author : #{book.author}"
end

but that's most likely overkill.
Pedro D. (Guest)
on 2007-02-26 19:36
(Received via mailing list)
> Are those OK?

Perfect :). Thanks a lot.


--
-------------------------------------
Pedro Del G.

Email              :   removed_email_address@domain.invalid
This topic is locked and can not be replied to.