stratagem 0.1.7
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 +99 -0
- data/Rakefile +17 -0
- data/bin/stratagem +10 -0
- data/init.rb +2 -0
- data/lib/bootstrap.rb +31 -0
- data/lib/stratagem/authentication.rb +64 -0
- data/lib/stratagem/auto_mock/aquifer.rb +86 -0
- data/lib/stratagem/auto_mock/factory.rb +213 -0
- data/lib/stratagem/auto_mock/value_generator.rb +174 -0
- data/lib/stratagem/auto_mock.rb +6 -0
- data/lib/stratagem/blocker.rb +16 -0
- data/lib/stratagem/client.rb +32 -0
- data/lib/stratagem/command.rb +13 -0
- data/lib/stratagem/commands/analyze.rb +22 -0
- data/lib/stratagem/commands/base.rb +11 -0
- data/lib/stratagem/commands/devel_crawl.rb +27 -0
- data/lib/stratagem/commands/devel_mock.rb +10 -0
- data/lib/stratagem/commands.rb +7 -0
- data/lib/stratagem/crawler/authentication.rb +109 -0
- data/lib/stratagem/crawler/form.rb +101 -0
- data/lib/stratagem/crawler/html_utils.rb +92 -0
- data/lib/stratagem/crawler/session.rb +296 -0
- data/lib/stratagem/crawler/site_model.rb +138 -0
- data/lib/stratagem/crawler/trace_utils.rb +10 -0
- data/lib/stratagem/crawler.rb +9 -0
- data/lib/stratagem/extensions/class.rb +9 -0
- data/lib/stratagem/extensions/hash.rb +16 -0
- data/lib/stratagem/extensions/module.rb +11 -0
- data/lib/stratagem/extensions/object.rb +15 -0
- data/lib/stratagem/extensions/red_parse.rb +86 -0
- data/lib/stratagem/extensions/string.rb +20 -0
- data/lib/stratagem/extensions.rb +6 -0
- data/lib/stratagem/framework_extensions/controllers/action_controller.rb +10 -0
- data/lib/stratagem/framework_extensions/controllers/action_mailer.rb +12 -0
- data/lib/stratagem/framework_extensions/controllers.rb +5 -0
- data/lib/stratagem/framework_extensions/models/adapters/active_model/detect.rb +7 -0
- data/lib/stratagem/framework_extensions/models/adapters/active_model/extensions.rb +35 -0
- data/lib/stratagem/framework_extensions/models/adapters/active_model/metadata.rb +103 -0
- data/lib/stratagem/framework_extensions/models/adapters/active_model/tracing.rb +50 -0
- data/lib/stratagem/framework_extensions/models/adapters/authlogic/detect.rb +11 -0
- data/lib/stratagem/framework_extensions/models/adapters/authlogic/extensions.rb +10 -0
- data/lib/stratagem/framework_extensions/models/adapters/authlogic/metadata.rb +30 -0
- data/lib/stratagem/framework_extensions/models/adapters/authlogic/tracing.rb +4 -0
- data/lib/stratagem/framework_extensions/models/adapters/common/authentication_metadata.rb +21 -0
- data/lib/stratagem/framework_extensions/models/adapters/restful_authentication/detect.rb +13 -0
- data/lib/stratagem/framework_extensions/models/adapters/restful_authentication/extensions.rb +19 -0
- data/lib/stratagem/framework_extensions/models/adapters/restful_authentication/metadata.rb +30 -0
- data/lib/stratagem/framework_extensions/models/adapters/restful_authentication/tracing.rb +4 -0
- data/lib/stratagem/framework_extensions/models/annotations.rb +79 -0
- data/lib/stratagem/framework_extensions/models/detect.rb +7 -0
- data/lib/stratagem/framework_extensions/models/metadata.rb +85 -0
- data/lib/stratagem/framework_extensions/models/mocking.rb +23 -0
- data/lib/stratagem/framework_extensions/models/tracing.rb +71 -0
- data/lib/stratagem/framework_extensions/models.rb +21 -0
- data/lib/stratagem/framework_extensions/rails.rb +8 -0
- data/lib/stratagem/framework_extensions.rb +6 -0
- data/lib/stratagem/interface/browser.rb +37 -0
- data/lib/stratagem/interface/public/images/backgrounds/content.png +0 -0
- data/lib/stratagem/interface/public/images/backgrounds/shadow.png +0 -0
- data/lib/stratagem/interface/public/javascripts/jquery-1.4.2.min.js +154 -0
- data/lib/stratagem/interface/public/javascripts/stratagem.js +27 -0
- data/lib/stratagem/interface/public/javascripts/stratagem_debug.js +53 -0
- data/lib/stratagem/interface/public/stylesheets/960.css +1 -0
- data/lib/stratagem/interface/public/stylesheets/reset.css +10 -0
- data/lib/stratagem/interface/public/stylesheets/stratagem.css +20 -0
- data/lib/stratagem/interface/public/stylesheets/stratagem_debug.css +20 -0
- data/lib/stratagem/interface/views/debug.haml +43 -0
- data/lib/stratagem/interface/views/index.haml +35 -0
- data/lib/stratagem/labs/auto_mock.rb +7 -0
- data/lib/stratagem/labs/crawler.rb +0 -0
- data/lib/stratagem/logger.rb +46 -0
- data/lib/stratagem/model/application.rb +157 -0
- data/lib/stratagem/model/components/base.rb +55 -0
- data/lib/stratagem/model/components/controller.rb +118 -0
- data/lib/stratagem/model/components/model.rb +170 -0
- data/lib/stratagem/model/components/reference.rb +30 -0
- data/lib/stratagem/model/components/route.rb +53 -0
- data/lib/stratagem/model/components/static_file.rb +18 -0
- data/lib/stratagem/model/components/view.rb +186 -0
- data/lib/stratagem/model/parse_util.rb +61 -0
- data/lib/stratagem/model.rb +12 -0
- data/lib/stratagem/model_builder.rb +146 -0
- data/lib/stratagem/recipes/deploy.rb +30 -0
- data/lib/stratagem/scan/checks/capistrano/secure_deploy.rb +43 -0
- data/lib/stratagem/scan/checks/email_address.rb +15 -0
- data/lib/stratagem/scan/checks/error_pages.rb +25 -0
- data/lib/stratagem/scan/checks/filter_parameter_logging.rb +6 -0
- data/lib/stratagem/scan/checks/mongo_mapper/base.rb +19 -0
- data/lib/stratagem/scan/checks/mongo_mapper/foreign_keys_exposed.rb +32 -0
- data/lib/stratagem/scan/checks/routes.rb +16 -0
- data/lib/stratagem/scan/checks/ssl/secure_login_page.rb +19 -0
- data/lib/stratagem/scan/checks/ssl/secure_login_submit.rb +18 -0
- data/lib/stratagem/scan/result.rb +45 -0
- data/lib/stratagem/scan.rb +19 -0
- data/lib/stratagem/scanner.rb +32 -0
- data/lib/stratagem/site_crawler.rb +47 -0
- data/lib/stratagem/snapshot.rb +33 -0
- data/lib/stratagem.rb +77 -0
- data/lib/tasks/_old_stratagem.rake +99 -0
- data/stratagem.gemspec +56 -0
- metadata +380 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Note that an exception may be raised when a Gem is missing
|
|
2
|
+
# and not configured in environment.rb. Check for this case
|
|
3
|
+
# when loading classes
|
|
4
|
+
# Stratagem::Model
|
|
5
|
+
|
|
6
|
+
require 'set'
|
|
7
|
+
require 'singleton'
|
|
8
|
+
|
|
9
|
+
module Stratagem::Model
|
|
10
|
+
# container for application
|
|
11
|
+
class Application
|
|
12
|
+
include Singleton
|
|
13
|
+
|
|
14
|
+
attr_accessor :crawler
|
|
15
|
+
attr_reader :models, :controllers, :routes, :views, :static_files, :gems, :plugins
|
|
16
|
+
|
|
17
|
+
def initialize
|
|
18
|
+
log "initializing application model"
|
|
19
|
+
@models = ComponentContainer.new self
|
|
20
|
+
@controllers = ComponentContainer.new self
|
|
21
|
+
@routes = RouteContainer.new self
|
|
22
|
+
@views = ComponentContainer.new self
|
|
23
|
+
@static_files = ComponentContainer.new self
|
|
24
|
+
@gems = GemContainer.new self
|
|
25
|
+
@plugins = PluginContainer.new self
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def log(msg)
|
|
29
|
+
Stratagem.logger.debug(msg)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def export
|
|
33
|
+
puts "exporting site model"
|
|
34
|
+
p crawler.export
|
|
35
|
+
puts "done."
|
|
36
|
+
h = {
|
|
37
|
+
:rails_version => rails_version,
|
|
38
|
+
:models => @models.export,
|
|
39
|
+
:controllers => @controllers.export,
|
|
40
|
+
:routes => @routes.export,
|
|
41
|
+
:views => @views.export,
|
|
42
|
+
:gems => @gems.export,
|
|
43
|
+
:plugins => @plugins.export,
|
|
44
|
+
:site_model => crawler.export,
|
|
45
|
+
:references => []
|
|
46
|
+
}
|
|
47
|
+
h
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def rails_version
|
|
51
|
+
Rails.stratagem_rails_version
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
protected
|
|
56
|
+
|
|
57
|
+
class GemContainer
|
|
58
|
+
include Enumerable
|
|
59
|
+
|
|
60
|
+
def initialize(app_model)
|
|
61
|
+
@app_model = app_model
|
|
62
|
+
@gems = Gem.loaded_specs
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def names
|
|
66
|
+
@gems.map {|g| g[0] }
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def export(options=nil)
|
|
70
|
+
@gems.map {|g|
|
|
71
|
+
name, spec = g
|
|
72
|
+
[name, {:version => spec.version.version}]
|
|
73
|
+
}
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def each
|
|
77
|
+
@gems.each {|spec| yield spec }
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
class ComponentContainer
|
|
82
|
+
include Enumerable
|
|
83
|
+
|
|
84
|
+
attr_reader :invalid, :missing, :parse_trees, :components, :errors
|
|
85
|
+
|
|
86
|
+
def initialize(app_model)
|
|
87
|
+
@app_model = app_model
|
|
88
|
+
@components = Set.new()
|
|
89
|
+
@parse_trees = {}
|
|
90
|
+
@invalid = []
|
|
91
|
+
@missing = {}
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def export(options=nil)
|
|
95
|
+
{
|
|
96
|
+
:components => @components.to_a.map {|c| c.export }.compact,
|
|
97
|
+
:invalid => @invalid.map {|c| c.export }.compact
|
|
98
|
+
}
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def find
|
|
102
|
+
@components.find{|component| yield component }
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def size
|
|
106
|
+
@components.size
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def -(other)
|
|
110
|
+
@components-other
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def each
|
|
114
|
+
@components.each {|e| yield e }
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def << (component)
|
|
118
|
+
if (component.kind_of?(Array))
|
|
119
|
+
component.each {|e|
|
|
120
|
+
@components << e
|
|
121
|
+
e.app_model = @app_model if e.methods_include?(:app_model=)
|
|
122
|
+
}
|
|
123
|
+
elsif (component.kind_of?(Exception))
|
|
124
|
+
errors << component
|
|
125
|
+
else
|
|
126
|
+
@components << component
|
|
127
|
+
component.app_model = @app_model if component.methods_include?(:app_model=)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
class RouteContainer < ComponentContainer
|
|
133
|
+
def recognize(page, method=nil)
|
|
134
|
+
path = nil
|
|
135
|
+
if (page.kind_of?(Stratagem::Crawler::Page))
|
|
136
|
+
method = page.method
|
|
137
|
+
path = page.path
|
|
138
|
+
else
|
|
139
|
+
path = page
|
|
140
|
+
end
|
|
141
|
+
#ActionController::Routing::Routes.recognize_path('http://www.example.com/user_sessions/new', {:method => :get})
|
|
142
|
+
route = ActionController::Routing::Routes.routes.find {|r| r.recognize(path, {:method => method}) }
|
|
143
|
+
self.find {|r| r.route == route }
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
class PluginContainer < ComponentContainer
|
|
148
|
+
def names
|
|
149
|
+
components.map {|plugin| plugin.name }
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def export(options=nil)
|
|
153
|
+
names
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module Stratagem::Model::Component
|
|
2
|
+
class Base
|
|
3
|
+
include Stratagem::Model::ParseUtil
|
|
4
|
+
|
|
5
|
+
attr_reader :path, :source, :parse_tree, :klass
|
|
6
|
+
attr_accessor :app_model
|
|
7
|
+
|
|
8
|
+
def initialize(path, parse_tree, klass)
|
|
9
|
+
@path = path
|
|
10
|
+
@parse_tree = parse_tree
|
|
11
|
+
@klass = klass
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def logger
|
|
15
|
+
Stratagem.logger
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.logger
|
|
19
|
+
Stratagem.logger
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def name
|
|
23
|
+
classname = @klass ? @klass.name : self.class.name.gsub(/.*[^A-Z0-9a-z]/, '')
|
|
24
|
+
"#{path}$#{classname}"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# loads all classes contained within a given filename
|
|
28
|
+
def self.load_all(path)
|
|
29
|
+
if (path =~ /\.rb$/)
|
|
30
|
+
source = File.read(path)
|
|
31
|
+
begin
|
|
32
|
+
parse_tree = RedParse.new(source).parse
|
|
33
|
+
Stratagem::Model::ParseUtil.find_classes(parse_tree).map {|klass|
|
|
34
|
+
self.new(path, parse_tree, klass)
|
|
35
|
+
}
|
|
36
|
+
rescue
|
|
37
|
+
puts $!.message
|
|
38
|
+
logger.fatal "Unable to load parse tree for #{path}"
|
|
39
|
+
[]
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def ==(other)
|
|
45
|
+
if (other.kind_of?(String))
|
|
46
|
+
self.path == other
|
|
47
|
+
elsif (other.kind_of?(self.class))
|
|
48
|
+
self.path == other.path
|
|
49
|
+
else
|
|
50
|
+
raise "unknown comparison to #{other.class.name}"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
require 'set'
|
|
2
|
+
|
|
3
|
+
module Stratagem::Model::Component
|
|
4
|
+
class Action
|
|
5
|
+
def initialize(controller, name, method)
|
|
6
|
+
@name = name
|
|
7
|
+
@method = method # :put, :get, :post, :delete
|
|
8
|
+
@models_rendered = {} # model => [MethodInvocation]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def models_read
|
|
12
|
+
models(ActiveRecord::Base.stratagem.read_invocations)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def models_modified
|
|
16
|
+
models(ActiveRecord::Base.stratagem.write_invocations)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def models(invocations)
|
|
20
|
+
invocations.values.select {|invocation|
|
|
21
|
+
(invocation.controller_path == controller.path) &&
|
|
22
|
+
(invocation.controller_action == self.name)
|
|
23
|
+
}.map {|invocation|
|
|
24
|
+
invocation.model_class
|
|
25
|
+
}.uniq
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class Controller < Base
|
|
31
|
+
attr_reader :clazz, :actions
|
|
32
|
+
attr_accessor :invalid_routes # named routes linked to the controller that are invalid
|
|
33
|
+
|
|
34
|
+
def initialize(*args)
|
|
35
|
+
super(*args)
|
|
36
|
+
@invalid_routes = {}
|
|
37
|
+
@actions = []
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def add_routable_action(name, method)
|
|
41
|
+
@actions << Action.new(self, name, method)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def export
|
|
45
|
+
{
|
|
46
|
+
:external_id => self.object_id,
|
|
47
|
+
:type => :controller,
|
|
48
|
+
:path => @path.gsub(RAILS_ROOT+'/', ''),
|
|
49
|
+
:class_name => @klass.name,
|
|
50
|
+
:invalid_routes => @invalid_routes
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# returns a list of references that create or update the specified model.
|
|
55
|
+
# see deletes? for destruction of model
|
|
56
|
+
def modifies(model)
|
|
57
|
+
# @modifies ||= {}
|
|
58
|
+
# @modifies[model] ||= begin
|
|
59
|
+
# outline = {} # method keys, value is hash of variables and values
|
|
60
|
+
# current_method = nil
|
|
61
|
+
# references = Set.new
|
|
62
|
+
#
|
|
63
|
+
# # return [] unless ((model.klass == WineFollow) && (self.klass == FollowsController))
|
|
64
|
+
#
|
|
65
|
+
# self.parse_tree.walk {|parent,i,subi,node|
|
|
66
|
+
# case node
|
|
67
|
+
# when RedParse::MethodNode #... do something with method calls
|
|
68
|
+
# current_method = node.name
|
|
69
|
+
# outline[current_method] = {}
|
|
70
|
+
# # puts "CURRENTMETHOD: #{current_method}"
|
|
71
|
+
# when RedParse::AssignNode
|
|
72
|
+
# if (node.left.kind_of?(RedParse::VarNode))
|
|
73
|
+
# begin
|
|
74
|
+
# # puts "assigning:#{node.left.name} -> #{node.right.dereference}"
|
|
75
|
+
# deref = node.right.dereference
|
|
76
|
+
# ((outline[current_method][node.left.name] ||= []) << deref) if current_method && deref
|
|
77
|
+
# rescue
|
|
78
|
+
# puts $!.message
|
|
79
|
+
# puts $!.backtrace
|
|
80
|
+
# logger.error("Cannot dereference node #{node.right.to_s}")
|
|
81
|
+
# end
|
|
82
|
+
# end
|
|
83
|
+
# when RedParse::CallNode
|
|
84
|
+
# ['update','create','new'].each {|m|
|
|
85
|
+
# # then this is a crud operation (excluding destroy)
|
|
86
|
+
# if (node.name.include?(m))
|
|
87
|
+
# if (node.talking_about? model)
|
|
88
|
+
# references << create_reference(node, current_method, model)
|
|
89
|
+
# break
|
|
90
|
+
# elsif (node.receiver && node.receiver.methods_include?(:name) && outline[current_method])
|
|
91
|
+
# if ((outline[current_method][node.receiver.name] || []).include?(model.klass))
|
|
92
|
+
# references << create_reference(node, current_method, model)
|
|
93
|
+
# break
|
|
94
|
+
# end
|
|
95
|
+
# end
|
|
96
|
+
# end
|
|
97
|
+
# }
|
|
98
|
+
# end
|
|
99
|
+
# node
|
|
100
|
+
# }
|
|
101
|
+
# references.to_a
|
|
102
|
+
# end
|
|
103
|
+
[]
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
private
|
|
107
|
+
|
|
108
|
+
def create_reference(node, method, model)
|
|
109
|
+
Reference.new(
|
|
110
|
+
:from_class => self.klass,
|
|
111
|
+
:to_class => model.klass,
|
|
112
|
+
:method => method,
|
|
113
|
+
:line_number => node.linerange.first,
|
|
114
|
+
:reference_type => :write
|
|
115
|
+
)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
module Stratagem::Model::Component
|
|
2
|
+
class Model < Base
|
|
3
|
+
attr_reader :model_attributes # database attributes that the model contains
|
|
4
|
+
attr_reader :model_assignable_attributes # fields / methods that can be manipulated in Model.new(..)
|
|
5
|
+
attr_reader :model_internal_attributes
|
|
6
|
+
attr_reader :model_accessible_attributes
|
|
7
|
+
attr_accessor :model_referenced_by # other classes / libraries that reference this model
|
|
8
|
+
|
|
9
|
+
ModificationMethods = ['update','create','new']
|
|
10
|
+
|
|
11
|
+
def initialize(*args)
|
|
12
|
+
super(*args)
|
|
13
|
+
load_attributes
|
|
14
|
+
@model_assignable_attributes = find_assignable_attributes
|
|
15
|
+
@model_instance_methods = self.klass.instance_methods
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def stratagem?
|
|
19
|
+
klass.methods_include?(:stratagem)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# iterate model's associations to see if there's an association with the specific
|
|
23
|
+
# name and class. This is used as an aproximation to determine whether or
|
|
24
|
+
# not a node in the parse tree could be talking about a specific relationship
|
|
25
|
+
def association_match?(association_name, desired_model)
|
|
26
|
+
@association_matches ||= {}
|
|
27
|
+
@association_matches[association_name+"_"+desired_model.klass.name] ||= begin
|
|
28
|
+
klass.stratagem.relations.select {|relation|
|
|
29
|
+
(relation.name.to_sym == association_name.to_sym) && (relation.klass == desired_model.klass)
|
|
30
|
+
}.map {|relation|
|
|
31
|
+
relation.klass.name
|
|
32
|
+
}.first
|
|
33
|
+
rescue
|
|
34
|
+
Rails.logger.error("unable to lookup associations on #{self.klass.name} not active record model?")
|
|
35
|
+
Rails.logger.error($!)
|
|
36
|
+
false
|
|
37
|
+
end
|
|
38
|
+
@association_matches[association_name+"_"+desired_model.klass.name]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def load_attributes
|
|
42
|
+
@model_attributes = {}
|
|
43
|
+
if (stratagem?)
|
|
44
|
+
object = klass.new # used to look up metadata
|
|
45
|
+
object.stratagem.attribute_names.each {|attribute|
|
|
46
|
+
@model_attributes[attribute.to_sym] = object.stratagem.attribute_type(attribute.to_sym)
|
|
47
|
+
}
|
|
48
|
+
@model_foreign_keys = object.stratagem.foreign_keys
|
|
49
|
+
@model_internal_attributes = object.stratagem.internal_attributes
|
|
50
|
+
@model_accessible_attributes = object.stratagem.attribute_names - object.stratagem.unaccessible_attributes
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# TODO - refactor into model persistence strategy
|
|
55
|
+
def find_assignable_attributes
|
|
56
|
+
assignable_attributes = []
|
|
57
|
+
|
|
58
|
+
# Using instance methods allows us to check for functions that would be mass assignable
|
|
59
|
+
# in addition to Active Record attributes
|
|
60
|
+
begin
|
|
61
|
+
if (stratagem?)
|
|
62
|
+
object = klass.new # used to look up metadata
|
|
63
|
+
if (object)
|
|
64
|
+
methods = nil
|
|
65
|
+
if (klass.stratagem.unaccessible_attributes)
|
|
66
|
+
assignable_attributes = (klass.stratagem.attribute_names - klass.stratagem.unaccessible_attributes).to_a
|
|
67
|
+
else
|
|
68
|
+
methods = klass.instance_methods + object.stratagem.attribute_names
|
|
69
|
+
methods.each {|method|
|
|
70
|
+
param_name = method.to_s.gsub('=','').to_sym
|
|
71
|
+
val = rand(100)
|
|
72
|
+
params = { param_name => val }
|
|
73
|
+
begin
|
|
74
|
+
instance = klass.new(params)
|
|
75
|
+
assignable_attributes << param_name.to_sym
|
|
76
|
+
rescue ActiveRecord::UnknownAttributeError
|
|
77
|
+
# the attribute is not mass assignable
|
|
78
|
+
rescue
|
|
79
|
+
# the function was called but an error was raised
|
|
80
|
+
assignable_attributes << param_name.to_sym
|
|
81
|
+
end
|
|
82
|
+
}
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
assignable_attributes.uniq
|
|
86
|
+
end
|
|
87
|
+
rescue
|
|
88
|
+
puts "Unable to analyze model #{klass.name}"
|
|
89
|
+
puts $!.message
|
|
90
|
+
puts $!.backtrace
|
|
91
|
+
# raise $!
|
|
92
|
+
[]
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# References to the find and find_x methods on the model
|
|
97
|
+
def references_to_finders()
|
|
98
|
+
references = []
|
|
99
|
+
method = nil
|
|
100
|
+
app_model.controllers.each {|controller|
|
|
101
|
+
controller.parse_tree.walk {|parent,i,subi,node|
|
|
102
|
+
case node
|
|
103
|
+
when RedParse::MethodNode
|
|
104
|
+
method = node
|
|
105
|
+
when RedParse::CallNode
|
|
106
|
+
if (!(parent.kind_of?(RedParse::AssignNode)) && (node.receiver) && (node.receiver.to_s == klass.name))
|
|
107
|
+
references << ControllerModelReference.new(controller, method.name, node.name, node)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
case parent
|
|
112
|
+
when RedParse::AssignNode
|
|
113
|
+
# p parent
|
|
114
|
+
begin
|
|
115
|
+
if (node.kind_of?(RedParse::CallNode) && (node.receiver) && (node.receiver.name == klass.name))
|
|
116
|
+
references << ControllerModelReference.new(controller, method.name, node.name, node)
|
|
117
|
+
end
|
|
118
|
+
rescue
|
|
119
|
+
puts $!.message
|
|
120
|
+
puts $!.backtrace
|
|
121
|
+
# p parent
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
true
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
references
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def export
|
|
131
|
+
adapters = stratagem? ? klass.stratagem.callbacks.map {|c| c.class.name } : []
|
|
132
|
+
{
|
|
133
|
+
:type => :model,
|
|
134
|
+
:path => @path.gsub(RAILS_ROOT+'/', ''),
|
|
135
|
+
:class_name => @klass.name,
|
|
136
|
+
:superclass => @klass.superclass.name,
|
|
137
|
+
:included_modules => @klass.included_modules.map {|m| m.name},
|
|
138
|
+
:attributes => @model_attributes,
|
|
139
|
+
:foreign_keys => @model_foreign_keys,
|
|
140
|
+
:assignable_attributes => @model_assignable_attributes,
|
|
141
|
+
:internal_attributes => @model_internal_attributes,
|
|
142
|
+
:accessible_attributes => @model_accessible_attributes,
|
|
143
|
+
:whitelists_attributes => stratagem? ? @klass.stratagem.whitelists_attributes? : nil,
|
|
144
|
+
:blacklists_attributes => stratagem? ? @klass.stratagem.blacklists_attributes? : nil,
|
|
145
|
+
:instance_methods => @model_instance_methods,
|
|
146
|
+
:referenced_by => @model_referenced_by.map {|r| r.export },
|
|
147
|
+
:relations => relations.map {|r| r.export },
|
|
148
|
+
:adapters => adapters
|
|
149
|
+
}
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
private
|
|
153
|
+
|
|
154
|
+
def relations
|
|
155
|
+
if (stratagem?)
|
|
156
|
+
@relations ||= klass.stratagem.relations.map {|relation|
|
|
157
|
+
Reference.new(:reference_type => relation.macro, :from_class => self.klass, :to_class => relation.klass)
|
|
158
|
+
}
|
|
159
|
+
else
|
|
160
|
+
[]
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def assignable(object, assignable_attributes, attribute)
|
|
165
|
+
column = object.column_for_attribute(attribute)
|
|
166
|
+
assignable_attributes[attribute] = column ? column.type : nil
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
end
|
|
170
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Stratagem::Model::Component
|
|
2
|
+
class Reference
|
|
3
|
+
attr_accessor :reference_type # :read, :write
|
|
4
|
+
attr_accessor :from_class, :to_class
|
|
5
|
+
attr_accessor :line_number
|
|
6
|
+
attr_accessor :method
|
|
7
|
+
|
|
8
|
+
Vars = [:reference_type, :from_class, :to_class, :line_number, :method]
|
|
9
|
+
|
|
10
|
+
def initialize(args={})
|
|
11
|
+
args.each {|key,val| self.send("#{key}=", val) }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def ==(other)
|
|
15
|
+
Vars.each do |attribute|
|
|
16
|
+
self.send(attribute) == other.send(attribute)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def export
|
|
21
|
+
h = {}
|
|
22
|
+
Vars.each do |key|
|
|
23
|
+
h[key.to_s] = self.send(key).to_s
|
|
24
|
+
end
|
|
25
|
+
h[:from_class.to_s] = from_class.name
|
|
26
|
+
h[:to_class.to_s] = to_class.name
|
|
27
|
+
h
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module Stratagem::Model::Component
|
|
2
|
+
class Route < Base
|
|
3
|
+
attr_reader :route
|
|
4
|
+
|
|
5
|
+
def initialize(route)
|
|
6
|
+
@route = route
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def controller
|
|
10
|
+
if (route.requirements[:controller])
|
|
11
|
+
begin
|
|
12
|
+
controller_class = "#{route.requirements[:controller].to_s.camelize}Controller".constantize
|
|
13
|
+
Stratagem::Model::Application.instance.controllers.find {|c| c.klass == controller_class }
|
|
14
|
+
rescue
|
|
15
|
+
puts "unable to determine controller #{route.requirements[:controller]}"
|
|
16
|
+
puts $!.message
|
|
17
|
+
nil
|
|
18
|
+
end
|
|
19
|
+
else
|
|
20
|
+
nil
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def action
|
|
25
|
+
route.requirements[:action] ? route.requirements[:action].to_sym : nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def ==(other)
|
|
29
|
+
if (other.kind_of?(ActionController::Routing::Route))
|
|
30
|
+
self.route == other
|
|
31
|
+
elsif (other.kind_of?(Stratagem::Model::Component::Route))
|
|
32
|
+
self.route.requirements == other.route.requirements && self.route.segments == other.route.segments
|
|
33
|
+
else
|
|
34
|
+
raise "unknown comparison to #{other.class.name}"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def export
|
|
39
|
+
p @route.requirements
|
|
40
|
+
p action
|
|
41
|
+
puts "--"
|
|
42
|
+
{
|
|
43
|
+
:external_id => self.object_id,
|
|
44
|
+
:type => :route,
|
|
45
|
+
:path => nil,
|
|
46
|
+
:requirements => @route.requirements,
|
|
47
|
+
:segments => @route.segments.map {|s| s.to_s },
|
|
48
|
+
:controller_external_id => controller ? controller.object_id : nil,
|
|
49
|
+
:action => action,
|
|
50
|
+
}
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Stratagem::Model::Component
|
|
2
|
+
class StaticFile < Base
|
|
3
|
+
|
|
4
|
+
def initialize(public_path)
|
|
5
|
+
@path = public_path
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def read
|
|
9
|
+
File.read(full_path)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def full_path
|
|
13
|
+
File.join(RAILS_ROOT, 'public', path)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
|