live_ast 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.rdoc +6 -0
- data/MANIFEST +54 -0
- data/README.rdoc +388 -0
- data/Rakefile +19 -0
- data/devel/jumpstart.rb +983 -0
- data/lib/live_ast/ast_eval.rb +13 -0
- data/lib/live_ast/ast_load.rb +15 -0
- data/lib/live_ast/base.rb +56 -0
- data/lib/live_ast/cache.rb +14 -0
- data/lib/live_ast/error.rb +30 -0
- data/lib/live_ast/evaler.rb +66 -0
- data/lib/live_ast/linker.rb +107 -0
- data/lib/live_ast/loader.rb +69 -0
- data/lib/live_ast/parser.rb +48 -0
- data/lib/live_ast/replace_load.rb +14 -0
- data/lib/live_ast/replace_raise.rb +21 -0
- data/lib/live_ast/to_ast.rb +17 -0
- data/lib/live_ast/to_ruby.rb +12 -0
- data/lib/live_ast/version.rb +3 -0
- data/lib/live_ast.rb +4 -0
- data/test/ast_eval_feature_test.rb +11 -0
- data/test/ast_load_feature_test.rb +11 -0
- data/test/backtrace_test.rb +159 -0
- data/test/covert_define_method_test.rb +23 -0
- data/test/def_test.rb +35 -0
- data/test/define_method_test.rb +41 -0
- data/test/define_singleton_method_test.rb +15 -0
- data/test/encoding_test/bad.rb +1 -0
- data/test/encoding_test/cp932.rb +6 -0
- data/test/encoding_test/default.rb +5 -0
- data/test/encoding_test/eucjp.rb +6 -0
- data/test/encoding_test/koi8.rb +6 -0
- data/test/encoding_test/koi8_shebang.rb +7 -0
- data/test/encoding_test/usascii.rb +6 -0
- data/test/encoding_test/utf8.rb +6 -0
- data/test/encoding_test.rb +51 -0
- data/test/error_test.rb +115 -0
- data/test/eval_test.rb +269 -0
- data/test/flush_cache_test.rb +98 -0
- data/test/lambda_test.rb +56 -0
- data/test/load_path_test.rb +84 -0
- data/test/load_test.rb +85 -0
- data/test/noninvasive_test.rb +51 -0
- data/test/readme_test.rb +11 -0
- data/test/recursive_eval_test.rb +52 -0
- data/test/redefine_method_test.rb +83 -0
- data/test/reload_test.rb +108 -0
- data/test/shared/ast_generators.rb +124 -0
- data/test/shared/main.rb +110 -0
- data/test/stdlib_test.rb +11 -0
- data/test/thread_test.rb +44 -0
- data/test/to_ast_feature_test.rb +15 -0
- data/test/to_ruby_feature_test.rb +15 -0
- data/test/to_ruby_test.rb +86 -0
- metadata +223 -0
data/test/lambda_test.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require_relative 'shared/main'
|
2
|
+
|
3
|
+
class LambdaTest < RegularTest
|
4
|
+
def test_block_braces_multiline
|
5
|
+
block = return_block { |x, y|
|
6
|
+
x + y
|
7
|
+
}
|
8
|
+
|
9
|
+
expected = binop_block(:return_block, :+)
|
10
|
+
assert_equal expected, block.to_ast
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_block_do_end_multiline
|
14
|
+
block = return_block do |x, y|
|
15
|
+
x * y
|
16
|
+
end
|
17
|
+
|
18
|
+
expected = binop_block(:return_block, :*)
|
19
|
+
assert_equal expected, block.to_ast
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_lambda
|
23
|
+
a = lambda { |x, y| x - y }
|
24
|
+
|
25
|
+
expected = binop_block(:lambda, :-)
|
26
|
+
assert_equal expected, a.to_ast
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_proc
|
30
|
+
a = proc { |x, y| x / y }
|
31
|
+
|
32
|
+
expected = binop_block(:proc, :/)
|
33
|
+
assert_equal expected, a.to_ast
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_proc_new
|
37
|
+
a = Proc.new { |x, y| x + y }
|
38
|
+
|
39
|
+
expected = binop_proc_new(:+)
|
40
|
+
assert_equal expected, a.to_ast
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_block_braces_one_line
|
44
|
+
block = return_block { |x, y| x * y }
|
45
|
+
|
46
|
+
expected = binop_block(:return_block, :*)
|
47
|
+
assert_equal expected, block.to_ast
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_block_do_end_one_line
|
51
|
+
block = return_block do |x, y| x - y end
|
52
|
+
|
53
|
+
expected = binop_block(:return_block, :-)
|
54
|
+
assert_equal expected, block.to_ast
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require_relative 'shared/main'
|
2
|
+
|
3
|
+
class AAA_LoadPathTest < BaseTest
|
4
|
+
include FileUtils
|
5
|
+
|
6
|
+
def test_load_path
|
7
|
+
$LOAD_PATH.unshift DATA_DIR
|
8
|
+
begin
|
9
|
+
check_load
|
10
|
+
check_errors
|
11
|
+
temp_file "foo.rb" do
|
12
|
+
Dir.chdir(DATA_DIR) do
|
13
|
+
compare_load_errors("/foo.rb")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
ensure
|
17
|
+
$LOAD_PATH.shift
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_chdir
|
22
|
+
mkdir DATA_DIR, :verbose => false rescue nil
|
23
|
+
Dir.chdir(DATA_DIR) do
|
24
|
+
check_load
|
25
|
+
check_errors
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def check_load
|
30
|
+
code_1 = %{
|
31
|
+
def hello
|
32
|
+
"password"
|
33
|
+
end
|
34
|
+
}
|
35
|
+
|
36
|
+
code_2 = %{
|
37
|
+
def goodbye
|
38
|
+
"bubbleboy"
|
39
|
+
end
|
40
|
+
}
|
41
|
+
|
42
|
+
temp_file "foo.rb" do |path|
|
43
|
+
write_file(path, code_1)
|
44
|
+
|
45
|
+
Object.send(:remove_method, :hello) rescue nil
|
46
|
+
load "foo.rb"
|
47
|
+
assert_equal "password", hello
|
48
|
+
|
49
|
+
write_file path, code_2
|
50
|
+
|
51
|
+
Object.send(:remove_method, :goodbye) rescue nil
|
52
|
+
LiveAST.load "foo.rb"
|
53
|
+
assert_equal "bubbleboy", goodbye
|
54
|
+
end
|
55
|
+
ensure
|
56
|
+
Object.send(:remove_method, :hello) rescue nil
|
57
|
+
Object.send(:remove_method, :goodbye) rescue nil
|
58
|
+
end
|
59
|
+
|
60
|
+
def compare_load_errors(file)
|
61
|
+
orig = assert_raise LoadError do
|
62
|
+
load file
|
63
|
+
end
|
64
|
+
live = assert_raise LoadError do
|
65
|
+
LiveAST.load file
|
66
|
+
end
|
67
|
+
assert_equal orig.message, live.message
|
68
|
+
end
|
69
|
+
|
70
|
+
def check_errors
|
71
|
+
temp_file "foo.rb" do |path|
|
72
|
+
touch path, :verbose => false
|
73
|
+
[
|
74
|
+
"foo",
|
75
|
+
"",
|
76
|
+
"/usr",
|
77
|
+
".",
|
78
|
+
"..",
|
79
|
+
].each do |file|
|
80
|
+
compare_load_errors(file)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/test/load_test.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require_relative 'shared/main'
|
2
|
+
|
3
|
+
class AAA_LoadFileTest < BaseTest
|
4
|
+
class << self
|
5
|
+
attr_accessor :flag
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_a_no_locals_created
|
9
|
+
code = %{
|
10
|
+
AAA_LoadFileTest.flag = :code_a
|
11
|
+
FOO = 77
|
12
|
+
x = 33
|
13
|
+
y = 99
|
14
|
+
}
|
15
|
+
|
16
|
+
temp_file do |file|
|
17
|
+
write_file file, code
|
18
|
+
|
19
|
+
ret = LiveAST.load file
|
20
|
+
assert_equal true, ret
|
21
|
+
assert_equal :code_a, AAA_LoadFileTest.flag
|
22
|
+
|
23
|
+
assert_raise NameError do
|
24
|
+
eval("x", TOPLEVEL_BINDING)
|
25
|
+
end
|
26
|
+
|
27
|
+
assert_equal 77, ::FOO
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_b_no_locals_modified
|
32
|
+
code = %{
|
33
|
+
AAA_LoadFileTest.flag = :code_b
|
34
|
+
r = 55
|
35
|
+
}
|
36
|
+
|
37
|
+
temp_file do |file|
|
38
|
+
eval("r = 66", TOPLEVEL_BINDING)
|
39
|
+
|
40
|
+
write_file file, code
|
41
|
+
|
42
|
+
ret = LiveAST.load file
|
43
|
+
assert_equal true, ret
|
44
|
+
assert_equal :code_b, AAA_LoadFileTest.flag
|
45
|
+
|
46
|
+
actual = eval("r", TOPLEVEL_BINDING)
|
47
|
+
assert_equal 66, actual
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_c_wrap
|
52
|
+
code = %{
|
53
|
+
AAA_LoadFileTest.flag = :code_c
|
54
|
+
ZOOM = 111
|
55
|
+
}
|
56
|
+
|
57
|
+
temp_file do |file|
|
58
|
+
write_file file, code
|
59
|
+
|
60
|
+
ret = LiveAST.load file, true
|
61
|
+
assert_equal true, ret
|
62
|
+
assert_equal :code_c, AAA_LoadFileTest.flag
|
63
|
+
|
64
|
+
assert_raises NameError do
|
65
|
+
ZOOM
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.from_d
|
71
|
+
self.flag = :code_d
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_d_empty_locals_list
|
75
|
+
code = %{
|
76
|
+
AAA_LoadFileTest.from_d
|
77
|
+
}
|
78
|
+
|
79
|
+
temp_file do |file|
|
80
|
+
write_file file, code
|
81
|
+
LiveAST.load file
|
82
|
+
assert_equal :code_d, AAA_LoadFileTest.flag
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require_relative 'shared/main'
|
2
|
+
|
3
|
+
class AAA_NoninvasiveTest < BaseTest
|
4
|
+
def test_no_clutter
|
5
|
+
[Method, UnboundMethod, Proc].each do |klass|
|
6
|
+
assert !klass.instance_methods.include?(:to_ast)
|
7
|
+
assert !klass.instance_methods.include?(:to_ruby)
|
8
|
+
end
|
9
|
+
|
10
|
+
assert !respond_to?(:ast_eval)
|
11
|
+
assert !Kernel.respond_to?(:ast_eval)
|
12
|
+
assert !respond_to?(:ast_load)
|
13
|
+
assert !Kernel.respond_to?(:ast_load)
|
14
|
+
end
|
15
|
+
|
16
|
+
DEFINE_A = lambda do
|
17
|
+
class A
|
18
|
+
def f
|
19
|
+
"A#f"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_method
|
25
|
+
DEFINE_A.call
|
26
|
+
|
27
|
+
expected = no_arg_def(:f, "A#f")
|
28
|
+
assert_equal expected, LiveAST.ast(A.instance_method(:f))
|
29
|
+
assert_equal expected, LiveAST.ast(A.new.method(:f))
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_lambda
|
33
|
+
a = lambda { |x, y| x ** y }
|
34
|
+
|
35
|
+
assert_equal binop_block(:lambda, :**), LiveAST.ast(a)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_ast_eval
|
39
|
+
code = %{ lambda { |x, y| x / y } }
|
40
|
+
|
41
|
+
expected = binop_block(:lambda, :/)
|
42
|
+
result = LiveAST.ast(LiveAST.eval(code, binding))
|
43
|
+
assert_equal expected, result
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_bogus
|
47
|
+
assert_raises TypeError do
|
48
|
+
LiveAST.ast(99)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/test/readme_test.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require_relative 'shared/main'
|
2
|
+
|
3
|
+
class RecursiveEvalTest < RegularTest
|
4
|
+
DEFINE = lambda do
|
5
|
+
ast_eval %{
|
6
|
+
class A
|
7
|
+
ast_eval %{
|
8
|
+
def f
|
9
|
+
"A#f"
|
10
|
+
end
|
11
|
+
}, binding
|
12
|
+
|
13
|
+
ast_eval %{
|
14
|
+
ast_eval %{
|
15
|
+
remove_method :f
|
16
|
+
def f(x, y)
|
17
|
+
x + y
|
18
|
+
end
|
19
|
+
|
20
|
+
def g
|
21
|
+
"A#g"
|
22
|
+
end
|
23
|
+
}, binding
|
24
|
+
|
25
|
+
LAMBDA = ast_eval %{
|
26
|
+
lambda { |x, y| x * y }
|
27
|
+
}, binding
|
28
|
+
}, binding
|
29
|
+
end
|
30
|
+
}, binding
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_method
|
34
|
+
defined?(A) or DEFINE.call
|
35
|
+
assert_equal "#{self.class}::A", A.name
|
36
|
+
|
37
|
+
assert_equal binop_def(:f, :+),
|
38
|
+
A.instance_method(:f).to_ast
|
39
|
+
|
40
|
+
assert_equal no_arg_def(:g, "A#g"),
|
41
|
+
A.instance_method(:g).to_ast
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_lambda
|
45
|
+
defined?(A) or DEFINE.call
|
46
|
+
assert_equal "#{self.class}::A", A.name
|
47
|
+
|
48
|
+
assert_equal binop_block(:lambda, :*),
|
49
|
+
A::LAMBDA.to_ast
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require_relative 'shared/main'
|
2
|
+
|
3
|
+
class RedefineMethodTest < RegularTest
|
4
|
+
DEFINE_A = lambda do
|
5
|
+
class A
|
6
|
+
def f
|
7
|
+
"old A#f"
|
8
|
+
end
|
9
|
+
|
10
|
+
PREVIOUS_Af = instance_method(:f)
|
11
|
+
remove_method :f
|
12
|
+
|
13
|
+
def f(x, y)
|
14
|
+
x * y
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_inclass_redef
|
20
|
+
DEFINE_A.call
|
21
|
+
|
22
|
+
assert_equal binop_def(:f, :*),
|
23
|
+
A.instance_method(:f).to_ast
|
24
|
+
|
25
|
+
assert_equal no_arg_def(:f, "old A#f"),
|
26
|
+
A::PREVIOUS_Af.to_ast
|
27
|
+
end
|
28
|
+
|
29
|
+
DEFINE_B = lambda do
|
30
|
+
class B
|
31
|
+
def f
|
32
|
+
"old B#f"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_dynamic_redef
|
38
|
+
DEFINE_B.call
|
39
|
+
|
40
|
+
assert_equal "old B#f", B.new.f
|
41
|
+
assert_equal no_arg_def(:f, "old B#f"), B.instance_method(:f).to_ast
|
42
|
+
|
43
|
+
B.class_eval do
|
44
|
+
remove_method :f
|
45
|
+
define_method :f do |x, y|
|
46
|
+
x - y
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
assert_equal 11, B.new.f(44, 33)
|
51
|
+
|
52
|
+
assert_equal binop_define_method(:f, :-),
|
53
|
+
B.instance_method(:f).to_ast
|
54
|
+
end
|
55
|
+
|
56
|
+
DEFINE_C = lambda do
|
57
|
+
class C
|
58
|
+
def f
|
59
|
+
"old C#f"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_dynamic_redef_with_eval
|
65
|
+
DEFINE_C.call
|
66
|
+
|
67
|
+
assert_equal "old C#f", C.new.f
|
68
|
+
|
69
|
+
C.class_eval do
|
70
|
+
ast_eval %{
|
71
|
+
remove_method :f
|
72
|
+
define_method :f do |x, y|
|
73
|
+
x * y
|
74
|
+
end
|
75
|
+
}, binding
|
76
|
+
end
|
77
|
+
|
78
|
+
assert_equal 12, C.new.f(3, 4)
|
79
|
+
|
80
|
+
assert_equal binop_define_method(:f, :*),
|
81
|
+
C.instance_method(:f).to_ast
|
82
|
+
end
|
83
|
+
end
|
data/test/reload_test.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
require_relative 'shared/main'
|
2
|
+
|
3
|
+
class AAB_ReloadTest < BaseTest
|
4
|
+
include FileUtils
|
5
|
+
|
6
|
+
def test_reloading
|
7
|
+
raw_reload
|
8
|
+
require 'live_ast/ast_load'
|
9
|
+
noninvasive_ast_reload
|
10
|
+
require 'live_ast/replace_load'
|
11
|
+
ast_reload
|
12
|
+
end
|
13
|
+
|
14
|
+
def raw_reload
|
15
|
+
code_1 = %{
|
16
|
+
class AAB_ReloadTest::A
|
17
|
+
def f
|
18
|
+
"first A#f"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
}
|
22
|
+
|
23
|
+
code_2 = %{
|
24
|
+
class AAB_ReloadTest::A
|
25
|
+
def f
|
26
|
+
"second A#f"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
}
|
30
|
+
|
31
|
+
temp_file do |file|
|
32
|
+
write_file file, code_1
|
33
|
+
load file
|
34
|
+
|
35
|
+
LiveAST.ast(A.instance_method(:f))
|
36
|
+
|
37
|
+
write_file file, code_2
|
38
|
+
load file
|
39
|
+
|
40
|
+
# forced a raw-reload inconsistency -- verify bogus
|
41
|
+
|
42
|
+
assert_equal no_arg_def(:f, "first A#f"),
|
43
|
+
LiveAST.ast(A.instance_method(:f))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def noninvasive_ast_reload
|
48
|
+
code_1 = %{
|
49
|
+
class AAB_ReloadTest::B
|
50
|
+
def f
|
51
|
+
"first B#f"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
}
|
55
|
+
|
56
|
+
code_2 = %{
|
57
|
+
class AAB_ReloadTest::B
|
58
|
+
def f
|
59
|
+
"second B#f"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
}
|
63
|
+
|
64
|
+
temp_file do |file|
|
65
|
+
write_file file, code_1
|
66
|
+
load file
|
67
|
+
|
68
|
+
LiveAST.ast(B.instance_method(:f))
|
69
|
+
|
70
|
+
write_file file, code_2
|
71
|
+
ast_load file
|
72
|
+
|
73
|
+
assert_equal no_arg_def(:f, "second B#f"),
|
74
|
+
LiveAST.ast(B.instance_method(:f))
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def ast_reload
|
79
|
+
code_1 = %{
|
80
|
+
class AAB_ReloadTest::C
|
81
|
+
def f
|
82
|
+
"first C#f"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
}
|
86
|
+
|
87
|
+
code_2 = %{
|
88
|
+
class AAB_ReloadTest::C
|
89
|
+
def f
|
90
|
+
"second C#f"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
}
|
94
|
+
|
95
|
+
temp_file do |file|
|
96
|
+
write_file file, code_1
|
97
|
+
load file
|
98
|
+
|
99
|
+
LiveAST.ast(C.instance_method(:f))
|
100
|
+
|
101
|
+
write_file file, code_2
|
102
|
+
load file
|
103
|
+
|
104
|
+
assert_equal no_arg_def(:f, "second C#f"),
|
105
|
+
LiveAST.ast(C.instance_method(:f))
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module ASTGenerators
|
2
|
+
#
|
3
|
+
# no_arg_def(:f, "A#f") returns the ast of
|
4
|
+
#
|
5
|
+
# def f
|
6
|
+
# "A#f"
|
7
|
+
# end
|
8
|
+
#
|
9
|
+
def no_arg_def(name, ret)
|
10
|
+
s(:defn, name, s(:args), s(:scope, s(:block, s(:str, ret))))
|
11
|
+
end
|
12
|
+
|
13
|
+
#
|
14
|
+
# no_arg_def_return(no_arg_def(:f, "A#f")) == "A#f"
|
15
|
+
#
|
16
|
+
def no_arg_def_return(ast)
|
17
|
+
ast[3][1][1][1]
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# binop_def(:f, :+) returns the ast of
|
22
|
+
#
|
23
|
+
# def f(x, y)
|
24
|
+
# x + y
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
def binop_def(name, op)
|
28
|
+
s(:defn,
|
29
|
+
name,
|
30
|
+
s(:args, :x, :y),
|
31
|
+
s(:scope,
|
32
|
+
s(:block, s(:call, s(:lvar, :x), op, s(:arglist, s(:lvar, :y))))))
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# binop_define_method(:f, :*) returns the ast of
|
37
|
+
#
|
38
|
+
# define_method :f do |x, y|
|
39
|
+
# x * y
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
def binop_define_method(name, op)
|
43
|
+
s(:iter,
|
44
|
+
s(:call, nil, :define_method, s(:arglist, s(:lit, name))),
|
45
|
+
s(:masgn, s(:array, s(:lasgn, :x), s(:lasgn, :y))),
|
46
|
+
s(:call, s(:lvar, :x), op, s(:arglist, s(:lvar, :y))))
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# binop_covert_define_method(:f, :-, :my_def) returns the ast of
|
51
|
+
#
|
52
|
+
# my_def :f do |x, y|
|
53
|
+
# x - y
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
def binop_covert_define_method(name, op, covert_name)
|
57
|
+
s(:iter,
|
58
|
+
s(:call, nil, covert_name, s(:arglist, s(:lit, name))),
|
59
|
+
s(:masgn, s(:array, s(:lasgn, :x), s(:lasgn, :y))),
|
60
|
+
s(:call, s(:lvar, :x), op, s(:arglist, s(:lvar, :y))))
|
61
|
+
end
|
62
|
+
|
63
|
+
#
|
64
|
+
# binop_define_method_with_var(:method_name, :/) returns the ast of
|
65
|
+
#
|
66
|
+
# define_method method_name do |x, y|
|
67
|
+
# x / y
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
def binop_define_method_with_var(name, op)
|
71
|
+
s(:iter,
|
72
|
+
s(:call, nil, :define_method, s(:arglist, s(:lvar, name))),
|
73
|
+
s(:masgn, s(:array, s(:lasgn, :x), s(:lasgn, :y))),
|
74
|
+
s(:call, s(:lvar, :x), op, s(:arglist, s(:lvar, :y))))
|
75
|
+
end
|
76
|
+
|
77
|
+
#
|
78
|
+
# binop_define_singleton_method(:f, :+, :a) returns the ast of
|
79
|
+
#
|
80
|
+
# a.define_singleton_method :f do |x, y|
|
81
|
+
# x + y
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
def binop_define_singleton_method(name, op, receiver)
|
85
|
+
s(:iter,
|
86
|
+
s(:call, s(:lvar, receiver), :define_singleton_method,
|
87
|
+
s(:arglist, s(:lit, name))),
|
88
|
+
s(:masgn, s(:array, s(:lasgn, :x), s(:lasgn, :y))),
|
89
|
+
s(:call, s(:lvar, :x), op, s(:arglist, s(:lvar, :y))))
|
90
|
+
end
|
91
|
+
|
92
|
+
#
|
93
|
+
# no_arg_block(:foo, "bar") returns the ast of
|
94
|
+
#
|
95
|
+
# foo { "bar" }
|
96
|
+
#
|
97
|
+
def no_arg_block(name, ret)
|
98
|
+
s(:iter, s(:call, nil, name, s(:arglist)), nil, s(:str, ret))
|
99
|
+
end
|
100
|
+
|
101
|
+
#
|
102
|
+
# binop_block(:foo, :+) returns the ast of
|
103
|
+
#
|
104
|
+
# foo { |x, y| x + y }
|
105
|
+
#
|
106
|
+
def binop_block(name, op, receiver = nil, args = [])
|
107
|
+
s(:iter,
|
108
|
+
s(:call, receiver, name, s(:arglist, *args)),
|
109
|
+
s(:masgn, s(:array, s(:lasgn, :x), s(:lasgn, :y))),
|
110
|
+
s(:call, s(:lvar, :x), op, s(:arglist, s(:lvar, :y))))
|
111
|
+
end
|
112
|
+
|
113
|
+
#
|
114
|
+
# binop_proc_new(:*) returns the ast of
|
115
|
+
#
|
116
|
+
# Proc.new { |x, y| x * y }
|
117
|
+
#
|
118
|
+
def binop_proc_new(op)
|
119
|
+
s(:iter,
|
120
|
+
s(:call, s(:const, :Proc), :new, s(:arglist)),
|
121
|
+
s(:masgn, s(:array, s(:lasgn, :x), s(:lasgn, :y))),
|
122
|
+
s(:call, s(:lvar, :x), op, s(:arglist, s(:lvar, :y))))
|
123
|
+
end
|
124
|
+
end
|