active_mocker 2.0.0.beta1 → 2.0.0.pre1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -1
- data/README.md +11 -18
- data/lib/active_mocker.rb +5 -0
- data/lib/active_mocker/config.rb +7 -8
- data/lib/active_mocker/{mock → deprecated_components}/mock_abilities.rb +19 -7
- data/lib/active_mocker/deprecated_components/rspec.rb +12 -0
- data/lib/active_mocker/display_errors.rb +64 -0
- data/lib/active_mocker/error_object.rb +46 -0
- data/lib/active_mocker/generate.rb +30 -64
- data/lib/active_mocker/mock.rb +1 -2
- data/lib/active_mocker/mock/association.rb +0 -2
- data/lib/active_mocker/mock/base.rb +270 -256
- data/lib/active_mocker/mock/belongs_to.rb +14 -20
- data/lib/active_mocker/mock/collection.rb +0 -6
- data/lib/active_mocker/mock/do_nothing_active_record_methods.rb +39 -41
- data/lib/active_mocker/mock/exceptions.rb +4 -11
- data/lib/active_mocker/mock/has_and_belongs_to_many.rb +0 -2
- data/lib/active_mocker/mock/has_many.rb +4 -5
- data/lib/active_mocker/mock/has_one.rb +5 -11
- data/lib/active_mocker/mock/hash_process.rb +14 -17
- data/lib/active_mocker/mock/mock_relation.rb +10 -0
- data/lib/active_mocker/mock/object_inspect.rb +29 -32
- data/lib/active_mocker/mock/queries.rb +14 -18
- data/lib/active_mocker/mock/records.rb +45 -43
- data/lib/active_mocker/mock/relation.rb +1 -4
- data/lib/active_mocker/mock/single_relation.rb +13 -17
- data/lib/active_mocker/mock/template_methods.rb +1 -4
- data/lib/active_mocker/mock_creator.rb +4 -5
- data/lib/active_mocker/mock_template/_associations.erb +6 -6
- data/lib/active_mocker/mock_template/_class_methods.erb +1 -1
- data/lib/active_mocker/mock_template/_scopes.erb +3 -3
- data/lib/active_mocker/parent_class.rb +1 -1
- data/lib/active_mocker/public_methods.rb +5 -2
- data/lib/active_mocker/rspec.rb +0 -8
- data/lib/active_mocker/rspec_helper.rb +0 -2
- data/lib/active_mocker/task.rake +0 -2
- data/lib/active_mocker/version.rb +1 -1
- metadata +36 -19
- data/lib/active_mocker/logger.rb +0 -15
- data/lib/active_mocker/output_capture.rb +0 -32
data/lib/active_mocker/mock.rb
CHANGED
@@ -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,325 +1,339 @@
|
|
1
1
|
module ActiveMocker
|
2
|
-
|
3
|
-
|
2
|
+
class Base
|
3
|
+
include DoNothingActiveRecordMethods
|
4
|
+
include TemplateMethods
|
5
|
+
extend Queries
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
-
|
11
|
+
class << self
|
50
12
|
|
51
|
-
|
52
|
-
|
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
|
-
|
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
|
-
|
48
|
+
def records
|
49
|
+
@records ||= Records.new
|
50
|
+
end
|
85
51
|
|
86
|
-
|
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
|
-
|
54
|
+
delegate :insert, :exists?, :to_a, :to => :records
|
55
|
+
delegate :first, :last, :to => :all
|
95
56
|
|
96
|
-
|
97
|
-
|
98
|
-
|
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
|
-
|
102
|
-
true
|
103
|
-
end
|
81
|
+
alias_method :destroy, :delete
|
104
82
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
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
|
-
|
111
|
-
ActiveMocker::LoadedMocks.find(klass)
|
112
|
-
end
|
91
|
+
alias_method :destroy_all, :delete_all
|
113
92
|
|
114
|
-
|
115
|
-
|
116
|
-
|
93
|
+
# @api private
|
94
|
+
def from_limit?
|
95
|
+
false
|
96
|
+
end
|
117
97
|
|
118
|
-
|
98
|
+
def abstract_class?
|
99
|
+
true
|
100
|
+
end
|
119
101
|
|
120
|
-
|
102
|
+
def build_type(type)
|
103
|
+
@@built_types ||= {}
|
104
|
+
@@built_types[type] ||= Virtus::Attribute.build(type)
|
105
|
+
end
|
121
106
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
end
|
107
|
+
def classes(klass)
|
108
|
+
ActiveMocker::LoadedMocks.find(klass)
|
109
|
+
end
|
126
110
|
|
127
|
-
|
128
|
-
|
129
|
-
|
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
|
-
|
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
|
-
|
119
|
+
public
|
136
120
|
|
121
|
+
# @deprecated
|
122
|
+
def clear_mock
|
123
|
+
delete_all
|
137
124
|
end
|
138
125
|
|
139
|
-
def
|
140
|
-
|
126
|
+
def _find_associations_by_class(klass_name)
|
127
|
+
associations_by_class[klass_name.to_s]
|
141
128
|
end
|
142
129
|
|
143
|
-
private
|
130
|
+
private
|
144
131
|
|
145
|
-
|
146
|
-
|
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
|
-
|
164
|
-
|
165
|
-
|
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
|
-
|
170
|
-
|
171
|
-
|
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
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
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
|
-
|
152
|
+
private :call_mock_method
|
189
153
|
|
190
|
-
|
191
|
-
|
192
|
-
|
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
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
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
|
-
|
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
|
-
|
211
|
-
self.class.send(:records)
|
212
|
-
end
|
185
|
+
private :setup_instance_variables
|
213
186
|
|
214
|
-
|
187
|
+
def update(attributes={})
|
188
|
+
assign_attributes(attributes)
|
189
|
+
end
|
215
190
|
|
216
|
-
|
217
|
-
|
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
|
-
|
221
|
-
|
222
|
-
delegate :[], :[]=, to: :attributes
|
204
|
+
alias attributes= assign_attributes
|
223
205
|
|
224
|
-
|
225
|
-
|
226
|
-
|
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
|
-
|
230
|
-
|
231
|
-
|
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
|
-
|
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
|
-
|
248
|
-
|
249
|
-
|
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
|
-
|
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
|
-
|
273
|
-
|
274
|
-
|
232
|
+
def delete
|
233
|
+
records.delete(self)
|
234
|
+
end
|
275
235
|
|
276
|
-
|
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
|
-
|
238
|
+
delegate :[], :[]=, to: :attributes
|
286
239
|
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
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
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
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
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
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
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|