lemon 0.9.0 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.ruby +23 -14
- data/.yardopts +6 -0
- data/Config.rb +14 -0
- data/{HISTORY.rdoc → HISTORY.md} +26 -11
- data/LICENSE.txt +27 -0
- data/README.md +42 -28
- data/SPECSHEET.md +314 -0
- data/bin/{lemonade → lemons} +0 -0
- data/lib/lemon.yml +23 -14
- data/lib/lemon/cli.rb +19 -8
- data/lib/lemon/cli/base.rb +50 -20
- data/lib/lemon/cli/generate.rb +51 -16
- data/lib/lemon/cli/lemon.ascii +84 -0
- data/lib/lemon/cli/obrother.rb +35 -0
- data/lib/lemon/cli/scaffold.rb +116 -0
- data/lib/lemon/core_ext.rb +2 -2
- data/lib/lemon/core_ext/module.rb +9 -0
- data/lib/lemon/coverage/analyzer.rb +76 -5
- data/lib/lemon/coverage/cover_unit.rb +38 -14
- data/lib/lemon/coverage/formats/verbose.rb +1 -1
- data/lib/lemon/coverage/generator.rb +196 -0
- data/lib/lemon/coverage/snapshot.rb +16 -16
- data/lib/lemon/coverage/source_parser.rb +103 -37
- data/lib/lemon/ignore_callers.rb +19 -0
- data/lib/lemon/test_case.rb +135 -26
- data/lib/lemon/test_class.rb +16 -3
- data/lib/lemon/test_class_method.rb +58 -0
- data/lib/lemon/test_method.rb +57 -68
- data/lib/lemon/test_module.rb +47 -44
- data/lib/lemon/test_proc.rb +28 -2
- data/lib/lemon/test_scope.rb +14 -0
- data/lib/lemon/test_setup.rb +1 -1
- data/lib/lemon/test_world.rb +7 -0
- data/{work/deprecated/features/support → spec/applique}/ae.rb +0 -0
- data/spec/coverage/{01_complete.rdoc → 01_complete.md} +3 -3
- data/spec/coverage/{02_incomplete.rdoc → 02_incomplete.md} +2 -2
- data/spec/coverage/{03_extensions.rdoc → 03_extensions.md} +2 -2
- data/try/case_scope.rb +19 -0
- metadata +50 -102
- data/.gemspec +0 -152
- data/.gitignore +0 -8
- data/.reap/digest +0 -678
- data/.reap/test.reap +0 -7
- data/Assembly +0 -37
- data/COPYING.rdoc +0 -33
- data/MANIFEST +0 -55
- data/PROFILE +0 -30
- data/Rakefile +0 -23
- data/VERSION +0 -1
- data/lib/lemon/core_ext/omission.rb +0 -18
- data/lib/lemon/generator.rb +0 -149
- data/notes/2010-05-05-coverage.rdoc +0 -47
- data/notes/2010-05-06-files-not-classes.rdoc +0 -19
- data/notes/2010-07-11-acid-testing.rdoc +0 -52
- data/notes/2010-08-02-enforcing-the-unit.md +0 -68
- data/notes/2010-08-03-new-api.md +0 -37
- data/notes/2011-07-07-nailing-down-the-nomenclature.md +0 -6
- data/site/.rsync-filter +0 -8
- data/site/assets/images/cut-lemon.png +0 -0
- data/site/assets/images/forkme.png +0 -0
- data/site/assets/images/github-logo.png +0 -0
- data/site/assets/images/lemon.jpg +0 -0
- data/site/assets/images/lemon.svg +0 -39
- data/site/assets/images/lemons-are-good.png +0 -0
- data/site/assets/images/opensource.png +0 -0
- data/site/assets/images/ruby-logo.png +0 -0
- data/site/assets/images/skin.jpg +0 -0
- data/site/assets/images/skin1.jpg +0 -0
- data/site/assets/images/tap.png +0 -0
- data/site/assets/images/title.png +0 -0
- data/site/assets/styles/class.css +0 -6
- data/site/assets/styles/reset.css +0 -17
- data/site/assets/styles/site.css +0 -33
- data/site/index.html +0 -218
- data/work/deprecated/command/abstract.rb +0 -29
- data/work/deprecated/command/coverage.rb +0 -115
- data/work/deprecated/command/generate.rb +0 -124
- data/work/deprecated/command/test.rb +0 -112
- data/work/deprecated/cucumber.yml +0 -3
- data/work/deprecated/features/coverage.feature +0 -65
- data/work/deprecated/features/generate.feature +0 -66
- data/work/deprecated/features/step_definitions/coverage_steps.rb +0 -1
- data/work/deprecated/features/support/aruba.rb +0 -1
- data/work/deprecated/features/test.feature +0 -67
- data/work/deprecated/model/dsl/advice.rb +0 -78
- data/work/deprecated/model/dsl/subject.rb +0 -40
- data/work/deprecated/model/main.rb +0 -87
- data/work/deprecated/model/test.rb +0 -54
- data/work/deprecated/model/test_base_dsl.rb +0 -88
- data/work/deprecated/model/test_clause.rb +0 -112
- data/work/deprecated/model/test_context.rb +0 -90
- data/work/deprecated/model/test_feature.rb +0 -128
- data/work/deprecated/model/test_scenario.rb +0 -137
- data/work/deprecated/model/test_suite.rb +0 -297
- data/work/deprecated/rake.rb +0 -103
- data/work/deprecated/test/case_coverage_analyzer.rb +0 -25
- data/work/deprecated/test/case_test_case_dsl.rb +0 -46
- data/work/deprecated/test/fixtures/case_complete.rb +0 -25
- data/work/deprecated/test/fixtures/case_inclusion.rb +0 -18
- data/work/deprecated/test/fixtures/case_incomplete.rb +0 -12
- data/work/deprecated/test/fixtures/example.rb +0 -13
- data/work/deprecated/test/fixtures/helper.rb +0 -13
- data/work/deprecated/test/runner +0 -2
- data/work/old-tests/case_example.rb +0 -15
- data/work/old-tests/feature_example.rb +0 -40
- data/work/reference/dsl2.rb +0 -140
- data/work/reference/dynamic_constant_lookup.rb +0 -76
@@ -41,7 +41,7 @@ module Lemon::CoverReports
|
|
41
41
|
|
42
42
|
#
|
43
43
|
def unit_line(unit, color)
|
44
|
-
data = [unit.to_s.ansi(color), unit.access.to_s, unit.
|
44
|
+
data = [unit.to_s.ansi(color), unit.access.to_s, unit.singleton? ? 'class method' : 'instance method']
|
45
45
|
"* %s %s %s" % data
|
46
46
|
end
|
47
47
|
|
@@ -0,0 +1,196 @@
|
|
1
|
+
module Lemon
|
2
|
+
|
3
|
+
require 'lemon/coverage/analyzer'
|
4
|
+
require 'lemon/coverage/source_parser'
|
5
|
+
|
6
|
+
# TODO: Add option to add `require <file>` for each test file genetated.
|
7
|
+
|
8
|
+
# Test Scaffold Generator.
|
9
|
+
#
|
10
|
+
class Generator
|
11
|
+
|
12
|
+
# New Scaffold Generator.
|
13
|
+
#
|
14
|
+
# @option options [Array] :files
|
15
|
+
# Ruby scripts for which to generate tests.
|
16
|
+
#
|
17
|
+
# @option options [Array] :tests
|
18
|
+
# Test files that already exist.
|
19
|
+
#
|
20
|
+
# @option options [Array] :namespaces
|
21
|
+
# List of class/module names to limit scaffolding.
|
22
|
+
#
|
23
|
+
# @option options [Boolean] :private
|
24
|
+
# Include private methods in scaffolding.
|
25
|
+
#
|
26
|
+
# @option options [Symbol] :group
|
27
|
+
# Group by `:case` or by `:file`.
|
28
|
+
#
|
29
|
+
def initialize(options={})
|
30
|
+
@files = options[:files] || []
|
31
|
+
@tests = options[:tests] || []
|
32
|
+
@group = options[:group] || :case
|
33
|
+
|
34
|
+
@namespaces = options[:namespaces]
|
35
|
+
#@coverage = options[:coverage]
|
36
|
+
@private = options[:private]
|
37
|
+
@caps = options[:caps]
|
38
|
+
|
39
|
+
#if @namespaces
|
40
|
+
# @coverage ||= :all
|
41
|
+
#else
|
42
|
+
# @coverage ||= :uncovered
|
43
|
+
#end
|
44
|
+
|
45
|
+
#@snapshot = Snapshot.capture
|
46
|
+
|
47
|
+
@analyzer = CoverageAnalyzer.new(files + tests, options)
|
48
|
+
@suite = @analyzer.suite
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
attr :files
|
53
|
+
|
54
|
+
#
|
55
|
+
attr :tests
|
56
|
+
|
57
|
+
# Group tests by `:case` or `:file`.
|
58
|
+
attr :group
|
59
|
+
|
60
|
+
# List of class and module namespaces to limit scaffolding.
|
61
|
+
attr :namespaces
|
62
|
+
|
63
|
+
# Target coverage `:all`, `:uncovered` or `:covered`.
|
64
|
+
#def coverage
|
65
|
+
# @coverage
|
66
|
+
#end
|
67
|
+
|
68
|
+
# Include private and protected methods.
|
69
|
+
def private?
|
70
|
+
@private
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns CoverageAnalyzer instance.
|
74
|
+
def analyzer
|
75
|
+
@analyzer
|
76
|
+
end
|
77
|
+
|
78
|
+
# Units in groups, by file or by case.
|
79
|
+
def grouped_units
|
80
|
+
case group
|
81
|
+
when :case
|
82
|
+
units_by_case
|
83
|
+
when :file
|
84
|
+
units_by_file
|
85
|
+
else
|
86
|
+
units_by_case # default ?
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Generate test template(s).
|
91
|
+
def generate
|
92
|
+
render_map = {}
|
93
|
+
|
94
|
+
if tests.empty?
|
95
|
+
grouped_units.each do |group, units|
|
96
|
+
units = filter(units)
|
97
|
+
render_map[group] = render(units)
|
98
|
+
end
|
99
|
+
else
|
100
|
+
uncovered_units = analyzer.uncovered
|
101
|
+
grouped_units.each do |group, units|
|
102
|
+
units = filter(units)
|
103
|
+
units = units & uncovered_units
|
104
|
+
render_map[group] = render(units)
|
105
|
+
end
|
106
|
+
#when :covered
|
107
|
+
# covered_units = analyzer.target.units
|
108
|
+
# grouped_units.each do |group, units|
|
109
|
+
# units = filter(units)
|
110
|
+
# units = units & covered_units
|
111
|
+
# map[group] = render(units)
|
112
|
+
# end
|
113
|
+
#else
|
114
|
+
# #units = Snapshot.capture(namespaces).units
|
115
|
+
# #units = (units - @snapshot.units)
|
116
|
+
end
|
117
|
+
|
118
|
+
render_map
|
119
|
+
end
|
120
|
+
|
121
|
+
# TODO: If units knew which file they came from that would make
|
122
|
+
# the code more efficient b/c then we could group after all
|
123
|
+
# filtering instead of before.
|
124
|
+
|
125
|
+
#
|
126
|
+
def units_by_case
|
127
|
+
units = []
|
128
|
+
files.each do |file|
|
129
|
+
units.concat SourceParser.parse_units(File.read(file))
|
130
|
+
end
|
131
|
+
units.group_by{ |u| u.namespace }
|
132
|
+
end
|
133
|
+
|
134
|
+
#
|
135
|
+
def units_by_file
|
136
|
+
map = {}
|
137
|
+
files.each do |file|
|
138
|
+
units = SourceParser.parse_units(File.read(file))
|
139
|
+
map[file] = units
|
140
|
+
end
|
141
|
+
map
|
142
|
+
end
|
143
|
+
|
144
|
+
# Filter targets to include only specified namespaces.
|
145
|
+
def filter(units)
|
146
|
+
return units if namespaces.nil? or namespaces.empty?
|
147
|
+
units.select do |u|
|
148
|
+
namespaces.any? do |ns|
|
149
|
+
/^#{ns}/ =~ u.namespace.to_s
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Generate code template.
|
155
|
+
def render(units)
|
156
|
+
code = []
|
157
|
+
mods = units.group_by{ |u| u.namespace }
|
158
|
+
mods.each do |mod, units|
|
159
|
+
code << "#{term_case} #{mod} do"
|
160
|
+
units.each do |unit|
|
161
|
+
next unless private? or unit.public?
|
162
|
+
if unit.singleton?
|
163
|
+
code << "\n #{term_class_method} :#{unit.method} do"
|
164
|
+
code << "\n test '' do"
|
165
|
+
code << "\n end"
|
166
|
+
code << "\n end"
|
167
|
+
else
|
168
|
+
code << "\n #{term_method} :#{unit.method} do"
|
169
|
+
code << "\n test '' do"
|
170
|
+
code << "\n end"
|
171
|
+
code << "\n end"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
code << "\nend\n"
|
175
|
+
end
|
176
|
+
code.join("\n")
|
177
|
+
end
|
178
|
+
|
179
|
+
#
|
180
|
+
def term_case
|
181
|
+
@caps ? 'TestCase' : 'test_case'
|
182
|
+
end
|
183
|
+
|
184
|
+
#
|
185
|
+
def term_class_method
|
186
|
+
@caps ? 'ClassMethod' : 'class_method'
|
187
|
+
end
|
188
|
+
|
189
|
+
#
|
190
|
+
def term_method
|
191
|
+
@caps ? 'Method' : 'method'
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
@@ -64,7 +64,7 @@ module Lemon
|
|
64
64
|
methods = mod.__send__("#{access}methods", false)
|
65
65
|
#methods -= Object.__send__("#{access}methods", true)
|
66
66
|
methods.each do |method|
|
67
|
-
@units << Unit.new(mod, method, :access=>access, :
|
67
|
+
@units << Unit.new(mod, method, :access=>access, :singleton=>true)
|
68
68
|
end
|
69
69
|
end
|
70
70
|
return @units
|
@@ -105,19 +105,19 @@ module Lemon
|
|
105
105
|
attr :method
|
106
106
|
|
107
107
|
# Is the method a "class method", rather than an instance method.
|
108
|
-
attr :
|
108
|
+
attr :singleton
|
109
109
|
|
110
110
|
def initialize(target, method, props={})
|
111
|
-
@target
|
112
|
-
@method
|
113
|
-
@
|
114
|
-
@covered
|
111
|
+
@target = target
|
112
|
+
@method = method.to_sym
|
113
|
+
@singleton = props[:singleton] ? true : false
|
114
|
+
@covered = props[:covered]
|
115
115
|
|
116
|
-
if @
|
116
|
+
if @singleton
|
117
117
|
@private = @target.private_methods.find{ |m| m.to_sym == @method }
|
118
118
|
@protected = @target.protected_methods.find{ |m| m.to_sym == @method }
|
119
119
|
else
|
120
|
-
@private
|
120
|
+
@private = @target.private_instance_methods.find{ |m| m.to_sym == @method }
|
121
121
|
@protected = @target.protected_instance_methods.find{ |m| m.to_sym == @method }
|
122
122
|
end
|
123
123
|
end
|
@@ -131,8 +131,8 @@ module Lemon
|
|
131
131
|
end
|
132
132
|
|
133
133
|
#
|
134
|
-
def
|
135
|
-
@
|
134
|
+
def singleton?
|
135
|
+
@singleton
|
136
136
|
end
|
137
137
|
|
138
138
|
# Method access is public?
|
@@ -164,12 +164,12 @@ module Lemon
|
|
164
164
|
|
165
165
|
#
|
166
166
|
def hash
|
167
|
-
@target.hash ^ @method.hash ^ @
|
167
|
+
@target.hash ^ @method.hash ^ @singleton.hash
|
168
168
|
end
|
169
169
|
|
170
170
|
#
|
171
171
|
def to_s
|
172
|
-
if @
|
172
|
+
if @singleton
|
173
173
|
"#{@target}.#{@method}"
|
174
174
|
else
|
175
175
|
"#{@target}##{@method}"
|
@@ -181,19 +181,19 @@ module Lemon
|
|
181
181
|
return false unless Unit === other
|
182
182
|
return false unless target == other.target
|
183
183
|
return false unless method == other.method
|
184
|
-
return false unless
|
184
|
+
return false unless singleton == other.singleton
|
185
185
|
return true
|
186
186
|
end
|
187
187
|
|
188
188
|
def inspect
|
189
|
-
"#{target}#{
|
189
|
+
"#{target}#{singleton ? '.' : '#'}#{method}"
|
190
190
|
end
|
191
191
|
|
192
192
|
def <=>(other)
|
193
193
|
c = (target.name <=> other.target.name)
|
194
194
|
return c unless c == 0
|
195
|
-
return -1 if
|
196
|
-
return 1 if !
|
195
|
+
return -1 if singleton && !other.singleton
|
196
|
+
return 1 if !singleton && other.singleton
|
197
197
|
method.to_s <=> other.method.to_s
|
198
198
|
end
|
199
199
|
end
|
@@ -1,6 +1,7 @@
|
|
1
|
-
|
1
|
+
require 'ripper'
|
2
|
+
require 'lemon/coverage/snapshot'
|
2
3
|
|
3
|
-
|
4
|
+
module Lemon
|
4
5
|
|
5
6
|
#
|
6
7
|
class SourceParser
|
@@ -8,24 +9,38 @@ module Lemon
|
|
8
9
|
#
|
9
10
|
# text - A String of Ruby code.
|
10
11
|
#
|
11
|
-
# Returns a Hash with each key a namespace and each value another
|
12
|
-
# Hash or a TomDoc::Scope.
|
12
|
+
# Returns a Hash with each key a namespace and each value another Hash or Scope.
|
13
13
|
def self.parse(text)
|
14
14
|
new.parse(text)
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
# Converts Ruby code into a data structure.
|
18
|
+
#
|
19
|
+
# text - A String of Ruby code.
|
20
|
+
#
|
21
|
+
# Returns an Array of Snapshot::Unit objects.
|
22
|
+
def self.parse_units(text)
|
23
|
+
sp = new
|
24
|
+
sp.parse(text)
|
25
|
+
sp.units
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_accessor :parser
|
29
|
+
|
30
|
+
attr_accessor :scopes
|
31
|
+
|
32
|
+
attr_accessor :options
|
18
33
|
|
19
34
|
# Each instance of SourceParser accumulates scopes with each
|
20
35
|
# parse, making it easy to parse an entire project in chunks but
|
21
36
|
# more difficult to parse disparate files in one go. Create
|
22
37
|
# separate instances for separate global scopes.
|
23
38
|
#
|
24
|
-
# Returns an instance of
|
39
|
+
# Returns an instance of SourceParser.
|
25
40
|
def initialize(options = {})
|
26
41
|
@options = {}
|
27
|
-
@parser = RubyParser.new
|
28
42
|
@scopes = {}
|
43
|
+
#@parser = RubyParser.new
|
29
44
|
end
|
30
45
|
|
31
46
|
# Resets the state of the parser to a pristine one. Maintains options.
|
@@ -43,14 +58,13 @@ module Lemon
|
|
43
58
|
# text - A String of Ruby code.
|
44
59
|
#
|
45
60
|
# Examples
|
46
|
-
# @parser =
|
61
|
+
# @parser = SourceParser.new
|
47
62
|
# files.each do |file|
|
48
63
|
# @parser.parse(File.read(file))
|
49
64
|
# end
|
50
65
|
# pp @parser.scopes
|
51
66
|
#
|
52
|
-
# Returns a Hash with each key a namespace and each value another
|
53
|
-
# Hash or a TomDoc::Scope.
|
67
|
+
# Returns a Hash with each key a namespace and each value another Hash or Scope.
|
54
68
|
def parse(text)
|
55
69
|
process(tokenize(sexp(text)))
|
56
70
|
@scopes
|
@@ -62,7 +76,8 @@ module Lemon
|
|
62
76
|
#
|
63
77
|
# Returns a Sexp representing the AST.
|
64
78
|
def sexp(text)
|
65
|
-
|
79
|
+
Ripper.sexp(text)
|
80
|
+
#@parser.parse(text)
|
66
81
|
end
|
67
82
|
|
68
83
|
# Converts a tokenized Array of classes, modules, and methods into
|
@@ -73,13 +88,14 @@ module Lemon
|
|
73
88
|
# scope - An optional Scope object for nested classes or modules.
|
74
89
|
#
|
75
90
|
# Returns nothing.
|
76
|
-
def process(ast, scope
|
91
|
+
def process(ast, scope=nil)
|
77
92
|
case Array(ast)[0]
|
78
93
|
when :module, :class
|
79
94
|
name = ast[1]
|
80
95
|
new_scope = Scope.new(name, ast[2])
|
81
96
|
|
82
97
|
if scope
|
98
|
+
new_scope.parent = scope
|
83
99
|
scope.scopes[name] = new_scope
|
84
100
|
elsif @scopes[name]
|
85
101
|
new_scope = @scopes[name]
|
@@ -119,22 +135,22 @@ module Lemon
|
|
119
135
|
def tokenize(node)
|
120
136
|
case Array(node)[0]
|
121
137
|
when :module
|
122
|
-
name = node[1]
|
123
|
-
[ :module, name,
|
138
|
+
name = node[1][1][1]
|
139
|
+
[ :module, name, '', tokenize(node[2]) ]
|
124
140
|
when :class
|
125
|
-
name = node[1]
|
126
|
-
[ :class, name,
|
127
|
-
when :
|
128
|
-
name = node[1]
|
141
|
+
name = node[1][1][1]
|
142
|
+
[ :class, name, '', tokenize(node[3]) ]
|
143
|
+
when :def
|
144
|
+
name = node[1][1]
|
129
145
|
args = args_for_node(node[2])
|
130
|
-
[ :imethod, name,
|
146
|
+
[ :imethod, name, '', args ]
|
131
147
|
when :defs
|
132
|
-
name = node[
|
133
|
-
args = args_for_node(node[
|
134
|
-
[ :cmethod, name,
|
148
|
+
name = node[3][1]
|
149
|
+
args = args_for_node(node[4])
|
150
|
+
[ :cmethod, name, '', args ]
|
135
151
|
when :block
|
136
152
|
tokenize(node[1..-1])
|
137
|
-
when :scope
|
153
|
+
when :program, :bodystmt, :scope
|
138
154
|
tokenize(node[1])
|
139
155
|
when Array
|
140
156
|
node.map { |n| tokenize(n) }.compact
|
@@ -143,27 +159,34 @@ module Lemon
|
|
143
159
|
|
144
160
|
# Given a method sexp, returns an array of the args.
|
145
161
|
def args_for_node(node)
|
146
|
-
Array(node)[1..-1].select
|
162
|
+
Array(node)[1..-1].select{ |arg| arg.is_a? Symbol }
|
147
163
|
end
|
148
164
|
|
149
|
-
#
|
150
|
-
|
165
|
+
#
|
166
|
+
def units
|
167
|
+
list = []
|
168
|
+
@scopes.each do |name, scope|
|
169
|
+
list.concat(scope.to_units)
|
170
|
+
end
|
171
|
+
list
|
172
|
+
end
|
173
|
+
|
174
|
+
# A Scope is a Module or Class, and may contain other scopes.
|
151
175
|
class Scope
|
152
176
|
include Enumerable
|
153
177
|
|
154
178
|
attr_accessor :name, :comment, :instance_methods, :class_methods
|
179
|
+
|
180
|
+
attr_accessor :parent
|
181
|
+
|
155
182
|
attr_accessor :scopes
|
156
183
|
|
157
|
-
def initialize(name, comment
|
158
|
-
@name
|
159
|
-
@comment
|
184
|
+
def initialize(name, comment='', instance_methods=[], class_methods=[])
|
185
|
+
@name = name
|
186
|
+
@comment = comment
|
160
187
|
@instance_methods = instance_methods
|
161
|
-
@class_methods
|
162
|
-
@scopes
|
163
|
-
end
|
164
|
-
|
165
|
-
def tomdoc
|
166
|
-
@tomdoc ||= TomDoc.new(@comment)
|
188
|
+
@class_methods = class_methods
|
189
|
+
@scopes = {}
|
167
190
|
end
|
168
191
|
|
169
192
|
def [](scope)
|
@@ -183,16 +206,59 @@ module Lemon
|
|
183
206
|
end
|
184
207
|
|
185
208
|
def inspect
|
186
|
-
scopes
|
209
|
+
scopes = @scopes.keys.join(', ')
|
187
210
|
imethods = @instance_methods.inspect
|
188
211
|
cmethods = @class_methods.inspect
|
189
212
|
|
190
213
|
"<#{name} scopes:[#{scopes}] :#{cmethods}: ##{imethods}#>"
|
191
214
|
end
|
192
215
|
|
216
|
+
#
|
217
|
+
def target
|
218
|
+
if parent
|
219
|
+
parent.target.const_get(name)
|
220
|
+
else
|
221
|
+
Object.const_get(name)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
#
|
226
|
+
def to_units
|
227
|
+
units = []
|
228
|
+
@instance_methods.each do |imethod|
|
229
|
+
units << Snapshot::Unit.new(target, imethod, :singleton=>false)
|
230
|
+
end
|
231
|
+
@class_methods.each do |imethod|
|
232
|
+
units << Snapshot::Unit.new(target, imethod, :singleton=>true)
|
233
|
+
end
|
234
|
+
@scopes.each do |name, scope|
|
235
|
+
units.concat(scope.to_units)
|
236
|
+
end
|
237
|
+
units
|
238
|
+
end
|
239
|
+
|
240
|
+
end
|
241
|
+
|
242
|
+
# A Method can be instance or class level.
|
243
|
+
class Method
|
244
|
+
attr_accessor :name, :comment, :args
|
245
|
+
|
246
|
+
def initialize(name, comment='', args=[])
|
247
|
+
@name = name
|
248
|
+
@comment = comment
|
249
|
+
@args = args || []
|
250
|
+
end
|
251
|
+
alias_method :to_s, :name
|
252
|
+
|
253
|
+
def to_sym
|
254
|
+
name.to_sym
|
255
|
+
end
|
256
|
+
|
257
|
+
def inspect
|
258
|
+
"#{name}(#{args.join(', ')})"
|
259
|
+
end
|
193
260
|
end
|
194
261
|
|
195
262
|
end
|
196
263
|
|
197
264
|
end
|
198
|
-
|