Any ruby library to inspect what are the arguments that a certain methods take?
I don't know of any third-party libraries or even RubyGems that can do this reliably. It just isn't possible to do this kind of inspection given the limited reflection facilities Ruby provides.
You will have to make do with what is available in the core library, which is basically Method#parameters
:
def foo(a, b=nil, *c, d, &e); end
method(:foo).parameters
# => [[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]]
How do i get the names or arguments inside the method definition?
You can use the values directly.
def speak(name, age, address)
puts "Hello #{name}!"
end
To access the names you could use local_variables
but I don't really recommend it.
def speak(name, age, address)
p local_variables # => [:name, :age, :address]
end
But most likely you'll want to use a hash:
def speak(hash)
# use the keys/values of hash
end
Now you can use
speak({:name => "foo", :age => 42, :address => "123"})
# or
speak(:name => "foo", :age => 42, :address => "123")
Is there a way to access method arguments in Ruby?
In Ruby 1.9.2 and later you can use the parameters
method on a method to get the list of parameters for that method. This will return a list of pairs indicating the name of the parameter and whether it is required.
e.g.
If you do
def foo(x, y)
end
then
method(:foo).parameters # => [[:req, :x], [:req, :y]]
You can use the special variable __method__
to get the name of the current method. So within a method the names of its parameters can be obtained via
args = method(__method__).parameters.map { |arg| arg[1].to_s }
You could then display the name and value of each parameter with
logger.error "Method failed with " + args.map { |arg| "#{arg} = #{eval arg}" }.join(', ')
Note: since this answer was originally written, in current versions of Ruby eval
can no longer be called with a symbol. To address this, an explicit to_s
has been added when building the list of parameter names i.e. parameters.map { |arg| arg[1].to_s }
ArgumentError: wrong number of arguments' on Ruby inspect (same code line, only for some values)
The _argument error says: given 0, expected 1
for inspect
. This means that the inspect
being invoked here, expects one argument. But inspect
is always supposed to be invoked without arguments.
From this I conclude that the method inspect
has been redefined for context.class
.
UPDATE:
Now, based on the comment of the OP to my answer, I suggest the following modification the failing program:
First, we verify that the exception really comes from that invocation of inspect
that we suspect; though it seems to be obvious, the devil nevers sleeps and we want to go sure. If it does, we have a closer look at the properties of the offending object:
We replace p context
by
begin
# Doing an explicit `inspect` to be in control of what is going on
ic = context.inspect
puts ic
rescue ArgumentError => e
puts "Exception!"
puts e
puts "context is a #{context.class}"
puts "inspect expects: #{context.class.method(:inspect).parameters}"
end
If it is really the case, as the OP claims, that this code displays Exception!, but still shows an empty parameter array, I would report this exact example to the Ruby bug tracker.
Passing arguments to Ruby methods
Examine the AST with Ripper
In Ruby, parentheses are largely optional except when needed to avoid ambiguity, such as when passing arguments to methods that take a block. Under the hood, mainline Ruby has a lot of moving parts that tokenize and parse the code you write. One of the most useful is the Ripper module (documented here) which enables you to see the abstract syntax tree that Ruby produces from your code.
Here are two versions of your code as Ruby sees them. You can see from the S-expressions that the failing version is different from the non-failing version. In irb:
Ripper.sexp %q{x = fruits.include?(item) ? 'You picked a fruit' : 'You did not pick a fru
it'}
#=>
[:program,
[[:assign,
[:var_field, [:@ident, "x", [1, 0]]],
[:ifop,
[:method_add_arg,
[:call,
[:vcall, [:@ident, "fruits", [1, 4]]],
[:@period, ".", [1, 10]],
[:@ident, "include?", [1, 11]]],
[:arg_paren, [:args_add_block, [[:vcall, [:@ident, "item", [1, 20]]]], false]]],
[:string_literal, [:string_content, [:@tstring_content, "You picked a fruit", [1, 29]]]],
[:string_literal, [:string_content, [:@tstring_content, "You did not pick a fruit", [1, 52]]]]]]]]
Ripper.sexp %q{x = fruits.include? item ? 'You picked a fruit' : 'You did not pick a frui
t'}
#=>
[:program,
[[:assign,
[:var_field, [:@ident, "x", [1, 0]]],
[:command_call,
[:vcall, [:@ident, "fruits", [1, 4]]],
[:@period, ".", [1, 10]],
[:@ident, "include?", [1, 11]],
[:args_add_block,
[[:ifop,
[:vcall, [:@ident, "item", [1, 20]]],
[:string_literal, [:string_content, [:@tstring_content, "You picked a fruit", [1, 28]]]],
[:string_literal, [:string_content, [:@tstring_content, "You did not pick a fruit", [1, 51]]]]]],
false]]]]]
Since Ruby treats almost everything as an expression that returns a value, the order of operations can affect how the parser forms expressions. The ternary operator must ultimately evaluate as three expressions, and if you use what the parser considers ambiguous syntax it will cause problems.
See Also
- parse.y
How to get argument names using reflection
I suggest you take a look at Merb's action-args library.
require 'rubygems'
require 'merb'
include GetArgs
def foo(bar, zed=42)
end
method(:foo).get_args # => [[[:bar], [:zed, 42]], [:zed]]
If you don't want to depend on Merb, you can choose and pick the best parts from the source code in github.
Related Topics
When Is the Do Keyword Required in Ruby
Assign to an Array and Replace Emerged Nil Values
How to Recursively Flatten a Yaml File into a JSON Object Where Keys Are Dot Separated Strings
Gem Install JSON Fails with Redifinition of Struct Timezone/Timespec
Why Should You Avoid the Then Keyword in Ruby
How to Cancel Evaluating a Required Ruby File? (A.K.A. Top-Level Return)
What Is an Eoferror in Ruby File I/O
Defined' and 'Unless' Not Working as Expected
Why Can't We Override '||' and '&&'
Get List Timeline by Using Twitter Gem
Rubymine: Expected ; or End of Line Error After Some Colon
Integrate Shoes into Aptana Studio Radrails