dm-core 0.10.1 → 0.10.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. data/.autotest +29 -0
  2. data/.document +5 -0
  3. data/.gitignore +27 -0
  4. data/LICENSE +20 -0
  5. data/{README.txt → README.rdoc} +14 -3
  6. data/Rakefile +23 -22
  7. data/VERSION +1 -0
  8. data/dm-core.gemspec +201 -10
  9. data/lib/dm-core.rb +32 -23
  10. data/lib/dm-core/adapters.rb +0 -1
  11. data/lib/dm-core/adapters/data_objects_adapter.rb +230 -151
  12. data/lib/dm-core/adapters/mysql_adapter.rb +7 -8
  13. data/lib/dm-core/adapters/oracle_adapter.rb +39 -59
  14. data/lib/dm-core/adapters/postgres_adapter.rb +0 -1
  15. data/lib/dm-core/adapters/sqlite3_adapter.rb +5 -0
  16. data/lib/dm-core/adapters/sqlserver_adapter.rb +114 -0
  17. data/lib/dm-core/adapters/yaml_adapter.rb +0 -5
  18. data/lib/dm-core/associations/many_to_many.rb +118 -56
  19. data/lib/dm-core/associations/many_to_one.rb +48 -21
  20. data/lib/dm-core/associations/one_to_many.rb +8 -30
  21. data/lib/dm-core/associations/one_to_one.rb +1 -5
  22. data/lib/dm-core/associations/relationship.rb +89 -97
  23. data/lib/dm-core/collection.rb +299 -184
  24. data/lib/dm-core/core_ext/enumerable.rb +28 -0
  25. data/lib/dm-core/core_ext/kernel.rb +0 -2
  26. data/lib/dm-core/migrations.rb +314 -170
  27. data/lib/dm-core/model.rb +97 -66
  28. data/lib/dm-core/model/descendant_set.rb +1 -1
  29. data/lib/dm-core/model/hook.rb +0 -3
  30. data/lib/dm-core/model/property.rb +7 -10
  31. data/lib/dm-core/model/relationship.rb +79 -26
  32. data/lib/dm-core/model/scope.rb +3 -4
  33. data/lib/dm-core/property.rb +152 -90
  34. data/lib/dm-core/property_set.rb +18 -37
  35. data/lib/dm-core/query.rb +452 -153
  36. data/lib/dm-core/query/conditions/comparison.rb +266 -173
  37. data/lib/dm-core/query/conditions/operation.rb +499 -57
  38. data/lib/dm-core/query/direction.rb +0 -3
  39. data/lib/dm-core/query/operator.rb +0 -4
  40. data/lib/dm-core/query/path.rb +10 -12
  41. data/lib/dm-core/query/sort.rb +4 -10
  42. data/lib/dm-core/repository.rb +10 -6
  43. data/lib/dm-core/resource.rb +343 -148
  44. data/lib/dm-core/spec/adapter_shared_spec.rb +17 -1
  45. data/lib/dm-core/spec/data_objects_adapter_shared_spec.rb +277 -17
  46. data/lib/dm-core/support/chainable.rb +0 -2
  47. data/lib/dm-core/support/equalizer.rb +27 -3
  48. data/lib/dm-core/transaction.rb +75 -75
  49. data/lib/dm-core/type.rb +19 -5
  50. data/lib/dm-core/types/discriminator.rb +4 -4
  51. data/lib/dm-core/types/object.rb +2 -7
  52. data/lib/dm-core/types/paranoid_boolean.rb +8 -2
  53. data/lib/dm-core/types/paranoid_datetime.rb +8 -2
  54. data/lib/dm-core/version.rb +1 -1
  55. data/script/performance.rb +7 -7
  56. data/script/profile.rb +6 -6
  57. data/spec/lib/collection_helpers.rb +2 -2
  58. data/spec/lib/pending_helpers.rb +22 -3
  59. data/spec/lib/rspec_immediate_feedback_formatter.rb +1 -0
  60. data/spec/public/associations/many_to_many_spec.rb +6 -4
  61. data/spec/public/associations/many_to_one_spec.rb +10 -1
  62. data/spec/public/associations/many_to_one_with_boolean_cpk_spec.rb +39 -0
  63. data/spec/public/associations/one_to_many_spec.rb +4 -3
  64. data/spec/public/associations/one_to_one_spec.rb +19 -1
  65. data/spec/public/associations/one_to_one_with_boolean_cpk_spec.rb +45 -0
  66. data/spec/public/collection_spec.rb +4 -3
  67. data/spec/public/migrations_spec.rb +144 -0
  68. data/spec/public/model/relationship_spec.rb +115 -55
  69. data/spec/public/model_spec.rb +13 -13
  70. data/spec/public/property/object_spec.rb +106 -0
  71. data/spec/public/property_spec.rb +18 -14
  72. data/spec/public/resource_spec.rb +10 -1
  73. data/spec/public/sel_spec.rb +16 -49
  74. data/spec/public/setup_spec.rb +1 -1
  75. data/spec/public/shared/association_collection_shared_spec.rb +6 -14
  76. data/spec/public/shared/collection_finder_shared_spec.rb +267 -0
  77. data/spec/public/shared/collection_shared_spec.rb +214 -217
  78. data/spec/public/shared/finder_shared_spec.rb +259 -365
  79. data/spec/public/shared/resource_shared_spec.rb +524 -248
  80. data/spec/public/transaction_spec.rb +27 -3
  81. data/spec/public/types/discriminator_spec.rb +1 -1
  82. data/spec/rcov.opts +6 -0
  83. data/spec/semipublic/adapters/sqlserver_adapter_spec.rb +17 -0
  84. data/spec/semipublic/associations/many_to_one_spec.rb +3 -20
  85. data/spec/semipublic/associations_spec.rb +2 -2
  86. data/spec/semipublic/collection_spec.rb +0 -32
  87. data/spec/semipublic/model_spec.rb +96 -0
  88. data/spec/semipublic/property_spec.rb +3 -3
  89. data/spec/semipublic/query/conditions/comparison_spec.rb +1719 -0
  90. data/spec/semipublic/query/conditions/operation_spec.rb +1292 -0
  91. data/spec/semipublic/query_spec.rb +1285 -144
  92. data/spec/semipublic/resource_spec.rb +0 -24
  93. data/spec/semipublic/shared/resource_shared_spec.rb +103 -38
  94. data/spec/spec.opts +1 -1
  95. data/spec/spec_helper.rb +15 -6
  96. data/tasks/ci.rake +1 -0
  97. data/tasks/metrics.rake +37 -0
  98. data/tasks/spec.rake +41 -0
  99. data/tasks/yard.rake +9 -0
  100. data/tasks/yardstick.rake +19 -0
  101. metadata +99 -29
  102. data/CONTRIBUTING +0 -51
  103. data/FAQ +0 -93
  104. data/History.txt +0 -27
  105. data/MIT-LICENSE +0 -22
  106. data/Manifest.txt +0 -121
  107. data/QUICKLINKS +0 -11
  108. data/SPECS +0 -35
  109. data/TODO +0 -1
  110. data/spec/semipublic/query/conditions_spec.rb +0 -528
  111. data/tasks/ci.rb +0 -24
  112. data/tasks/dm.rb +0 -58
  113. data/tasks/doc.rb +0 -17
  114. data/tasks/gemspec.rb +0 -23
  115. data/tasks/hoe.rb +0 -45
  116. data/tasks/install.rb +0 -18
@@ -7,13 +7,13 @@ describe DataMapper::Model do
7
7
  class Article
8
8
  include DataMapper::Resource
9
9
 
10
- property :id, Serial
11
- property :title, String, :nullable => false
12
- property :content, Text
10
+ property :id, Serial
11
+ property :title, String, :required => true
12
+ property :content, Text, :writer => :private, :default => lambda { |resource, property| resource.title }
13
13
  property :subtitle, String
14
- property :author, String, :nullable => false
14
+ property :author, String, :required => true
15
15
 
16
- belongs_to :original, self, :nullable => true
16
+ belongs_to :original, self, :required => false
17
17
  has n, :revisions, self, :child_key => [ :original_id ]
18
18
  has 1, :previous, self, :child_key => [ :original_id ], :order => [ :id.desc ]
19
19
  end
@@ -26,9 +26,9 @@ describe DataMapper::Model do
26
26
  before :all do
27
27
  @author = 'Dan Kubb'
28
28
 
29
- @original = @article_model.create(:title => 'Original Article', :author => @author)
30
- @article = @article_model.create(:title => 'Sample Article', :content => 'Sample', :original => @original, :author => @author)
31
- @other = @article_model.create(:title => 'Other Article', :content => 'Other', :author => @author)
29
+ @original = @article_model.create(:title => 'Original Article', :author => @author)
30
+ @article = @article_model.create(:title => 'Sample Article', :original => @original, :author => @author)
31
+ @other = @article_model.create(:title => 'Other Article', :author => @author)
32
32
  end
33
33
 
34
34
  it { @article_model.should respond_to(:copy) }
@@ -40,8 +40,8 @@ describe DataMapper::Model do
40
40
  @return = @resources = @article_model.copy(@repository.name, @alternate_adapter.name)
41
41
  end
42
42
 
43
- it 'should return an Enumerable' do
44
- @return.should be_a_kind_of(Enumerable)
43
+ it 'should return a Collection' do
44
+ @return.should be_a_kind_of(DataMapper::Collection)
45
45
  end
46
46
 
47
47
  it 'should return Resources' do
@@ -84,8 +84,8 @@ describe DataMapper::Model do
84
84
  @return = @resources = @article_model.copy(@alternate_adapter.name, :default)
85
85
  end
86
86
 
87
- it 'should return an Enumerable' do
88
- @return.should be_a_kind_of(Enumerable)
87
+ it 'should return a Collection' do
88
+ @return.should be_a_kind_of(DataMapper::Collection)
89
89
  end
90
90
 
91
91
  it 'should return Resources' do
@@ -120,7 +120,7 @@ describe DataMapper::Model do
120
120
  property :content, Text
121
121
  property :subtitle, String
122
122
 
123
- belongs_to :original, self, :nullable => true
123
+ belongs_to :original, self, :required => false
124
124
  has n, :revisions, self, :child_key => [ :original_id ]
125
125
  has 1, :previous, self, :child_key => [ :original_id ], :order => [ :id.desc ]
126
126
  has n, :publications, :through => Resource
@@ -0,0 +1,106 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
2
+
3
+ describe DataMapper::Property, 'Object type' do
4
+ before :all do
5
+ module ::Blog
6
+ class Article
7
+ include DataMapper::Resource
8
+
9
+ property :id, Serial
10
+ property :title, String
11
+ property :meta, Object, :required => true
12
+ end
13
+ end
14
+
15
+ @model = Blog::Article
16
+ @property = @model.properties[:meta]
17
+ end
18
+
19
+ subject { @property }
20
+
21
+ it { should respond_to(:typecast) }
22
+
23
+ describe '#typecast' do
24
+ before do
25
+ @value = { 'lang' => 'en_CA' }
26
+ end
27
+
28
+ subject { @property.typecast(@value) }
29
+
30
+ it { should equal(@value) }
31
+ end
32
+
33
+ it { should respond_to(:value) }
34
+
35
+ describe '#value' do
36
+ describe 'with a value' do
37
+ before do
38
+ @value = { 'lang' => 'en_CA' }
39
+ end
40
+
41
+ subject { @property.value(@value) }
42
+
43
+ it { @property.type.load(subject, @property).should == @value }
44
+ end
45
+
46
+ describe 'with nil' do
47
+ subject { @property.value(nil) }
48
+
49
+ it { should be_nil }
50
+ end
51
+ end
52
+
53
+ it { should respond_to(:valid?) }
54
+
55
+ describe '#valid?' do
56
+ describe 'with a valid primitive' do
57
+ subject { @property.valid?('lang' => 'en_CA') }
58
+
59
+ it { should be_true }
60
+ end
61
+
62
+ describe 'with nil and property is not required' do
63
+ before do
64
+ @property = @model.property(:meta, Object, :required => false)
65
+ end
66
+
67
+ subject { @property.valid?(nil) }
68
+
69
+ it { should be_true }
70
+ end
71
+
72
+ describe 'with nil and property is required' do
73
+ subject { @property.valid?(nil) }
74
+
75
+ it { should be_false }
76
+ end
77
+
78
+ describe 'with nil and property is required, but validity is negated' do
79
+ subject { @property.valid?(nil, true) }
80
+
81
+ it { should be_true }
82
+ end
83
+ end
84
+
85
+ describe 'persistable' do
86
+ supported_by :all do
87
+ before :all do
88
+ @do_adapter = defined?(DataMapper::Adapters::DataObjectsAdapter) && @adapter.kind_of?(DataMapper::Adapters::DataObjectsAdapter)
89
+ end
90
+
91
+ before :all do
92
+ @resource = @model.create(:title => 'Test', :meta => { 'lang' => 'en_CA' })
93
+ end
94
+
95
+ subject { @resource.reload.meta }
96
+
97
+ it 'should load the correct value' do
98
+ pending_if 'Fix adapters to use different serialization methods', !@do_adapter do
99
+ pending_if 'Fix DO adapter to send String for Text primitive', !!(RUBY_PLATFORM =~ /java/) do
100
+ should == { 'lang' => 'en_CA' }
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -20,7 +20,7 @@ describe DataMapper::Property do
20
20
  include DataMapper::Resource
21
21
 
22
22
  property :md5hash, String, :key => true, :length => 32
23
- property :title, String, :nullable => false, :unique => true
23
+ property :title, String, :required => true, :unique => true
24
24
  property :description, Text, :length => 1..1024, :lazy => [ :detail ]
25
25
  property :format, String, :default => 'jpeg'
26
26
  property :taken_at, Time, :default => proc { Time.now }
@@ -255,13 +255,13 @@ describe DataMapper::Property do
255
255
  end
256
256
  end
257
257
 
258
- describe '#nullable?' do
258
+ describe '#allow_nil?' do
259
259
  it 'returns true when property can accept nil as its value' do
260
- Track.properties[:artist].nullable?.should be_true
260
+ Track.properties[:artist].allow_nil?.should be_true
261
261
  end
262
262
 
263
263
  it 'returns false when property nil value is prohibited for this property' do
264
- Image.properties[:title].nullable?.should be_false
264
+ Image.properties[:title].allow_nil?.should be_false
265
265
  end
266
266
  end
267
267
 
@@ -282,16 +282,18 @@ describe DataMapper::Property do
282
282
  # (since original value is set, property is no longer dirty)
283
283
  describe '#set_original_value' do
284
284
  before :all do
285
- @image = Image.create(:md5hash => '5268f0f3f452844c79843e820f998869',
286
- :title => 'Rome at the sunset',
287
- :description => 'Just wow')
288
- @image.reload
285
+ @image = Image.create(
286
+ :md5hash => '5268f0f3f452844c79843e820f998869',
287
+ :title => 'Rome at the sunset',
288
+ :description => 'Just wow'
289
+ )
290
+
289
291
  @property = Image.properties[:title]
290
292
  end
291
293
 
292
294
  describe 'when value changes' do
293
295
  before :all do
294
- @property.set_original_value(@image, 'Rome at the sunset')
296
+ @property.set_original_value(@image, 'New title')
295
297
  end
296
298
 
297
299
  it 'sets original value of the property' do
@@ -306,7 +308,7 @@ describe DataMapper::Property do
306
308
 
307
309
  it 'only sets original value when it has changed' do
308
310
  @property.set_original_value(@image, 'Rome at the sunset')
309
- @image.original_attributes[@property].should be_blank
311
+ @image.original_attributes.should_not have_key(@property)
310
312
  end
311
313
  end
312
314
  end
@@ -315,10 +317,12 @@ describe DataMapper::Property do
315
317
  before :all do
316
318
  # keep in mind we must run these examples with a
317
319
  # saved model instance
318
- @image = Image.create(:md5hash => '5268f0f3f452844c79843e820f998869',
319
- :title => 'Rome at the sunset',
320
- :description => 'Just wow')
321
- @image.reload
320
+ @image = Image.create(
321
+ :md5hash => '5268f0f3f452844c79843e820f998869',
322
+ :title => 'Rome at the sunset',
323
+ :description => 'Just wow'
324
+ )
325
+
322
326
  @property = Image.properties[:title]
323
327
  end
324
328
 
@@ -12,7 +12,10 @@ describe DataMapper::Resource do
12
12
  property :description, Text
13
13
  property :admin, Boolean, :accessor => :private
14
14
 
15
- belongs_to :referrer, self, :nullable => true
15
+ belongs_to :parent, self, :required => false
16
+ has n, :children, self, :inverse => :parent
17
+
18
+ belongs_to :referrer, self, :required => false
16
19
  has n, :comments
17
20
 
18
21
  # FIXME: figure out a different approach than stubbing things out
@@ -51,6 +54,12 @@ describe DataMapper::Resource do
51
54
  end
52
55
  end
53
56
 
57
+ class ::Default
58
+ include DataMapper::Resource
59
+
60
+ property :name, String, :key => true, :default => 'a default value'
61
+ end
62
+
54
63
  @user_model = Blog::User
55
64
  @author_model = Blog::Author
56
65
  @comment_model = Blog::Comment
@@ -1,48 +1,5 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
2
 
3
- describe 'SEL', 'with different key types' do
4
- before :all do
5
- module ::Blog
6
- class Author
7
- include DataMapper::Resource
8
-
9
- property :id, Serial
10
- property :name, String
11
-
12
- has n, :articles
13
- end
14
-
15
- class Article
16
- include DataMapper::Resource
17
-
18
- property :id, Serial
19
- property :title, String, :nullable => false
20
-
21
- property :author_id, String # different type
22
-
23
- belongs_to :author
24
- end
25
- end
26
-
27
- @author_model = Blog::Author
28
- @article_model = Blog::Article
29
- end
30
-
31
- supported_by :all do
32
- before :all do
33
- @author1 = @author_model.create(:name => 'Dan Kubb')
34
- @author2 = @author_model.create(:name => 'Carl Porth')
35
-
36
- @article1 = @author1.articles.create(:title => 'Sample Article')
37
- @article2 = @author2.articles.create(:title => 'Other Article')
38
- end
39
-
40
- it 'should return expected results' do
41
- @article_model.all.map { |article| article.author }.should == [ @author1, @author2 ]
42
- end
43
- end
44
- end
45
-
46
3
  describe 'SEL', 'with STI subclasses' do
47
4
  before :all do
48
5
  module ::Blog
@@ -60,7 +17,7 @@ describe 'SEL', 'with STI subclasses' do
60
17
 
61
18
  property :id, Serial
62
19
  property :type, Discriminator
63
- property :title, String, :nullable => false
20
+ property :title, String, :required => true
64
21
 
65
22
  belongs_to :author
66
23
  end
@@ -77,12 +34,22 @@ describe 'SEL', 'with STI subclasses' do
77
34
 
78
35
  supported_by :all do
79
36
  before :all do
80
- author1 = @author_model.create(:name => 'Dan Kubb')
81
- author2 = @author_model.create(:name => 'Sindre Aarsaether')
37
+ @skip = defined?(DataMapper::Adapters::YamlAdapter) && @adapter.kind_of?(DataMapper::Adapters::YamlAdapter)
38
+ end
39
+
40
+ before :all do
41
+ rescue_if 'TODO: fix YAML serialization/deserialization', @skip do
42
+ author1 = @author_model.create(:name => 'Dan Kubb')
43
+ author2 = @author_model.create(:name => 'Sindre Aarsaether')
44
+
45
+ @article_model.create(:title => 'SEL', :author => author1)
46
+ @article_model.create(:title => 'STI', :author => author1)
47
+ @comment_model.create(:title => 'SEL and STI error', :author => author2)
48
+ end
49
+ end
82
50
 
83
- @article_model.create(:title => 'SEL', :author => author1)
84
- @article_model.create(:title => 'STI', :author => author1)
85
- @comment_model.create(:title => 'SEL and STI error', :author => author2)
51
+ before do
52
+ pending if @skip
86
53
  end
87
54
 
88
55
  it 'should allow STI loading of mixed relationships' do
@@ -114,7 +114,7 @@ describe DataMapper do
114
114
  end
115
115
  end
116
116
 
117
- supported_by :postgres, :mysql, :sqlite3 do
117
+ supported_by :postgres, :mysql, :sqlite3, :sqlserver do
118
118
  { :path => :database, :user => :username }.each do |original_key, new_key|
119
119
  describe "using #{new_key.inspect} option" do
120
120
  before :all do
@@ -22,10 +22,6 @@ share_examples_for 'It can transfer a Resource from another association' do
22
22
  pending if @skip
23
23
  end
24
24
 
25
- it 'should relate the Resource to the Collection' do
26
- @resource.collection.should equal(@articles)
27
- end
28
-
29
25
  it 'should remove the Resource from the original Collection' do
30
26
  pending do
31
27
  @original.should_not be_include(@resource)
@@ -64,7 +60,7 @@ share_examples_for 'A public Association Collection' do
64
60
  @original = @other_articles
65
61
  @resource = @original.first
66
62
 
67
- rescue_if 'TODO', @skip do
63
+ rescue_if @skip do
68
64
  @return = @articles << @resource
69
65
  end
70
66
  end
@@ -107,7 +103,7 @@ share_examples_for 'A public Association Collection' do
107
103
  @original = @other_articles
108
104
  @resource = @original.first
109
105
 
110
- rescue_if 'TODO', @skip do
106
+ rescue_if @skip do
111
107
  @return = @articles.concat([ @resource ])
112
108
  end
113
109
  end
@@ -163,7 +159,7 @@ share_examples_for 'A public Association Collection' do
163
159
  @original = @other_articles
164
160
  @resource = @original.first
165
161
 
166
- rescue_if 'TODO', @skip do
162
+ rescue_if @skip do
167
163
  @return = @articles.insert(0, @resource)
168
164
  end
169
165
  end
@@ -226,7 +222,7 @@ share_examples_for 'A public Association Collection' do
226
222
  @original = @other_articles
227
223
  @resource = @original.first
228
224
 
229
- rescue_if 'TODO', @skip do
225
+ rescue_if @skip do
230
226
  @return = @articles.push(@resource)
231
227
  end
232
228
  end
@@ -249,7 +245,7 @@ share_examples_for 'A public Association Collection' do
249
245
  @original = @other_articles
250
246
  @resource = @original.first
251
247
 
252
- rescue_if 'TODO', @skip do
248
+ rescue_if @skip do
253
249
  @return = @articles.replace([ @resource ])
254
250
  end
255
251
  end
@@ -262,10 +258,6 @@ share_examples_for 'A public Association Collection' do
262
258
  @return.should equal(@articles)
263
259
  end
264
260
 
265
- it 'should relate the Resource to the Collection' do
266
- @resource.collection.should equal(@articles)
267
- end
268
-
269
261
  it_should_behave_like 'It can transfer a Resource from another association'
270
262
  end
271
263
  end
@@ -276,7 +268,7 @@ share_examples_for 'A public Association Collection' do
276
268
  @original = @other_articles
277
269
  @resource = @original.first
278
270
 
279
- rescue_if 'TODO', @skip do
271
+ rescue_if @skip do
280
272
  @return = @articles.unshift(@resource)
281
273
  end
282
274
  end
@@ -0,0 +1,267 @@
1
+ share_examples_for 'Collection Finder Interface' do
2
+ before :all do
3
+ %w[ @article_model @article @other @articles ].each do |ivar|
4
+ raise "+#{ivar}+ should be defined in before block" unless instance_variable_defined?(ivar)
5
+ raise "+#{ivar}+ should not be nil in before block" unless instance_variable_get(ivar)
6
+ end
7
+ end
8
+
9
+ before :all do
10
+ @no_join = defined?(DataMapper::Adapters::InMemoryAdapter) && @adapter.kind_of?(DataMapper::Adapters::InMemoryAdapter) ||
11
+ defined?(DataMapper::Adapters::YamlAdapter) && @adapter.kind_of?(DataMapper::Adapters::YamlAdapter)
12
+
13
+ @many_to_many = @articles.kind_of?(DataMapper::Associations::ManyToMany::Collection)
14
+
15
+ @skip = @no_join && @many_to_many
16
+ end
17
+
18
+ before do
19
+ pending if @skip
20
+ end
21
+
22
+ describe '#at' do
23
+ before :all do
24
+ @copy = @articles.dup
25
+ @copy.to_a
26
+ end
27
+
28
+ describe 'with positive offset', 'after prepending to the collection' do
29
+ before :all do
30
+ @return = @resource = @articles.unshift(@other).at(0)
31
+ end
32
+
33
+ should_not_be_a_kicker
34
+
35
+ it 'should return a Resource' do
36
+ @return.should be_kind_of(DataMapper::Resource)
37
+ end
38
+
39
+ it 'should return expected Resource' do
40
+ @resource.should equal(@other)
41
+ end
42
+ end
43
+
44
+ describe 'with negative offset', 'after appending to the collection' do
45
+ before :all do
46
+ @return = @resource = @articles.push(@other).at(-1)
47
+ end
48
+
49
+ should_not_be_a_kicker
50
+
51
+ it 'should return a Resource' do
52
+ @return.should be_kind_of(DataMapper::Resource)
53
+ end
54
+
55
+ it 'should return expected Resource' do
56
+ @resource.should equal(@other)
57
+ end
58
+ end
59
+ end
60
+
61
+ describe '#first' do
62
+ before :all do
63
+ 1.upto(5) { |number| @articles.create(:content => "Article #{number}") }
64
+
65
+ @copy = @articles.dup
66
+ @copy.to_a
67
+
68
+ # reload the articles
69
+ @articles = @article_model.all(@articles.query)
70
+ end
71
+
72
+ describe 'with no arguments' do
73
+ before :all do
74
+ @return = @resource = @articles.first
75
+ end
76
+
77
+ it 'should return a Resource' do
78
+ @return.should be_kind_of(DataMapper::Resource)
79
+ end
80
+
81
+ it 'should be first Resource in the Collection' do
82
+ @resource.should equal(@copy.entries.first)
83
+ end
84
+
85
+ it 'should return the same Resource every time' do
86
+ @return.should equal(@articles.first)
87
+ end
88
+ end
89
+
90
+ describe 'with no arguments', 'after prepending to the collection' do
91
+ before :all do
92
+ @return = @resource = @articles.unshift(@other).first
93
+ end
94
+
95
+ it 'should return a Resource' do
96
+ @return.should be_kind_of(DataMapper::Resource)
97
+ end
98
+
99
+ it 'should return expected Resource' do
100
+ @resource.should equal(@other)
101
+ end
102
+
103
+ it 'should be first Resource in the Collection' do
104
+ @resource.should equal(@copy.entries.unshift(@other).first)
105
+ end
106
+ end
107
+
108
+ describe 'with empty query', 'after prepending to the collection' do
109
+ before :all do
110
+ @return = @resource = @articles.unshift(@other).first({})
111
+ end
112
+
113
+ it 'should return a Resource' do
114
+ @return.should be_kind_of(DataMapper::Resource)
115
+ end
116
+
117
+ it 'should return expected Resource' do
118
+ @resource.should equal(@other)
119
+ end
120
+
121
+ it 'should be first Resource in the Collection' do
122
+ @resource.should equal(@copy.entries.unshift(@other).first)
123
+ end
124
+ end
125
+
126
+ describe 'with a limit specified', 'after prepending to the collection' do
127
+ before :all do
128
+ @return = @resources = @articles.unshift(@other).first(1)
129
+ end
130
+
131
+ it 'should return a Collection' do
132
+ @return.should be_kind_of(DataMapper::Collection)
133
+ end
134
+
135
+ it 'should be the expected Collection' do
136
+ @resources.should == [ @other ]
137
+ end
138
+
139
+ it 'should be the first N Resources in the Collection' do
140
+ @resources.should == @copy.entries.unshift(@other).first(1)
141
+ end
142
+ end
143
+ end
144
+
145
+ [ :get, :get! ].each do |method|
146
+ describe 'with a key to a Resource within a Collection using a limit' do
147
+ before :all do
148
+ rescue_if @skip && method == :get! do
149
+ @articles = @articles.all(:limit => 1)
150
+
151
+ @return = @resource = @articles.send(method, *@article.key)
152
+ end
153
+ end
154
+
155
+ it 'should return a Resource' do
156
+ @return.should be_kind_of(DataMapper::Resource)
157
+ end
158
+
159
+ it 'should be matching Resource in the Collection' do
160
+ @resource.should == @article
161
+ end
162
+ end
163
+
164
+ describe 'with a key to a Resource within a Collection using an offset' do
165
+ before :all do
166
+ rescue_if @skip && method == :get! do
167
+ @new = @articles.create(:content => 'New Article')
168
+ @articles = @articles.all(:offset => 1, :limit => 1)
169
+
170
+ @return = @resource = @articles.send(method, *@new.key)
171
+ end
172
+ end
173
+
174
+ it 'should return a Resource' do
175
+ @return.should be_kind_of(DataMapper::Resource)
176
+ end
177
+
178
+ it 'should be matching Resource in the Collection' do
179
+ @resource.should equal(@new)
180
+ end
181
+ end
182
+ end
183
+
184
+ describe '#last' do
185
+ before :all do
186
+ 1.upto(5) { |number| @articles.create(:content => "Article #{number}") }
187
+
188
+ @copy = @articles.dup
189
+ @copy.to_a
190
+
191
+ # reload the articles
192
+ @articles = @article_model.all(@articles.query)
193
+ end
194
+
195
+ describe 'with no arguments' do
196
+ before :all do
197
+ @return = @resource = @articles.last
198
+ end
199
+
200
+ it 'should return a Resource' do
201
+ @return.should be_kind_of(DataMapper::Resource)
202
+ end
203
+
204
+ it 'should be last Resource in the Collection' do
205
+ @resource.should equal(@copy.entries.last)
206
+ end
207
+
208
+ it 'should return the same Resource every time' do
209
+ @return.should equal(@articles.last)
210
+ end
211
+ end
212
+
213
+ describe 'with no arguments', 'after appending to the collection' do
214
+ before :all do
215
+ @return = @resource = @articles.push(@other).last
216
+ end
217
+
218
+ it 'should return a Resource' do
219
+ @return.should be_kind_of(DataMapper::Resource)
220
+ end
221
+
222
+ it 'should return expected Resource' do
223
+ @resource.should equal(@other)
224
+ end
225
+
226
+ it 'should be last Resource in the Collection' do
227
+ @resource.should equal(@copy.entries.push(@other).last)
228
+ end
229
+ end
230
+
231
+ describe 'with empty query', 'after appending to the collection' do
232
+ before :all do
233
+ @return = @resource = @articles.push(@other).last({})
234
+ end
235
+
236
+ it 'should return a Resource' do
237
+ @return.should be_kind_of(DataMapper::Resource)
238
+ end
239
+
240
+ it 'should return expected Resource' do
241
+ @resource.should equal(@other)
242
+ end
243
+
244
+ it 'should be last Resource in the Collection' do
245
+ @resource.should equal(@copy.entries.push(@other).last)
246
+ end
247
+ end
248
+
249
+ describe 'with a limit specified', 'after appending to the collection' do
250
+ before :all do
251
+ @return = @resources = @articles.push(@other).last(1)
252
+ end
253
+
254
+ it 'should return a Collection' do
255
+ @return.should be_kind_of(DataMapper::Collection)
256
+ end
257
+
258
+ it 'should be the expected Collection' do
259
+ @resources.should == [ @other ]
260
+ end
261
+
262
+ it 'should be the last N Resources in the Collection' do
263
+ @resources.should == @copy.entries.push(@other).last(1)
264
+ end
265
+ end
266
+ end
267
+ end