reflexive 0.0.3 → 0.0.4

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