stratagem 0.1.8 → 0.1.9

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 (64) hide show
  1. data/Manifest +16 -18
  2. data/Rakefile +3 -3
  3. data/bin/stratagem +54 -6
  4. data/generators/stratagem/stratagem_generator.rb +26 -0
  5. data/lib/generators/stratagem/install/USAGE +0 -0
  6. data/lib/generators/stratagem/install/install_base.rb +35 -0
  7. data/lib/generators/stratagem/install/install_generator.rb +24 -0
  8. data/lib/stratagem.rb +87 -57
  9. data/lib/stratagem/authentication.rb +2 -2
  10. data/lib/stratagem/auto_mock/aquifer.rb +6 -1
  11. data/lib/stratagem/auto_mock/factory.rb +2 -2
  12. data/lib/stratagem/client.rb +1 -1
  13. data/lib/stratagem/crawler.rb +2 -0
  14. data/lib/stratagem/crawler/authentication.rb +10 -9
  15. data/lib/stratagem/crawler/parameter_resolver.rb +83 -0
  16. data/lib/stratagem/crawler/route_invoker.rb +187 -0
  17. data/lib/stratagem/crawler/session.rb +23 -251
  18. data/lib/stratagem/crawler/site_model.rb +18 -16
  19. data/lib/stratagem/framework_extensions.rb +12 -1
  20. data/lib/stratagem/framework_extensions/method_invocation.rb +50 -0
  21. data/lib/stratagem/framework_extensions/models/adapters/active_model/detect.rb +1 -1
  22. data/lib/stratagem/framework_extensions/models/adapters/active_model/extensions.rb +20 -11
  23. data/lib/stratagem/framework_extensions/models/adapters/active_model/metadata.rb +7 -3
  24. data/lib/stratagem/framework_extensions/models/adapters/active_model/tracing.rb +11 -9
  25. data/lib/stratagem/framework_extensions/models/adapters/friendly_id/detect.rb +12 -0
  26. data/lib/stratagem/framework_extensions/models/adapters/friendly_id/extensions.rb +0 -0
  27. data/lib/stratagem/framework_extensions/models/adapters/friendly_id/metadata.rb +21 -0
  28. data/lib/stratagem/framework_extensions/models/adapters/friendly_id/tracing.rb +4 -0
  29. data/lib/stratagem/framework_extensions/models/annotations.rb +1 -24
  30. data/lib/stratagem/framework_extensions/models/tracing.rb +9 -3
  31. data/lib/stratagem/framework_extensions/rails.rb +0 -6
  32. data/lib/stratagem/framework_extensions/{controllers → rails2}/action_controller.rb +0 -0
  33. data/lib/stratagem/framework_extensions/{controllers → rails2}/action_mailer.rb +0 -0
  34. data/lib/stratagem/framework_extensions/rails3/parameters.rb +14 -0
  35. data/lib/stratagem/interface/browser.rb +3 -1
  36. data/lib/stratagem/model/application.rb +6 -6
  37. data/lib/stratagem/model/components/controller.rb +17 -63
  38. data/lib/stratagem/model/components/model.rb +33 -33
  39. data/lib/stratagem/model/components/reference.rb +8 -4
  40. data/lib/stratagem/model/components/route.rb +40 -14
  41. data/lib/stratagem/model/components/view.rb +1 -1
  42. data/lib/stratagem/model_builder.rb +71 -42
  43. data/lib/stratagem/site_crawler.rb +1 -1
  44. data/lib/stratagem/snapshot.rb +0 -1
  45. data/stratagem.gemspec +10 -7
  46. data/templates/install/environments/stratagem.rb.erb +16 -0
  47. data/templates/install/tasks/stratagem.rake +18 -0
  48. metadata +57 -40
  49. data/lib/stratagem/framework_extensions/controllers.rb +0 -5
  50. data/lib/stratagem/scan/checks/filter_parameter_logging.rb +0 -6
  51. data/lib/stratagem/scan/checks/mongo_mapper/base.rb +0 -19
  52. data/lib/stratagem/scan/checks/mongo_mapper/foreign_keys_exposed.rb +0 -32
  53. data/lib/stratagem/scan/checks/routes.rb +0 -16
  54. data/lib/tasks/_old_stratagem.rake +0 -99
  55. data/spec/model/component_spec.rb +0 -43
  56. data/spec/model/components/view_spec.rb +0 -43
  57. data/spec/model/test_spec.rb +0 -10
  58. data/spec/samples/404.html.erb +0 -30
  59. data/spec/samples/_form.html.erb +0 -8
  60. data/spec/samples/index.html.erb +0 -77
  61. data/spec/samples/sample_model.rb +0 -5
  62. data/spec/samples/signup.html.erb +0 -14
  63. data/spec/scan/checks/email_address_spec.rb +0 -24
  64. data/spec/scan/checks/error_pages_spec.rb +0 -22
@@ -51,12 +51,12 @@ module Stratagem::AutoMock
51
51
  return [object,valid] if valid
52
52
  end
53
53
 
54
- protected
55
-
56
54
  def add_mocked(instance)
57
55
  (mocked(instance.class)) << instance
58
56
  end
59
57
 
58
+ protected
59
+
60
60
  def mocked(model=nil)
61
61
  @mocked ||= {}
62
62
  if (model)
@@ -11,7 +11,7 @@ module Stratagem
11
11
  url = URI.parse("#{@authentication.base_url}/snapshots")
12
12
  req = Net::HTTP::Post.new(url.path)
13
13
  req.set_form_data({
14
- 'api_key' => @authentication.credentials[:token],
14
+ 'auth_token' => @authentication.credentials[:token],
15
15
  'project_id' => @authentication.credentials[:project],
16
16
  'timestamp' => snapshot.timestamp.to_i,
17
17
  'model' => snapshot.model.export.to_json
@@ -5,5 +5,7 @@ require 'stratagem/crawler/form'
5
5
  require 'stratagem/crawler/trace_utils'
6
6
  require 'stratagem/crawler/html_utils'
7
7
  require 'stratagem/crawler/authentication'
8
+ require 'stratagem/crawler/parameter_resolver'
9
+ require 'stratagem/crawler/route_invoker'
8
10
  require 'stratagem/crawler/session'
9
11
  require 'stratagem/crawler/site_model'
@@ -41,14 +41,14 @@ module Stratagem::Crawler
41
41
  reset_authentication
42
42
 
43
43
  login(user)
44
- route = application_model.routes.recognize(response.request.path, :post)
44
+ route = application_model.routes.recognize(request.path, :post)
45
45
 
46
46
  redirected_to = nil
47
- page = site_model.add(route, response) {|redirect_url| redirected_to = redirect_url }
47
+ page = site_model.add(route, request, response) {|redirect_url| redirected_to = redirect_url }
48
48
  authentication.response_page = page
49
49
 
50
50
  begin
51
- if (response.request.url == (redirected_to || '')) || (![200,302].include?(response.code.to_i))
51
+ if (request.url == (redirected_to || '')) || (![200,302].include?(response.code.to_i))
52
52
  authentication.success = false
53
53
  else
54
54
  authentication.success = authentication.response_page.login_form.nil?
@@ -60,7 +60,7 @@ module Stratagem::Crawler
60
60
 
61
61
  puts "authenticated? #{authentication.success}"
62
62
  if (response && authentication.success)
63
- authentication.ssl = response.request.ssl?
63
+ authentication.ssl = request.ssl?
64
64
  yield
65
65
  logout
66
66
  else
@@ -90,15 +90,13 @@ module Stratagem::Crawler
90
90
  end
91
91
 
92
92
  def logout
93
- get "/signout"
94
- get "/logout"
95
- delete "/user_sessions/1"
93
+ reset!
96
94
  end
97
95
 
98
96
  def login(user)
99
97
  populate_login_form(user).submit {|action,params|
100
98
  post(action, params)
101
- puts response.body
99
+ # puts response.body
102
100
  }
103
101
  end
104
102
 
@@ -124,7 +122,10 @@ module Stratagem::Crawler
124
122
  def populate_login_form(user)
125
123
  # set up the form
126
124
  page = find_login_form
127
- page.reload {|url| get url; response }
125
+ p page.login_form
126
+ page.reload {|url| get url; [request,response] }
127
+ p page.login_form
128
+ p page.response.body
128
129
  form = page.login_form
129
130
 
130
131
  # map the input values
@@ -0,0 +1,83 @@
1
+ module Stratagem::Crawler
2
+ module ParameterResolver
3
+
4
+ def resolve_parameter_types(route_container)
5
+ log "\tresolving parameter types"
6
+ resolved_params = {}
7
+ route_infos, params = build_url(route_container, resolved_params)
8
+ route_info = route_infos.first
9
+ unknown_params = params.keys
10
+ log "\tunknown params: #{unknown_params.inspect} - #{unknown_params.size}"
11
+
12
+ resolve_with_convention(unknown_params, resolved_params)
13
+ log "\tunknown params after convention: #{unknown_params.inspect} - #{unknown_params.size}"
14
+
15
+ resolve_with_instrumentation(route_container, resolved_params)
16
+ log "\tunknown params after instrumentation: #{unknown_params.inspect} - #{unknown_params.size}"
17
+
18
+ p resolved_params
19
+
20
+ if (resolved_params.size > 0)
21
+ resolved_params
22
+ else
23
+ nil
24
+ end
25
+ end
26
+
27
+ def resolve_with_instrumentation(route_container, resolved_params)
28
+ route_infos, params = build_url(route_container, resolved_params)
29
+ route_info = route_infos.first
30
+ unknown_params = params.keys
31
+
32
+ progress = nil
33
+ while ((unknown_params.size > 0) && (progress.nil? || (progress > 0)))
34
+ progress = 0
35
+
36
+ puts "\tloading model invocations for request"
37
+ delta = model_invocations_for_request do
38
+ call_route(route_info, false)
39
+ end
40
+
41
+ puts "\tcalled route, found #{delta.size} invocations"
42
+
43
+ unknown_params.clone.each do |key|
44
+ value = params[key]
45
+ value_s = params[key].map {|v| v.to_s }
46
+ delta.each do |invocation|
47
+ # TODO inspect is a hack, refactor
48
+ if (invocation.args.include?(value.first)) || (invocation.args.inspect.include?('"'+value.first.to_s+'"'))
49
+ # found match
50
+ puts "\t\tresolved #{key} to #{invocation.model_class}"
51
+ unknown_params.delete(key)
52
+ resolved_params[key] = invocation.model_class
53
+ progress += 1
54
+ break
55
+ end
56
+ end
57
+ end
58
+
59
+ route_infos, params = build_url(route_container, resolved_params)
60
+ route_info = route_infos.first
61
+ end
62
+ end
63
+
64
+ def resolve_with_convention(unknown_params, resolved_params)
65
+ unknown_params.each do |param|
66
+ if (param =~ /_id$/)
67
+ begin
68
+ model = param.gsub(/^:/,'').gsub(/_id$/, '').camelize.constantize
69
+ #success
70
+ resolved_params[param] = model
71
+ unknown_params.delete(param)
72
+ puts "\t\tresolved #{param} to #{model} using convention"
73
+ rescue NameError
74
+ puts $!
75
+ puts $!.backtrace
76
+ # not a model
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,187 @@
1
+ module Stratagem::Crawler
2
+ module RouteInvoker
3
+ include Stratagem::Crawler::ParameterResolver
4
+
5
+ def visit(route_container)
6
+ puts "Visiting #{route_container.route}"
7
+ build_urls(route_container).each do |route_info|
8
+ call_route(route_info)
9
+ end
10
+ end
11
+
12
+ def call_route(route_info, track_invocations=true)
13
+ begin
14
+ call_route!(route_info, track_invocations)
15
+ rescue
16
+ # TODO - add exception as a response page
17
+ puts "ERROR: #{$!.message}"
18
+ end
19
+ end
20
+
21
+ def call_route!(route_info, track_invocations=true)
22
+ return if route_info.nil?
23
+
24
+ puts 'CALLING: .'+route_info[:verb].downcase+". - "+route_info[:path]
25
+ verb = route_info[:verb].downcase
26
+ verb = 'get' if verb == '' || verb == 'any'
27
+
28
+ invocations = model_invocations_for_request do
29
+ case verb
30
+ when 'get'
31
+ do_get(route_info)
32
+ puts "\tresponse code: #{response.code}" if response
33
+ when 'post'
34
+ when 'put'
35
+ do_put(route_info)
36
+ when 'delete'
37
+ else
38
+ raise "Unsupported verb: #{route[:verb]}"
39
+ end
40
+ end
41
+
42
+ if (response)
43
+ if (track_invocations)
44
+ changes = detect_attribute_changes_in_models(invocations)
45
+ puts "\tfound #{invocations.size} invocations"
46
+ puts "\tchanges: #{changes.values.inspect}" if changes.size > 0
47
+ site_model.add(route_info[:route_container], request, response, invocations, changes) {|redirect_url| redirect_proc.call(redirect_url) }
48
+ end
49
+ else
50
+ puts "ERROR: did not call #{route_info.inspect}"
51
+ end
52
+ end
53
+
54
+ def do_get(route_info)
55
+ get route_info[:path]
56
+ end
57
+
58
+ def do_put(route_info)
59
+
60
+ # note: this should fail to generate anything meaningful, as we have not yet set up the parameters
61
+ put route_info[:path]
62
+
63
+ # let's find out what the method is looking for in the params object
64
+ params = map_models_to_attributes(infer_models_for_param_reads(route_info[:route_container],controller.params.hash_reads))
65
+
66
+ # run again with the params
67
+ puts "PUTTING: #{route_info[:path]} with #{params.inspect}"
68
+
69
+ invocation_delta = model_invocations_for_request(:write) do
70
+ put route_info[:path], params
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+
77
+ def map_models_to_attributes(models)
78
+ result = {}
79
+ models.each {|param_read,model|
80
+ result[param_read] = aquifer.mock_attributes(model.klass)
81
+ }
82
+ result
83
+ end
84
+
85
+ def infer_models_for_param_reads(route,param_reads)
86
+ param_reads = param_reads.select {|read| read.to_s !~ /_id$/ }
87
+ param_reads -= [:action,'action',:controller,'controller',:id,'id',:format,'format']
88
+
89
+ result = {}
90
+
91
+ # resolve param reads to model types
92
+ # only support simple expected mappings at the moment
93
+ param_reads.each do |param_read|
94
+ class_name = param_read.to_s.camelize
95
+ if (class_name.singularize == class_name)
96
+ # this looks promising
97
+ model = application_model.models.find {|model| model.klass.name == class_name }
98
+ if (model)
99
+ puts "\t\tresolved param #{param_read} to #{model.klass.name}"
100
+ result[param_read] = model
101
+ end
102
+ end
103
+ end
104
+
105
+ result
106
+ end
107
+
108
+ def detect_attribute_changes_in_models(invocations)
109
+ changes = {}
110
+ invocations.select {|invocation| invocation.type == :write }.each do |invocation|
111
+ if (invocation.model_instance)
112
+ model = application_model.models.find {|m| m.klass == invocation.model_instance.class }
113
+
114
+ puts "\t\t#{invocation.model_class}.#{invocation.method} - #{invocation.model_instance}"
115
+ prior = aquifer.instances_of(invocation.model_instance.class).find {|m| m.id == invocation.model_instance.id }
116
+ post = invocation.model_instance
117
+ attribute_names = (prior.stratagem.attribute_names + prior.stratagem.foreign_keys)
118
+ changes[model] = attribute_names.select {|an|
119
+ begin
120
+ prior.send(an) != post.send(an)
121
+ rescue
122
+ puts "\t\t\t#{an} cannot be determined - #{$!.message}"
123
+ end
124
+ }
125
+ end
126
+ end
127
+ changes
128
+ end
129
+
130
+ # Builds a list of string URLs for a given route. This is done
131
+ # by replacing :xyz_id segments in the route with known values
132
+ # from the well
133
+ def build_urls(route_container)
134
+ urls = []
135
+ route = route_container.route
136
+ param_types = (self.parameter_types[route_container] ||= resolve_parameter_types(route_container))
137
+ route_infos, params = build_url(route_container, param_types)
138
+ route_infos
139
+ end
140
+
141
+ def url_permutations(route, segment_values, &block)
142
+ path = route.path.sub('(.:format)', '')
143
+ if (segment_values.size == 0)
144
+ yield path
145
+ else
146
+ combinations = segment_values[0].product(*segment_values.slice(1,segment_values.size-1))
147
+ combinations.each do |combination|
148
+ url = path.clone
149
+ route.segment_keys.each_with_index {|segment_key,i| url.gsub!(':'+segment_key.to_s, combination[i].to_s) }
150
+ yield url
151
+ end
152
+ end
153
+ end
154
+
155
+ def build_url(route_container, parameter_types={})
156
+ parameter_types ||= {}
157
+ params = {}
158
+ route = route_container.route
159
+ verb = route_container.verb.to_s
160
+
161
+
162
+ i = 12345
163
+ insert_values = (route.segment_keys - [:format]).map {|segment_key|
164
+ model = parameter_types[segment_key.to_s]
165
+ value = nil
166
+ if (model)
167
+ value = (aquifer.instances_of model).map {|inst|
168
+ inst.methods_include?(segment_key) ? inst.send(segment_key) : inst.to_param
169
+ }
170
+ else
171
+ value = [i += 1]
172
+ end
173
+ params[segment_key.to_s] = value
174
+ }
175
+
176
+ routes = []
177
+ url_permutations(route_container,insert_values) do |path|
178
+ puts "yielded: #{path}"
179
+ permutation = {:verb => verb, :path => path, :route_container => route_container}
180
+ routes << permutation
181
+ end
182
+
183
+ [routes, params]
184
+ end
185
+
186
+ end
187
+ end
@@ -29,6 +29,20 @@ module Stratagem::Crawler::Session
29
29
  include Stratagem::Crawler::HtmlUtils
30
30
  include Stratagem::Crawler::TraceUtils
31
31
  include Stratagem::Crawler::Authentication
32
+ include Stratagem::Crawler::RouteInvoker
33
+
34
+ attr_writer :aquifer
35
+
36
+ # def self.app
37
+ # # DEPRECATE Rails application fallback
38
+ # # This should be set by the initializer
39
+ # (defined?(Rails.application) && Rails.application) || nil
40
+ # end
41
+ #
42
+
43
+ def app
44
+ (defined?(Rails.application) && Rails.application) || nil
45
+ end
32
46
 
33
47
  def log(msg)
34
48
  Stratagem.logger.debug msg
@@ -68,14 +82,18 @@ module Stratagem::Crawler::Session
68
82
  end
69
83
 
70
84
  def page_set(name, &block)
85
+ reset!
71
86
  site_models << Stratagem::Crawler::SiteModel.new(name)
72
87
  yield site_model
73
88
  end
74
89
 
75
- def display
90
+ def print
76
91
  # print out pages and inbound / outbound links
77
92
  site_model.pages.each do |page|
78
- log "Page: #{page.url} - #{page.title} - #{page.response.code}"
93
+ title = page.title
94
+ title ||= page.redirected_to.url if page.redirected_to
95
+ title ||= page.response.code
96
+ log "Page: #{page.url} - #{title} - #{page.response.code}"
79
97
  page.outbound_edges.each do |edge|
80
98
  log "\tout: #{edge.to.url} - #{edge.to.title} - #{edge.to.route}"
81
99
  end
@@ -102,10 +120,10 @@ module Stratagem::Crawler::Session
102
120
  else
103
121
  if (application_model.routes.invalid.include?(route_container))
104
122
  log "Skipping invalid route #{route_container.route.to_s}"
105
- elsif (verbs.include?(route_container.route.conditions[:method]))
123
+ elsif (verbs.include?(route_container.verb))
106
124
  visit(route_container)
107
125
  else
108
- log "Skipping route with verb #{route_container.route.conditions[:method]} - #{route_container.route.to_s}"
126
+ log "Skipping route with verb #{route_container.verb} - #{route_container.route.to_s}"
109
127
  end
110
128
  end
111
129
  }
@@ -120,203 +138,6 @@ module Stratagem::Crawler::Session
120
138
 
121
139
  private
122
140
 
123
- def visit(route_container)
124
- puts "Visiting #{route_container.route}"
125
- build_urls(route_container).each do |route_info|
126
- call_route(route_container, route_info)
127
- end
128
- end
129
-
130
- def call_route(route, route_info, track_invocations=true)
131
- return if route_info.nil?
132
-
133
- puts 'CALLING: .'+route_info[:verb].downcase+". - "+route_info[:path]
134
- verb = route_info[:verb].downcase
135
- verb = 'get' if verb == '' || verb == 'any'
136
-
137
- begin
138
- invocations = model_invocations_for_request do
139
- case verb
140
- when 'get'
141
- do_get(route, route_info[:path])
142
- puts "\tresponse code: #{response.code}" if response
143
- when 'post'
144
- when 'put'
145
- do_put(route, route_info[:path])
146
- when 'delete'
147
- else
148
- raise "Unsupported verb: #{route[:verb]}"
149
- end
150
- end
151
-
152
- if (response)
153
- changes = detect_attribute_changes_in_models(invocations)
154
- puts "\tfound #{invocations.size} invocations"
155
- puts "\tchanges: #{changes.values.inspect}" if changes.size > 0
156
- site_model.add(route, response, invocations, changes) {|redirect_url| redirect_proc.call(redirect_url) }
157
- else
158
- puts "ERROR: did not call #{route_info.inspect}"
159
- end
160
- rescue
161
- puts $!.message
162
- puts $!.backtrace
163
- end
164
- end
165
-
166
- def do_get(route,path)
167
- get path
168
- end
169
-
170
- def do_put(route,path)
171
-
172
- # note: this should fail to generate anything meaningful, as we have not yet set up the parameters
173
- put path
174
-
175
- # let's find out what the method is looking for in the params object
176
- params = map_models_to_attributes(infer_models_for_param_reads(route,controller.params.hash_reads))
177
-
178
- # run again with the params
179
- puts "PUTTING: #{path} with #{params.inspect}"
180
-
181
- invocation_delta = model_invocations_for_request(:write) do
182
- put path, params
183
- end
184
- end
185
-
186
- def map_models_to_attributes(models)
187
- result = {}
188
- models.each {|param_read,model|
189
- result[param_read] = aquifer.mock_attributes(model.klass)
190
- }
191
- result
192
- end
193
-
194
- def infer_models_for_param_reads(route,param_reads)
195
- param_reads = param_reads.select {|read| read.to_s !~ /_id$/ }
196
- param_reads -= [:action,'action',:controller,'controller',:id,'id',:format,'format']
197
-
198
- result = {}
199
-
200
- # resolve param reads to model types
201
- # only support simple expected mappings at the moment
202
- param_reads.each do |param_read|
203
- class_name = param_read.to_s.camelize
204
- if (class_name.singularize == class_name)
205
- # this looks promising
206
- model = application_model.models.find {|model| model.klass.name == class_name }
207
- if (model)
208
- puts "\t\tresolved param #{param_read} to #{model.klass.name}"
209
- result[param_read] = model
210
- end
211
- end
212
- end
213
-
214
- result
215
- end
216
-
217
- def detect_attribute_changes_in_models(invocations)
218
- changes = {}
219
- invocations.select {|invocation| invocation.type == :write }.each do |invocation|
220
- if (invocation.model_instance)
221
- model = application_model.models.find {|m| m.klass == invocation.model_instance.class }
222
-
223
- puts "\t\t#{invocation.model_class}.#{invocation.method} - #{invocation.model_instance}"
224
- prior = aquifer.instances_of(invocation.model_instance.class).find {|m| m.id == invocation.model_instance.id }
225
- post = invocation.model_instance
226
- attribute_names = (prior.stratagem.attribute_names + prior.stratagem.foreign_keys)
227
- changes[model] = attribute_names.select {|an|
228
- begin
229
- prior.send(an) != post.send(an)
230
- rescue
231
- puts "\t\t\t#{an} cannot be determined - #{$!.message}"
232
- end
233
- }
234
- end
235
- end
236
- changes
237
- end
238
-
239
- # Builds a list of string URLs for a given route. This is done
240
- # by replacing :xyz_id segments in the route with known values
241
- # from the well
242
- def build_urls(route_container)
243
- urls = []
244
- route = route_container.route
245
- param_types = (self.parameter_types[route_container] ||= resolve_parameter_types(route_container))
246
- route_infos, params = build_url(route_container, param_types)
247
- # puts "route: #{route_container.route.to_s} - #{parameter_types.inspect} - permutations:"
248
- # route_infos.each do |info|
249
- # puts "\t#{info[:path]}"
250
- # end
251
- route_infos
252
- end
253
-
254
- def url_permutations(meta_segments, segment_stack=[], &block)
255
- if (segment_stack.size == meta_segments.size)
256
- yield segment_stack
257
- else
258
- cursor = segment_stack.size
259
- options = meta_segments[cursor]
260
- if (options.kind_of?(Array))
261
- options.each do |option|
262
- url_permutations(meta_segments, segment_stack + [option], &block)
263
- end
264
- else
265
- url_permutations(meta_segments, segment_stack + [options], &block)
266
- end
267
- end
268
- end
269
-
270
- def build_url(route_container, parameter_types={})
271
- params = {}
272
- route = route_container.route
273
- name = route.to_s
274
- verb = route.conditions[:method].to_s
275
-
276
- parameter_types ||= {}
277
-
278
- i = 12345
279
- segs = route.segments.inject([]) {|accumulated,segment|
280
- s = segment.to_s
281
- if (s =~ /^:/)
282
- model = parameter_types[s]
283
- value = nil
284
- if (model)
285
- if (aquifer.instances_of(model).size == 0)
286
- aquifer.print
287
- end
288
- value = (aquifer.instances_of model).map {|inst|
289
- attr_name = s.gsub(/^:/, '').to_sym
290
- if inst.methods_include?(attr_name)
291
- inst.send(attr_name)
292
- else
293
- inst.id
294
- end
295
- }
296
- else
297
- i += 1
298
- value = [i]
299
- end
300
- accumulated << value
301
- params[s] = value
302
- else
303
- accumulated << s
304
- end
305
- accumulated
306
- }
307
-
308
- routes = []
309
- reqs = route.requirements.empty? ? "" : route.requirements.inspect
310
- url_permutations(segs) do |segments|
311
- path = segments.join('').gsub('(.:format)', '').gsub(/\/$/, '')
312
- puts "\t\tbuilt url: #{path}"
313
- permutation = {:name => name, :verb => verb, :segs => segs, :reqs => reqs, :path => path}
314
- routes << permutation
315
- end
316
-
317
- [routes, params]
318
- end
319
-
320
141
  def handle_redirect(redirect_url)
321
142
  existing_pages = site_model.pages_for(response.redirect_url)
322
143
  if (existing_pages.size > 0)
@@ -326,59 +147,10 @@ module Stratagem::Crawler::Session
326
147
  get redirect_url
327
148
  end
328
149
 
329
- site_model.add(nil, response) {|redirect_url|
150
+ site_model.add(nil, request, response) {|redirect_url|
330
151
  # TODO - record as bug!
331
152
  puts "recursive redirect #{redirect_url}"
332
153
  }
333
154
  end
334
155
  end
335
-
336
- def resolve_parameter_types(route_container)
337
- puts "\tresolving parameter types"
338
- resolved_parameters = {}
339
- route_infos, params = build_url(route_container, resolved_parameters)
340
- route_info = route_infos.first
341
- unknown_params = params.keys
342
- log "\tunknown params: #{unknown_params.inspect} - #{unknown_params.size}"
343
- progress = nil
344
- while ((unknown_params.size > 0) && (progress.nil? || (progress > 0)))
345
- progress = 0
346
-
347
- puts "\tloading model invocations for request"
348
- delta = model_invocations_for_request do
349
- call_route(route_container, route_info, false)
350
- end
351
-
352
- puts "\tcalled route, found #{delta.size} invocations"
353
-
354
- unknown_params.clone.each do |key|
355
- value = params[key]
356
- value_s = params[key].map {|v| v.to_s }
357
- delta.each do |invocation|
358
- # puts "\t#{route_info[:path]} - #{invocation.model_class.name} - #{invocation.method} - #{invocation.args.inspect} - #{value_s}"
359
- # TODO inspect is a hack, refactor
360
- if (invocation.args.include?(value.first)) || (invocation.args.inspect.include?('"'+value.first.to_s+'"'))
361
- # found match
362
-
363
- puts "\t\tresolved #{key} to #{invocation.model_class}"
364
- unknown_params.delete(key)
365
- resolved_parameters[key] = invocation.model_class
366
- progress += 1
367
-
368
- break
369
- end
370
- end
371
- end
372
-
373
- route_infos, params = build_url(route_container, resolved_parameters)
374
- route_info = route_infos.first
375
- end
376
-
377
- if (resolved_parameters.size > 0)
378
- resolved_parameters
379
- else
380
- nil
381
- end
382
- end
383
-
384
156
  end