spbtv_pickle 0.5.1

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 (80) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +10 -0
  5. data/Gemfile +3 -0
  6. data/Gemfile.lock.development +158 -0
  7. data/History.txt +499 -0
  8. data/License.txt +20 -0
  9. data/README.md +566 -0
  10. data/Rakefile +20 -0
  11. data/Rakefile.d/cucumber.rake +27 -0
  12. data/Rakefile.d/release.rake +44 -0
  13. data/Rakefile.d/rspec.rake +3 -0
  14. data/Rakefile.d/yard.rake +5 -0
  15. data/Todo.txt +3 -0
  16. data/autotest/discover.rb +9 -0
  17. data/features/app/app.rb +128 -0
  18. data/features/app/blueprints.rb +6 -0
  19. data/features/app/fabricators.rb +6 -0
  20. data/features/app/factories.rb +25 -0
  21. data/features/app/views/notifier/email.erb +1 -0
  22. data/features/app/views/notifier/user_email.erb +6 -0
  23. data/features/email/email.feature +64 -0
  24. data/features/generator/generators.feature +59 -0
  25. data/features/path/models_page.feature +44 -0
  26. data/features/path/named_route_page.feature +10 -0
  27. data/features/pickle/create_from_active_record.feature +83 -0
  28. data/features/pickle/create_from_fabrication.feature +46 -0
  29. data/features/pickle/create_from_factory_girl.feature +66 -0
  30. data/features/pickle/create_from_machinist.feature +46 -0
  31. data/features/step_definitions/email_steps.rb +1 -0
  32. data/features/step_definitions/extra_email_steps.rb +12 -0
  33. data/features/step_definitions/fork_steps.rb +4 -0
  34. data/features/step_definitions/generator_steps.rb +52 -0
  35. data/features/step_definitions/path_steps.rb +14 -0
  36. data/features/step_definitions/pickle_steps.rb +1 -0
  37. data/features/step_definitions/raise_error_steps.rb +7 -0
  38. data/features/support/email.rb +1 -0
  39. data/features/support/env.rb +14 -0
  40. data/features/support/paths.rb +47 -0
  41. data/features/support/pickle.rb +27 -0
  42. data/features/support/pickle_app.rb +4 -0
  43. data/init.rb +0 -0
  44. data/lib/generators/pickle_generator.rb +44 -0
  45. data/lib/pickle.rb +26 -0
  46. data/lib/pickle/adapter.rb +183 -0
  47. data/lib/pickle/adapters/active_record.rb +67 -0
  48. data/lib/pickle/adapters/data_mapper.rb +42 -0
  49. data/lib/pickle/adapters/mongoid.rb +54 -0
  50. data/lib/pickle/config.rb +49 -0
  51. data/lib/pickle/email.rb +87 -0
  52. data/lib/pickle/email/parser.rb +18 -0
  53. data/lib/pickle/email/world.rb +13 -0
  54. data/lib/pickle/parser.rb +65 -0
  55. data/lib/pickle/parser/matchers.rb +87 -0
  56. data/lib/pickle/path.rb +45 -0
  57. data/lib/pickle/path/world.rb +5 -0
  58. data/lib/pickle/session.rb +244 -0
  59. data/lib/pickle/session/parser.rb +34 -0
  60. data/lib/pickle/version.rb +3 -0
  61. data/lib/pickle/world.rb +14 -0
  62. data/lib/spbtv_pickle.rb +1 -0
  63. data/rails_generators/pickle/pickle_generator.rb +31 -0
  64. data/rails_generators/pickle/templates/email.rb +21 -0
  65. data/rails_generators/pickle/templates/email_steps.rb +65 -0
  66. data/rails_generators/pickle/templates/paths.rb +47 -0
  67. data/rails_generators/pickle/templates/pickle.rb +29 -0
  68. data/rails_generators/pickle/templates/pickle_steps.rb +105 -0
  69. data/spbtv_pickle.gemspec +38 -0
  70. data/spec/pickle/adapter_spec.rb +203 -0
  71. data/spec/pickle/config_spec.rb +112 -0
  72. data/spec/pickle/email/parser_spec.rb +51 -0
  73. data/spec/pickle/email_spec.rb +187 -0
  74. data/spec/pickle/parser/matchers_spec.rb +70 -0
  75. data/spec/pickle/parser_spec.rb +165 -0
  76. data/spec/pickle/path_spec.rb +120 -0
  77. data/spec/pickle/session_spec.rb +448 -0
  78. data/spec/pickle_spec.rb +24 -0
  79. data/spec/spec_helper.rb +78 -0
  80. metadata +370 -0
@@ -0,0 +1,87 @@
1
+ module Pickle
2
+ module Email
3
+ # return the deliveries array, optionally selected by the passed fields
4
+ def emails(fields = nil)
5
+ @emails = ActionMailer::Base.deliveries.select {|m| email_has_fields?(m, fields)}
6
+ end
7
+
8
+ def email(ref, fields = nil)
9
+ (match = ref.match(/^#{capture_index_in_email}$/)) or raise ArgumentError, "argument should match #{match_email}"
10
+ @emails or raise RuntimeError, "Call #emails before calling #email"
11
+ index = parse_index(match[1])
12
+ email_has_fields?(@emails[index], fields) ? @emails[index] : nil
13
+ end
14
+
15
+ def email_has_fields?(email, fields)
16
+ parse_fields(fields).each do |key, val|
17
+ return false unless (Array(email.send(key)) & Array(val)).any?
18
+ end
19
+ true
20
+ end
21
+
22
+ def visit_in_email(email, link_text)
23
+ visit(parse_email_for_link(email, link_text))
24
+ end
25
+
26
+ def click_first_link_in_email(email)
27
+ link = links_in_email(email).first
28
+ visit link
29
+ end
30
+
31
+ protected
32
+ def open_in_browser(path) # :nodoc
33
+ require "launchy"
34
+ Launchy.open(path)
35
+ rescue LoadError
36
+ warn "Sorry, you need to install launchy to open emails: `gem install launchy`"
37
+ end
38
+
39
+ # Saves the emails out to RAILS_ROOT/tmp/ and opens it in the default
40
+ # web browser if on OS X. (depends on webrat)
41
+ def save_and_open_emails
42
+ emails_to_open = @emails || emails
43
+ filename = "pickle-email-#{Time.now.to_i}.html"
44
+ File.open(filename, "w") do |f|
45
+ emails_to_open.each_with_index do |e, i|
46
+ f.write "<h1>Email #{i+1}</h1><pre>#{e}</pre><hr />"
47
+ end
48
+ end
49
+ open_in_browser(filename)
50
+ end
51
+
52
+ def parse_email_for_link(email, text_or_regex)
53
+ url = parse_email_for_explicit_link(email, text_or_regex)
54
+ url ||= parse_email_for_anchor_text_link(email, text_or_regex)
55
+ raise "No link found matching #{text_or_regex.inspect} in #{email}" unless url
56
+ url
57
+ end
58
+
59
+ # e.g. confirm in http://confirm
60
+ def parse_email_for_explicit_link(email, regex)
61
+ regex = /#{Regexp.escape(regex)}/ unless regex.is_a?(Regexp)
62
+ links_in_email(email).detect { |link| link =~ regex }
63
+ end
64
+
65
+ # e.g. Click here in <a href="http://confirm">Click here</a>
66
+ def parse_email_for_anchor_text_link(email, link_text)
67
+ if email.multipart?
68
+ body = email.html_part.body
69
+ else
70
+ body = email.body
71
+ end
72
+ if match_data = body.match(%r{<a[^>]*href=['"]?([^'"]*)['"]?[^>]*?>[^<]*?#{link_text}[^<]*?</a>})
73
+ match_data[1]
74
+ end
75
+ end
76
+
77
+ def links_in_email(email, protos=['http', 'https'])
78
+ if email.multipart?
79
+ body = email.html_part.body
80
+ else
81
+ body = email.body
82
+ end
83
+ URI.extract(body.to_s, protos)
84
+ end
85
+
86
+ end
87
+ end
@@ -0,0 +1,18 @@
1
+ module Pickle
2
+ module Email
3
+ # add ability to parse emails
4
+ module Parser
5
+ def match_email
6
+ "(?:#{match_prefix}?(?:#{match_index} )?email)"
7
+ end
8
+
9
+ def capture_email
10
+ "(#{match_email})"
11
+ end
12
+
13
+ def capture_index_in_email
14
+ "(?:#{match_prefix}?(?:#{capture_index} )?email)"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ require 'pickle'
2
+ require 'pickle/email'
3
+ require 'pickle/email/parser'
4
+
5
+ # add email parser expressions
6
+ Pickle::Parser.send :include, Pickle::Email::Parser
7
+
8
+ World(Pickle::Email)
9
+
10
+ # shortcuts for use in step regexps
11
+ class << self
12
+ delegate :capture_email, :to => 'Pickle.parser'
13
+ end
@@ -0,0 +1,65 @@
1
+ require 'pickle/parser/matchers'
2
+
3
+ module Pickle
4
+ class Parser
5
+ include Matchers
6
+
7
+ attr_reader :config
8
+
9
+ def initialize(options = {})
10
+ @config = options[:config] || raise(ArgumentError, "Parser.new requires a :config")
11
+ end
12
+
13
+ # given a string like 'foo: "bar", bar: "baz"' returns {"foo" => "bar", "bar" => "baz"}
14
+ def parse_fields(fields)
15
+ if fields.blank?
16
+ {}
17
+ elsif fields =~ /^#{match_fields}$/
18
+ fields.scan(/(#{match_field})(?:,|$)/).inject({}) do |m, match|
19
+ m.merge(parse_field(match[0]))
20
+ end
21
+ else
22
+ raise ArgumentError, "The fields string is not in the correct format.\n\n'#{fields}' did not match: #{match_fields}"
23
+ end
24
+ end
25
+
26
+ # given a string like 'foo: expr' returns {key => value}
27
+ def parse_field(field)
28
+ if field =~ /^#{capture_key_and_value_in_field}$/
29
+ { $1 => eval($2) }
30
+ else
31
+ raise ArgumentError, "The field argument is not in the correct format.\n\n'#{field}' did not match: #{match_field}"
32
+ end
33
+ end
34
+
35
+ # returns really underscored name
36
+ def canonical(str)
37
+ str.to_s.underscore.gsub(' ','_').gsub('/','_')
38
+ end
39
+
40
+ # return [factory_name, name or integer index]
41
+ def parse_model(model_name)
42
+ apply_mappings!(model_name)
43
+ if /#{capture_index} #{capture_factory}$/ =~ model_name
44
+ [canonical($2), parse_index($1)]
45
+ elsif /#{capture_factory}#{capture_name_in_label}?$/ =~ model_name
46
+ [canonical($1), canonical($2)]
47
+ end
48
+ end
49
+
50
+ def parse_index(index)
51
+ case index
52
+ when nil, '', 'last' then -1
53
+ when /#{capture_number_in_ordinal}/ then $1.to_i - 1
54
+ when 'first' then 0
55
+ end
56
+ end
57
+
58
+ private
59
+ def apply_mappings!(string)
60
+ config.mappings.each do |mapping|
61
+ string.sub! /^#{mapping.search}$/, mapping.replacement
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,87 @@
1
+ module Pickle
2
+ class Parser
3
+ module Matchers
4
+ def match_ordinal
5
+ '(?:\d+(?:st|nd|rd|th))'
6
+ end
7
+
8
+ def match_index
9
+ "(?:first|last|#{match_ordinal})"
10
+ end
11
+
12
+ def match_prefix
13
+ '(?:(?:a|an|another|the|that) )'
14
+ end
15
+
16
+ def match_quoted
17
+ '(?:\\\\"|[^\\"]|\\.)*'
18
+ end
19
+
20
+ def match_label
21
+ "(?::? \"#{match_quoted}\")"
22
+ end
23
+
24
+ def match_value
25
+ "(?:\"#{match_quoted}\"|nil|true|false|[+-]?[0-9_]+(?:\\.\\d+)?)"
26
+ end
27
+
28
+ def match_field
29
+ "(?:\\w+: #{match_value})"
30
+ end
31
+
32
+ def match_fields
33
+ "(?:#{match_field}, )*#{match_field}"
34
+ end
35
+
36
+ def match_mapping
37
+ "(?:#{config.mappings.map(&:search).join('|')})"
38
+ end
39
+
40
+ def match_factory
41
+ "(?:#{config.factories.keys.map{|n| n.gsub('_','[_ ]')}.join('|')})"
42
+ end
43
+
44
+ def match_plural_factory
45
+ "(?:#{config.factories.keys.map{|n| n.pluralize.gsub('_','[_ ]')}.join('|')})"
46
+ end
47
+
48
+ def match_indexed_model
49
+ "(?:(?:#{match_index} )?#{match_factory})"
50
+ end
51
+
52
+ def match_labeled_model
53
+ "(?:#{match_factory}#{match_label})"
54
+ end
55
+
56
+ def match_model
57
+ "(?:#{match_mapping}|#{match_prefix}?(?:#{match_indexed_model}|#{match_labeled_model}))"
58
+ end
59
+
60
+ def match_predicate
61
+ "(?:#{config.predicates.map{|m| m.to_s.sub(/^has_/,'').sub(/\?$/,'').gsub('_','[_ ]')}.join('|')})"
62
+ end
63
+
64
+ # create capture analogues of match methods
65
+ instance_methods.select{|m| m =~ /^match_/}.each do |method|
66
+ eval <<-end_eval
67
+ def #{method.to_s.sub('match_', 'capture_')} # def capture_field
68
+ "(" + #{method} + ")" # "(" + match_field + ")"
69
+ end # end
70
+ end_eval
71
+ end
72
+
73
+ # special capture methods
74
+ def capture_number_in_ordinal
75
+ '(?:(\d+)(?:st|nd|rd|th))'
76
+ end
77
+
78
+ def capture_name_in_label
79
+ "(?::? \"(#{match_quoted})\")"
80
+ end
81
+
82
+ def capture_key_and_value_in_field
83
+ "(?:(\\w+): #{capture_value})"
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,45 @@
1
+ module Pickle
2
+ module Path
3
+ # given args of pickle model name, and an optional extra action, or segment, will attempt to find
4
+ # a matching named route
5
+ #
6
+ # path_to_pickle 'the user', :action => 'edit' # => /users/3/edit
7
+ # path_to_pickle 'the user', 'the comment' # => /users/3/comments/1
8
+ # path_to_pickle 'the user', :segment => 'comments' # => /users/3/comments
9
+ #
10
+ # If you don;t know if the 'extra' part of the path is an action or a segment, then just
11
+ # pass it as 'extra' and this method will run through the possibilities
12
+ #
13
+ # path_to_pickle 'the user', :extra => 'new comment' # => /users/3/comments/new
14
+ def path_to_pickle(*pickle_names)
15
+ options = pickle_names.extract_options!
16
+ resources = pickle_names.map{|n| model(n) || n.to_sym}
17
+ if options[:extra]
18
+ parts = options[:extra].underscore.gsub(' ','_').split("_")
19
+ find_pickle_path_using_action_segment_combinations(resources, parts)
20
+ else
21
+ pickle_path_for_resources_action_segment(resources, options[:action], options[:segment])
22
+ end or raise "Could not figure out a path for #{pickle_names.inspect} #{options.inspect}"
23
+ end
24
+
25
+ protected
26
+ def find_pickle_path_using_action_segment_combinations(resources, parts)
27
+ path = nil
28
+ (0..parts.length).each do |idx|
29
+ action = parts.slice(0, idx).join('_')
30
+ segment = parts.slice(idx, parts.length).join('_')
31
+ path = pickle_path_for_resources_action_segment(resources, action, segment) and break
32
+ end
33
+ path
34
+ end
35
+
36
+ def pickle_path_for_resources_action_segment(resources, action, segment)
37
+ action.blank? or action = action.downcase.gsub(' ','_')
38
+ segment.blank? or segment = segment.downcase.gsub(' ','_')
39
+ resource_names = resources.map{|s| s.is_a?(Symbol) ? s.to_s : s.class.name.underscore.gsub('/', '_')}.join("_")
40
+ models = resources.reject{|s| s.is_a?(Symbol)}
41
+ parts = [action, resource_names, segment].reject(&:blank?)
42
+ send("#{parts.join('_')}_path", *models) rescue nil
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,5 @@
1
+ require 'pickle'
2
+ require 'pickle/path'
3
+
4
+ # make world pickle/path aware
5
+ World(Pickle::Path)
@@ -0,0 +1,244 @@
1
+ module Pickle
2
+ module Session
3
+ class ModelNotKnownError < RuntimeError
4
+ attr_reader :name
5
+
6
+ def initialize(name, message = nil)
7
+ @name = name
8
+ @message = message.presence || "The model: '#{name}' is not known in this scenario. Use #create_model to create, or #find_model to find, and store a reference in this scenario."
9
+ end
10
+
11
+ def to_s
12
+ @message
13
+ end
14
+ end
15
+
16
+ class ModelNotFoundError < RuntimeError
17
+ end
18
+
19
+ class << self
20
+ def included(world_class)
21
+ proxy_to_pickle_parser(world_class)
22
+ end
23
+
24
+ def extended(world_object)
25
+ proxy_to_pickle_parser(class << world_object; self; end) # metaclass is not 2.1 compatible
26
+ end
27
+
28
+ protected
29
+ def proxy_to_pickle_parser(world_class)
30
+ world_class.class_eval do
31
+ unless methods.include?('method_missing_with_pickle_parser')
32
+ alias_method_chain :method_missing, :pickle_parser
33
+ alias_method_chain :respond_to?, :pickle_parser
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ def create_model(pickle_ref, fields = nil)
40
+ create_or_build_model(:create, 1, pickle_ref, fields)
41
+ end
42
+
43
+ def create_models(count, pickle_ref, fields = nil)
44
+ create_or_build_model(:create, count, pickle_ref, fields)
45
+ end
46
+
47
+ def build_model(pickle_ref, fields = nil)
48
+ create_or_build_model(:build, 1, pickle_ref, fields)
49
+ end
50
+
51
+ def build_models(count, pickle_ref, fields = nil)
52
+ create_or_build_model(:build, count, pickle_ref, fields)
53
+ end
54
+
55
+ # if a column exists in the table which matches the singular factory name, this is used as the pickle ref
56
+ def create_models_from_table(plural_factory, table)
57
+ factory = plural_factory.singularize
58
+ table.hashes.map do |hash|
59
+ pickle_ref = factory + (hash[factory] ? " \"#{hash.delete(factory)}\"" : "")
60
+ create_model(pickle_ref, hash)
61
+ end
62
+ end
63
+
64
+ def find_model(a_model_name, fields = nil)
65
+ factory, name = *parse_model(a_model_name)
66
+
67
+ raise ArgumentError, "Can't find a model with an ordinal (e.g. 1st user)" if name.is_a?(Integer)
68
+
69
+ model_class = pickle_config.factories[factory].klass
70
+ fields = fields.is_a?(Hash) ? parse_hash(fields) : parse_fields(fields)
71
+ conditions = convert_models_to_attributes(model_class, fields)
72
+ record = Pickle::Adapter.find_first_model(model_class, conditions)
73
+
74
+ store_model(factory, name, record) if record
75
+
76
+ record
77
+ end
78
+
79
+ def find_model!(name, fields = nil)
80
+ find_model(name, fields) or raise ModelNotFoundError, "Can't find #{name}#{" with #{fields}" if fields.present?} from the orm in this scenario"
81
+ end
82
+
83
+ def find_models(factory, fields = nil)
84
+ factory = pickle_parser.canonical(factory)
85
+
86
+ models_by_index(factory).clear
87
+
88
+ model_class = pickle_config.factories[factory].klass
89
+ conditions = convert_models_to_attributes(model_class, parse_fields(fields))
90
+ records = Pickle::Adapter.find_all_models(model_class, conditions)
91
+
92
+ records.each {|record| store_model(factory, nil, record)}
93
+ end
94
+
95
+ # if a column exists in the table which matches the singular factory name, this is used as the pickle ref
96
+ def find_models_from_table(plural_factory, table)
97
+ factory = plural_factory.singularize
98
+ table.hashes.map do |hash|
99
+ pickle_ref = factory + (hash[factory] ? " \"#{hash.delete(factory)}\"" : "")
100
+ find_model(pickle_ref, hash)
101
+ end
102
+ end
103
+
104
+ # return the original model stored by create_model or find_model
105
+ def created_model(name)
106
+ factory, name_or_index = *parse_model(name)
107
+
108
+ if name_or_index.blank?
109
+ models_by_index(factory).last
110
+ elsif name_or_index.is_a?(Integer)
111
+ models_by_index(factory)[name_or_index]
112
+ else
113
+ models_by_name(factory)[name_or_index] or raise ModelNotKnownError, name
114
+ end
115
+ end
116
+
117
+ # predicate version which raises no errors
118
+ def created_model?(name)
119
+ (created_model(name) rescue nil) ? true : false
120
+ end
121
+
122
+ # return a newly selected model
123
+ def model(name)
124
+ model = created_model(name)
125
+ return nil unless model
126
+ Pickle::Adapter.get_model(model.class, model.id)
127
+ end
128
+
129
+ # predicate version which raises no errors
130
+ def model?(name)
131
+ (model(name) rescue nil) ? true : false
132
+ end
133
+
134
+ # like model, but raise an error if it can't be found
135
+ def model!(name)
136
+ model(name) or raise ModelNotKnownError, name
137
+ end
138
+
139
+ # like created_model, but raise an error if it can't be found
140
+ def created_model!(name)
141
+ created_model(name) or raise ModelNotKnownError, name
142
+ end
143
+
144
+ # return all original models of specified type
145
+ def created_models(factory)
146
+ models_by_index(factory)
147
+ end
148
+
149
+ # return all models of specified type (freshly selected from the database)
150
+ def models(factory)
151
+ created_models(factory).map do |model|
152
+ Pickle::Adapter.get_model(model.class, model.id)
153
+ end
154
+ end
155
+
156
+ def respond_to_with_pickle_parser?(method, include_private = false)
157
+ respond_to_without_pickle_parser?(method, include_private) || pickle_parser.respond_to?(method, include_private)
158
+ end
159
+
160
+ protected
161
+ def create_or_build_model(method, count, pickle_ref, fields = nil)
162
+ factory, label = *parse_model(pickle_ref)
163
+ raise ArgumentError, "Can't #{method} with an ordinal (e.g. 1st user)" if label.is_a?(Integer)
164
+ fields = fields.is_a?(Hash) ? parse_hash(fields) : parse_fields(fields)
165
+
166
+ count.to_i.times.map do
167
+ record = pickle_config.factories[factory].send(method, fields)
168
+ store_model(factory, label, record)
169
+ return record if count == 1
170
+ record
171
+ end
172
+ end
173
+
174
+ def method_missing_with_pickle_parser(method, *args, &block)
175
+ if pickle_parser.respond_to?(method)
176
+ pickle_parser.send(method, *args, &block)
177
+ else
178
+ method_missing_without_pickle_parser(method, *args, &block)
179
+ end
180
+ end
181
+
182
+ def pickle_parser=(parser)
183
+ parser.session = self
184
+ @pickle_parser = parser
185
+ end
186
+
187
+ def pickle_parser
188
+ @pickle_parser or self.pickle_parser = Pickle.parser
189
+ end
190
+
191
+ def pickle_config
192
+ pickle_parser.config
193
+ end
194
+
195
+ def convert_models_to_attributes(klass, attrs)
196
+ columns = nil
197
+ conditions = {}
198
+
199
+ attrs.each do |key, val|
200
+ if supported = supported_association_model_type?(val) or val.nil?
201
+ columns ||= Pickle::Adapter.column_names(klass)
202
+ end
203
+
204
+ if supported && columns.include?("#{key}_id")
205
+ conditions["#{key}_id"] = val.id
206
+ conditions["#{key}_type"] = val.class.base_class.name if columns.include?("#{key}_type")
207
+ elsif val.nil? && columns.include?("#{key}_id") && !columns.include?("#{key}")
208
+ # NOOP
209
+ else
210
+ conditions[key] = val
211
+ end
212
+ end
213
+
214
+ conditions
215
+ end
216
+
217
+ def supported_association_model_type?(associated_model)
218
+ (defined?(ActiveRecord::Base) && associated_model.is_a?(ActiveRecord::Base)) ||
219
+ (defined?(DataMapper::Model) && associated_model.is_a?(DataMapper::Model)) ||
220
+ (defined?(Mongoid::Document) && associated_model.is_a?(Mongoid::Document))
221
+ end
222
+
223
+ def models_by_name(factory)
224
+ @models_by_name ||= {}
225
+ @models_by_name[pickle_parser.canonical(factory)] ||= {}
226
+ end
227
+
228
+ def models_by_index(factory)
229
+ @models_by_index ||= {}
230
+ @models_by_index[pickle_parser.canonical(factory)] ||= []
231
+ end
232
+
233
+ # if the factory name != the model name, store under both names
234
+ def store_model(factory, name, record)
235
+ store_record(record.class.name, name, record) unless pickle_parser.canonical(factory) == pickle_parser.canonical(record.class.name)
236
+ store_record(factory, name, record)
237
+ end
238
+
239
+ def store_record(factory, name, record)
240
+ models_by_name(factory)[name] = record
241
+ models_by_index(factory) << record
242
+ end
243
+ end
244
+ end