mvz-live_ast 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES.rdoc +93 -0
  3. data/README.rdoc +419 -0
  4. data/Rakefile +21 -0
  5. data/devel/levitate.rb +853 -0
  6. data/devel/levitate_config.rb +4 -0
  7. data/lib/live_ast.rb +4 -0
  8. data/lib/live_ast/ast_eval.rb +11 -0
  9. data/lib/live_ast/ast_load.rb +15 -0
  10. data/lib/live_ast/base.rb +73 -0
  11. data/lib/live_ast/common.rb +48 -0
  12. data/lib/live_ast/error.rb +20 -0
  13. data/lib/live_ast/evaler.rb +32 -0
  14. data/lib/live_ast/full.rb +2 -0
  15. data/lib/live_ast/irb_spy.rb +43 -0
  16. data/lib/live_ast/linker.rb +122 -0
  17. data/lib/live_ast/loader.rb +60 -0
  18. data/lib/live_ast/reader.rb +26 -0
  19. data/lib/live_ast/replace_eval.rb +121 -0
  20. data/lib/live_ast/replace_load.rb +14 -0
  21. data/lib/live_ast/replace_raise.rb +18 -0
  22. data/lib/live_ast/ruby_parser.rb +36 -0
  23. data/lib/live_ast/ruby_parser/test.rb +197 -0
  24. data/lib/live_ast/ruby_parser/unparser.rb +13 -0
  25. data/lib/live_ast/to_ast.rb +26 -0
  26. data/lib/live_ast/to_ruby.rb +24 -0
  27. data/lib/live_ast/version.rb +3 -0
  28. data/test/ast_eval_feature_test.rb +11 -0
  29. data/test/ast_load_feature_test.rb +11 -0
  30. data/test/attr_test.rb +24 -0
  31. data/test/backtrace_test.rb +158 -0
  32. data/test/covert_define_method_test.rb +23 -0
  33. data/test/def_test.rb +35 -0
  34. data/test/define_method_test.rb +67 -0
  35. data/test/define_singleton_method_test.rb +15 -0
  36. data/test/encoding_test.rb +52 -0
  37. data/test/encoding_test/bad.rb +1 -0
  38. data/test/encoding_test/cp932.rb +6 -0
  39. data/test/encoding_test/default.rb +5 -0
  40. data/test/encoding_test/eucjp.rb +6 -0
  41. data/test/encoding_test/koi8.rb +6 -0
  42. data/test/encoding_test/koi8_shebang.rb +7 -0
  43. data/test/encoding_test/koi8_with_utf8bom.rb +6 -0
  44. data/test/encoding_test/usascii.rb +6 -0
  45. data/test/encoding_test/usascii_with_utf8bom.rb +6 -0
  46. data/test/encoding_test/utf8.rb +6 -0
  47. data/test/encoding_test/utf8bom.rb +6 -0
  48. data/test/encoding_test/utf8bom_only.rb +5 -0
  49. data/test/encoding_test/utf8dos.rb +6 -0
  50. data/test/encoding_test/utf8mac.rb +6 -0
  51. data/test/encoding_test/utf8mac_alt.rb +6 -0
  52. data/test/encoding_test/utf8unix.rb +6 -0
  53. data/test/error_test.rb +116 -0
  54. data/test/eval_test.rb +269 -0
  55. data/test/flush_cache_test.rb +98 -0
  56. data/test/irb_test.rb +25 -0
  57. data/test/lambda_test.rb +56 -0
  58. data/test/load_path_test.rb +78 -0
  59. data/test/load_test.rb +123 -0
  60. data/test/main.rb +140 -0
  61. data/test/nested_test.rb +29 -0
  62. data/test/noninvasive_test.rb +51 -0
  63. data/test/readme_test.rb +16 -0
  64. data/test/recursive_eval_test.rb +52 -0
  65. data/test/redefine_method_test.rb +83 -0
  66. data/test/reload_test.rb +105 -0
  67. data/test/replace_eval_test.rb +405 -0
  68. data/test/rubygems_test.rb +25 -0
  69. data/test/rubyspec_test.rb +39 -0
  70. data/test/singleton_test.rb +25 -0
  71. data/test/stdlib_test.rb +13 -0
  72. data/test/thread_test.rb +44 -0
  73. data/test/to_ast_feature_test.rb +15 -0
  74. data/test/to_ruby_feature_test.rb +15 -0
  75. data/test/to_ruby_test.rb +87 -0
  76. metadata +275 -0
@@ -0,0 +1,98 @@
1
+ require_relative 'main'
2
+
3
+ # test for flushing side-effects: unsort this TestCase from other
4
+ # TestCases.
5
+
6
+ define_unsorted_test_case "FlushCacheTest", RegularTest do
7
+ def test_cache
8
+ # testing global state of cache -- must be sequential
9
+ uncached_method_from_require
10
+ uncached_method_from_eval
11
+ cached_method_from_eval
12
+ lost_method_from_require
13
+ flush_lambda
14
+ end
15
+
16
+ def uncached_method_from_require
17
+ klass = Class.new do
18
+ def f ; end
19
+ def g ; end
20
+ end
21
+
22
+ LiveAST.flush_cache
23
+
24
+ #
25
+ # file never made it into the cache; unaffected by flush
26
+ #
27
+ assert_nothing_raised do
28
+ klass.instance_method(:g).to_ast
29
+ end
30
+ end
31
+
32
+ def uncached_method_from_eval
33
+ klass = Class.new do
34
+ ast_eval %{
35
+ def f ; end
36
+ def g ; end
37
+ }, binding
38
+ end
39
+
40
+ LiveAST.flush_cache
41
+
42
+ assert_raises LiveAST::ASTNotFoundError do
43
+ klass.instance_method(:g).to_ast
44
+ end
45
+ end
46
+
47
+ def cached_method_from_eval
48
+ klass = Class.new do
49
+ ast_eval %{
50
+ def f ; end
51
+ def g ; end
52
+ }, binding
53
+ end
54
+
55
+ f_ast = klass.instance_method(:f).to_ast
56
+
57
+ LiveAST.flush_cache
58
+
59
+ assert_equal f_ast.object_id,
60
+ klass.instance_method(:f).to_ast.object_id
61
+
62
+ assert_raises LiveAST::ASTNotFoundError do
63
+ klass.instance_method(:g).to_ast
64
+ end
65
+ end
66
+
67
+ def lost_method_from_require
68
+ klass = Class.new do
69
+ def f ; end
70
+ def g ; end
71
+ end
72
+
73
+ # check that previous flushing did not cause side effect
74
+ assert_nothing_raised do
75
+ klass.instance_method(:f).to_ast
76
+ end
77
+ end
78
+
79
+ def flush_lambda
80
+ a, b = ast_eval %{
81
+ [
82
+ lambda { "aaa" },
83
+ lambda { "bbb" },
84
+ ]
85
+ }, binding
86
+
87
+ a_ast = a.to_ast
88
+ assert_equal no_arg_block(:lambda, "aaa"), a_ast
89
+
90
+ LiveAST.flush_cache
91
+
92
+ assert_equal a_ast.object_id, a.to_ast.object_id
93
+
94
+ assert_raises LiveAST::ASTNotFoundError do
95
+ b.to_ast
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,25 @@
1
+ require_relative 'main'
2
+
3
+ class IRBTest < RegularTest
4
+ def with_module(parent, child)
5
+ parent.const_set child, Module.new
6
+ begin
7
+ yield
8
+ ensure
9
+ parent.send :remove_const, child
10
+ end
11
+ end
12
+
13
+ def test_irb
14
+ with_module(Object, :IRB) do
15
+ with_module(LiveAST, :IRBSpy) do
16
+ LiveAST::IRBSpy.class_eval do
17
+ def self.code_at(line)
18
+ "def f ; end"
19
+ end
20
+ end
21
+ LiveAST::Linker.fetch_from_cache("(irb)", 1)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,56 @@
1
+ require_relative '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,78 @@
1
+ require_relative '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 nil, "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 code_1, "foo.rb" do |path|
43
+ Object.send(:remove_method, :hello) rescue nil
44
+ load "foo.rb"
45
+ assert_equal "password", hello
46
+
47
+ write_file path, code_2
48
+
49
+ Object.send(:remove_method, :goodbye) rescue nil
50
+ LiveAST.load "foo.rb"
51
+ assert_equal "bubbleboy", goodbye
52
+ end
53
+ ensure
54
+ Object.send(:remove_method, :hello) rescue nil
55
+ Object.send(:remove_method, :goodbye) rescue nil
56
+ end
57
+
58
+ def compare_load_errors(file)
59
+ error = assert_raises LoadError do
60
+ LiveAST.load file
61
+ end
62
+ assert_equal "cannot load such file -- #{file}", error.message
63
+ end
64
+
65
+ def check_errors
66
+ temp_file "# do nothing", "foo.rb" do |path|
67
+ [
68
+ "foo",
69
+ "",
70
+ "/usr",
71
+ ".",
72
+ "..",
73
+ ].each do |file|
74
+ compare_load_errors(file)
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,123 @@
1
+ require_relative 'main'
2
+ require_relative '../devel/levitate'
3
+
4
+ class AAA_LoadFileTest < BaseTest
5
+ class << self
6
+ attr_accessor :flag
7
+ end
8
+
9
+ def test_a_no_locals_created
10
+ code = %{
11
+ AAA_LoadFileTest.flag = :code_a
12
+ FOO = 77
13
+ x = 33
14
+ y = 99
15
+ }
16
+
17
+ temp_file code do |file|
18
+ ret = LiveAST.load file
19
+ assert_equal true, ret
20
+ assert_equal :code_a, AAA_LoadFileTest.flag
21
+
22
+ assert_raises NameError do
23
+ eval("x", TOPLEVEL_BINDING)
24
+ end
25
+
26
+ assert_equal 77, ::FOO
27
+ end
28
+ end
29
+
30
+ def test_b_no_locals_modified
31
+ code = %{
32
+ AAA_LoadFileTest.flag = :code_b
33
+ r = 55
34
+ }
35
+
36
+ temp_file code do |file|
37
+ eval("r = 66", TOPLEVEL_BINDING)
38
+
39
+ ret = LiveAST.load file
40
+ assert_equal true, ret
41
+ assert_equal :code_b, AAA_LoadFileTest.flag
42
+
43
+ actual = eval("r", TOPLEVEL_BINDING)
44
+ assert_equal 66, actual
45
+ end
46
+ end
47
+
48
+ def test_c_wrap
49
+ code = %{
50
+ AAA_LoadFileTest.flag = :code_c
51
+ ZOOM = 111
52
+ }
53
+
54
+ temp_file code do |file|
55
+ ret = LiveAST.load file, true
56
+ assert_equal true, ret
57
+ assert_equal :code_c, AAA_LoadFileTest.flag
58
+
59
+ assert_raises NameError do
60
+ ZOOM
61
+ end
62
+ end
63
+ end
64
+
65
+ def self.from_d
66
+ self.flag = :code_d
67
+ end
68
+
69
+ def test_d_empty_locals_list
70
+ code = %{
71
+ AAA_LoadFileTest.from_d
72
+ }
73
+
74
+ temp_file code do |file|
75
+ LiveAST.load file
76
+ assert_equal :code_d, AAA_LoadFileTest.flag
77
+ end
78
+ end
79
+
80
+ def test_verbose_respected
81
+ lib = File.expand_path(File.dirname(__FILE__) + "/../lib")
82
+
83
+ [
84
+ # respects a loaded file setting $VERBOSE = true
85
+ [
86
+ "false",
87
+ "true",
88
+ lambda { |file|
89
+ Levitate.run file
90
+ }
91
+ ],
92
+
93
+ # unfixable: does not respect a loaded file setting $VERBOSE = nil
94
+ [
95
+ "true",
96
+ "false",
97
+ lambda { |file|
98
+ unfixable do
99
+ assert_nothing_raised do
100
+ Levitate.run file
101
+ end
102
+ end
103
+ }
104
+ ]
105
+ ].each do |main_value, loaded_value, action|
106
+ loaded_code = %{
107
+ $VERBOSE = #{loaded_value}
108
+ }
109
+
110
+ temp_file loaded_code do |loaded_file|
111
+ main_code = %{
112
+ $LOAD_PATH.unshift '#{lib}'
113
+ require 'live_ast/base'
114
+ toplevel_local = 444
115
+ $VERBOSE = #{main_value}
116
+ LiveAST.load '#{loaded_file}'
117
+ $VERBOSE == #{loaded_value} or exit(1)
118
+ }
119
+ temp_file main_code, &action
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,140 @@
1
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
2
+
3
+ # require first for stdlib_test
4
+ require 'pp'
5
+ require 'find'
6
+ require 'fileutils'
7
+
8
+ require 'minitest/unit'
9
+ require 'minitest/mock'
10
+ require 'minitest/autorun'
11
+
12
+ $VERBOSE = true
13
+
14
+ require 'live_ast/base'
15
+
16
+ def define_unsorted_test_case(name, superclass, &block)
17
+ klass = Class.new superclass, &block
18
+ letter = ('A'..'Z').to_a[rand(26)]
19
+ Object.const_set "#{letter}#{name}", klass
20
+ end
21
+
22
+ class JLMiniTest < MiniTest::Unit::TestCase
23
+ def self.test_methods
24
+ default = super
25
+ onlies = default.select { |m| m =~ %r!__only\Z! }
26
+ if onlies.empty?
27
+ default
28
+ else
29
+ puts "\nNOTE: running ONLY *__only tests for #{self}"
30
+ onlies
31
+ end
32
+ end
33
+
34
+ def delim(char)
35
+ "\n" << (char*72) << "\n"
36
+ end
37
+
38
+ def mu_pp(obj)
39
+ delim("_") <<
40
+ obj.pretty_inspect.chomp <<
41
+ delim("=")
42
+ end
43
+
44
+ def unfixable
45
+ begin
46
+ yield
47
+ raise "claimed to be unfixable, but assertion succeeded"
48
+ rescue MiniTest::Assertion
49
+ end
50
+ end
51
+
52
+ def assert_nothing_raised
53
+ yield
54
+ assert_nil nil
55
+ rescue => ex
56
+ raise MiniTest::Assertion,
57
+ exception_details(ex, "Expected nothing raised, but got:")
58
+ end
59
+
60
+ %w[
61
+ empty equal in_delta in_epsilon includes instance_of
62
+ kind_of match nil operator respond_to same
63
+ ].each { |name|
64
+ alias_method "assert_not_#{name}", "refute_#{name}"
65
+ }
66
+ end
67
+
68
+ class BaseTest < JLMiniTest
69
+ include LiveAST.parser::Test
70
+
71
+ DATA_DIR = File.expand_path(File.dirname(__FILE__) + "/data")
72
+
73
+ def self.stdlib_has_source?
74
+ RUBY_ENGINE != "jruby"
75
+ end
76
+
77
+ def temp_file(code, basename = nil)
78
+ basename ||= ('a'..'z').to_a.shuffle.join + ".rb"
79
+ path = DATA_DIR + "/" + basename
80
+ FileUtils.mkdir DATA_DIR unless File.directory? DATA_DIR
81
+
82
+ write_file path, code if code
83
+ begin
84
+ yield path
85
+ ensure
86
+ FileUtils.rm_f path
87
+ FileUtils.rmdir DATA_DIR rescue nil
88
+ end
89
+ end
90
+
91
+ def write_file(file, contents)
92
+ File.open(file, "w") { |f| f.print contents }
93
+ end
94
+
95
+ def return_block(&block)
96
+ block
97
+ end
98
+
99
+ def exception_backtrace
100
+ begin
101
+ yield
102
+ rescue Exception => e
103
+ e.backtrace
104
+ end
105
+ end
106
+
107
+ def ignore(*args)
108
+ end
109
+ end
110
+
111
+ class RegularTest < BaseTest
112
+ def setup
113
+ super
114
+ require 'live_ast'
115
+ end
116
+ end
117
+
118
+ class ReplaceEvalTest < BaseTest
119
+ def initialize(*args)
120
+ super
121
+ ok = begin
122
+ require 'live_ast/full'
123
+ true
124
+ rescue LoadError
125
+ if RUBY_ENGINE == "ruby"
126
+ raise "need: gem install boc"
127
+ end
128
+ false
129
+ end
130
+
131
+ unless ok
132
+ self.class.class_eval do
133
+ instance_methods(false).each do |m|
134
+ remove_method(m)
135
+ define_method(m) { }
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end