ghost_dm-core 1.3.0.beta
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 +29 -0
- data/.document +5 -0
- data/.gitignore +35 -0
- data/.yardopts +1 -0
- data/Gemfile +65 -0
- data/LICENSE +20 -0
- data/README.md +269 -0
- data/Rakefile +4 -0
- data/dm-core.gemspec +24 -0
- data/lib/dm-core.rb +292 -0
- data/lib/dm-core/adapters.rb +222 -0
- data/lib/dm-core/adapters/abstract_adapter.rb +237 -0
- data/lib/dm-core/adapters/in_memory_adapter.rb +113 -0
- data/lib/dm-core/associations/many_to_many.rb +499 -0
- data/lib/dm-core/associations/many_to_one.rb +290 -0
- data/lib/dm-core/associations/one_to_many.rb +348 -0
- data/lib/dm-core/associations/one_to_one.rb +86 -0
- data/lib/dm-core/associations/relationship.rb +663 -0
- data/lib/dm-core/backwards.rb +13 -0
- data/lib/dm-core/collection.rb +1515 -0
- data/lib/dm-core/core_ext/kernel.rb +23 -0
- data/lib/dm-core/core_ext/pathname.rb +6 -0
- data/lib/dm-core/core_ext/symbol.rb +10 -0
- data/lib/dm-core/identity_map.rb +7 -0
- data/lib/dm-core/model.rb +874 -0
- data/lib/dm-core/model/hook.rb +103 -0
- data/lib/dm-core/model/is.rb +32 -0
- data/lib/dm-core/model/property.rb +249 -0
- data/lib/dm-core/model/relationship.rb +378 -0
- data/lib/dm-core/model/scope.rb +89 -0
- data/lib/dm-core/property.rb +866 -0
- data/lib/dm-core/property/binary.rb +21 -0
- data/lib/dm-core/property/boolean.rb +20 -0
- data/lib/dm-core/property/class.rb +17 -0
- data/lib/dm-core/property/date.rb +10 -0
- data/lib/dm-core/property/date_time.rb +10 -0
- data/lib/dm-core/property/decimal.rb +36 -0
- data/lib/dm-core/property/discriminator.rb +44 -0
- data/lib/dm-core/property/float.rb +16 -0
- data/lib/dm-core/property/integer.rb +22 -0
- data/lib/dm-core/property/invalid_value_error.rb +22 -0
- data/lib/dm-core/property/lookup.rb +27 -0
- data/lib/dm-core/property/numeric.rb +38 -0
- data/lib/dm-core/property/object.rb +34 -0
- data/lib/dm-core/property/serial.rb +14 -0
- data/lib/dm-core/property/string.rb +38 -0
- data/lib/dm-core/property/text.rb +9 -0
- data/lib/dm-core/property/time.rb +10 -0
- data/lib/dm-core/property_set.rb +177 -0
- data/lib/dm-core/query.rb +1366 -0
- data/lib/dm-core/query/conditions/comparison.rb +911 -0
- data/lib/dm-core/query/conditions/operation.rb +721 -0
- data/lib/dm-core/query/direction.rb +36 -0
- data/lib/dm-core/query/operator.rb +35 -0
- data/lib/dm-core/query/path.rb +114 -0
- data/lib/dm-core/query/sort.rb +39 -0
- data/lib/dm-core/relationship_set.rb +72 -0
- data/lib/dm-core/repository.rb +226 -0
- data/lib/dm-core/resource.rb +1214 -0
- data/lib/dm-core/resource/persistence_state.rb +75 -0
- data/lib/dm-core/resource/persistence_state/clean.rb +40 -0
- data/lib/dm-core/resource/persistence_state/deleted.rb +30 -0
- data/lib/dm-core/resource/persistence_state/dirty.rb +96 -0
- data/lib/dm-core/resource/persistence_state/immutable.rb +34 -0
- data/lib/dm-core/resource/persistence_state/persisted.rb +29 -0
- data/lib/dm-core/resource/persistence_state/transient.rb +80 -0
- data/lib/dm-core/spec/lib/adapter_helpers.rb +64 -0
- data/lib/dm-core/spec/lib/collection_helpers.rb +21 -0
- data/lib/dm-core/spec/lib/counter_adapter.rb +38 -0
- data/lib/dm-core/spec/lib/pending_helpers.rb +50 -0
- data/lib/dm-core/spec/lib/spec_helper.rb +74 -0
- data/lib/dm-core/spec/setup.rb +174 -0
- data/lib/dm-core/spec/shared/adapter_spec.rb +341 -0
- data/lib/dm-core/spec/shared/public/property_spec.rb +229 -0
- data/lib/dm-core/spec/shared/resource_spec.rb +1232 -0
- data/lib/dm-core/spec/shared/sel_spec.rb +111 -0
- data/lib/dm-core/spec/shared/semipublic/property_spec.rb +176 -0
- data/lib/dm-core/spec/shared/semipublic/query/conditions/abstract_comparison_spec.rb +261 -0
- data/lib/dm-core/support/assertions.rb +8 -0
- data/lib/dm-core/support/chainable.rb +18 -0
- data/lib/dm-core/support/deprecate.rb +12 -0
- data/lib/dm-core/support/descendant_set.rb +89 -0
- data/lib/dm-core/support/equalizer.rb +48 -0
- data/lib/dm-core/support/ext/array.rb +22 -0
- data/lib/dm-core/support/ext/blank.rb +25 -0
- data/lib/dm-core/support/ext/hash.rb +67 -0
- data/lib/dm-core/support/ext/module.rb +47 -0
- data/lib/dm-core/support/ext/object.rb +57 -0
- data/lib/dm-core/support/ext/string.rb +24 -0
- data/lib/dm-core/support/ext/try_dup.rb +12 -0
- data/lib/dm-core/support/hook.rb +405 -0
- data/lib/dm-core/support/inflections.rb +60 -0
- data/lib/dm-core/support/inflector/inflections.rb +211 -0
- data/lib/dm-core/support/inflector/methods.rb +151 -0
- data/lib/dm-core/support/lazy_array.rb +451 -0
- data/lib/dm-core/support/local_object_space.rb +13 -0
- data/lib/dm-core/support/logger.rb +201 -0
- data/lib/dm-core/support/mash.rb +176 -0
- data/lib/dm-core/support/naming_conventions.rb +90 -0
- data/lib/dm-core/support/ordered_set.rb +380 -0
- data/lib/dm-core/support/subject.rb +33 -0
- data/lib/dm-core/support/subject_set.rb +250 -0
- data/lib/dm-core/version.rb +3 -0
- data/script/performance.rb +275 -0
- data/script/profile.rb +218 -0
- data/spec/lib/rspec_immediate_feedback_formatter.rb +54 -0
- data/spec/public/associations/many_to_many/read_multiple_join_spec.rb +68 -0
- data/spec/public/associations/many_to_many_spec.rb +197 -0
- data/spec/public/associations/many_to_one_spec.rb +83 -0
- data/spec/public/associations/many_to_one_with_boolean_cpk_spec.rb +40 -0
- data/spec/public/associations/many_to_one_with_custom_fk_spec.rb +49 -0
- data/spec/public/associations/one_to_many_spec.rb +81 -0
- data/spec/public/associations/one_to_one_spec.rb +176 -0
- data/spec/public/associations/one_to_one_with_boolean_cpk_spec.rb +46 -0
- data/spec/public/collection_spec.rb +69 -0
- data/spec/public/finalize_spec.rb +76 -0
- data/spec/public/model/hook_spec.rb +246 -0
- data/spec/public/model/property_spec.rb +88 -0
- data/spec/public/model/relationship_spec.rb +1040 -0
- data/spec/public/model_spec.rb +462 -0
- data/spec/public/property/binary_spec.rb +41 -0
- data/spec/public/property/boolean_spec.rb +22 -0
- data/spec/public/property/class_spec.rb +28 -0
- data/spec/public/property/date_spec.rb +22 -0
- data/spec/public/property/date_time_spec.rb +22 -0
- data/spec/public/property/decimal_spec.rb +23 -0
- data/spec/public/property/discriminator_spec.rb +135 -0
- data/spec/public/property/float_spec.rb +22 -0
- data/spec/public/property/integer_spec.rb +22 -0
- data/spec/public/property/object_spec.rb +107 -0
- data/spec/public/property/serial_spec.rb +22 -0
- data/spec/public/property/string_spec.rb +22 -0
- data/spec/public/property/text_spec.rb +63 -0
- data/spec/public/property/time_spec.rb +22 -0
- data/spec/public/property_spec.rb +341 -0
- data/spec/public/resource_spec.rb +288 -0
- data/spec/public/sel_spec.rb +53 -0
- data/spec/public/setup_spec.rb +145 -0
- data/spec/public/shared/association_collection_shared_spec.rb +309 -0
- data/spec/public/shared/collection_finder_shared_spec.rb +267 -0
- data/spec/public/shared/collection_shared_spec.rb +1667 -0
- data/spec/public/shared/finder_shared_spec.rb +1629 -0
- data/spec/rcov.opts +6 -0
- data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
- data/spec/semipublic/adapters/in_memory_adapter_spec.rb +13 -0
- data/spec/semipublic/associations/many_to_many_spec.rb +94 -0
- data/spec/semipublic/associations/many_to_one_spec.rb +63 -0
- data/spec/semipublic/associations/one_to_many_spec.rb +55 -0
- data/spec/semipublic/associations/one_to_one_spec.rb +53 -0
- data/spec/semipublic/associations/relationship_spec.rb +200 -0
- data/spec/semipublic/associations_spec.rb +177 -0
- data/spec/semipublic/collection_spec.rb +110 -0
- data/spec/semipublic/model_spec.rb +96 -0
- data/spec/semipublic/property/binary_spec.rb +13 -0
- data/spec/semipublic/property/boolean_spec.rb +47 -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 +83 -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/lookup_spec.rb +29 -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 +114 -0
- data/spec/semipublic/query/conditions/comparison_spec.rb +1501 -0
- data/spec/semipublic/query/conditions/operation_spec.rb +1294 -0
- data/spec/semipublic/query/path_spec.rb +471 -0
- data/spec/semipublic/query_spec.rb +3682 -0
- 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 +162 -0
- data/spec/semipublic/resource/state/immutable_spec.rb +105 -0
- data/spec/semipublic/resource/state/transient_spec.rb +162 -0
- data/spec/semipublic/resource/state_spec.rb +230 -0
- data/spec/semipublic/resource_spec.rb +23 -0
- data/spec/semipublic/shared/condition_shared_spec.rb +9 -0
- data/spec/semipublic/shared/resource_shared_spec.rb +199 -0
- data/spec/semipublic/shared/resource_state_shared_spec.rb +79 -0
- data/spec/semipublic/shared/subject_shared_spec.rb +79 -0
- data/spec/spec.opts +5 -0
- data/spec/spec_helper.rb +38 -0
- data/spec/support/core_ext/hash.rb +10 -0
- data/spec/support/core_ext/inheritable_attributes.rb +46 -0
- data/spec/support/properties/huge_integer.rb +17 -0
- data/spec/unit/array_spec.rb +23 -0
- data/spec/unit/blank_spec.rb +73 -0
- data/spec/unit/data_mapper/ordered_set/append_spec.rb +26 -0
- data/spec/unit/data_mapper/ordered_set/clear_spec.rb +24 -0
- data/spec/unit/data_mapper/ordered_set/delete_spec.rb +28 -0
- data/spec/unit/data_mapper/ordered_set/each_spec.rb +19 -0
- data/spec/unit/data_mapper/ordered_set/empty_spec.rb +20 -0
- data/spec/unit/data_mapper/ordered_set/entries_spec.rb +22 -0
- data/spec/unit/data_mapper/ordered_set/eql_spec.rb +51 -0
- data/spec/unit/data_mapper/ordered_set/equal_value_spec.rb +84 -0
- data/spec/unit/data_mapper/ordered_set/hash_spec.rb +12 -0
- data/spec/unit/data_mapper/ordered_set/include_spec.rb +23 -0
- data/spec/unit/data_mapper/ordered_set/index_spec.rb +28 -0
- data/spec/unit/data_mapper/ordered_set/initialize_spec.rb +32 -0
- data/spec/unit/data_mapper/ordered_set/merge_spec.rb +36 -0
- data/spec/unit/data_mapper/ordered_set/shared/append_spec.rb +24 -0
- data/spec/unit/data_mapper/ordered_set/shared/clear_spec.rb +9 -0
- data/spec/unit/data_mapper/ordered_set/shared/delete_spec.rb +25 -0
- data/spec/unit/data_mapper/ordered_set/shared/each_spec.rb +17 -0
- data/spec/unit/data_mapper/ordered_set/shared/empty_spec.rb +9 -0
- data/spec/unit/data_mapper/ordered_set/shared/entries_spec.rb +9 -0
- data/spec/unit/data_mapper/ordered_set/shared/include_spec.rb +9 -0
- data/spec/unit/data_mapper/ordered_set/shared/index_spec.rb +13 -0
- data/spec/unit/data_mapper/ordered_set/shared/initialize_spec.rb +28 -0
- data/spec/unit/data_mapper/ordered_set/shared/merge_spec.rb +28 -0
- data/spec/unit/data_mapper/ordered_set/shared/size_spec.rb +13 -0
- data/spec/unit/data_mapper/ordered_set/shared/to_ary_spec.rb +11 -0
- data/spec/unit/data_mapper/ordered_set/size_spec.rb +27 -0
- data/spec/unit/data_mapper/ordered_set/to_ary_spec.rb +23 -0
- data/spec/unit/data_mapper/subject_set/append_spec.rb +47 -0
- data/spec/unit/data_mapper/subject_set/clear_spec.rb +34 -0
- data/spec/unit/data_mapper/subject_set/delete_spec.rb +40 -0
- data/spec/unit/data_mapper/subject_set/each_spec.rb +30 -0
- data/spec/unit/data_mapper/subject_set/empty_spec.rb +31 -0
- data/spec/unit/data_mapper/subject_set/entries_spec.rb +31 -0
- data/spec/unit/data_mapper/subject_set/get_spec.rb +34 -0
- data/spec/unit/data_mapper/subject_set/include_spec.rb +32 -0
- data/spec/unit/data_mapper/subject_set/named_spec.rb +33 -0
- data/spec/unit/data_mapper/subject_set/shared/append_spec.rb +18 -0
- data/spec/unit/data_mapper/subject_set/shared/clear_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/delete_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/each_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/empty_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/entries_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/get_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/include_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/named_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/size_spec.rb +13 -0
- data/spec/unit/data_mapper/subject_set/shared/to_ary_spec.rb +9 -0
- data/spec/unit/data_mapper/subject_set/shared/values_at_spec.rb +44 -0
- data/spec/unit/data_mapper/subject_set/size_spec.rb +42 -0
- data/spec/unit/data_mapper/subject_set/to_ary_spec.rb +34 -0
- data/spec/unit/data_mapper/subject_set/values_at_spec.rb +57 -0
- data/spec/unit/hash_spec.rb +28 -0
- data/spec/unit/hook_spec.rb +1235 -0
- data/spec/unit/inflections_spec.rb +16 -0
- data/spec/unit/lazy_array_spec.rb +1949 -0
- data/spec/unit/mash_spec.rb +312 -0
- data/spec/unit/module_spec.rb +71 -0
- data/spec/unit/object_spec.rb +38 -0
- data/spec/unit/try_dup_spec.rb +46 -0
- data/tasks/ci.rake +1 -0
- data/tasks/spec.rake +38 -0
- data/tasks/yard.rake +9 -0
- data/tasks/yardstick.rake +19 -0
- metadata +365 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
module DataMapper
|
|
2
|
+
|
|
3
|
+
# An ordered set of things
|
|
4
|
+
#
|
|
5
|
+
# {OrderedSet} implements set behavior and keeps
|
|
6
|
+
# track of the order in which entries were added.
|
|
7
|
+
#
|
|
8
|
+
# {OrderedSet} allows to inject a class that implements
|
|
9
|
+
# {OrderedSet::Cache::API} at construction time, and will
|
|
10
|
+
# use that cache implementation to enforce set semantics
|
|
11
|
+
# and perform internal caching of insertion order.
|
|
12
|
+
#
|
|
13
|
+
# @see OrderedSet::Cache::API
|
|
14
|
+
# @see OrderedSet::Cache
|
|
15
|
+
# @see SubjectSet::NameCache
|
|
16
|
+
#
|
|
17
|
+
# @api private
|
|
18
|
+
class OrderedSet
|
|
19
|
+
|
|
20
|
+
# The default cache used by {OrderedSet}
|
|
21
|
+
#
|
|
22
|
+
# Uses a {Hash} as internal storage and enforces set semantics
|
|
23
|
+
# by calling #eql? and #hash on the set's entries.
|
|
24
|
+
#
|
|
25
|
+
# @api private
|
|
26
|
+
class Cache
|
|
27
|
+
|
|
28
|
+
# The default implementation of the {API} that {OrderedSet} expects from
|
|
29
|
+
# the cache object that it uses to
|
|
30
|
+
#
|
|
31
|
+
# 1. keep track of insertion order
|
|
32
|
+
# 2. enforce set semantics.
|
|
33
|
+
#
|
|
34
|
+
# Classes including {API} must customize the behavior of the cache in 2 ways:
|
|
35
|
+
#
|
|
36
|
+
# They must determine the value to use as cache key and thus set discriminator,
|
|
37
|
+
# by implementing the {#key_for} method. The {#key_for} method accepts an arbitrary
|
|
38
|
+
# object as param and the method is free to return whatever value from that method.
|
|
39
|
+
# Obviously this will most likely be some attribute or value otherwise derived from
|
|
40
|
+
# the object that got passed in.
|
|
41
|
+
#
|
|
42
|
+
# They must determine which objects are valid set entries by overwriting the
|
|
43
|
+
# {#valid?} method. The {#valid?} method accepts an arbitrary object as param and
|
|
44
|
+
# the overwriting method must return either true or false.
|
|
45
|
+
#
|
|
46
|
+
# The motivation behind this is that set semantics cannot always be enforced
|
|
47
|
+
# by calling {#eql?} and {#hash} on the set's entries. For example, two entries
|
|
48
|
+
# might be considered unique wrt the set if their names are the same, but other
|
|
49
|
+
# internal state differs. This is exactly the case for {DataMapper::Property} and
|
|
50
|
+
# {DataMapper::Associations::Relationship} objects.
|
|
51
|
+
#
|
|
52
|
+
# @see DataMapper::SubjectSet::NameCache
|
|
53
|
+
#
|
|
54
|
+
# @api private
|
|
55
|
+
module API
|
|
56
|
+
|
|
57
|
+
# Initialize a new Cache
|
|
58
|
+
#
|
|
59
|
+
# @api private
|
|
60
|
+
def initialize
|
|
61
|
+
@cache = {}
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Tests if the given entry qualifies to be added to the cache
|
|
65
|
+
#
|
|
66
|
+
# @param [Object] entry
|
|
67
|
+
# the entry to be checked
|
|
68
|
+
#
|
|
69
|
+
# @return [Boolean]
|
|
70
|
+
# true if the entry qualifies to be added to the cache
|
|
71
|
+
#
|
|
72
|
+
# @api private
|
|
73
|
+
def valid?(entry)
|
|
74
|
+
raise NotImplementedError, "#{self}#valid? must be implemented"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Given an entry, return the key to be used in the cache
|
|
78
|
+
#
|
|
79
|
+
# @param [Object] entry
|
|
80
|
+
# the entry to get the key for
|
|
81
|
+
#
|
|
82
|
+
# @return [Object, nil]
|
|
83
|
+
# a value derived from the entry that is used as key in the cache
|
|
84
|
+
#
|
|
85
|
+
# @api private
|
|
86
|
+
def key_for(entry)
|
|
87
|
+
raise NotImplementedError, "#{self}#key_for must be implemented"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Check if the entry exists in the cache
|
|
91
|
+
#
|
|
92
|
+
# @param [Object] entry
|
|
93
|
+
# the entry to test for
|
|
94
|
+
#
|
|
95
|
+
# @return [Boolean]
|
|
96
|
+
# true if entry is included in the cache
|
|
97
|
+
#
|
|
98
|
+
# @api private
|
|
99
|
+
def include?(entry)
|
|
100
|
+
@cache.has_key?(key_for(entry))
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Return the index for the entry in the cache
|
|
104
|
+
#
|
|
105
|
+
# @param [Object] entry
|
|
106
|
+
# the entry to get the index for
|
|
107
|
+
#
|
|
108
|
+
# @return [Integer, nil]
|
|
109
|
+
# the index for the entry, or nil if it does not exist
|
|
110
|
+
#
|
|
111
|
+
# @api private
|
|
112
|
+
def [](entry)
|
|
113
|
+
@cache[key_for(entry)]
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Set the index for the entry in the cache
|
|
117
|
+
#
|
|
118
|
+
# @param [Object] entry
|
|
119
|
+
# the entry to set the index for
|
|
120
|
+
# @param [Integer] index
|
|
121
|
+
# the index to assign to the given entry
|
|
122
|
+
#
|
|
123
|
+
# @return [Integer]
|
|
124
|
+
# the given index for the entry
|
|
125
|
+
#
|
|
126
|
+
# @api private
|
|
127
|
+
def []=(entry, index)
|
|
128
|
+
if valid?(entry)
|
|
129
|
+
@cache[key_for(entry)] = index
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Delete an entry from the cache
|
|
134
|
+
#
|
|
135
|
+
# @param [Object] entry
|
|
136
|
+
# the entry to delete from the cache
|
|
137
|
+
#
|
|
138
|
+
# @return [API] self
|
|
139
|
+
#
|
|
140
|
+
# @api private
|
|
141
|
+
def delete(entry)
|
|
142
|
+
deleted_index = @cache.delete(key_for(entry))
|
|
143
|
+
if deleted_index
|
|
144
|
+
@cache.each do |key, index|
|
|
145
|
+
@cache[key] -= 1 if index > deleted_index
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
deleted_index
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Removes all entries and returns self
|
|
152
|
+
#
|
|
153
|
+
# @return [API] self
|
|
154
|
+
#
|
|
155
|
+
# @api private
|
|
156
|
+
def clear
|
|
157
|
+
@cache.clear
|
|
158
|
+
self
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
end # module API
|
|
162
|
+
|
|
163
|
+
include API
|
|
164
|
+
|
|
165
|
+
# Tests if the given entry qualifies to be added to the cache
|
|
166
|
+
#
|
|
167
|
+
# @param [Object] entry
|
|
168
|
+
# the entry to be checked
|
|
169
|
+
#
|
|
170
|
+
# @return [true] true
|
|
171
|
+
#
|
|
172
|
+
# @api private
|
|
173
|
+
def valid?(entry)
|
|
174
|
+
true
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Given an entry, return the key to be used in the cache
|
|
178
|
+
#
|
|
179
|
+
# @param [Object] entry
|
|
180
|
+
# the entry to get the key for
|
|
181
|
+
#
|
|
182
|
+
# @return [Object]
|
|
183
|
+
# the passed in entry
|
|
184
|
+
#
|
|
185
|
+
# @api private
|
|
186
|
+
def key_for(entry)
|
|
187
|
+
entry
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
end # class Cache
|
|
191
|
+
|
|
192
|
+
include Enumerable
|
|
193
|
+
extend Equalizer
|
|
194
|
+
|
|
195
|
+
# This set's entries
|
|
196
|
+
#
|
|
197
|
+
# The order in this Array is not guaranteed
|
|
198
|
+
# to be the order in which the entries were
|
|
199
|
+
# inserted. Use #each to access the entries
|
|
200
|
+
# in insertion order.
|
|
201
|
+
#
|
|
202
|
+
# @return [Array]
|
|
203
|
+
# this set's entries
|
|
204
|
+
#
|
|
205
|
+
# @api private
|
|
206
|
+
attr_reader :entries
|
|
207
|
+
|
|
208
|
+
equalize :entries
|
|
209
|
+
|
|
210
|
+
# Initialize an OrderedSet
|
|
211
|
+
#
|
|
212
|
+
# @param [#each] entries
|
|
213
|
+
# the entries to initialize this set with
|
|
214
|
+
# @param [Class<Cache::API>] cache
|
|
215
|
+
# the cache implementation to use
|
|
216
|
+
#
|
|
217
|
+
# @api private
|
|
218
|
+
def initialize(entries = [], cache = Cache)
|
|
219
|
+
@cache = cache.new
|
|
220
|
+
@entries = []
|
|
221
|
+
merge(entries.to_ary)
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# Initialize a copy of OrderedSet
|
|
225
|
+
#
|
|
226
|
+
# @api private
|
|
227
|
+
def initialize_copy(*)
|
|
228
|
+
@cache = @cache.dup
|
|
229
|
+
@entries = @entries.dup
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Get the entry at the given index
|
|
233
|
+
#
|
|
234
|
+
# @param [Integer] index
|
|
235
|
+
# the index of the desired entry
|
|
236
|
+
#
|
|
237
|
+
# @return [Object, nil]
|
|
238
|
+
# the entry at the given index, or nil if no entry is present
|
|
239
|
+
#
|
|
240
|
+
# @api private
|
|
241
|
+
def [](index)
|
|
242
|
+
entries[index]
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# Add or update an entry in the set
|
|
246
|
+
#
|
|
247
|
+
# If the entry to add isn't part of the set already,
|
|
248
|
+
# it will be added. If an entry with the same cache
|
|
249
|
+
# key as the entry to add is part of the set already,
|
|
250
|
+
# it will be replaced with the given entry.
|
|
251
|
+
#
|
|
252
|
+
# @param [Object] entry
|
|
253
|
+
# the entry to be added
|
|
254
|
+
#
|
|
255
|
+
# @return [OrderedSet] self
|
|
256
|
+
#
|
|
257
|
+
# @api private
|
|
258
|
+
def <<(entry)
|
|
259
|
+
if index = @cache[entry]
|
|
260
|
+
entries[index] = entry
|
|
261
|
+
else
|
|
262
|
+
@cache[entry] = size
|
|
263
|
+
entries << entry
|
|
264
|
+
end
|
|
265
|
+
self
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# Merge with another Enumerable object
|
|
269
|
+
#
|
|
270
|
+
# @param [#each] other
|
|
271
|
+
# the Enumerable to merge with this OrderedSet
|
|
272
|
+
#
|
|
273
|
+
# @return [OrderedSet] self
|
|
274
|
+
#
|
|
275
|
+
# @api private
|
|
276
|
+
def merge(other)
|
|
277
|
+
other.each { |entry| self << entry }
|
|
278
|
+
self
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# Delete an entry from this OrderedSet
|
|
282
|
+
#
|
|
283
|
+
# @param [Object] entry
|
|
284
|
+
# the entry to delete
|
|
285
|
+
#
|
|
286
|
+
# @return [Object, nil]
|
|
287
|
+
# the deleted entry or nil
|
|
288
|
+
#
|
|
289
|
+
# @api private
|
|
290
|
+
def delete(entry)
|
|
291
|
+
if index = @cache.delete(entry)
|
|
292
|
+
entries.delete_at(index)
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
# Removes all entries and returns self
|
|
297
|
+
#
|
|
298
|
+
# @return [OrderedSet] self
|
|
299
|
+
#
|
|
300
|
+
# @api private
|
|
301
|
+
def clear
|
|
302
|
+
@cache.clear
|
|
303
|
+
entries.clear
|
|
304
|
+
self
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
# Iterate over each entry in the set
|
|
308
|
+
#
|
|
309
|
+
# @yield [entry]
|
|
310
|
+
# all entries in the set
|
|
311
|
+
#
|
|
312
|
+
# @yieldparam [Object] entry
|
|
313
|
+
# an entry in the set
|
|
314
|
+
#
|
|
315
|
+
# @return [OrderedSet] self
|
|
316
|
+
#
|
|
317
|
+
# @api private
|
|
318
|
+
def each
|
|
319
|
+
entries.each { |entry| yield(entry) }
|
|
320
|
+
self
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
# The number of entries
|
|
324
|
+
#
|
|
325
|
+
# @return [Integer]
|
|
326
|
+
# the number of entries
|
|
327
|
+
#
|
|
328
|
+
# @api private
|
|
329
|
+
def size
|
|
330
|
+
entries.size
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
# Check if there are any entries
|
|
334
|
+
#
|
|
335
|
+
# @return [Boolean]
|
|
336
|
+
# true if the set is empty
|
|
337
|
+
#
|
|
338
|
+
# @api private
|
|
339
|
+
def empty?
|
|
340
|
+
entries.empty?
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
# Check if the entry exists in the set
|
|
344
|
+
#
|
|
345
|
+
# @param [Object] entry
|
|
346
|
+
# the entry to test for
|
|
347
|
+
#
|
|
348
|
+
# @return [Boolean]
|
|
349
|
+
# true if entry is included in the set
|
|
350
|
+
#
|
|
351
|
+
# @api private
|
|
352
|
+
def include?(entry)
|
|
353
|
+
entries.include?(entry)
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
# Return the index for the entry in the set
|
|
357
|
+
#
|
|
358
|
+
# @param [Object] entry
|
|
359
|
+
# the entry to check the set for
|
|
360
|
+
#
|
|
361
|
+
# @return [Integer, nil]
|
|
362
|
+
# the index for the entry, or nil if it does not exist
|
|
363
|
+
#
|
|
364
|
+
# @api private
|
|
365
|
+
def index(entry)
|
|
366
|
+
@cache[entry]
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
# Convert the OrderedSet into an Array
|
|
370
|
+
#
|
|
371
|
+
# @return [Array]
|
|
372
|
+
# an array containing all the OrderedSet's entries
|
|
373
|
+
#
|
|
374
|
+
# @api private
|
|
375
|
+
def to_ary
|
|
376
|
+
entries
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
end # class OrderedSet
|
|
380
|
+
end # module DataMapper
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module DataMapper
|
|
2
|
+
module Subject
|
|
3
|
+
# Returns a default value of the subject for given resource
|
|
4
|
+
#
|
|
5
|
+
# When default value is a callable object, it is called with resource
|
|
6
|
+
# and subject passed as arguments.
|
|
7
|
+
#
|
|
8
|
+
# @param [Resource] resource
|
|
9
|
+
# the model instance for which the default is to be set
|
|
10
|
+
#
|
|
11
|
+
# @return [Object]
|
|
12
|
+
# the default value of this subject for +resource+
|
|
13
|
+
#
|
|
14
|
+
# @api semipublic
|
|
15
|
+
def default_for(resource)
|
|
16
|
+
if @default.respond_to?(:call)
|
|
17
|
+
@default.call(resource, self)
|
|
18
|
+
else
|
|
19
|
+
DataMapper::Ext.try_dup(@default)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Returns true if the subject has a default value
|
|
24
|
+
#
|
|
25
|
+
# @return [Boolean]
|
|
26
|
+
# true if the subject has a default value
|
|
27
|
+
#
|
|
28
|
+
# @api semipublic
|
|
29
|
+
def default?
|
|
30
|
+
@options.key?(:default)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
module DataMapper
|
|
2
|
+
|
|
3
|
+
# An insertion ordered set of named objects
|
|
4
|
+
#
|
|
5
|
+
# {SubjectSet} uses {DataMapper::OrderedSet}
|
|
6
|
+
# under the hood to keep track of a set of
|
|
7
|
+
# entries. In DataMapper code, a subject
|
|
8
|
+
# can be either a {DataMapper::Property}, or
|
|
9
|
+
# a {DataMapper::Associations::Relationship}.
|
|
10
|
+
#
|
|
11
|
+
# All entries added to instances of this
|
|
12
|
+
# class must respond to the {#name} method
|
|
13
|
+
#
|
|
14
|
+
# The motivation behind this is that we
|
|
15
|
+
# use this class as a base to keep track
|
|
16
|
+
# properties and relationships.
|
|
17
|
+
# The following constraints apply for these
|
|
18
|
+
# types of objects: {Property} names must be
|
|
19
|
+
# unique within any model.
|
|
20
|
+
# {Associations::Relationship} names must be
|
|
21
|
+
# unique within any model
|
|
22
|
+
#
|
|
23
|
+
# When adding an entry with a name that
|
|
24
|
+
# already exists, the already existing
|
|
25
|
+
# entry will be replaced with the new
|
|
26
|
+
# entry with the same name. This is because
|
|
27
|
+
# we want to be able to update properties,
|
|
28
|
+
# and relationship during the course of
|
|
29
|
+
# initializing our application.
|
|
30
|
+
#
|
|
31
|
+
# This also happens to be consistent with
|
|
32
|
+
# the way ruby handles redefining methods,
|
|
33
|
+
# where the last definitions "wins".
|
|
34
|
+
#
|
|
35
|
+
# Furthermore, the builtin ruby {Set#<<} method
|
|
36
|
+
# also updates the old object if a new object
|
|
37
|
+
# gets added.
|
|
38
|
+
#
|
|
39
|
+
# @api private
|
|
40
|
+
class SubjectSet
|
|
41
|
+
|
|
42
|
+
# An {OrderedSet::Cache::API} implementation that establishes
|
|
43
|
+
# set semantics based on the name of its entries. The cache
|
|
44
|
+
# uses the entries' names as cache key and refuses to add
|
|
45
|
+
# entries that don't respond_to?(:name).
|
|
46
|
+
#
|
|
47
|
+
# @see OrderedSet::Cache::API
|
|
48
|
+
#
|
|
49
|
+
# @api private
|
|
50
|
+
class NameCache
|
|
51
|
+
|
|
52
|
+
include OrderedSet::Cache::API
|
|
53
|
+
|
|
54
|
+
# Tests if the given entry qualifies to be added to the cache
|
|
55
|
+
#
|
|
56
|
+
# @param [#name] entry
|
|
57
|
+
# the entry to be checked
|
|
58
|
+
#
|
|
59
|
+
# @return [Boolean]
|
|
60
|
+
# true if the entry respond_to?(:name)
|
|
61
|
+
#
|
|
62
|
+
# @api private
|
|
63
|
+
def valid?(entry)
|
|
64
|
+
entry.respond_to?(:name)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Given an entry, return the key to be used in the cache
|
|
68
|
+
#
|
|
69
|
+
# @param [#name] entry
|
|
70
|
+
# the entry to get the key for
|
|
71
|
+
#
|
|
72
|
+
# @return [#to_s, nil]
|
|
73
|
+
# the entry's name or nil if the entry isn't #valid?
|
|
74
|
+
#
|
|
75
|
+
# @api private
|
|
76
|
+
def key_for(entry)
|
|
77
|
+
valid?(entry) ? entry.name : nil
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
end # class NameCache
|
|
81
|
+
|
|
82
|
+
include Enumerable
|
|
83
|
+
|
|
84
|
+
# The elements in the SubjectSet
|
|
85
|
+
#
|
|
86
|
+
# @return [OrderedSet]
|
|
87
|
+
#
|
|
88
|
+
# @api private
|
|
89
|
+
attr_reader :entries
|
|
90
|
+
|
|
91
|
+
# Initialize a SubjectSet
|
|
92
|
+
#
|
|
93
|
+
# @param [Enumerable<#name>] entries
|
|
94
|
+
# the entries to initialize this set with
|
|
95
|
+
#
|
|
96
|
+
# @api private
|
|
97
|
+
def initialize(entries = [])
|
|
98
|
+
@entries = OrderedSet.new(entries, NameCache)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Initialize a copy of a SubjectSet
|
|
102
|
+
#
|
|
103
|
+
# @api private
|
|
104
|
+
def initialize_copy(*)
|
|
105
|
+
@entries = @entries.dup
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Make sure that entry is part of this SubjectSet
|
|
109
|
+
#
|
|
110
|
+
# If an entry with the same name already exists, it
|
|
111
|
+
# will be updated. If no such named entry exists, it
|
|
112
|
+
# will be added.
|
|
113
|
+
#
|
|
114
|
+
# @param [#name] entry
|
|
115
|
+
# the entry to be added
|
|
116
|
+
#
|
|
117
|
+
# @return [SubjectSet] self
|
|
118
|
+
#
|
|
119
|
+
# @api private
|
|
120
|
+
def <<(entry)
|
|
121
|
+
entries << entry
|
|
122
|
+
self
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Delete an entry from this SubjectSet
|
|
126
|
+
#
|
|
127
|
+
# @param [#name] entry
|
|
128
|
+
# the entry to delete
|
|
129
|
+
#
|
|
130
|
+
# @return [#name, nil]
|
|
131
|
+
# the deleted entry or nil
|
|
132
|
+
#
|
|
133
|
+
# @api private
|
|
134
|
+
def delete(entry)
|
|
135
|
+
entries.delete(entry)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Removes all entries and returns self
|
|
139
|
+
#
|
|
140
|
+
# @return [SubjectSet] self
|
|
141
|
+
#
|
|
142
|
+
# @api private
|
|
143
|
+
def clear
|
|
144
|
+
entries.clear
|
|
145
|
+
self
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Test if the given entry is included in this SubjectSet
|
|
149
|
+
#
|
|
150
|
+
# @param [#name] entry
|
|
151
|
+
# the entry to test for
|
|
152
|
+
#
|
|
153
|
+
# @return [Boolean]
|
|
154
|
+
# true if the entry is included in this SubjectSet
|
|
155
|
+
#
|
|
156
|
+
# @api private
|
|
157
|
+
def include?(entry)
|
|
158
|
+
entries.include?(entry)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Tests wether the SubjectSet contains a entry named name
|
|
162
|
+
#
|
|
163
|
+
# @param [#to_s] name
|
|
164
|
+
# the entry name to test for
|
|
165
|
+
#
|
|
166
|
+
# @return [Boolean]
|
|
167
|
+
# true if the SubjectSet contains a entry named name
|
|
168
|
+
#
|
|
169
|
+
# @api private
|
|
170
|
+
def named?(name)
|
|
171
|
+
!self[name].nil?
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Check if there are any entries
|
|
175
|
+
#
|
|
176
|
+
# @return [Boolean]
|
|
177
|
+
# true if the set contains at least one entry
|
|
178
|
+
#
|
|
179
|
+
# @api private
|
|
180
|
+
def empty?
|
|
181
|
+
entries.empty?
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Lookup an entry in the SubjectSet based on a given name
|
|
185
|
+
#
|
|
186
|
+
# @param [#to_s] name
|
|
187
|
+
# the name of the entry
|
|
188
|
+
#
|
|
189
|
+
# @return [Object, nil]
|
|
190
|
+
# the entry having the given name, or nil if not found
|
|
191
|
+
#
|
|
192
|
+
# @api private
|
|
193
|
+
def [](name)
|
|
194
|
+
name = name.to_s
|
|
195
|
+
entries.detect { |entry| entry.name.to_s == name }
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Iterate over each entry in the set
|
|
199
|
+
#
|
|
200
|
+
# @yield [entry]
|
|
201
|
+
# each entry in the set
|
|
202
|
+
#
|
|
203
|
+
# @yieldparam [#name] entry
|
|
204
|
+
# an entry in the set
|
|
205
|
+
#
|
|
206
|
+
# @return [SubjectSet] self
|
|
207
|
+
#
|
|
208
|
+
# @api private
|
|
209
|
+
def each
|
|
210
|
+
entries.each { |entry| yield(entry) }
|
|
211
|
+
self
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# All entries (or nil values) that have any of the given names
|
|
215
|
+
#
|
|
216
|
+
# @param [Enumerable<#to_s>] names
|
|
217
|
+
# the names of the desired entries
|
|
218
|
+
#
|
|
219
|
+
# @return [Array<#name, nil>]
|
|
220
|
+
# an array containing entries whose names match any of the given
|
|
221
|
+
# names, or nil values for those names with no matching entries
|
|
222
|
+
# in the set
|
|
223
|
+
#
|
|
224
|
+
# @api private
|
|
225
|
+
def values_at(*names)
|
|
226
|
+
names.map { |name| self[name] }
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Get the number of elements inside this SubjectSet
|
|
230
|
+
#
|
|
231
|
+
# @return [Integer]
|
|
232
|
+
# the number of elements
|
|
233
|
+
#
|
|
234
|
+
# @api private
|
|
235
|
+
def size
|
|
236
|
+
entries.size
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Convert the SubjectSet into an Array
|
|
240
|
+
#
|
|
241
|
+
# @return [Array]
|
|
242
|
+
# an array containing all the SubjectSet's entries
|
|
243
|
+
#
|
|
244
|
+
# @api private
|
|
245
|
+
def to_ary
|
|
246
|
+
to_a
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
end # class SubjectSet
|
|
250
|
+
end # module DataMapper
|