reflexive 0.0.6 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +9 -7
- data/Rakefile +10 -4
- data/config.ru +1 -1
- data/lib/reflexive/application.rb +50 -30
- data/lib/reflexive/coderay_html_encoder.rb +1 -1
- data/lib/reflexive/coderay_ruby_scanner.rb +2 -0
- data/lib/reflexive/core_ext/module/reflexive_instance_methods.rb +44 -0
- data/lib/reflexive/descendants.rb +12 -2
- data/lib/reflexive/helpers.rb +26 -9
- data/lib/reflexive/method_lookup.rb +199 -0
- data/lib/reflexive/methods.rb +3 -2
- data/lib/reflexive/parse_tree_top_down_walker.rb +69 -8
- data/lib/reflexive/reflexive_ripper.rb +5 -2
- data/lib/reflexive/routing_helpers.rb +74 -53
- data/public/stylesheets/reflexive/reflexive.css +5 -0
- data/reflexive.gemspec +9 -6
- data/spec/coderay_html_encoder_spec.rb +8 -2
- data/spec/integration_spec.rb +227 -0
- data/spec/integration_spec_fixture.rb +87 -0
- data/spec/method_lookup_spec.rb +348 -0
- data/spec/methods_spec.rb +246 -28
- data/spec/rails_integration_spec.rb +7 -0
- data/spec/rails_integration_spec_helper.rb +21 -11
- data/spec/reflexive_ripper_spec.rb +57 -19
- data/spec/reflexive_spec.rb +15 -0
- data/views/constants_show.erb +18 -1
- data/views/dashboard.erb +3 -4
- data/views/layout.erb +10 -0
- data/views/methods_apidock.erb +9 -1
- data/views/methods_choose.erb +19 -0
- metadata +76 -40
data/lib/reflexive/methods.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "reflexive/core_ext/kernel/singleton_class"
|
2
|
+
require "reflexive/core_ext/module/reflexive_instance_methods"
|
2
3
|
|
3
4
|
module Reflexive
|
4
5
|
class Methods
|
@@ -36,7 +37,7 @@ module Reflexive
|
|
36
37
|
def each_immediate_class_and_instance_method(&block)
|
37
38
|
VISIBILITIES.each do |visibility|
|
38
39
|
[ @klass_or_module, @klass_or_module.singleton_class ].each do |klass|
|
39
|
-
methods = klass.send("#{ visibility }_instance_methods", false)
|
40
|
+
methods = klass.send("reflexive_#{ visibility }_instance_methods", false)
|
40
41
|
methods.each { |m| block.call(klass.instance_method(m)) }
|
41
42
|
end
|
42
43
|
end
|
@@ -123,7 +124,7 @@ module Reflexive
|
|
123
124
|
# when no methods are found - returns nil
|
124
125
|
def collect_instance_methods(klass)
|
125
126
|
methods_with_visibility = VISIBILITIES.map do |visibility|
|
126
|
-
methods = klass.send("#{ visibility }_instance_methods", false)
|
127
|
+
methods = klass.send("reflexive_#{ visibility }_instance_methods", false)
|
127
128
|
[visibility, methods] unless methods.empty?
|
128
129
|
end.compact
|
129
130
|
Hash[methods_with_visibility] unless methods_with_visibility.empty?
|
@@ -91,7 +91,17 @@ module Reflexive
|
|
91
91
|
return unless params_event
|
92
92
|
params_event = params_event[1] if params_event[0] == :paren # ?
|
93
93
|
found = false
|
94
|
-
|
94
|
+
|
95
|
+
if options_arguments = params_event[2]
|
96
|
+
options_arguments.each do |optional_argument|
|
97
|
+
if scanner_event?(event = optional_argument[0])
|
98
|
+
add_local_variable(event)
|
99
|
+
keep_walking(optional_argument[1..-1])
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
for scanner_event in extract_scanner_events_from_tree(params_event.values_at(1,3,4,5))
|
95
105
|
if scanner_event[:ident]
|
96
106
|
found = true
|
97
107
|
add_local_variable(scanner_event)
|
@@ -167,10 +177,11 @@ module Reflexive
|
|
167
177
|
|
168
178
|
def on_def(name, params, body)
|
169
179
|
push_local_variables_context
|
180
|
+
# TODO this is hack :(
|
181
|
+
push_namespace_instance_scope unless @in_singleton_class_defition
|
170
182
|
add_local_variables_from_params_event(params)
|
171
|
-
push_namespace_instance_scope
|
172
183
|
keep_walking(body)
|
173
|
-
pop_namespace_scope
|
184
|
+
pop_namespace_scope unless @in_singleton_class_defition
|
174
185
|
pop_local_variables_context
|
175
186
|
end
|
176
187
|
|
@@ -182,7 +193,7 @@ module Reflexive
|
|
182
193
|
end
|
183
194
|
|
184
195
|
def on_class(name, ancestor, body)
|
185
|
-
keep_walking(name)
|
196
|
+
keep_walking(name, ancestor)
|
186
197
|
push_local_variables_context
|
187
198
|
push_namespace_scope(resolve_constant_ref(name))
|
188
199
|
keep_walking(body)
|
@@ -192,7 +203,9 @@ module Reflexive
|
|
192
203
|
|
193
204
|
def on_sclass(target, body)
|
194
205
|
push_local_variables_context
|
206
|
+
@in_singleton_class_defition = true
|
195
207
|
keep_walking(body)
|
208
|
+
@in_singleton_class_defition = false
|
196
209
|
pop_local_variables_context
|
197
210
|
end
|
198
211
|
|
@@ -231,13 +244,61 @@ module Reflexive
|
|
231
244
|
|
232
245
|
def on_command(operation, command_args)
|
233
246
|
method_call(operation, nil) if is_ident?(operation)
|
247
|
+
if operation[:ident] == "autoload" &&
|
248
|
+
(arguments = resolve_arguments(command_args))
|
249
|
+
|
250
|
+
if [:const, :tstring_content].include?(arguments[0].keys.first)
|
251
|
+
constant_access(arguments[0], arguments[0].values.first)
|
252
|
+
end
|
253
|
+
end
|
234
254
|
keep_walking(command_args)
|
235
255
|
end
|
236
256
|
|
257
|
+
def resolve_arguments(arguments)
|
258
|
+
arguments = arguments[1] if arguments[0] == :arg_paren
|
259
|
+
if arguments[0] == :args_add_block
|
260
|
+
if arguments[1].is_a?(Array)
|
261
|
+
arguments[1].map { |a| resolve_argument(a) }
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def resolve_argument(argument)
|
267
|
+
if argument[0] == :symbol_literal
|
268
|
+
# [:symbol_literal, [:symbol, {:const=>"C"}]]
|
269
|
+
if argument[1].is_a?(Array)
|
270
|
+
if argument[1][0] == :symbol
|
271
|
+
argument[1][1] # {:const=>"C"}
|
272
|
+
end
|
273
|
+
end
|
274
|
+
elsif argument[0] == :string_literal
|
275
|
+
# [:string_literal, [:string_content, {:tstring_content=>"C"}]]
|
276
|
+
if argument[1].is_a?(Array)
|
277
|
+
if argument[1][0] == :string_content
|
278
|
+
argument[1][1] # {:tstring_content=>"C"}
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
237
284
|
def on_fcall(operation)
|
238
285
|
method_call(operation, nil) if is_ident?(operation)
|
239
286
|
end
|
240
287
|
|
288
|
+
def on_method_add_arg(method, arguments)
|
289
|
+
|
290
|
+
if method[0] == :fcall &&
|
291
|
+
scanner_event?(method[1]) &&
|
292
|
+
method[1][:ident] == "autoload"
|
293
|
+
if arguments = resolve_arguments(arguments)
|
294
|
+
if [:const, :tstring_content].include?(arguments[0].keys.first)
|
295
|
+
constant_access(arguments[0], arguments[0].values.first)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
keep_walking(method, arguments)
|
300
|
+
end
|
301
|
+
|
241
302
|
# primary_value => anything
|
242
303
|
# operation2 : tIDENTIFIER
|
243
304
|
# | tCONSTANT
|
@@ -277,9 +338,9 @@ module Reflexive
|
|
277
338
|
def on_call(receiver, dot, method)
|
278
339
|
if rcv = resolve_receiver(receiver)
|
279
340
|
method_call(method, [rcv])
|
280
|
-
else
|
281
|
-
keep_walking(receiver)
|
282
341
|
end
|
342
|
+
|
343
|
+
keep_walking(receiver)
|
283
344
|
end
|
284
345
|
|
285
346
|
def on_var_ref(ref_event)
|
@@ -328,8 +389,8 @@ module Reflexive
|
|
328
389
|
|
329
390
|
def method_call(scanner_event, receiver, *args)
|
330
391
|
unless receiver
|
331
|
-
# implict self concept
|
332
|
-
receiver = @scope.
|
392
|
+
# implict self concept (will be fetched from constant_access_scope)
|
393
|
+
receiver = @scope.last == :instance ? :instance : :class
|
333
394
|
end
|
334
395
|
merge_tags(scanner_event,
|
335
396
|
{:method_call =>
|
@@ -1,70 +1,91 @@
|
|
1
1
|
require "cgi" unless defined?(CGI) && defined?(CGI::escape)
|
2
2
|
|
3
|
-
module
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
else
|
11
|
-
new_method_path(receiver.join("::"), :class, name)
|
12
|
-
end rescue(r(method_call_tag))
|
13
|
-
end
|
3
|
+
module Reflexive
|
4
|
+
module RoutingHelpers
|
5
|
+
# method_call_tag is the scanner event tag emitted by ReflexiveRipper
|
6
|
+
def method_call_path(method_call_tag)
|
7
|
+
# r method_call_tag.values_at(:name, :receiver)
|
8
|
+
name, receiver, scope = method_call_tag.values_at(:name, :receiver, :scope)
|
9
|
+
scope = scope.join("::")
|
14
10
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
11
|
+
if receiver == :class
|
12
|
+
scope = "Kernel" if scope.empty?
|
13
|
+
new_method_path(scope, :class, name)
|
14
|
+
elsif receiver == :instance
|
15
|
+
scope = "Kernel" if scope.empty?
|
16
|
+
new_method_path(scope, :instance, name)
|
17
|
+
else
|
18
|
+
receiver = receiver.join("::")
|
19
|
+
new_method_path(Reflexive.constant_lookup(receiver, scope), :class, name)
|
20
|
+
end
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
# if receiver.last == :instance
|
23
|
+
# new_method_path(receiver[0..-2].join("::"), :instance, name)
|
24
|
+
# else
|
25
|
+
# new_method_path(receiver.join("::"), :class, name)
|
26
|
+
# end rescue(r(method_call_tag))
|
27
|
+
end
|
25
28
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
+
# entry point for method links (may dispatch to
|
30
|
+
# class_method_definition_path or method_documentation_path based on whether
|
31
|
+
# the method definition was found by with our reflection capabilities)
|
32
|
+
def new_method_path(constant, level, method_name)
|
33
|
+
"/reflexive/constants/#{ constant }/#{ level }_methods/#{ CGI.escape(method_name.to_s) }"
|
34
|
+
end
|
29
35
|
|
30
|
-
|
31
|
-
|
32
|
-
|
36
|
+
def method_path(constant, method_name)
|
37
|
+
"/reflexive/constants/#{ constant }/methods/#{ CGI.escape(method_name.to_s) }"
|
38
|
+
end
|
33
39
|
|
34
|
-
|
35
|
-
|
36
|
-
|
40
|
+
def new_method_definition_path(constant, level, method_name)
|
41
|
+
new_method_path(constant, level, method_name) + "/definition"
|
42
|
+
end
|
37
43
|
|
38
|
-
|
39
|
-
|
40
|
-
|
44
|
+
def class_method_definition_path(constant, method_name)
|
45
|
+
new_method_path(constant, :class, method_name) + "/definition"
|
46
|
+
end
|
41
47
|
|
42
|
-
|
43
|
-
|
44
|
-
|
48
|
+
def instance_method_definition_path(constant, method_name)
|
49
|
+
new_method_path(constant, :instance, method_name) + "/definition"
|
50
|
+
end
|
45
51
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
52
|
+
def method_documentation_path(constant, level, method_name)
|
53
|
+
new_method_path(constant, level, method_name) + "/apidock"
|
54
|
+
end
|
50
55
|
|
51
|
-
|
52
|
-
|
53
|
-
|
56
|
+
def dashboard_path
|
57
|
+
"/reflexive/dashboard"
|
58
|
+
end
|
54
59
|
|
55
|
-
|
56
|
-
|
57
|
-
|
60
|
+
def up_path(path)
|
61
|
+
file_path(File.expand_path("../", path))
|
62
|
+
end
|
58
63
|
|
59
|
-
|
60
|
-
|
61
|
-
|
64
|
+
def file_path(path)
|
65
|
+
File.join("/reflexive/files", path)
|
66
|
+
end
|
62
67
|
|
63
|
-
|
64
|
-
|
65
|
-
|
68
|
+
def constant_lookup_path(name, scope)
|
69
|
+
"/reflexive/constant_lookup" <<
|
70
|
+
"?name=#{ CGI.escape(name) }&scope=#{ CGI.escape(scope.join("::"))}"
|
71
|
+
end
|
72
|
+
|
73
|
+
def load_path_lookup_path(path)
|
74
|
+
"/reflexive/load_path_lookup?path=#{ CGI.escape(path.to_s) }"
|
75
|
+
end
|
76
|
+
|
77
|
+
def constant_path(constant)
|
78
|
+
"/reflexive/constants/#{ constant }"
|
79
|
+
end
|
80
|
+
|
81
|
+
def apidock_path(constant, level, method_name)
|
82
|
+
path = "http://apidock.com/ruby/#{ constant }/#{ CGI.escape(method_name.to_s) }"
|
83
|
+
path << "/class" if level == :class
|
84
|
+
path
|
85
|
+
end
|
66
86
|
|
67
|
-
|
68
|
-
|
87
|
+
def method_definition_path(constant, level, method_name)
|
88
|
+
method_path(constant, method_name) + "/definition"
|
89
|
+
end
|
69
90
|
end
|
70
91
|
end
|
data/reflexive.gemspec
CHANGED
@@ -13,13 +13,16 @@ Gem::Specification.new do |s|
|
|
13
13
|
s.required_ruby_version = '>= 1.9.1'
|
14
14
|
|
15
15
|
# keeping this in sync with Gemfile manually
|
16
|
-
s.add_dependency "rack"
|
17
|
-
s.add_dependency "sinatra"
|
18
|
-
s.add_dependency "sinatra_more"
|
19
|
-
s.add_dependency "coderay"
|
20
|
-
s.add_dependency "rdiscount"
|
16
|
+
s.add_dependency "rack", "1.1.0"
|
17
|
+
s.add_dependency "sinatra", "1.0"
|
18
|
+
s.add_dependency "sinatra_more", "0.3.40"
|
19
|
+
s.add_dependency "coderay", "0.9.3"
|
20
|
+
# s.add_dependency "rdiscount"
|
21
21
|
|
22
22
|
s.add_development_dependency "rails", "3.0.0.beta3"
|
23
23
|
s.add_development_dependency "rspec", "2.0.0.beta.8"
|
24
|
-
s.add_development_dependency "sinatra-reloader"
|
24
|
+
s.add_development_dependency "sinatra-reloader", "0.4.1"
|
25
|
+
s.add_development_dependency "thin", "1.2.7"
|
26
|
+
s.add_development_dependency "rack-test", "0.5.3"
|
27
|
+
s.add_development_dependency "webrat", "0.7.1"
|
25
28
|
end
|
@@ -11,6 +11,12 @@ describe Reflexive::CodeRayHtmlEncoder do
|
|
11
11
|
{:constant_access=>{:name=>"Cons", :scope=>[]}}]]).should(include("<a href"))
|
12
12
|
end
|
13
13
|
|
14
|
+
it "emits constant links for :content tokens" do
|
15
|
+
encoder = Reflexive::CodeRayHtmlEncoder.new(:wrap => :div, :css => :style)
|
16
|
+
encoder.encode_tokens([["Cons", :content,
|
17
|
+
{:constant_access=>{:name=>"Cons", :scope=>[]}}]]).should(include("<a href"))
|
18
|
+
end
|
19
|
+
|
14
20
|
it "emits links with proper nesting info" do
|
15
21
|
tokens = [["Cons", :constant,
|
16
22
|
{:constant_access=>{:name=>"Cons", :scope=>["A", "B"]}}]]
|
@@ -26,7 +32,7 @@ describe Reflexive::CodeRayHtmlEncoder do
|
|
26
32
|
it "emits class method links" do
|
27
33
|
tokens = [ [
|
28
34
|
"m!", :ident,
|
29
|
-
{:method_call=>{:name=>"m!", :receiver=>["A"]} }
|
35
|
+
{:method_call=>{:name=>"m!", :receiver=>:class, :scope=>["A"]} }
|
30
36
|
] ]
|
31
37
|
encoder.encode_tokens(tokens).should include("/constants/A/class_methods/m%21")
|
32
38
|
end
|
@@ -34,7 +40,7 @@ describe Reflexive::CodeRayHtmlEncoder do
|
|
34
40
|
it "emits instance method links" do
|
35
41
|
tokens = [ [
|
36
42
|
"m!", :ident,
|
37
|
-
{:method_call=>{:name=>"m!", :receiver=>["A"
|
43
|
+
{:method_call=>{:name=>"m!", :receiver=>:instance, :scope => ["A"]} }
|
38
44
|
] ]
|
39
45
|
encoder.encode_tokens(tokens).should include("/constants/A/instance_methods/m%21")
|
40
46
|
end
|
@@ -0,0 +1,227 @@
|
|
1
|
+
require "reflexive/application"
|
2
|
+
require "rack/test"
|
3
|
+
require "nokogiri"
|
4
|
+
require "webrat/core/matchers"
|
5
|
+
|
6
|
+
FIXTURE_FILE_PATH = File.expand_path("../integration_spec_fixture.rb", __FILE__)
|
7
|
+
require FIXTURE_FILE_PATH
|
8
|
+
|
9
|
+
describe Reflexive::Application do
|
10
|
+
include Rack::Test::Methods
|
11
|
+
include Webrat::Matchers
|
12
|
+
|
13
|
+
include Reflexive::RoutingHelpers
|
14
|
+
|
15
|
+
def app
|
16
|
+
Reflexive::Application
|
17
|
+
end
|
18
|
+
|
19
|
+
it "shows dashboard" do
|
20
|
+
get(dashboard_path)
|
21
|
+
last_response.should be_ok
|
22
|
+
last_response.body.should include("Reflexive", "$LOAD_PATH", "Favorites")
|
23
|
+
last_response.body.should have_selector('a', :content => "Date")
|
24
|
+
last_response.body.should have_selector('a', :content => "Gem")
|
25
|
+
last_response.body.should have_selector('a', :content => "FileUtils")
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "class/module browser" do
|
29
|
+
def constant_browser_for(constant)
|
30
|
+
get(constant_path(constant))
|
31
|
+
last_response.should be_ok
|
32
|
+
last_response.body
|
33
|
+
end
|
34
|
+
|
35
|
+
it "shows class name" do
|
36
|
+
get(constant_path("OpenStruct"))
|
37
|
+
last_response.should be_ok
|
38
|
+
last_response.body.should include("OpenStruct")
|
39
|
+
end
|
40
|
+
|
41
|
+
it "shows files in which class is defined" do
|
42
|
+
constant_browser_for("OpenStruct").
|
43
|
+
should include("ostruct.rb")
|
44
|
+
constant_browser_for("IntegrationSpecFixture::TestClass").
|
45
|
+
should include("integration_spec_fixture.rb")
|
46
|
+
end
|
47
|
+
|
48
|
+
it "shows superclass" do
|
49
|
+
constant_browser_for("IntegrationSpecFixture::TestClass").
|
50
|
+
should include("TestBaseClass")
|
51
|
+
constant_browser_for("OpenStruct").
|
52
|
+
should include("BasicObject")
|
53
|
+
end
|
54
|
+
|
55
|
+
it "shows instance methods" do
|
56
|
+
constant_browser_for("IntegrationSpecFixture::TestClass").
|
57
|
+
should include("public_meth", "protected_meth", "private_meth")
|
58
|
+
end
|
59
|
+
|
60
|
+
it "shows class methods" do
|
61
|
+
constant_browser_for("IntegrationSpecFixture::TestClass").
|
62
|
+
should include("class_meth")
|
63
|
+
end
|
64
|
+
|
65
|
+
it "shows inherited instance methods" do
|
66
|
+
constant_browser_for("IntegrationSpecFixture::TestClass").
|
67
|
+
should include("inherited_meth")
|
68
|
+
end
|
69
|
+
|
70
|
+
it "shows inherited class methods" do
|
71
|
+
constant_browser_for("IntegrationSpecFixture::TestClass").
|
72
|
+
should include("inherited_class_meth")
|
73
|
+
end
|
74
|
+
|
75
|
+
it "shows instance methods for module" do
|
76
|
+
constant_browser_for("IntegrationSpecFixture::TestModule").
|
77
|
+
should include("module_meth")
|
78
|
+
end
|
79
|
+
|
80
|
+
it "shows class methods for module" do
|
81
|
+
constant_browser_for("IntegrationSpecFixture::TestModule").
|
82
|
+
should include("module_class_meth")
|
83
|
+
end
|
84
|
+
|
85
|
+
it "shows classes module is included in" do
|
86
|
+
constant_browser_for("IntegrationSpecFixture::TestModule").
|
87
|
+
should include("TestClass")
|
88
|
+
end
|
89
|
+
|
90
|
+
it "shows classes class is derived from" do
|
91
|
+
constant_browser_for("IntegrationSpecFixture::TestBaseClass").
|
92
|
+
should include("TestClass")
|
93
|
+
end
|
94
|
+
|
95
|
+
it "shows classes nested inside the class" do
|
96
|
+
constant_browser_for("IntegrationSpecFixture::TestClass").
|
97
|
+
should have_selector("a", :content => "NestedClass")
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "source browser" do
|
102
|
+
def source_browser
|
103
|
+
get(file_path(FIXTURE_FILE_PATH))
|
104
|
+
last_response.should be_ok
|
105
|
+
last_response.body
|
106
|
+
end
|
107
|
+
|
108
|
+
it "shows arbitrary files from file system" do
|
109
|
+
get(file_path(FIXTURE_FILE_PATH))
|
110
|
+
last_response.should be_ok
|
111
|
+
last_response.body.should include("integration_spec_fixture.rb")
|
112
|
+
end
|
113
|
+
|
114
|
+
it "browses directories" do
|
115
|
+
dir = File.dirname(FIXTURE_FILE_PATH)
|
116
|
+
get(file_path(dir))
|
117
|
+
last_response.should be_ok
|
118
|
+
|
119
|
+
Dir["#{ dir }/*"].each do |path|
|
120
|
+
last_response.body.should include(File.basename(path))
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
it "highlights the code" do
|
125
|
+
source_browser.should have_selector("span.no")
|
126
|
+
source_browser.should have_selector("span.s")
|
127
|
+
source_browser.should have_selector("span.r")
|
128
|
+
source_browser.should have_selector("span.co")
|
129
|
+
end
|
130
|
+
|
131
|
+
it "links class names" do
|
132
|
+
source_browser.should have_selector('a[href$="constant_lookup?name=TestBaseClass&scope=IntegrationSpecFixture"]')
|
133
|
+
end
|
134
|
+
|
135
|
+
it "links module names" do
|
136
|
+
source_browser.should have_selector('a[href$="constant_lookup?name=IntegrationSpecFixture&scope="]')
|
137
|
+
end
|
138
|
+
|
139
|
+
it "links arguments to require/load" do
|
140
|
+
source_browser.should have_selector('a[href$="load_path_lookup?path=ostruct"]')
|
141
|
+
end
|
142
|
+
|
143
|
+
it "links method calls from top level" do
|
144
|
+
source_browser.should have_selector('a[href$="constants/Kernel/class_methods/require"]')
|
145
|
+
end
|
146
|
+
|
147
|
+
it "links method calls from class instance level" do
|
148
|
+
source_browser.should have_selector('a[href$="constants/IntegrationSpecFixture::TestClass/class_methods/inherited_class_meth"]')
|
149
|
+
end
|
150
|
+
|
151
|
+
it "links method calls from class definition level" do
|
152
|
+
source_browser.should have_selector('a[href$="constants/IntegrationSpecFixture::TestClass/class_methods/another_inherited_class_meth"]')
|
153
|
+
end
|
154
|
+
|
155
|
+
it "links local variable assignments and access" do
|
156
|
+
source_browser.should have_selector('span[id^="lv:"][id$=":local_var"]', :content => "local_var") do |local_var_assignment|
|
157
|
+
source_browser.should have_selector('a[href="#' + local_var_assignment.first["id"] + '"]')
|
158
|
+
end
|
159
|
+
source_browser.should have_selector('span[id^="lv:"][id$=":another_local_var"]', :content => "another_local_var")
|
160
|
+
# source_browser.should have_selector('a.lva', :content => "another_local_var")
|
161
|
+
end
|
162
|
+
|
163
|
+
it "links method calls" do
|
164
|
+
source_browser.should have_selector('a[href$="constants/IntegrationSpecFixture::TestClass/instance_methods/not_defined_meth"]', :content => "not_defined_meth")
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe "constant lookup" do
|
169
|
+
it "redirects to found constant" do
|
170
|
+
get(constant_lookup_path("TestModule", ["IntegrationSpecFixture::TestClass"]))
|
171
|
+
|
172
|
+
last_response.should be_redirect
|
173
|
+
last_response.body.should be_empty
|
174
|
+
|
175
|
+
follow_redirect!
|
176
|
+
|
177
|
+
last_response.body.should match(/module\s+IntegrationSpecFixture::TestModule/)
|
178
|
+
last_response.body.should include("integration_spec_fixture.rb")
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
describe "method lookup" do
|
183
|
+
it "redirects to found method" do
|
184
|
+
get(new_method_path("IntegrationSpecFixture::TestClass", :instance, "inherited_meth"))
|
185
|
+
|
186
|
+
last_response.should be_redirect
|
187
|
+
last_response.body.should be_empty
|
188
|
+
|
189
|
+
follow_redirect!
|
190
|
+
|
191
|
+
last_request.path.should include("constants/IntegrationSpecFixture::TestClass/instance_methods/inherited_meth/definition")
|
192
|
+
end
|
193
|
+
|
194
|
+
it "shows error message when method is not found" do
|
195
|
+
get(new_method_path("IntegrationSpecFixture::TestClass", :instance, "not_defined_meth"))
|
196
|
+
|
197
|
+
last_response.should be_ok
|
198
|
+
last_response.body.should include("Reflexive Error")
|
199
|
+
end
|
200
|
+
|
201
|
+
it "redirect to documentation for core methods" do
|
202
|
+
get(new_method_path("IntegrationSpecFixture::TestClass", :class, "class_eval"))
|
203
|
+
|
204
|
+
last_response.should be_redirect
|
205
|
+
|
206
|
+
follow_redirect!
|
207
|
+
|
208
|
+
last_request.path.should include("constants/Module/instance_methods/class_eval/apidock")
|
209
|
+
end
|
210
|
+
|
211
|
+
it "uses heuristics providing user a way to choose method for module instance methods" do
|
212
|
+
get(new_method_path("IntegrationSpecFixture::HeuristicLookupBaseModule", :instance, "meth"))
|
213
|
+
|
214
|
+
last_response.should be_ok
|
215
|
+
last_response.body.should include("HeuristicLookupIncludingClass1")
|
216
|
+
last_response.body.should include("HeuristicLookupIncludingClass2")
|
217
|
+
end
|
218
|
+
|
219
|
+
it "uses heuristics providing user a way to choose method for class instance methods" do
|
220
|
+
get(new_method_path("IntegrationSpecFixture::HeuristicLookupBaseClass", :instance, "meth"))
|
221
|
+
|
222
|
+
last_response.should be_ok
|
223
|
+
last_response.body.should include("HeuristicLookupInheritingClass1")
|
224
|
+
last_response.body.should include("HeuristicLookupInheritingClass2")
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|