Object
ParseTree is a RubyInline-style extension that accesses and traverses the internal parse tree created by ruby.
class Example def blah return 1 + 1 end end ParseTree.new.parse_tree(Example) => [[:class, :Example, :Object, [:defn, "blah", [:scope, [:block, [:args], [:return, [:call, [:lit, 1], "+", [:array, [:lit, 1]]]]]]]]]
Initializes a ParseTree instance. Includes newline nodes if include_newlines which defaults to +$DEBUG+.
# File lib/parse_tree.rb, line 82 def initialize(include_newlines=$DEBUG) @include_newlines = include_newlines end
Front end translation method.
# File lib/parse_tree.rb, line 51 def self.translate(klass_or_str, method=nil) pt = self.new(false) case klass_or_str when String then sexp = pt.parse_tree_for_string(klass_or_str).first if method then # class, scope, block, *methods sexp.last.last[1..-1].find do |defn| defn[1] == method end else sexp end else unless method.nil? then if method.to_s =~ /^self\./ then method = method.to_s[5..-1].intern pt.parse_tree_for_method(klass_or_str, method, true) else pt.parse_tree_for_method(klass_or_str, method) end else pt.parse_tree(klass_or_str).first end end end
Main driver for ParseTree. Returns an array of arrays containing the parse tree for klasses.
Structure:
[[:class, classname, superclassname, [:defn :method1, ...], ...], ...]
NOTE: v1.0 - v1.1 had the signature (klass, meth=nil). This wasn’t used much at all and since parse_tree_for_method already existed, it was deemed more useful to expand this method to do multiple classes.
# File lib/parse_tree.rb, line 99 def parse_tree(*klasses) result = [] klasses.each do |klass| klassname = klass.name rescue '' # HACK klass.name should never be nil # Tempfile's DelegateClass(File) seems to # cause this klassname = "UnnamedClass_#{klass.object_id}" if klassname.empty? klassname = klassname.to_sym code = if Class === klass then sc = klass.superclass sc_name = ((sc.nil? or sc.name.empty?) ? "nil" : sc.name).intern [:class, klassname, [:const, sc_name]] else [:module, klassname] end method_names = [] method_names += klass.instance_methods false method_names += klass.private_instance_methods false # protected methods are included in instance_methods, go figure! method_names.sort.each do |m| r = parse_tree_for_method(klass, m.to_sym) code << r end klass.modules.each do |mod| # TODO: add a test for this damnit mod.instance_methods.each do |m| r = parse_tree_for_method(mod, m.to_sym) code << r end end klass.singleton_methods(false).sort.each do |m| code << parse_tree_for_method(klass, m.to_sym, true) end result << code end return result end
Returns the parse tree for just one method of a class klass.
Format:
[:defn, :name, :body]
# File lib/parse_tree.rb, line 149 def parse_tree_for_method(klass, method, is_cls_meth=false, verbose = true) $stderr.puts "** parse_tree_for_method(#{klass}, #{method}):" if $DEBUG old_verbose, $VERBOSE = $VERBOSE, verbose r = parse_tree_for_meth(klass, method.to_sym, is_cls_meth) r ensure $VERBOSE = old_verbose end
Returns the parse tree for a string source.
Format:
[[sexps] ... ]
# File lib/parse_tree.rb, line 165 def parse_tree_for_string(source, filename = '(string)', line = 1, verbose = true) old_verbose, $VERBOSE = $VERBOSE, verbose return parse_tree_for_str0(source, filename, line) ensure $VERBOSE = old_verbose end
# File test/test_parse_tree.rb, line 23 def process(input, verbose = nil) # TODO: remove test_method = caller[0][/\`(.*)\'/, 1] verbose = test_method =~ /mri_verbose_flag/ ? true : nil # um. kinda stupid, but cleaner case input when Array then ParseTree.translate(*input) else self.parse_tree_for_string(input, '(string)', 1, verbose).first end end
Generated with the Darkfish Rdoc Generator 2.