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/lib/live_ast/evaler.rb
CHANGED
@@ -1,66 +1,32 @@
|
|
1
1
|
module LiveAST
|
2
2
|
module Evaler
|
3
3
|
class << self
|
4
|
+
include Common
|
5
|
+
|
4
6
|
def eval(parser_source, *args)
|
5
|
-
evaler_source, bind, *
|
7
|
+
evaler_source, bind, *rest = handle_args(*args)
|
6
8
|
|
7
|
-
file, line =
|
8
|
-
file =
|
9
|
+
file, line = location_for_eval(bind, *rest)
|
10
|
+
file = LiveAST.strip_token(file)
|
9
11
|
|
10
12
|
key, _ = Linker.new_cache_synced(parser_source, file, line, false)
|
11
13
|
|
12
14
|
begin
|
13
15
|
NATIVE_EVAL.call(evaler_source, bind, key, line)
|
14
16
|
rescue Exception => ex
|
15
|
-
|
17
|
+
ex.backtrace.map! { |s| LiveAST.strip_token s }
|
16
18
|
raise ex
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
20
|
-
#
|
21
|
-
# match eval's error messages
|
22
|
-
#
|
23
22
|
def handle_args(*args)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
raise TypeError,
|
30
|
-
"wrong argument type #{args[1].class} (expected Binding)"
|
31
|
-
end
|
32
|
-
args[0] = arg_to_str(args[0])
|
33
|
-
args[2] = arg_to_str(args[2]) unless args[2].nil?
|
34
|
-
args
|
35
|
-
end
|
36
|
-
|
37
|
-
def arg_to_str(arg)
|
38
|
-
begin
|
39
|
-
arg.to_str
|
40
|
-
rescue
|
41
|
-
raise TypeError, "can't convert #{arg.class} into String"
|
23
|
+
args.tap do
|
24
|
+
check_arity(args, 2..4)
|
25
|
+
args[0] = arg_to_str(args[0])
|
26
|
+
check_type(args[1], Binding)
|
27
|
+
args[2] = arg_to_str(args[2]) if args[2]
|
42
28
|
end
|
43
29
|
end
|
44
|
-
|
45
|
-
#
|
46
|
-
# match eval's behavior
|
47
|
-
#
|
48
|
-
def handle_location(bind, *location)
|
49
|
-
case location.size
|
50
|
-
when 0
|
51
|
-
NATIVE_EVAL.call("[__FILE__, __LINE__]", bind)
|
52
|
-
when 1
|
53
|
-
[location.first, 1]
|
54
|
-
else
|
55
|
-
location
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def fix_backtrace(backtrace)
|
60
|
-
backtrace.map! { |line|
|
61
|
-
LiveAST::Linker.strip_token line
|
62
|
-
}
|
63
|
-
end
|
64
30
|
end
|
65
31
|
end
|
66
32
|
end
|
data/lib/live_ast/irb_spy.rb
CHANGED
@@ -1,27 +1,33 @@
|
|
1
1
|
|
2
2
|
module LiveAST
|
3
|
+
@history = nil
|
4
|
+
|
3
5
|
module IRBSpy
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
6
|
+
class << self
|
7
|
+
attr_writer :history
|
8
|
+
|
9
|
+
def code_at(line)
|
10
|
+
unless @history
|
11
|
+
raise NotImplementedError,
|
12
|
+
"LiveAST cannot access history for this IRB input method"
|
13
|
+
end
|
14
|
+
grow = 0
|
15
|
+
begin
|
16
|
+
code = @history[line..(line + grow)].join
|
17
|
+
LiveAST.parser.new.parse(code) or raise "#{LiveAST.parser} error"
|
18
|
+
rescue
|
19
|
+
grow += 1
|
20
|
+
retry if line + grow < @history.size
|
21
|
+
raise
|
22
|
+
end
|
23
|
+
code
|
17
24
|
end
|
18
|
-
code
|
19
25
|
end
|
20
26
|
end
|
21
27
|
end
|
22
28
|
|
23
29
|
[
|
24
|
-
IRB::StdioInputMethod,
|
30
|
+
defined?(IRB::StdioInputMethod) ? IRB::StdioInputMethod : nil,
|
25
31
|
defined?(IRB::ReadlineInputMethod) ? IRB::ReadlineInputMethod : nil,
|
26
32
|
].compact.each do |klass|
|
27
33
|
klass.module_eval do
|
@@ -29,7 +35,7 @@ end
|
|
29
35
|
def gets
|
30
36
|
live_ast_original_gets.tap do
|
31
37
|
if defined?(@line)
|
32
|
-
LiveAST::IRBSpy.
|
38
|
+
LiveAST::IRBSpy.history = @line
|
33
39
|
end
|
34
40
|
end
|
35
41
|
end
|
data/lib/live_ast/linker.rb
CHANGED
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'live_ast/base'
|
2
|
+
require 'boc'
|
3
|
+
|
4
|
+
module LiveAST
|
5
|
+
module ReplaceEval
|
6
|
+
class << self
|
7
|
+
def cache
|
8
|
+
Thread.current[:_live_ast_arg_cache] ||= {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def handle_args(args)
|
12
|
+
if args.empty?
|
13
|
+
raise ArgumentError, "block not supplied"
|
14
|
+
end
|
15
|
+
|
16
|
+
args[0] = Common.arg_to_str(args[0])
|
17
|
+
|
18
|
+
unless (1..3).include? args.size
|
19
|
+
raise ArgumentError,
|
20
|
+
"wrong number of arguments: instance_eval(src) or instance_eval{..}"
|
21
|
+
end
|
22
|
+
|
23
|
+
args[1] = Common.arg_to_str(args[1]) if args[1]
|
24
|
+
end
|
25
|
+
|
26
|
+
def module_or_instance_eval(which, remote_self, bind, args)
|
27
|
+
handle_args(args)
|
28
|
+
begin
|
29
|
+
cache[:remote_self] = remote_self
|
30
|
+
cache[:args] = args
|
31
|
+
|
32
|
+
code = %{
|
33
|
+
::LiveAST::ReplaceEval.cache[:remote_self].
|
34
|
+
live_ast_original_#{which}_eval %{
|
35
|
+
::LiveAST.eval(
|
36
|
+
::LiveAST::ReplaceEval.cache[:args][0],
|
37
|
+
binding,
|
38
|
+
*::LiveAST::ReplaceEval.cache[:args][1..-1])
|
39
|
+
}
|
40
|
+
}
|
41
|
+
live_ast_original_eval(code, bind)
|
42
|
+
ensure
|
43
|
+
cache.clear
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
module Kernel
|
51
|
+
private
|
52
|
+
|
53
|
+
alias_method :live_ast_original_eval, :eval
|
54
|
+
|
55
|
+
def eval(*args)
|
56
|
+
LiveAST::Common.check_arity(args, 1..4)
|
57
|
+
LiveAST.eval(
|
58
|
+
args[0],
|
59
|
+
args[1] || Boc.value,
|
60
|
+
*LiveAST::Common.location_for_eval(*args[1..3]))
|
61
|
+
end
|
62
|
+
|
63
|
+
class << self
|
64
|
+
alias_method :live_ast_original_singleton_eval, :eval
|
65
|
+
|
66
|
+
def eval(*args)
|
67
|
+
LiveAST::Common.check_arity(args, 1..4)
|
68
|
+
LiveAST.eval(
|
69
|
+
"::Kernel.live_ast_original_instance_eval do;" << args[0] << ";end",
|
70
|
+
args[1] || Boc.value,
|
71
|
+
*LiveAST::Common.location_for_eval(*args[1..3]))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class Binding
|
77
|
+
alias_method :live_ast_original_binding_eval, :eval
|
78
|
+
|
79
|
+
def eval(*args)
|
80
|
+
LiveAST.eval(args[0], self, *args[1..-1])
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class BasicObject
|
85
|
+
alias_method :live_ast_original_instance_eval, :instance_eval
|
86
|
+
|
87
|
+
def instance_eval(*args, &block)
|
88
|
+
if block
|
89
|
+
live_ast_original_instance_eval(*args, &block)
|
90
|
+
else
|
91
|
+
::LiveAST::ReplaceEval.module_or_instance_eval(
|
92
|
+
:instance, self, ::Boc.value, args)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class Module
|
98
|
+
alias_method :live_ast_original_module_eval, :module_eval
|
99
|
+
|
100
|
+
def module_eval(*args, &block)
|
101
|
+
if block
|
102
|
+
live_ast_original_module_eval(*args, &block)
|
103
|
+
else
|
104
|
+
LiveAST::ReplaceEval.module_or_instance_eval(
|
105
|
+
:module, self, Boc.value, args)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
Boc.enable Kernel, :eval
|
111
|
+
Boc.enable Kernel.singleton_class, :eval
|
112
|
+
Boc.enable Module, :module_eval
|
113
|
+
Boc.enable BasicObject, :instance_eval
|
114
|
+
|
115
|
+
class Module
|
116
|
+
remove_method :class_eval
|
117
|
+
alias_method :class_eval, :module_eval
|
118
|
+
end
|
@@ -8,14 +8,11 @@ module Kernel
|
|
8
8
|
def raise(*args)
|
9
9
|
ex = begin
|
10
10
|
live_ast_original_raise(*args)
|
11
|
-
rescue Exception =>
|
12
|
-
|
11
|
+
rescue Exception => t
|
12
|
+
t
|
13
13
|
end
|
14
|
-
|
15
14
|
ex.backtrace.reject! { |line| line.index __FILE__ }
|
16
|
-
|
17
|
-
LiveAST::Evaler.fix_backtrace ex.backtrace
|
18
|
-
|
15
|
+
ex.backtrace.map! { |line| LiveAST.strip_token line }
|
19
16
|
live_ast_original_raise ex
|
20
17
|
end
|
21
18
|
end
|
data/lib/live_ast/version.rb
CHANGED
data/test/backtrace_test.rb
CHANGED
@@ -136,7 +136,7 @@ define_unsorted_test_case "BacktraceTest", RegularTest do
|
|
136
136
|
orig_top = exception_backtrace { orig.call }.first
|
137
137
|
live_top = exception_backtrace { live.call }.first
|
138
138
|
|
139
|
-
assert_equal orig_top, LiveAST
|
139
|
+
assert_equal orig_top, LiveAST.strip_token(live_top)
|
140
140
|
|
141
141
|
if will_succeed
|
142
142
|
assert_equal orig_top, live_top
|
data/test/encoding_test.rb
CHANGED
@@ -45,7 +45,7 @@ class AllEncodingTest < RegularTest
|
|
45
45
|
|
46
46
|
def test_bad
|
47
47
|
orig = assert_raises ArgumentError do
|
48
|
-
|
48
|
+
live_ast_original_load "./test/encoding_test/bad.rb"
|
49
49
|
end
|
50
50
|
live = assert_raises ArgumentError do
|
51
51
|
LiveAST.load "./test/encoding_test/bad.rb"
|
data/test/main.rb
CHANGED
@@ -24,7 +24,7 @@ class JLMiniTest < MiniTest::Unit::TestCase
|
|
24
24
|
if onlies.empty?
|
25
25
|
default
|
26
26
|
else
|
27
|
-
puts "\
|
27
|
+
puts "\nNOTE: running ONLY *__only tests for #{self}"
|
28
28
|
onlies
|
29
29
|
end
|
30
30
|
end
|
@@ -48,26 +48,16 @@ class JLMiniTest < MiniTest::Unit::TestCase
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def assert_nothing_raised
|
51
|
-
assert_equal 3, 3
|
52
51
|
yield
|
52
|
+
assert_nil nil
|
53
53
|
rescue => ex
|
54
54
|
raise MiniTest::Assertion,
|
55
55
|
exception_details(ex, "Expected nothing raised, but got:")
|
56
56
|
end
|
57
57
|
|
58
58
|
%w[
|
59
|
-
empty
|
60
|
-
|
61
|
-
in_delta
|
62
|
-
in_epsilon
|
63
|
-
includes
|
64
|
-
instance_of
|
65
|
-
kind_of
|
66
|
-
match
|
67
|
-
nil
|
68
|
-
operator
|
69
|
-
respond_to
|
70
|
-
same
|
59
|
+
empty equal in_delta in_epsilon includes instance_of
|
60
|
+
kind_of match nil operator respond_to same
|
71
61
|
].each { |name|
|
72
62
|
alias_method "assert_not_#{name}", "refute_#{name}"
|
73
63
|
}
|
@@ -122,3 +112,27 @@ class RegularTest < BaseTest
|
|
122
112
|
require 'live_ast'
|
123
113
|
end
|
124
114
|
end
|
115
|
+
|
116
|
+
class ReplaceEvalTest < BaseTest
|
117
|
+
def initialize(*args)
|
118
|
+
super
|
119
|
+
ok = begin
|
120
|
+
require 'live_ast/full'
|
121
|
+
true
|
122
|
+
rescue LoadError
|
123
|
+
if RUBY_ENGINE == "ruby"
|
124
|
+
raise "need: gem install boc"
|
125
|
+
end
|
126
|
+
false
|
127
|
+
end
|
128
|
+
|
129
|
+
unless ok
|
130
|
+
self.class.class_eval do
|
131
|
+
instance_methods(false).each do |m|
|
132
|
+
remove_method(m)
|
133
|
+
define_method(m) { }
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
data/test/readme_test.rb
CHANGED
@@ -5,9 +5,9 @@ if LiveAST.parser::Test.respond_to?(:unified_sexp?) and
|
|
5
5
|
LiveAST.parser::Test.unified_sexp?
|
6
6
|
sections = [
|
7
7
|
"Synopsis",
|
8
|
-
"Loading Source",
|
9
|
-
"Noninvasive Interface",
|
10
8
|
"+to_ruby+",
|
9
|
+
"Noninvasive Interface",
|
10
|
+
"Pure Ruby and +ast_eval+",
|
11
11
|
]
|
12
12
|
|
13
13
|
Levitate.doc_to_test("README.rdoc", *sections)
|