sam-dm-core 0.9.6

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.
Files changed (126) hide show
  1. data/.autotest +26 -0
  2. data/CONTRIBUTING +51 -0
  3. data/FAQ +92 -0
  4. data/History.txt +145 -0
  5. data/MIT-LICENSE +22 -0
  6. data/Manifest.txt +125 -0
  7. data/QUICKLINKS +12 -0
  8. data/README.txt +143 -0
  9. data/Rakefile +30 -0
  10. data/SPECS +63 -0
  11. data/TODO +1 -0
  12. data/lib/dm-core.rb +224 -0
  13. data/lib/dm-core/adapters.rb +4 -0
  14. data/lib/dm-core/adapters/abstract_adapter.rb +202 -0
  15. data/lib/dm-core/adapters/data_objects_adapter.rb +707 -0
  16. data/lib/dm-core/adapters/mysql_adapter.rb +136 -0
  17. data/lib/dm-core/adapters/postgres_adapter.rb +188 -0
  18. data/lib/dm-core/adapters/sqlite3_adapter.rb +105 -0
  19. data/lib/dm-core/associations.rb +199 -0
  20. data/lib/dm-core/associations/many_to_many.rb +147 -0
  21. data/lib/dm-core/associations/many_to_one.rb +107 -0
  22. data/lib/dm-core/associations/one_to_many.rb +309 -0
  23. data/lib/dm-core/associations/one_to_one.rb +61 -0
  24. data/lib/dm-core/associations/relationship.rb +218 -0
  25. data/lib/dm-core/associations/relationship_chain.rb +81 -0
  26. data/lib/dm-core/auto_migrations.rb +113 -0
  27. data/lib/dm-core/collection.rb +638 -0
  28. data/lib/dm-core/dependency_queue.rb +31 -0
  29. data/lib/dm-core/hook.rb +11 -0
  30. data/lib/dm-core/identity_map.rb +45 -0
  31. data/lib/dm-core/is.rb +16 -0
  32. data/lib/dm-core/logger.rb +232 -0
  33. data/lib/dm-core/migrations/destructive_migrations.rb +17 -0
  34. data/lib/dm-core/migrator.rb +29 -0
  35. data/lib/dm-core/model.rb +471 -0
  36. data/lib/dm-core/naming_conventions.rb +84 -0
  37. data/lib/dm-core/property.rb +673 -0
  38. data/lib/dm-core/property_set.rb +162 -0
  39. data/lib/dm-core/query.rb +625 -0
  40. data/lib/dm-core/repository.rb +159 -0
  41. data/lib/dm-core/resource.rb +637 -0
  42. data/lib/dm-core/scope.rb +58 -0
  43. data/lib/dm-core/support.rb +7 -0
  44. data/lib/dm-core/support/array.rb +13 -0
  45. data/lib/dm-core/support/assertions.rb +8 -0
  46. data/lib/dm-core/support/errors.rb +23 -0
  47. data/lib/dm-core/support/kernel.rb +7 -0
  48. data/lib/dm-core/support/symbol.rb +41 -0
  49. data/lib/dm-core/transaction.rb +267 -0
  50. data/lib/dm-core/type.rb +160 -0
  51. data/lib/dm-core/type_map.rb +80 -0
  52. data/lib/dm-core/types.rb +19 -0
  53. data/lib/dm-core/types/boolean.rb +7 -0
  54. data/lib/dm-core/types/discriminator.rb +34 -0
  55. data/lib/dm-core/types/object.rb +24 -0
  56. data/lib/dm-core/types/paranoid_boolean.rb +34 -0
  57. data/lib/dm-core/types/paranoid_datetime.rb +33 -0
  58. data/lib/dm-core/types/serial.rb +9 -0
  59. data/lib/dm-core/types/text.rb +10 -0
  60. data/lib/dm-core/version.rb +3 -0
  61. data/script/all +5 -0
  62. data/script/performance.rb +203 -0
  63. data/script/profile.rb +87 -0
  64. data/spec/integration/association_spec.rb +1371 -0
  65. data/spec/integration/association_through_spec.rb +203 -0
  66. data/spec/integration/associations/many_to_many_spec.rb +449 -0
  67. data/spec/integration/associations/many_to_one_spec.rb +163 -0
  68. data/spec/integration/associations/one_to_many_spec.rb +151 -0
  69. data/spec/integration/auto_migrations_spec.rb +398 -0
  70. data/spec/integration/collection_spec.rb +1069 -0
  71. data/spec/integration/data_objects_adapter_spec.rb +32 -0
  72. data/spec/integration/dependency_queue_spec.rb +58 -0
  73. data/spec/integration/model_spec.rb +127 -0
  74. data/spec/integration/mysql_adapter_spec.rb +85 -0
  75. data/spec/integration/postgres_adapter_spec.rb +731 -0
  76. data/spec/integration/property_spec.rb +233 -0
  77. data/spec/integration/query_spec.rb +506 -0
  78. data/spec/integration/repository_spec.rb +57 -0
  79. data/spec/integration/resource_spec.rb +475 -0
  80. data/spec/integration/sqlite3_adapter_spec.rb +352 -0
  81. data/spec/integration/sti_spec.rb +208 -0
  82. data/spec/integration/strategic_eager_loading_spec.rb +138 -0
  83. data/spec/integration/transaction_spec.rb +75 -0
  84. data/spec/integration/type_spec.rb +271 -0
  85. data/spec/lib/logging_helper.rb +18 -0
  86. data/spec/lib/mock_adapter.rb +27 -0
  87. data/spec/lib/model_loader.rb +91 -0
  88. data/spec/lib/publicize_methods.rb +28 -0
  89. data/spec/models/vehicles.rb +34 -0
  90. data/spec/models/zoo.rb +47 -0
  91. data/spec/spec.opts +3 -0
  92. data/spec/spec_helper.rb +86 -0
  93. data/spec/unit/adapters/abstract_adapter_spec.rb +133 -0
  94. data/spec/unit/adapters/adapter_shared_spec.rb +15 -0
  95. data/spec/unit/adapters/data_objects_adapter_spec.rb +628 -0
  96. data/spec/unit/adapters/postgres_adapter_spec.rb +133 -0
  97. data/spec/unit/associations/many_to_many_spec.rb +17 -0
  98. data/spec/unit/associations/many_to_one_spec.rb +152 -0
  99. data/spec/unit/associations/one_to_many_spec.rb +393 -0
  100. data/spec/unit/associations/one_to_one_spec.rb +7 -0
  101. data/spec/unit/associations/relationship_spec.rb +71 -0
  102. data/spec/unit/associations_spec.rb +242 -0
  103. data/spec/unit/auto_migrations_spec.rb +111 -0
  104. data/spec/unit/collection_spec.rb +182 -0
  105. data/spec/unit/data_mapper_spec.rb +35 -0
  106. data/spec/unit/identity_map_spec.rb +126 -0
  107. data/spec/unit/is_spec.rb +80 -0
  108. data/spec/unit/migrator_spec.rb +33 -0
  109. data/spec/unit/model_spec.rb +339 -0
  110. data/spec/unit/naming_conventions_spec.rb +36 -0
  111. data/spec/unit/property_set_spec.rb +83 -0
  112. data/spec/unit/property_spec.rb +753 -0
  113. data/spec/unit/query_spec.rb +530 -0
  114. data/spec/unit/repository_spec.rb +93 -0
  115. data/spec/unit/resource_spec.rb +626 -0
  116. data/spec/unit/scope_spec.rb +142 -0
  117. data/spec/unit/transaction_spec.rb +493 -0
  118. data/spec/unit/type_map_spec.rb +114 -0
  119. data/spec/unit/type_spec.rb +119 -0
  120. data/tasks/ci.rb +68 -0
  121. data/tasks/dm.rb +63 -0
  122. data/tasks/doc.rb +20 -0
  123. data/tasks/gemspec.rb +23 -0
  124. data/tasks/hoe.rb +46 -0
  125. data/tasks/install.rb +20 -0
  126. metadata +216 -0
@@ -0,0 +1,35 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe DataMapper do
4
+ describe ".dependency_queue" do
5
+ before(:all) do
6
+ @q = DataMapper.dependency_queue
7
+ end
8
+
9
+ it "should return a dependency queue" do
10
+ @q.should be_a_kind_of(DataMapper::DependencyQueue)
11
+ end
12
+
13
+ it "should only create one dependency queue" do
14
+ @q.should == DataMapper.dependency_queue
15
+ end
16
+ end
17
+
18
+ describe ".prepare" do
19
+ it "should pass the default repository to the block if no argument is given" do
20
+ DataMapper.should_receive(:repository).with(no_args).and_return :default_repo
21
+
22
+ DataMapper.prepare do |r|
23
+ r.should == :default_repo
24
+ end
25
+ end
26
+
27
+ it "should allow custom type maps to be defined inside the prepare block" do
28
+ lambda {
29
+ DataMapper.prepare do |r|
30
+ r.map(String).to(:VARCHAR).with(:size => 1000)
31
+ end
32
+ }.should_not raise_error
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,126 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe "DataMapper::IdentityMap" do
4
+ before(:all) do
5
+ class Cow
6
+ include DataMapper::Resource
7
+ property :id, Integer, :key => true
8
+ property :name, String
9
+ end
10
+
11
+ class Chicken
12
+ include DataMapper::Resource
13
+ property :name, String
14
+ end
15
+
16
+ class Pig
17
+ include DataMapper::Resource
18
+ property :id, Integer, :key => true
19
+ property :composite, Integer, :key => true
20
+ property :name, String
21
+ end
22
+ end
23
+
24
+ it "should use a second level cache if created with on"
25
+
26
+ it "should return nil on #get when it does not find the requested instance" do
27
+ map = DataMapper::IdentityMap.new
28
+ map.get([23]).should be_nil
29
+ end
30
+
31
+ it "should return an instance on #get when it finds the requested instance" do
32
+ betsy = Cow.new({:id=>23,:name=>'Betsy'})
33
+ map = DataMapper::IdentityMap.new
34
+ map.set(betsy.key, betsy)
35
+ map.get([23]).should == betsy
36
+ end
37
+
38
+ it "should store an instance on #set" do
39
+ betsy = Cow.new({:id=>23,:name=>'Betsy'})
40
+ map = DataMapper::IdentityMap.new
41
+ map.set(betsy.key, betsy)
42
+ map.get([23]).should == betsy
43
+ end
44
+
45
+ it "should store instances with composite keys on #set" do
46
+ pig = Pig.new({:id=>1,:composite=>1,:name=> 'Pig'})
47
+ piggy = Pig.new({:id=>1,:composite=>2,:name=>'Piggy'})
48
+
49
+ map = DataMapper::IdentityMap.new
50
+ map.set(pig.key, pig)
51
+ map.set(piggy.key, piggy)
52
+
53
+ map.get([1,1]).should == pig
54
+ map.get([1,2]).should == piggy
55
+ end
56
+
57
+ it "should remove an instance on #delete" do
58
+ betsy = Cow.new({:id=>23,:name=>'Betsy'})
59
+ map = DataMapper::IdentityMap.new
60
+ map.set(betsy.key, betsy)
61
+ map.delete([23])
62
+ map.get([23]).should be_nil
63
+ end
64
+ end
65
+
66
+ describe "Second Level Caching" do
67
+
68
+ before :all do
69
+ @mock_class = Class.new do
70
+ def get(key); raise NotImplementedError end
71
+ def set(key, instance); raise NotImplementedError end
72
+ def delete(key); raise NotImplementedError end
73
+ end
74
+ end
75
+
76
+ it 'should expose a standard API' do
77
+ cache = @mock_class.new
78
+ cache.should respond_to(:get)
79
+ cache.should respond_to(:set)
80
+ cache.should respond_to(:delete)
81
+ end
82
+
83
+ it 'should provide values when the first level cache entry is empty' do
84
+ cache = @mock_class.new
85
+ key = %w[ test ]
86
+
87
+ cache.should_receive(:get).with(key).and_return('resource')
88
+
89
+ map = DataMapper::IdentityMap.new(cache)
90
+ map.get(key).should == 'resource'
91
+ end
92
+
93
+ it 'should be set when the first level cache entry is set' do
94
+ cache = @mock_class.new
95
+ betsy = Cow.new(:id => 23, :name => 'Betsy')
96
+
97
+ cache.should_receive(:set).with(betsy.key, betsy).and_return(betsy)
98
+
99
+ map = DataMapper::IdentityMap.new(cache)
100
+ map.set(betsy.key, betsy).should == betsy
101
+ end
102
+
103
+ it 'should be deleted when the first level cache entry is deleted' do
104
+ cache = @mock_class.new
105
+ betsy = Cow.new(:id => 23, :name => 'Betsy')
106
+
107
+ cache.stub!(:set)
108
+ cache.should_receive(:delete).with(betsy.key).and_return(betsy)
109
+
110
+ map = DataMapper::IdentityMap.new(cache)
111
+ map.set(betsy.key, betsy).should == betsy
112
+ map.delete(betsy.key).should == betsy
113
+ end
114
+
115
+ it 'should not provide values when the first level cache entry is full' do
116
+ cache = @mock_class.new
117
+ betsy = Cow.new(:id => 23, :name => 'Betsy')
118
+
119
+ cache.stub!(:set)
120
+ cache.should_not_receive(:get)
121
+
122
+ map = DataMapper::IdentityMap.new(cache)
123
+ map.set(betsy.key, betsy).should == betsy
124
+ map.get(betsy.key).should == betsy
125
+ end
126
+ end
@@ -0,0 +1,80 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe "DataMapper::Is" do
4
+ describe ".is" do
5
+
6
+ module DataMapper
7
+
8
+ module Is
9
+ module Example
10
+
11
+ def is_example(*args)
12
+ @args = args
13
+
14
+ extend DataMapper::Is::Example::ClassMethods
15
+ end
16
+
17
+ def is_example_args
18
+ @args
19
+ end
20
+
21
+ module ClassMethods
22
+ def example_class_method
23
+
24
+ end
25
+ end
26
+
27
+ end
28
+ end
29
+
30
+ module Model
31
+ include DataMapper::Is::Example
32
+ end # module Model
33
+ end # module DataMapper
34
+
35
+ class House
36
+ include DataMapper::Resource
37
+ end
38
+
39
+ class Cabin
40
+ include DataMapper::Resource
41
+ end
42
+
43
+ it "should raise error unless it finds the plugin" do
44
+ lambda do
45
+ class House
46
+ is :no_plugin_by_this_name
47
+ end
48
+ end.should raise_error(DataMapper::PluginNotFoundError)
49
+ end
50
+
51
+ it "should call plugin is_* method" do
52
+ lambda do
53
+ class House
54
+ is :example
55
+ end
56
+ end.should_not raise_error
57
+ end
58
+
59
+ it "should pass through arguments to plugin is_* method" do
60
+ class House
61
+ is :example ,:option1 => :ping, :option2 => :pong
62
+ end
63
+
64
+ House.is_example_args.length.should == 1
65
+ House.is_example_args.first[:option2].should == :pong
66
+ end
67
+
68
+ it "should not add class_methods before the plugin is activated" do
69
+ Cabin.respond_to?(:example_class_method).should be_false
70
+
71
+ class Cabin
72
+ is :example
73
+ end
74
+
75
+ Cabin.respond_to?(:example_class_method).should be_true
76
+
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,33 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
+
4
+ describe DataMapper::Migrator do
5
+ before(:each) do
6
+ DataMapper::Migrator.subclasses.clear
7
+ end
8
+
9
+ after(:each) do
10
+ DataMapper::Migrator.subclasses.clear
11
+ end
12
+
13
+ it "should keep track of subclasses" do
14
+ lambda { Class.new(DataMapper::Migrator) }.should change{ DataMapper::Migrator.subclasses.size }.by(1)
15
+ end
16
+
17
+ it "should define a class level 'models' method for each subclass" do
18
+ klass = Class.new(DataMapper::Migrator)
19
+
20
+ klass.should respond_to(:models)
21
+ end
22
+
23
+ it "should keep subclass models seperated" do
24
+ klass_a = Class.new(DataMapper::Migrator)
25
+ klass_b = Class.new(DataMapper::Migrator)
26
+
27
+ klass_a.models << :foo
28
+
29
+ klass_b.models.should be_empty
30
+
31
+ klass_a.models.should == [:foo]
32
+ end
33
+ end
@@ -0,0 +1,339 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe 'DataMapper::Model' do
4
+ module ModelSpec
5
+ class Resource
6
+ include DataMapper::Resource
7
+
8
+ storage_names[:legacy] = 'legacy_resource'
9
+
10
+ property :id, Serial
11
+ property :name, String
12
+ property :type, Discriminator
13
+ end
14
+ end
15
+
16
+ it 'should provide .new' do
17
+ meta_class = class << ModelSpec::Resource; self end
18
+ meta_class.should respond_to(:new)
19
+ end
20
+
21
+ describe '.new' do
22
+ it 'should require a default storage name and accept a block' do
23
+ pluto = DataMapper::Model.new('planets') do
24
+ property :name, String, :key => true
25
+ end
26
+
27
+ pluto.storage_name(:default).should == 'planets'
28
+ pluto.storage_name(:legacy).should == 'planets'
29
+ pluto.properties[:name].should_not be_nil
30
+ end
31
+ end
32
+
33
+ it 'should provide #transaction' do
34
+ ModelSpec::Resource.should respond_to(:transaction)
35
+ end
36
+
37
+ describe '#transaction' do
38
+ it 'should return a new Transaction with Model as argument' do
39
+ transaction = mock("transaction")
40
+ DataMapper::Transaction.should_receive(:new).with(ModelSpec::Resource).and_return(transaction)
41
+ ModelSpec::Resource.transaction.should == transaction
42
+ end
43
+ end
44
+
45
+ it 'should provide #before' do
46
+ ModelSpec::Resource.should respond_to(:before)
47
+ end
48
+
49
+ it 'should provide #after' do
50
+ ModelSpec::Resource.should respond_to(:after)
51
+ end
52
+
53
+ it 'should provide #repository' do
54
+ ModelSpec::Resource.should respond_to(:repository)
55
+ end
56
+
57
+ describe '#repository' do
58
+ it 'should delegate to DataMapper.repository' do
59
+ repository = mock('repository')
60
+ DataMapper.should_receive(:repository).with(:legacy).and_return(repository)
61
+ ModelSpec::Resource.repository(:legacy).should == repository
62
+ end
63
+
64
+ it 'should use default repository when not passed any arguments' do
65
+ ModelSpec::Resource.repository.name.should == ModelSpec::Resource.repository(:default).name
66
+ end
67
+ end
68
+
69
+ it 'should provide #storage_name' do
70
+ ModelSpec::Resource.should respond_to(:storage_name)
71
+ end
72
+
73
+ describe '#storage_name' do
74
+ it 'should map a repository to the storage location' do
75
+ ModelSpec::Resource.storage_name(:legacy).should == 'legacy_resource'
76
+ end
77
+
78
+ it 'should use default repository when not passed any arguments' do
79
+ ModelSpec::Resource.storage_name.object_id.should == ModelSpec::Resource.storage_name(:default).object_id
80
+ end
81
+ end
82
+
83
+ it 'should provide #storage_names' do
84
+ ModelSpec::Resource.should respond_to(:storage_names)
85
+ end
86
+
87
+ describe '#storage_names' do
88
+ it 'should return a Hash mapping each repository to a storage location' do
89
+ ModelSpec::Resource.storage_names.should be_kind_of(Hash)
90
+ ModelSpec::Resource.storage_names.should == { :default => 'model_spec_resources', :legacy => 'legacy_resource' }
91
+ end
92
+ end
93
+
94
+ it 'should provide #property' do
95
+ ModelSpec::Resource.should respond_to(:property)
96
+ end
97
+
98
+ describe '#property' do
99
+ it 'should raise a SyntaxError when the name contains invalid characters' do
100
+ lambda {
101
+ ModelSpec::Resource.property(:"with space", TrueClass)
102
+ }.should raise_error(SyntaxError)
103
+ end
104
+ end
105
+
106
+ it 'should provide #properties' do
107
+ ModelSpec::Resource.should respond_to(:properties)
108
+ end
109
+
110
+ describe '#properties' do
111
+ it 'should return an PropertySet' do
112
+ ModelSpec::Resource.properties(:legacy).should be_kind_of(DataMapper::PropertySet)
113
+ ModelSpec::Resource.properties(:legacy).should have(3).entries
114
+ end
115
+
116
+ it 'should use default repository when not passed any arguments' do
117
+ ModelSpec::Resource.properties.object_id.should == ModelSpec::Resource.properties(:default).object_id
118
+ end
119
+ end
120
+
121
+ it 'should provide #key' do
122
+ ModelSpec::Resource.should respond_to(:key)
123
+ end
124
+
125
+ describe '#key' do
126
+ it 'should return an Array of Property objects' do
127
+ ModelSpec::Resource.key(:legacy).should be_kind_of(Array)
128
+ ModelSpec::Resource.key(:legacy).should have(1).entries
129
+ ModelSpec::Resource.key(:legacy).first.should be_kind_of(DataMapper::Property)
130
+ end
131
+
132
+ it 'should use default repository when not passed any arguments' do
133
+ ModelSpec::Resource.key.should == ModelSpec::Resource.key(:default)
134
+ end
135
+
136
+ it 'should not cache the key value' do
137
+ class GasGiant < ModelSpec::Resource
138
+ end
139
+
140
+ GasGiant.key.object_id.should_not == ModelSpec::Resource.key(:default)
141
+
142
+ # change the key and make sure the Array changes
143
+ GasGiant.key == GasGiant.properties.slice(:id)
144
+ GasGiant.property(:new_prop, String, :key => true)
145
+ GasGiant.key.object_id.should_not == ModelSpec::Resource.key(:default)
146
+ GasGiant.key == GasGiant.properties.slice(:id, :new_prop)
147
+ end
148
+ end
149
+
150
+ it 'should provide #inheritance_property' do
151
+ ModelSpec::Resource.should respond_to(:inheritance_property)
152
+ end
153
+
154
+ describe '#inheritance_property' do
155
+ it 'should return a Property object' do
156
+ ModelSpec::Resource.inheritance_property(:legacy).should be_kind_of(DataMapper::Property)
157
+ ModelSpec::Resource.inheritance_property(:legacy).name.should == :type
158
+ ModelSpec::Resource.inheritance_property(:legacy).type.should == DM::Discriminator
159
+ end
160
+
161
+ it 'should use default repository when not passed any arguments' do
162
+ ModelSpec::Resource.inheritance_property.object_id.should == ModelSpec::Resource.inheritance_property(:default).object_id
163
+ end
164
+ end
165
+
166
+ it 'should provide #get' do
167
+ ModelSpec::Resource.should respond_to(:get)
168
+ end
169
+
170
+ it 'should provide #first' do
171
+ ModelSpec::Resource.should respond_to(:first)
172
+ end
173
+
174
+ it 'should provide #all' do
175
+ ModelSpec::Resource.should respond_to(:all)
176
+ end
177
+
178
+ it 'should provide #storage_exists?' do
179
+ ModelSpec::Resource.should respond_to(:storage_exists?)
180
+ end
181
+
182
+ describe '#storage_exists?' do
183
+ it 'should return whether or not the storage exists' do
184
+ ModelSpec::Resource.should_receive(:repository).with(:default) do
185
+ repository = mock('repository')
186
+ repository.should_receive(:storage_exists?).with('model_spec_resources').and_return(true)
187
+ repository
188
+ end
189
+ ModelSpec::Resource.storage_exists?.should == true
190
+ end
191
+ end
192
+
193
+ it 'should provide #default_order' do
194
+ ModelSpec::Resource.should respond_to(:default_order)
195
+ end
196
+
197
+ describe '#default_order' do
198
+ it 'should be equal to #key by default' do
199
+ ModelSpec::Resource.default_order.should == [ DataMapper::Query::Direction.new(ModelSpec::Resource.properties[:id], :asc) ]
200
+ end
201
+ end
202
+
203
+ describe '#append_inclusions' do
204
+ before(:all) do
205
+ @standard_resource_inclusions = DataMapper::Resource.instance_variable_get('@extra_inclusions')
206
+ @standard_model_extensions = DataMapper::Model.instance_variable_get('@extra_extensions')
207
+ end
208
+
209
+ before(:each) do
210
+ DataMapper::Resource.instance_variable_set('@extra_inclusions', [])
211
+ DataMapper::Model.instance_variable_set('@extra_extensions', [])
212
+
213
+ @module = Module.new do
214
+ def greet
215
+ hi_mom!
216
+ end
217
+ end
218
+
219
+ @another_module = Module.new do
220
+ def hello
221
+ hi_dad!
222
+ end
223
+ end
224
+
225
+ @class = Class.new
226
+
227
+ @class_code = %{
228
+ include DataMapper::Resource
229
+ property :id, Serial
230
+ }
231
+ end
232
+
233
+ after(:each) do
234
+ DataMapper::Resource.instance_variable_set('@extra_inclusions', @standard_resource_inclusions)
235
+ DataMapper::Model.instance_variable_set('@extra_extensions', @standard_model_extensions)
236
+ end
237
+
238
+ it "should append the module to be included in resources" do
239
+ DataMapper::Resource.append_inclusions @module
240
+ @class.class_eval(@class_code)
241
+
242
+ instance = @class.new
243
+ instance.should_receive(:hi_mom!)
244
+ instance.greet
245
+ end
246
+
247
+ it "should append the module to all resources" do
248
+ DataMapper::Resource.append_inclusions @module
249
+
250
+ objects = (1..5).map do
251
+ the_class = Class.new
252
+ the_class.class_eval(@class_code)
253
+
254
+ instance = the_class.new
255
+ instance.should_receive(:hi_mom!)
256
+ instance
257
+ end
258
+
259
+ objects.each { |obj| obj.greet }
260
+ end
261
+
262
+ it "should append multiple modules to be included in resources" do
263
+ DataMapper::Resource.append_inclusions @module, @another_module
264
+ @class.class_eval(@class_code)
265
+
266
+ instance = @class.new
267
+ instance.should_receive(:hi_mom!)
268
+ instance.should_receive(:hi_dad!)
269
+ instance.greet
270
+ instance.hello
271
+ end
272
+
273
+ it "should include the appended modules in order" do
274
+ module_one = Module.new do
275
+ def self.included(base); base.hi_mom!; end;
276
+ end
277
+
278
+ module_two = Module.new do
279
+ def self.included(base); base.hi_dad!; end;
280
+ end
281
+
282
+ DataMapper::Resource.append_inclusions module_two, module_one
283
+
284
+ @class.should_receive(:hi_dad!).once.ordered
285
+ @class.should_receive(:hi_mom!).once.ordered
286
+
287
+ @class.class_eval(@class_code)
288
+ end
289
+
290
+ it "should append the module to extend resources with" do
291
+ DataMapper::Model.append_extensions @module
292
+ @class.class_eval(@class_code)
293
+
294
+ @class.should_receive(:hi_mom!)
295
+ @class.greet
296
+ end
297
+
298
+ it "should extend all resources with the module" do
299
+ DataMapper::Model.append_extensions @module
300
+
301
+ classes = (1..5).map do
302
+ the_class = Class.new
303
+ the_class.class_eval(@class_code)
304
+ the_class.should_receive(:hi_mom!)
305
+ the_class
306
+ end
307
+
308
+ classes.each { |cla| cla.greet }
309
+ end
310
+
311
+ it "should append multiple modules to extend resources with" do
312
+ DataMapper::Model.append_extensions @module, @another_module
313
+ @class.class_eval(@class_code)
314
+
315
+ @class.should_receive(:hi_mom!)
316
+ @class.should_receive(:hi_dad!)
317
+ @class.greet
318
+ @class.hello
319
+ end
320
+
321
+ it "should extend the resource in the order that the modules were appended" do
322
+ @module.class_eval do
323
+ def self.extended(base); base.hi_mom!; end;
324
+ end
325
+
326
+ @another_module.class_eval do
327
+ def self.extended(base); base.hi_dad!; end;
328
+ end
329
+
330
+ DataMapper::Model.append_extensions @another_module, @module
331
+
332
+ @class.should_receive(:hi_dad!).once.ordered
333
+ @class.should_receive(:hi_mom!).once.ordered
334
+
335
+ @class.class_eval(@class_code)
336
+ end
337
+
338
+ end
339
+ end