[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Re: "stereotyping"

David Naseby

11/21/2003 9:33:00 PM

> From: Rasputin [mailto:rasputin@idoru.mine.nu]
> It seemed like you were more interested in a way to know how an API
> will use your object. Why not send in a probe?
>
> Pass a custom object in that has a method_missing? method that does
> a ludicrous amount of debugging of how its called. That would tell you
> how an API is actually using your object, what methods it calls and how.

Below is a quick hack to do that. Needs work. Needs redirection of IO. But
its kinda cute.. Has issues with side effects, of course, and printing
crapola all over the place.

# Usage:
# ins = ObjectProbe::Inspector.new( SomeObject.new )
# ins.probe
module ObjectProbe

class Inspector
def initialize( object )
@object = object
end

def target_class
@object.class
end

def target_methods
@object.methods - Object.new.methods
end

def probe
puts "Probing: #{target_class}"
target_methods.each do | method |
meta = MetaMethod.new( method.intern, @object )
print " Method: #{method}( "
meta.args.each do | arg |
print "[ #{arg.___requires.join(', ')} ], "
end
puts
end
end
end

class MetaMethod
def initialize( method, object )
@method = method
@object = object
end

def symbol
@method
end

def arity
m = @object.method( @method )
m.arity
end

def args
result = []
arity.times { result << DummyArgument.new }
begin
@object.send( @method, *result )
rescue
puts $!.to_s
end
result
end
end

class DummyArgument
attr_reader :___requires

def initialize
@___requires = []
end

def DummyArgument.clean_out_methods
methods_list = Object.new.methods
methods_list.each do | m |
meth = m.intern
# keep the important fns, and keep __send__ and __id__ to prevent
warnings.
next if( meth == :method_missing || meth == :__send__ || meth ==
:__id__ )
module_eval <<-"end_eval"
alias_method :__#{meth.to_i}__, #{meth.inspect}
def #{meth.id2name}(*args, &block)
method_missing( :#{meth}, *args )
__#{meth.to_i}__(*args, &block)
end
end_eval
end
end

def method_missing( symbol, *args )
@___requires << symbol
end

clean_out_methods
end
end


3 Answers

Greg McIntyre

11/21/2003 11:51:00 PM

0

"David Naseby" <david.naseby@eonesolutions.com.au> wrote:
> Below is a quick hack to do that. Needs work. Needs redirection of IO.
> But its kinda cute.. Has issues with side effects, of course, and
> printing crapola all over the place.

Is this or something like it on the RAA? Perhaps a slightly more general
mechanism to proxy messages to the "real" object and call a
hook/callback?

--
Greg McIntyre ======[ greg@puyo.cjb.net ]===[ http://pu... ]===

T. Onoma

11/22/2003 1:22:00 AM

0

and i thought it was so radical when i wrote it yesterday

# notice if TypeErrors woud return offending respond_to? method
# in error message then it would continue to probe

class DuckHunter

def initialize
@a_r_g_s = {}
end

def a_r_g_s
@a_r_g_s
end

def d_u_c_k_c_a_l_l
begin
yield
rescue TypeError => e
self.send(e.message)
retry
end
end

def method_missing(aSym, *args)
# This will happen the first time
aSymStr = aSym.to_s
@a_r_g_s["#{aSymStr}"] = [ args.collect { |a| "#{a.class}" } ]
begin
d = %Q{
def self.#{aSymStr}(*args)
# This will happen the subsequent time
@a_r_g_s["#{aSymStr}"] } + %q{.concat [ args.collect { |a|
"#{a.class}" } ]
self
end
}
instance_eval d
rescue SyntaxError
puts "TypeError induced SyntaxError! TypeError must return respond_to
method!"
raise
end
self
end

end

# example

class TypeTest
def ameth(x)
big4 x
#---
puts x.to_i
puts x.jump(4)
puts x.do_what_ever("Duck can take it!", /\w+/)
puts x.do_what_ever("Duck can take it!", /\w+/, 42)
end
end

t = TypeTest.new

puts "\nDUCK QUACKS"

dh = DuckHunter.new
dh.d_u_c_k_c_a_l_l do
t.ameth(dh)
end

# show args
puts "\nameth:"
dh.a_r_g_s.each { |name, argpat| argpat.each { |args| puts "\t#{name}
(#{args.join(',')})" } }

# -----------

On Saturday 22 November 2003 12:52 am, Greg McIntyre wrote:
> "David Naseby" <david.naseby@eonesolutions.com.au> wrote:
> > Below is a quick hack to do that. Needs work. Needs redirection of IO.
> > But its kinda cute.. Has issues with side effects, of course, and
> > printing crapola all over the place.
>
> Is this or something like it on the RAA? Perhaps a slightly more general
> mechanism to proxy messages to the "real" object and call a
> hook/callback?

late could be added




T. Onoma

11/22/2003 11:11:00 AM

0

Sorry I forgot to post results of DuckHunter examples. (DuckHunter itself is
also included below).

DuckHunter is a concise probe providing the functionality of #duck_signature,
and has a unique feature that suggests how Ruby might proceed to cleaning up
some of its code: If a type error returns the method that was not implemented
in the error message then DuckHunter will fix and continue to probe. Using
this on a number of libraries I have discoverd that ruby has a problem in
that it allows TypeError to be raised for any reason whatsoever. There needs
to be a tighter system for raising TypeErrors, including returning the
offened method. I believe that one of the first things that needs to happen
to improve Ruby's type mechanics is to ensure that a signature probe can run
without fail on any method.

Results:

DUCK QUACKS

big4:
succ()
to_i()
>()
>(Fixnum)

DUCK QUACKS
#<DuckHunter:0x402a8738>
#<DuckHunter:0x402a8738>
#<DuckHunter:0x402a8738>
#<DuckHunter:0x402a8738>

ameth:
succ()
jump(Fixnum)
to_i()
to_i()
>()
>(Fixnum)
do_what_ever(String,Regexp)
do_what_ever(String,Regexp,Fixnum)

-t0


On Saturday 22 November 2003 02:22 am, T. Onoma wrote:
> and i thought it was so radical when i wrote it yesterday
>
> # notice if TypeErrors woud return offending respond_to? method
> # in error message then it would continue to probe
>
> class DuckHunter
>
> def initialize
> @a_r_g_s = {}
> end
>
> def a_r_g_s
> @a_r_g_s
> end
>
> def d_u_c_k_c_a_l_l
> begin
> yield
> rescue TypeError => e
> self.send(e.message)
> retry
> end
> end
>
> def method_missing(aSym, *args)
> # This will happen the first time
> aSymStr = aSym.to_s
> @a_r_g_s["#{aSymStr}"] = [ args.collect { |a| "#{a.class}" } ]
> begin
> d = %Q{
> def self.#{aSymStr}(*args)
> # This will happen the subsequent time
> @a_r_g_s["#{aSymStr}"] } + %q{.concat [ args.collect { |a|
> "#{a.class}" } ]
> self
> end
> }
> instance_eval d
> rescue SyntaxError
> puts "TypeError induced SyntaxError! TypeError must return respond_to
> method!"
> raise
> end
> self
> end
>
> end
>
> # example
>
> class TypeTest
> def ameth(x)
> big4 x
> #---
> puts x.to_i
> puts x.jump(4)
> puts x.do_what_ever("Duck can take it!", /\w+/)
> puts x.do_what_ever("Duck can take it!", /\w+/, 42)
> end
> end
>
> t = TypeTest.new
>
> puts "\nDUCK QUACKS"
>
> dh = DuckHunter.new
> dh.d_u_c_k_c_a_l_l do
> t.ameth(dh)
> end
>
> # show args
> puts "\nameth:"
> dh.a_r_g_s.each { |name, argpat| argpat.each { |args| puts "\t#{name}
> (#{args.join(',')})" } }
>
> # -----------
>
> On Saturday 22 November 2003 12:52 am, Greg McIntyre wrote:
> > "David Naseby" <david.naseby@eonesolutions.com.au> wrote:
> > > Below is a quick hack to do that. Needs work. Needs redirection of IO.
> > > But its kinda cute.. Has issues with side effects, of course, and
> > > printing crapola all over the place.
> >
> > Is this or something like it on the RAA? Perhaps a slightly more general
> > mechanism to proxy messages to the "real" object and call a
> > hook/callback?
>
> late could be added