Class: Lemon::SourceParser
- Inherits:
-
Object
- Object
- Lemon::SourceParser
- Defined in:
- lib/lemon/coverage/source_parser.rb
Defined Under Namespace
Instance Attribute Summary collapse
-
#options ⇒ Object
Returns the value of attribute options.
-
#parser ⇒ Object
Returns the value of attribute parser.
-
#scopes ⇒ Object
Returns the value of attribute scopes.
Class Method Summary collapse
-
.parse(text) ⇒ Object
Converts Ruby code into a data structure.
-
.parse_units(text) ⇒ Object
Converts Ruby code into a data structure.
Instance Method Summary collapse
-
#args_for_node(node) ⇒ Object
Given a method sexp, returns an array of the args.
-
#initialize(options = {}) ⇒ SourceParser
constructor
Each instance of SourceParser accumulates scopes with each parse, making it easy to parse an entire project in chunks but more difficult to parse disparate files in one go.
-
#parse(text) ⇒ Object
Converts Ruby code into a data structure.
-
#process(ast, scope = nil) ⇒ Object
Converts a tokenized Array of classes, modules, and methods into Scopes and Methods, adding them to the @scopes instance variable as it works.
-
#reset ⇒ Object
Resets the state of the parser to a pristine one.
-
#sexp(text) ⇒ Object
Converts Ruby sourcecode into an AST.
-
#tokenize(node) ⇒ Object
Converts a Ruby AST-style Sexp into an Array of more useful tokens.
- #units ⇒ Object
Constructor Details
#initialize(options = {}) ⇒ SourceParser
Each instance of SourceParser accumulates scopes with each parse, making it easy to parse an entire project in chunks but more difficult to parse disparate files in one go. Create separate instances for separate global scopes.
Returns an instance of SourceParser.
40 41 42 43 44 |
# File 'lib/lemon/coverage/source_parser.rb', line 40 def initialize( = {}) @options = {} @scopes = {} #@parser = RubyParser.new end |
Instance Attribute Details
#options ⇒ Object
Returns the value of attribute options.
32 33 34 |
# File 'lib/lemon/coverage/source_parser.rb', line 32 def @options end |
#parser ⇒ Object
Returns the value of attribute parser.
28 29 30 |
# File 'lib/lemon/coverage/source_parser.rb', line 28 def parser @parser end |
#scopes ⇒ Object
Returns the value of attribute scopes.
30 31 32 |
# File 'lib/lemon/coverage/source_parser.rb', line 30 def scopes @scopes end |
Class Method Details
.parse(text) ⇒ Object
Converts Ruby code into a data structure.
text - A String of Ruby code.
Returns a Hash with each key a namespace and each value another Hash or Scope.
13 14 15 |
# File 'lib/lemon/coverage/source_parser.rb', line 13 def self.parse(text) new.parse(text) end |
.parse_units(text) ⇒ Object
Converts Ruby code into a data structure.
text - A String of Ruby code.
Returns an Array of Snapshot::Unit objects.
22 23 24 25 26 |
# File 'lib/lemon/coverage/source_parser.rb', line 22 def self.parse_units(text) sp = new sp.parse(text) sp.units end |
Instance Method Details
#args_for_node(node) ⇒ Object
Given a method sexp, returns an array of the args.
161 162 163 |
# File 'lib/lemon/coverage/source_parser.rb', line 161 def args_for_node(node) Array(node)[1..-1].select{ |arg| arg.is_a? Symbol } end |
#parse(text) ⇒ Object
Converts Ruby code into a data structure. Note that at the instance level scopes accumulate, which makes it easy to parse multiple files in a single project but harder to parse files that have no connection.
text - A String of Ruby code.
Examples
@parser = SourceParser.new
files.each do |file|
@parser.parse(File.read(file))
end
pp @parser.scopes
Returns a Hash with each key a namespace and each value another Hash or Scope.
68 69 70 71 |
# File 'lib/lemon/coverage/source_parser.rb', line 68 def parse(text) process(tokenize(sexp(text))) @scopes end |
#process(ast, scope = nil) ⇒ Object
Converts a tokenized Array of classes, modules, and methods into Scopes and Methods, adding them to the @scopes instance variable as it works.
ast - Tokenized Array produced by calling ‘tokenize`. scope - An optional Scope object for nested classes or modules.
Returns nothing.
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/lemon/coverage/source_parser.rb', line 91 def process(ast, scope=nil) case Array(ast)[0] when :module, :class name = ast[1] new_scope = Scope.new(name, ast[2]) if scope new_scope.parent = scope scope.scopes[name] = new_scope elsif @scopes[name] new_scope = @scopes[name] else @scopes[name] = new_scope end process(ast[3], new_scope) when :imethod ast.shift scope.instance_methods << Method.new(*ast) when :cmethod ast.shift scope.class_methods << Method.new(*ast) when Array ast.map { |a| process(a, scope) } end end |
#reset ⇒ Object
Resets the state of the parser to a pristine one. Maintains options.
Returns nothing.
49 50 51 |
# File 'lib/lemon/coverage/source_parser.rb', line 49 def reset initialize(@options) end |
#sexp(text) ⇒ Object
Converts Ruby sourcecode into an AST.
text - A String of Ruby source.
Returns a Sexp representing the AST.
78 79 80 81 |
# File 'lib/lemon/coverage/source_parser.rb', line 78 def sexp(text) Ripper.sexp(text) #@parser.parse(text) end |
#tokenize(node) ⇒ Object
Converts a Ruby AST-style Sexp into an Array of more useful tokens.
node - A Ruby AST Sexp or Array
Examples
[:module, :Math, "",
[:class, :Multiplexer, "# Class Comment",
[:cmethod,
:multiplex, "# Class Method Comment", [:text]],
[:imethod,
:multiplex, "# Instance Method Comment", [:text, :count]]]]
# In others words:
# [ :type, :name, :comment, other ]
Returns an Array in the above format.
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/lemon/coverage/source_parser.rb', line 135 def tokenize(node) case Array(node)[0] when :module name = node[1][1][1] [ :module, name, '', tokenize(node[2]) ] when :class name = node[1][1][1] [ :class, name, '', tokenize(node[3]) ] when :def name = node[1][1] args = args_for_node(node[2]) [ :imethod, name, '', args ] when :defs name = node[3][1] args = args_for_node(node[4]) [ :cmethod, name, '', args ] when :block tokenize(node[1..-1]) when :program, :bodystmt, :scope tokenize(node[1]) when Array node.map { |n| tokenize(n) }.compact end end |
#units ⇒ Object
166 167 168 169 170 171 172 |
# File 'lib/lemon/coverage/source_parser.rb', line 166 def units list = [] @scopes.each do |name, scope| list.concat(scope.to_units) end list end |