On Sun, 20 Aug 2006 20:37:58 +0200, Jonathan M.
[email protected]
wrote:
I guess I could look into working with a different parser but I’d prefer
Ripper.
Ah okay, I thought you were trying to get Ripper running for the first
time, for a new project. If you already have code then it might be
easier
to get Ripper working.
Anyway, here is some basic code to get methods and classes with RubyNode
(it’s really basic and doesn’t work with nested classes, just to get you
started):
Lets say we have this file:
$ cat test.rb
class A
def a
1
end
def b
2
end
end
class B
def c
3
end
end
Then this code:
require “rubynode”
require “pp”
tree = IO.read(“test.rb”).parse_to_nodes.transform
def statements(block_or_single_node)
if block_or_single_node.first == :block
block_or_single_node.last
else
[block_or_single_node] # only one statement
end
end
statements(tree).each { |s|
if s.first == :class
p s.last[:cpath]
statements(s.last[:body].last[:next]).each { |d|
if d.first == :defn
p d.last[:mid]
pp d.last[:defn]
end
}
end
}
outputs:
[:colon2, {:mid=>:A, :head=>false}]
:a
[:scope,
{:rval=>false,
:tbl=>nil,
:next=>
[:block, [[:args, {:cnt=>0, :opt=>false, :rest=>-1}], [:lit,
{:lit=>1}]]]}]
:b
[:scope,
{:rval=>false,
:tbl=>nil,
:next=>
[:block, [[:args, {:cnt=>0, :opt=>false, :rest=>-1}], [:lit,
{:lit=>2}]]]}]
[:colon2, {:mid=>:B, :head=>false}]
:c
[:scope,
{:rval=>false,
:tbl=>nil,
:next=>
[:block, [[:args, {:cnt=>0, :opt=>false, :rest=>-1}], [:lit,
{:lit=>3}]]]}]
The only thing that RubyNode or ParseTree won’t give you are the
comments and whitespace in the code.
That’s a bit of a letdown, nothing too serious. Probably easy to work
around by wrapping the IO-source.
Do you have any idea as to how memory-intensive either are?
They both wrap Ruby’s internal NODEs. ParseTree converts them into
s-expressions (nested arrays), RubyNode’s transform converts them to
something similar (see above, a mix of arrays and hashes). So they use
as
much memory as their output needs.
If you really want to avoid the transformation to s-expressions then you
can use RubyNodes directly without calling transform (see
documentation),
but that usually shouldn’t be necessary.
And btw. if you want to get the nodes without evaling the code then you
currently have to use RubyNode, ParseTree doesn’t support that (yet).
Dominik