stratagem 0.2.0 → 0.2.2

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 (81) hide show
  1. data/LICENSE +29 -0
  2. data/Manifest +40 -38
  3. data/Rakefile +3 -3
  4. data/lib/stratagem.rb +22 -7
  5. data/lib/stratagem/authentication.rb +2 -1
  6. data/lib/stratagem/auto_mock/aquifer.rb +88 -15
  7. data/lib/stratagem/auto_mock/factory.rb +19 -30
  8. data/lib/stratagem/auto_mock/value_generator.rb +3 -1
  9. data/lib/stratagem/client.rb +3 -2
  10. data/lib/stratagem/crawler/authentication.rb +10 -3
  11. data/lib/stratagem/crawler/form.rb +2 -2
  12. data/lib/stratagem/crawler/html_utils.rb +12 -1
  13. data/lib/stratagem/crawler/parameter_resolver.rb +18 -4
  14. data/lib/stratagem/crawler/route_invoker.rb +58 -16
  15. data/lib/stratagem/crawler/session.rb +13 -5
  16. data/lib/stratagem/crawler/site_model.rb +20 -8
  17. data/lib/stratagem/extensions/object.rb +2 -2
  18. data/lib/stratagem/extensions/string.rb +2 -2
  19. data/lib/stratagem/instrumentation.rb +18 -0
  20. data/lib/stratagem/{framework_extensions → instrumentation}/method_invocation.rb +1 -1
  21. data/lib/stratagem/instrumentation/models.rb +25 -0
  22. data/lib/stratagem/instrumentation/models/annotations.rb +114 -0
  23. data/lib/stratagem/instrumentation/models/association.rb +40 -0
  24. data/lib/stratagem/instrumentation/models/authentication.rb +7 -0
  25. data/lib/stratagem/{framework_extensions/models/adapters → instrumentation/models/authentication}/authlogic/detect.rb +2 -2
  26. data/lib/stratagem/instrumentation/models/authentication/authlogic/instrumentation.rb +13 -0
  27. data/lib/stratagem/{framework_extensions/models/adapters → instrumentation/models/authentication}/authlogic/metadata.rb +1 -3
  28. data/lib/stratagem/instrumentation/models/authentication/devise/detect.rb +11 -0
  29. data/lib/stratagem/instrumentation/models/authentication/devise/instrumentation.rb +18 -0
  30. data/lib/stratagem/{framework_extensions/models/adapters → instrumentation/models/authentication}/devise/metadata.rb +7 -3
  31. data/lib/stratagem/{framework_extensions/models/adapters/util/authentication_metadata.rb → instrumentation/models/authentication/metadata.rb} +2 -2
  32. data/lib/stratagem/{framework_extensions/models/adapters → instrumentation/models/authentication}/restful_authentication/detect.rb +2 -4
  33. data/lib/stratagem/{framework_extensions/models/adapters/restful_authentication/extensions.rb → instrumentation/models/authentication/restful_authentication/instrumentation.rb} +1 -1
  34. data/lib/stratagem/{framework_extensions/models/adapters → instrumentation/models/authentication}/restful_authentication/metadata.rb +2 -2
  35. data/lib/stratagem/{framework_extensions → instrumentation}/models/detect.rb +1 -1
  36. data/lib/stratagem/{framework_extensions → instrumentation}/models/metadata.rb +6 -4
  37. data/lib/stratagem/{framework_extensions → instrumentation}/models/mocking.rb +1 -1
  38. data/lib/stratagem/instrumentation/models/persistence.rb +9 -0
  39. data/lib/stratagem/instrumentation/models/persistence/active_record/detect.rb +18 -0
  40. data/lib/stratagem/{framework_extensions/models/adapters → instrumentation/models/persistence}/active_record/extensions.rb +5 -1
  41. data/lib/stratagem/{framework_extensions/models/adapters → instrumentation/models/persistence}/active_record/metadata.rb +25 -9
  42. data/lib/stratagem/{framework_extensions/models/adapters → instrumentation/models/persistence}/active_record/tracing.rb +4 -2
  43. data/lib/stratagem/instrumentation/models/persistence/common/detect.rb +7 -0
  44. data/lib/stratagem/{framework_extensions/models/adapters → instrumentation/models/persistence}/common/extensions.rb +0 -0
  45. data/lib/stratagem/{framework_extensions/models/adapters → instrumentation/models/persistence}/common/metadata.rb +6 -2
  46. data/lib/stratagem/instrumentation/models/persistence/common/tracing.rb +4 -0
  47. data/lib/stratagem/instrumentation/models/support_libraries.rb +7 -0
  48. data/lib/stratagem/{framework_extensions/models/adapters → instrumentation/models/support_libraries}/friendly_id/detect.rb +2 -2
  49. data/lib/stratagem/{framework_extensions/models/adapters → instrumentation/models/support_libraries}/friendly_id/metadata.rb +2 -2
  50. data/lib/stratagem/instrumentation/models/support_libraries/state_machine/detect.rb +11 -0
  51. data/lib/stratagem/instrumentation/models/support_libraries/state_machine/metadata.rb +17 -0
  52. data/lib/stratagem/{framework_extensions → instrumentation}/models/tracing.rb +2 -2
  53. data/lib/stratagem/{framework_extensions → instrumentation}/rails.rb +0 -0
  54. data/lib/stratagem/{framework_extensions → instrumentation}/rails2/action_controller.rb +0 -0
  55. data/lib/stratagem/{framework_extensions → instrumentation}/rails2/action_mailer.rb +0 -0
  56. data/lib/stratagem/{framework_extensions → instrumentation}/rails3/parameters.rb +0 -0
  57. data/lib/stratagem/{framework_extensions → instrumentation}/request_forgery_protection.rb +0 -0
  58. data/lib/stratagem/model/application.rb +30 -15
  59. data/lib/stratagem/model/components/controller.rb +2 -2
  60. data/lib/stratagem/model/components/reference.rb +2 -2
  61. data/lib/stratagem/model/components/view.rb +1 -1
  62. data/lib/stratagem/model_builder.rb +19 -8
  63. data/lib/stratagem/scanner.rb +1 -1
  64. data/lib/stratagem/site_crawler.rb +4 -2
  65. data/stratagem.gemspec +7 -7
  66. data/templates/install/tasks/stratagem.rake +9 -1
  67. metadata +86 -82
  68. data/lib/stratagem/framework_extensions.rb +0 -18
  69. data/lib/stratagem/framework_extensions/models.rb +0 -21
  70. data/lib/stratagem/framework_extensions/models/adapters/active_record/detect.rb +0 -7
  71. data/lib/stratagem/framework_extensions/models/adapters/authlogic/extensions.rb +0 -10
  72. data/lib/stratagem/framework_extensions/models/adapters/authlogic/tracing.rb +0 -4
  73. data/lib/stratagem/framework_extensions/models/adapters/common/detect.rb +0 -7
  74. data/lib/stratagem/framework_extensions/models/adapters/common/tracing.rb +0 -4
  75. data/lib/stratagem/framework_extensions/models/adapters/devise/detect.rb +0 -11
  76. data/lib/stratagem/framework_extensions/models/adapters/devise/extensions.rb +0 -0
  77. data/lib/stratagem/framework_extensions/models/adapters/devise/tracing.rb +0 -4
  78. data/lib/stratagem/framework_extensions/models/adapters/friendly_id/extensions.rb +0 -0
  79. data/lib/stratagem/framework_extensions/models/adapters/friendly_id/tracing.rb +0 -4
  80. data/lib/stratagem/framework_extensions/models/adapters/restful_authentication/tracing.rb +0 -4
  81. data/lib/stratagem/framework_extensions/models/annotations.rb +0 -78
@@ -9,7 +9,7 @@ module Stratagem
9
9
  def send(snapshot)
10
10
  Stratagem.logger.debug "Sending report to server"
11
11
  url = URI.parse("#{@authentication.base_url}/snapshots")
12
- req = Net::HTTPS::Post.new(url.path)
12
+ req = Stratagem.ssl? ? Net::HTTPS::Post.new(url.path) : Net::HTTP::Post.new(url.path)
13
13
 
14
14
  req.set_form_data({
15
15
  'auth_token' => @authentication.credentials[:token],
@@ -17,7 +17,8 @@ module Stratagem
17
17
  'timestamp' => snapshot.timestamp.to_i,
18
18
  'model' => snapshot.model.export.to_json
19
19
  }, ';')
20
- res = Net::HTTPS.new(url.host, url.port).start {|http| http.request(req) }
20
+ client = Stratagem.ssl? ? Net::HTTPS.new(url.host, url.port) : Net::HTTP.new(url.host, url.port)
21
+ res = client.start {|http| http.request(req) }
21
22
  puts "response:"
22
23
  case res
23
24
  when Net::HTTPSuccess, Net::HTTPRedirection
@@ -75,9 +75,15 @@ module Stratagem::Crawler
75
75
  if authentication.login_page.nil?
76
76
  puts "locating login page"
77
77
  puts "testing #{site_models.first.pages.size} pages"
78
- site_models.first.pages.sort {|a,b| b.inbound_edges(:redirect).size <=> a.inbound_edges(:redirect).size }.each do |page|
79
- if (page.login_form)
80
- puts "\tfound login form - #{page.login_form}"
78
+ possibilities = site_models.first.pages.select {|page| page.login_form != nil }
79
+ possibilities.sort! {|a,b| b.inbound_edges(:redirect).size <=> a.inbound_edges(:redirect).size }
80
+
81
+ # if the first page has one or more redirects to it then use it; otherwise select with page with the fewest inputs
82
+ if (possibilities.first.inbound_edges(:redirect).size > 0)
83
+ return possibilities.first
84
+ else
85
+ page = possibilities.sort {|a,b| a.login_form.inputs.size <=> b.login_form.inputs.size }.first
86
+ if (page)
81
87
  authentication.login_page = page
82
88
  return page
83
89
  end
@@ -94,6 +100,7 @@ module Stratagem::Crawler
94
100
 
95
101
  def login(user)
96
102
  populate_login_form(user).submit {|action,params|
103
+ p params
97
104
  post(action, params)
98
105
  }
99
106
  end
@@ -1,7 +1,7 @@
1
1
  # Primarily used to fill out login forms rather than trying to fudge the before_filters
2
2
  module Stratagem::Crawler
3
3
  class Form
4
- attr_accessor :action, :method, :fields, :buttons, :page
4
+ attr_accessor :action, :method, :buttons, :page
5
5
  attr_reader :inputs, :buttons
6
6
 
7
7
  def initialize
@@ -70,7 +70,7 @@ module Stratagem::Crawler
70
70
 
71
71
  def guess_alternate_attribute
72
72
  if (name =~ /(.*)\[(.*)\]/)
73
- $1.to_sym
73
+ $2.to_sym
74
74
  else
75
75
  name.to_sym
76
76
  end
@@ -13,12 +13,22 @@ module Stratagem::Crawler
13
13
  # this maps to the form action, not the controller action
14
14
  form.action =~ /log[-]*in/ ||
15
15
  form.action =~ /sign[-]*in/ ||
16
- !form.inputs.find {|input| input.type == 'password' }.nil?
16
+ begin
17
+ password_field = form.inputs.find {|input| input.type == 'password' }
18
+ if (password_field)
19
+ confirmation_field = form.inputs.find {|input| input.name.include?('_confirmation') && (input.name.to_s.sub('_confirmation','') == password_field.name) }
20
+ confirmation_field.nil?
21
+ else
22
+ false
23
+ end
24
+ end
17
25
  }.sort {|a,b| a.inputs.size <=> b.inputs.size }
18
26
  possibilities.first
19
27
  end
20
28
 
21
29
  def parse_forms(document)
30
+ return [] if document.nil?
31
+
22
32
  document.xpath('//form').map do |form_tag|
23
33
  form = Form.new()
24
34
  form.action = form_load_attribute(form_tag, 'action')
@@ -49,6 +59,7 @@ module Stratagem::Crawler
49
59
  value = (value ? value.value : option_tag.inner_html).strip
50
60
  input << value unless value.empty?
51
61
  end
62
+ form << input
52
63
  end
53
64
 
54
65
  def form_add_input(form, input_tag)
@@ -10,7 +10,7 @@ module Stratagem::Crawler
10
10
  if (unknown_params.size > 0)
11
11
  resolve_with_convention(unknown_params, resolved_params)
12
12
  resolve_with_instrumentation(route_container, resolved_params)
13
-
13
+ resolve_id_with_convention(route_container, unknown_params, resolved_params)
14
14
  log "\tresolved parameter types - #{resolved_params.inspect}"
15
15
  end
16
16
 
@@ -67,13 +67,27 @@ module Stratagem::Crawler
67
67
  unknown_params.delete(param)
68
68
  puts "\t\tresolved #{param} to #{model} using convention"
69
69
  rescue NameError
70
- puts $!
71
- puts $!.backtrace
72
- # not a model
70
+ puts "ERROR: #{$!.message}"
73
71
  end
74
72
  end
75
73
  end
76
74
  end
77
75
 
76
+ # resolve the ID parameter by looking at the previous segment of the URL
77
+ def resolve_id_with_convention(route_container, unknown_params, resolved_params)
78
+ if (unknown_params.include?('id'))
79
+ route_container.path.split('/').inject(nil) {|prev,part|
80
+ if (prev && part == ':id')
81
+ begin
82
+ resolved_params['id'] = prev.singularize.camelize.constantize
83
+ unknown_params.delete('id')
84
+ rescue
85
+ puts $!.message
86
+ end
87
+ end
88
+ part
89
+ }
90
+ end
91
+ end
78
92
  end
79
93
  end
@@ -14,16 +14,17 @@ module Stratagem::Crawler
14
14
  def call_route(route_info, track_invocations=true)
15
15
  begin
16
16
  call_route!(route_info, track_invocations)
17
- rescue
17
+ rescue Exception
18
18
  # TODO - add exception as a response page
19
19
  puts "ERROR: #{$!.message}"
20
+ puts $!.backtrace
20
21
  end
21
22
  end
22
23
 
23
24
  def call_route!(route_info, track_invocations=true)
24
25
  return if route_info.nil?
25
26
 
26
- puts route_info[:verb].downcase+" "+route_info[:path]
27
+ puts route_info[:verb].downcase+" "+route_info[:path]+" - #{route_info[:route_container].path}"
27
28
  verb = route_info[:verb].downcase
28
29
  verb = 'get' if verb == '' || verb == 'any'
29
30
 
@@ -33,6 +34,7 @@ module Stratagem::Crawler
33
34
  do_get(route_info)
34
35
  puts "\tresponse code: #{response.code}" if response
35
36
  when 'post'
37
+ do_post(route_info)
36
38
  when 'put'
37
39
  do_put(route_info)
38
40
  when 'delete'
@@ -48,8 +50,10 @@ module Stratagem::Crawler
48
50
  invocations.each do |i|
49
51
  puts "\t\t#{i.controller_action} -> #{i.model_class}"
50
52
  end
51
- puts "\tchanges: #{changes.values.inspect}" if changes.size > 0
53
+
54
+ puts "\tchanges values: #{changes.values.inspect}" if changes.size > 0
52
55
  site_model.add(route_info[:route_container], controller, request, response, invocations, changes) {|redirect_url| redirect_proc.call(redirect_url) }
56
+ puts "\tadded to site model"
53
57
  end
54
58
  else
55
59
  puts "ERROR: did not call #{route_info.inspect}"
@@ -61,9 +65,12 @@ module Stratagem::Crawler
61
65
  end
62
66
 
63
67
  def do_put(route_info)
64
- raise "unable to invoke PUT requests, application must first be crawled with GET requests for phase #{phase}." unless site_model.pages.size > 0
68
+ # raise "unable to invoke PUT requests, application must first be crawled with GET requests for phase #{site_model.name}." unless site_model.pages.size > 0
65
69
 
66
70
  form = guess_form_for_route(route_info)
71
+ if (form.nil?)
72
+ puts "WARNING: could not locate form for route #{route_info[:route_container].path}"
73
+ end
67
74
 
68
75
  params = {}
69
76
 
@@ -77,15 +84,11 @@ module Stratagem::Crawler
77
84
  end
78
85
  end
79
86
 
80
- p hash_reads
81
-
82
87
  # let's find out what the method is looking for in the params object
83
88
  models_by_hash_key = infer_models_for_param_reads(route_info[:route_container],hash_reads)
84
89
  params = map_models_to_attributes(models_by_hash_key)
85
90
 
86
- p params
87
-
88
- guess_unknown_params(models_by_hash_key, params, form)
91
+ guess_unknown_params(models_by_hash_key, params, form) if form
89
92
 
90
93
  # run again with the params
91
94
  puts "PUTTING: #{route_info[:path]} with #{params.inspect}"
@@ -95,13 +98,47 @@ module Stratagem::Crawler
95
98
  end
96
99
  end
97
100
 
101
+ def do_post(route_info)
102
+ raise "unable to invoke PUT requests, application must first be crawled with GET requests for phase #{phase}." unless site_model.pages.size > 0
103
+
104
+ form = guess_form_for_route(route_info)
105
+ if (form.nil?)
106
+ puts "WARNING: could not locate form for route #{route_info[:route_container].path}"
107
+ end
108
+
109
+ params = {}
110
+
111
+ # note: this should fail to generate anything meaningful, as we have not yet set up the parameters
112
+ hash_reads = Hash.track_parameter_reads do
113
+ begin
114
+ post route_info[:path], params
115
+ rescue
116
+ # TODO - log error as page response
117
+ puts "ERROR: #{response.code}"
118
+ end
119
+ end
120
+
121
+ # let's find out what the method is looking for in the params object
122
+ models_by_hash_key = infer_models_for_param_reads(route_info[:route_container],hash_reads)
123
+ params = map_models_to_attributes(models_by_hash_key)
124
+
125
+ guess_unknown_params(models_by_hash_key, params, form) if form
126
+
127
+ # run again with the params
128
+ puts "POSTING: #{route_info[:path]} with #{params.inspect}"
129
+
130
+ invocation_delta = model_invocations_for_request(:write) do
131
+ post route_info[:path], params
132
+ end
133
+ end
134
+
98
135
  private
99
136
 
100
137
  def guess_unknown_params(models_by_hash_key, known_params, form)
101
138
  (form.parameter_keys - IGNORE_PARAMETERS) .each {|path_s|
102
139
  path = path_s.split('[')
103
140
  path.last.gsub!(']', '')
104
- value = known_params
141
+ value = known_params || {}
105
142
  model = nil
106
143
  path.each do |key|
107
144
  key = key.to_sym
@@ -137,8 +174,11 @@ module Stratagem::Crawler
137
174
  site_model.pages.each do |page|
138
175
  page.forms.each do |form|
139
176
  usable = route_info[:route_container].responds_to?(form.action, form.implied_method || form.method)
140
- # puts "\t#{form.action} - #{form.method} - #{form.implied_method}"
141
- # puts "\tUSABLE" if usable
177
+ usable ||= begin
178
+ (route_info[:path].sub(/\.\(\:format\)*/, '') == form.action) &&
179
+ ((form.implied_method || form.method).to_s.downcase == route_info[:verb].to_s.downcase)
180
+ end
181
+ puts "\tform: #{form.action} - #{form.implied_method || form.method} - #{usable}"
142
182
  forms << form if (usable)
143
183
  end
144
184
  end
@@ -183,9 +223,12 @@ module Stratagem::Crawler
183
223
  if (invocation.model_instance)
184
224
  model = application_model.models.find {|m| m.klass == invocation.model_instance.class }
185
225
 
186
- puts "\t\t#{invocation.model_class}.#{invocation.method} - #{invocation.model_instance}"
226
+ puts "\t\t#{invocation.model_class}.#{invocation.method} - #{invocation.model_instance} - #{invocation.model_instance.id}"
227
+ ids = aquifer.instances_of(invocation.model_instance.class).map {|i| i.id }
228
+ puts "\t\tinstances: #{ids.inspect}"
187
229
  prior = aquifer.instances_of(invocation.model_instance.class).find {|m| m.id == invocation.model_instance.id }
188
230
  post = invocation.model_instance
231
+ prior ||= post
189
232
  attribute_names = (prior.stratagem.attribute_names + prior.stratagem.foreign_keys)
190
233
  changes[model] = attribute_names.select {|an|
191
234
  begin
@@ -216,7 +259,7 @@ module Stratagem::Crawler
216
259
  yield path
217
260
  else
218
261
  combinations = segment_values[0].product(*segment_values.slice(1,segment_values.size-1))
219
- combinations.each do |combination|
262
+ combinations.uniq.each do |combination|
220
263
  url = path.clone
221
264
  route.segment_keys.each_with_index {|segment_key,i| url.gsub!(':'+segment_key.to_s, combination[i].to_s) }
222
265
  yield url
@@ -232,7 +275,7 @@ module Stratagem::Crawler
232
275
 
233
276
 
234
277
  i = 12345
235
- insert_values = (route.segment_keys - [:format]).map {|segment_key|
278
+ insert_values = (route_container.segment_keys - [:format]).map {|segment_key|
236
279
  model = parameter_types[segment_key.to_s]
237
280
  value = nil
238
281
  if (model)
@@ -250,7 +293,6 @@ module Stratagem::Crawler
250
293
  permutation = {:verb => verb, :path => path, :route_container => route_container}
251
294
  routes << permutation
252
295
  end
253
-
254
296
  [routes, params]
255
297
  end
256
298
 
@@ -91,21 +91,29 @@ module Stratagem::Crawler::Session
91
91
 
92
92
  def print
93
93
  # print out pages and inbound / outbound links
94
+ # debugger
94
95
  site_model.pages.each do |page|
95
96
  title = page.title
96
97
  title ||= page.redirected_to.url if page.redirected_to
97
98
  title ||= page.response.code
98
99
  log "Page: #{page.url} - #{title} - #{page.response.code}"
99
- page.outbound_edges.each do |edge|
100
- log "\tout: #{edge.to.url} - #{edge.to.title} - #{edge.to.route}"
101
- end
102
- page.inbound_edges.each do |edge|
103
- log "\tin: #{edge.from.url} - #{edge.from.title}"
100
+ begin
101
+ page.outbound_edges.each do |edge|
102
+ log "\tout: #{edge.to.url} - #{edge.to.title} - #{edge.to.route}"
103
+ end
104
+ page.inbound_edges.each do |edge|
105
+ log "\tin: #{edge.from.url} - #{edge.from.title}"
106
+ end
107
+ rescue Exception
108
+ puts $!.message
109
+ puts $!.backtrace
104
110
  end
105
111
  end
112
+ puts "end of site model"
106
113
  end
107
114
 
108
115
  def crawl(verbs=[:any,:get])
116
+ puts "crawling site for verbs #{verbs.inspect}"
109
117
  verbs = [verbs] unless verbs.kind_of?(Array)
110
118
 
111
119
  # grab all pages independently
@@ -17,6 +17,7 @@ module Stratagem::Crawler
17
17
  :pages => @pages.map {|page| page.export },
18
18
  :edges => @edges.map {|edge| edge.export },
19
19
  :authentication => authentication.nil? ? nil : {
20
+ :authenticated_user_id => authentication.authenticated_with.object_id,
20
21
  :success => authentication.success,
21
22
  :login_page_external_id => authentication.login_page.object_id,
22
23
  :response_page_external_id => authentication.response_page.object_id,
@@ -74,12 +75,13 @@ module Stratagem::Crawler
74
75
  attr_accessor :method
75
76
  attr_accessor :redirected_to
76
77
  attr_accessor :document
78
+ attr_accessor :response_body
77
79
 
78
80
  def initialize(site_model, controller, request, response, invocations, model_changes, &block)
79
81
  @site_model = site_model
80
82
  @invocations = invocations
81
83
  @model_changes = model_changes
82
- @authenticity_checked = controller.authenticity_checked?
84
+ @authenticity_checked = (controller && controller.methods.include?(:authenticity_checked?)) ? controller.authenticity_checked? : true
83
85
  init(request, response, &block)
84
86
  end
85
87
 
@@ -98,7 +100,8 @@ module Stratagem::Crawler
98
100
  :references => @invocations.map {|i| i.to_reference.export },
99
101
  :model_changes => Hash[@model_changes.map {|model,changes| [model.object_id, changes] }].to_json,
100
102
  :authenticity_checked => @authenticity_checked,
101
- :parameters => @request.parameters.to_json
103
+ :parameters => @request.parameters.to_json,
104
+ :response_body => @response_body
102
105
  }
103
106
  h
104
107
  end
@@ -109,7 +112,12 @@ module Stratagem::Crawler
109
112
  @url = request.url
110
113
  @path = request.path
111
114
  @method = request.method
112
- @document = Nokogiri::HTML(response.body)
115
+ begin
116
+ @document = Nokogiri::HTML(response.body)
117
+ rescue
118
+ puts "ERROR: Could not parse html: #{$!.message} - #{response.body}"
119
+ end
120
+ @response_body = response.body
113
121
  self.redirected_to = block.call(response.redirect_url) if response.redirect?
114
122
  end
115
123
 
@@ -126,11 +134,15 @@ module Stratagem::Crawler
126
134
 
127
135
  def forms
128
136
  @forms ||= begin
129
- forms = self.parse_forms(@document)
130
- forms.each do |form|
131
- form.page = self
137
+ if (@document)
138
+ forms = self.parse_forms(@document)
139
+ forms.each do |form|
140
+ form.page = self
141
+ end
142
+ forms
143
+ else
144
+ []
132
145
  end
133
- forms
134
146
  end
135
147
  end
136
148
 
@@ -151,7 +163,7 @@ module Stratagem::Crawler
151
163
  end
152
164
 
153
165
  def title
154
- unless @title
166
+ if ((@document) && !(@title))
155
167
  title = (@document/'head title').first
156
168
  @title = title.inner_html if title
157
169
  end
@@ -2,8 +2,8 @@ class Object
2
2
  def methods_include?(name)
3
3
  methods.include?(name.to_sym) || methods.include?(name.to_s)
4
4
  end
5
-
6
- def self.subclasses
5
+
6
+ def self.sg_subclasses
7
7
  classes = []
8
8
  ObjectSpace.each_object(Class) do |c|
9
9
  next unless c.superclass == self || c.ancestors.include?(self)
@@ -7,8 +7,8 @@ class String
7
7
  match = false
8
8
  [
9
9
  Regexp.compile("^#{token}$", true),
10
- Regexp.compile("^#{token}[^A-Za-z0-9]", true),
11
- Regexp.compile("[^A-Za-z0-9]#{token}$", true),
10
+ Regexp.compile("^#{token}[^A-Za-z0-9_\-]*", true),
11
+ Regexp.compile("[^A-Za-z0-9_\-]*#{token}$", true),
12
12
  ].each do |regex|
13
13
  if (regex.match(self))
14
14
  match = true
@@ -0,0 +1,18 @@
1
+ module Stratagem::Instrumentation; end
2
+
3
+ require 'stratagem/instrumentation/rails'
4
+ require 'stratagem/instrumentation/method_invocation'
5
+ require 'stratagem/instrumentation/models'
6
+ require 'stratagem/instrumentation/request_forgery_protection'
7
+
8
+ if (Stratagem.rails_3?)
9
+ require 'stratagem/instrumentation/rails3/parameters'
10
+ elsif (Stratagem.rails_2?)
11
+ require 'stratagem/instrumentation/rails2/action_controller'
12
+ require 'stratagem/instrumentation/rails2/action_mailer'
13
+ else
14
+ raise "Unsupported Rails version #{Stratagem.rails_version}"
15
+ end
16
+
17
+
18
+