reflexive 0.0.3 → 0.0.4

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.
Files changed (142) hide show
  1. data/Gemfile +16 -0
  2. data/Rakefile +31 -0
  3. data/config.ru +3 -0
  4. data/reflexive.gemspec +1 -1
  5. data/spec/coderay_html_encoder_spec.rb +57 -0
  6. data/spec/coderay_ruby_scanner_spec.rb +194 -0
  7. data/spec/io_interceptor.rb +64 -0
  8. data/spec/method_lookup_spec.rb +0 -0
  9. data/spec/methods_spec.rb +202 -0
  10. data/spec/rails_integration_spec.rb +139 -0
  11. data/spec/rails_integration_spec_helper.rb +115 -0
  12. data/spec/reflexive_ripper_spec.rb +351 -0
  13. data/spec/reflexive_spec.rb +98 -0
  14. data/spec/ripper_events_recorder.rb +50 -0
  15. data/spec/ripper_spec.rb +758 -0
  16. data/spec/sexp_builder_with_scanner_events.rb +39 -0
  17. data/spec/shell_out.rb +417 -0
  18. data/spec/spec_helper.rb +4 -0
  19. data/spec/test_apps/rails2_test_app/README +243 -0
  20. data/spec/test_apps/rails2_test_app/Rakefile +10 -0
  21. data/spec/test_apps/rails2_test_app/app/controllers/application_controller.rb +10 -0
  22. data/spec/test_apps/rails2_test_app/app/controllers/posts_controller.rb +85 -0
  23. data/spec/test_apps/rails2_test_app/app/helpers/application_helper.rb +3 -0
  24. data/spec/test_apps/rails2_test_app/app/helpers/posts_helper.rb +2 -0
  25. data/spec/test_apps/rails2_test_app/app/models/post.rb +5 -0
  26. data/spec/test_apps/rails2_test_app/app/views/layouts/posts.html.erb +17 -0
  27. data/spec/test_apps/rails2_test_app/app/views/posts/edit.html.erb +12 -0
  28. data/spec/test_apps/rails2_test_app/app/views/posts/index.html.erb +18 -0
  29. data/spec/test_apps/rails2_test_app/app/views/posts/new.html.erb +11 -0
  30. data/spec/test_apps/rails2_test_app/app/views/posts/show.html.erb +3 -0
  31. data/spec/test_apps/rails2_test_app/config/boot.rb +110 -0
  32. data/spec/test_apps/rails2_test_app/config/database.yml +22 -0
  33. data/spec/test_apps/rails2_test_app/config/environment.rb +43 -0
  34. data/spec/test_apps/rails2_test_app/config/environments/development.rb +17 -0
  35. data/spec/test_apps/rails2_test_app/config/environments/production.rb +28 -0
  36. data/spec/test_apps/rails2_test_app/config/environments/test.rb +28 -0
  37. data/spec/test_apps/rails2_test_app/config/initializers/backtrace_silencers.rb +7 -0
  38. data/spec/test_apps/rails2_test_app/config/initializers/inflections.rb +10 -0
  39. data/spec/test_apps/rails2_test_app/config/initializers/mime_types.rb +5 -0
  40. data/spec/test_apps/rails2_test_app/config/initializers/new_rails_defaults.rb +21 -0
  41. data/spec/test_apps/rails2_test_app/config/initializers/session_store.rb +15 -0
  42. data/spec/test_apps/rails2_test_app/config/locales/en.yml +5 -0
  43. data/spec/test_apps/rails2_test_app/config/routes.rb +45 -0
  44. data/spec/test_apps/rails2_test_app/db/development.sqlite3 +0 -0
  45. data/spec/test_apps/rails2_test_app/db/migrate/20100512073155_create_posts.rb +12 -0
  46. data/spec/test_apps/rails2_test_app/db/schema.rb +19 -0
  47. data/spec/test_apps/rails2_test_app/db/seeds.rb +7 -0
  48. data/spec/test_apps/rails2_test_app/doc/README_FOR_APP +2 -0
  49. data/spec/test_apps/rails2_test_app/log/development.log +251 -0
  50. data/spec/test_apps/rails2_test_app/log/production.log +0 -0
  51. data/spec/test_apps/rails2_test_app/log/server.log +0 -0
  52. data/spec/test_apps/rails2_test_app/log/test.log +0 -0
  53. data/spec/test_apps/rails2_test_app/public/404.html +30 -0
  54. data/spec/test_apps/rails2_test_app/public/422.html +30 -0
  55. data/spec/test_apps/rails2_test_app/public/500.html +30 -0
  56. data/spec/test_apps/rails2_test_app/public/favicon.ico +0 -0
  57. data/spec/test_apps/rails2_test_app/public/images/rails.png +0 -0
  58. data/spec/test_apps/rails2_test_app/public/index.html +275 -0
  59. data/spec/test_apps/rails2_test_app/public/javascripts/application.js +2 -0
  60. data/spec/test_apps/rails2_test_app/public/javascripts/controls.js +963 -0
  61. data/spec/test_apps/rails2_test_app/public/javascripts/dragdrop.js +973 -0
  62. data/spec/test_apps/rails2_test_app/public/javascripts/effects.js +1128 -0
  63. data/spec/test_apps/rails2_test_app/public/javascripts/prototype.js +4320 -0
  64. data/spec/test_apps/rails2_test_app/public/robots.txt +5 -0
  65. data/spec/test_apps/rails2_test_app/public/stylesheets/1.css +0 -0
  66. data/spec/test_apps/rails2_test_app/public/stylesheets/scaffold.css +54 -0
  67. data/spec/test_apps/rails2_test_app/script/about +4 -0
  68. data/spec/test_apps/rails2_test_app/script/console +3 -0
  69. data/spec/test_apps/rails2_test_app/script/dbconsole +3 -0
  70. data/spec/test_apps/rails2_test_app/script/destroy +3 -0
  71. data/spec/test_apps/rails2_test_app/script/generate +3 -0
  72. data/spec/test_apps/rails2_test_app/script/performance/benchmarker +3 -0
  73. data/spec/test_apps/rails2_test_app/script/performance/profiler +3 -0
  74. data/spec/test_apps/rails2_test_app/script/plugin +3 -0
  75. data/spec/test_apps/rails2_test_app/script/runner +3 -0
  76. data/spec/test_apps/rails2_test_app/script/server +3 -0
  77. data/spec/test_apps/rails2_test_app/test/fixtures/posts.yml +7 -0
  78. data/spec/test_apps/rails2_test_app/test/functional/posts_controller_test.rb +45 -0
  79. data/spec/test_apps/rails2_test_app/test/performance/browsing_test.rb +9 -0
  80. data/spec/test_apps/rails2_test_app/test/test_helper.rb +38 -0
  81. data/spec/test_apps/rails2_test_app/test/unit/helpers/posts_helper_test.rb +4 -0
  82. data/spec/test_apps/rails2_test_app/test/unit/post_test.rb +8 -0
  83. data/spec/test_apps/rails3_test_app/Gemfile +28 -0
  84. data/spec/test_apps/rails3_test_app/README +244 -0
  85. data/spec/test_apps/rails3_test_app/Rakefile +10 -0
  86. data/spec/test_apps/rails3_test_app/app/controllers/application_controller.rb +4 -0
  87. data/spec/test_apps/rails3_test_app/app/controllers/posts_controller.rb +83 -0
  88. data/spec/test_apps/rails3_test_app/app/helpers/application_helper.rb +2 -0
  89. data/spec/test_apps/rails3_test_app/app/helpers/posts_helper.rb +2 -0
  90. data/spec/test_apps/rails3_test_app/app/models/post.rb +2 -0
  91. data/spec/test_apps/rails3_test_app/app/views/layouts/application.html.erb +14 -0
  92. data/spec/test_apps/rails3_test_app/app/views/posts/_form.html.erb +16 -0
  93. data/spec/test_apps/rails3_test_app/app/views/posts/edit.html.erb +6 -0
  94. data/spec/test_apps/rails3_test_app/app/views/posts/index.html.erb +21 -0
  95. data/spec/test_apps/rails3_test_app/app/views/posts/new.html.erb +5 -0
  96. data/spec/test_apps/rails3_test_app/app/views/posts/show.html.erb +5 -0
  97. data/spec/test_apps/rails3_test_app/config/application.rb +49 -0
  98. data/spec/test_apps/rails3_test_app/config/boot.rb +6 -0
  99. data/spec/test_apps/rails3_test_app/config/database.yml +22 -0
  100. data/spec/test_apps/rails3_test_app/config/environment.rb +5 -0
  101. data/spec/test_apps/rails3_test_app/config/environments/development.rb +19 -0
  102. data/spec/test_apps/rails3_test_app/config/environments/production.rb +42 -0
  103. data/spec/test_apps/rails3_test_app/config/environments/test.rb +32 -0
  104. data/spec/test_apps/rails3_test_app/config/initializers/backtrace_silencers.rb +7 -0
  105. data/spec/test_apps/rails3_test_app/config/initializers/inflections.rb +10 -0
  106. data/spec/test_apps/rails3_test_app/config/initializers/mime_types.rb +5 -0
  107. data/spec/test_apps/rails3_test_app/config/initializers/secret_token.rb +7 -0
  108. data/spec/test_apps/rails3_test_app/config/initializers/session_store.rb +8 -0
  109. data/spec/test_apps/rails3_test_app/config/locales/en.yml +5 -0
  110. data/spec/test_apps/rails3_test_app/config/routes.rb +60 -0
  111. data/spec/test_apps/rails3_test_app/config.ru +4 -0
  112. data/spec/test_apps/rails3_test_app/db/development.sqlite3 +0 -0
  113. data/spec/test_apps/rails3_test_app/db/migrate/20100512075428_create_posts.rb +12 -0
  114. data/spec/test_apps/rails3_test_app/db/schema.rb +19 -0
  115. data/spec/test_apps/rails3_test_app/db/seeds.rb +7 -0
  116. data/spec/test_apps/rails3_test_app/doc/README_FOR_APP +2 -0
  117. data/spec/test_apps/rails3_test_app/log/development.log +349 -0
  118. data/spec/test_apps/rails3_test_app/log/production.log +0 -0
  119. data/spec/test_apps/rails3_test_app/log/server.log +0 -0
  120. data/spec/test_apps/rails3_test_app/log/test.log +0 -0
  121. data/spec/test_apps/rails3_test_app/public/404.html +26 -0
  122. data/spec/test_apps/rails3_test_app/public/422.html +26 -0
  123. data/spec/test_apps/rails3_test_app/public/500.html +26 -0
  124. data/spec/test_apps/rails3_test_app/public/favicon.ico +0 -0
  125. data/spec/test_apps/rails3_test_app/public/images/rails.png +0 -0
  126. data/spec/test_apps/rails3_test_app/public/index.html +279 -0
  127. data/spec/test_apps/rails3_test_app/public/javascripts/application.js +2 -0
  128. data/spec/test_apps/rails3_test_app/public/javascripts/controls.js +965 -0
  129. data/spec/test_apps/rails3_test_app/public/javascripts/dragdrop.js +974 -0
  130. data/spec/test_apps/rails3_test_app/public/javascripts/effects.js +1123 -0
  131. data/spec/test_apps/rails3_test_app/public/javascripts/prototype.js +4874 -0
  132. data/spec/test_apps/rails3_test_app/public/javascripts/rails.js +118 -0
  133. data/spec/test_apps/rails3_test_app/public/robots.txt +5 -0
  134. data/spec/test_apps/rails3_test_app/public/stylesheets/scaffold.css +60 -0
  135. data/spec/test_apps/rails3_test_app/script/rails +9 -0
  136. data/spec/test_apps/rails3_test_app/test/fixtures/posts.yml +11 -0
  137. data/spec/test_apps/rails3_test_app/test/functional/posts_controller_test.rb +49 -0
  138. data/spec/test_apps/rails3_test_app/test/performance/browsing_test.rb +9 -0
  139. data/spec/test_apps/rails3_test_app/test/test_helper.rb +13 -0
  140. data/spec/test_apps/rails3_test_app/test/unit/helpers/posts_helper_test.rb +4 -0
  141. data/spec/test_apps/rails3_test_app/test/unit/post_test.rb +8 -0
  142. metadata +142 -2
@@ -0,0 +1,139 @@
1
+ require "fileutils"
2
+ require "open-uri"
3
+
4
+ require "reflexive"
5
+
6
+ require File.expand_path("../rails_integration_spec_helper", __FILE__)
7
+
8
+ shared_examples_for "fresh Rails app with Reflexive installed" do
9
+ it "responds on localhost" do
10
+ get("/").should include("Welcome aboard")
11
+ end
12
+
13
+ it "responds for Reflexive paths" do
14
+ constant_reflexion = get("/reflexive/constants/ActiveRecord::Base")
15
+ constant_reflexion.should include("ActiveRecord")
16
+ constant_reflexion.should include("Object")
17
+ constant_reflexion.should include("Class")
18
+ constant_reflexion.should include("Module")
19
+ end
20
+ end
21
+
22
+ describe "Integration with" do
23
+ describe "Rails 2.x" do
24
+ before(:all) do
25
+ bootstrap_gem_environment("rails", "2.3.5")
26
+ build_and_install_test_gem
27
+ end
28
+
29
+ it "installs proper version of Rails" do
30
+ sh_in_tmp_gemset("rails -v", :out => :return).should include("Rails 2")
31
+ end
32
+
33
+ it "installs test Reflexive gem" do
34
+ sh_in_tmp_gemset("gem list", :out => :return).should include("reflexive")
35
+ end
36
+
37
+ describe "creates Rails application" do
38
+ before(:all) do
39
+ create_rails_app("2")
40
+ end
41
+
42
+ it "which has config/environment.rb file" do
43
+ Dir.chdir($app_dir) do
44
+ File.exist?("config/environment.rb")
45
+ end
46
+ end
47
+
48
+ describe "and installs Reflexive gem into it" do
49
+ before(:all) do
50
+ patch_app_file("config/environment.rb",
51
+ "Rails::Initializer.run do |config|",
52
+ <<-RUBY)
53
+ Rails::Initializer.run do |config|
54
+ config.gem "reflexive"
55
+ config.middleware.insert_after("Rack::Lock", "Reflexive::Application")
56
+ RUBY
57
+ end
58
+
59
+ it "properly" do
60
+ Dir.chdir($app_dir) do
61
+ IO.read("config/environment.rb").should include("Reflexive")
62
+ end
63
+ end
64
+
65
+ describe "and runs application" do
66
+ before(:all) do
67
+ Dir.chdir($app_dir) do
68
+ spawn_server_and_wait_for_response("ruby script/server")
69
+ end
70
+ end
71
+
72
+ it_should_behave_like "fresh Rails app with Reflexive installed"
73
+
74
+ after(:all) do
75
+ terminate_server_blocking
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ describe "Rails 3.x" do
83
+ before(:all) do
84
+ bootstrap_gem_environment("rails", "3.0.0.beta3")
85
+ build_and_install_test_gem
86
+ end
87
+
88
+ it "installs proper version of Rails" do
89
+ sh_in_tmp_gemset("rails -v", :out => :return).should include("Rails 3")
90
+ end
91
+
92
+ it "installs test Reflexive gem" do
93
+ sh_in_tmp_gemset("gem list", :out => :return).should include("reflexive")
94
+ end
95
+
96
+ describe "creates Rails application" do
97
+ before(:all) do
98
+ create_rails_app("3")
99
+ end
100
+
101
+ it "which has config/application.rb file" do
102
+ Dir.chdir($app_dir) do
103
+ File.exist?("config/application.rb")
104
+ end
105
+ end
106
+
107
+ describe "and installs Reflexive gem into it" do
108
+ before(:all) do
109
+ patch_app_file("config/application.rb",
110
+ "class Application < Rails::Application",
111
+ <<-RUBY)
112
+ class Application < Rails::Application
113
+ config.middleware.insert_after("Rack::Lock", "Reflexive::Application")
114
+ RUBY
115
+ end
116
+
117
+ it "properly" do
118
+ Dir.chdir($app_dir) do
119
+ IO.read("config/application.rb").should include("Reflexive")
120
+ end
121
+ end
122
+
123
+ describe "and runs application" do
124
+ before(:all) do
125
+ Dir.chdir($app_dir) do
126
+ spawn_server_and_wait_for_response("rails server")
127
+ end
128
+ end
129
+
130
+ it_should_behave_like "fresh Rails app with Reflexive installed"
131
+
132
+ after(:all) do
133
+ terminate_server_blocking
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,115 @@
1
+ require "fileutils"
2
+ require "reflexive"
3
+ require "open-uri"
4
+
5
+ def sh(*args)
6
+ require File.expand_path("../shell_out", __FILE__)
7
+ shell_out_args = args.dup
8
+ options = shell_out_args.pop if shell_out_args[-1].is_a?(Hash)
9
+ shell_out_args << { :raise_exceptions => true,
10
+ :verbose => true }.merge(options || {})
11
+ ShellOut(*shell_out_args)
12
+ end
13
+
14
+ def tmp_gemset_env
15
+ { "GEM_HOME" => $tmp_gemdir,
16
+ "GEM_PATH" => $tmp_gemdir }
17
+ end
18
+
19
+ def sh_in_tmp_gemset(cmd, options = {})
20
+ sh(tmp_gemset_env, cmd, options)
21
+ end
22
+
23
+ $purge_at_exit = []
24
+
25
+ at_exit do
26
+ for dir in $purge_at_exit
27
+ FileUtils::Verbose.rm_rf(dir)
28
+ end
29
+ end
30
+
31
+ def mktmpdir(prefix)
32
+ tmp_dir = Dir.mktmpdir
33
+ $purge_at_exit << tmp_dir.dup
34
+ tmp_dir
35
+ end
36
+
37
+ def gem_repository_option
38
+ gem_repository_path = File.expand_path("../../tmp/gem_repository", __FILE__)
39
+
40
+ if File.directory?(gem_repository_path)
41
+ "--source file://#{ gem_repository_path }"
42
+ else
43
+ ""
44
+ end
45
+ end
46
+
47
+ def bootstrap_gem_environment(*args)
48
+ $tmp_gemdir = mktmpdir("reflexive_test_gemset")
49
+ while name = args.shift
50
+ version = args.shift
51
+ sh_in_tmp_gemset "gem install #{ name } --version='#{ version }' " <<
52
+ "--no-update-sources --quiet #{ gem_repository_option }"
53
+ end
54
+ end
55
+
56
+ def make_tmp_gemset_name
57
+ t = Time.now.strftime("%Y%m%d")
58
+ "reflexive_test_gemset_#{t}_#{$$}_#{rand(0x100000000).to_s(36)}"
59
+ end
60
+
61
+ def build_and_install_test_gem
62
+ Dir.chdir(File.expand_path("../../", __FILE__)) do
63
+ sh({ "GEM_VERSION" => "9.9.9" }, "gem build reflexive.gemspec")
64
+ begin
65
+ sh_in_tmp_gemset("gem install reflexive-9.9.9.gem --quiet")
66
+ ensure
67
+ File.delete("reflexive-9.9.9.gem")
68
+ end
69
+ end
70
+ end
71
+
72
+ def spawn_server_and_wait_for_response(cmd)
73
+ $server_pid = spawn(tmp_gemset_env, cmd)
74
+ puts "Spawned server with #{ $server_pid } PID"
75
+ tries = 0
76
+ print "Waiting for server to start..."
77
+ started = false
78
+ while (tries += 1) < 10 && !started
79
+ started = get("/").include?("Welcome aboard") rescue false
80
+ print "."
81
+ sleep 1
82
+ end
83
+ print "\n"
84
+ abort "Failed to start server" unless started
85
+ end
86
+
87
+ def terminate_server_blocking
88
+ puts "Terminating server with #{ $server_pid } PID..."
89
+ `kill -9 #{ $server_pid }`
90
+ Process::waitpid2($server_pid)
91
+ end
92
+
93
+ def get(path)
94
+ open("http://localhost:3000#{ path }").read
95
+ end
96
+
97
+ def create_rails_app(version)
98
+ unless $tmp_dir # one dir is enough
99
+ $tmp_dir = mktmpdir("reflexive_test_rails_apps")
100
+ end
101
+
102
+ $app_dir = File.join($tmp_dir, "reflexive_test_rails#{ version }_app")
103
+
104
+ Dir.chdir($tmp_dir) do
105
+ sh_in_tmp_gemset("rails reflexive_test_rails#{ version }_app")
106
+ end
107
+ end
108
+
109
+ def patch_app_file(path, pattern, replacement)
110
+ Dir.chdir($app_dir) do
111
+ contents = IO.read(path)
112
+ contents.sub!(pattern, replacement)
113
+ File.open(path, "w") { |f| f.write(contents) }
114
+ end
115
+ end
@@ -0,0 +1,351 @@
1
+ require "reflexive/reflexive_ripper"
2
+
3
+ Rspec::Matchers.define :have_scopes do |*expected_scopes|
4
+ match do |actual_scanner_events|
5
+ @actual_scopes = actual_scanner_events.
6
+ map { |e| e[:meta_scope] }.compact
7
+ @actual_scopes == expected_scopes
8
+ end
9
+
10
+ failure_message_for_should do |actual_scanner_events|
11
+ "expected that scanner events: #{ actual_scanner_events } \n" <<
12
+ "(with scopes: #{ @actual_scopes }) \n" <<
13
+ "would have following scopes: #{ expected_scopes[0] }"
14
+ end
15
+ end
16
+
17
+ Rspec::Matchers.define :have_tags do |*expected_tags|
18
+ match do |actual_scanner_events|
19
+ @actual_tags = actual_scanner_events.map { |e| e[:tags] }.compact
20
+ (expected_tags - @actual_tags).empty?
21
+ end
22
+
23
+ failure_message_for_should do |actual_scanner_events|
24
+ "expected that scanner events: #{ actual_scanner_events } \n" <<
25
+ "(with tags: #{ @actual_tags }) \n" <<
26
+ "would have following tags: #{ expected_tags }"
27
+ end
28
+ end
29
+
30
+ Rspec::Matchers.define :have_exact_tags do |*expected_tags|
31
+ match do |actual_scanner_events|
32
+ @actual_tags = actual_scanner_events.map { |e| e[:tags] }.compact
33
+ expected_tags == @actual_tags
34
+ end
35
+
36
+ failure_message_for_should do |actual_scanner_events|
37
+ "expected that scanner events: #{ actual_scanner_events } \n" <<
38
+ "(with tags: #{ @actual_tags }) \n" <<
39
+ "would have exact tags: #{ expected_tags[0] }"
40
+ end
41
+ end
42
+
43
+ describe Reflexive::ReflexiveRipper do
44
+ def scanner_events_for(source)
45
+ parser = Reflexive::ReflexiveRipper.new(source)
46
+ parser.parse
47
+ parser.scanner_events
48
+ end
49
+
50
+ it "collects scanner events as hashes" do
51
+ scanner_events_for("a = 42").should == [
52
+ {:ident=>"a", :tags=>{:local_variable_assignment=>"1:a"}},
53
+ {:sp=>" "}, {:op=>"="}, {:sp=>" "}, {:int=>"42"}
54
+ ]
55
+ end
56
+
57
+ describe "injects method call scanner event tags" do
58
+ specify "m!" do
59
+ scanner_events_for("m!").should(have_tags(
60
+ {:method_call=>{:name=>"m!", :receiver=>[], :scope => []}}
61
+ ))
62
+ end
63
+
64
+ specify "A.b!()" do
65
+ scanner_events_for("A.b!").should(have_tags(
66
+ {:method_call=>{:name=>"b!", :receiver=>["A"], :scope => []}}
67
+ ))
68
+ end
69
+
70
+ specify "A::B.c!()" do
71
+ scanner_events_for("A::B.c!()").should(have_tags(
72
+ {:method_call=>{:name=>"c!", :receiver=>["A::B"], :scope => []}}
73
+ ))
74
+ end
75
+
76
+ specify "module A; B.c!(); end" do
77
+ scanner_events_for("module A; B.c!(); end").should(have_tags(
78
+ {:method_call=>{:name=>"c!", :receiver=>["B"], :scope => ["A"]}}
79
+ ))
80
+ end
81
+ end
82
+
83
+ describe "injects local variable assignment event tags" do
84
+ specify "v = 1" do
85
+ scanner_events_for("a = 42").should(have_tags(
86
+ :local_variable_assignment=>"1:a"))
87
+ end
88
+
89
+ specify "def m(arg) end" do
90
+ scanner_events_for("def m(arg); end").should(have_tags(
91
+ :local_variable_assignment=>"2:arg"))
92
+ end
93
+
94
+ specify "a, b = 1, 2" do
95
+ scanner_events_for("a, b = 1, 2").should(have_tags(
96
+ {:local_variable_assignment=>"1:a"},
97
+ {:local_variable_assignment=>"1:b"}))
98
+ end
99
+
100
+ specify "a, b, *c, d = 1, 2" do
101
+ scanner_events_for("a, b, *c, d = 1, 2").should(have_tags(
102
+ {:local_variable_assignment=>"1:a"},
103
+ {:local_variable_assignment=>"1:b"},
104
+ {:local_variable_assignment=>"1:c"},
105
+ {:local_variable_assignment=>"1:d"}
106
+ ))
107
+ end
108
+
109
+ specify "1.tap { (dv = 1).tap { puts dv } }" do
110
+ scanner_events_for("1.tap { (dv = 1).tap { puts dv } }").should(have_exact_tags(
111
+ {:local_variable_assignment=>"2:dv"},
112
+ {:method_call=>{:name=>"puts", :receiver=>[], :scope => []}},
113
+ {:local_variable_access=>"2:dv"}
114
+ ))
115
+ end
116
+
117
+ specify "1.tap { x = 1; 1.tap { puts x } }" do
118
+ scanner_events_for("1.tap { x = 1; 1.tap { puts x } }").should(have_tags(
119
+ {:local_variable_assignment=>"2:x"},
120
+ {:local_variable_assignment=>"2:x"}))
121
+ end
122
+
123
+ specify "tv = 1; def m; puts tv; end" do
124
+ scanner_events_for("tv = 1; def m; puts tv; end").should(have_tags(
125
+ {:local_variable_assignment=>"1:tv"},
126
+ {:method_call=>{:name=>"puts", :receiver=>[:instance], :scope => []}},
127
+ {:method_call=>{:name=>"tv", :receiver=>[:instance], :scope => []}}))
128
+ end
129
+
130
+ end
131
+
132
+ describe "scope handling" do
133
+ describe "for method calls" do
134
+ specify "from top level" do
135
+ scanner_events_for("m()").should(have_tags(
136
+ {:method_call=>{:name=>"m", :receiver=>[], :scope => []}}))
137
+ end
138
+
139
+ specify "class definition level" do
140
+ scanner_events_for("class C; cm(); end").should(have_tags(
141
+ {:method_call=>{:name=>"cm", :receiver=>["C"], :scope => ["C"]}}))
142
+ scanner_events_for("module M; cm(); end").should(have_tags(
143
+ {:method_call=>{:name=>"cm", :receiver=>["M"], :scope => ["M"]}}))
144
+ end
145
+
146
+ specify "class instance level" do
147
+ scanner_events_for("class C; def im1; im2; end end").should(have_tags(
148
+ {:method_call=>{:name=>"im2", :receiver=>["C", :instance], :scope => ["C"]}}))
149
+ scanner_events_for("module M; def im1; im2; end end").should(have_tags(
150
+ {:method_call=>{:name=>"im2", :receiver=>["M", :instance], :scope => ["M"]}}))
151
+ end
152
+
153
+ specify "class singleton level" do
154
+ scanner_events_for("class C; def self.cm1() cm2; end end").should(have_tags(
155
+ {:method_call=>{:name=>"cm2", :receiver=>["C"], :scope => ["C"]}}))
156
+ scanner_events_for("module M; def self.cm1() cm2; end end").should(have_tags(
157
+ {:method_call=>{:name=>"cm2", :receiver=>["M"], :scope => ["M"]}}))
158
+ end
159
+
160
+ pending "nested method calls with constant references" do
161
+ src = <<-RUBY
162
+ module M
163
+ class C
164
+ def self.m
165
+ end
166
+ end
167
+ end
168
+ class M::C
169
+ def m
170
+ c = C.m
171
+ end
172
+ end
173
+ RUBY
174
+ end
175
+ end
176
+
177
+ describe "for constant references" do
178
+ specify "top level" do
179
+ scanner_events_for("C").should(have_tags(
180
+ :constant_access=>{:name=>"C", :scope=>[]}
181
+ ))
182
+ end
183
+
184
+ specify "path" do
185
+ scanner_events_for("A::B").should(have_tags(
186
+ {:constant_access=>{:name=>"A", :scope=>[]}},
187
+ {:constant_access=>{:name=>"A::B", :scope=>[]}}
188
+ ))
189
+ scanner_events_for("A::B::C").should(have_tags(
190
+ {:constant_access=>{:name=>"A", :scope=>[]}},
191
+ {:constant_access=>{:name=>"A::B", :scope=>[]}},
192
+ {:constant_access=>{:name=>"A::B::C", :scope=>[]}}
193
+ ))
194
+ end
195
+
196
+ specify "top path" do
197
+ scanner_events_for("::A::B").should(have_tags(
198
+ {:constant_access=>{:name=>"::A::B", :scope=>[]}}
199
+ ))
200
+ end
201
+
202
+ specify "nested" do
203
+ scanner_events_for("module A; module B; C; end end").should(have_tags(
204
+ {:constant_access=>{:name=>"A", :scope=>[]}},
205
+ {:constant_access=>{:name=>"B", :scope=>["A"]}},
206
+ {:constant_access=>{:name=>"C", :scope=>["A", "B"]}}
207
+ ))
208
+ scanner_events_for("module A; class B; C; end end").should(have_tags(
209
+ {:constant_access=>{:name=>"A", :scope=>[]}},
210
+ {:constant_access=>{:name=>"B", :scope=>["A"]}},
211
+ {:constant_access=>{:name=>"C", :scope=>["A", "B"]}}
212
+ ))
213
+ end
214
+
215
+ specify "combined (nested with path)" do
216
+ scanner_events_for("module M; C::D; end").should(have_tags(
217
+ {:constant_access=>{:name=>"M", :scope=>[]}},
218
+ {:constant_access=>{:name=>"C", :scope=>["M"]}},
219
+ {:constant_access=>{:name=>"C::D", :scope=>["M"]}}
220
+ ))
221
+ end
222
+
223
+ specify "combined (nested with top level)" do
224
+ scanner_events_for("module M; ::C::D; end").should(have_tags(
225
+ {:constant_access=>{:name=>"M", :scope=>[]}},
226
+ {:constant_access=>{:name=>"::C::D", :scope=>["M"]}}
227
+ ))
228
+ end
229
+
230
+ specify "from instance methods" do
231
+ scanner_events_for("def m; C; end").should(have_tags(
232
+ {:constant_access=>{:name=>"C", :scope=>[]}}
233
+ ))
234
+
235
+ end
236
+ end
237
+ end
238
+
239
+ describe "injects scope meta events" do
240
+ example "simple class def" do
241
+ scanner_events_for("class C; end").should(
242
+ have_scopes(["C"], []))
243
+ end
244
+
245
+ example "nested class def" do
246
+ scanner_events_for("class C; class D; end end").should(
247
+ have_scopes(["C"], ["C", "D"], ["C"], []))
248
+ end
249
+
250
+ example "class inside module def" do
251
+ scanner_events_for("module M; class C; end end").should(
252
+ have_scopes(["M"], ["M", "C"], ["M"], []))
253
+ end
254
+
255
+ it "handles const_path_ref" do
256
+ scanner_events_for("class Const::PathRef < ::TopConstRef; end").should(
257
+ have_scopes(["Const::PathRef"], []))
258
+ end
259
+
260
+ it "handles top_const_ref" do
261
+ scanner_events_for("class ::TopConstRef; end").should(
262
+ have_scopes(["::TopConstRef"], []))
263
+ end
264
+ end
265
+
266
+ # describe "injects require/load argument tag" do
267
+ # specify "require" do
268
+ # scanner_events_for("require 'f'").should(have_tags(
269
+ # {:local_variable_assignment=>"1:tv"}
270
+ # ))
271
+ # end
272
+ # end
273
+
274
+ it "shouldn't get confused with non-scope changing const refs" do
275
+ scanner_events_for("v = :class; SomeConst = 123").should(
276
+ have_scopes())
277
+ end
278
+
279
+ it "should handle complex arbitrary nesting" do
280
+ src = <<-RUBY
281
+ class TC
282
+ def m
283
+ end
284
+ end
285
+
286
+ module M1
287
+ def m
288
+ end
289
+
290
+ module M2
291
+ def m
292
+ end
293
+ class C1
294
+
295
+ end
296
+ class C1
297
+ def m
298
+ end
299
+ end
300
+ end
301
+
302
+ class C3
303
+ def m
304
+ end
305
+ end
306
+
307
+ end
308
+
309
+ module M1::M2
310
+ class C4
311
+ module M4
312
+ def m
313
+ end
314
+ end
315
+
316
+ class C5
317
+ module M3
318
+ end
319
+ class C6
320
+ end
321
+ end
322
+ end
323
+ end
324
+ RUBY
325
+ scanner_events_for(src).should(
326
+ have_scopes(["TC"],
327
+ [],
328
+ ["M1"],
329
+ ["M1", "M2"],
330
+ ["M1", "M2", "C1"],
331
+ ["M1", "M2"],
332
+ ["M1", "M2", "C1"],
333
+ ["M1", "M2"],
334
+ ["M1"],
335
+ ["M1", "C3"],
336
+ ["M1"],
337
+ [],
338
+ ["M1::M2"],
339
+ ["M1::M2", "C4"],
340
+ ["M1::M2", "C4", "M4"],
341
+ ["M1::M2", "C4"],
342
+ ["M1::M2", "C4", "C5"],
343
+ ["M1::M2", "C4", "C5", "M3"],
344
+ ["M1::M2", "C4", "C5"],
345
+ ["M1::M2", "C4", "C5", "C6"],
346
+ ["M1::M2", "C4", "C5"],
347
+ ["M1::M2", "C4"],
348
+ ["M1::M2"],
349
+ []))
350
+ end
351
+ end
@@ -0,0 +1,98 @@
1
+ require "reflexive/helpers"
2
+ require "reflexive/constantize"
3
+ require "reflexive/descendants"
4
+
5
+ describe "Reflexive.loaded_features_lookup" do
6
+ before(:all) do
7
+ @native_feature = $LOADED_FEATURES.detect { |f| f =~ /\.so\z/ }
8
+ @ruby_feature = $LOADED_FEATURES.detect { |f| f =~ /\.rb\z/ }
9
+ raise "Can't setup test: need at least one native and ruby feature loaded" unless @native_feature && @ruby_feature
10
+ end
11
+
12
+ it "doesn't looks up native features" do
13
+ Reflexive.loaded_features_lookup(@native_feature).should == nil
14
+ end
15
+
16
+ it "looks up ruby features when passed feature basename" do
17
+ ruby_feature_basename = File.basename(@ruby_feature)
18
+ Reflexive.loaded_features_lookup(ruby_feature_basename).should == @ruby_feature
19
+ end
20
+
21
+ it "looks up ruby features when passed feature basename and path part" do
22
+ feature_dirname = File.dirname(@ruby_feature)
23
+ feature_basename = File.basename(@ruby_feature)
24
+ feature_name = File.join(feature_dirname.split("/").last(2).join("/"),
25
+ feature_basename)
26
+ Reflexive.loaded_features_lookup(feature_name).should == @ruby_feature
27
+ end
28
+
29
+ it "looks up ruby features when passed feature basename without extension" do
30
+ ruby_feature_basename = File.basename(@ruby_feature).sub(/\.\w+\z/, "")
31
+ Reflexive.loaded_features_lookup(ruby_feature_basename).should == @ruby_feature
32
+ end
33
+ end
34
+
35
+ describe "Reflexive.constant_lookup" do
36
+ module M1
37
+ class C1
38
+ end
39
+ module M2
40
+ module M3
41
+ class C2
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ it "looks up top-level constants" do
48
+ Reflexive.constant_lookup("::String", "Some::Ignored::Scope").should == ::String
49
+ end
50
+
51
+ it "returns nil for non existing top-level constant" do
52
+ Reflexive.constant_lookup("::StringAsd", "Some::Ignored::Scope").should == nil
53
+ end
54
+
55
+ it "looks up top-level constants without scope" do
56
+ Reflexive.constant_lookup("String", "").should == ::String
57
+ end
58
+
59
+ it "looks up non top-level constants with scope" do
60
+ Reflexive.constant_lookup("C1", "M1").should == ::M1::C1
61
+ Reflexive.constant_lookup("C2", "M1::M2::M3").should == ::M1::M2::M3::C2
62
+ end
63
+
64
+ it "returns nil for non existing non top-level constants with scope" do
65
+ Reflexive.constant_lookup("CNotExist", "M1").should == nil
66
+ end
67
+ end
68
+
69
+ describe "Reflexive.load_path_lookup" do
70
+ it "looks up features present in $LOAD_PATH" do
71
+ feature = nil
72
+ $LOAD_PATH.each { |p| break if (feature = Dir["#{ p }/*.rb"].first) }
73
+ feature_basename = File.basename(feature).sub(/\.\w+\z/, "")
74
+ Reflexive.load_path_lookup(feature_basename).should == feature
75
+ end
76
+ end
77
+
78
+ describe "Reflexive.descendants" do
79
+ class X2 ; end
80
+ class A2 < X2; end
81
+ class B2 < X2; end
82
+
83
+ module M2
84
+ end
85
+
86
+ class C2
87
+ end
88
+
89
+ C2.extend(M2)
90
+
91
+ it "finds class descendant" do
92
+ Reflexive.descendants(X2).should =~ [B2, A2]
93
+ end
94
+
95
+ it "finds singleton class descendant" do
96
+ Reflexive.descendants(M2).should =~ [C2]
97
+ end
98
+ end