On 3/30/07, Kristoffer LundñÏ <kristoffer.lunden / gmail.com> wrote: > On 3/31/07, Nasir Khan <rubylearner / gmail.com> wrote: > > Anyway, there could be several uses for such a thing. Simplest use case > > would be a RAILS like (but not RAILS) situation where a controller is > > deployed on a running server which (controller) optionally comes as a string > > enveloped in a protocol message, this string is evaled and the controller is > > instatiated but the system also needs to maintain meta information including > > the name of the controller just deployed, which defaults to the fully > > qualified name of the class. > > My use case is similar. > > > > Here's one way to capture that info as it's evaled. Not thread-safe > as-is. Not even sure if it's useful at all, but I was a bit curious. > There's more ways to do this, of course, especially depending on when > you want to capture this info. > > str = <<EOF > module A > class B > def b > puts "hello" > end > end > end > EOF > > set_trace_func proc {|event, file, line, id, binding, classname| > return unless event == 'class' > name = eval('self.class == Class && Module.nesting[0]', binding) > if name > # Do something with name > end > } > > eval(str) > > set_trace_func(nil) I like his idea of evaluating the string in the context of a 'sandbox' module, here's a refinement which does that. It strips off the throwaway module since I assume that he's doing this to pre-flight check actually re-running the code again after scanning it. I also check to see if the trace function is running on the originating thread, there are still thread safety issues since another thread might also be using set_trace_func. Another way to approach this would be to set and reset Thread.critical, but it doesn't solve the second problem since there doesn't seem to be a way to stack trace functions. rick@bill:/public/rubyscripts$ cat find_classes.rb def classes_defined_in(str) begin this_thread = Thread.current result = [] set_trace_func(lambda do |event, file, line, id, binding, classname| return unless Thread.current == this_thread return unless event == 'class' name = eval('self.class == Class && Module.nesting[0]',binding) result << name.to_s.split(/::/,2)[1] if name end) ensure Module.new.module_eval(str) set_trace_func(nil) end result end str = <<EOF module M1 class C1 def c puts "hello" end end module M2 class C2 end end end module M3 class C3 end end EOF p classes_defined_in(str) rick@bill:/public/rubyscripts$ ruby find_classes.rb ["M1::C1", "M1::M2::C2", "M3::C3"] -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/