live_ast 0.6.3 → 0.7.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.
- data/CHANGES.rdoc +9 -0
- data/MANIFEST +5 -0
- data/README.rdoc +118 -122
- data/Rakefile +3 -5
- data/devel/levitate.rb +57 -27
- data/lib/live_ast/base.rb +8 -0
- data/lib/live_ast/common.rb +48 -0
- data/lib/live_ast/evaler.rb +11 -45
- data/lib/live_ast/full.rb +2 -0
- data/lib/live_ast/irb_spy.rb +22 -16
- data/lib/live_ast/linker.rb +0 -4
- data/lib/live_ast/replace_eval.rb +118 -0
- data/lib/live_ast/replace_raise.rb +3 -6
- data/lib/live_ast/version.rb +1 -1
- data/test/backtrace_test.rb +1 -1
- data/test/encoding_test.rb +1 -1
- data/test/main.rb +28 -14
- data/test/readme_test.rb +2 -2
- data/test/replace_eval_test.rb +376 -0
- data/test/rubyspec_test.rb +28 -0
- metadata +17 -6
data/CHANGES.rdoc
CHANGED
@@ -1,6 +1,15 @@
|
|
1
1
|
|
2
2
|
= live_ast Changes
|
3
3
|
|
4
|
+
== Version 0.7.0
|
5
|
+
|
6
|
+
* eval replacement option now included in the gem
|
7
|
+
* new 'boc' gem for eval replacement -- no more syntax restrictions
|
8
|
+
* add require 'live_ast/full' -- shortcut for 'live_ast' + 'live_ast/replace_eval'
|
9
|
+
* rubyspec conformance for require 'live_ast/full'
|
10
|
+
* added required_ruby_version to gemspec
|
11
|
+
* fixed error when IRB is partially required
|
12
|
+
|
4
13
|
== Version 0.6.3
|
5
14
|
|
6
15
|
* minor change for Ruby 1.9.3
|
data/MANIFEST
CHANGED
@@ -7,12 +7,15 @@ lib/live_ast.rb
|
|
7
7
|
lib/live_ast/ast_eval.rb
|
8
8
|
lib/live_ast/ast_load.rb
|
9
9
|
lib/live_ast/base.rb
|
10
|
+
lib/live_ast/common.rb
|
10
11
|
lib/live_ast/error.rb
|
11
12
|
lib/live_ast/evaler.rb
|
13
|
+
lib/live_ast/full.rb
|
12
14
|
lib/live_ast/irb_spy.rb
|
13
15
|
lib/live_ast/linker.rb
|
14
16
|
lib/live_ast/loader.rb
|
15
17
|
lib/live_ast/reader.rb
|
18
|
+
lib/live_ast/replace_eval.rb
|
16
19
|
lib/live_ast/replace_load.rb
|
17
20
|
lib/live_ast/replace_raise.rb
|
18
21
|
lib/live_ast/to_ast.rb
|
@@ -53,6 +56,8 @@ test/readme_test.rb
|
|
53
56
|
test/recursive_eval_test.rb
|
54
57
|
test/redefine_method_test.rb
|
55
58
|
test/reload_test.rb
|
59
|
+
test/replace_eval_test.rb
|
60
|
+
test/rubyspec_test.rb
|
56
61
|
test/stdlib_test.rb
|
57
62
|
test/thread_test.rb
|
58
63
|
test/to_ast_feature_test.rb
|
data/README.rdoc
CHANGED
@@ -3,8 +3,7 @@
|
|
3
3
|
|
4
4
|
== Summary
|
5
5
|
|
6
|
-
|
7
|
-
methods and procs.
|
6
|
+
Live abstract syntax trees of methods and procs.
|
8
7
|
|
9
8
|
== Synopsis
|
10
9
|
|
@@ -18,15 +17,12 @@ methods and procs.
|
|
18
17
|
|
19
18
|
#### ASTs of methods
|
20
19
|
|
21
|
-
|
22
|
-
|
23
|
-
p m.to_ast
|
20
|
+
p Greet.instance_method(:default).to_ast
|
24
21
|
# => s(:defn, :default, s(:args), s(:scope, s(:block, s(:str, "hello"))))
|
25
22
|
|
26
23
|
#### ASTs of lambdas, procs, blocks
|
27
24
|
|
28
25
|
f = lambda { "foo" }
|
29
|
-
|
30
26
|
p f.to_ast
|
31
27
|
# => s(:iter, s(:call, nil, :lambda, s(:arglist)), nil, s(:str, "foo"))
|
32
28
|
|
@@ -39,18 +35,27 @@ methods and procs.
|
|
39
35
|
"bar"
|
40
36
|
end
|
41
37
|
|
42
|
-
#### ASTs from dynamic code
|
38
|
+
#### ASTs from dynamic code -- fully integrated version
|
43
39
|
|
44
|
-
|
40
|
+
require 'live_ast/full'
|
45
41
|
|
42
|
+
f = eval "lambda { 'dynamic1' }"
|
46
43
|
p f.to_ast
|
47
|
-
# => s(:iter, s(:call, nil, :lambda, s(:arglist)), nil, s(:str, "
|
44
|
+
# => s(:iter, s(:call, nil, :lambda, s(:arglist)), nil, s(:str, "dynamic1"))
|
45
|
+
|
46
|
+
eval "def g ; 'dynamic2' ; end"
|
47
|
+
p method(:g).to_ast
|
48
|
+
# => s(:defn, :g, s(:args), s(:scope, s(:block, s(:str, "dynamic2"))))
|
49
|
+
|
50
|
+
#### ASTs from dynamic code -- pure ruby version
|
48
51
|
|
49
|
-
ast_eval "
|
50
|
-
|
52
|
+
u = ast_eval "lambda { 'dynamic3' }", binding
|
53
|
+
p u.to_ast
|
54
|
+
# => s(:iter, s(:call, nil, :lambda, s(:arglist)), nil, s(:str, "dynamic3"))
|
51
55
|
|
52
|
-
|
53
|
-
|
56
|
+
ast_eval "def v ; 'dynamic4' ; end", binding
|
57
|
+
p method(:v).to_ast
|
58
|
+
# => s(:defn, :v, s(:args), s(:scope, s(:block, s(:str, "dynamic4"))))
|
54
59
|
|
55
60
|
== Install
|
56
61
|
|
@@ -64,20 +69,19 @@ Or from inside an unpacked .tgz download, <code>rake install</code> /
|
|
64
69
|
LiveAST enables a program to find the ASTs of objects created by
|
65
70
|
dynamically generated code. It may be used in a strictly noninvasive
|
66
71
|
manner, where no standard classes or methods are modified, or it may
|
67
|
-
be transparently integrated into Ruby
|
68
|
-
|
72
|
+
be transparently integrated into Ruby. The default setting is in
|
73
|
+
between.
|
69
74
|
|
70
|
-
RubyParser is
|
71
|
-
|
72
|
-
|
73
|
-
|
75
|
+
RubyParser is the default parsing engine. To replace it with Ripper,
|
76
|
+
<code>gem install live_ast_ripper</code> and then <code>require
|
77
|
+
'live_ast_ripper'</code>. A simple plug-in interface allows LiveAST to
|
78
|
+
work with any parser.
|
74
79
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
'live_ast_ripper'</code>.
|
80
|
+
The advantage of RubyParser is that it gives the traditional ParseTree
|
81
|
+
sexps used by tools such as <code>ruby2ruby</code>. The disadvantage
|
82
|
+
is that the newer Ruby 1.9 syntax is not supported. However the 1.8
|
83
|
+
syntax restriction only applies to files from which ASTs are actually
|
84
|
+
requested. All other files may use 1.9 syntax.
|
81
85
|
|
82
86
|
LiveAST is thread-safe.
|
83
87
|
|
@@ -92,15 +96,14 @@ Ruby 1.9.2 or higher is required.
|
|
92
96
|
|
93
97
|
== +to_ruby+
|
94
98
|
|
95
|
-
|
99
|
+
When the default parser is active,
|
96
100
|
|
97
101
|
require 'live_ast/to_ruby'
|
98
102
|
|
99
|
-
will
|
100
|
-
|
101
|
-
|
103
|
+
will define the +to_ruby+ method for the +Method+, +UnboundMethod+,
|
104
|
+
and +Proc+ classes. These methods are one-liners which pass the
|
105
|
+
extracted ASTs to <code>ruby2ruby</code>.
|
102
106
|
|
103
|
-
require 'live_ast'
|
104
107
|
require 'live_ast/to_ruby'
|
105
108
|
|
106
109
|
p lambda { |x, y| x + y }.to_ruby # => "lambda { |x, y| (x + y) }"
|
@@ -114,38 +117,50 @@ the extracted ASTs to +ruby2ruby+.
|
|
114
117
|
p A.instance_method(:f).to_ruby # => "def f\n \"A#f\"\nend"
|
115
118
|
|
116
119
|
In general, +to_ruby+ will hook into the unparser provided by the
|
117
|
-
parser, if one is found.
|
120
|
+
parser plug-in, if one is found.
|
118
121
|
|
119
|
-
==
|
122
|
+
== Pure Ruby and +ast_eval+
|
120
123
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
124
|
+
An essential feature of <code>require 'live_ast'</code> is that it is
|
125
|
+
implemented in pure ruby. However since pure ruby is not powerful
|
126
|
+
enough to replace +eval+, one must use +ast_eval+ instead of +eval+
|
127
|
+
for AST-accessible objects. +ast_eval+ has the same semantics as
|
128
|
+
+eval+ except that the binding argument is required.
|
125
129
|
|
126
130
|
require 'live_ast'
|
131
|
+
|
132
|
+
u = ast_eval "lambda { 'dynamic3' }", binding
|
133
|
+
p u.to_ast
|
134
|
+
# => s(:iter, s(:call, nil, :lambda, s(:arglist)), nil, s(:str, "dynamic3"))
|
127
135
|
|
128
|
-
|
129
|
-
ast_eval %{
|
130
|
-
def f
|
131
|
-
"A#f"
|
132
|
-
end
|
133
|
-
|
134
|
-
# nested evals OK
|
135
|
-
ast_eval %{
|
136
|
-
def g
|
137
|
-
"A#g"
|
138
|
-
end
|
139
|
-
}, binding
|
140
|
-
|
141
|
-
}, binding
|
142
|
-
end
|
136
|
+
== Full integration
|
143
137
|
|
144
|
-
|
145
|
-
|
138
|
+
In order for LiveAST to be transparent to the user, +eval+ must be
|
139
|
+
replaced. This requires the +boc+ gem (http://quix.github.com/boc)
|
140
|
+
which at present only targets MRI 1.9.2 (other platforms are planned).
|
141
|
+
|
142
|
+
To replace +eval+,
|
143
|
+
|
144
|
+
% gem install boc
|
145
|
+
|
146
|
+
and then
|
147
|
+
|
148
|
+
require 'live_ast/full'
|
146
149
|
|
147
|
-
|
148
|
-
|
150
|
+
The new AST-electrified +eval+, +instance_eval+, +module_eval+,
|
151
|
+
+class_eval+, and <code>Binding#eval</code> all pass RubySpec
|
152
|
+
(http://rubyspec.org) with the minor exception of backtraces sometimes
|
153
|
+
not matching that of the original +eval+. See the "Backtraces" section
|
154
|
+
below for details.
|
155
|
+
|
156
|
+
require 'live_ast/full'
|
157
|
+
|
158
|
+
f = eval "lambda { 'dynamic1' }"
|
159
|
+
p f.to_ast
|
160
|
+
# => s(:iter, s(:call, nil, :lambda, s(:arglist)), nil, s(:str, "dynamic1"))
|
161
|
+
|
162
|
+
Since LiveAST itself is pure ruby, any new platforms supported by
|
163
|
+
+boc+ will automatically work with <code>live_ast/full</code>.
|
149
164
|
|
150
165
|
== Limitations
|
151
166
|
|
@@ -173,6 +188,49 @@ You can probably skip these next sections. Goodbye.
|
|
173
188
|
|
174
189
|
----
|
175
190
|
|
191
|
+
== Backtraces
|
192
|
+
|
193
|
+
+ast_eval+ is meant to be compatible with +eval+. For instance the
|
194
|
+
first line of +ast_eval+'s backtrace should be identical to that of
|
195
|
+
+eval+:
|
196
|
+
|
197
|
+
require 'live_ast'
|
198
|
+
|
199
|
+
ast_eval %{ raise "boom" }, binding
|
200
|
+
# => test.rb:3:in `<main>': boom (RuntimeError)
|
201
|
+
|
202
|
+
Let's make a slight change,
|
203
|
+
|
204
|
+
require 'live_ast'
|
205
|
+
|
206
|
+
f = ast_eval %{ lambda { raise "boom" } }, binding
|
207
|
+
f.call
|
208
|
+
# => test.rb|ast@a:3:in `block in <main>': boom (RuntimeError)
|
209
|
+
|
210
|
+
What the heck is '<code>|ast@a</code>' doing there? LiveAST's
|
211
|
+
implementation has just been exposed: each source input is assigned a
|
212
|
+
unique key which enables a Ruby object to find its own definition.
|
213
|
+
|
214
|
+
In the first case above, +ast_eval+ has removed the key from the
|
215
|
+
exception backtrace. But in the second case there is no opportunity to
|
216
|
+
remove it since +ast_eval+ has already returned.
|
217
|
+
|
218
|
+
If you find this to be problem---for example if you cannot add a
|
219
|
+
filter for the jump-to-location feature in your editor---then +raise+
|
220
|
+
may be redefined to strip these tokens,
|
221
|
+
|
222
|
+
require 'live_ast'
|
223
|
+
require 'live_ast/replace_raise'
|
224
|
+
|
225
|
+
f = ast_eval %{ lambda { raise "boom" } }, binding
|
226
|
+
f.call
|
227
|
+
# => test.rb:4:in `block in <main>': boom (RuntimeError)
|
228
|
+
|
229
|
+
However this only applies to a +raise+ call originating from Ruby
|
230
|
+
code. An exception from within a native method will likely still
|
231
|
+
contain the token in its backtrace (e.g., in MRI the exception raised
|
232
|
+
by <code>1/0</code> comes from C).
|
233
|
+
|
176
234
|
== Replacing the Parser
|
177
235
|
|
178
236
|
Despite its name, LiveAST knows nothing about ASTs. It merely reports
|
@@ -180,7 +238,7 @@ what it finds in the line-to-AST hash returned by the parser's +parse+
|
|
180
238
|
method. Replacing the parser class is therefore easy: the only
|
181
239
|
specification is that the +parse+ instance method return such a hash.
|
182
240
|
|
183
|
-
To override the default parser,
|
241
|
+
To override the default parser with your own,
|
184
242
|
|
185
243
|
LiveAST.parser = YourParser
|
186
244
|
|
@@ -274,9 +332,10 @@ paranoia; the noninvasive option may be the most appropriate.
|
|
274
332
|
|
275
333
|
+ast_eval+ and +load+ cache all incoming code, while
|
276
334
|
<code>require</code>d files are cached on a need-to-know basis. When
|
277
|
-
an AST is requested, the corresponding source is parsed and
|
278
|
-
leaving behind method and block ASTs. +to_ast+ removes an
|
279
|
-
cache and attaches it to the appropriate object (a Proc
|
335
|
+
an AST is requested, the corresponding source file is parsed and
|
336
|
+
discarded, leaving behind method and block ASTs. +to_ast+ removes an
|
337
|
+
AST from the cache and attaches it to the appropriate object (a Proc
|
338
|
+
or Module).
|
280
339
|
|
281
340
|
Ignored, unextracted ASTs will therefore linger in the cache. Since
|
282
341
|
sexps are generally small there is little need for concern unless one
|
@@ -311,69 +370,6 @@ only once. Furthermore, if a file has not been reloaded then it is
|
|
311
370
|
assumed that the file is unmodified between the moment it is
|
312
371
|
<code>require</code>d and the moment the first AST is pulled from it.
|
313
372
|
|
314
|
-
== Backtraces
|
315
|
-
|
316
|
-
+ast_eval+ is meant to be compatible with +eval+. For instance the
|
317
|
-
first line of +ast_eval+'s backtrace should be identical to that of
|
318
|
-
+eval+:
|
319
|
-
|
320
|
-
require 'live_ast'
|
321
|
-
|
322
|
-
ast_eval %{ raise "boom" }, binding
|
323
|
-
# => test.rb:3:in `<main>': boom (RuntimeError)
|
324
|
-
|
325
|
-
Let's make a slight change,
|
326
|
-
|
327
|
-
require 'live_ast'
|
328
|
-
|
329
|
-
f = ast_eval %{ lambda { raise "boom" } }, binding
|
330
|
-
f.call
|
331
|
-
# => test.rb|ast@a:3:in `block in <main>': boom (RuntimeError)
|
332
|
-
|
333
|
-
What the heck is '<code>|ast@a</code>' doing there? LiveAST's
|
334
|
-
implementation has just been exposed: each source input is assigned a
|
335
|
-
unique key which enables a Ruby object to find its own definition.
|
336
|
-
|
337
|
-
In the first case above, +ast_eval+ has removed the key from the
|
338
|
-
exception backtrace. But in the second case there is no opportunity to
|
339
|
-
remove it since +ast_eval+ has already returned.
|
340
|
-
|
341
|
-
If you find this to be problem---for example if you cannot add a
|
342
|
-
filter for the jump-to-location feature in your editor---then +raise+
|
343
|
-
may be redefined to strip these tokens,
|
344
|
-
|
345
|
-
require 'live_ast'
|
346
|
-
require 'live_ast/replace_raise'
|
347
|
-
|
348
|
-
f = ast_eval %{ lambda { raise "boom" } }, binding
|
349
|
-
f.call
|
350
|
-
# => test.rb:4:in `block in <main>': boom (RuntimeError)
|
351
|
-
|
352
|
-
However this only applies to a +raise+ call originating from Ruby
|
353
|
-
code. An exception raised within a native method will likely still
|
354
|
-
contain the token in its backtrace (e.g., in MRI the exception raised
|
355
|
-
by <code>1/0</code> comes from C). In principle this could be fixed by
|
356
|
-
having the Ruby interpreter dynamically call +raise+.
|
357
|
-
|
358
|
-
|
359
|
-
== Replacing +eval+
|
360
|
-
|
361
|
-
If +ast_eval+ did not require a binding argument then it could assume
|
362
|
-
the role of +eval+, thereby making LiveAST fully transparent to the
|
363
|
-
user. Is this possible in pure Ruby?
|
364
|
-
|
365
|
-
The only option which has been investigated thus far is MRI, which can
|
366
|
-
summon <code>Binding.of_caller</code> (recently rewritten for 1.9.2)
|
367
|
-
to fill in the missing binding argument. Unfortunately a limitation
|
368
|
-
with tracing events in MRI places a few odd restrictions on the syntax
|
369
|
-
surrounding +eval+, though all restrictions can be trivially
|
370
|
-
sidestepped. Nonetheless it does work (it passes rubyspec minus the
|
371
|
-
above backtrace issue) despite being somewhat impractical.
|
372
|
-
|
373
|
-
This (mis)feature is maintained in a separate branch named
|
374
|
-
+replace_eval+ on github (not part of the gem). For more information see
|
375
|
-
replace_eval.rb[http://github.com/quix/live_ast/blob/replace_eval/lib/live_ast/replace_eval.rb].
|
376
|
-
|
377
373
|
== Author
|
378
374
|
|
379
375
|
* James M. Lawrence < quixoticsycophant@gmail.com >
|
data/Rakefile
CHANGED
@@ -2,11 +2,11 @@ require_relative 'devel/levitate'
|
|
2
2
|
|
3
3
|
Levitate.new "live_ast" do |s|
|
4
4
|
s.developers << ["James M. Lawrence", "quixoticsycophant@gmail.com"]
|
5
|
-
s.
|
5
|
+
s.username = "quix"
|
6
6
|
s.rubyforge_info = ["quix", "liveast"]
|
7
7
|
s.camel_name = "LiveAST"
|
8
|
-
|
9
|
-
s.
|
8
|
+
s.required_ruby_version = ">= 1.9.2"
|
9
|
+
s.dependencies << ["live_ast_ruby_parser", ">= 0.6.0"]
|
10
10
|
s.rdoc_files = %w[
|
11
11
|
lib/live_ast/ast_eval.rb
|
12
12
|
lib/live_ast/base.rb
|
@@ -15,6 +15,4 @@ Levitate.new "live_ast" do |s|
|
|
15
15
|
lib/live_ast/version.rb
|
16
16
|
]
|
17
17
|
s.rdoc_options << "-a"
|
18
|
-
|
19
|
-
s.dependencies << ["live_ast_ruby_parser", ">= 0.6.0"]
|
20
18
|
end
|
data/devel/levitate.rb
CHANGED
@@ -219,31 +219,18 @@ class Levitate
|
|
219
219
|
}
|
220
220
|
contents
|
221
221
|
end
|
222
|
-
end
|
223
|
-
|
224
|
-
module InstanceEvalWithArgs
|
225
|
-
module_function
|
226
222
|
|
227
|
-
def
|
228
|
-
|
229
|
-
|
223
|
+
def instance_exec2(obj, *args, &block)
|
224
|
+
method_name = ["_", obj.object_id, "_", Thread.current.object_id].join
|
225
|
+
(class << obj ; self ; end).class_eval do
|
226
|
+
define_method method_name, &block
|
230
227
|
begin
|
231
|
-
|
228
|
+
obj.send(method_name, *args)
|
232
229
|
ensure
|
233
|
-
remove_method
|
230
|
+
remove_method method_name
|
234
231
|
end
|
235
232
|
end
|
236
233
|
end
|
237
|
-
|
238
|
-
def call_temp_method(instance, method_name, *args, &method_block)
|
239
|
-
with_temp_method(instance, method_name, method_block) {
|
240
|
-
instance.send(method_name, *args)
|
241
|
-
}
|
242
|
-
end
|
243
|
-
|
244
|
-
def instance_eval_with_args(instance, *args, &block)
|
245
|
-
call_temp_method(instance, :__temp_method, *args, &block)
|
246
|
-
end
|
247
234
|
end
|
248
235
|
|
249
236
|
include AttrLazy
|
@@ -296,6 +283,10 @@ class Levitate
|
|
296
283
|
mod.const_get(version_constant_name)
|
297
284
|
end or "0.0.0"
|
298
285
|
end
|
286
|
+
|
287
|
+
attribute :required_ruby_version do
|
288
|
+
">= 0"
|
289
|
+
end
|
299
290
|
|
300
291
|
attribute :readme_file do
|
301
292
|
"README.rdoc"
|
@@ -362,6 +353,10 @@ class Levitate
|
|
362
353
|
[]
|
363
354
|
end
|
364
355
|
|
356
|
+
attribute :extra_gemspec do
|
357
|
+
lambda { |spec| }
|
358
|
+
end
|
359
|
+
|
365
360
|
attribute :files do
|
366
361
|
if File.file? manifest_file
|
367
362
|
File.read(manifest_file).split("\n")
|
@@ -381,7 +376,7 @@ class Levitate
|
|
381
376
|
end
|
382
377
|
|
383
378
|
attribute :rdoc_title do
|
384
|
-
"#{gem_name}: #{summary}"
|
379
|
+
"#{gem_name}: #{summary}".sub(/\.\Z/, "")
|
385
380
|
end
|
386
381
|
|
387
382
|
attribute :require_paths do
|
@@ -426,6 +421,8 @@ class Levitate
|
|
426
421
|
rdoc_options
|
427
422
|
extra_rdoc_files
|
428
423
|
require_paths
|
424
|
+
required_ruby_version
|
425
|
+
extensions
|
429
426
|
].each do |param|
|
430
427
|
t = send(param) and g.send("#{param}=", t)
|
431
428
|
end
|
@@ -438,6 +435,7 @@ class Levitate
|
|
438
435
|
development_dependencies.each { |dep|
|
439
436
|
g.add_development_dependency(*dep)
|
440
437
|
}
|
438
|
+
extra_gemspec.call(g)
|
441
439
|
end
|
442
440
|
end
|
443
441
|
|
@@ -490,22 +488,22 @@ class Levitate
|
|
490
488
|
}
|
491
489
|
|
492
490
|
attribute :url do
|
493
|
-
"http://#{
|
491
|
+
"http://#{username}.github.com/#{gem_name}"
|
494
492
|
end
|
495
493
|
|
496
|
-
attribute :
|
497
|
-
raise "
|
494
|
+
attribute :username do
|
495
|
+
raise "username not set"
|
498
496
|
end
|
499
497
|
|
500
498
|
attribute :rubyforge_info do
|
501
499
|
nil
|
502
500
|
end
|
503
501
|
|
504
|
-
|
502
|
+
def authors
|
505
503
|
developers.map { |d| d[0] }
|
506
504
|
end
|
507
505
|
|
508
|
-
|
506
|
+
def email
|
509
507
|
developers.map { |d| d[1] }
|
510
508
|
end
|
511
509
|
|
@@ -521,6 +519,10 @@ class Levitate
|
|
521
519
|
[]
|
522
520
|
end
|
523
521
|
|
522
|
+
attribute :extensions do
|
523
|
+
["ext/#{gem_name}/extconf.rb"].select { |f| File.file? f }
|
524
|
+
end
|
525
|
+
|
524
526
|
def define_clean
|
525
527
|
require 'rake/clean'
|
526
528
|
task :clean do
|
@@ -800,6 +802,35 @@ class Levitate
|
|
800
802
|
puts gemspec.to_ruby
|
801
803
|
end
|
802
804
|
end
|
805
|
+
|
806
|
+
def define_extension
|
807
|
+
unless extensions.empty?
|
808
|
+
require 'rbconfig'
|
809
|
+
require 'rake/extensiontask'
|
810
|
+
|
811
|
+
Rake::ExtensionTask.new gem_name, gemspec do |ext|
|
812
|
+
ext.cross_compile = true
|
813
|
+
ext.cross_platform = 'i386-mswin32'
|
814
|
+
ext.cross_compiling do |gemspec|
|
815
|
+
gemspec.post_install_message =
|
816
|
+
"U got dat binary versionation of this gemination!"
|
817
|
+
end
|
818
|
+
end
|
819
|
+
|
820
|
+
so = "lib/#{gem_name}.#{RbConfig::CONFIG["DLEXT"]}"
|
821
|
+
if Rake::Task[so].needed?
|
822
|
+
task :test => so
|
823
|
+
end
|
824
|
+
|
825
|
+
task :cross_native_gem do
|
826
|
+
Rake::Task[:gem].reenable
|
827
|
+
Rake.application.top_level_tasks.replace %w[cross native gem]
|
828
|
+
Rake.application.top_level
|
829
|
+
end
|
830
|
+
|
831
|
+
task :gem => :cross_native_gem
|
832
|
+
end
|
833
|
+
end
|
803
834
|
|
804
835
|
def open_browser(*files)
|
805
836
|
sh(*([browser].flatten + files))
|
@@ -827,7 +858,6 @@ class Levitate
|
|
827
858
|
|
828
859
|
class << self
|
829
860
|
include Util
|
830
|
-
include InstanceEvalWithArgs
|
831
861
|
|
832
862
|
# From minitest, part of the Ruby source; by Ryan Davis.
|
833
863
|
def capture_io
|
@@ -867,7 +897,7 @@ class Levitate
|
|
867
897
|
actual = Ruby.run_file_and_capture(temp_file.path).chomp
|
868
898
|
}
|
869
899
|
|
870
|
-
|
900
|
+
instance_exec2(instance, expected, actual, index, &block)
|
871
901
|
end
|
872
902
|
|
873
903
|
def run_doc_section(file, section, instance, &block)
|
data/lib/live_ast/base.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'thread'
|
2
2
|
|
3
|
+
require 'live_ast/common'
|
3
4
|
require 'live_ast/reader'
|
4
5
|
require 'live_ast/evaler'
|
5
6
|
require 'live_ast/linker'
|
@@ -61,5 +62,12 @@ module LiveAST
|
|
61
62
|
def load(file, wrap = false) #:nodoc:
|
62
63
|
Loader.load(file, wrap)
|
63
64
|
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# strip the revision token from a string
|
68
|
+
#
|
69
|
+
def strip_token(file) #:nodoc:
|
70
|
+
file.sub(/#{Regexp.quote Linker::REVISION_TOKEN}[a-z]+/, "")
|
71
|
+
end
|
64
72
|
end
|
65
73
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
|
2
|
+
module LiveAST
|
3
|
+
module Common
|
4
|
+
module_function
|
5
|
+
|
6
|
+
def arg_to_str(arg)
|
7
|
+
begin
|
8
|
+
arg.to_str
|
9
|
+
rescue NameError
|
10
|
+
thing = if arg.nil? then nil else arg.class end
|
11
|
+
|
12
|
+
raise TypeError, "can't convert #{thing.inspect} into String"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def check_arity(args, range)
|
17
|
+
unless range.include? args.size
|
18
|
+
range = 0 if range == (0..0)
|
19
|
+
|
20
|
+
raise ArgumentError,
|
21
|
+
"wrong number of arguments (#{args.size} for #{range})"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def check_type(obj, klass)
|
26
|
+
unless obj.is_a? klass
|
27
|
+
raise TypeError, "wrong argument type #{obj.class} (expected #{klass})"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def location_for_eval(*args)
|
32
|
+
bind, *location = args
|
33
|
+
|
34
|
+
if bind
|
35
|
+
case location.size
|
36
|
+
when 0
|
37
|
+
NATIVE_EVAL.call("[__FILE__, __LINE__]", bind)
|
38
|
+
when 1
|
39
|
+
[location.first, 1]
|
40
|
+
else
|
41
|
+
location
|
42
|
+
end
|
43
|
+
else
|
44
|
+
["(eval)", 1]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|