Novice: self, @self.respond_to? and dynamically built methods

I have been plodding through a Ruby tutorial and came across the
‘require’
and ‘load’ methods(?). Prior to that, all of the tutorial examples I
played with had been bolted into one file. I had added in a ‘zenity’
based menu option to drive the selection of the tutorial subjects.
Now I have split each of the tutorial subjects into separate files that
get ‘loaded’ or ‘required’. The ‘main’ section is then just a call to
the zenity menu driver, and calls to the respective methods.

All works fine…apart from…

I had an old tutorial module that looked at the passing of arguments
into Ruby from the command line. This example did little more than split
the arguments into the argument type and value and then displayed them.
I thought it would be nice then to revisit this and make the argument
type the name of a tutorial ‘method’ and the argument value any value
required by that tutorial method.

This seemed relatively straight forward, so I could now call my Ruby
module as:
./ptutorial.rb -s"HASHES" -o"1"

From my driver menu, I could then select the argument tutorial - and it
would split the two arguments into a variable containing a method name
(by downcasing and appending _test to the -s argument) and option
variable.

Now, to stop a call to a non existent method, I wanted to see if the
built method variable existed as a method.

What I thought I could then do, was to see if ‘self’ responded to the
method by using:
if self.respond_to?(method)

but it seems that ‘self’ does not respond to that method - although if I
call self.send(method, option) it appears to work fine (even though if I
look at the methods that self/@self supports via the methods method,
none of my ‘local’ tutorial methods appear).

I thought that it may be down to use of ‘self’ as opposed to ‘@self’ but
both fail on the respond_to?, and seem to process the method ok on the
send.

What I want is to dynamically build a method name, then see if the
object (in this case ‘self’ or the current module) supports that method
and if so to then execute that method with any optional arguments.

Have you tried self.methods.include?

Joel P. wrote in post #1094736:

Have you tried self.methods.include?

Joel,
Just tried, but no joy.
BUT…
I tried adding the full method footprint into the self.respond_to? and
that then seemed to work - seemed being the operative word, as I looked
more at respond_to? and I read that the second argument is a flag for
checking private methods. So, that implies that somehow, my ‘local’
methods have been classed as private? I can’t see a private statement in
my code at all - are methods in ‘main’ then classed as private by
default?

That also then made me think whether what I’m trying to achieve (all be
it in learning mode) is possible.
If respond_to? only checks if that method name is valid for the given
object, I still have the problem of knowing what the method’s footprint
is.

In my case, I have a whole series of tutorial modules - mainly called
foo_test (ie array_test, hash_test, range_test…etc) - which can then
optionally take arguments - ie in my hash_test, there may be umpteen
sub-subjects - each being triggered by the option passed (ie
hash_test(1) will show me blah, hash_test(2)…)

So what I was after was dynamically building foo_test from the command
line argument(s) and then calling the method, with or without arguments.
But if respond_to? doesn’t check the footprint, I still end up with a
crash. Given that, is a better practice to simply call the method with
and without the arguments, catching any error and simply not bothering
to see if the object responds to that method?

Am 01.02.2013 12:36, schrieb Steve Tu:

if self.respond_to?(method)
What I want is to dynamically build a method name, then see if the
object (in this case ‘self’ or the current module) supports that method
and if so to then execute that method with any optional arguments.

To me, this does not sound like a use case for metaprogramming.
Why don’t you use a method that takes the section as an argument?

But to your question: I assume you are talking about ‘global’ methods?
If so, I cannot reproduce your problem:

1.9.3p374 :001 > def test_method; puts ‘test’; end
=> nil
1.9.3p374 :002 > self.methods.include?(:test_method)
=> true
1.9.3p374 :003 > test_method
test
=> nil
1.9.3p374 :004 > self.send(:test_method)
test
=> nil
1.9.3p374 :005 > self.respond_to?(:test_method)
=> true

unknown wrote in post #1094752:

Am 01.02.2013 12:36, schrieb Steve Tu:

if self.respond_to?(method)
What I want is to dynamically build a method name, then see if the
object (in this case ‘self’ or the current module) supports that method
and if so to then execute that method with any optional arguments.

To me, this does not sound like a use case for metaprogramming.
Why don’t you use a method that takes the section as an argument?

But to your question: I assume you are talking about ‘global’ methods?
If so, I cannot reproduce your problem:

1.9.3p374 :001 > def test_method; puts ‘test’; end
=> nil
1.9.3p374 :002 > self.methods.include?(:test_method)
=> true
1.9.3p374 :003 > test_method
test
=> nil
1.9.3p374 :004 > self.send(:test_method)
test
=> nil
1.9.3p374 :005 > self.respond_to?(:test_method)
=> true

The code I have is now split into separate files that are ‘load’ or
'require’d. The argument test file contains:
#-----------------------------------------------------------------------

F O R M A L A R G U M E N T S

#-----------------------------------------------------------------------
def arguments_test
require ‘getoptlong’

# The parameters can be in any order
STDOUT.puts "Arguments "+ARGV.length.to_s
unless ARGV.length >= 1
    `zenity --info --title="Usage ... " --text="Usage: 

./ptutorial.rb -s"Subject" -o"Options""`
exit
end

subject = option =  ''
# specify the options we accept and initialize
# the option parser
opts = GetoptLong.new(
            [ "--subject", "-s", GetoptLong::REQUIRED_ARGUMENT ],
            [ "--option", "-o", GetoptLong::OPTIONAL_ARGUMENT ],
        )
# process the parsed options
opts.each do |opt, arg|
    case opt
        when '--subject'
            subject = arg
        when '--option'
            option = arg
    end
end

STDOUT.puts "(#{self}) - (#{self.to_s}) Supports (#{self.methods})"
STDOUT.puts "No Class Supports (#{methods})"


method  = "#{subject.to_s.chomp.downcase}_test"
if self.respond_to?(method)
    self.send(method)
else
    if self.respond_to?(method,TRUE)
        self.send(method,option)
    else
        `zenity --info --title="Arguments ... " --text="Args: 

(#{@self})… Does Not Support #{method}"`
end
end

`zenity --info --title="Arguments ... " --text="Args: Subject 

(#{subject}) Option (#{option})"`

end

What I now end up with is the ‘private’ respond_to? test working - which
is one point I don’t understand (ie what determines a method’s
visibility - I thought it had to be explicitly defined or was assumed as
public?). That then lead onto the question re how to determine the
footprint of the method being called, as the code above works if the
method passed accepts a single parameter. If the method accepts o
parameters then the code fails anyway - and hence the question re
whether it is simply then better to just attempt the method call and
trap the errors thrown, rather than trying to see if the method is
supported in the first place.
Am I making any sense at all?

Am 01.02.2013 16:06, schrieb Steve Tu:

The code I have is now split into separate files that are ‘load’ or
'require’d. The argument test file contains:
#-----------------------------------------------------------------------

F O R M A L A R G U M E N T S

#-----------------------------------------------------------------------
def arguments_test
require ‘getoptlong’

I like optparse.

 # The parameters can be in any order
 STDOUT.puts "Arguments "+ARGV.length.to_s

puts uses stdout by default, so you can just use `puts’.

             [ "--subject", "-s", GetoptLong::REQUIRED_ARGUMENT ],
 end

 STDOUT.puts "(#{self}) - (#{self.to_s}) Supports (#{self.methods})"

#{self} sends to_s implicitly, so #{self} and #{self.to_s} are the same

         `zenity --info --title="Arguments ... " --text="Args:

What I now end up with is the ‘private’ respond_to? test working - which
is one point I don’t understand (ie what determines a method’s
visibility - I thought it had to be explicitly defined or was assumed as
public?).

Seems ‘global’ methods behave differently, they are private methods
of `Object’, see
http://stackoverflow.com/questions/8799704/are-ruby-imported-methods-always-private

That then lead onto the question re how to determine the
footprint of the method being called, as the code above works if the
method passed accepts a single parameter. If the method accepts o
parameters then the code fails anyway - and hence the question re
whether it is simply then better to just attempt the method call and
trap the errors thrown, rather than trying to see if the method is
supported in the first place.
Am I making any sense at all?

You could use an optional argument hash.

Still, this approach seems a bit strange to me.
Ever thought about defining classes?

unknown wrote in post #1094776:

Am 01.02.2013 16:06, schrieb Steve Tu:

The code I have is now split into separate files that are ‘load’ or
'require’d. The argument test file contains:
#-----------------------------------------------------------------------

F O R M A L A R G U M E N T S

#-----------------------------------------------------------------------
def arguments_test
require ‘getoptlong’

I like optparse.

 # The parameters can be in any order
 STDOUT.puts "Arguments "+ARGV.length.to_s

puts uses stdout by default, so you can just use `puts’.

             [ "--subject", "-s", GetoptLong::REQUIRED_ARGUMENT ],
 end

 STDOUT.puts "(#{self}) - (#{self.to_s}) Supports (#{self.methods})"

#{self} sends to_s implicitly, so #{self} and #{self.to_s} are the same

         `zenity --info --title="Arguments ... " --text="Args:

What I now end up with is the ‘private’ respond_to? test working - which
is one point I don’t understand (ie what determines a method’s
visibility - I thought it had to be explicitly defined or was assumed as
public?).

Seems ‘global’ methods behave differently, they are private methods
of `Object’, see

http://stackoverflow.com/questions/8799704/are-ruby-imported-methods-always-private

That then lead onto the question re how to determine the
footprint of the method being called, as the code above works if the
method passed accepts a single parameter. If the method accepts o
parameters then the code fails anyway - and hence the question re
whether it is simply then better to just attempt the method call and
trap the errors thrown, rather than trying to see if the method is
supported in the first place.
Am I making any sense at all?

You could use an optional argument hash.

Still, this approach seems a bit strange to me.
Ever thought about defining classes?

I am following a tutorial, so am picking up each example as is. I am
then trying to modify those examples (on a limited basis), just to make
sure I understand the lesson and what it implies. I may revisit older
examples if I see a new facility that I think applies - as here, where I
thought I could bypass my menu and use the passed arguments to
dynamically call the tutorial lesson.
I just get a bit lost as to Ruby’s built in methods and what they’re
meant to do (I can see WHAT they do, but the implication of
when/where/why sometimes loses me). Here, for example, you can see if a
method is available by respond_to? and eval and send will then execute a
‘prepared’ string as a method. But if I can’t tell what the footprint is
of the method what is the point in being able to dynamically execute a
method (ie I could end up calling a methods as blah() when it should be
called as blah(int, string, int))? What then is dynamic method execution
for, if I can’t tell how the method is to be called in detail?

Thanks for the info on ‘global’ methods by the way - that explains the
why I was seeing my ‘respond_to?’ fail - and also why I thought it
worked when I called it as respond_to?(“hashes_test”,“1”).

Am 03.02.2013 09:45, schrieb Steve Tu:

‘prepared’ string as a method. But if I can’t tell what the footprint is
of the method what is the point in being able to dynamically execute a
method (ie I could end up calling a methods as blah() when it should be
called as blah(int, string, int))? What then is dynamic method execution
for, if I can’t tell how the method is to be called in detail?

As I mentioned, one approach could be to use an argument hash.
But: I think as a novice you should postpone metaprogramming
(constructing method names etc.) for some time.

First thing you should do is to drop the ‘global’ methods
and start learning about classes.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs