dm-core 0.10.2 → 1.0.0.rc1
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/.gitignore +10 -1
- data/Gemfile +143 -0
- data/Rakefile +9 -5
- data/VERSION +1 -1
- data/dm-core.gemspec +160 -57
- data/lib/dm-core.rb +131 -56
- data/lib/dm-core/adapters.rb +98 -14
- data/lib/dm-core/adapters/abstract_adapter.rb +24 -4
- data/lib/dm-core/adapters/in_memory_adapter.rb +7 -2
- data/lib/dm-core/associations/many_to_many.rb +19 -30
- data/lib/dm-core/associations/many_to_one.rb +58 -42
- data/lib/dm-core/associations/one_to_many.rb +33 -23
- data/lib/dm-core/associations/one_to_one.rb +27 -11
- data/lib/dm-core/associations/relationship.rb +4 -4
- data/lib/dm-core/collection.rb +23 -16
- data/lib/dm-core/core_ext/array.rb +36 -0
- data/lib/dm-core/core_ext/hash.rb +30 -0
- data/lib/dm-core/core_ext/module.rb +46 -0
- data/lib/dm-core/core_ext/object.rb +31 -0
- data/lib/dm-core/core_ext/pathname.rb +20 -0
- data/lib/dm-core/core_ext/string.rb +22 -0
- data/lib/dm-core/core_ext/try_dup.rb +44 -0
- data/lib/dm-core/model.rb +88 -27
- data/lib/dm-core/model/hook.rb +75 -18
- data/lib/dm-core/model/property.rb +50 -9
- data/lib/dm-core/model/relationship.rb +31 -31
- data/lib/dm-core/model/scope.rb +3 -3
- data/lib/dm-core/property.rb +196 -516
- data/lib/dm-core/property/binary.rb +7 -0
- data/lib/dm-core/property/boolean.rb +35 -0
- data/lib/dm-core/property/class.rb +24 -0
- data/lib/dm-core/property/date.rb +47 -0
- data/lib/dm-core/property/date_time.rb +48 -0
- data/lib/dm-core/property/decimal.rb +43 -0
- data/lib/dm-core/property/discriminator.rb +48 -0
- data/lib/dm-core/property/float.rb +24 -0
- data/lib/dm-core/property/integer.rb +32 -0
- data/lib/dm-core/property/numeric.rb +43 -0
- data/lib/dm-core/property/object.rb +32 -0
- data/lib/dm-core/property/serial.rb +8 -0
- data/lib/dm-core/property/string.rb +49 -0
- data/lib/dm-core/property/text.rb +12 -0
- data/lib/dm-core/property/time.rb +48 -0
- data/lib/dm-core/property/typecast/numeric.rb +32 -0
- data/lib/dm-core/property/typecast/time.rb +28 -0
- data/lib/dm-core/property_set.rb +10 -4
- data/lib/dm-core/query.rb +14 -37
- data/lib/dm-core/query/conditions/comparison.rb +8 -6
- data/lib/dm-core/query/conditions/operation.rb +33 -2
- data/lib/dm-core/query/operator.rb +2 -5
- data/lib/dm-core/query/path.rb +4 -6
- data/lib/dm-core/repository.rb +21 -6
- data/lib/dm-core/resource.rb +316 -133
- data/lib/dm-core/resource/state.rb +79 -0
- data/lib/dm-core/resource/state/clean.rb +40 -0
- data/lib/dm-core/resource/state/deleted.rb +30 -0
- data/lib/dm-core/resource/state/dirty.rb +86 -0
- data/lib/dm-core/resource/state/immutable.rb +34 -0
- data/lib/dm-core/resource/state/persisted.rb +29 -0
- data/lib/dm-core/resource/state/transient.rb +70 -0
- data/lib/dm-core/spec/lib/adapter_helpers.rb +52 -0
- data/lib/dm-core/spec/lib/collection_helpers.rb +20 -0
- data/{spec → lib/dm-core/spec}/lib/counter_adapter.rb +5 -1
- data/lib/dm-core/spec/lib/pending_helpers.rb +50 -0
- data/lib/dm-core/spec/lib/spec_helper.rb +68 -0
- data/lib/dm-core/spec/setup.rb +165 -0
- data/lib/dm-core/spec/{adapter_shared_spec.rb → shared/adapter_spec.rb} +21 -7
- data/{spec/public/shared/resource_shared_spec.rb → lib/dm-core/spec/shared/resource_spec.rb} +120 -83
- data/{spec/public/shared/sel_shared_spec.rb → lib/dm-core/spec/shared/sel_spec.rb} +5 -6
- data/lib/dm-core/support/assertions.rb +8 -0
- data/lib/dm-core/support/equalizer.rb +1 -0
- data/lib/dm-core/support/hook.rb +420 -0
- data/lib/dm-core/support/lazy_array.rb +453 -0
- data/lib/dm-core/support/local_object_space.rb +12 -0
- data/lib/dm-core/support/logger.rb +193 -6
- data/lib/dm-core/support/naming_conventions.rb +8 -8
- data/lib/dm-core/support/subject.rb +33 -0
- data/lib/dm-core/type.rb +4 -0
- data/lib/dm-core/types/boolean.rb +2 -0
- data/lib/dm-core/types/decimal.rb +9 -0
- data/lib/dm-core/types/discriminator.rb +2 -0
- data/lib/dm-core/types/object.rb +3 -0
- data/lib/dm-core/types/serial.rb +2 -0
- data/lib/dm-core/types/text.rb +2 -0
- data/lib/dm-core/version.rb +1 -1
- data/spec/public/associations/many_to_many/read_multiple_join_spec.rb +67 -0
- data/spec/public/model/hook_spec.rb +209 -0
- data/spec/public/model/property_spec.rb +35 -0
- data/spec/public/model/relationship_spec.rb +33 -20
- data/spec/public/model_spec.rb +142 -10
- data/spec/public/property/binary_spec.rb +14 -0
- data/spec/public/property/boolean_spec.rb +14 -0
- data/spec/public/property/class_spec.rb +20 -0
- data/spec/public/property/date_spec.rb +14 -0
- data/spec/public/property/date_time_spec.rb +14 -0
- data/spec/public/property/decimal_spec.rb +14 -0
- data/spec/public/{types → property}/discriminator_spec.rb +2 -12
- data/spec/public/property/float_spec.rb +14 -0
- data/spec/public/property/integer_spec.rb +14 -0
- data/spec/public/property/object_spec.rb +9 -17
- data/spec/public/property/serial_spec.rb +14 -0
- data/spec/public/property/string_spec.rb +14 -0
- data/spec/public/property/text_spec.rb +52 -0
- data/spec/public/property/time_spec.rb +14 -0
- data/spec/public/property_spec.rb +28 -87
- data/spec/public/resource_spec.rb +101 -0
- data/spec/public/sel_spec.rb +5 -15
- data/spec/public/shared/collection_shared_spec.rb +16 -30
- data/spec/public/shared/finder_shared_spec.rb +2 -4
- data/spec/public/shared/property_shared_spec.rb +176 -0
- data/spec/semipublic/adapters/abstract_adapter_spec.rb +1 -1
- data/spec/semipublic/adapters/in_memory_adapter_spec.rb +2 -2
- data/spec/semipublic/associations/many_to_many_spec.rb +89 -0
- data/spec/semipublic/associations/many_to_one_spec.rb +24 -1
- data/spec/semipublic/associations/one_to_many_spec.rb +51 -0
- data/spec/semipublic/associations/one_to_one_spec.rb +49 -0
- data/spec/semipublic/associations/relationship_spec.rb +3 -3
- data/spec/semipublic/associations_spec.rb +1 -1
- data/spec/semipublic/property/binary_spec.rb +13 -0
- data/spec/semipublic/property/boolean_spec.rb +65 -0
- data/spec/semipublic/property/class_spec.rb +33 -0
- data/spec/semipublic/property/date_spec.rb +43 -0
- data/spec/semipublic/property/date_time_spec.rb +46 -0
- data/spec/semipublic/property/decimal_spec.rb +82 -0
- data/spec/semipublic/property/discriminator_spec.rb +19 -0
- data/spec/semipublic/property/float_spec.rb +82 -0
- data/spec/semipublic/property/integer_spec.rb +82 -0
- data/spec/semipublic/property/serial_spec.rb +13 -0
- data/spec/semipublic/property/string_spec.rb +13 -0
- data/spec/semipublic/property/text_spec.rb +31 -0
- data/spec/semipublic/property/time_spec.rb +50 -0
- data/spec/semipublic/property_spec.rb +2 -532
- data/spec/semipublic/query/conditions/comparison_spec.rb +171 -169
- data/spec/semipublic/query/conditions/operation_spec.rb +53 -51
- data/spec/semipublic/query/path_spec.rb +17 -17
- data/spec/semipublic/query_spec.rb +47 -78
- data/spec/semipublic/resource/state/clean_spec.rb +88 -0
- data/spec/semipublic/resource/state/deleted_spec.rb +78 -0
- data/spec/semipublic/resource/state/dirty_spec.rb +133 -0
- data/spec/semipublic/resource/state/immutable_spec.rb +99 -0
- data/spec/semipublic/resource/state/transient_spec.rb +128 -0
- data/spec/semipublic/resource/state_spec.rb +226 -0
- data/spec/semipublic/shared/property_shared_spec.rb +143 -0
- data/spec/semipublic/shared/resource_shared_spec.rb +16 -15
- data/spec/semipublic/shared/resource_state_shared_spec.rb +78 -0
- data/spec/semipublic/shared/subject_shared_spec.rb +79 -0
- data/spec/spec_helper.rb +21 -97
- data/spec/support/types/huge_integer.rb +17 -0
- data/spec/unit/array_spec.rb +48 -0
- data/spec/unit/hash_spec.rb +35 -0
- data/spec/unit/hook_spec.rb +1234 -0
- data/spec/unit/lazy_array_spec.rb +1959 -0
- data/spec/unit/module_spec.rb +70 -0
- data/spec/unit/object_spec.rb +37 -0
- data/spec/unit/try_dup_spec.rb +45 -0
- data/tasks/local_gemfile.rake +18 -0
- data/tasks/spec.rake +0 -3
- metadata +197 -71
- data/deps.rip +0 -2
- data/lib/dm-core/adapters/data_objects_adapter.rb +0 -712
- data/lib/dm-core/adapters/mysql_adapter.rb +0 -42
- data/lib/dm-core/adapters/oracle_adapter.rb +0 -229
- data/lib/dm-core/adapters/postgres_adapter.rb +0 -22
- data/lib/dm-core/adapters/sqlite3_adapter.rb +0 -17
- data/lib/dm-core/adapters/sqlserver_adapter.rb +0 -114
- data/lib/dm-core/adapters/yaml_adapter.rb +0 -111
- data/lib/dm-core/core_ext/enumerable.rb +0 -28
- data/lib/dm-core/migrations.rb +0 -1427
- data/lib/dm-core/spec/data_objects_adapter_shared_spec.rb +0 -366
- data/lib/dm-core/transaction.rb +0 -508
- data/lib/dm-core/types/paranoid_boolean.rb +0 -42
- data/lib/dm-core/types/paranoid_datetime.rb +0 -41
- data/spec/lib/adapter_helpers.rb +0 -105
- data/spec/lib/collection_helpers.rb +0 -18
- data/spec/lib/pending_helpers.rb +0 -46
- data/spec/public/migrations_spec.rb +0 -503
- data/spec/public/transaction_spec.rb +0 -153
- data/spec/semipublic/adapters/mysql_adapter_spec.rb +0 -17
- data/spec/semipublic/adapters/oracle_adapter_spec.rb +0 -194
- data/spec/semipublic/adapters/postgres_adapter_spec.rb +0 -17
- data/spec/semipublic/adapters/sqlite3_adapter_spec.rb +0 -17
- data/spec/semipublic/adapters/sqlserver_adapter_spec.rb +0 -17
- data/spec/semipublic/adapters/yaml_adapter_spec.rb +0 -12
@@ -6,9 +6,10 @@ module DataMapper
|
|
6
6
|
# (1 to 1, 1 to n, n to m) implements a subclass of this class
|
7
7
|
# with methods like get and set overridden.
|
8
8
|
class Relationship
|
9
|
-
include
|
9
|
+
include DataMapper::Assertions
|
10
|
+
include Subject
|
10
11
|
|
11
|
-
OPTIONS = [ :child_repository_name, :parent_repository_name, :child_key, :parent_key, :min, :max, :inverse, :reader_visibility, :writer_visibility ].to_set
|
12
|
+
OPTIONS = [ :child_repository_name, :parent_repository_name, :child_key, :parent_key, :min, :max, :inverse, :reader_visibility, :writer_visibility, :default ].to_set
|
12
13
|
|
13
14
|
# Relationship name
|
14
15
|
#
|
@@ -319,8 +320,6 @@ module DataMapper
|
|
319
320
|
#
|
320
321
|
# @api semipublic
|
321
322
|
def loaded?(resource)
|
322
|
-
assert_kind_of 'resource', resource, source_model
|
323
|
-
|
324
323
|
resource.instance_variable_defined?(instance_variable_name)
|
325
324
|
end
|
326
325
|
|
@@ -449,6 +448,7 @@ module DataMapper
|
|
449
448
|
@max = @options[:max]
|
450
449
|
@reader_visibility = @options.fetch(:reader_visibility, :public)
|
451
450
|
@writer_visibility = @options.fetch(:writer_visibility, :public)
|
451
|
+
@default = @options.fetch(:default, nil)
|
452
452
|
|
453
453
|
# TODO: normalize the @query to become :conditions => AndOperation
|
454
454
|
# - Property/Relationship/Path should be left alone
|
data/lib/dm-core/collection.rb
CHANGED
@@ -352,8 +352,12 @@ module DataMapper
|
|
352
352
|
def at(offset)
|
353
353
|
if loaded? || partially_loaded?(offset)
|
354
354
|
super
|
355
|
-
elsif offset
|
355
|
+
elsif offset == 0
|
356
|
+
first
|
357
|
+
elsif offset > 0
|
356
358
|
first(:offset => offset)
|
359
|
+
elsif offset == -1
|
360
|
+
last
|
357
361
|
else
|
358
362
|
last(:offset => offset.abs - 1)
|
359
363
|
end
|
@@ -787,7 +791,7 @@ module DataMapper
|
|
787
791
|
#
|
788
792
|
# @api public
|
789
793
|
def create(attributes = {})
|
790
|
-
_create(
|
794
|
+
_create(attributes)
|
791
795
|
end
|
792
796
|
|
793
797
|
# Create a Resource in the Collection, bypassing hooks
|
@@ -800,7 +804,7 @@ module DataMapper
|
|
800
804
|
#
|
801
805
|
# @api public
|
802
806
|
def create!(attributes = {})
|
803
|
-
_create(
|
807
|
+
_create(attributes, false)
|
804
808
|
end
|
805
809
|
|
806
810
|
# Update every Resource in the Collection
|
@@ -814,7 +818,7 @@ module DataMapper
|
|
814
818
|
# true if the resources were successfully updated
|
815
819
|
#
|
816
820
|
# @api public
|
817
|
-
def update(attributes
|
821
|
+
def update(attributes)
|
818
822
|
assert_update_clean_only(:update)
|
819
823
|
|
820
824
|
dirty_attributes = model.new(attributes).dirty_attributes
|
@@ -832,7 +836,7 @@ module DataMapper
|
|
832
836
|
# true if the resources were successfully updated
|
833
837
|
#
|
834
838
|
# @api public
|
835
|
-
def update!(attributes
|
839
|
+
def update!(attributes)
|
836
840
|
assert_update_clean_only(:update!)
|
837
841
|
|
838
842
|
model = self.model
|
@@ -866,7 +870,7 @@ module DataMapper
|
|
866
870
|
#
|
867
871
|
# @api public
|
868
872
|
def save
|
869
|
-
_save
|
873
|
+
_save
|
870
874
|
end
|
871
875
|
|
872
876
|
# Save every Resource in the Collection bypassing validation
|
@@ -915,7 +919,10 @@ module DataMapper
|
|
915
919
|
return false
|
916
920
|
end
|
917
921
|
|
918
|
-
each
|
922
|
+
each do |resource|
|
923
|
+
resource.persisted_state = Resource::State::Immutable.new(resource)
|
924
|
+
end
|
925
|
+
|
919
926
|
clear
|
920
927
|
else
|
921
928
|
mark_loaded
|
@@ -1192,8 +1199,8 @@ module DataMapper
|
|
1192
1199
|
|
1193
1200
|
# Creates a resource in the collection
|
1194
1201
|
#
|
1195
|
-
# @param [Boolean]
|
1196
|
-
# Whether to
|
1202
|
+
# @param [Boolean] execute_hooks
|
1203
|
+
# Whether to execute hooks or not
|
1197
1204
|
# @param [Hash] attributes
|
1198
1205
|
# Attributes with which to create the new resource
|
1199
1206
|
#
|
@@ -1201,8 +1208,8 @@ module DataMapper
|
|
1201
1208
|
# a saved Resource
|
1202
1209
|
#
|
1203
1210
|
# @api private
|
1204
|
-
def _create(
|
1205
|
-
resource = repository.scope { model.send(
|
1211
|
+
def _create(attributes, execute_hooks = true)
|
1212
|
+
resource = repository.scope { model.send(execute_hooks ? :create : :create!, default_attributes.merge(attributes)) }
|
1206
1213
|
self << resource if resource.saved?
|
1207
1214
|
resource
|
1208
1215
|
end
|
@@ -1220,18 +1227,18 @@ module DataMapper
|
|
1220
1227
|
|
1221
1228
|
# Saves a collection
|
1222
1229
|
#
|
1223
|
-
# @param [
|
1224
|
-
#
|
1230
|
+
# @param [Boolean] execute_hooks
|
1231
|
+
# Whether to execute hooks or not
|
1225
1232
|
#
|
1226
1233
|
# @return [Boolean]
|
1227
1234
|
# Returns true if collection was updated
|
1228
1235
|
#
|
1229
1236
|
# @api private
|
1230
|
-
def _save(
|
1237
|
+
def _save(execute_hooks = true)
|
1231
1238
|
loaded_entries = self.loaded_entries
|
1232
1239
|
loaded_entries.each { |resource| set_default_attributes(resource) }
|
1233
1240
|
@removed.clear
|
1234
|
-
loaded_entries.all? { |resource| resource.__send__(
|
1241
|
+
loaded_entries.all? { |resource| resource.__send__(execute_hooks ? :save : :save!) }
|
1235
1242
|
end
|
1236
1243
|
|
1237
1244
|
# Returns default values to initialize new Resources in the Collection
|
@@ -1436,7 +1443,7 @@ module DataMapper
|
|
1436
1443
|
|
1437
1444
|
if model.model_method_defined?(method)
|
1438
1445
|
delegate_to_model(method, *args, &block)
|
1439
|
-
elsif relationship = relationships[method] || relationships[method.to_s.
|
1446
|
+
elsif relationship = relationships[method] || relationships[method.to_s.singularize.to_sym]
|
1440
1447
|
delegate_to_relationship(relationship, *args)
|
1441
1448
|
else
|
1442
1449
|
super
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Array
|
2
|
+
|
3
|
+
##
|
4
|
+
# Transforms an Array of key/value pairs into a Hash
|
5
|
+
#
|
6
|
+
# This is a better idiom than using Hash[*array.flatten] in Ruby 1.8.6
|
7
|
+
# because it is not possible to limit the flattening to a single
|
8
|
+
# level.
|
9
|
+
#
|
10
|
+
# @return [Hash]
|
11
|
+
# A Hash where each entry in the Array is turned into a key/value
|
12
|
+
#
|
13
|
+
# @api public
|
14
|
+
def to_hash
|
15
|
+
h = {}
|
16
|
+
each { |k,v| h[k] = v }
|
17
|
+
h
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Transforms an Array of key/value pairs into a Mash
|
22
|
+
#
|
23
|
+
# This is a better idiom than using Mash[*array.flatten] in Ruby 1.8.6
|
24
|
+
# because it is not possible to limit the flattening to a single
|
25
|
+
# level.
|
26
|
+
#
|
27
|
+
# @return [Mash]
|
28
|
+
# A Hash where each entry in the Array is turned into a key/value
|
29
|
+
#
|
30
|
+
# @api public
|
31
|
+
def to_mash
|
32
|
+
m = Mash.new
|
33
|
+
each { |k,v| m[k] = v }
|
34
|
+
m
|
35
|
+
end
|
36
|
+
end # class Array
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Hash
|
2
|
+
|
3
|
+
##
|
4
|
+
# Create a hash with *only* key/value pairs in receiver and +allowed+
|
5
|
+
#
|
6
|
+
# { :one => 1, :two => 2, :three => 3 }.only(:one) #=> { :one => 1 }
|
7
|
+
#
|
8
|
+
# @param [Array[String, Symbol]] *allowed The hash keys to include.
|
9
|
+
#
|
10
|
+
# @return [Hash] A new hash with only the selected keys.
|
11
|
+
#
|
12
|
+
# @api public
|
13
|
+
def only(*allowed)
|
14
|
+
hash = {}
|
15
|
+
allowed.each {|k| hash[k] = self[k] if self.has_key?(k) }
|
16
|
+
hash
|
17
|
+
end
|
18
|
+
|
19
|
+
# Convert to Mash. This class has semantics of ActiveSupport's
|
20
|
+
# HashWithIndifferentAccess and we only have it so that people can write
|
21
|
+
# params[:key] instead of params['key'].
|
22
|
+
#
|
23
|
+
# @return [Mash] This hash as a Mash for string or symbol key access.
|
24
|
+
def to_mash
|
25
|
+
hash = Mash.new(self)
|
26
|
+
hash.default = default
|
27
|
+
hash
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'dm-core/core_ext/object'
|
2
|
+
|
3
|
+
class Module
|
4
|
+
|
5
|
+
def find_const(const_name)
|
6
|
+
if const_name[0..1] == '::'
|
7
|
+
Object.full_const_get(const_name[2..-1])
|
8
|
+
else
|
9
|
+
nested_const_lookup(const_name)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
# Doesn't do any caching since constants can change with remove_const
|
16
|
+
def nested_const_lookup(const_name)
|
17
|
+
unless equal?(Object)
|
18
|
+
constants = []
|
19
|
+
|
20
|
+
name.split('::').each do |part|
|
21
|
+
const = constants.last || Object
|
22
|
+
constants << const.const_get(part)
|
23
|
+
end
|
24
|
+
|
25
|
+
parts = const_name.split('::')
|
26
|
+
|
27
|
+
# from most to least specific constant, use each as a base and try
|
28
|
+
# to find a constant with the name const_name within them
|
29
|
+
constants.reverse_each do |const|
|
30
|
+
# return the nested constant if available
|
31
|
+
return const if parts.all? do |part|
|
32
|
+
const = if RUBY_VERSION >= '1.9.0'
|
33
|
+
const.const_defined?(part, false) ? const.const_get(part, false) : nil
|
34
|
+
else
|
35
|
+
const.const_defined?(part) ? const.const_get(part) : nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# no relative constant found, fallback to an absolute lookup and
|
42
|
+
# use const_missing if not found
|
43
|
+
Object.full_const_get(const_name)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Object
|
2
|
+
|
3
|
+
# @param name<String> The name of the constant to get, e.g. "Merb::Router".
|
4
|
+
#
|
5
|
+
# @return [Object] The constant corresponding to the name.
|
6
|
+
def full_const_get(name)
|
7
|
+
list = name.split("::")
|
8
|
+
list.shift if list.first.blank?
|
9
|
+
obj = self
|
10
|
+
list.each do |x|
|
11
|
+
# This is required because const_get tries to look for constants in the
|
12
|
+
# ancestor chain, but we only want constants that are HERE
|
13
|
+
obj = obj.const_defined?(x) ? obj.const_get(x) : obj.const_missing(x)
|
14
|
+
end
|
15
|
+
obj
|
16
|
+
end
|
17
|
+
|
18
|
+
# @param name<String> The name of the constant to get, e.g. "Merb::Router".
|
19
|
+
# @param value<Object> The value to assign to the constant.
|
20
|
+
#
|
21
|
+
# @return [Object] The constant corresponding to the name.
|
22
|
+
def full_const_set(name, value)
|
23
|
+
list = name.split("::")
|
24
|
+
toplevel = list.first.blank?
|
25
|
+
list.shift if toplevel
|
26
|
+
last = list.pop
|
27
|
+
obj = list.empty? ? Object : Object.full_const_get(list.join("::"))
|
28
|
+
obj.const_set(last, value) if obj && !obj.const_defined?(last)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Pathname
|
2
|
+
# Append path segments and expand to absolute path
|
3
|
+
#
|
4
|
+
# file = Pathname(Dir.pwd) / "subdir1" / :subdir2 / "filename.ext"
|
5
|
+
#
|
6
|
+
# @param [Pathname, String, #to_s] path path segment to concatenate with receiver
|
7
|
+
#
|
8
|
+
# @return [Pathname]
|
9
|
+
# receiver with _path_ appended and expanded to an absolute path
|
10
|
+
#
|
11
|
+
# @api public
|
12
|
+
def /(path)
|
13
|
+
(self + path).expand_path
|
14
|
+
end
|
15
|
+
|
16
|
+
# alias to_s to to_str when to_str not defined
|
17
|
+
unless public_instance_methods(false).any? { |m| m.to_sym == :to_str }
|
18
|
+
alias to_str to_s
|
19
|
+
end
|
20
|
+
end # class Pathname
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
##
|
4
|
+
# Replace sequences of whitespace (including newlines) with either
|
5
|
+
# a single space or remove them entirely (according to param _spaced_)
|
6
|
+
#
|
7
|
+
# <<QUERY.compress_lines
|
8
|
+
# SELECT name
|
9
|
+
# FROM users
|
10
|
+
# QUERY => "SELECT name FROM users"
|
11
|
+
#
|
12
|
+
# @param [TrueClass, FalseClass] spaced (default=true)
|
13
|
+
# Determines whether returned string has whitespace collapsed or removed
|
14
|
+
#
|
15
|
+
# @return [String] Receiver with whitespace (including newlines) replaced
|
16
|
+
#
|
17
|
+
# @api public
|
18
|
+
def compress_lines(spaced = true)
|
19
|
+
split($/).map { |line| line.strip }.join(spaced ? ' ' : '')
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class Object
|
2
|
+
# Override this in a child if it cannot be dup'ed
|
3
|
+
#
|
4
|
+
# @return [Object]
|
5
|
+
def try_dup
|
6
|
+
self.dup
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class TrueClass
|
11
|
+
def try_dup
|
12
|
+
self
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class FalseClass
|
17
|
+
def try_dup
|
18
|
+
self
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Module
|
23
|
+
def try_dup
|
24
|
+
self
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class NilClass
|
29
|
+
def try_dup
|
30
|
+
self
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Numeric
|
35
|
+
def try_dup
|
36
|
+
self
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class Symbol
|
41
|
+
def try_dup
|
42
|
+
self
|
43
|
+
end
|
44
|
+
end
|
data/lib/dm-core/model.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# TODO: add Model#create!, Model#update, Model#update!, Model#destroy and Model#destroy!
|
2
2
|
|
3
|
+
# TODO: DRY up raise_on_save_failure with attr_accessor_with_default
|
4
|
+
# once AS branch is merged in
|
5
|
+
|
3
6
|
module DataMapper
|
4
7
|
module Model
|
5
8
|
extend Chainable
|
@@ -30,7 +33,7 @@ module DataMapper
|
|
30
33
|
warn "Passing in +storage_name+ to #{name}.new is deprecated (#{caller[0]})"
|
31
34
|
model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
32
35
|
def self.default_storage_name
|
33
|
-
#{
|
36
|
+
#{ActiveSupport::Inflector.classify(storage_name).inspect}.freeze
|
34
37
|
end
|
35
38
|
RUBY
|
36
39
|
end
|
@@ -72,6 +75,68 @@ module DataMapper
|
|
72
75
|
# @api semipublic
|
73
76
|
attr_reader :descendants
|
74
77
|
|
78
|
+
# Return if Resource#save should raise an exception on save failures (globally)
|
79
|
+
#
|
80
|
+
# This is false by default.
|
81
|
+
#
|
82
|
+
# DataMapper::Model.raise_on_save_failure # => false
|
83
|
+
#
|
84
|
+
# @return [Boolean]
|
85
|
+
# true if a failure in Resource#save should raise an exception
|
86
|
+
#
|
87
|
+
# @api public
|
88
|
+
def self.raise_on_save_failure
|
89
|
+
if defined?(@raise_on_save_failure)
|
90
|
+
@raise_on_save_failure
|
91
|
+
else
|
92
|
+
false
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Specify if Resource#save should raise an exception on save failures (globally)
|
97
|
+
#
|
98
|
+
# @param [Boolean]
|
99
|
+
# a boolean that if true will cause Resource#save to raise an exception
|
100
|
+
#
|
101
|
+
# @return [Boolean]
|
102
|
+
# true if a failure in Resource#save should raise an exception
|
103
|
+
#
|
104
|
+
# @api public
|
105
|
+
def self.raise_on_save_failure=(raise_on_save_failure)
|
106
|
+
@raise_on_save_failure = raise_on_save_failure
|
107
|
+
end
|
108
|
+
|
109
|
+
# Return if Resource#save should raise an exception on save failures (per-model)
|
110
|
+
#
|
111
|
+
# This delegates to DataMapper::Model.raise_on_save_failure by default.
|
112
|
+
#
|
113
|
+
# User.raise_on_save_failure # => false
|
114
|
+
#
|
115
|
+
# @return [Boolean]
|
116
|
+
# true if a failure in Resource#save should raise an exception
|
117
|
+
#
|
118
|
+
# @api public
|
119
|
+
def raise_on_save_failure
|
120
|
+
if defined?(@raise_on_save_failure)
|
121
|
+
@raise_on_save_failure
|
122
|
+
else
|
123
|
+
DataMapper::Model.raise_on_save_failure
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Specify if Resource#save should raise an exception on save failures (per-model)
|
128
|
+
#
|
129
|
+
# @param [Boolean]
|
130
|
+
# a boolean that if true will cause Resource#save to raise an exception
|
131
|
+
#
|
132
|
+
# @return [Boolean]
|
133
|
+
# true if a failure in Resource#save should raise an exception
|
134
|
+
#
|
135
|
+
# @api public
|
136
|
+
def raise_on_save_failure=(raise_on_save_failure)
|
137
|
+
@raise_on_save_failure = raise_on_save_failure
|
138
|
+
end
|
139
|
+
|
75
140
|
# Appends a module for inclusion into the model class after Resource.
|
76
141
|
#
|
77
142
|
# This is a useful way to extend Resource while still retaining a
|
@@ -147,6 +212,8 @@ module DataMapper
|
|
147
212
|
model.instance_variable_set(:@default_order, {})
|
148
213
|
model.instance_variable_set(:@descendants, descendants.class.new(model, descendants))
|
149
214
|
|
215
|
+
model.extend(Chainable)
|
216
|
+
|
150
217
|
extra_extensions.each { |mod| model.extend(mod) }
|
151
218
|
extra_inclusions.each { |mod| model.send(:include, mod) }
|
152
219
|
end
|
@@ -163,13 +230,6 @@ module DataMapper
|
|
163
230
|
model.instance_variable_set(:@storage_names, @storage_names.dup)
|
164
231
|
model.instance_variable_set(:@default_order, @default_order.dup)
|
165
232
|
model.instance_variable_set(:@descendants, descendants.class.new(model, descendants))
|
166
|
-
|
167
|
-
# TODO: move this into dm-validations
|
168
|
-
if respond_to?(:validators)
|
169
|
-
validators.contexts.each do |context, validators|
|
170
|
-
model.validators.context(context).concat(validators)
|
171
|
-
end
|
172
|
-
end
|
173
233
|
end
|
174
234
|
end
|
175
235
|
|
@@ -410,7 +470,7 @@ module DataMapper
|
|
410
470
|
#
|
411
471
|
# @api public
|
412
472
|
def create(attributes = {})
|
413
|
-
_create(
|
473
|
+
_create(attributes)
|
414
474
|
end
|
415
475
|
|
416
476
|
# Create a Resource, bypassing hooks
|
@@ -423,7 +483,7 @@ module DataMapper
|
|
423
483
|
#
|
424
484
|
# @api public
|
425
485
|
def create!(attributes = {})
|
426
|
-
_create(
|
486
|
+
_create(attributes, false)
|
427
487
|
end
|
428
488
|
|
429
489
|
# Copy a set of records from one repository to another.
|
@@ -452,7 +512,7 @@ module DataMapper
|
|
452
512
|
|
453
513
|
all(query.merge(:repository => source_repository_name)).each do |resource|
|
454
514
|
new_resource = new
|
455
|
-
query[:fields].each { |property| property.
|
515
|
+
query[:fields].each { |property| new_resource.__send__("#{property.name}=", property.get(resource)) }
|
456
516
|
resources << new_resource if new_resource.save
|
457
517
|
end
|
458
518
|
|
@@ -490,7 +550,7 @@ module DataMapper
|
|
490
550
|
record = record.dup
|
491
551
|
field_map.each { |property, field| record[property] = record.delete(field) if record.key?(field) }
|
492
552
|
|
493
|
-
model = discriminator && record[discriminator] || self
|
553
|
+
model = discriminator && discriminator.load(record[discriminator]) || self
|
494
554
|
model_key = model.key(repository_name)
|
495
555
|
|
496
556
|
resource = if model_key.valid?(key_values = record.values_at(*model_key))
|
@@ -507,9 +567,7 @@ module DataMapper
|
|
507
567
|
|
508
568
|
# TODO: typecasting should happen inside the Adapter
|
509
569
|
# and all values should come back as expected objects
|
510
|
-
|
511
|
-
value = property.type.load(value, property)
|
512
|
-
end
|
570
|
+
value = property.load(value)
|
513
571
|
|
514
572
|
property.set!(resource, value)
|
515
573
|
end
|
@@ -533,14 +591,15 @@ module DataMapper
|
|
533
591
|
end
|
534
592
|
|
535
593
|
resource.instance_variable_set(:@_repository, repository)
|
536
|
-
resource.instance_variable_set(:@_saved, true)
|
537
594
|
|
538
595
|
if identity_map
|
596
|
+
resource.persisted_state = Resource::State::Clean.new(resource) unless resource.persisted_state?
|
597
|
+
|
539
598
|
# defer setting the IdentityMap so second level caches can
|
540
599
|
# record the state of the resource after loaded
|
541
600
|
identity_map[key_values] = resource
|
542
601
|
else
|
543
|
-
resource.
|
602
|
+
resource.persisted_state = Resource::State::Immutable.new(resource)
|
544
603
|
end
|
545
604
|
|
546
605
|
resource
|
@@ -622,9 +681,9 @@ module DataMapper
|
|
622
681
|
private
|
623
682
|
|
624
683
|
# @api private
|
625
|
-
def _create(
|
684
|
+
def _create(attributes, execute_hooks = true)
|
626
685
|
resource = new(attributes)
|
627
|
-
resource.__send__(
|
686
|
+
resource.__send__(execute_hooks ? :save : :save!)
|
628
687
|
resource
|
629
688
|
end
|
630
689
|
|
@@ -635,8 +694,10 @@ module DataMapper
|
|
635
694
|
self
|
636
695
|
elsif name == :Resource
|
637
696
|
Resource
|
638
|
-
elsif
|
639
|
-
|
697
|
+
elsif DataMapper::Property.const_defined?(name)
|
698
|
+
DataMapper::Property.const_get(name)
|
699
|
+
elsif DataMapper::Types.const_defined?(name)
|
700
|
+
DataMapper::Types.const_get(name)
|
640
701
|
else
|
641
702
|
super
|
642
703
|
end
|
@@ -681,14 +742,14 @@ module DataMapper
|
|
681
742
|
if self.query.repository == repository
|
682
743
|
query
|
683
744
|
else
|
684
|
-
|
745
|
+
repository.new_query(self, query.options)
|
685
746
|
end
|
686
747
|
end
|
687
748
|
end
|
688
749
|
|
689
750
|
# @api private
|
690
|
-
def assert_valid # :nodoc:
|
691
|
-
return if @valid
|
751
|
+
def assert_valid(force = false) # :nodoc:
|
752
|
+
return if @valid && !force
|
692
753
|
@valid = true
|
693
754
|
|
694
755
|
name = self.name
|
@@ -704,8 +765,8 @@ module DataMapper
|
|
704
765
|
end
|
705
766
|
|
706
767
|
# initialize join models and target keys
|
707
|
-
@relationships.
|
708
|
-
relationships.
|
768
|
+
@relationships.values.each do |relationships|
|
769
|
+
relationships.values.each do |relationship|
|
709
770
|
relationship.child_key
|
710
771
|
relationship.through if relationship.respond_to?(:through)
|
711
772
|
relationship.via if relationship.respond_to?(:via)
|
@@ -715,7 +776,7 @@ module DataMapper
|
|
715
776
|
|
716
777
|
# @api private
|
717
778
|
def model_methods
|
718
|
-
@model_methods ||= ancestor_instance_methods { |mod| mod.
|
779
|
+
@model_methods ||= ancestor_instance_methods { |mod| mod.singleton_class }
|
719
780
|
end
|
720
781
|
|
721
782
|
# @api private
|