A define_method question

J

Juston

I have a question about define_method, more specifically how to bend
it to my purpose.

The problem I am trying to solve is I have an object "Action" which
basically carries out a static set of actions based off instance
variables. "Action" can also be modified by MANY "Modifier"s. A
"Modifier" just adds in a little bit of extra code that can changes an
"Action"s operations just a bit. (Example: Action with a Modifier to
email someone with a report, something I wouldn't want on every object
and don't want to lump into some sort if/else statement in Action)

What I would like to be able to do is have an empty method
"Action.runModifiedCode" within the "Action" class that would allow me
to just inject the code right into "Action." This is easy enough to do
using define_method (or a mix-in) to override the mock method, but
this doesn't work when the "Action" has more than one "Modifier."

Long winded story short, is there something that would allow me to
take the code from one object method and append to another object's
method?
 
R

Ryan Davis

I have a question about define_method, more specifically how to bend
it to my purpose.

The problem I am trying to solve is I have an object "Action" which
basically carries out a static set of actions based off instance
variables. "Action" can also be modified by MANY "Modifier"s. A
"Modifier" just adds in a little bit of extra code that can changes an
"Action"s operations just a bit. (Example: Action with a Modifier to
email someone with a report, something I wouldn't want on every object
and don't want to lump into some sort if/else statement in Action)

What I would like to be able to do is have an empty method
"Action.runModifiedCode" within the "Action" class that would allow me
to just inject the code right into "Action." This is easy enough to do
using define_method (or a mix-in) to override the mock method, but
this doesn't work when the "Action" has more than one "Modifier."

Long winded story short, is there something that would allow me to
take the code from one object method and append to another object's
method?

in almost all cases I'm prolly going to suggest using eval instead of
define method. I'm biased towards it, and so is ruby (there is a
(very) slight speed penalty calling a method created with
define_method).

if simply calling them is sufficient (ie, they're not relying on
manipulating local variables) then you can do something like:

eval "def #{name}; #{features.compact.join("; "); end"

If you truly need their bodies injected and find composing them as
methods easier, then you may want to check out using a combination of
ParseTree (1.8 only) and ruby2ruby. There are drawbacks there tho.
First off, to get live extraction of method bodies, you have to use
ParseTree or jump through extra hoops with ruby_parser. Either way it
is pretty heavy handed but a very versatile option.

Otherwise, some sort of in-between would be:

feature_bodies = {
:feature1 => "...code...",
:feature2 => "...code...",
...
}

eval "def #{name}; #{features.compact.map { |n|
feature_bodies[n] }.join("; "); end"
 
J

Joel VanderWerf

Juston said:
I have a question about define_method, more specifically how to bend
it to my purpose.

The problem I am trying to solve is I have an object "Action" which
basically carries out a static set of actions based off instance
variables. "Action" can also be modified by MANY "Modifier"s. A
"Modifier" just adds in a little bit of extra code that can changes an
"Action"s operations just a bit. (Example: Action with a Modifier to
email someone with a report, something I wouldn't want on every object
and don't want to lump into some sort if/else statement in Action)

What I would like to be able to do is have an empty method
"Action.runModifiedCode" within the "Action" class that would allow me
to just inject the code right into "Action." This is easy enough to do
using define_method (or a mix-in) to override the mock method, but
this doesn't work when the "Action" has more than one "Modifier."

Long winded story short, is there something that would allow me to
take the code from one object method and append to another object's
method?

Are you sure mixins won't work?

class Action
def do_stuff
super if defined? super
puts "starting to do stuff"
end
end

module M1
def do_stuff
super if defined? super
puts "M1 modifier"
end
end

module M2
def do_stuff
super if defined? super
puts "M2 modifier"
end
end

module M3
def do_stuff
super if defined? super
puts "M3 modifier"
end
end

a = Action.new
a.extend M1
a.extend M2
class Action
include M3 # M3 is global for all instances of Action
end

a.do_stuff
# ==>
# M3 modifier
# starting to do stuff
# M1 modifier
# M2 modifier
 
J

Juston

I did think of that, and it's probably the route I wind up taking
unwillingly. The problem is that if all the "Modifier" objects have
their own unpredictable method names the host object doesn't know how
to invoke them in its native (template) code.

This will probably make more sense if I explain the context with a bit
more dept (feel free to skip to the next paragraph.) I'm writing some
automated testing software that will use Watir to interact with a
browser dynamically, this stuff will be run nightly with no user
present to direct it. The program builds a set of objects that define
basic behavior from an input file filled with a problem-specific
domain language. The fundamental objects are "TestSuite," "Test," ...
"Step" and "Action." Any of these objects is subject to be changed by
a "Modifier" that would alter the way the host object would say handle
an error or record runtime or reset all children objects after its run
etc. This means that most of the objects created during runtime are
singletons in the sense that no two are ever really exactly the same,
though they all come from the same templates. The further complicate
the problem there are four basic types of modifiers that can be added
at anytime: Ones that run before the template code executes, ones that
run after the template code executes, ones that handle exceptions, and
ones that run every time the host object becomes the focus of the
stack. Modifiers are sporadically defined in the domain language (and
subsequent ruby code module) added and removed without any regard to
the underlying code, their presence is largely masked from the logic
of the main system.

The problem with the mix-in solution is that if I have all these
modifiers with unique method names I can't really account for invoking
them within the test logic natively, the template code would have to
know in advance what methods it would have to invoke. Alternatively, I
could have the mix-ins all use the same method names, but they would
override one another and force each object to have at most one
"modifier." My best practical solution so far is to include all the
"modifiers" as mix-ins with unique method names, then have one
template method that would use iterate through
Object.protected_instance_methods and execute the mix-in methods.
However, this makes dealing with the four basic types of modifiers
rather difficult, I would either have to enforce method naming
conventions to allow the template code to discern when to run which
method or (hopefully) something more clever.

I did also have the idea that I could define a DATA stream block in
the highest parent "Modifier" that would allow me to read the code of
any child as if it were a string. I could then collect all the code
from the "modifiers" for a given host object into one string and then
use something like "eval 'define methodx'.concat(codeString)" to re-
define (override) an empty template method that could be executed by
native the template code. Though Im not sure how easy it might be to
only extrapolate the code from the internally defined "modifier"
methods, or the practicality of the whole idea in general. My rather
green instinct says it may just be crazy enough to work, but I wanted
to check with the community for a better idea first.

*gasp* That was a lot to explain, hopefully it all makes sense. Thanks
in advance for your input and help!
 
J

Joel VanderWerf

Juston said:
I did think of that, and it's probably the route I wind up taking
unwillingly. The problem is that if all the "Modifier" objects have
their own unpredictable method names the host object doesn't know how
to invoke them in its native (template) code.

This will probably make more sense if I explain the context with a bit
more dept (feel free to skip to the next paragraph.) I'm writing some
automated testing software that will use Watir to interact with a
browser dynamically, this stuff will be run nightly with no user
present to direct it. The program builds a set of objects that define
basic behavior from an input file filled with a problem-specific
domain language. The fundamental objects are "TestSuite," "Test," ...
"Step" and "Action." Any of these objects is subject to be changed by
a "Modifier" that would alter the way the host object would say handle
an error or record runtime or reset all children objects after its run
etc. This means that most of the objects created during runtime are
singletons in the sense that no two are ever really exactly the same,
though they all come from the same templates. The further complicate
the problem there are four basic types of modifiers that can be added
at anytime: Ones that run before the template code executes, ones that
run after the template code executes, ones that handle exceptions, and
ones that run every time the host object becomes the focus of the
stack. Modifiers are sporadically defined in the domain language (and
subsequent ruby code module) added and removed without any regard to
the underlying code, their presence is largely masked from the logic
of the main system.

I'd still avoid eval-ing code and try to use data structures of procs,
something like this:

class Action
def some_template
before.each {|pr| pr.call(self)}
puts "in template code"
after.each {|pr| pr.call(self)}
end

def before
@before ||= []
end

def after
@after ||= []
end
end

a = Action.new
a.before << proc {puts "before 1"}
a.before << proc {puts "before 2"}
a.after << proc {puts "after"}

a.some_template
 
J

Juston

That looks pretty sharp actually, after reading more about proc
objects I think that may be the way to go. A lot cleaner than one
giant define on a conglomerate string and a bit more flexible.
Also, it looks like Ruby2Ruby and ParseTree (or ruby_parser) is going
to help me get what I need from the "Modifier" objects too. I still
need to do some more reading before I fully understand how to use it.
If anyone has a good guide let me know, otherwise I'll hit the search
engines.

Thanks for the help and excellent input, this saves me a lot of time
and headache!

Juston said:
I did think of that, and it's probably the route I wind up taking
unwillingly. The problem is that if all the "Modifier" objects have
their own unpredictable method names the host object doesn't know how
to invoke them in its native (template) code.
This will probably make more sense if I explain the context with a bit
more dept (feel free to skip to the next paragraph.) I'm writing some
automated testing software that will use Watir to interact with a
browser dynamically, this stuff will be run nightly with no user
present to direct it. The program builds a set of objects that define
basic behavior from an input file filled with a problem-specific
domain language. The fundamental objects are "TestSuite," "Test," ...
"Step" and "Action." Any of these objects is subject to be changed by
a "Modifier" that would alter the way the host object would say handle
an error or record runtime or reset all children objects after its run
etc. This means that most of the objects created during runtime are
singletons in the sense that no two are ever really exactly the same,
though they all come from the same templates. The further complicate
the problem there are four basic types of modifiers that can be added
at anytime: Ones that run before the template code executes, ones that
run after the template code executes, ones that handle exceptions, and
ones that run every time the host object becomes the focus of the
stack. Modifiers are sporadically defined in the domain language (and
subsequent ruby code module) added and removed without any regard to
the underlying code, their presence is largely masked from the logic
of the main system.

I'd still avoid eval-ing code and try to use data structures of procs,
something like this:

class Action
=A0 =A0def some_template
=A0 =A0 =A0before.each {|pr| pr.call(self)}
=A0 =A0 =A0puts "in template code"
=A0 =A0 =A0after.each {|pr| pr.call(self)}
=A0 =A0end

=A0 =A0def before
=A0 =A0 =A0@before ||=3D []
=A0 =A0end

=A0 =A0def after
=A0 =A0 =A0@after ||=3D []
=A0 =A0end
end

a =3D Action.new
a.before << proc {puts "before 1"}
a.before << proc {puts "before 2"}
a.after << proc {puts "after"}

a.some_template
 
J

Juston Davies

I can't seem to get Ruby2Ruby to work, and despite my efforts I can't
seem to find the documentation I need or any sort of tutorial. Is
there any other way to take a method from another object and store it
into a proc or lambda object?

That looks pretty sharp actually, after reading more about proc
objects I think that may be the way to go. A lot cleaner than one
giant define on a conglomerate string and a bit more flexible.
Also, it looks like Ruby2Ruby and ParseTree (or ruby_parser) is going
to help me get what I need from the "Modifier" objects too. I still
need to do some more reading before I fully understand how to use it.
If anyone has a good guide let me know, otherwise I'll hit the search
engines.

Thanks for the help and excellent input, this saves me a lot of time
and headache!

I'd still avoid eval-ing code and try to use data structures of procs,
something like this:
class Action
=A0 =A0def some_template
=A0 =A0 =A0before.each {|pr| pr.call(self)}
=A0 =A0 =A0puts "in template code"
=A0 =A0 =A0after.each {|pr| pr.call(self)}
=A0 =A0end
=A0 =A0def before
=A0 =A0 =A0@before ||=3D []
=A0 =A0end
=A0 =A0def after
=A0 =A0 =A0@after ||=3D []
=A0 =A0end
end
a =3D Action.new
a.before << proc {puts "before 1"}
a.before << proc {puts "before 2"}
a.after << proc {puts "after"}
07
 
J

Joel VanderWerf

Juston said:
Is there any other way to take a method from another object and store it
into a proc or lambda object?

Yes. The result isn't a proc/lambda, but it is callable.

s = "foo"
m = s.method :reverse
m2 = m.unbind

s2 = "bar"
m3 = m2.bind(s2)
puts m3.call # ==> rab

See docs for Method and UnboundMethod.
 
J

Juston Davies

That'll do, after looking at the doc looks like you an .to_proc a
method object. Thanks for the help!
 
J

Joel VanderWerf

Juston said:
That'll do, after looking at the doc looks like you an .to_proc a
method object.

Maybe you don't even need to call #to_proc. From a duck-typing
perspective, a Method instance is close enough, since it has #call and
#[] already.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,968
Messages
2,570,154
Members
46,702
Latest member
LukasConde

Latest Threads

Top