astrolabe 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Guardfile +1 -0
- data/Rakefile +14 -1
- data/benchmark/.rubocop.yml +5 -0
- data/benchmark/benchmark_helper.rb +107 -0
- data/benchmark/performance_spec.rb +342 -0
- data/lib/astrolabe/node.rb +18 -9
- data/lib/astrolabe/version.rb +1 -1
- data/spec/astrolabe/node_spec.rb +2 -2
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b3016609691bcb111bfe66a66ff77da7e533aab
|
4
|
+
data.tar.gz: f3314ca723a831d03df024b7e5be1539a5483f76
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 59af596675bb9815ee963ab92275f636034031c2ec1e245163af0a77b3602a82cdf01072191e958d1faa746d1248a7737fe27907eae741225858d172eaf6c854
|
7
|
+
data.tar.gz: c200880804038aa30c87fe8d64f0c50d51823ef5c7c878d7bb3ad6d319238557dd47c2e8585e988efc0a18c8ba3f7a62b451739919ad5a95da1125bb0a4dc3d9
|
data/Guardfile
CHANGED
@@ -7,6 +7,7 @@ group :red_green_refactor, halt_on_fail: true do
|
|
7
7
|
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
8
8
|
watch('spec/spec_helper.rb') { 'spec' }
|
9
9
|
watch(%r{^spec/support/.+\.rb$}) { 'spec' }
|
10
|
+
watch(%r{^benchmark/.+_spec\.rb$})
|
10
11
|
end
|
11
12
|
|
12
13
|
guard :rubocop, cli: '--format fuubar' do
|
data/Rakefile
CHANGED
@@ -5,7 +5,20 @@ require 'rspec/core/rake_task'
|
|
5
5
|
require 'rubocop/rake_task'
|
6
6
|
|
7
7
|
RSpec::Core::RakeTask.new(:spec)
|
8
|
+
|
9
|
+
desc 'Run benchmark specs'
|
10
|
+
RSpec::Core::RakeTask.new(:benchmark) do |task|
|
11
|
+
task.pattern = 'benchmark/**/*_spec.rb'
|
12
|
+
task.rspec_opts = '--format documentation'
|
13
|
+
end
|
14
|
+
|
8
15
|
RuboCop::RakeTask.new(:style)
|
9
16
|
|
10
17
|
task default: %w(spec style)
|
11
|
-
|
18
|
+
|
19
|
+
if RUBY_ENGINE == 'ruby'
|
20
|
+
task ci: %w(spec style benchmark)
|
21
|
+
else
|
22
|
+
# Benchmarks on JRuby and Rubinius are not as stable as CRuby...
|
23
|
+
task ci: %w(spec style)
|
24
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
class Benchmarking
|
4
|
+
class << self
|
5
|
+
attr_accessor :warm_up
|
6
|
+
alias_method :warm_up?, :warm_up
|
7
|
+
attr_writer :loop_count
|
8
|
+
|
9
|
+
def loop_count
|
10
|
+
@loop_count ||= 100
|
11
|
+
end
|
12
|
+
|
13
|
+
def pretty_time(time)
|
14
|
+
format('%0.05f sec', time)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader :name
|
19
|
+
|
20
|
+
def initialize(name, &block)
|
21
|
+
@name = name
|
22
|
+
@process = block
|
23
|
+
end
|
24
|
+
|
25
|
+
def run
|
26
|
+
@process.call
|
27
|
+
end
|
28
|
+
|
29
|
+
def time
|
30
|
+
return @time if @time
|
31
|
+
|
32
|
+
self.class.loop_count.times { run } if self.class.warm_up?
|
33
|
+
GC.start # https://github.com/ruby/ruby/blob/v2_1_2/lib/benchmark.rb#L265
|
34
|
+
|
35
|
+
beginning = Time.now
|
36
|
+
self.class.loop_count.times { run }
|
37
|
+
ending = Time.now
|
38
|
+
|
39
|
+
@time = ending - beginning
|
40
|
+
end
|
41
|
+
|
42
|
+
def pretty_time
|
43
|
+
self.class.pretty_time(time)
|
44
|
+
end
|
45
|
+
|
46
|
+
def inspect
|
47
|
+
"#{name} (#{pretty_time})"
|
48
|
+
end
|
49
|
+
|
50
|
+
alias_method :to_s, :inspect
|
51
|
+
end
|
52
|
+
|
53
|
+
RSpec::Matchers.define :be_faster_than do |other|
|
54
|
+
match do |subject|
|
55
|
+
if @times
|
56
|
+
subject.time < (other.time / @times)
|
57
|
+
else
|
58
|
+
subject.time < other.time
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
{
|
63
|
+
twice: 2,
|
64
|
+
three_times: 3,
|
65
|
+
four_times: 4,
|
66
|
+
five_times: 5,
|
67
|
+
six_times: 6,
|
68
|
+
seven_times: 7
|
69
|
+
}.each do |name, value|
|
70
|
+
chain name do
|
71
|
+
@times = value
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
failure_message do |subject|
|
76
|
+
other_label = other.name
|
77
|
+
other_label << " / #{@times}" if @times
|
78
|
+
|
79
|
+
label_width = [subject.name, other_label].map { |label| label.length }.max
|
80
|
+
|
81
|
+
message = "#{subject.name.rjust(label_width)}: #{subject.pretty_time}\n"
|
82
|
+
|
83
|
+
if @times
|
84
|
+
message << "#{other_label.rjust(label_width)}: "
|
85
|
+
shortened_other_time = Benchmarking.pretty_time(other.time / @times)
|
86
|
+
message << "#{shortened_other_time} (#{other.pretty_time} / #{@times})"
|
87
|
+
else
|
88
|
+
message << "#{other_label.rjust(label_width)}: #{other.pretty_time}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
RSpec::Matchers.define :be_as_fast_as do |other|
|
94
|
+
margin = 1.2
|
95
|
+
|
96
|
+
match do |subject|
|
97
|
+
subject.time < (other.time * margin)
|
98
|
+
end
|
99
|
+
|
100
|
+
failure_message do |subject|
|
101
|
+
label_width = [subject, other].map { |b| b.name.length }.max
|
102
|
+
|
103
|
+
[subject, other].map do |benchmark|
|
104
|
+
"#{benchmark.name.rjust(label_width)}: #{benchmark.pretty_time}"
|
105
|
+
end.join("\n")
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,342 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require_relative 'benchmark_helper'
|
4
|
+
require 'astrolabe/node'
|
5
|
+
require 'parser/current'
|
6
|
+
|
7
|
+
describe 'performance' do
|
8
|
+
Benchmarking.warm_up = true
|
9
|
+
Benchmarking.loop_count = 1000
|
10
|
+
|
11
|
+
def generate_source(max, current_nest_level = 1)
|
12
|
+
<<-END
|
13
|
+
class SomeClass#{current_nest_level}
|
14
|
+
def some_method(foo)
|
15
|
+
do_something do |bar|
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
#{generate_source(max, current_nest_level + 1) if current_nest_level < max}
|
20
|
+
end
|
21
|
+
END
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:source) { generate_source(100) }
|
25
|
+
|
26
|
+
def create_builder_class(node_class)
|
27
|
+
Class.new(Parser::Builders::Default) do
|
28
|
+
define_method(:n) do |type, children, source_map|
|
29
|
+
node_class.new(type, children, location: source_map)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def ast_with_node_class(node_class)
|
35
|
+
buffer = Parser::Source::Buffer.new('(string)')
|
36
|
+
buffer.source = source
|
37
|
+
builder = create_builder_class(node_class).new
|
38
|
+
parser = Parser::CurrentRuby.new(builder)
|
39
|
+
parser.parse(buffer)
|
40
|
+
end
|
41
|
+
|
42
|
+
describe 'Node#each_descendant' do
|
43
|
+
class EachDescendantBenchmark < Benchmarking
|
44
|
+
def initialize(name, root_node)
|
45
|
+
@name = name
|
46
|
+
@root_node = root_node
|
47
|
+
end
|
48
|
+
|
49
|
+
def run
|
50
|
+
count = 0
|
51
|
+
|
52
|
+
@root_node.each_descendant do
|
53
|
+
count += 1
|
54
|
+
end
|
55
|
+
|
56
|
+
fail if count == 0
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
let(:current_implementation) do
|
61
|
+
EachDescendantBenchmark.new('current implementation', ast_with_node_class(Astrolabe::Node))
|
62
|
+
end
|
63
|
+
|
64
|
+
describe 'nested-yield vs. block-pass vs. proc-pass' do
|
65
|
+
let(:nested_yield) do
|
66
|
+
node_class = Class.new(Astrolabe::Node) do
|
67
|
+
def each_descendant
|
68
|
+
return to_enum(__method__) unless block_given?
|
69
|
+
|
70
|
+
each_child_node do |child_node|
|
71
|
+
yield child_node
|
72
|
+
child_node.each_descendant { |node| yield node }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
EachDescendantBenchmark.new('nested-yield', ast_with_node_class(node_class))
|
78
|
+
end
|
79
|
+
|
80
|
+
let(:block_pass) do
|
81
|
+
node_class = Class.new(Astrolabe::Node) do
|
82
|
+
def each_descendant(&block)
|
83
|
+
return to_enum(__method__) unless block_given?
|
84
|
+
|
85
|
+
each_child_node do |child_node|
|
86
|
+
yield child_node
|
87
|
+
child_node.each_descendant(&block)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
EachDescendantBenchmark.new('block-pass', ast_with_node_class(node_class))
|
93
|
+
end
|
94
|
+
|
95
|
+
let(:proc_pass) do
|
96
|
+
node_class = Class.new(Astrolabe::Node) do
|
97
|
+
# Yeah, this is ugly interface, but just for reference.
|
98
|
+
def each_descendant(proc_object = nil, &block)
|
99
|
+
return to_enum(__method__) if !block_given? && !proc_object
|
100
|
+
|
101
|
+
proc_object ||= block
|
102
|
+
|
103
|
+
each_child_node do |child_node|
|
104
|
+
proc_object.call(child_node)
|
105
|
+
child_node.each_descendant(proc_object)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
EachDescendantBenchmark.new('proc-pass', ast_with_node_class(node_class))
|
111
|
+
end
|
112
|
+
|
113
|
+
specify 'block-pass is obviously (at least 5 times) faster than nested-yield' do
|
114
|
+
expect(block_pass).to be_faster_than(nested_yield).five_times
|
115
|
+
end
|
116
|
+
|
117
|
+
specify 'block-pass is a bit faster than proc-pass' do
|
118
|
+
expect(block_pass).to be_faster_than(proc_pass)
|
119
|
+
end
|
120
|
+
|
121
|
+
describe 'current implementation' do
|
122
|
+
it 'is as fast as block-pass' do
|
123
|
+
expect(current_implementation).to be_as_fast_as(block_pass)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe 'inline code vs. delegation to #each_child_node' do
|
129
|
+
let(:inline_code) do
|
130
|
+
node_class = Class.new(Astrolabe::Node) do
|
131
|
+
def each_descendant(&block)
|
132
|
+
return to_enum(__method__) unless block_given?
|
133
|
+
|
134
|
+
children.each do |child|
|
135
|
+
next unless child.is_a?(self.class)
|
136
|
+
yield child
|
137
|
+
child.each_descendant(&block)
|
138
|
+
end
|
139
|
+
|
140
|
+
self
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
EachDescendantBenchmark.new('inline code', ast_with_node_class(node_class))
|
145
|
+
end
|
146
|
+
|
147
|
+
let(:delegation) do
|
148
|
+
node_class = Class.new(Astrolabe::Node) do
|
149
|
+
def each_descendant(&block)
|
150
|
+
return to_enum(__method__) unless block_given?
|
151
|
+
|
152
|
+
each_child_node do |child_node|
|
153
|
+
yield child_node
|
154
|
+
child_node.each_descendant(&block)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
EachDescendantBenchmark.new('delegation', ast_with_node_class(node_class))
|
160
|
+
end
|
161
|
+
|
162
|
+
specify 'inline code is relatively faster than delegation' do
|
163
|
+
expect(inline_code).to be_faster_than(delegation)
|
164
|
+
end
|
165
|
+
|
166
|
+
describe 'current implementation' do
|
167
|
+
it 'is as fast as inline code' do
|
168
|
+
expect(current_implementation).to be_as_fast_as(inline_code)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe 'Array#each vs. for-loop' do
|
174
|
+
let(:array_each) do
|
175
|
+
node_class = Class.new(Astrolabe::Node) do
|
176
|
+
def each_descendant(&block)
|
177
|
+
return to_enum(__method__) unless block_given?
|
178
|
+
|
179
|
+
children.each do |child|
|
180
|
+
next unless child.is_a?(self.class)
|
181
|
+
yield child
|
182
|
+
child.each_descendant(&block)
|
183
|
+
end
|
184
|
+
|
185
|
+
self
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
EachDescendantBenchmark.new('Array#each', ast_with_node_class(node_class))
|
190
|
+
end
|
191
|
+
|
192
|
+
let(:for_loop) do
|
193
|
+
node_class = Class.new(Astrolabe::Node) do
|
194
|
+
def each_descendant(&block)
|
195
|
+
return to_enum(__method__) unless block_given?
|
196
|
+
|
197
|
+
for child in children # rubocop:disable For
|
198
|
+
next unless child.is_a?(self.class)
|
199
|
+
yield child
|
200
|
+
child.each_descendant(&block)
|
201
|
+
end
|
202
|
+
|
203
|
+
self
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
EachDescendantBenchmark.new('for-loop', ast_with_node_class(node_class))
|
208
|
+
end
|
209
|
+
|
210
|
+
specify "there's no obvious difference between them" do
|
211
|
+
expect(array_each).to be_as_fast_as(for_loop)
|
212
|
+
end
|
213
|
+
|
214
|
+
describe 'current implementation' do
|
215
|
+
it 'is as fast as Array#each' do
|
216
|
+
expect(current_implementation).to be_as_fast_as(array_each)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe 'pure recursion vs. combination of entry and recursion methods' do
|
222
|
+
let(:pure_recursion) do
|
223
|
+
node_class = Class.new(Astrolabe::Node) do
|
224
|
+
def each_descendant(&block)
|
225
|
+
return to_enum(__method__) unless block_given?
|
226
|
+
|
227
|
+
children.each do |child|
|
228
|
+
next unless child.is_a?(self.class)
|
229
|
+
yield child
|
230
|
+
child.each_descendant(&block)
|
231
|
+
end
|
232
|
+
|
233
|
+
self
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
EachDescendantBenchmark.new('pure recursion', ast_with_node_class(node_class))
|
238
|
+
end
|
239
|
+
|
240
|
+
let(:combination) do
|
241
|
+
node_class = Class.new(Astrolabe::Node) do
|
242
|
+
def each_descendant(&block)
|
243
|
+
return to_enum(__method__) unless block_given?
|
244
|
+
visit_descendants(&block)
|
245
|
+
self
|
246
|
+
end
|
247
|
+
|
248
|
+
def visit_descendants(&block)
|
249
|
+
children.each do |child|
|
250
|
+
next unless child.is_a?(self.class)
|
251
|
+
yield child
|
252
|
+
child.visit_descendants(&block)
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
EachDescendantBenchmark.new('combination', ast_with_node_class(node_class))
|
258
|
+
end
|
259
|
+
|
260
|
+
specify 'combination is faster than pure recursion' do
|
261
|
+
expect(combination).to be_faster_than(pure_recursion)
|
262
|
+
end
|
263
|
+
|
264
|
+
describe 'current implementation' do
|
265
|
+
it 'is as fast as combination' do
|
266
|
+
expect(current_implementation).to be_as_fast_as(combination)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
describe 'Node#each_ancestor' do
|
273
|
+
class EachAncestorBenchmark < Benchmarking
|
274
|
+
def initialize(name, root_node)
|
275
|
+
@name = name
|
276
|
+
@deepest_node = root_node.each_node.max_by { |node| node.each_ancestor.count }
|
277
|
+
end
|
278
|
+
|
279
|
+
def run
|
280
|
+
count = 0
|
281
|
+
|
282
|
+
@deepest_node.each_ancestor do
|
283
|
+
count += 1
|
284
|
+
end
|
285
|
+
|
286
|
+
fail if count == 0
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
let(:current_implementation) do
|
291
|
+
EachAncestorBenchmark.new('current implementation', ast_with_node_class(Astrolabe::Node))
|
292
|
+
end
|
293
|
+
|
294
|
+
describe 'recursion vs. while-loop' do
|
295
|
+
let(:while_loop) do
|
296
|
+
node_class = Class.new(Astrolabe::Node) do
|
297
|
+
def each_ancestor
|
298
|
+
return to_enum(__method__) unless block_given?
|
299
|
+
|
300
|
+
last_node = self
|
301
|
+
|
302
|
+
while (current_node = last_node.parent)
|
303
|
+
yield current_node
|
304
|
+
last_node = current_node
|
305
|
+
end
|
306
|
+
|
307
|
+
self
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
EachAncestorBenchmark.new('while-loop', ast_with_node_class(node_class))
|
312
|
+
end
|
313
|
+
|
314
|
+
let(:recursion) do
|
315
|
+
node_class = Class.new(Astrolabe::Node) do
|
316
|
+
def each_ancestor(&block)
|
317
|
+
return to_enum(__method__) unless block_given?
|
318
|
+
|
319
|
+
if parent
|
320
|
+
yield parent
|
321
|
+
parent.each_ancestor(&block)
|
322
|
+
end
|
323
|
+
|
324
|
+
self
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
EachAncestorBenchmark.new('recursion', ast_with_node_class(node_class))
|
329
|
+
end
|
330
|
+
|
331
|
+
specify 'while-loop is faster than recursion' do
|
332
|
+
expect(while_loop).to be_faster_than(recursion)
|
333
|
+
end
|
334
|
+
|
335
|
+
describe 'current implementation' do
|
336
|
+
it 'is as fast as while-loop' do
|
337
|
+
expect(current_implementation).to be_as_fast_as(while_loop)
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
data/lib/astrolabe/node.rb
CHANGED
@@ -69,12 +69,14 @@ module Astrolabe
|
|
69
69
|
# @yieldparam [Node] node each ancestor node
|
70
70
|
# @return [self] if a block is given
|
71
71
|
# @return [Enumerator] if no block is given
|
72
|
-
def each_ancestor
|
72
|
+
def each_ancestor
|
73
73
|
return to_enum(__method__) unless block_given?
|
74
74
|
|
75
|
-
|
76
|
-
|
77
|
-
|
75
|
+
last_node = self
|
76
|
+
|
77
|
+
while (current_node = last_node.parent)
|
78
|
+
yield current_node
|
79
|
+
last_node = current_node
|
78
80
|
end
|
79
81
|
|
80
82
|
self
|
@@ -108,11 +110,8 @@ module Astrolabe
|
|
108
110
|
# @return [Enumerator] if no block is given
|
109
111
|
def each_descendant(&block)
|
110
112
|
return to_enum(__method__) unless block_given?
|
111
|
-
|
112
|
-
|
113
|
-
yield child_node
|
114
|
-
child_node.each_descendant(&block)
|
115
|
-
end
|
113
|
+
visit_descendants(&block)
|
114
|
+
self
|
116
115
|
end
|
117
116
|
|
118
117
|
# Calls the given block for the receiver and each descendant node with depth first order.
|
@@ -129,5 +128,15 @@ module Astrolabe
|
|
129
128
|
yield self
|
130
129
|
each_descendant(&block)
|
131
130
|
end
|
131
|
+
|
132
|
+
protected
|
133
|
+
|
134
|
+
def visit_descendants(&block)
|
135
|
+
children.each do |child|
|
136
|
+
next unless child.is_a?(Node)
|
137
|
+
yield child
|
138
|
+
child.visit_descendants(&block)
|
139
|
+
end
|
140
|
+
end
|
132
141
|
end
|
133
142
|
end
|
data/lib/astrolabe/version.rb
CHANGED
data/spec/astrolabe/node_spec.rb
CHANGED
@@ -17,7 +17,7 @@ module Astrolabe
|
|
17
17
|
# (arg :arg_b))
|
18
18
|
# (send nil :do_something))
|
19
19
|
|
20
|
-
context '
|
20
|
+
context 'with a non-root node' do
|
21
21
|
let(:target_node) { root_node.each_node.find(&:args_type?) }
|
22
22
|
|
23
23
|
it 'returns the parent node' do
|
@@ -25,7 +25,7 @@ module Astrolabe
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
context '
|
28
|
+
context 'with a root node' do
|
29
29
|
it 'returns nil' do
|
30
30
|
expect(root_node.parent).to be_nil
|
31
31
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: astrolabe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yuji Nakayama
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-07-
|
11
|
+
date: 2014-07-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|
@@ -188,6 +188,9 @@ files:
|
|
188
188
|
- README.md
|
189
189
|
- Rakefile
|
190
190
|
- astrolabe.gemspec
|
191
|
+
- benchmark/.rubocop.yml
|
192
|
+
- benchmark/benchmark_helper.rb
|
193
|
+
- benchmark/performance_spec.rb
|
191
194
|
- lib/astrolabe.rb
|
192
195
|
- lib/astrolabe/builder.rb
|
193
196
|
- lib/astrolabe/node.rb
|