Maybe this is a stupid question, but I can't figure it out. I have a "feeling" why main is self during execution of the block. But I don't have a solid explanation for it.
It seems that the question who is self depends on the context where the block is defined. Is this right?
Can anyone explain it to me?
?> class Klass
?> def yld
?> yield
?> end
>> end
>>
>> o1 = Klass.new
>> o2 = Klass.new
>>
?> o1.yld {
?> o2.yld {
?> p self
?> }
>> }
main
self doesn't change because of a block. The reason you get main is because you are calling yld from the main context:
p self #=> main
o1.yld {
p self #=> main
o2.yld {
p self #=> main
}
p self #=> main
}
p self #=> main
However, self can be changed explicitly, e.g. via instance_eval:
def foo(&block)
"hello".instance_eval(&block)
end
p self #=> main
foo {
p self #=> "hello"
p size #=> 5
p upcase #=> "HELLO"
}
p self #=> main
In the above code, self is changed to the string instance "hello" during the block.
Related
def errors_matching(&block)
m = Module.new
(class << m ;self; end).instance_eval do
define_method(:===, &block)
end
m
end
This allows me to define dynamic rescue clauses in Ruby, for example:
begin
raise 'hi'
rescue errors_matching { |e| e.class.name.include?('Runtime') } => e
puts "Ignoring #{e.message}"
end
I don't understand the first piece of code. What's the whole point of m = Module.new and then putting self (which is main in this case) inside a singleton class and doing instance_eval on it?
This:
class << m; self end
is obviously the same as:
m.singleton_class
And
m.singleton_class.instance_eval { define_method(:foo) {} }
is just the same as
m.define_singleton_method(:foo) {}
So, the whole errors_matching method is just a very convoluted way of saying:
def errors_matching(&block)
Module.new.tap do |m| m.define_singleton_method(:===, &block) end
end
Could anyone please help me to understand the difference between "yield self" and "yield"?
class YieldFirstLast
attr_accessor :first, :last
def initialize(first = nil, last = nil)
#first = first
#last = last
yield self if block_given?
end
def hello
puts "#{#first} #{#last} says hello!"
end
end
In the case of yield self, self is the argument passed to the block. With simply yield, no argument is passed. self is not special here, anything could be yielded, e.g.
class Foo
def a() yield self end
def b() yield end
def c() yield "Bar" end
def d() yield 1, 2, "scuba" end
def to_s() "A!" end
end
Foo.new.a {|x| puts x } #=> A!
Foo.new.b {|x| puts x } #=> (a blank line, nil was yielded)
Foo.new.c {|x| puts x } #=> Bar
Foo.new.d {|x, y, z| puts z } #=> scuba
yield self enters block, associated with method call, passing current object as argument to the block, plain yield just enters the block without passing any arguments.
Think of yield as invoking your block and yield self is invoking your block with the current instance as the parameter.
For (auto-)educational purposes, I'm trying to mimic the super behavior to learn how it works.
I could mimic super for instance methods, but I couldn't do it for class methods.
Here is my code:
class A
def aa
#msg ||= 'Original...: '
puts "#{#msg}#{self}.aa: #{self.class} < #{self.class.superclass}"
end
def self.ab
#msg ||= 'Original...: '
puts "#{#msg}#{self}.ab: #{self} < #{self.superclass}"
end
end
class B < A
def aa
#msg = "Real super.: "
super
end
def self.ab
#msg = "Real super.: "
super
end
def mimic_aa
#msg = "Mimic super: "
self.class.superclass.instance_method(:aa).bind(self).call
end
def self.mimic_ab
#msg = "Mimic super: "
#superclass.method(:ab).unbind.bind(self).call
#=> Error: singleton method only works in original object
#superclass.ab
#=> self is A; I want self to be B
proc = superclass.method(:ab).to_proc
#self.instance_eval(&proc)
#=> ArgumentError: instance_eval seems to call aa(some_unwanted_param)
# Note: Ruby 1.8.7
#eval('proc.call', binding)
#=> self is A; I want self to be B
end
end
a = A.new
b = B.new
a.aa #=> Original...: #<A:0xb77c66ec>.aa: A < Object
b.aa #=> Real super.: #<B:0xb77c6624>.aa: B < A
b.mimic_aa #=> Mimic super: #<B:0xb77c6624>.aa: B < A
puts ''
A.ab #=> Original...: A.ab: A < Object
B.ab #=> Real super.: B.ab: B < A
B.mimic_ab #=> (expected the same as above)
Any ideas?
Well, the problem is probably the version of Ruby that you are using. I'm running 1.9.2, and the program runs as expected. I think (from the comment in your code) that the problem is that you are running Ruby v1.8.7. It also wouldn't hurt to try running your code again.
class Setter
attr_accessor :foo
def initialize
#foo = "It aint easy being cheesy!"
end
def set
self.instance_eval { yield if block_given? }
end
end
options = Setter.new
# Works
options.instance_eval do
p foo
end
# Fails
options.set do
p foo
end
Why does the 'set' method fail?
EDIT
Figured it out...
def set
self.instance_eval { yield if block_given? }
end
Needed to be:
def set(&blk)
instance_eval(&blk)
end
Yep - yield evaluates in the context within which it was defined.
Good write up here, but a simple example shows the problem:
>> foo = "wrong foo"
>> options.set do
?> p foo
>> end
"wrong foo"
In Ruby, is there a way to redefine a method of a particular instance of a class using a proc? For example:
class Foo
def bar()
return "hello"
end
end
x = Foo.new
y = Foo.new
(Something like):
y.method(:bar) = lambda { return "goodbye" }
x.bar
y.bar
Producing:
hello
goodbye
Thanks.
def define_singleton_method_by_proc(obj, name, block)
metaclass = class << obj; self; end
metaclass.send(:define_method, name, block)
end
p = proc { "foobar!" }
define_singleton_method_by_proc(y, :bar, p)
or, if you want to monkey-patch Object to make it easy
class Object
# note that this method is already defined in Ruby 1.9
def define_singleton_method(name, callable = nil, &block)
block ||= callable
metaclass = class << self; self; end
metaclass.send(:define_method, name, block)
end
end
p = proc { "foobar!" }
y.define_singleton_method(:bar, p)
#or
y.define_singleton_method(:bar) do
"foobar!"
end
or, if you want to define your proc inline, this may be more readable
class << y
define_method(:bar, proc { "foobar!" })
end
or,
class << y
define_method(:bar) { "foobar!" }
end
this is the most readable, but probably doesn't fit your needs
def y.bar
"goodbye"
end
This question is highly related
I'm not sure what version of Ruby this was added in (at least 1.8.7), but there seems to be an even simpler way of doing this:
str1 = "Hello"
str2 = "Goodbye"
def str1.to_spanish
"Hola"
end
puts str1 # => Hello
puts str1.to_spanish # => Hola
puts str2 # => Goodbye
puts str2.to_spanish # => Throws a NoMethodError
Learnt about this whilst reading the Ruby Koans (about_class_methods.rb lesson).
I'm still not entirely sure what the purpose of this is since it seems a bit dangerous to me.
You can use the syntax class <<object to get an object's "singleton class" (that's a special parent class belonging only to that object) and define methods only for that instance. For example:
str1 = "Hello"
str2 = "Foo"
class <<str1
def to_spanish
'Hola'
end
end
Now if you do str1.to_spanish, it will return "Hola", but str2.to_spanish will give you a NoMethodFound exception.