Start with the following scenario:
class Foo
def bar(baz={})
p baz
end
end
foo = Foo.new
p meth = foo.method(:bar) # => #<Method: Foo#bar>
p meth.parameters # => [[:opt, :baz]]
So I can figure out that the method bar is optional, but how do I find the default value ({}) for the method?
Just do this:
foo.bar
Since you are not passing in a value for baz, it will print out the default value.
Although, I'm betting you want something that would apply to any method. The only consistent way I know of, is to look at the source code.
The Answer: Somebody wrote a script that does it here.
However, looking over the script to try and understand just how it pulls out the default values makes my head hurt.
Related
I'm writing a DSL for a project and I've run into an issue involving local variables bleeding into nested procs when I don't want them to. It seems like no matter what I try, I can't overwrite a local variable's value with something from another scope once it's been set into a proc's binding.
an example of what I'm trying to get to work:
class Obj
def foo
:foo
end
end
def run_proc(context, &block)
context.instance_exec(&block)
end
def run_example(context)
# This `foo` the local var that ends up in the binding of
# the proc on the next line that I can't seem to overwrite
foo = :bar
run_proc(context) { foo }
# ^ I want to be able to eval `foo` based on the passed context obj
end
obj = Obj.new
# I want all three of these calls to return `:foo`
obj.foo #=> :foo # works as expected
obj.instance_exec { foo } #=> :foo # works as expected
run_example(obj) #=> :bar # doesn't work, since the `run_example`
# method's local `foo` var takes precedence
# over the passed object's `foo` method
I did some digging around and found answers with a similar approach to what I've been trying: Change the binding of a Proc in Ruby. I've also looked into the possibility of undefining the local variables in a proc's binding but this answer claims doing so is impossible: Undefine variable in Ruby.
So my question now is this: Should I just give up trying to nest procs and/or find a workaround that doesn't have local var/method name conflict issues, or is there actually a way to get around this?
You can use self.foo explicitely
Using it will call the bindings of the object self currently refers to rather then the closure of the state when proc/block is created.
Let's say I have a function with a default keyword argument
def foo(bar: "baz")
bar
end
Is there a way to call foo with the keyword argument but still invoke whatever the default is? For example, a way to make this work?
foo(bar: :default)
#=> "baz"
Alternatively, is there a way to see what the default arguments of a method are from within that method?
It's easier than you think. Just don't specify it:
foo
# => "baz"
Defaults are applied only to those values that are not explicitly specified. As a note this means that in this case you're overriding it:
foo(bar: nil)
# => nil
This is why I generally try to write methods of this form:
def foo(bar: nil)
bar or 'baz'
end
That way you can be assured that no matter what you get you return a value.
tadman already explained that you cannot retrieve a method's default arguments via Ruby's built-in reflection API.
You can however simply extract the default value into its own method:
def default
'baz'
end
def foo(bar: default)
p bar: bar, default: default
end
foo
# {:bar=>"baz", :default=>"baz"}
foo(bar: nil)
# {:bar=>nil, :default=>"baz"}
In addition, you could make default private.
You can do like this:
def foo(bar = "baz")
args = method(__method__).parameters // This will give current methods argument info.
bar
end
I have an instance variable #foo and I want to write some code so that I get string 'foo'
any hint?
If all you have is a reference to the object, you can't really do it cleanly.
def foo
bar #something
end
def bar(value)
value # no clean way to know this is #something
end
The only hack I can think of is to loop through ALL instance variables on self, looking for matches. But its a very messy approach that's likely to be slow.
def bar(value)
instance_variables.each do |ivar_name|
if instance_variable_get(ivar_name) == value
return ivar_name.to_s.sub(/^#/, '') # change '#something' to 'something'
end
end
# return nil if no match was found
nil
end
#something = 'abc123'
bar #something # returns 'something'
# But passing the same value, will return a value it's equal to as well
bar 'abc123' # returns 'something'
This works because instance_variables returns an array of symbols that are the names of instance variables.
instance_variables
#=> [:#something, :#whatever]
And instance_variable_get allows you to fetch the value by it's name.
instance_variable_get :#something # note the #
#=> 'abc123'
Combine the two methods and you can get close to what you want.
Just use it wisely. Before using a solution based on this, see if you can refactor things a way so that it's not necessary. Meta-programming is like a martial art. You should know how it works, but have the discipline to avoid using it whenever possible.
In Ruby, you can only manipulate objects. Variables (including instance variables) aren't objects.
Besides, what do you want your magic method to return in this case:
foo = Object.new
bar = foo
#baz = bar
#qux = bar
magic_method(foo) # what should the return value be and how would it know?
You can call the method instance_variables to get the name of all instance variables of an object. Caution though that instance variables are only included in that list after they have been initialized.
>> class A; attr_accessor :foo; end
=> nil
>> a = A.new
=> #<A:0x103b310b0>
>> a.instance_variables
=> []
>> a.foo = 42
=> 42
>> a.instance_variables
=> ["#foo"]
class Object
def get_name
line_number = caller[0].split(':')[1].to_i
line_exectued = File.readlines( __FILE__)[line_number-1]
line_exectued.match(/(\S+).get_name/)[1]
end
end
inconceivable = true
p inconceivable.get_name
In Ruby, inside a class's instance method, we use a getter by
foo
and we use a setter by
self.foo = something
One doesn't need to have a self. and the other does, is there a way to make them look more similar, and not using something like self.foo as the getter, as it also looks verbose.
(update: note that getter and setter may simply get or set an instance variable, but they might also do a lot of work, such as going into the DB and check the existence of a record and if not, create it, etc)
Since local scope takes precedence, when you say foo = something, a local variable foo will be created and assigned the contents of something.
The reason you can write foo in order to use the getter is because Ruby will move up in scope when it can't find a variable with that name and it will eventually find the method.
If there is a local variable with the same name as the getter method, Ruby will use its value instead:
class Foo
attr_accessor :foo
def initialize
#foo = :one
end
def f
foo = :two
foo
end
end
Foo.new.f
# => :two
In order to make it clear that you want to access the setter, you must write self.foo = something. That will tell Ruby you want to execute the foo= method on the self object with something as parameter.
If you are willing to break the conventions, you can write your setters using jQuery style, using the same method for getter and setter, depending of whether it has arguments or not:
def foo *args
return #foo if args.empty?
#foo = args.first
end
# => nil
foo
# => nil
foo(:bar) # foo = :bar
# => :bar
foo
# => :bar
As far as I know, there isn't a way around this in Ruby. I'm pretty confident this is simply how Ruby evaluates expressions.
When given a value, Ruby will first check if there is a local variable within the context which matches the one being called. If there is (perhaps 'foo' in your case), that will be the value used. If there is no such value, then Ruby will try to look up the value as a method call (falling through to "self" as the caller). If no such method exists in the look up path, an error will be raised.
The need to use "self" in the setter is to avoid Ruby setting the value as a local variable, while the lack of the use of "self" only works in the getter instance when there is no local variable of the same name being used in that context. It is probably better and clearer, albeit slightly more verbose, to be explicit with your use of self as to avoid confusion about where values are coming from.
Given the following module,
module Foo
def bar
:baz
end
end
def send_to_foo(method)
# ...?
end
send_to_foo(:bar) # => :baz
What code should go in send_to_foo to make the last line work as expected? (send_to_foo is obviously not how I would implement this; it just makes clearer what I'm looking for.)
I expected Foo.send(:bar) to work at first, but it makes sense that it doesn't. It would if the method were defined as def self.bar, but that's no fun.
well, the easy way would be
Foo.extend Foo # let Foo use the methods it contains as instance methods
def send_to_foo(method)
Foo.send(method)
end
So now
irb> send_to_foo(:bar)
#=> :baz