# Methods and :parameters

**URL:** <https://www.ruby-forum.com/t/methods-and-parameters/86802>\
**Category:** Ruby\
**Created:** [February 26, 2007, 2:58am UTC](https://www.ruby-forum.com/t/methods-and-parameters/86802 "2007-02-26T02:58:35Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![pedro](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/919ad9/32.png) [@pedro](https://www.ruby-forum.com/u/pedro)\
**Post date:** [February 26, 2007, 2:58am UTC](https://www.ruby-forum.com/t/methods-and-parameters/86802/1 "2007-02-26T02:58:35Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![pedro](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/919ad9/32.png) [@pedro](https://www.ruby-forum.com/u/pedro)\
**Post date:** [February 26, 2007, 4:11am UTC](https://www.ruby-forum.com/t/methods-and-parameters/86802/2 "2007-02-26T04:11:42Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![pedro](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/919ad9/32.png) [@pedro](https://www.ruby-forum.com/u/pedro)\
**Post date:** [February 26, 2007, 4:13am UTC](https://www.ruby-forum.com/t/methods-and-parameters/86802/3 "2007-02-26T04:13:42Z")

</div>

On 2/26/07, Pedro Del G. [removed\_email\_address@domain.invalid](mailto: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.

---

<div class="post-metadata">

**Author:** ![pedro](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/919ad9/32.png) [@pedro](https://www.ruby-forum.com/u/pedro)\
**Post date:** [February 26, 2007, 2:03pm UTC](https://www.ruby-forum.com/t/methods-and-parameters/86802/4 "2007-02-26T14:03:41Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![pedro](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/919ad9/32.png) [@pedro](https://www.ruby-forum.com/u/pedro)\
**Post date:** [February 26, 2007, 3:13pm UTC](https://www.ruby-forum.com/t/methods-and-parameters/86802/5 "2007-02-26T15:13:49Z")

</div>

From: “Pedro Del G.” [removed\_email\_address@domain.invalid](mailto: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](mailto: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?

---

<div class="post-metadata">

**Author:** ![pedro](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/919ad9/32.png) [@pedro](https://www.ruby-forum.com/u/pedro)\
**Post date:** [February 26, 2007, 6:06am UTC](https://www.ruby-forum.com/t/methods-and-parameters/86802/6 "2007-02-26T06:06:48Z")

</div>

From: “Pedro Del G.” [removed\_email\_address@domain.invalid](mailto: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](mailto: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.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

---

<div class="post-metadata">

**Author:** ![pedro](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/919ad9/32.png) [@pedro](https://www.ruby-forum.com/u/pedro)\
**Post date:** [February 26, 2007, 4:10pm UTC](https://www.ruby-forum.com/t/methods-and-parameters/86802/7 "2007-02-26T16:10:58Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![pedro](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/919ad9/32.png) [@pedro](https://www.ruby-forum.com/u/pedro)\
**Post date:** [February 26, 2007, 6:36pm UTC](https://www.ruby-forum.com/t/methods-and-parameters/86802/8 "2007-02-26T18:36:30Z")

</div>

> Are those OK?

Perfect :). Thanks a lot.

## –

Pedro Del G.

Email : removed\_email\_address@domain.invalid
