reflexive 0.0.6 → 0.1.0

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.
@@ -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
- for scanner_event in extract_scanner_events_from_tree(params_event)
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.dup
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 =>
@@ -19,8 +19,11 @@ module Reflexive
19
19
 
20
20
  def parse
21
21
  parse_tree = super
22
- require 'pp'
23
- # pp parse_tree
22
+
23
+ if ENV["DEBUG"]
24
+ require 'pp'
25
+ pp parse_tree
26
+ end
24
27
 
25
28
  ParseTreeTopDownWalker.new(parse_tree).walk
26
29
  parse_tree
@@ -1,70 +1,91 @@
1
1
  require "cgi" unless defined?(CGI) && defined?(CGI::escape)
2
2
 
3
- module RoutingHelpers
4
- # method_call_tag is the scanner event tag emitted by ReflexiveRipper
5
- def method_call_path(method_call_tag)
6
- # r method_call_tag.values_at(:name, :receiver)
7
- name, receiver = method_call_tag.values_at(:name, :receiver)
8
- if receiver.last == :instance
9
- new_method_path(receiver[0..-2].join("::"), :instance, name)
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
- # entry point for method links (may dispatch to
16
- # class_method_definition_path or method_documentation_path based on whether
17
- # the method definition was found by with our reflection capabilities)
18
- def new_method_path(constant, level, method_name)
19
- "/reflexive/constants/#{ constant }/#{ level }_methods/#{ CGI.escape(method_name.to_s) }"
20
- end
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
- def class_method_definition_path(constant, method_name)
23
- new_method_path(constant, :class, method_name) + "/definition"
24
- end
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
- def instance_method_definition_path(constant, method_name)
27
- new_method_path(constant, :instance, method_name) + "/definition"
28
- end
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
- def method_documentation_path(constant, method_name)
31
- method_path(constant, method_name) + "/apidock"
32
- end
36
+ def method_path(constant, method_name)
37
+ "/reflexive/constants/#{ constant }/methods/#{ CGI.escape(method_name.to_s) }"
38
+ end
33
39
 
34
- def dashboard_path
35
- "/reflexive/dashboard"
36
- end
40
+ def new_method_definition_path(constant, level, method_name)
41
+ new_method_path(constant, level, method_name) + "/definition"
42
+ end
37
43
 
38
- def up_path(path)
39
- file_path(File.expand_path("../", path))
40
- end
44
+ def class_method_definition_path(constant, method_name)
45
+ new_method_path(constant, :class, method_name) + "/definition"
46
+ end
41
47
 
42
- def file_path(path)
43
- File.join("/reflexive/files", path)
44
- end
48
+ def instance_method_definition_path(constant, method_name)
49
+ new_method_path(constant, :instance, method_name) + "/definition"
50
+ end
45
51
 
46
- def constant_lookup_path(name, scope)
47
- "/reflexive/constant_lookup" <<
48
- "?name=#{ CGI.escape(name) }&scope=#{ CGI.escape(scope.join("::"))}"
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
- def load_path_lookup_path(path)
52
- "/reflexive/load_path_lookup?path=#{ CGI.escape(path.to_s) }"
53
- end
56
+ def dashboard_path
57
+ "/reflexive/dashboard"
58
+ end
54
59
 
55
- def constant_path(constant)
56
- "/reflexive/constants/#{ constant }"
57
- end
60
+ def up_path(path)
61
+ file_path(File.expand_path("../", path))
62
+ end
58
63
 
59
- def method_path(constant, method_name)
60
- "/reflexive/constants/#{ constant }/methods/#{ CGI.escape(method_name.to_s) }"
61
- end
64
+ def file_path(path)
65
+ File.join("/reflexive/files", path)
66
+ end
62
67
 
63
- def apidock_path(constant, method_name)
64
- "http://apidock.com/ruby/#{ constant }/#{ CGI.escape(method_name.to_s) }"
65
- end
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
- def method_definition_path(constant, method_name)
68
- method_path(constant, method_name) + "/definition"
87
+ def method_definition_path(constant, level, method_name)
88
+ method_path(constant, method_name) + "/definition"
89
+ end
69
90
  end
70
91
  end
@@ -102,6 +102,11 @@ pre .lva-highlight
102
102
  .dashboard .column
103
103
  {
104
104
  float: left;
105
+
106
+ }
107
+
108
+ .dashboard .column.first
109
+ {
105
110
  width: 350px;
106
111
  }
107
112
 
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", :instance]} }
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