stratagem 0.1.7 → 0.1.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|