sam-dm-core 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
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