active_mocker 2.0.0.beta1 → 2.0.0.pre1

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