dm-core 0.9.2 → 0.9.3
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.
- data/.autotest +26 -0
- data/{CHANGELOG → History.txt} +78 -77
- data/Manifest.txt +123 -0
- data/{README → README.txt} +0 -0
- data/Rakefile +29 -0
- data/SPECS +63 -0
- data/TODO +1 -0
- data/lib/dm-core.rb +6 -1
- data/lib/dm-core/adapters/data_objects_adapter.rb +29 -32
- data/lib/dm-core/adapters/mysql_adapter.rb +1 -1
- data/lib/dm-core/adapters/postgres_adapter.rb +1 -1
- data/lib/dm-core/adapters/sqlite3_adapter.rb +2 -2
- data/lib/dm-core/associations.rb +26 -0
- data/lib/dm-core/associations/many_to_many.rb +34 -25
- data/lib/dm-core/associations/many_to_one.rb +4 -4
- data/lib/dm-core/associations/one_to_many.rb +48 -13
- data/lib/dm-core/associations/one_to_one.rb +4 -4
- data/lib/dm-core/associations/relationship.rb +144 -42
- data/lib/dm-core/associations/relationship_chain.rb +31 -24
- data/lib/dm-core/auto_migrations.rb +0 -4
- data/lib/dm-core/collection.rb +40 -7
- data/lib/dm-core/dependency_queue.rb +31 -0
- data/lib/dm-core/hook.rb +2 -2
- data/lib/dm-core/is.rb +2 -2
- data/lib/dm-core/logger.rb +10 -10
- data/lib/dm-core/model.rb +94 -41
- data/lib/dm-core/property.rb +72 -41
- data/lib/dm-core/property_set.rb +8 -14
- data/lib/dm-core/query.rb +34 -9
- data/lib/dm-core/repository.rb +0 -0
- data/lib/dm-core/resource.rb +13 -13
- data/lib/dm-core/scope.rb +25 -2
- data/lib/dm-core/type.rb +3 -3
- data/lib/dm-core/types/discriminator.rb +10 -8
- data/lib/dm-core/types/object.rb +4 -0
- data/lib/dm-core/types/paranoid_boolean.rb +15 -4
- data/lib/dm-core/types/paranoid_datetime.rb +15 -4
- data/lib/dm-core/version.rb +3 -0
- data/script/all +5 -0
- data/script/performance.rb +191 -0
- data/script/profile.rb +86 -0
- data/spec/integration/association_spec.rb +288 -204
- data/spec/integration/association_through_spec.rb +9 -3
- data/spec/integration/associations/many_to_many_spec.rb +97 -31
- data/spec/integration/associations/many_to_one_spec.rb +41 -6
- data/spec/integration/associations/one_to_many_spec.rb +18 -2
- data/spec/integration/auto_migrations_spec.rb +0 -0
- data/spec/integration/collection_spec.rb +89 -42
- data/spec/integration/dependency_queue_spec.rb +58 -0
- data/spec/integration/model_spec.rb +67 -8
- data/spec/integration/postgres_adapter_spec.rb +19 -20
- data/spec/integration/property_spec.rb +17 -8
- data/spec/integration/query_spec.rb +273 -191
- data/spec/integration/resource_spec.rb +108 -10
- data/spec/integration/strategic_eager_loading_spec.rb +138 -0
- data/spec/integration/transaction_spec.rb +3 -3
- data/spec/integration/type_spec.rb +121 -0
- data/spec/lib/logging_helper.rb +18 -0
- data/spec/lib/model_loader.rb +91 -0
- data/spec/lib/publicize_methods.rb +28 -0
- data/spec/models/vehicles.rb +34 -0
- data/spec/models/zoo.rb +48 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +25 -62
- data/spec/unit/adapters/data_objects_adapter_spec.rb +1 -0
- data/spec/unit/associations/many_to_many_spec.rb +3 -0
- data/spec/unit/associations/many_to_one_spec.rb +9 -1
- data/spec/unit/associations/one_to_many_spec.rb +12 -4
- data/spec/unit/associations/relationship_spec.rb +19 -15
- data/spec/unit/associations_spec.rb +37 -0
- data/spec/unit/collection_spec.rb +8 -0
- data/spec/unit/data_mapper_spec.rb +14 -0
- data/spec/unit/model_spec.rb +2 -2
- data/spec/unit/property_set_spec.rb +0 -13
- data/spec/unit/property_spec.rb +92 -21
- data/spec/unit/query_spec.rb +49 -4
- data/spec/unit/resource_spec.rb +122 -60
- data/spec/unit/scope_spec.rb +11 -0
- data/tasks/ci.rb +68 -0
- data/tasks/dm.rb +63 -0
- data/tasks/doc.rb +20 -0
- data/tasks/hoe.rb +38 -0
- data/tasks/install.rb +20 -0
- metadata +63 -22
data/lib/dm-core/property.rb
CHANGED
@@ -61,9 +61,9 @@ module DataMapper
|
|
61
61
|
#
|
62
62
|
# class Post
|
63
63
|
# include DataMapper::Resource
|
64
|
-
# property :title, String,
|
64
|
+
# property :title, String, :accessor => :private
|
65
65
|
# # Both reader and writer are private
|
66
|
-
# property :body, Text,
|
66
|
+
# property :body, Text, :accessor => :protected
|
67
67
|
# # Both reader and writer are protected
|
68
68
|
# end
|
69
69
|
#
|
@@ -243,7 +243,7 @@ module DataMapper
|
|
243
243
|
# NOTE: PLEASE update PROPERTY_OPTIONS in DataMapper::Type when updating
|
244
244
|
# them here
|
245
245
|
PROPERTY_OPTIONS = [
|
246
|
-
:
|
246
|
+
:accessor, :reader, :writer,
|
247
247
|
:lazy, :default, :nullable, :key, :serial, :field, :size, :length,
|
248
248
|
:format, :index, :unique_index, :check, :ordinal, :auto_validation,
|
249
249
|
:validates, :unique, :track, :precision, :scale
|
@@ -264,7 +264,8 @@ module DataMapper
|
|
264
264
|
Time,
|
265
265
|
Object,
|
266
266
|
Class,
|
267
|
-
DataMapper::Types::Discriminator
|
267
|
+
DataMapper::Types::Discriminator,
|
268
|
+
DataMapper::Types::Serial
|
268
269
|
]
|
269
270
|
|
270
271
|
IMMUTABLE_TYPES = [ TrueClass, Float, Integer, BigDecimal]
|
@@ -273,7 +274,8 @@ module DataMapper
|
|
273
274
|
|
274
275
|
DEFAULT_LENGTH = 50
|
275
276
|
DEFAULT_PRECISION = 10
|
276
|
-
|
277
|
+
DEFAULT_SCALE_BIGDECIMAL = 0
|
278
|
+
DEFAULT_SCALE_FLOAT = nil
|
277
279
|
|
278
280
|
attr_reader :primitive, :model, :name, :instance_variable_name,
|
279
281
|
:type, :reader_visibility, :writer_visibility, :getter, :options,
|
@@ -284,18 +286,14 @@ module DataMapper
|
|
284
286
|
# @return <String> name of field in data-store
|
285
287
|
# -
|
286
288
|
# @api semi-public
|
287
|
-
def field(
|
288
|
-
@
|
289
|
+
def field(repository_name = nil)
|
290
|
+
@field || fields[repository_name || model.repository_name]
|
289
291
|
end
|
290
292
|
|
291
293
|
def unique
|
292
294
|
@unique ||= @options.fetch(:unique, @serial || @key || false)
|
293
295
|
end
|
294
296
|
|
295
|
-
def repository(*args)
|
296
|
-
@model.repository(*args)
|
297
|
-
end
|
298
|
-
|
299
297
|
def hash
|
300
298
|
if @custom && !@bound
|
301
299
|
@type.bind(self)
|
@@ -336,7 +334,6 @@ module DataMapper
|
|
336
334
|
@lazy
|
337
335
|
end
|
338
336
|
|
339
|
-
|
340
337
|
# Returns whether or not the property is a key or a part of a key
|
341
338
|
#
|
342
339
|
# @return <TrueClass, FalseClass> whether the property is a key or a part of
|
@@ -377,17 +374,7 @@ module DataMapper
|
|
377
374
|
def get(resource)
|
378
375
|
new_record = resource.new_record?
|
379
376
|
|
380
|
-
unless new_record || resource.attribute_loaded?(name)
|
381
|
-
# TODO: refactor this section
|
382
|
-
contexts = if lazy?
|
383
|
-
name
|
384
|
-
else
|
385
|
-
model.properties(resource.repository.name).reject do |property|
|
386
|
-
property.lazy? || resource.attribute_loaded?(property.name)
|
387
|
-
end
|
388
|
-
end
|
389
|
-
resource.send(:lazy_load, contexts)
|
390
|
-
end
|
377
|
+
lazy_load(resource) unless new_record || resource.attribute_loaded?(name)
|
391
378
|
|
392
379
|
value = get!(resource)
|
393
380
|
|
@@ -416,6 +403,7 @@ module DataMapper
|
|
416
403
|
#-
|
417
404
|
# @api private
|
418
405
|
def set(resource, value)
|
406
|
+
lazy_load(resource) unless resource.new_record? || resource.attribute_loaded?(name)
|
419
407
|
new_value = typecast(value)
|
420
408
|
old_value = get!(resource)
|
421
409
|
|
@@ -432,6 +420,21 @@ module DataMapper
|
|
432
420
|
resource.instance_variable_set(instance_variable_name, value)
|
433
421
|
end
|
434
422
|
|
423
|
+
# Loads lazy columns when get or set is called.
|
424
|
+
#-
|
425
|
+
# @api private
|
426
|
+
def lazy_load(resource)
|
427
|
+
# TODO: refactor this section
|
428
|
+
contexts = if lazy?
|
429
|
+
name
|
430
|
+
else
|
431
|
+
model.properties(resource.repository.name).reject do |property|
|
432
|
+
property.lazy? || resource.attribute_loaded?(property.name)
|
433
|
+
end
|
434
|
+
end
|
435
|
+
resource.send(:lazy_load, contexts)
|
436
|
+
end
|
437
|
+
|
435
438
|
# typecasts values into a primitive
|
436
439
|
#
|
437
440
|
# @return <TrueClass, String, Float, Integer, BigDecimal, DateTime, Date, Time
|
@@ -439,17 +442,37 @@ module DataMapper
|
|
439
442
|
#-
|
440
443
|
# @api private
|
441
444
|
def typecast(value)
|
442
|
-
return value if
|
445
|
+
return type.typecast(value, self) if type.respond_to?(:typecast)
|
446
|
+
return value if value.kind_of?(primitive) || value.nil?
|
443
447
|
begin
|
444
|
-
if
|
445
|
-
elsif
|
446
|
-
elsif
|
447
|
-
elsif
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
448
|
+
if primitive == TrueClass then %w[ true 1 t ].include?(value.to_s.downcase)
|
449
|
+
elsif primitive == String then value.to_s
|
450
|
+
elsif primitive == Float then value.to_f
|
451
|
+
elsif primitive == Integer
|
452
|
+
# The simplest possible implementation, i.e. value.to_i, is not
|
453
|
+
# desirable because "junk".to_i gives "0". We want nil instead,
|
454
|
+
# because this makes it clear that the typecast failed.
|
455
|
+
#
|
456
|
+
# After benchmarking, we preferred the current implementation over
|
457
|
+
# these two alternatives:
|
458
|
+
# * Integer(value) rescue nil
|
459
|
+
# * Integer(value_to_s =~ /(\d+)/ ? $1 : value_to_s) rescue nil
|
460
|
+
value_to_i = value.to_i
|
461
|
+
if value_to_i == 0 && value != '0'
|
462
|
+
value_to_s = value.to_s
|
463
|
+
begin
|
464
|
+
Integer(value_to_s =~ /^(\d+)/ ? $1 : value_to_s)
|
465
|
+
rescue ArgumentError
|
466
|
+
nil
|
467
|
+
end
|
468
|
+
else
|
469
|
+
value_to_i
|
470
|
+
end
|
471
|
+
elsif primitive == BigDecimal then BigDecimal(value.to_s)
|
472
|
+
elsif primitive == DateTime then typecast_to_datetime(value)
|
473
|
+
elsif primitive == Date then typecast_to_date(value)
|
474
|
+
elsif primitive == Time then typecast_to_time(value)
|
475
|
+
elsif primitive == Class then self.class.find_const(value)
|
453
476
|
else
|
454
477
|
value
|
455
478
|
end
|
@@ -503,6 +526,7 @@ module DataMapper
|
|
503
526
|
@primitive = @options.fetch(:primitive, @type.respond_to?(:primitive) ? @type.primitive : @type)
|
504
527
|
|
505
528
|
@getter = TrueClass == @primitive ? "#{@name}?".to_sym : @name
|
529
|
+
@field = @options.fetch(:field, nil)
|
506
530
|
@serial = @options.fetch(:serial, false)
|
507
531
|
@key = @options.fetch(:key, @serial || false)
|
508
532
|
@default = @options.fetch(:default, nil)
|
@@ -524,18 +548,23 @@ module DataMapper
|
|
524
548
|
@length = @options.fetch(:length, @options.fetch(:size, DEFAULT_LENGTH))
|
525
549
|
elsif BigDecimal == @primitive || Float == @primitive
|
526
550
|
@precision = @options.fetch(:precision, DEFAULT_PRECISION)
|
527
|
-
|
551
|
+
|
552
|
+
default_scale = (Float == @primitive) ? DEFAULT_SCALE_FLOAT : DEFAULT_SCALE_BIGDECIMAL
|
553
|
+
@scale = @options.fetch(:scale, default_scale)
|
554
|
+
# @scale = @options.fetch(:scale, DEFAULT_SCALE_BIGDECIMAL)
|
528
555
|
|
529
556
|
unless @precision > 0
|
530
557
|
raise ArgumentError, "precision must be greater than 0, but was #{@precision.inspect}"
|
531
558
|
end
|
532
559
|
|
533
|
-
|
534
|
-
|
535
|
-
|
560
|
+
if (BigDecimal == @primitive) || (Float == @primitive && !@scale.nil?)
|
561
|
+
unless @scale >= 0
|
562
|
+
raise ArgumentError, "scale must be equal to or greater than 0, but was #{@scale.inspect}"
|
563
|
+
end
|
536
564
|
|
537
|
-
|
538
|
-
|
565
|
+
unless @precision >= @scale
|
566
|
+
raise ArgumentError, "precision must be equal to or greater than scale, but was #{@precision.inspect} and scale was #{@scale.inspect}"
|
567
|
+
end
|
539
568
|
end
|
540
569
|
end
|
541
570
|
|
@@ -545,11 +574,13 @@ module DataMapper
|
|
545
574
|
@model.property_serialization_setup(self) if @model.respond_to?(:property_serialization_setup)
|
546
575
|
end
|
547
576
|
|
577
|
+
def fields
|
578
|
+
@fields ||= Hash.new { |h,k| h[k] = repository(k).adapter.field_naming_convention.call(self.name) }
|
579
|
+
end
|
580
|
+
|
548
581
|
def determine_visibility # :nodoc:
|
549
582
|
@reader_visibility = @options[:reader] || @options[:accessor] || :public
|
550
583
|
@writer_visibility = @options[:writer] || @options[:accessor] || :public
|
551
|
-
@writer_visibility = :protected if @options[:protected]
|
552
|
-
@writer_visibility = :private if @options[:private]
|
553
584
|
|
554
585
|
unless VISIBILITY_OPTIONS.include?(@reader_visibility) && VISIBILITY_OPTIONS.include?(@writer_visibility)
|
555
586
|
raise ArgumentError, 'property visibility must be :public, :protected, or :private', caller(2)
|
data/lib/dm-core/property_set.rb
CHANGED
@@ -4,10 +4,12 @@ module DataMapper
|
|
4
4
|
include Enumerable
|
5
5
|
|
6
6
|
def [](name)
|
7
|
-
@property_for[name]
|
7
|
+
@property_for[name] || raise(ArgumentError, "Unknown property '#{name}'", caller)
|
8
8
|
end
|
9
9
|
|
10
|
-
|
10
|
+
def has_property?(name)
|
11
|
+
!!@property_for[name]
|
12
|
+
end
|
11
13
|
|
12
14
|
def slice(*names)
|
13
15
|
@property_for.values_at(*names)
|
@@ -44,13 +46,15 @@ module DataMapper
|
|
44
46
|
|
45
47
|
def indexes
|
46
48
|
index_hash = {}
|
47
|
-
|
49
|
+
repository_name = repository.name
|
50
|
+
each { |property| parse_index(property.index, property.field(repository_name), index_hash) }
|
48
51
|
index_hash
|
49
52
|
end
|
50
53
|
|
51
54
|
def unique_indexes
|
52
55
|
index_hash = {}
|
53
|
-
|
56
|
+
repository_name = repository.name
|
57
|
+
each { |property| parse_index(property.unique_index, property.field(repository_name), index_hash) }
|
54
58
|
index_hash
|
55
59
|
end
|
56
60
|
|
@@ -108,16 +112,6 @@ module DataMapper
|
|
108
112
|
'#<PropertySet:{' + map { |property| property.inspect }.join(',') + '}>'
|
109
113
|
end
|
110
114
|
|
111
|
-
def dup(target = nil)
|
112
|
-
return super() unless target
|
113
|
-
|
114
|
-
properties = map do |property|
|
115
|
-
Property.new(target || property.model, property.name, property.type, property.options.dup)
|
116
|
-
end
|
117
|
-
|
118
|
-
self.class.new(properties)
|
119
|
-
end
|
120
|
-
|
121
115
|
private
|
122
116
|
|
123
117
|
def initialize(properties = [])
|
data/lib/dm-core/query.rb
CHANGED
@@ -3,10 +3,10 @@ module DataMapper
|
|
3
3
|
include Assertions
|
4
4
|
|
5
5
|
OPTIONS = [
|
6
|
-
:reload, :offset, :limit, :order, :add_reversed, :fields, :links, :includes, :conditions
|
6
|
+
:reload, :offset, :limit, :order, :add_reversed, :fields, :links, :includes, :conditions, :unique
|
7
7
|
]
|
8
8
|
|
9
|
-
attr_reader :repository, :model, *OPTIONS - [ :reload ]
|
9
|
+
attr_reader :repository, :model, *OPTIONS - [ :reload, :unique ]
|
10
10
|
attr_writer :add_reversed
|
11
11
|
alias add_reversed? add_reversed
|
12
12
|
|
@@ -14,6 +14,10 @@ module DataMapper
|
|
14
14
|
@reload
|
15
15
|
end
|
16
16
|
|
17
|
+
def unique?
|
18
|
+
@unique
|
19
|
+
end
|
20
|
+
|
17
21
|
def reverse
|
18
22
|
dup.reverse!
|
19
23
|
end
|
@@ -42,6 +46,7 @@ module DataMapper
|
|
42
46
|
|
43
47
|
# only overwrite the attributes with non-default values
|
44
48
|
@reload = other.reload? unless other.reload? == false
|
49
|
+
@unique = other.unique? unless other.unique? == false
|
45
50
|
@offset = other.offset unless other.offset == 0
|
46
51
|
@limit = other.limit unless other.limit == nil
|
47
52
|
@order = other.order unless other.order == model.default_order
|
@@ -67,6 +72,7 @@ module DataMapper
|
|
67
72
|
# return hash == other.hash
|
68
73
|
@model == other.model &&
|
69
74
|
@reload == other.reload? &&
|
75
|
+
@unique == other.unique? &&
|
70
76
|
@offset == other.offset &&
|
71
77
|
@limit == other.limit &&
|
72
78
|
@order == other.order && # order is significant, so do not sort this
|
@@ -136,6 +142,7 @@ module DataMapper
|
|
136
142
|
[ :limit, limit ],
|
137
143
|
[ :offset, offset ],
|
138
144
|
[ :reload, reload? ],
|
145
|
+
[ :unique, unique? ],
|
139
146
|
]
|
140
147
|
|
141
148
|
"#<#{self.class.name} #{attrs.map { |(k,v)| "@#{k}=#{v.inspect}" } * ' '}>"
|
@@ -157,6 +164,7 @@ module DataMapper
|
|
157
164
|
|
158
165
|
@model = model # must be Class that includes DM::Resource
|
159
166
|
@reload = options.fetch :reload, false # must be true or false
|
167
|
+
@unique = options.fetch :unique, false # must be true or false
|
160
168
|
@offset = options.fetch :offset, 0 # must be an Integer greater than or equal to 0
|
161
169
|
@limit = options.fetch :limit, nil # must be an Integer greater than or equal to 1
|
162
170
|
@order = options.fetch :order, model.default_order # must be an Array of Symbol, DM::Query::Direction or DM::Property
|
@@ -214,18 +222,20 @@ module DataMapper
|
|
214
222
|
options.each do |key, value|
|
215
223
|
case key
|
216
224
|
when DataMapper::Query::Operator
|
217
|
-
options[key] = properties[key.target].type.dump(value, properties[key.target]) if
|
225
|
+
options[key] = properties[key.target].type.dump(value, properties[key.target]) if properties.has_property?(key.target) && properties[key.target].custom?
|
218
226
|
when Symbol, String
|
219
|
-
options[key] = properties[key].type.dump(value, properties[key]) if
|
227
|
+
options[key] = properties[key].type.dump(value, properties[key]) if properties.has_property?(key) && properties[key].custom?
|
220
228
|
end
|
221
229
|
end
|
222
230
|
end
|
223
231
|
|
224
232
|
# validate the options
|
225
233
|
def assert_valid_options(options)
|
226
|
-
# validate the reload option
|
227
|
-
|
228
|
-
|
234
|
+
# validate the reload option and unique option
|
235
|
+
([ :reload, :unique ] & options.keys).each do |attribute|
|
236
|
+
if options[attribute] != true && options[attribute] != false
|
237
|
+
raise ArgumentError, "+options[:#{attribute}]+ must be true or false, but was #{options[attribute].inspect}", caller(2)
|
238
|
+
end
|
229
239
|
end
|
230
240
|
|
231
241
|
# validate the offset and limit options
|
@@ -248,7 +258,17 @@ module DataMapper
|
|
248
258
|
assert_kind_of "options[:#{attribute}]", value, Array
|
249
259
|
|
250
260
|
if value.empty?
|
251
|
-
|
261
|
+
if attribute == :fields
|
262
|
+
if options[:unique] == false
|
263
|
+
raise ArgumentError, '+options[:fields]+ cannot be empty if +options[:unique] is false', caller(2)
|
264
|
+
end
|
265
|
+
elsif attribute == :order
|
266
|
+
if options[:fields] && options[:fields].any? { |p| !p.kind_of?(Operator) }
|
267
|
+
raise ArgumentError, '+options[:order]+ cannot be empty if +options[:fields] contains a non-operator', caller(2)
|
268
|
+
end
|
269
|
+
else
|
270
|
+
raise ArgumentError, "+options[:#{attribute}]+ cannot be empty", caller(2)
|
271
|
+
end
|
252
272
|
end
|
253
273
|
end
|
254
274
|
|
@@ -318,9 +338,10 @@ module DataMapper
|
|
318
338
|
# normalize fields to DM::Property
|
319
339
|
def normalize_fields(fields)
|
320
340
|
# TODO: return a PropertySet
|
341
|
+
# TODO: raise an exception if the property is not available in the repository
|
321
342
|
fields.map do |field|
|
322
343
|
case field
|
323
|
-
when Property
|
344
|
+
when Property, Operator
|
324
345
|
# TODO: if the Property's model doesn't match
|
325
346
|
# self.model, append the property's model to @links
|
326
347
|
# eg:
|
@@ -527,6 +548,8 @@ module DataMapper
|
|
527
548
|
end
|
528
549
|
|
529
550
|
def ==(other)
|
551
|
+
return true if super
|
552
|
+
return false unless other.kind_of?(self.class)
|
530
553
|
@operator == other.operator && @target == other.target
|
531
554
|
end
|
532
555
|
|
@@ -542,6 +565,8 @@ module DataMapper
|
|
542
565
|
|
543
566
|
class Path
|
544
567
|
include Assertions
|
568
|
+
|
569
|
+
%w[ id type ].each { |m| undef_method m }
|
545
570
|
|
546
571
|
attr_reader :relationships, :model, :property, :operator
|
547
572
|
|
data/lib/dm-core/repository.rb
CHANGED
File without changes
|
data/lib/dm-core/resource.rb
CHANGED
@@ -2,6 +2,8 @@ require 'set'
|
|
2
2
|
|
3
3
|
module DataMapper
|
4
4
|
module Resource
|
5
|
+
include Assertions
|
6
|
+
|
5
7
|
##
|
6
8
|
#
|
7
9
|
# Appends a module for inclusion into the model class after
|
@@ -22,12 +24,10 @@ module DataMapper
|
|
22
24
|
extra_inclusions.concat inclusions
|
23
25
|
true
|
24
26
|
end
|
25
|
-
|
27
|
+
|
26
28
|
def self.extra_inclusions
|
27
29
|
@extra_inclusions ||= []
|
28
30
|
end
|
29
|
-
|
30
|
-
include Assertions
|
31
31
|
|
32
32
|
# When Resource is included in a class this method makes sure
|
33
33
|
# it gets all the methods
|
@@ -334,11 +334,7 @@ module DataMapper
|
|
334
334
|
# --
|
335
335
|
# @api public
|
336
336
|
def loaded_attributes
|
337
|
-
|
338
|
-
properties.each do |property|
|
339
|
-
names << property.name if attribute_loaded?(property.name)
|
340
|
-
end
|
341
|
-
names
|
337
|
+
properties.map{|p| p.name if attribute_loaded?(p.name)}.compact
|
342
338
|
end
|
343
339
|
|
344
340
|
# set of original values of properties
|
@@ -471,7 +467,9 @@ module DataMapper
|
|
471
467
|
# --
|
472
468
|
# @api public
|
473
469
|
def attributes
|
474
|
-
properties.map
|
470
|
+
properties.map do |p|
|
471
|
+
[p.name, send(p.getter)] if p.reader_visibility == :public
|
472
|
+
end.compact.to_hash
|
475
473
|
end
|
476
474
|
|
477
475
|
# Mass assign of attributes
|
@@ -485,9 +483,11 @@ module DataMapper
|
|
485
483
|
values_hash.each_pair do |k,v|
|
486
484
|
setter = "#{k.to_s.sub(/\?\z/, '')}="
|
487
485
|
|
488
|
-
|
489
|
-
|
490
|
-
|
486
|
+
if respond_to?(setter)
|
487
|
+
send(setter, v)
|
488
|
+
else
|
489
|
+
raise NameError, "#{setter} is not a public property"
|
490
|
+
end
|
491
491
|
end
|
492
492
|
end
|
493
493
|
|
@@ -585,7 +585,7 @@ module DataMapper
|
|
585
585
|
end
|
586
586
|
|
587
587
|
def lazy_load(name)
|
588
|
-
reload_attributes(*properties.lazy_load_context(name))
|
588
|
+
reload_attributes(*properties.lazy_load_context(name) - loaded_attributes)
|
589
589
|
end
|
590
590
|
|
591
591
|
def child_associations
|