active_mocker 1.8.4 → 2.0.0.beta1

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