datamapper-dm-core 0.9.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. data/.autotest +26 -0
  2. data/.gitignore +18 -0
  3. data/CONTRIBUTING +51 -0
  4. data/FAQ +92 -0
  5. data/History.txt +41 -0
  6. data/MIT-LICENSE +22 -0
  7. data/Manifest.txt +130 -0
  8. data/QUICKLINKS +11 -0
  9. data/README.txt +143 -0
  10. data/Rakefile +30 -0
  11. data/SPECS +62 -0
  12. data/TODO +1 -0
  13. data/dm-core.gemspec +40 -0
  14. data/lib/dm-core.rb +217 -0
  15. data/lib/dm-core/adapters.rb +16 -0
  16. data/lib/dm-core/adapters/abstract_adapter.rb +209 -0
  17. data/lib/dm-core/adapters/data_objects_adapter.rb +716 -0
  18. data/lib/dm-core/adapters/in_memory_adapter.rb +87 -0
  19. data/lib/dm-core/adapters/mysql_adapter.rb +136 -0
  20. data/lib/dm-core/adapters/postgres_adapter.rb +189 -0
  21. data/lib/dm-core/adapters/sqlite3_adapter.rb +105 -0
  22. data/lib/dm-core/associations.rb +207 -0
  23. data/lib/dm-core/associations/many_to_many.rb +147 -0
  24. data/lib/dm-core/associations/many_to_one.rb +107 -0
  25. data/lib/dm-core/associations/one_to_many.rb +315 -0
  26. data/lib/dm-core/associations/one_to_one.rb +61 -0
  27. data/lib/dm-core/associations/relationship.rb +229 -0
  28. data/lib/dm-core/associations/relationship_chain.rb +81 -0
  29. data/lib/dm-core/auto_migrations.rb +105 -0
  30. data/lib/dm-core/collection.rb +670 -0
  31. data/lib/dm-core/dependency_queue.rb +32 -0
  32. data/lib/dm-core/hook.rb +11 -0
  33. data/lib/dm-core/identity_map.rb +42 -0
  34. data/lib/dm-core/is.rb +16 -0
  35. data/lib/dm-core/logger.rb +232 -0
  36. data/lib/dm-core/migrations/destructive_migrations.rb +17 -0
  37. data/lib/dm-core/migrator.rb +29 -0
  38. data/lib/dm-core/model.rb +526 -0
  39. data/lib/dm-core/naming_conventions.rb +84 -0
  40. data/lib/dm-core/property.rb +676 -0
  41. data/lib/dm-core/property_set.rb +169 -0
  42. data/lib/dm-core/query.rb +676 -0
  43. data/lib/dm-core/repository.rb +167 -0
  44. data/lib/dm-core/resource.rb +671 -0
  45. data/lib/dm-core/scope.rb +58 -0
  46. data/lib/dm-core/support.rb +7 -0
  47. data/lib/dm-core/support/array.rb +13 -0
  48. data/lib/dm-core/support/assertions.rb +8 -0
  49. data/lib/dm-core/support/errors.rb +23 -0
  50. data/lib/dm-core/support/kernel.rb +11 -0
  51. data/lib/dm-core/support/symbol.rb +41 -0
  52. data/lib/dm-core/transaction.rb +267 -0
  53. data/lib/dm-core/type.rb +160 -0
  54. data/lib/dm-core/type_map.rb +80 -0
  55. data/lib/dm-core/types.rb +19 -0
  56. data/lib/dm-core/types/boolean.rb +7 -0
  57. data/lib/dm-core/types/discriminator.rb +34 -0
  58. data/lib/dm-core/types/object.rb +24 -0
  59. data/lib/dm-core/types/paranoid_boolean.rb +34 -0
  60. data/lib/dm-core/types/paranoid_datetime.rb +33 -0
  61. data/lib/dm-core/types/serial.rb +9 -0
  62. data/lib/dm-core/types/text.rb +10 -0
  63. data/lib/dm-core/version.rb +3 -0
  64. data/script/all +4 -0
  65. data/script/performance.rb +282 -0
  66. data/script/profile.rb +87 -0
  67. data/spec/integration/association_spec.rb +1382 -0
  68. data/spec/integration/association_through_spec.rb +203 -0
  69. data/spec/integration/associations/many_to_many_spec.rb +449 -0
  70. data/spec/integration/associations/many_to_one_spec.rb +163 -0
  71. data/spec/integration/associations/one_to_many_spec.rb +188 -0
  72. data/spec/integration/auto_migrations_spec.rb +413 -0
  73. data/spec/integration/collection_spec.rb +1073 -0
  74. data/spec/integration/data_objects_adapter_spec.rb +32 -0
  75. data/spec/integration/dependency_queue_spec.rb +46 -0
  76. data/spec/integration/model_spec.rb +197 -0
  77. data/spec/integration/mysql_adapter_spec.rb +85 -0
  78. data/spec/integration/postgres_adapter_spec.rb +731 -0
  79. data/spec/integration/property_spec.rb +253 -0
  80. data/spec/integration/query_spec.rb +514 -0
  81. data/spec/integration/repository_spec.rb +61 -0
  82. data/spec/integration/resource_spec.rb +513 -0
  83. data/spec/integration/sqlite3_adapter_spec.rb +352 -0
  84. data/spec/integration/sti_spec.rb +273 -0
  85. data/spec/integration/strategic_eager_loading_spec.rb +156 -0
  86. data/spec/integration/transaction_spec.rb +75 -0
  87. data/spec/integration/type_spec.rb +275 -0
  88. data/spec/lib/logging_helper.rb +18 -0
  89. data/spec/lib/mock_adapter.rb +27 -0
  90. data/spec/lib/model_loader.rb +100 -0
  91. data/spec/lib/publicize_methods.rb +28 -0
  92. data/spec/models/content.rb +16 -0
  93. data/spec/models/vehicles.rb +34 -0
  94. data/spec/models/zoo.rb +48 -0
  95. data/spec/spec.opts +3 -0
  96. data/spec/spec_helper.rb +91 -0
  97. data/spec/unit/adapters/abstract_adapter_spec.rb +133 -0
  98. data/spec/unit/adapters/adapter_shared_spec.rb +15 -0
  99. data/spec/unit/adapters/data_objects_adapter_spec.rb +632 -0
  100. data/spec/unit/adapters/in_memory_adapter_spec.rb +98 -0
  101. data/spec/unit/adapters/postgres_adapter_spec.rb +133 -0
  102. data/spec/unit/associations/many_to_many_spec.rb +32 -0
  103. data/spec/unit/associations/many_to_one_spec.rb +159 -0
  104. data/spec/unit/associations/one_to_many_spec.rb +393 -0
  105. data/spec/unit/associations/one_to_one_spec.rb +7 -0
  106. data/spec/unit/associations/relationship_spec.rb +71 -0
  107. data/spec/unit/associations_spec.rb +242 -0
  108. data/spec/unit/auto_migrations_spec.rb +111 -0
  109. data/spec/unit/collection_spec.rb +182 -0
  110. data/spec/unit/data_mapper_spec.rb +35 -0
  111. data/spec/unit/identity_map_spec.rb +126 -0
  112. data/spec/unit/is_spec.rb +80 -0
  113. data/spec/unit/migrator_spec.rb +33 -0
  114. data/spec/unit/model_spec.rb +321 -0
  115. data/spec/unit/naming_conventions_spec.rb +36 -0
  116. data/spec/unit/property_set_spec.rb +90 -0
  117. data/spec/unit/property_spec.rb +753 -0
  118. data/spec/unit/query_spec.rb +571 -0
  119. data/spec/unit/repository_spec.rb +93 -0
  120. data/spec/unit/resource_spec.rb +649 -0
  121. data/spec/unit/scope_spec.rb +142 -0
  122. data/spec/unit/transaction_spec.rb +493 -0
  123. data/spec/unit/type_map_spec.rb +114 -0
  124. data/spec/unit/type_spec.rb +119 -0
  125. data/tasks/ci.rb +36 -0
  126. data/tasks/dm.rb +63 -0
  127. data/tasks/doc.rb +20 -0
  128. data/tasks/gemspec.rb +23 -0
  129. data/tasks/hoe.rb +46 -0
  130. data/tasks/install.rb +20 -0
  131. metadata +215 -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,321 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe 'DataMapper::Model' do
4
+ before do
5
+ Object.send(:remove_const, :ModelSpec) if defined?(ModelSpec)
6
+ module ModelSpec
7
+ class Resource
8
+ include DataMapper::Resource
9
+
10
+ storage_names[:legacy] = 'legacy_resource'
11
+
12
+ property :id, Serial
13
+ property :name, String
14
+ property :type, Discriminator
15
+ end
16
+ end
17
+ end
18
+
19
+ it 'should provide .new' do
20
+ meta_class = class << ModelSpec::Resource; self end
21
+ meta_class.should respond_to(:new)
22
+ end
23
+
24
+ describe '.new' do
25
+ it 'should require a default storage name and accept a block' do
26
+ pluto = DataMapper::Model.new('planets') do
27
+ property :name, String, :key => true
28
+ end
29
+
30
+ pluto.storage_name(:default).should == 'planets'
31
+ pluto.storage_name(:legacy).should == 'planets'
32
+ pluto.properties[:name].should_not be_nil
33
+ end
34
+ end
35
+
36
+ it 'should provide #transaction' do
37
+ ModelSpec::Resource.should respond_to(:transaction)
38
+ end
39
+
40
+ describe '#transaction' do
41
+ it 'should return a new Transaction with Model as argument' do
42
+ transaction = mock("transaction")
43
+ DataMapper::Transaction.should_receive(:new).with(ModelSpec::Resource).and_return(transaction)
44
+ ModelSpec::Resource.transaction.should == transaction
45
+ end
46
+ end
47
+
48
+ it 'should provide #before' do
49
+ ModelSpec::Resource.should respond_to(:before)
50
+ end
51
+
52
+ it 'should provide #after' do
53
+ ModelSpec::Resource.should respond_to(:after)
54
+ end
55
+
56
+ it 'should provide #repository' do
57
+ ModelSpec::Resource.should respond_to(:repository)
58
+ end
59
+
60
+ describe '#repository' do
61
+ it 'should delegate to DataMapper.repository' do
62
+ repository = mock('repository')
63
+ DataMapper.should_receive(:repository).with(:legacy).and_return(repository)
64
+ ModelSpec::Resource.repository(:legacy).should == repository
65
+ end
66
+
67
+ it 'should use default repository when not passed any arguments' do
68
+ ModelSpec::Resource.repository.name.should == ModelSpec::Resource.repository(:default).name
69
+ end
70
+ end
71
+
72
+ it 'should provide #storage_name' do
73
+ ModelSpec::Resource.should respond_to(:storage_name)
74
+ end
75
+
76
+ describe '#storage_name' do
77
+ it 'should map a repository to the storage location' do
78
+ ModelSpec::Resource.storage_name(:legacy).should == 'legacy_resource'
79
+ end
80
+
81
+ it 'should use default repository when not passed any arguments' do
82
+ ModelSpec::Resource.storage_name.object_id.should == ModelSpec::Resource.storage_name(:default).object_id
83
+ end
84
+ end
85
+
86
+ it 'should provide #storage_names' do
87
+ ModelSpec::Resource.should respond_to(:storage_names)
88
+ end
89
+
90
+ describe '#storage_names' do
91
+ it 'should return a Hash mapping each repository to a storage location' do
92
+ ModelSpec::Resource.storage_names.should be_kind_of(Hash)
93
+ ModelSpec::Resource.storage_names.should == { :legacy => 'legacy_resource' }
94
+ end
95
+ end
96
+
97
+ it 'should provide #property' do
98
+ ModelSpec::Resource.should respond_to(:property)
99
+ end
100
+
101
+ describe '#property' do
102
+ it 'should raise a SyntaxError when the name contains invalid characters' do
103
+ lambda {
104
+ ModelSpec::Resource.property(:"with space", TrueClass)
105
+ }.should raise_error(SyntaxError)
106
+ end
107
+ end
108
+
109
+ it 'should provide #properties' do
110
+ ModelSpec::Resource.should respond_to(:properties)
111
+ end
112
+
113
+ describe '#properties' do
114
+ it 'should return an PropertySet' do
115
+ ModelSpec::Resource.properties(:legacy).should be_kind_of(DataMapper::PropertySet)
116
+ ModelSpec::Resource.properties(:legacy).should have(3).entries
117
+ end
118
+
119
+ it 'should use default repository when not passed any arguments' do
120
+ ModelSpec::Resource.properties.object_id.should == ModelSpec::Resource.properties(:default).object_id
121
+ end
122
+ end
123
+
124
+ it 'should provide #key' do
125
+ ModelSpec::Resource.should respond_to(:key)
126
+ end
127
+
128
+ describe '#key' do
129
+ it 'should return an Array of Property objects' do
130
+ ModelSpec::Resource.key(:legacy).should be_kind_of(Array)
131
+ ModelSpec::Resource.key(:legacy).should have(1).entries
132
+ ModelSpec::Resource.key(:legacy).first.should be_kind_of(DataMapper::Property)
133
+ end
134
+
135
+ it 'should use default repository when not passed any arguments' do
136
+ ModelSpec::Resource.key.should == ModelSpec::Resource.key(:default)
137
+ end
138
+
139
+ it 'should not cache the key value' do
140
+ class GasGiant < ModelSpec::Resource
141
+ end
142
+
143
+ GasGiant.key.object_id.should_not == ModelSpec::Resource.key(:default)
144
+
145
+ # change the key and make sure the Array changes
146
+ GasGiant.key == GasGiant.properties.slice(:id)
147
+ GasGiant.property(:new_prop, String, :key => true)
148
+ GasGiant.key.object_id.should_not == ModelSpec::Resource.key(:default)
149
+ GasGiant.key == GasGiant.properties.slice(:id, :new_prop)
150
+ end
151
+ end
152
+
153
+ it 'should provide #get' do
154
+ ModelSpec::Resource.should respond_to(:get)
155
+ end
156
+
157
+ it 'should provide #first' do
158
+ ModelSpec::Resource.should respond_to(:first)
159
+ end
160
+
161
+ it 'should provide #all' do
162
+ ModelSpec::Resource.should respond_to(:all)
163
+ end
164
+
165
+ it 'should provide #storage_exists?' do
166
+ ModelSpec::Resource.should respond_to(:storage_exists?)
167
+ end
168
+
169
+ describe '#storage_exists?' do
170
+ it 'should return whether or not the storage exists' do
171
+ ModelSpec::Resource.storage_exists?.should == false
172
+ end
173
+ end
174
+
175
+ it 'should provide #default_order' do
176
+ ModelSpec::Resource.should respond_to(:default_order)
177
+ end
178
+
179
+ describe '#default_order' do
180
+ it 'should be equal to #key by default' do
181
+ ModelSpec::Resource.default_order.should == [ DataMapper::Query::Direction.new(ModelSpec::Resource.properties[:id], :asc) ]
182
+ end
183
+ end
184
+
185
+ describe '#append_inclusions' do
186
+ before(:all) do
187
+ @standard_resource_inclusions = DataMapper::Resource.instance_variable_get('@extra_inclusions')
188
+ @standard_model_extensions = DataMapper::Model.instance_variable_get('@extra_extensions')
189
+ end
190
+
191
+ before(:each) do
192
+ DataMapper::Resource.instance_variable_set('@extra_inclusions', [])
193
+ DataMapper::Model.instance_variable_set('@extra_extensions', [])
194
+
195
+ @module = Module.new do
196
+ def greet
197
+ hi_mom!
198
+ end
199
+ end
200
+
201
+ @another_module = Module.new do
202
+ def hello
203
+ hi_dad!
204
+ end
205
+ end
206
+
207
+ @class = Class.new
208
+
209
+ @class_code = %{
210
+ include DataMapper::Resource
211
+ property :id, Serial
212
+ }
213
+ end
214
+
215
+ after(:each) do
216
+ DataMapper::Resource.instance_variable_set('@extra_inclusions', @standard_resource_inclusions)
217
+ DataMapper::Model.instance_variable_set('@extra_extensions', @standard_model_extensions)
218
+ end
219
+
220
+ it "should append the module to be included in resources" do
221
+ DataMapper::Resource.append_inclusions @module
222
+ @class.class_eval(@class_code)
223
+
224
+ instance = @class.new
225
+ instance.should_receive(:hi_mom!)
226
+ instance.greet
227
+ end
228
+
229
+ it "should append the module to all resources" do
230
+ DataMapper::Resource.append_inclusions @module
231
+
232
+ objects = (1..5).map do
233
+ the_class = Class.new
234
+ the_class.class_eval(@class_code)
235
+
236
+ instance = the_class.new
237
+ instance.should_receive(:hi_mom!)
238
+ instance
239
+ end
240
+
241
+ objects.each { |obj| obj.greet }
242
+ end
243
+
244
+ it "should append multiple modules to be included in resources" do
245
+ DataMapper::Resource.append_inclusions @module, @another_module
246
+ @class.class_eval(@class_code)
247
+
248
+ instance = @class.new
249
+ instance.should_receive(:hi_mom!)
250
+ instance.should_receive(:hi_dad!)
251
+ instance.greet
252
+ instance.hello
253
+ end
254
+
255
+ it "should include the appended modules in order" do
256
+ module_one = Module.new do
257
+ def self.included(base); base.hi_mom!; end;
258
+ end
259
+
260
+ module_two = Module.new do
261
+ def self.included(base); base.hi_dad!; end;
262
+ end
263
+
264
+ DataMapper::Resource.append_inclusions module_two, module_one
265
+
266
+ @class.should_receive(:hi_dad!).once.ordered
267
+ @class.should_receive(:hi_mom!).once.ordered
268
+
269
+ @class.class_eval(@class_code)
270
+ end
271
+
272
+ it "should append the module to extend resources with" do
273
+ DataMapper::Model.append_extensions @module
274
+ @class.class_eval(@class_code)
275
+
276
+ @class.should_receive(:hi_mom!)
277
+ @class.greet
278
+ end
279
+
280
+ it "should extend all resources with the module" do
281
+ DataMapper::Model.append_extensions @module
282
+
283
+ classes = (1..5).map do
284
+ the_class = Class.new
285
+ the_class.class_eval(@class_code)
286
+ the_class.should_receive(:hi_mom!)
287
+ the_class
288
+ end
289
+
290
+ classes.each { |cla| cla.greet }
291
+ end
292
+
293
+ it "should append multiple modules to extend resources with" do
294
+ DataMapper::Model.append_extensions @module, @another_module
295
+ @class.class_eval(@class_code)
296
+
297
+ @class.should_receive(:hi_mom!)
298
+ @class.should_receive(:hi_dad!)
299
+ @class.greet
300
+ @class.hello
301
+ end
302
+
303
+ it "should extend the resource in the order that the modules were appended" do
304
+ @module.class_eval do
305
+ def self.extended(base); base.hi_mom!; end;
306
+ end
307
+
308
+ @another_module.class_eval do
309
+ def self.extended(base); base.hi_dad!; end;
310
+ end
311
+
312
+ DataMapper::Model.append_extensions @another_module, @module
313
+
314
+ @class.should_receive(:hi_dad!).once.ordered
315
+ @class.should_receive(:hi_mom!).once.ordered
316
+
317
+ @class.class_eval(@class_code)
318
+ end
319
+
320
+ end
321
+ end