stratagem 0.1.7 → 0.1.8
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.
- data/Manifest +16 -4
- data/Rakefile +2 -2
- data/lib/bootstrap.rb +1 -0
- data/lib/stratagem/auto_mock/aquifer.rb +15 -7
- data/lib/stratagem/auto_mock/factory.rb +12 -2
- data/lib/stratagem/auto_mock/value_generator.rb +1 -1
- data/lib/stratagem/commands.rb +0 -1
- data/lib/stratagem/crawler/authentication.rb +116 -54
- data/lib/stratagem/crawler/form.rb +12 -0
- data/lib/stratagem/crawler/html_utils.rb +19 -7
- data/lib/stratagem/crawler/session.rb +156 -68
- data/lib/stratagem/crawler/site_model.rb +21 -7
- data/lib/stratagem/crawler/trace_utils.rb +3 -1
- data/lib/stratagem/extensions/trace_compression.rb +52 -0
- data/lib/stratagem/extensions.rb +1 -0
- data/lib/stratagem/framework_extensions/models/adapters/active_model/metadata.rb +3 -8
- data/lib/stratagem/framework_extensions/models/adapters/active_model/tracing.rb +21 -2
- data/lib/stratagem/framework_extensions/models/adapters/common/detect.rb +7 -0
- data/lib/stratagem/framework_extensions/models/adapters/common/extensions.rb +0 -0
- data/lib/stratagem/framework_extensions/models/adapters/common/metadata.rb +36 -0
- data/lib/stratagem/framework_extensions/models/adapters/common/tracing.rb +4 -0
- data/lib/stratagem/framework_extensions/models/adapters/{common → util}/authentication_metadata.rb +0 -0
- data/lib/stratagem/framework_extensions/models/annotations.rb +23 -1
- data/lib/stratagem/framework_extensions/models/metadata.rb +3 -3
- data/lib/stratagem/framework_extensions/models/tracing.rb +32 -10
- data/lib/stratagem/framework_extensions/models.rb +2 -2
- data/lib/stratagem/model/application.rb +8 -4
- data/lib/stratagem/model/components/base.rb +3 -0
- data/lib/stratagem/model/components/controller.rb +22 -23
- data/lib/stratagem/model/components/model.rb +3 -2
- data/lib/stratagem/model/components/reference.rb +24 -13
- data/lib/stratagem/model/components/route.rb +0 -3
- data/lib/stratagem/model/components/view.rb +1 -0
- data/lib/stratagem/model_builder.rb +9 -11
- data/lib/stratagem/site_crawler.rb +14 -19
- data/lib/stratagem.rb +1 -1
- data/spec/model/component_spec.rb +43 -0
- data/spec/model/components/view_spec.rb +43 -0
- data/spec/model/test_spec.rb +10 -0
- data/spec/samples/404.html.erb +30 -0
- data/spec/samples/_form.html.erb +8 -0
- data/spec/samples/index.html.erb +77 -0
- data/spec/samples/sample_model.rb +5 -0
- data/spec/samples/signup.html.erb +14 -0
- data/spec/scan/checks/email_address_spec.rb +24 -0
- data/spec/scan/checks/error_pages_spec.rb +22 -0
- data/stratagem.gemspec +7 -4
- metadata +50 -21
- data/lib/stratagem/commands/devel_crawl.rb +0 -27
- data/lib/stratagem/scan/checks/ssl/secure_login_page.rb +0 -19
- data/lib/stratagem/scan/checks/ssl/secure_login_submit.rb +0 -18
@@ -24,8 +24,6 @@ class CrawlError < StratagemError; end
|
|
24
24
|
# end
|
25
25
|
# end
|
26
26
|
|
27
|
-
PHASES = [:unauthenticated,:authenticated]
|
28
|
-
|
29
27
|
module Stratagem::Crawler::Session
|
30
28
|
include ActionController::Integration::Runner
|
31
29
|
include Stratagem::Crawler::HtmlUtils
|
@@ -36,38 +34,42 @@ module Stratagem::Crawler::Session
|
|
36
34
|
Stratagem.logger.debug msg
|
37
35
|
end
|
38
36
|
|
37
|
+
def parameter_types
|
38
|
+
@parameter_types ||= {}
|
39
|
+
end
|
40
|
+
|
41
|
+
def redirect_proc
|
42
|
+
@redirect_proc ||= Proc.new {|redirect_url| handle_redirect(redirect_url) }
|
43
|
+
end
|
44
|
+
|
39
45
|
def crawler_session(application_model=nil)
|
40
|
-
@
|
41
|
-
@model ||= Stratagem::ModelBuilder.new.run
|
42
|
-
@redirect_proc = Proc.new {|redirect_url| handle_redirect(redirect_url) }
|
43
|
-
@parameter_types = {} # routecontainer -> {:route_segment => Model, :route_segment => Model}
|
46
|
+
@application_model = application_model if application_model
|
44
47
|
open_session do |session|
|
45
48
|
@session = session
|
46
|
-
phase(:unauthenticated)
|
47
49
|
yield
|
48
50
|
end
|
49
51
|
end
|
50
52
|
|
51
53
|
def application_model
|
52
|
-
@
|
54
|
+
@application_model ||= Stratagem::ModelBuilder.new.run
|
55
|
+
end
|
56
|
+
|
57
|
+
def aquifer(initial_capacity=6)
|
58
|
+
@aquifer ||= Stratagem::AutoMock::Aquifer.init(application_model).fill(initial_capacity)
|
53
59
|
end
|
54
60
|
|
55
61
|
def site_models
|
56
|
-
@site_models ||=
|
62
|
+
@site_models ||= []
|
57
63
|
end
|
58
64
|
|
59
65
|
def site_model
|
60
|
-
raise Stratagem::Crawler::CrawlError.new("
|
61
|
-
|
62
|
-
end
|
63
|
-
|
64
|
-
def phase(new_phase)
|
65
|
-
@current_phase = new_phase
|
66
|
-
@current_model = site_models[@current_phase] ||= Stratagem::Crawler::SiteModel.new
|
66
|
+
raise Stratagem::Crawler::CrawlError.new("Not within page set") unless site_models.last
|
67
|
+
site_models.last
|
67
68
|
end
|
68
69
|
|
69
|
-
def
|
70
|
-
site_models
|
70
|
+
def page_set(name, &block)
|
71
|
+
site_models << Stratagem::Crawler::SiteModel.new(name)
|
72
|
+
yield site_model
|
71
73
|
end
|
72
74
|
|
73
75
|
def display
|
@@ -83,23 +85,28 @@ module Stratagem::Crawler::Session
|
|
83
85
|
end
|
84
86
|
end
|
85
87
|
|
86
|
-
def crawl
|
88
|
+
def crawl(verbs=[:any,:get])
|
89
|
+
verbs = [verbs] unless verbs.kind_of?(Array)
|
90
|
+
|
87
91
|
# grab all pages independently
|
88
|
-
@model.routes.invalid.each {|route_container|
|
89
|
-
puts "skipping invalid route #{route_container.route.to_s}"
|
90
|
-
}
|
91
92
|
|
92
93
|
authentication_controller = nil
|
93
|
-
if (
|
94
|
-
route =
|
95
|
-
authentication_controller = route.controller
|
94
|
+
if (site_model.authentication)
|
95
|
+
route = application_model.routes.recognize(authentication.login_page)
|
96
|
+
authentication_controller = route.controller if route
|
96
97
|
end
|
97
98
|
|
98
|
-
|
99
|
+
application_model.routes.each {|route_container|
|
99
100
|
if authentication_controller && route_container.controller && (route_container.controller.klass == authentication_controller.klass)
|
100
101
|
log "Skipping authentication routes #{route_container.route.to_s}"
|
101
102
|
else
|
102
|
-
|
103
|
+
if (application_model.routes.invalid.include?(route_container))
|
104
|
+
log "Skipping invalid route #{route_container.route.to_s}"
|
105
|
+
elsif (verbs.include?(route_container.route.conditions[:method]))
|
106
|
+
visit(route_container)
|
107
|
+
else
|
108
|
+
log "Skipping route with verb #{route_container.route.conditions[:method]} - #{route_container.route.to_s}"
|
109
|
+
end
|
103
110
|
end
|
104
111
|
}
|
105
112
|
|
@@ -114,40 +121,133 @@ module Stratagem::Crawler::Session
|
|
114
121
|
private
|
115
122
|
|
116
123
|
def visit(route_container)
|
117
|
-
puts "
|
124
|
+
puts "Visiting #{route_container.route}"
|
118
125
|
build_urls(route_container).each do |route_info|
|
119
126
|
call_route(route_container, route_info)
|
120
127
|
end
|
121
128
|
end
|
122
129
|
|
123
|
-
def call_route(route, route_info)
|
130
|
+
def call_route(route, route_info, track_invocations=true)
|
131
|
+
return if route_info.nil?
|
132
|
+
|
124
133
|
puts 'CALLING: .'+route_info[:verb].downcase+". - "+route_info[:path]
|
125
134
|
verb = route_info[:verb].downcase
|
126
135
|
verb = 'get' if verb == '' || verb == 'any'
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
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) }
|
134
157
|
else
|
135
|
-
|
158
|
+
puts "ERROR: did not call #{route_info.inspect}"
|
159
|
+
end
|
160
|
+
rescue
|
161
|
+
puts $!.message
|
162
|
+
puts $!.backtrace
|
136
163
|
end
|
137
164
|
end
|
138
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
|
+
|
139
239
|
# Builds a list of string URLs for a given route. This is done
|
140
240
|
# by replacing :xyz_id segments in the route with known values
|
141
241
|
# from the well
|
142
242
|
def build_urls(route_container)
|
143
243
|
urls = []
|
144
244
|
route = route_container.route
|
145
|
-
|
146
|
-
route_infos, params = build_url(route_container,
|
147
|
-
puts "route: #{route_container.route.to_s} permutations:"
|
148
|
-
route_infos.each do |info|
|
149
|
-
|
150
|
-
end
|
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
|
151
251
|
route_infos
|
152
252
|
end
|
153
253
|
|
@@ -182,13 +282,14 @@ module Stratagem::Crawler::Session
|
|
182
282
|
model = parameter_types[s]
|
183
283
|
value = nil
|
184
284
|
if (model)
|
185
|
-
|
285
|
+
if (aquifer.instances_of(model).size == 0)
|
286
|
+
aquifer.print
|
287
|
+
end
|
288
|
+
value = (aquifer.instances_of model).map {|inst|
|
186
289
|
attr_name = s.gsub(/^:/, '').to_sym
|
187
290
|
if inst.methods_include?(attr_name)
|
188
|
-
puts "#{attr_name} is a method on the object"
|
189
291
|
inst.send(attr_name)
|
190
292
|
else
|
191
|
-
puts "#{attr_name} is being mapped to the id on the object"
|
192
293
|
inst.id
|
193
294
|
end
|
194
295
|
}
|
@@ -208,6 +309,7 @@ module Stratagem::Crawler::Session
|
|
208
309
|
reqs = route.requirements.empty? ? "" : route.requirements.inspect
|
209
310
|
url_permutations(segs) do |segments|
|
210
311
|
path = segments.join('').gsub('(.:format)', '').gsub(/\/$/, '')
|
312
|
+
puts "\t\tbuilt url: #{path}"
|
211
313
|
permutation = {:name => name, :verb => verb, :segs => segs, :reqs => reqs, :path => path}
|
212
314
|
routes << permutation
|
213
315
|
end
|
@@ -231,48 +333,34 @@ module Stratagem::Crawler::Session
|
|
231
333
|
end
|
232
334
|
end
|
233
335
|
|
234
|
-
def do_get(route,path)
|
235
|
-
begin
|
236
|
-
get path
|
237
|
-
site_model.add(route, response) {|redirect_url| @redirect_proc.call(redirect_url) }
|
238
|
-
rescue
|
239
|
-
puts $!.message
|
240
|
-
puts path
|
241
|
-
#puts $!.backtrace
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
336
|
def resolve_parameter_types(route_container)
|
246
|
-
puts "
|
337
|
+
puts "\tresolving parameter types"
|
247
338
|
resolved_parameters = {}
|
248
339
|
route_infos, params = build_url(route_container, resolved_parameters)
|
249
340
|
route_info = route_infos.first
|
250
341
|
unknown_params = params.keys
|
251
|
-
|
342
|
+
log "\tunknown params: #{unknown_params.inspect} - #{unknown_params.size}"
|
252
343
|
progress = nil
|
253
344
|
while ((unknown_params.size > 0) && (progress.nil? || (progress > 0)))
|
254
345
|
progress = 0
|
255
346
|
|
256
|
-
|
257
|
-
# puts "---"
|
347
|
+
puts "\tloading model invocations for request"
|
258
348
|
delta = model_invocations_for_request do
|
259
|
-
call_route(route_container, route_info)
|
349
|
+
call_route(route_container, route_info, false)
|
260
350
|
end
|
261
351
|
|
262
|
-
puts "
|
263
|
-
#p delta
|
352
|
+
puts "\tcalled route, found #{delta.size} invocations"
|
264
353
|
|
265
354
|
unknown_params.clone.each do |key|
|
266
355
|
value = params[key]
|
267
356
|
value_s = params[key].map {|v| v.to_s }
|
268
357
|
delta.each do |invocation|
|
269
|
-
puts "#{route_info[:path]} - #{invocation.model_class.name} - #{invocation.method} - #{invocation.args.inspect} - #{value_s}"
|
270
|
-
|
358
|
+
# puts "\t#{route_info[:path]} - #{invocation.model_class.name} - #{invocation.method} - #{invocation.args.inspect} - #{value_s}"
|
271
359
|
# TODO inspect is a hack, refactor
|
272
360
|
if (invocation.args.include?(value.first)) || (invocation.args.inspect.include?('"'+value.first.to_s+'"'))
|
273
361
|
# found match
|
274
362
|
|
275
|
-
puts "\tresolved #{key} to #{invocation.model_class}"
|
363
|
+
puts "\t\tresolved #{key} to #{invocation.model_class}"
|
276
364
|
unknown_params.delete(key)
|
277
365
|
resolved_parameters[key] = invocation.model_class
|
278
366
|
progress += 1
|
@@ -285,6 +373,7 @@ module Stratagem::Crawler::Session
|
|
285
373
|
route_infos, params = build_url(route_container, resolved_parameters)
|
286
374
|
route_info = route_infos.first
|
287
375
|
end
|
376
|
+
|
288
377
|
if (resolved_parameters.size > 0)
|
289
378
|
resolved_parameters
|
290
379
|
else
|
@@ -292,5 +381,4 @@ module Stratagem::Crawler::Session
|
|
292
381
|
end
|
293
382
|
end
|
294
383
|
|
295
|
-
|
296
384
|
end
|
@@ -2,17 +2,26 @@ module Stratagem::Crawler
|
|
2
2
|
class SiteModel
|
3
3
|
include Stratagem::Crawler::HtmlUtils
|
4
4
|
|
5
|
-
attr_reader :pages, :edges
|
5
|
+
attr_reader :pages, :edges, :name
|
6
|
+
attr_accessor :authentication
|
6
7
|
|
7
|
-
def initialize
|
8
|
+
def initialize(name)
|
9
|
+
@name = name
|
8
10
|
@pages = []
|
9
11
|
@edges = []
|
10
12
|
end
|
11
13
|
|
12
14
|
def export
|
13
15
|
{
|
16
|
+
:name => name,
|
14
17
|
:pages => @pages.map {|page| page.export },
|
15
|
-
:edges => @edges.map {|edge| edge.export }
|
18
|
+
:edges => @edges.map {|edge| edge.export },
|
19
|
+
:authentication => authentication.nil? ? nil : {
|
20
|
+
:success => authentication.success,
|
21
|
+
:login_page_external_id => authentication.login_page.object_id,
|
22
|
+
:response_page_external_id => authentication.response_page.object_id,
|
23
|
+
:ssl => authentication.ssl
|
24
|
+
},
|
16
25
|
}
|
17
26
|
end
|
18
27
|
|
@@ -20,8 +29,8 @@ module Stratagem::Crawler
|
|
20
29
|
self.edges << Edge.new(from,to,type)
|
21
30
|
end
|
22
31
|
|
23
|
-
def add(route, response, &block)
|
24
|
-
page = Page.new(self, response, &block)
|
32
|
+
def add(route, response, invocations=[], model_changes={}, &block)
|
33
|
+
page = Page.new(self, response, invocations, model_changes, &block)
|
25
34
|
self.pages << page
|
26
35
|
page
|
27
36
|
end
|
@@ -66,8 +75,10 @@ module Stratagem::Crawler
|
|
66
75
|
attr_accessor :redirected_to
|
67
76
|
attr_accessor :document
|
68
77
|
|
69
|
-
def initialize(site_model, response, &block)
|
78
|
+
def initialize(site_model, response, invocations, model_changes, &block)
|
70
79
|
@site_model = site_model
|
80
|
+
@invocations = invocations
|
81
|
+
@model_changes = model_changes
|
71
82
|
init(response, &block)
|
72
83
|
end
|
73
84
|
|
@@ -82,7 +93,10 @@ module Stratagem::Crawler
|
|
82
93
|
:path => path,
|
83
94
|
:method => method,
|
84
95
|
:redirected_to_page_external_id => redirected_to ? redirected_to.object_id : nil,
|
85
|
-
:route_external_id => route.object_id
|
96
|
+
:route_external_id => route.object_id,
|
97
|
+
:references => @invocations.map {|i| i.to_reference.export },
|
98
|
+
:model_changes => Hash[@model_changes.map {|model,changes| [model.object_id, changes] }].to_json,
|
99
|
+
:parameters => response.request.parameters.to_json
|
86
100
|
}
|
87
101
|
end
|
88
102
|
|
@@ -1,10 +1,12 @@
|
|
1
1
|
module Stratagem::Crawler
|
2
2
|
module TraceUtils
|
3
|
-
def model_invocations_for_request()
|
3
|
+
def model_invocations_for_request(type=nil)
|
4
4
|
prior_invocations = ActiveRecord::Base.stratagem.invocations_audit.clone
|
5
5
|
yield
|
6
6
|
post_invocations = ActiveRecord::Base.stratagem.invocations_audit.clone
|
7
7
|
delta = post_invocations - prior_invocations
|
8
|
+
delta = delta.select {|i| i.type == type } if (type)
|
9
|
+
delta
|
8
10
|
end
|
9
11
|
end
|
10
12
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# it's not elegant, but it compresses stack traces in a json friendly manner
|
2
|
+
class TraceDeflator
|
3
|
+
class << self
|
4
|
+
def create_word_map(compressed)
|
5
|
+
word_counts = {}
|
6
|
+
compressed.each do |column|
|
7
|
+
column.each do |row|
|
8
|
+
word_counts[row[0]] ||= 0
|
9
|
+
word_counts[row[0]] += 1
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
map = word_counts.keys.select {|key| (key.length) > 2 && (word_counts[key] > 1) }.sort {|a,b| word_counts[b] <=> word_counts[a]}
|
14
|
+
end
|
15
|
+
|
16
|
+
def sub_in_word_map(compressed,word_map)
|
17
|
+
compressed.map! do |column|
|
18
|
+
column.map! do |row|
|
19
|
+
sub_index = word_map.index(row[0])
|
20
|
+
sub_index ? [sub_index,row[1]] : row
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def deflate(trace)
|
26
|
+
tokenized = trace.map {|s| s.split('/') }
|
27
|
+
longest = tokenized.inject(0) {|memo,a| a.size > memo ? a.size : memo }
|
28
|
+
tokenized.each {|a|
|
29
|
+
a << "" until a.size >= longest
|
30
|
+
}
|
31
|
+
compressed = tokenized.transpose.map do |column|
|
32
|
+
compressed_column = column.inject([]) {|new_col,col|
|
33
|
+
new_col << [col,0] if (new_col.size == 0)
|
34
|
+
prev = new_col.last
|
35
|
+
prev[0] == col ? prev[1] += 1 : new_col << [col,1]
|
36
|
+
new_col
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
word_map = create_word_map(compressed)
|
41
|
+
sub_in_word_map(compressed, word_map)
|
42
|
+
|
43
|
+
compressed = compressed.map {|column|
|
44
|
+
column.map {|row|
|
45
|
+
"#{row[1]}*#{row[0]}"
|
46
|
+
}.join("\n")
|
47
|
+
}
|
48
|
+
|
49
|
+
{:a => word_map, :b => compressed}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/stratagem/extensions.rb
CHANGED
@@ -13,7 +13,7 @@ module Stratagem::ApplicationExtensions::Models::Adapters::ActiveModel
|
|
13
13
|
def relations(relation_type=nil) # :belongs_to, :has_many
|
14
14
|
@relations ||= {}
|
15
15
|
@relations[relation_type || :all] ||= model.reflect_on_all_associations(relation_type).map {|a|
|
16
|
-
Stratagem::ApplicationExtensions::Models::Metadata::StratagemAssociation.new(a.name.to_sym, a.association_foreign_key.to_sym, a.klass, a.macro)
|
16
|
+
Stratagem::ApplicationExtensions::Models::Metadata::StratagemAssociation.new(a.name.to_sym, a.association_foreign_key.to_sym, a.klass, a.macro, a.options)
|
17
17
|
}
|
18
18
|
end
|
19
19
|
|
@@ -53,12 +53,7 @@ module Stratagem::ApplicationExtensions::Models::Adapters::ActiveModel
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def attribute_names
|
56
|
-
instance.attribute_names.map {|a| a.to_sym} - ignore_attributes
|
57
|
-
end
|
58
|
-
|
59
|
-
# junk attributes
|
60
|
-
def ignore_attributes
|
61
|
-
["!".to_sym, :[]]
|
56
|
+
instance.attribute_names.map {|a| a.to_sym} - model.stratagem.ignore_attributes
|
62
57
|
end
|
63
58
|
|
64
59
|
# Attributes generally used by the persistence mechanism that should not be human writable
|
@@ -83,7 +78,7 @@ module Stratagem::ApplicationExtensions::Models::Adapters::ActiveModel
|
|
83
78
|
column.type
|
84
79
|
end
|
85
80
|
else
|
86
|
-
if (name =~ /password/)
|
81
|
+
if (name.to_s =~ /password/)
|
87
82
|
:string
|
88
83
|
else
|
89
84
|
types = [:string, :boolean, :integer]
|
@@ -39,10 +39,29 @@ module Stratagem::ApplicationExtensions::Models::Adapters::ActiveModel
|
|
39
39
|
# add logging of save methods
|
40
40
|
|
41
41
|
def create_or_update(*args)
|
42
|
-
|
43
|
-
|
42
|
+
alternate_model = nil
|
43
|
+
path,action,line,trace,index = stratagem.controller_trace(/active_record\/base\.rb/)
|
44
|
+
if (index)
|
45
|
+
model_path,model_action,model_line = find_model_path(trace,index)
|
46
|
+
if (model_path)
|
47
|
+
puts "WRITE INVOCATION - USING: #{model_path},#{model_action},#{model_line}"
|
48
|
+
alternate_model = Stratagem::Model::Application.instance.models.find {|m| m.path == model_path }.klass
|
49
|
+
action = model_action
|
50
|
+
puts alternate_model
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
stratagem.write_invocation(self, alternate_model || self.class, action.to_sym, args)
|
44
55
|
old_create_or_update(*args)
|
45
56
|
end
|
57
|
+
|
58
|
+
def find_model_path(trace,controller_index)
|
59
|
+
0.upto(controller_index) do |i|
|
60
|
+
line = trace[i]
|
61
|
+
return stratagem.parse_trace_line(line) if (line =~ /\/app\/models\//)
|
62
|
+
end
|
63
|
+
[]
|
64
|
+
end
|
46
65
|
end
|
47
66
|
end
|
48
67
|
|
File without changes
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Stratagem::ApplicationExtensions::Models::Adapters::Common
|
2
|
+
|
3
|
+
# prefix method names with to avoid collision
|
4
|
+
class Metadata
|
5
|
+
|
6
|
+
attr_reader :model, :instance
|
7
|
+
|
8
|
+
def initialize(model)
|
9
|
+
@model = model
|
10
|
+
@instance = @model.new unless (@model == ActiveRecord::Base)
|
11
|
+
end
|
12
|
+
|
13
|
+
def attribute_names
|
14
|
+
@attribute_names ||= begin
|
15
|
+
names = model.new.methods.select {|m|
|
16
|
+
s = m.to_s
|
17
|
+
if (s.to_s =~ /=$/)
|
18
|
+
name = s.gsub(/=$/, '')
|
19
|
+
name.singularize == name
|
20
|
+
else
|
21
|
+
false
|
22
|
+
end
|
23
|
+
}.map {|m|
|
24
|
+
m.to_s.gsub(/=$/, '').to_sym
|
25
|
+
}
|
26
|
+
names - (model.stratagem.internal_attributes + model.stratagem.ignore_attributes + model.stratagem.relation_names)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# junk attributes
|
31
|
+
def ignore_attributes
|
32
|
+
@ignore_attributes ||= ["!", "[]", "===", "==", "=", "taguri"].map {|a| a.to_sym }
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
data/lib/stratagem/framework_extensions/models/adapters/{common → util}/authentication_metadata.rb
RENAMED
File without changes
|
@@ -1,8 +1,30 @@
|
|
1
1
|
# Defines the stratagem namespace attached to the model
|
2
2
|
module Stratagem::ApplicationExtensions::Models
|
3
|
-
MethodInvocation = Struct.new(:method, :controller_path, :controller_action, :line_number, :model_instance, :model_class, :stack_trace, :args)
|
3
|
+
MethodInvocation = Struct.new(:method, :controller_path, :controller_action, :line_number, :model_instance, :model_class, :stack_trace, :args, :type)
|
4
4
|
ValidatorDefinition = Struct.new(:validation, :field, :args, :model_class)
|
5
5
|
|
6
|
+
# Ability to convert a MethodInvocation object to a Reference object. Sort of a hack.
|
7
|
+
module MethodInvocationToReference
|
8
|
+
def to_reference
|
9
|
+
app = Stratagem::Model::Application.instance
|
10
|
+
model = model_class ? app.models.find {|model| model.klass == model_class } : nil
|
11
|
+
controller = controller_path ? app.controllers.find {|controller| controller.path == controller_path } : nil
|
12
|
+
Stratagem::Model::Component::Reference.new(
|
13
|
+
:from_component => controller,
|
14
|
+
:to_component => model,
|
15
|
+
:function => controller_action,
|
16
|
+
:method => method,
|
17
|
+
:line_number => line_number,
|
18
|
+
:reference_type => type,
|
19
|
+
:stack_trace => stack_trace
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
MethodInvocation.class_eval do
|
24
|
+
include MethodInvocationToReference
|
25
|
+
end
|
26
|
+
|
27
|
+
|
6
28
|
class InstanceAnnotations
|
7
29
|
include Mocking
|
8
30
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
module Stratagem::ApplicationExtensions::Models
|
3
3
|
module Metadata
|
4
|
-
StratagemAssociation = Struct.new(:name, :foreign_key, :klass, :macro)
|
4
|
+
StratagemAssociation = Struct.new(:name, :foreign_key, :klass, :macro, :options)
|
5
5
|
|
6
6
|
INSTANCE_ENUMERATION_METHODS = [:relations, :attribute_names, :ignore_attributes, :internal_attributes, :unaccessible_attributes, :invalid_columns, :exclude_attributes_for_mocking]
|
7
7
|
INSTANCE_ENTITY_METHODS = [:attribute_type, :column_from_error, :authenticates?, :whitelists_attributes?, :blacklists_attributes?]
|
@@ -74,11 +74,11 @@ module Stratagem::ApplicationExtensions::Models
|
|
74
74
|
memory << callback.send(method, *args) if callback.methods_include?(method) || callback.methods_include?(method.to_s)
|
75
75
|
memory
|
76
76
|
rescue
|
77
|
-
puts $!.message
|
77
|
+
puts "error running callbacks: #{$!.message}"
|
78
78
|
puts $!.backtrace
|
79
79
|
end
|
80
80
|
}
|
81
|
-
(results || []).flatten.compact
|
81
|
+
(results || []).flatten.compact.uniq
|
82
82
|
end
|
83
83
|
|
84
84
|
end
|