I am new to ruby and was trying to figure how the block will be executed
in a particular case.
class Test
def A ( &old_block)
unbound_obj = instance_method(:B)
define_method(:B) do |*args, &block|
instance_exec(*args,&old_block)
unbound_obj.bind(self).call(*args,&block)
end
def B(*args, &block)
…
end
end
Query:
Is Instance_exec in A going to form the body of method B or it will
simply execute the old_block and perform the action whatever were
present in old block
Can call take block as arguments, if yes, then when this block will
be executed, considering that method B has some body as well.
In Ruby, methods are usually defined with lowercase.
At the time the interpreter reach this line:
“unbound_obj = instance_method(:B)”
the method B does not exist, this will throw an error (Ruby is not
compiled, it has no forward declaration).
You did not give the #instance_exec a receiver (like k.instance_exec…)
so it will be executed on ‘main’ and not on an instance of Test.
Anyway if you define a method in a class (whatever you used to define
it), and later redefine that method, the previous functionality will be
lost.
Thanks for pointing out, I am from old school of programming and new to
ruby.
However the intent was not to seek correction of syntax but understand
the usage of block and define_method
Let me rephrase the question with proper working code snippet
module Trial
class Test
def self.methodA (method_name, &block)
method_name = method_name.to_sym
define_method(method_name, &block)
un_obj = instance_method(method_name)
define_method(method_name) do |*args, &new_block|
un_obj.bind(self).call(*args, &new_block)
end
end
end
end
Trial::Test.methodA(“b”) {puts “Help I am in A” }
obj = Trial::Test.new
obj.b do
puts “Hello World”
end
Output:
Help I am in A
Question: 1. The block passed in call Obj.b is lost and no error is
reported. Why ?
If I call methodA like below
Test.methodA(“b”) {… ; yeild}
To execute a block with “obj.b” first declaration must have yeild
statement, however placing yeild in block give error.
Why?
The block in obj.b is not lost, it is simply not invoked.
This:
define_method(method_name, &block)
creates a new method ‘b’ with the code:
{puts “Help I am in A” } #(through calling the class method)
Then you create a reference to this method (not just to the name #b, but
the entire method, along with its variables and functionality at the
moment you created that reference):
un_obj = instance_method(method_name)
(from this point on, you could even delete or completely rewrite method
‘b’, un_obj will still work, printing “Help I am in A”)
Then you create a new method, with the same name as the previous (why?),
and inside that method you execute the old method (un_obj), so it will
still print “Help I am in A”. The old method does not care if you pass
arguments and a block to it, as its signature (the old method) did not
contain any arguments.
Thanks. Now I am able to understand where I was loosing the context.
“Then you create a new method, with the same name as the previous
(why?)”
–> I have no answer to this, I am also trying to figure this out.
The code in class Test is meant to build the code which in turn will
process the DSL for sure.
Building the code like –
methodA B do
–
yeild/blk.call
end
Which explains the role of first define_method call
On DSL I am expecting something like … but unable to find in existing
code