Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Ruby (http://www.velocityreviews.com/forums/f66-ruby.html)
-   -   passing a method (http://www.velocityreviews.com/forums/t823505-passing-a-method.html)

Wybo Dekker 08-10-2005 10:05 AM

passing a method
 
I want to make a method which can execute another method given to it as
an argument. The following works but the call doesn't look elegant - is
it the ruby way?

wybo>cat test.rb
#!/usr/bin/env ruby
@t = ''
def bye
@t << 'bye'
end
def hello
@t << 'hello'
end
def doit(f)
f.call
end
doit(method(:hello))
doit(method(:bye))
doit(method(:hello))
puts @t
wybo>ruby test.rb
hellobyehello
wybo>

--
Wybo




Daniel Brockman 08-10-2005 10:48 AM

Re: passing a method
 
Hi Wybo,

> I want to make a method which can execute another method
> given to it as an argument.


Why do you want to do this?

> The following works but the call doesn't look elegant -
> is it the ruby way?


It's difficult to tell based on your contrived example,
but the Ruby way would probably be more like this:

def doit
yield
end

doit { hello }
doit { bye }
doit { hello }

You can write `doit { hello }' as `doit &method(:hello)'
if you really want to, but the general block syntax is
obviously much more flexible.

> wybo>cat test.rb
> #!/usr/bin/env ruby
> @t = ''
> def bye
> @t << 'bye'
> end
> def hello
> @t << 'hello'
> end
> def doit(f)
> f.call
> end
> doit(method(:hello))
> doit(method(:bye))
> doit(method(:hello))


This is a rather poor example, since the above three lines
could just as well be written like this:

hello
bye
hello

> puts @t
> wybo>ruby test.rb
> hellobyehello
> wybo>


--
Daniel Brockman <daniel@brockman.se>

So really, we all have to ask ourselves:
Am I waiting for RMS to do this? --TTN.




Devin Mullins 08-10-2005 10:55 AM

Re: passing a method
 
Wybo Dekker wrote:

> I want to make a method which can execute another method given to it as
> an argument. The following works but the call doesn't look elegant - is
> it the ruby way?


Since all your methods are on the same object, there's a simpler way:

C:\>ruby
@t = ''
def bye
@t << 'bye'
end
def hello
@t << 'hello'
end
def doit(f)
send f #ri Object#send
end
doit :hello
doit :bye
doit :hello
puts @t
^D
hellobyebello
C:\>

You could also try passing blocks:

C:\>ruby
@t = ''
def bye
@t << 'bye'
end
def hello
@t << 'hello'
end
def doit
yield
end
doit { hello }
doit { bye }
doit { hello }
puts @t
^D
hellobyebello
C:\>

Or modules/classes:

C:\>ruby
module Bye
def self.greet(t)
t << 'bye'
end
end
class Hello
def self.greet(t)
t << 'hello'
end
end
@t = ''
def doit(c)
c.greet @t
end
doit Hello
doit Bye
doit Hello
puts @t
^D
hellobyehello
C:\>

Longer, but maybe more elegant? Meh, I like the first one best.

Devin




Patrick Gundlach 08-10-2005 10:55 AM

Re: passing a method
 
Hello Wybo,

what about

@t = ''
def bye
@t << 'bye'
end
def hello
@t << 'hello'
end
def doit(f)
send f
end
doit(:hello)
doit(:bye)
doit(:hello)
puts @t

?

Patrick

David A. Black 08-10-2005 11:28 AM

Re: passing a method
 
Hi --

On Wed, 10 Aug 2005, Wybo Dekker wrote:

> I want to make a method which can execute another method given to it as
> an argument. The following works but the call doesn't look elegant - is
> it the ruby way?
>
> wybo>cat test.rb
> #!/usr/bin/env ruby
> @t = ''
> def bye
> @t << 'bye'
> end
> def hello
> @t << 'hello'
> end
> def doit(f)
> f.call
> end
> doit(method(:hello))
> doit(method(:bye))
> doit(method(:hello))
> puts @t
> wybo>ruby test.rb
> hellobyehello
> wybo>


Have you looked into the 'send' method?

str = "a string"
array = str.send(:split, //)
p array # => ["a", " ", "s", "t", "r", "i", "n", "g"]

The first argument is the method name; args 2+ are the args to the
method. You can use strings as well as symbols for the method name.


David

--
David A. Black
dblack@wobblini.net



Wybo Dekker 08-10-2005 11:46 AM

Re: passing a method
 
Patrick Gundlach and Devin Mullans wrote:

> @t = ''
> def bye
> @t << 'bye'
> end
> def hello
> @t << 'hello'
> end
> def doit(f)
> send f
> end
> doit(:hello)
> doit(:bye)
> doit(:hello)
> puts @t


That's exactly what I needed. Thanks!

As for daniel's question:

> Why do you want to do this?


and

> This is a rather poor example, since the above three lines
> could just as well be written like this:


> hello
> bye
> hello


Of course, that's because an exmaple should be short.
My actual code is an initializer for my scripts. I find myself all the
time re-inserting, in many scripts, code to test if executables are
available, code to read rc-files, to handle options, and more. I want to
put most of that stuff in a module which now contains an init method
using the above suggestion (for the last argument):

# program initializer:
# 1. check if all needed executables (in _needed_) are available
# 2. set the defaults (values of _defaults_) for
# option- and rc-variables (keys of _defaults_)
# 3. read the standard rc-files
# 4. handle the options, as defined in the _optionproc_ method
# 5. if @rc appears to be defined, read it as an rc-file

def init(needed,defaults,option_handler)
@rcfiles = [] # collect names for a report in case @verbose is true

# set defaults:
defaults.each do |k,v|
eval("@#{k} = #{v || 'nil'}")
end

# check if all needed executables (in _needed_) are available
check_execs(needed)

# run all standard rc-files
read_rc_files(defaults.keys)

# handle options
send option_handler

# in case a --rc option was used, read its argument as an rc-file:
read_rc_file(@rc,defaults.keys)

# if the --verbose option was used, report rc-files read:
if @verbose
if @rcfiles.size > 0
puts "These rc files were read:",@rcfiles.join("\n")
else
puts "No rc files were read"
end
end
end

--
Wybo




Robert Klemme 08-10-2005 12:01 PM

Re: passing a method
 
Wybo Dekker wrote:
> Patrick Gundlach and Devin Mullans wrote:
>
> > @t = ''
> > def bye
> > @t << 'bye'
> > end
> > def hello
> > @t << 'hello'
> > end
> > def doit(f)
> > send f
> > end
> > doit(:hello)
> > doit(:bye)
> > doit(:hello)
> > puts @t

>
> That's exactly what I needed. Thanks!
>
> As for daniel's question:
>
> > Why do you want to do this?

>
> and
>
> > This is a rather poor example, since the above three lines
> > could just as well be written like this:

>
> > hello
> > bye
> > hello

>
> Of course, that's because an exmaple should be short.
> My actual code is an initializer for my scripts. I find myself all the
> time re-inserting, in many scripts, code to test if executables are
> available, code to read rc-files, to handle options, and more. I want
> to put most of that stuff in a module which now contains an init
> method using the above suggestion (for the last argument):
>
> # program initializer:
> # 1. check if all needed executables (in _needed_) are available
> # 2. set the defaults (values of _defaults_) for
> # option- and rc-variables (keys of _defaults_)
> # 3. read the standard rc-files
> # 4. handle the options, as defined in the _optionproc_ method
> # 5. if @rc appears to be defined, read it as an rc-file
>
> def init(needed,defaults,option_handler)
> @rcfiles = [] # collect names for a report in case @verbose is true
>
> # set defaults:
> defaults.each do |k,v|
> eval("@#{k} = #{v || 'nil'}")
> end
>
> # check if all needed executables (in _needed_) are available
> check_execs(needed)
>
> # run all standard rc-files
> read_rc_files(defaults.keys)
>
> # handle options
> send option_handler
>
> # in case a --rc option was used, read its argument as an rc-file:
> read_rc_file(@rc,defaults.keys)
>
> # if the --verbose option was used, report rc-files read:
> if @verbose
> if @rcfiles.size > 0
> puts "These rc files were read:",@rcfiles.join("\n")
> else
> puts "No rc files were read"
> end
> end
> end


IMHO a superior solution would be to use a block instead of argument
option_handler. AFAICS you have only one such callback and that's exactly
what blocks are for. If you want access to the current instance you can
use instance_eval:

def init(needed,defaults,&option_handler)
....
# handle options
instance_eval &option_handler
....
end

Also, for setting instance variables, this idiom is better (because it
avoids evil eval and you don't need special handling of nil):

defaults.each {|k,v| instance_variable_set("@#{k}", v)}

Kind regards

robert


David A. Black 08-10-2005 12:02 PM

Re: passing a method
 
Hi --

On Wed, 10 Aug 2005, Wybo Dekker wrote:

> Patrick Gundlach and Devin Mullans wrote:
>
>> @t = ''
>> def bye
>> @t << 'bye'
>> end
>> def hello
>> @t << 'hello'
>> end
>> def doit(f)
>> send f
>> end
>> doit(:hello)
>> doit(:bye)
>> doit(:hello)
>> puts @t

>
> That's exactly what I needed. Thanks!


Why not just use send?


David

--
David A. Black
dblack@wobblini.net



nobu.nokada@softhome.net 08-10-2005 12:03 PM

Re: passing a method
 
Hi,

At Wed, 10 Aug 2005 19:05:04 +0900,
Wybo Dekker wrote in [ruby-talk:151467]:
> I want to make a method which can execute another method given to it as
> an argument. The following works but the call doesn't look elegant - is
> it the ruby way?


Another way:

> #!/usr/bin/env ruby
> @t = ''
> def bye
> @t << 'bye'
> end
> def hello
> @t << 'hello'
> end
> def doit

yield
> end

doit(&method(:hello))
doit(&method(:bye))
doit(&method(:hello))
puts @t

--
Nobu Nakada



Wybo Dekker 08-10-2005 01:08 PM

Re: passing a method
 
Robert Klemme wrote:

> IMHO a superior solution would be to use a block instead of argument
> option_handler. AFAICS you have only one such callback and that's

exactly
> what blocks are for. If you want access to the current instance you can
> use instance_eval:
>
> def init(needed,defaults,&option_handler)
> ....
> # handle options
> instance_eval &option_handler
> ....
> end


but that would need, in the calling program, something like

init(needed,defaults) { handle_options }

which I feel is less straightforward/consequent than

init(needed,defaults,:handle_options)

> Also, for setting instance variables, this idiom is better (because it
> avoids evil eval and you don't need special handling of nil):
>
> defaults.each {|k,v| instance_variable_set("@#{k}", v)}


Nice! I did'nt know about instance_variable_set yet.
Learned a lot today, thanks!

--
Wybo





All times are GMT. The time now is 11:29 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.