[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Use a string as a method call

Chris Bailey

8/28/2008 8:03:00 PM

I'm trying to come up with an efficient way of using user input as a
way of calling methods. I'm unhappy with the way that I am doing it
because it isn't very flexible. This is what I'm doing now.

input = gets.downcase.chomp

if input == foo
do_foo()
elsif input == bar
do_bar()
else
puts "That isn't a command!"
end

What I would like to do is more like so.

commands = {
'foo' => do_foo(),
'bar' => do_bar()
}

I then would like to search the commands hash for a key that matches the
player input and execute the method associated with that key. What I've
noticed is that upon initialization of the hash the value becomes equal
to the result of the method but that is not what I want. If I store the
value as a string ie "do_foo()" would I be able to parse that string and
execute it as a method? And if so, how would that be done?
--
Posted via http://www.ruby-....

16 Answers

Glen Holcomb

8/28/2008 8:07:00 PM

0

[Note: parts of this message were removed to make it a legal post.]

On Thu, Aug 28, 2008 at 2:02 PM, Chris Bailey <
christopher.sean.bailey@gmail.com> wrote:

> I'm trying to come up with an efficient way of using user input as a
> way of calling methods. I'm unhappy with the way that I am doing it
> because it isn't very flexible. This is what I'm doing now.
>
> input = gets.downcase.chomp
>
> if input == foo
> do_foo()
> elsif input == bar
> do_bar()
> else
> puts "That isn't a command!"
> end
>
> What I would like to do is more like so.
>
> commands = {
> 'foo' => do_foo(),
> 'bar' => do_bar()
> }
>
> I then would like to search the commands hash for a key that matches the
> player input and execute the method associated with that key. What I've
> noticed is that upon initialization of the hash the value becomes equal
> to the result of the method but that is not what I want. If I store the
> value as a string ie "do_foo()" would I be able to parse that string and
> execute it as a method? And if so, how would that be done?
> --
> Posted via http://www.ruby-....
>
>
You could do it with eval in this case it sounds like that would be fairly
safe although you could also use a proc I think.

--
"Hey brother Christian with your high and mighty errand, Your actions speak
so loud, I can't hear a word you're saying."

-Greg Graffin (Bad Religion)

TPReal

8/28/2008 8:08:00 PM

0

Chris Bailey wrote:
> I'm trying to come up with an efficient way of using user input as a
> way of calling methods. I'm unhappy with the way that I am doing it
> because it isn't very flexible. This is what I'm doing now.
>
> input = gets.downcase.chomp
>
> if input == foo
> do_foo()
> elsif input == bar
> do_bar()
> else
> puts "That isn't a command!"
> end

ALLOWED=[:foo,:bar]
input=gets.downcase.chomp.to_sym
if ALLOWED.include? input
send(input)
else
puts "That isn't a command!"
end

The method send calls a method specified as the first argument to send.
Try send(:puts,"abc") as an example.

TPR.
--
Posted via http://www.ruby-....

TPReal

8/28/2008 8:10:00 PM

0

Thomas B. wrote:
> send(input)

Sorry, more like send(:"do_#{input}") in your example.
TPR.
--
Posted via http://www.ruby-....

Gregory Brown

8/28/2008 8:10:00 PM

0

On Thu, Aug 28, 2008 at 4:02 PM, Chris Bailey
<christopher.sean.bailey@gmail.com> wrote:
> I'm trying to come up with an efficient way of using user input as a
> way of calling methods. I'm unhappy with the way that I am doing it
> because it isn't very flexible. This is what I'm doing now.
>
> input = gets.downcase.chomp
>
> if input == foo
> do_foo()
> elsif input == bar
> do_bar()
> else
> puts "That isn't a command!"
> end
>
> What I would like to do is more like so.
>
> commands = {
> 'foo' => do_foo(),
> 'bar' => do_bar()
> }


ACTIONS = %w[foo bar]

def execute(action)
return send("do_#{action}") if ACTIONS.include?(action)
raise "Unexpected action"
end




--
Technical Blaag at: http://blog.majesticseacr... | Non-tech
stuff at: http://metametta.bl...

John Pritchard-williams

8/28/2008 8:12:00 PM

0

Hi Chris,

Try this:

...
class MyClass
def mymethod
puts "mymethod called!"
end

def myothermethod
puts "myothermethod called!"
end
end


input = gets.downcase.chomp;
myinstance=MyClass.new;
myinstance.send(input.to_sym);
...

So use the 'send' method of your instance to invoke the method - first
convert the inputted string to a symbol. Wow..you gotta love Ruby for
stuff like this....:)

Cheers

John
--
Posted via http://www.ruby-....

Stefano Crocco

8/28/2008 8:13:00 PM

0

On Thursday 28 August 2008, Chris Bailey wrote:
> I'm trying to come up with an efficient way of using user input as a
> way of calling methods. I'm unhappy with the way that I am doing it
> because it isn't very flexible. This is what I'm doing now.
>
> input = gets.downcase.chomp
>
> if input == foo
> do_foo()
> elsif input == bar
> do_bar()
> else
> puts "That isn't a command!"
> end
>
> What I would like to do is more like so.
>
> commands = {
> 'foo' => do_foo(),
> 'bar' => do_bar()
> }
>
> I then would like to search the commands hash for a key that matches the
> player input and execute the method associated with that key. What I've
> noticed is that upon initialization of the hash the value becomes equal
> to the result of the method but that is not what I want. If I store the
> value as a string ie "do_foo()" would I be able to parse that string and
> execute it as a method? And if so, how would that be done?

You can do something like this:

method_name = gets.downcase.chomp
send method_name

send is a method which takes as a first argument a method name (as a string or
symbol) and calls that method on its receiver, passing all the remaining
arguments to it (see ri Object#send for a better explaination). To better
handle the possibility the user inserts a wrong string, you can rescue the
NoMethodError exception:

method_name = gets.downcase.chomp
begin
send method_name
rescue NoMethodError
puts "#{method_name} is not a valid command"
end

If you want to restrict the methods the user can call, store them in an array
and check whether the string he entered is there before calling send:

commands = %w[foo bar]
method_name = gets.downcase.chomp
if commands.include? method_name then send method_name
else puts "#{method_name} is not a valid command"
end

I hope this helps

Stefano

Sebastian Hungerecker

8/28/2008 8:19:00 PM

0

John Pritchard-williams wrote:
> So use the 'send' method of your instance to invoke the method - first
> convert the inputted string to a symbol.

Actually you don't need to do that. send takes strings too.

HTH,
Sebastian
--
NP: Porcupine Tree - Sleep Together
Jabber: sepp2k@jabber.org
ICQ: 205544826

Stefano Crocco

8/28/2008 8:23:00 PM

0

On Thursday 28 August 2008, Stefano Crocco wrote:
> On Thursday 28 August 2008, Chris Bailey wrote:
> > I'm trying to come up with an efficient way of using user input as a
> > way of calling methods. I'm unhappy with the way that I am doing it
> > because it isn't very flexible. This is what I'm doing now.
> >
> > input = gets.downcase.chomp
> >
> > if input == foo
> > do_foo()
> > elsif input == bar
> > do_bar()
> > else
> > puts "That isn't a command!"
> > end
> >
> > What I would like to do is more like so.
> >
> > commands = {
> > 'foo' => do_foo(),
> > 'bar' => do_bar()
> > }
> >
> > I then would like to search the commands hash for a key that matches the
> > player input and execute the method associated with that key. What I've
> > noticed is that upon initialization of the hash the value becomes equal
> > to the result of the method but that is not what I want. If I store the
> > value as a string ie "do_foo()" would I be able to parse that string and
> > execute it as a method? And if so, how would that be done?
>
> You can do something like this:
>
> method_name = gets.downcase.chomp
> send method_name
>
> send is a method which takes as a first argument a method name (as a string
> or symbol) and calls that method on its receiver, passing all the remaining
> arguments to it (see ri Object#send for a better explaination). To better
> handle the possibility the user inserts a wrong string, you can rescue the
> NoMethodError exception:
>
> method_name = gets.downcase.chomp
> begin
> send method_name
> rescue NoMethodError
> puts "#{method_name} is not a valid command"
> end
>
> If you want to restrict the methods the user can call, store them in an
> array and check whether the string he entered is there before calling send:
>
> commands = %w[foo bar]
> method_name = gets.downcase.chomp
> if commands.include? method_name then send method_name
> else puts "#{method_name} is not a valid command"
> end
>
> I hope this helps
>
> Stefano

Of course, with this approach, you'll need to change the names of your methods
to foo and bar, or to change the definition of method_name to something like
this:

method_name = "do_#{gets.downcase.chomp}"

Stefano


John Pritchard-williams

8/28/2008 8:25:00 PM

0

Even better! You gotta love Ruby _even_ more for that :) (Thanks !)


Sebastian Hungerecker wrote:
> John Pritchard-williams wrote:
>> So use the 'send' method of your instance to invoke the method - first
>> convert the inputted string to a symbol.
>
> Actually you don't need to do that. send takes strings too.
>
> HTH,
> Sebastian

--
Posted via http://www.ruby-....

Chris Bailey

8/28/2008 9:00:00 PM

0

Thank you everyone for the quick and helpful replies! I toyed around
with all of the suggestions and decided the following would be the best
choice in my application.

def parse
input = gets.downcase.chomp
if $cmd_list.key?(input)
send $cmd_list[input]
else
puts "#{input} is not a valid command."
end
end

I have however ran into another problem and my limited knowledge of send
(I hadn't heard of it until I read these replies) makes it difficult for
me to debug. Some of my methods that worked perfectly before accessing
them using send are no longer working properly. Consider the following.

cmd_list = {
'north' => 'do_north'
'south' => 'do_south'
'n' => 'do_north'
's' => 'do_south'
'look' => 'do_look'
}

def cmd_north
$PLROBJ.xcoord -=
showMap()
end

def cmd_south
$PLROBJ.xcoord +=
showMap()
end

def cmd_look
showMap
end

If the user input is "look", the showMap method is called properly, and
everything works as intended. However if north,south,n or s is typed
into the system it fails to update the $PLROBJ variable but executes
showMap() as usual and then crashes with the following error.

/commands.rb:16:in `-': nil can't be coerced into Fixnum (TypeError)
from ./commands.rb:16:in `cmd_north'
from bsud.rb:33:in `send'
from bsud.rb:33:in `parse'
from bsud.rb:58:in `main'
from bsud.rb:63


$PLROBJ.xcoord and ycoord are initiated with a value of 5 and as far as
I know there is nothing that would ever make them 'nil'. I have no idea
what this problem is =(


--
Posted via http://www.ruby-....