sbf-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.
- checksums.yaml +7 -0
- data/.autotest +29 -0
- data/.document +5 -0
- data/.gitignore +44 -0
- data/.rspec +1 -0
- data/.rubocop.yml +468 -0
- data/.travis.yml +57 -0
- data/.yardopts +1 -0
- data/Gemfile +70 -0
- data/LICENSE +20 -0
- data/README.md +269 -0
- data/Rakefile +4 -0
- data/dm-core.gemspec +21 -0
- data/lib/dm-core/adapters/abstract_adapter.rb +233 -0
- data/lib/dm-core/adapters/in_memory_adapter.rb +110 -0
- data/lib/dm-core/adapters.rb +249 -0
- data/lib/dm-core/associations/many_to_many.rb +477 -0
- data/lib/dm-core/associations/many_to_one.rb +282 -0
- data/lib/dm-core/associations/one_to_many.rb +332 -0
- data/lib/dm-core/associations/one_to_one.rb +84 -0
- data/lib/dm-core/associations/relationship.rb +650 -0
- data/lib/dm-core/backwards.rb +11 -0
- data/lib/dm-core/collection.rb +1486 -0
- data/lib/dm-core/core_ext/kernel.rb +21 -0
- data/lib/dm-core/core_ext/pathname.rb +4 -0
- data/lib/dm-core/core_ext/symbol.rb +10 -0
- data/lib/dm-core/identity_map.rb +6 -0
- data/lib/dm-core/model/hook.rb +99 -0
- data/lib/dm-core/model/is.rb +30 -0
- data/lib/dm-core/model/property.rb +244 -0
- data/lib/dm-core/model/relationship.rb +366 -0
- data/lib/dm-core/model/scope.rb +87 -0
- data/lib/dm-core/model.rb +876 -0
- data/lib/dm-core/property/binary.rb +19 -0
- data/lib/dm-core/property/boolean.rb +35 -0
- data/lib/dm-core/property/class.rb +23 -0
- data/lib/dm-core/property/date.rb +45 -0
- data/lib/dm-core/property/date_time.rb +44 -0
- data/lib/dm-core/property/decimal.rb +47 -0
- data/lib/dm-core/property/discriminator.rb +40 -0
- data/lib/dm-core/property/float.rb +27 -0
- data/lib/dm-core/property/integer.rb +32 -0
- data/lib/dm-core/property/invalid_value_error.rb +17 -0
- data/lib/dm-core/property/lookup.rb +26 -0
- data/lib/dm-core/property/numeric.rb +35 -0
- data/lib/dm-core/property/object.rb +33 -0
- data/lib/dm-core/property/serial.rb +13 -0
- data/lib/dm-core/property/string.rb +47 -0
- data/lib/dm-core/property/text.rb +12 -0
- data/lib/dm-core/property/time.rb +46 -0
- data/lib/dm-core/property/typecast/numeric.rb +32 -0
- data/lib/dm-core/property/typecast/time.rb +33 -0
- data/lib/dm-core/property.rb +856 -0
- data/lib/dm-core/property_set.rb +177 -0
- data/lib/dm-core/query/conditions/comparison.rb +886 -0
- data/lib/dm-core/query/conditions/operation.rb +710 -0
- data/lib/dm-core/query/direction.rb +33 -0
- data/lib/dm-core/query/operator.rb +34 -0
- data/lib/dm-core/query/path.rb +113 -0
- data/lib/dm-core/query/sort.rb +38 -0
- data/lib/dm-core/query.rb +1352 -0
- data/lib/dm-core/relationship_set.rb +69 -0
- data/lib/dm-core/repository.rb +226 -0
- data/lib/dm-core/resource/persistence_state/clean.rb +36 -0
- data/lib/dm-core/resource/persistence_state/deleted.rb +26 -0
- data/lib/dm-core/resource/persistence_state/dirty.rb +91 -0
- data/lib/dm-core/resource/persistence_state/immutable.rb +32 -0
- data/lib/dm-core/resource/persistence_state/persisted.rb +25 -0
- data/lib/dm-core/resource/persistence_state/transient.rb +87 -0
- data/lib/dm-core/resource/persistence_state.rb +70 -0
- data/lib/dm-core/resource.rb +1220 -0
- data/lib/dm-core/spec/lib/adapter_helpers.rb +63 -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 +164 -0
- data/lib/dm-core/spec/shared/adapter_spec.rb +366 -0
- data/lib/dm-core/spec/shared/public/property_spec.rb +229 -0
- data/lib/dm-core/spec/shared/resource_spec.rb +1221 -0
- data/lib/dm-core/spec/shared/sel_spec.rb +111 -0
- data/lib/dm-core/spec/shared/semipublic/property_spec.rb +184 -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 +388 -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 +109 -0
- data/lib/dm-core/support/ordered_set.rb +381 -0
- data/lib/dm-core/support/subject.rb +33 -0
- data/lib/dm-core/support/subject_set.rb +251 -0
- data/lib/dm-core/version.rb +3 -0
- data/lib/dm-core.rb +274 -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 +69 -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 +77 -0
- data/spec/public/model/hook_spec.rb +245 -0
- data/spec/public/model/property_spec.rb +91 -0
- data/spec/public/model/relationship_spec.rb +1040 -0
- data/spec/public/model_spec.rb +456 -0
- data/spec/public/property/binary_spec.rb +43 -0
- data/spec/public/property/boolean_spec.rb +21 -0
- data/spec/public/property/class_spec.rb +27 -0
- data/spec/public/property/date_spec.rb +21 -0
- data/spec/public/property/date_time_spec.rb +21 -0
- data/spec/public/property/decimal_spec.rb +23 -0
- data/spec/public/property/discriminator_spec.rb +134 -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 +117 -0
- data/spec/public/property/serial_spec.rb +22 -0
- data/spec/public/property/string_spec.rb +21 -0
- data/spec/public/property/text_spec.rb +62 -0
- data/spec/public/property/time_spec.rb +21 -0
- data/spec/public/property_spec.rb +333 -0
- data/spec/public/resource/state_spec.rb +72 -0
- data/spec/public/resource_spec.rb +289 -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 +1637 -0
- data/spec/public/shared/finder_shared_spec.rb +1647 -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 +1502 -0
- data/spec/semipublic/query/conditions/operation_spec.rb +1296 -0
- data/spec/semipublic/query/path_spec.rb +471 -0
- data/spec/semipublic/query_spec.rb +3665 -0
- data/spec/semipublic/resource/state/clean_spec.rb +89 -0
- data/spec/semipublic/resource/state/deleted_spec.rb +79 -0
- data/spec/semipublic/resource/state/dirty_spec.rb +163 -0
- data/spec/semipublic/resource/state/immutable_spec.rb +107 -0
- data/spec/semipublic/resource/state/transient_spec.rb +163 -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 +198 -0
- data/spec/semipublic/shared/resource_state_shared_spec.rb +91 -0
- data/spec/semipublic/shared/subject_shared_spec.rb +79 -0
- data/spec/spec_helper.rb +34 -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 +27 -0
- data/spec/unit/hook_spec.rb +1216 -0
- data/spec/unit/inflections_spec.rb +14 -0
- data/spec/unit/lazy_array_spec.rb +1949 -0
- data/spec/unit/mash_spec.rb +289 -0
- data/spec/unit/module_spec.rb +70 -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 +18 -0
- data/tasks/yard.rake +9 -0
- data/tasks/yardstick.rake +19 -0
- metadata +323 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
shared_examples 'A Collection supporting Strategic Eager Loading' do
|
|
2
|
+
describe 'using SEL when looping within a loop' do
|
|
3
|
+
before :all do
|
|
4
|
+
@many_to_many = @articles.kind_of?(DataMapper::Associations::ManyToMany::Collection)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
before :all do
|
|
8
|
+
attributes = {}
|
|
9
|
+
|
|
10
|
+
unless @many_to_many
|
|
11
|
+
attributes[:author] = @author
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
@revision = @article.revisions.create(attributes.merge(:title => 'Revision'))
|
|
15
|
+
|
|
16
|
+
@new_article = @article_model.create(attributes.merge(:title => 'Sample Article'))
|
|
17
|
+
@new_revision = @new_article.revisions.create(attributes.merge(:title => 'New Revision'))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
before :all do
|
|
21
|
+
@original_adapter = @adapter
|
|
22
|
+
|
|
23
|
+
@adapter.singleton_class.class_eval do
|
|
24
|
+
def eql?(other)
|
|
25
|
+
super || self == other
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
@adapter = DataMapper::Repository.adapters[@adapter.name] = CounterAdapter.new(@adapter)
|
|
30
|
+
@repository.instance_variable_set(:@adapter, @adapter)
|
|
31
|
+
@articles.instance_variable_get(:@query).instance_variable_set(:@repository, @repository)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
before :all do
|
|
35
|
+
@results = []
|
|
36
|
+
|
|
37
|
+
@articles.each do |article|
|
|
38
|
+
article.revisions.each do |revision|
|
|
39
|
+
@results << [ article, revision ]
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
after :all do
|
|
45
|
+
@adapter = @original_adapter
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "only executes the Adapter#read #{loaded ? 'once' : 'twice'}" do
|
|
49
|
+
expect(@adapter.counts[:read]).to eq (loaded ? 1 : 2)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'returns the expected results' do
|
|
53
|
+
# if the collection is already loaded, then when it iterates it will
|
|
54
|
+
# not know about the newly added articles and their revisions
|
|
55
|
+
if loaded
|
|
56
|
+
expect(@results).to eq [[@article, @revision]]
|
|
57
|
+
else
|
|
58
|
+
pending 'TODO: make m:m not kick when delegating to the relationship' if @many_to_many
|
|
59
|
+
|
|
60
|
+
expect(@results).to eq [[@article, @revision], [@new_article, @new_revision]]
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
shared_examples 'A Resource supporting Strategic Eager Loading' do
|
|
67
|
+
describe 'using SEL when inside a Collection' do
|
|
68
|
+
before :all do
|
|
69
|
+
@referrer = @user_model.create(:name => 'Referrer', :comment => @comment)
|
|
70
|
+
|
|
71
|
+
@user.update(:referrer => @referrer)
|
|
72
|
+
|
|
73
|
+
@new_user = @user_model.create(:name => 'Another User', :referrer => @referrer, :comment => @comment)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
before :all do
|
|
77
|
+
@original_adapter = @adapter
|
|
78
|
+
|
|
79
|
+
@adapter.singleton_class.class_eval do
|
|
80
|
+
def eql?(other)
|
|
81
|
+
super || other == self
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
@adapter = DataMapper::Repository.adapters[@adapter.name] = CounterAdapter.new(@adapter)
|
|
86
|
+
@repository.instance_variable_set(:@adapter, @adapter)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
before :all do
|
|
90
|
+
@results = @user_model.all.map do |user|
|
|
91
|
+
[ user, user.referrer ]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# some storage engines return the data in a different order
|
|
95
|
+
@results.sort!
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
after :all do
|
|
99
|
+
@adapter = @original_adapter
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it 'only executes the Adapter#read twice' do
|
|
103
|
+
expect(@adapter.counts[:read]).to eq 2
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it 'returns the expected results' do
|
|
107
|
+
# results are ordered alphabetically by the User name
|
|
108
|
+
expect(@results).to eq [[@new_user, @referrer], [@referrer, nil], [@user, @referrer]]
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
shared_examples 'A semipublic Property' do
|
|
2
|
+
before :all do
|
|
3
|
+
%w(@type @name @value @other_value).each do |ivar|
|
|
4
|
+
raise "+#{ivar}+ should be defined in before block" unless instance_variable_defined?(ivar)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
module ::Blog
|
|
8
|
+
class Article
|
|
9
|
+
include DataMapper::Resource
|
|
10
|
+
property :id, Serial
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
@model = Blog::Article
|
|
15
|
+
@options ||= {}
|
|
16
|
+
@property = @type.new(@model, @name, @options)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe '.new' do
|
|
20
|
+
describe 'when provided no options' do
|
|
21
|
+
it 'returns a Property' do
|
|
22
|
+
expect(@property).to be_kind_of(@type)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'sets the load_as' do
|
|
26
|
+
expect(@property.load_as).to be(@type.load_as)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'sets the model' do
|
|
30
|
+
expect(@property.model).to equal(@model)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'sets the options to the default' do
|
|
34
|
+
expect(@property.options).to eq @type.options.merge(@options)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
%i(index unique_index unique lazy).each do |attribute|
|
|
39
|
+
[true, false, :title, [:title]].each do |value|
|
|
40
|
+
describe "when provided #{(options = {attribute => value}).inspect}" do
|
|
41
|
+
before :all do
|
|
42
|
+
@property = @type.new(@model, @name, @options.merge(options))
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'returns a Property' do
|
|
46
|
+
expect(@property).to be_kind_of(@type)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'sets the model' do
|
|
50
|
+
expect(@property.model).to equal(@model)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'sets the load_as' do
|
|
54
|
+
expect(@property.load_as).to be(@type.load_as)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "sets the options to #{options.inspect}" do
|
|
58
|
+
expect(@property.options).to eq @type.options.merge(@options.merge(options))
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
[[], nil].each do |value|
|
|
64
|
+
describe "when provided #{(invalid_options = {attribute => value}).inspect}" do
|
|
65
|
+
it 'raises an exception' do
|
|
66
|
+
expect {
|
|
67
|
+
@type.new(@model, @name, @options.merge(invalid_options))
|
|
68
|
+
}.to raise_error(ArgumentError, "options[#{attribute.inspect}] must be either true, false, a Symbol or an Array of Symbols")
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
describe '#load' do
|
|
76
|
+
subject { @property.load(@value) }
|
|
77
|
+
|
|
78
|
+
before do
|
|
79
|
+
expect(@property).to receive(:typecast).with(@value).and_return(@value)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it { is_expected.to eql(@value) }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
describe '#typecast' do
|
|
86
|
+
describe "when is able to do typecasting on it's own" do
|
|
87
|
+
it 'delegates all the work to the type' do
|
|
88
|
+
return_value = double(@other_value)
|
|
89
|
+
expect(@property).to receive(:typecast_to_primitive).with(@invalid_value).and_return(return_value)
|
|
90
|
+
@property.typecast(@invalid_value)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
describe 'when value is nil' do
|
|
95
|
+
it 'returns value unchanged' do
|
|
96
|
+
expect(@property.typecast(nil)).to be(nil)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
describe 'when value is a Ruby primitive' do
|
|
100
|
+
it 'returns value unchanged' do
|
|
101
|
+
expect(@property.typecast(@value)).to eq @value
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
describe '#valid?' do
|
|
108
|
+
describe 'when provided a valid value' do
|
|
109
|
+
it 'returns true' do
|
|
110
|
+
expect(@property.valid?(@value)).to be(true)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
describe 'when provide an invalid value' do
|
|
115
|
+
it 'returns false' do
|
|
116
|
+
expect(@property.valid?(@invalid_value)).to be(false)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
describe 'when provide a nil value when required' do
|
|
121
|
+
it 'returns false' do
|
|
122
|
+
@property = @type.new(@model, @name, @options.merge(required: true))
|
|
123
|
+
expect(@property.valid?(nil)).to be(false)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
describe 'when provide a nil value when not required' do
|
|
128
|
+
it 'returns false' do
|
|
129
|
+
@property = @type.new(@model, @name, @options.merge(required: false))
|
|
130
|
+
expect(@property.valid?(nil)).to be(true)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
describe '#assert_valid_value' do
|
|
136
|
+
subject do
|
|
137
|
+
@property.assert_valid_value(value)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
shared_examples 'assert_valid_value on invalid value' do
|
|
141
|
+
it 'raises DataMapper::Property::InvalidValueError' do
|
|
142
|
+
expect { subject }.to(raise_error(DataMapper::Property::InvalidValueError) do |error|
|
|
143
|
+
expect(error.property).to eq @property
|
|
144
|
+
end)
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
describe 'when provided a valid value' do
|
|
149
|
+
let(:value) { @value }
|
|
150
|
+
|
|
151
|
+
it 'returns true' do
|
|
152
|
+
expect(subject).to be(true)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
describe 'when provide an invalid value' do
|
|
157
|
+
let(:value) { @invalid_value }
|
|
158
|
+
|
|
159
|
+
it_behaves_like 'assert_valid_value on invalid value'
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
describe 'when provide a nil value when required' do
|
|
163
|
+
before do
|
|
164
|
+
@property = @type.new(@model, @name, @options.merge(required: true))
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
let(:value) { nil }
|
|
168
|
+
|
|
169
|
+
it_behaves_like 'assert_valid_value on invalid value'
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
describe 'when provide a nil value when not required' do
|
|
173
|
+
before do
|
|
174
|
+
@property = @type.new(@model, @name, @options.merge(required: false))
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
let(:value) { nil }
|
|
178
|
+
|
|
179
|
+
it 'returns true' do
|
|
180
|
+
expect(subject).to be(true)
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
shared_examples 'DataMapper::Query::Conditions::AbstractComparison' do
|
|
2
|
+
before :all do
|
|
3
|
+
module ::Blog
|
|
4
|
+
class Article
|
|
5
|
+
include DataMapper::Resource
|
|
6
|
+
|
|
7
|
+
property :id, Serial
|
|
8
|
+
property :title, String, :required => true
|
|
9
|
+
|
|
10
|
+
belongs_to :parent, self, :required => false
|
|
11
|
+
has n, :children, self, :inverse => :parent
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
DataMapper.finalize
|
|
16
|
+
|
|
17
|
+
@model = Blog::Article
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
before do
|
|
21
|
+
class ::OtherComparison < DataMapper::Query::Conditions::AbstractComparison
|
|
22
|
+
slug :other
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
before do
|
|
27
|
+
@relationship = @model.relationships[:parent]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it { expect(subject.class).to respond_to(:new) }
|
|
31
|
+
|
|
32
|
+
describe '.new' do
|
|
33
|
+
subject { @comparison.class.new(@property, @value) }
|
|
34
|
+
|
|
35
|
+
it { is_expected.to be_kind_of(@comparison.class) }
|
|
36
|
+
|
|
37
|
+
it { expect(subject.subject).to equal(@property) }
|
|
38
|
+
|
|
39
|
+
it { expect(subject.value).to eq @value }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it { expect(subject.class).to respond_to(:slug) }
|
|
43
|
+
|
|
44
|
+
describe '.slug' do
|
|
45
|
+
describe 'with no arguments' do
|
|
46
|
+
subject { @comparison.class.slug }
|
|
47
|
+
|
|
48
|
+
it { is_expected.to eq @slug }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
describe 'with an argument' do
|
|
52
|
+
subject { @comparison.class.slug(:other) }
|
|
53
|
+
|
|
54
|
+
it { is_expected.to eq :other }
|
|
55
|
+
|
|
56
|
+
# reset the slug
|
|
57
|
+
after { @comparison.class.slug(@slug) }
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it { is_expected.to respond_to(:==) }
|
|
62
|
+
|
|
63
|
+
describe '#==' do
|
|
64
|
+
describe 'when the other AbstractComparison is equal' do
|
|
65
|
+
# artificially modify the object so #== will throw an
|
|
66
|
+
# exception if the equal? branch is not followed when heckling
|
|
67
|
+
before { @comparison.singleton_class.send(:undef_method, :slug) }
|
|
68
|
+
|
|
69
|
+
subject { @comparison == @comparison }
|
|
70
|
+
|
|
71
|
+
it { is_expected.to be(true) }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
describe 'when the other AbstractComparison is the same class' do
|
|
75
|
+
subject { @comparison == DataMapper::Query::Conditions::Comparison.new(@slug, @property, @value) }
|
|
76
|
+
|
|
77
|
+
it { is_expected.to be(true) }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
describe 'when the other AbstractComparison is a different class' do
|
|
81
|
+
subject { @comparison == DataMapper::Query::Conditions::Comparison.new(:other, @property, @value) }
|
|
82
|
+
|
|
83
|
+
it { is_expected.to be(false) }
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
describe 'when the other AbstractComparison is the same class, with different property' do
|
|
87
|
+
subject { @comparison == DataMapper::Query::Conditions::Comparison.new(@slug, @other_property, @value) }
|
|
88
|
+
|
|
89
|
+
it { is_expected.to be(false) }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
describe 'when the other AbstractComparison is the same class, with different value' do
|
|
93
|
+
subject { @comparison == DataMapper::Query::Conditions::Comparison.new(@slug, @property, @other_value) }
|
|
94
|
+
|
|
95
|
+
it { is_expected.to be(false) }
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it { is_expected.to respond_to(:eql?) }
|
|
100
|
+
|
|
101
|
+
describe '#eql?' do
|
|
102
|
+
describe 'when the other AbstractComparison is equal' do
|
|
103
|
+
# artificially modify the object so #eql? will throw an
|
|
104
|
+
# exception if the equal? branch is not followed when heckling
|
|
105
|
+
before { @comparison.singleton_class.send(:undef_method, :slug) }
|
|
106
|
+
|
|
107
|
+
subject { @comparison.eql?(@comparison) }
|
|
108
|
+
|
|
109
|
+
it { is_expected.to be(true) }
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
describe 'when the other AbstractComparison is the same class' do
|
|
113
|
+
subject { @comparison.eql?(DataMapper::Query::Conditions::Comparison.new(@slug, @property, @value)) }
|
|
114
|
+
|
|
115
|
+
it { is_expected.to be(true) }
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
describe 'when the other AbstractComparison is a different class' do
|
|
119
|
+
subject { @comparison.eql?(DataMapper::Query::Conditions::Comparison.new(:other, @property, @value)) }
|
|
120
|
+
|
|
121
|
+
it { is_expected.to be(false) }
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
describe 'when the other AbstractComparison is the same class, with different property' do
|
|
125
|
+
subject { @comparison.eql?(DataMapper::Query::Conditions::Comparison.new(@slug, @other_property, @value)) }
|
|
126
|
+
|
|
127
|
+
it { is_expected.to be(false) }
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
describe 'when the other AbstractComparison is the same class, with different value' do
|
|
131
|
+
subject { @comparison.eql?(DataMapper::Query::Conditions::Comparison.new(@slug, @property, @other_value)) }
|
|
132
|
+
|
|
133
|
+
it { is_expected.to be(false) }
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it { is_expected.to respond_to(:hash) }
|
|
138
|
+
|
|
139
|
+
describe '#hash' do
|
|
140
|
+
subject { @comparison.hash }
|
|
141
|
+
|
|
142
|
+
it 'matches the same AbstractComparison with the same property and value' do
|
|
143
|
+
is_expected.to eq DataMapper::Query::Conditions::Comparison.new(@slug, @property, @value).hash
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
it 'does not match the same AbstractComparison with different property' do
|
|
147
|
+
is_expected.not_to eq DataMapper::Query::Conditions::Comparison.new(@slug, @other_property, @value).hash
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
it 'does not match the same AbstractComparison with different value' do
|
|
151
|
+
is_expected.not_to eq DataMapper::Query::Conditions::Comparison.new(@slug, @property, @other_value).hash
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
it 'does not match a different AbstractComparison with the same property and value' do
|
|
155
|
+
is_expected.not_to eq @other.hash
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
it 'does not match a different AbstractComparison with different property' do
|
|
159
|
+
is_expected.not_to eq @other.class.new(@other_property, @value).hash
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
it 'does not match a different AbstractComparison with different value' do
|
|
163
|
+
is_expected.not_to eq @other.class.new(@property, @other_value).hash
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it { is_expected.to respond_to(:loaded_value) }
|
|
168
|
+
|
|
169
|
+
describe '#loaded_value' do
|
|
170
|
+
subject { @comparison.loaded_value }
|
|
171
|
+
|
|
172
|
+
it { is_expected.to eq @value }
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
it { is_expected.to respond_to(:parent) }
|
|
176
|
+
|
|
177
|
+
describe '#parent' do
|
|
178
|
+
subject { @comparison.parent }
|
|
179
|
+
|
|
180
|
+
describe 'is nil by default' do
|
|
181
|
+
it { is_expected.to be_nil }
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
describe 'relates to parent operation' do
|
|
185
|
+
before do
|
|
186
|
+
@operation = DataMapper::Query::Conditions::Operation.new(:and)
|
|
187
|
+
@comparison.parent = @operation
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
it { is_expected.to be_equal(@operation) }
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
it { is_expected.to respond_to(:parent=) }
|
|
195
|
+
|
|
196
|
+
describe '#parent=' do
|
|
197
|
+
before do
|
|
198
|
+
@operation = DataMapper::Query::Conditions::Operation.new(:and)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
subject { @comparison.parent = @operation }
|
|
202
|
+
|
|
203
|
+
it { is_expected.to equal(@operation) }
|
|
204
|
+
|
|
205
|
+
it 'changes the parent' do
|
|
206
|
+
expect(method(:subject)).to change(@comparison, :parent)
|
|
207
|
+
.from(nil)
|
|
208
|
+
.to(@operation)
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
it { is_expected.to respond_to(:property?) }
|
|
213
|
+
|
|
214
|
+
describe '#property?' do
|
|
215
|
+
subject { @comparison.property? }
|
|
216
|
+
|
|
217
|
+
it { is_expected.to be(true) }
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
it { is_expected.to respond_to(:slug) }
|
|
221
|
+
|
|
222
|
+
describe '#slug' do
|
|
223
|
+
subject { @comparison.slug }
|
|
224
|
+
|
|
225
|
+
it { is_expected.to eq @slug }
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
it { is_expected.to respond_to(:subject) }
|
|
229
|
+
|
|
230
|
+
describe '#subject' do
|
|
231
|
+
subject { @comparison.subject }
|
|
232
|
+
|
|
233
|
+
it { is_expected.to be_equal(@property) }
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
it { is_expected.to respond_to(:valid?) }
|
|
237
|
+
|
|
238
|
+
describe '#valid?' do
|
|
239
|
+
subject { @comparison.valid? }
|
|
240
|
+
|
|
241
|
+
describe 'when the value is valid for the subject' do
|
|
242
|
+
it { is_expected.to be(true) }
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
describe 'when the value is not valid for the subject' do
|
|
246
|
+
before do
|
|
247
|
+
@comparison = DataMapper::Query::Conditions::Comparison.new(@slug, @property, nil)
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
it { is_expected.to be(false) }
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
it { is_expected.to respond_to(:value) }
|
|
255
|
+
|
|
256
|
+
describe '#value' do
|
|
257
|
+
subject { @comparison.value }
|
|
258
|
+
|
|
259
|
+
it { is_expected.to eq @value }
|
|
260
|
+
end
|
|
261
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
module DataMapper
|
|
2
|
+
module Assertions
|
|
3
|
+
def assert_kind_of(name, value, *klasses)
|
|
4
|
+
klasses.each { |k| return if value.kind_of?(k) }
|
|
5
|
+
raise ArgumentError, "+#{name}+ should be #{klasses.map { |k| k.name } * ' or '}, but was #{value.class.name}", caller(2)
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module DataMapper
|
|
2
|
+
module Chainable
|
|
3
|
+
|
|
4
|
+
# @api private
|
|
5
|
+
def chainable(&block)
|
|
6
|
+
mod = Module.new(&block)
|
|
7
|
+
include mod
|
|
8
|
+
mod
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# @api private
|
|
12
|
+
def extendable(&block)
|
|
13
|
+
mod = Module.new(&block)
|
|
14
|
+
extend mod
|
|
15
|
+
mod
|
|
16
|
+
end
|
|
17
|
+
end # module Chainable
|
|
18
|
+
end # module DataMapper
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module DataMapper
|
|
2
|
+
module Deprecate
|
|
3
|
+
def deprecate(old_method, new_method)
|
|
4
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
5
|
+
def #{old_method}(*args, &block)
|
|
6
|
+
warn "\#{self.class}##{old_method} is deprecated, use \#{self.class}##{new_method} instead (\#{caller.first})"
|
|
7
|
+
send(#{new_method.inspect}, *args, &block)
|
|
8
|
+
end
|
|
9
|
+
RUBY
|
|
10
|
+
end
|
|
11
|
+
end # module Deprecate
|
|
12
|
+
end # module DataMapper
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
module DataMapper
|
|
2
|
+
class DescendantSet
|
|
3
|
+
include Enumerable
|
|
4
|
+
|
|
5
|
+
# Initialize a DescendantSet instance
|
|
6
|
+
#
|
|
7
|
+
# @param [#to_ary] descendants
|
|
8
|
+
# initialize with the descendants
|
|
9
|
+
#
|
|
10
|
+
# @api private
|
|
11
|
+
def initialize(descendants = [])
|
|
12
|
+
@descendants = SubjectSet.new(descendants)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Copy a DescendantSet instance
|
|
16
|
+
#
|
|
17
|
+
# @param [DescendantSet] original
|
|
18
|
+
# the original descendants
|
|
19
|
+
#
|
|
20
|
+
# @api private
|
|
21
|
+
def initialize_copy(original)
|
|
22
|
+
@descendants = @descendants.dup
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Add a descendant
|
|
26
|
+
#
|
|
27
|
+
# @param [Module] descendant
|
|
28
|
+
#
|
|
29
|
+
# @return [DescendantSet]
|
|
30
|
+
# self
|
|
31
|
+
#
|
|
32
|
+
# @api private
|
|
33
|
+
def <<(descendant)
|
|
34
|
+
@descendants << descendant
|
|
35
|
+
self
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Remove a descendant
|
|
39
|
+
#
|
|
40
|
+
# Also removes from all descendants
|
|
41
|
+
#
|
|
42
|
+
# @param [Module] descendant
|
|
43
|
+
#
|
|
44
|
+
# @return [DescendantSet]
|
|
45
|
+
# self
|
|
46
|
+
#
|
|
47
|
+
# @api private
|
|
48
|
+
def delete(descendant)
|
|
49
|
+
@descendants.delete(descendant)
|
|
50
|
+
each { |d| d.descendants.delete(descendant) }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Iterate over each descendant
|
|
54
|
+
#
|
|
55
|
+
# @yield [descendant]
|
|
56
|
+
# @yieldparam [Module] descendant
|
|
57
|
+
#
|
|
58
|
+
# @return [DescendantSet]
|
|
59
|
+
# self
|
|
60
|
+
#
|
|
61
|
+
# @api private
|
|
62
|
+
def each
|
|
63
|
+
@descendants.each do |descendant|
|
|
64
|
+
yield descendant
|
|
65
|
+
descendant.descendants.each { |dd| yield dd }
|
|
66
|
+
end
|
|
67
|
+
self
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Test if there are any descendants
|
|
71
|
+
#
|
|
72
|
+
# @return [Boolean]
|
|
73
|
+
#
|
|
74
|
+
# @api private
|
|
75
|
+
def empty?
|
|
76
|
+
@descendants.empty?
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Removes all entries and returns self
|
|
80
|
+
#
|
|
81
|
+
# @return [DescendantSet] self
|
|
82
|
+
#
|
|
83
|
+
# @api private
|
|
84
|
+
def clear
|
|
85
|
+
@descendants.clear
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
end # class DescendantSet
|
|
89
|
+
end # module DataMapper
|