active_mocker 1.8.4 → 2.0.0.beta1

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/README.md +4 -2
  4. data/lib/active_mocker.rb +9 -25
  5. data/lib/active_mocker/config.rb +26 -46
  6. data/lib/active_mocker/generate.rb +115 -110
  7. data/lib/active_mocker/loaded_mocks.rb +76 -65
  8. data/lib/active_mocker/mock/base.rb +283 -287
  9. data/lib/active_mocker/mock/has_many.rb +2 -0
  10. data/lib/active_mocker/mock_creator.rb +262 -0
  11. data/lib/active_mocker/mock_template.erb +9 -186
  12. data/lib/active_mocker/mock_template/_associations.erb +82 -0
  13. data/lib/active_mocker/mock_template/_attributes.erb +11 -0
  14. data/lib/active_mocker/mock_template/_class_methods.erb +41 -0
  15. data/lib/active_mocker/mock_template/_defined_methods.erb +10 -0
  16. data/lib/active_mocker/mock_template/_modules_constants.erb +10 -0
  17. data/lib/active_mocker/mock_template/_scopes.erb +23 -0
  18. data/lib/active_mocker/null_progress.rb +9 -0
  19. data/lib/active_mocker/output_capture.rb +32 -0
  20. data/lib/active_mocker/parent_class.rb +64 -0
  21. data/lib/active_mocker/progress.rb +13 -0
  22. data/lib/active_mocker/public_methods.rb +15 -23
  23. data/lib/active_mocker/rspec.rb +16 -0
  24. data/lib/active_mocker/rspec_helper.rb +10 -8
  25. data/lib/active_mocker/task.rake +6 -1
  26. data/lib/active_mocker/template_creator.rb +22 -0
  27. data/lib/active_mocker/version.rb +1 -1
  28. metadata +43 -103
  29. data/lib/active_mocker/active_record.rb +0 -74
  30. data/lib/active_mocker/active_record/field.rb +0 -39
  31. data/lib/active_mocker/active_record/relationships.rb +0 -110
  32. data/lib/active_mocker/active_record/schema.rb +0 -81
  33. data/lib/active_mocker/active_record/scope.rb +0 -22
  34. data/lib/active_mocker/active_record/table.rb +0 -26
  35. data/lib/active_mocker/active_record/unknown_class_method.rb +0 -17
  36. data/lib/active_mocker/active_record/unknown_module.rb +0 -30
  37. data/lib/active_mocker/db_to_ruby_type.rb +0 -29
  38. data/lib/active_mocker/file_reader.rb +0 -11
  39. data/lib/active_mocker/model_reader.rb +0 -191
  40. data/lib/active_mocker/model_schema.rb +0 -285
  41. data/lib/active_mocker/model_schema/assemble.rb +0 -220
  42. data/lib/active_mocker/reparameterize.rb +0 -41
  43. data/lib/active_mocker/ruby_parse.rb +0 -68
  44. data/lib/active_mocker/schema_reader.rb +0 -30
  45. data/lib/active_mocker/string_reader.rb +0 -18
@@ -1,329 +1,325 @@
1
1
  module ActiveMocker
2
- module Mock
3
- class Base
2
+ module Mock
3
+ class Base
4
4
 
5
- include DoNothingActiveRecordMethods
6
- include MockAbilities
7
- include TemplateMethods
8
- extend Queries
5
+ include DoNothingActiveRecordMethods
6
+ include MockAbilities
7
+ include TemplateMethods
8
+ extend Queries
9
9
 
10
- def self.inherited(subclass)
11
- return ActiveMocker::LoadedMocks.send(:add, subclass) if subclass.superclass == Base
12
- ActiveMocker::LoadedMocks.send(:add_subclass, subclass)
13
- end
14
-
15
- class << self
16
-
17
- # Creates an object (or multiple objects) and saves it to memory.
18
- #
19
- # The +attributes+ parameter can be either a Hash or an Array of Hashes. These Hashes describe the
20
- # attributes on the objects that are to be created.
21
- #
22
- # ==== Examples
23
- # # Create a single new object
24
- # User.create(first_name: 'Jamie')
25
- #
26
- # # Create an Array of new objects
27
- # User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])
28
- #
29
- # # Create a single object and pass it into a block to set other attributes.
30
- # User.create(first_name: 'Jamie') do |u|
31
- # u.is_admin = false
32
- # end
33
- #
34
- # # Creating an Array of new objects using a block, where the block is executed for each object:
35
- # User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }]) do |u|
36
- # u.is_admin = false
37
- # end
38
- def create(attributes = {}, &block)
39
- if attributes.is_a?(Array)
40
- attributes.collect { |attr| create(attr, &block) }
41
- else
42
- record = new(id: attributes[:id] || attributes['id'])
43
- record.save
44
- record.assign_attributes(attributes, &block)
45
- record._create_caller_locations = caller_locations
46
- record
10
+ def self.inherited(subclass)
11
+ return ActiveMocker::LoadedMocks.send(:add, subclass) if subclass.superclass == Base
47
12
  end
48
- end
49
13
 
50
- alias_method :create!, :create
51
-
52
- def records
53
- @records ||= Records.new
54
- end
14
+ class << self
15
+
16
+ # Creates an object (or multiple objects) and saves it to memory.
17
+ #
18
+ # The +attributes+ parameter can be either a Hash or an Array of Hashes. These Hashes describe the
19
+ # attributes on the objects that are to be created.
20
+ #
21
+ # ==== Examples
22
+ # # Create a single new object
23
+ # User.create(first_name: 'Jamie')
24
+ #
25
+ # # Create an Array of new objects
26
+ # User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])
27
+ #
28
+ # # Create a single object and pass it into a block to set other attributes.
29
+ # User.create(first_name: 'Jamie') do |u|
30
+ # u.is_admin = false
31
+ # end
32
+ #
33
+ # # Creating an Array of new objects using a block, where the block is executed for each object:
34
+ # User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }]) do |u|
35
+ # u.is_admin = false
36
+ # end
37
+ def create(attributes = {}, &block)
38
+ if attributes.is_a?(Array)
39
+ attributes.collect { |attr| create(attr, &block) }
40
+ else
41
+ record = new(id: attributes[:id] || attributes['id'])
42
+ record.save
43
+ record.assign_attributes(attributes, &block)
44
+ record._create_caller_locations = caller_locations
45
+ record
46
+ end
47
+ end
48
+
49
+ alias_method :create!, :create
50
+
51
+ def records
52
+ @records ||= Records.new
53
+ end
54
+
55
+ private :records
56
+
57
+ delegate :insert, :exists?, :to_a, :to => :records
58
+ delegate :first, :last, :to => :all
59
+
60
+ # Delete an object (or multiple objects) that has the given id.
61
+ #
62
+ # This essentially finds the object (or multiple objects) with the given id and then calls delete on it.
63
+ #
64
+ # ==== Parameters
65
+ #
66
+ # * +id+ - Can be either an Integer or an Array of Integers.
67
+ #
68
+ # ==== Examples
69
+ #
70
+ # # Destroy a single object
71
+ # TodoMock.delete(1)
72
+ #
73
+ # # Destroy multiple objects
74
+ # todos = [1,2,3]
75
+ # TodoMock.delete(todos)
76
+ def delete(id)
77
+ if id.is_a?(Array)
78
+ id.map { |one_id| delete(one_id) }
79
+ else
80
+ find(id).delete
81
+ end
82
+ end
83
+
84
+ alias_method :destroy, :delete
85
+
86
+ # Deletes the records matching +conditions+.
87
+ #
88
+ # Post.where(person_id: 5).where(category: ['Something', 'Else']).delete_all
89
+ def delete_all(conditions=nil)
90
+ return records.reset if conditions.nil?
91
+ super
92
+ end
93
+
94
+ alias_method :destroy_all, :delete_all
95
+
96
+ # @api private
97
+ def from_limit?
98
+ false
99
+ end
100
+
101
+ def abstract_class?
102
+ true
103
+ end
104
+
105
+ def build_type(type)
106
+ @@built_types ||= {}
107
+ @@built_types[type] ||= Virtus::Attribute.build(type)
108
+ end
109
+
110
+ def classes(klass)
111
+ ActiveMocker::LoadedMocks.find(klass)
112
+ end
113
+
114
+ def new_relation(collection)
115
+ ScopeRelation.new(collection)
116
+ end
117
+
118
+ private :classes, :build_type, :new_relation
119
+
120
+ public
121
+
122
+ def clear_mock
123
+ clear_mocked_methods
124
+ delete_all
125
+ end
126
+
127
+ def _find_associations_by_class(klass_name)
128
+ associations_by_class[klass_name.to_s]
129
+ end
130
+
131
+ def created_with(version)
132
+ raise UpdateMocksError.new(self.name, version, ActiveMocker::VERSION) if version != ActiveMocker::VERSION
133
+ end
134
+
135
+ private :created_with
55
136
 
56
- private :records
57
-
58
- delegate :insert, :exists?, :to_a, :to => :records
59
- delegate :first, :last, :to => :all
60
-
61
- # Delete an object (or multiple objects) that has the given id.
62
- #
63
- # This essentially finds the object (or multiple objects) with the given id and then calls delete on it.
64
- #
65
- # ==== Parameters
66
- #
67
- # * +id+ - Can be either an Integer or an Array of Integers.
68
- #
69
- # ==== Examples
70
- #
71
- # # Destroy a single object
72
- # TodoMock.delete(1)
73
- #
74
- # # Destroy multiple objects
75
- # todos = [1,2,3]
76
- # TodoMock.delete(todos)
77
- def delete(id)
78
- if id.is_a?(Array)
79
- id.map { |one_id| delete(one_id) }
80
- else
81
- find(id).delete
82
137
  end
83
- end
84
-
85
- alias_method :destroy, :delete
86
-
87
- # Deletes the records matching +conditions+.
88
- #
89
- # Post.where(person_id: 5).where(category: ['Something', 'Else']).delete_all
90
- def delete_all(conditions=nil)
91
- return records.reset if conditions.nil?
92
- super
93
- end
94
-
95
- alias_method :destroy_all, :delete_all
96
-
97
- # @api private
98
- def from_limit?
99
- false
100
- end
101
-
102
- def abstract_class?
103
- true
104
- end
105
-
106
- def build_type(type)
107
- @@built_types ||= {}
108
- @@built_types[type] ||= Virtus::Attribute.build(type)
109
- end
110
-
111
- def classes(klass)
112
- ActiveMocker::LoadedMocks.find(klass)
113
- end
114
-
115
- def new_relation(collection)
116
- ScopeRelation.new(collection)
117
- end
118
138
 
119
- private :classes, :build_type, :new_relation
120
-
121
- public
122
-
123
- def clear_mock
124
- clear_mocked_methods
125
- delete_all
126
- end
127
-
128
- def _find_associations_by_class(klass_name)
129
- associations_by_class[klass_name.to_s]
130
- end
139
+ def classes(klass)
140
+ self.class.send(:classes, klass)
141
+ end
131
142
 
132
- def created_with(version)
133
- raise UpdateMocksError.new(self.name, version, ActiveMocker::VERSION) if version != ActiveMocker::VERSION
134
- end
143
+ private :classes
144
+
145
+ attr_reader :associations, :types, :attributes
146
+ attr_accessor :_create_caller_locations
147
+ # New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
148
+ # attributes but not yet saved (pass a hash with key names matching the associated table column names).
149
+ # In both instances, valid attribute keys are determined by the column names of the associated table --
150
+ # hence you can't have attributes that aren't part of the table columns.
151
+ #
152
+ # ==== Example:
153
+ # # Instantiates a single new object
154
+ # UserMock.new(first_name: 'Jamie')
155
+ def initialize(attributes = {}, &block)
156
+ if self.class.abstract_class?
157
+ raise NotImplementedError, "#{self.class.name} is an abstract class and cannot be instantiated."
158
+ end
159
+ setup_instance_variables
160
+ assign_attributes(attributes, &block)
161
+ end
135
162
 
136
- private :created_with
163
+ def setup_instance_variables
164
+ @types = self.class.send(:types)
165
+ @attributes = self.class.send(:attributes).dup
166
+ @associations = self.class.send(:associations).dup
167
+ end
137
168
 
138
- end
169
+ private :setup_instance_variables
139
170
 
140
- def classes(klass)
141
- self.class.send(:classes, klass)
142
- end
171
+ def update(attributes={})
172
+ assign_attributes(attributes)
173
+ end
143
174
 
144
- private :classes
145
-
146
- attr_reader :associations, :types, :attributes
147
- attr_accessor :_create_caller_locations
148
- # New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
149
- # attributes but not yet saved (pass a hash with key names matching the associated table column names).
150
- # In both instances, valid attribute keys are determined by the column names of the associated table --
151
- # hence you can't have attributes that aren't part of the table columns.
152
- #
153
- # ==== Example:
154
- # # Instantiates a single new object
155
- # UserMock.new(first_name: 'Jamie')
156
- def initialize(attributes = {}, &block)
157
- if self.class.abstract_class?
158
- raise NotImplementedError, "#{self.class.name} is an abstract class and cannot be instantiated."
159
- end
160
- setup_instance_variables
161
- assign_attributes(attributes, &block)
162
- end
175
+ # @api private
176
+ def assign_attributes(new_attributes, &block)
177
+ yield self if block_given?
178
+ unless new_attributes.respond_to?(:stringify_keys)
179
+ raise ArgumentError, "When assigning attributes, you must pass a hash as an argument."
180
+ end
181
+ return nil if new_attributes.blank?
182
+ attributes = new_attributes.stringify_keys
183
+ attributes.each do |k, v|
184
+ _assign_attribute(k, v)
185
+ end
186
+ end
163
187
 
164
- def setup_instance_variables
165
- @types = self.class.send(:types)
166
- @attributes = self.class.send(:attributes).dup
167
- @associations = self.class.send(:associations).dup
168
- end
188
+ alias attributes= assign_attributes
189
+
190
+ # @api private
191
+ def _assign_attribute(k, v)
192
+ public_send("#{k}=", v)
193
+ rescue NoMethodError
194
+ if respond_to?("#{k}=")
195
+ raise
196
+ else
197
+ raise UnknownAttributeError.new(self, k)
198
+ end
199
+ end
169
200
 
170
- private :setup_instance_variables
201
+ def save(*args)
202
+ unless self.class.exists?(self)
203
+ self.class.send(:insert, self)
204
+ end
205
+ true
206
+ end
171
207
 
172
- def update(attributes={})
173
- assign_attributes(attributes)
174
- end
208
+ alias save! save
175
209
 
176
- # @api private
177
- def assign_attributes(new_attributes, &block)
178
- yield self if block_given?
179
- unless new_attributes.respond_to?(:stringify_keys)
180
- raise ArgumentError, "When assigning attributes, you must pass a hash as an argument."
181
- end
182
- return nil if new_attributes.blank?
183
- attributes = new_attributes.stringify_keys
184
- attributes.each do |k, v|
185
- _assign_attribute(k, v)
186
- end
187
- end
210
+ def records
211
+ self.class.send(:records)
212
+ end
188
213
 
189
- alias attributes= assign_attributes
214
+ private :records
190
215
 
191
- # @api private
192
- def _assign_attribute(k, v)
193
- public_send("#{k}=", v)
194
- rescue NoMethodError
195
- if respond_to?("#{k}=")
196
- raise
197
- else
198
- raise UnknownAttributeError.new(self, k)
199
- end
200
- end
216
+ def delete
217
+ records.delete(self)
218
+ end
201
219
 
202
- def save(*args)
203
- unless self.class.exists?(self)
204
- self.class.send(:insert, self)
205
- end
206
- true
207
- end
220
+ alias_method :destroy, :delete
208
221
 
209
- alias save! save
222
+ delegate :[], :[]=, to: :attributes
210
223
 
211
- def records
212
- self.class.send(:records)
213
- end
224
+ # Returns true if this object hasn't been saved yet; otherwise, returns false.
225
+ def new_record?
226
+ records.new_record?(self)
227
+ end
214
228
 
215
- private :records
229
+ # Indicates if the model is persisted. Default is +false+.
230
+ #
231
+ # person = Person.new(id: 1, name: 'bob')
232
+ # person.persisted? # => false
233
+ def persisted?
234
+ records.persisted?(id)
235
+ end
216
236
 
237
+ # Returns +true+ if the given attribute is in the attributes hash, otherwise +false+.
238
+ #
239
+ # person = Person.new
240
+ # person.has_attribute?(:name) # => true
241
+ # person.has_attribute?('age') # => true
242
+ # person.has_attribute?(:nothing) # => false
243
+ def has_attribute?(attr_name)
244
+ @attributes.has_key?(attr_name.to_s)
245
+ end
217
246
 
218
- def delete
219
- records.delete(self)
220
- end
247
+ # Returns +true+ if the specified +attribute+ has been set and is neither +nil+ nor <tt>empty?</tt> (the latter only applies
248
+ # to objects that respond to <tt>empty?</tt>, most notably Strings). Otherwise, +false+.
249
+ # Note that it always returns +true+ with boolean attributes.
250
+ #
251
+ # person = Task.new(title: '', is_done: false)
252
+ # person.attribute_present?(:title) # => false
253
+ # person.attribute_present?(:is_done) # => true
254
+ # person.name = 'Francesco'
255
+ # person.is_done = true
256
+ # person.attribute_present?(:title) # => true
257
+ # person.attribute_present?(:is_done) # => true
258
+ def attribute_present?(attribute)
259
+ value = read_attribute(attribute)
260
+ !value.nil? && !(value.respond_to?(:empty?) && value.empty?)
261
+ end
221
262
 
222
- alias_method :destroy, :delete
263
+ # Returns an array of names for the attributes available on this object.
264
+ #
265
+ # person = Person.new
266
+ # person.attribute_names
267
+ # # => ["id", "created_at", "updated_at", "name", "age"]
268
+ def attribute_names
269
+ self.class.attribute_names
270
+ end
223
271
 
224
- delegate :[], :[]=, to: :attributes
272
+ def inspect
273
+ ObjectInspect.new(self.class.name, attributes).to_s
274
+ end
225
275
 
226
- # Returns true if this object hasn't been saved yet; otherwise, returns false.
227
- def new_record?
228
- records.new_record?(self)
229
- end
276
+ # Will not allow attributes to be changed
277
+ #
278
+ # Will freeze attributes forever. Querying for the record again will not unfreeze it because records exist in memory
279
+ # and are not initialized upon a query. This behaviour differs from ActiveRecord, beware of any side effect this may
280
+ # have when using this method.
281
+ def freeze
282
+ @attributes.freeze; self
283
+ end
230
284
 
231
- # Indicates if the model is persisted. Default is +false+.
232
- #
233
- # person = Person.new(id: 1, name: 'bob')
234
- # person.persisted? # => false
235
- def persisted?
236
- records.persisted?(id)
237
- end
285
+ module PropertiesGetterAndSetter
238
286
 
239
- # Returns +true+ if the given attribute is in the attributes hash, otherwise +false+.
240
- #
241
- # person = Person.new
242
- # person.has_attribute?(:name) # => true
243
- # person.has_attribute?('age') # => true
244
- # person.has_attribute?(:nothing) # => false
245
- def has_attribute?(attr_name)
246
- @attributes.has_key?(attr_name.to_s)
247
- end
287
+ # Returns the value of the attribute identified by <tt>attr_name</tt> after
288
+ # it has been typecast (for example, "2004-12-12" in a date column is cast
289
+ # to a date object, like Date.new(2004, 12, 12))
290
+ def read_attribute(attr)
291
+ @attributes[attr]
292
+ end
248
293
 
249
- # Returns +true+ if the specified +attribute+ has been set and is neither +nil+ nor <tt>empty?</tt> (the latter only applies
250
- # to objects that respond to <tt>empty?</tt>, most notably Strings). Otherwise, +false+.
251
- # Note that it always returns +true+ with boolean attributes.
252
- #
253
- # person = Task.new(title: '', is_done: false)
254
- # person.attribute_present?(:title) # => false
255
- # person.attribute_present?(:is_done) # => true
256
- # person.name = 'Francesco'
257
- # person.is_done = true
258
- # person.attribute_present?(:title) # => true
259
- # person.attribute_present?(:is_done) # => true
260
- def attribute_present?(attribute)
261
- value = read_attribute(attribute)
262
- !value.nil? && !(value.respond_to?(:empty?) && value.empty?)
263
- end
294
+ # Updates the attribute identified by <tt>attr_name</tt> with the
295
+ # specified +value+. Empty strings for fixnum and float columns are
296
+ # turned into +nil+.
297
+ def write_attribute(attr, value)
298
+ @attributes[attr] = types[attr].coerce(value)
299
+ end
264
300
 
265
- # Returns an array of names for the attributes available on this object.
266
- #
267
- # person = Person.new
268
- # person.attribute_names
269
- # # => ["id", "created_at", "updated_at", "name", "age"]
270
- def attribute_names
271
- self.class.attribute_names
272
- end
301
+ # @api private
302
+ def read_association(attr, assign_if_value_nil=nil)
303
+ @associations[attr.to_sym] ||= assign_if_value_nil.try(:call)
304
+ end
273
305
 
274
- def inspect
275
- ObjectInspect.new(self.class.name, attributes).to_s
276
- end
306
+ # @api private
307
+ def write_association(attr, value)
308
+ @associations[attr.to_sym] = value
309
+ end
277
310
 
278
- # Will not allow attributes to be changed
279
- #
280
- # Will freeze attributes forever. Querying for the record again will not unfreeze it because records exist in memory
281
- # and are not initialized upon a query. This behaviour differs from ActiveRecord, beware of any side effect this may
282
- # have when using this method.
283
- def freeze
284
- @attributes.freeze; self
285
- end
311
+ protected :read_attribute, :write_attribute, :read_association, :write_association
286
312
 
287
- module PropertiesGetterAndSetter
313
+ end
288
314
 
289
- # Returns the value of the attribute identified by <tt>attr_name</tt> after
290
- # it has been typecast (for example, "2004-12-12" in a date column is cast
291
- # to a date object, like Date.new(2004, 12, 12))
292
- def read_attribute(attr)
293
- @attributes[attr]
294
- end
315
+ include PropertiesGetterAndSetter
295
316
 
296
- # Updates the attribute identified by <tt>attr_name</tt> with the
297
- # specified +value+. Empty strings for fixnum and float columns are
298
- # turned into +nil+.
299
- def write_attribute(attr, value)
300
- @attributes[attr] = types[attr].coerce(value)
301
- end
317
+ class ScopeRelation < Association
318
+ end
302
319
 
303
- # @api private
304
- def read_association(attr, assign_if_value_nil=nil)
305
- @associations[attr.to_sym] ||= assign_if_value_nil.try(:call)
306
- end
320
+ module Scopes
321
+ end
307
322
 
308
- # @api private
309
- def write_association(attr, value)
310
- @associations[attr.to_sym] = value
311
323
  end
312
-
313
- protected :read_attribute, :write_attribute, :read_association, :write_association
314
-
315
- end
316
-
317
- include PropertiesGetterAndSetter
318
-
319
- class ScopeRelation < ::ActiveMocker::Mock::Association
320
324
  end
321
-
322
- module Scopes
323
-
324
- end
325
-
326
- end
327
-
328
- end
329
325
  end