live_ast 0.6.3 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|