mongo_mapper-unstable 2009.10.11

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 (73) hide show
  1. data/.gitignore +8 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +50 -0
  4. data/Rakefile +87 -0
  5. data/VERSION +1 -0
  6. data/bin/mmconsole +55 -0
  7. data/lib/mongo_mapper/associations/base.rb +83 -0
  8. data/lib/mongo_mapper/associations/belongs_to_polymorphic_proxy.rb +34 -0
  9. data/lib/mongo_mapper/associations/belongs_to_proxy.rb +22 -0
  10. data/lib/mongo_mapper/associations/many_documents_as_proxy.rb +27 -0
  11. data/lib/mongo_mapper/associations/many_documents_proxy.rb +116 -0
  12. data/lib/mongo_mapper/associations/many_embedded_polymorphic_proxy.rb +33 -0
  13. data/lib/mongo_mapper/associations/many_embedded_proxy.rb +67 -0
  14. data/lib/mongo_mapper/associations/many_polymorphic_proxy.rb +11 -0
  15. data/lib/mongo_mapper/associations/many_proxy.rb +6 -0
  16. data/lib/mongo_mapper/associations/proxy.rb +74 -0
  17. data/lib/mongo_mapper/associations.rb +86 -0
  18. data/lib/mongo_mapper/callbacks.rb +106 -0
  19. data/lib/mongo_mapper/dirty.rb +137 -0
  20. data/lib/mongo_mapper/document.rb +340 -0
  21. data/lib/mongo_mapper/dynamic_finder.rb +35 -0
  22. data/lib/mongo_mapper/embedded_document.rb +355 -0
  23. data/lib/mongo_mapper/finder_options.rb +98 -0
  24. data/lib/mongo_mapper/key.rb +36 -0
  25. data/lib/mongo_mapper/observing.rb +50 -0
  26. data/lib/mongo_mapper/pagination.rb +51 -0
  27. data/lib/mongo_mapper/rails_compatibility/document.rb +15 -0
  28. data/lib/mongo_mapper/rails_compatibility/embedded_document.rb +27 -0
  29. data/lib/mongo_mapper/save_with_validation.rb +19 -0
  30. data/lib/mongo_mapper/serialization.rb +55 -0
  31. data/lib/mongo_mapper/serializers/json_serializer.rb +92 -0
  32. data/lib/mongo_mapper/support.rb +161 -0
  33. data/lib/mongo_mapper/validations.rb +69 -0
  34. data/lib/mongo_mapper.rb +111 -0
  35. data/mongo_mapper.gemspec +162 -0
  36. data/specs.watchr +32 -0
  37. data/test/NOTE_ON_TESTING +1 -0
  38. data/test/custom_matchers.rb +55 -0
  39. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +55 -0
  40. data/test/functional/associations/test_belongs_to_proxy.rb +49 -0
  41. data/test/functional/associations/test_many_documents_as_proxy.rb +244 -0
  42. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +132 -0
  43. data/test/functional/associations/test_many_embedded_proxy.rb +174 -0
  44. data/test/functional/associations/test_many_polymorphic_proxy.rb +297 -0
  45. data/test/functional/associations/test_many_proxy.rb +331 -0
  46. data/test/functional/test_associations.rb +44 -0
  47. data/test/functional/test_binary.rb +18 -0
  48. data/test/functional/test_callbacks.rb +85 -0
  49. data/test/functional/test_dirty.rb +138 -0
  50. data/test/functional/test_document.rb +1051 -0
  51. data/test/functional/test_embedded_document.rb +97 -0
  52. data/test/functional/test_logger.rb +20 -0
  53. data/test/functional/test_pagination.rb +87 -0
  54. data/test/functional/test_rails_compatibility.rb +30 -0
  55. data/test/functional/test_validations.rb +279 -0
  56. data/test/models.rb +195 -0
  57. data/test/test_helper.rb +30 -0
  58. data/test/unit/serializers/test_json_serializer.rb +189 -0
  59. data/test/unit/test_association_base.rb +144 -0
  60. data/test/unit/test_document.rb +184 -0
  61. data/test/unit/test_dynamic_finder.rb +125 -0
  62. data/test/unit/test_embedded_document.rb +656 -0
  63. data/test/unit/test_finder_options.rb +261 -0
  64. data/test/unit/test_key.rb +172 -0
  65. data/test/unit/test_mongomapper.rb +28 -0
  66. data/test/unit/test_observing.rb +101 -0
  67. data/test/unit/test_pagination.rb +109 -0
  68. data/test/unit/test_rails_compatibility.rb +39 -0
  69. data/test/unit/test_serializations.rb +52 -0
  70. data/test/unit/test_support.rb +291 -0
  71. data/test/unit/test_time_zones.rb +40 -0
  72. data/test/unit/test_validations.rb +503 -0
  73. metadata +210 -0
@@ -0,0 +1,261 @@
1
+ require 'test_helper'
2
+
3
+ class FinderOptionsTest < Test::Unit::TestCase
4
+ include MongoMapper
5
+
6
+ should "raise error if provided something other than a hash" do
7
+ lambda { FinderOptions.new }.should raise_error(ArgumentError)
8
+ lambda { FinderOptions.new(1) }.should raise_error(ArgumentError)
9
+ end
10
+
11
+ should "symbolize the keys of the hash provided" do
12
+ FinderOptions.new('offset' => 1).options.keys.map do |key|
13
+ key.should be_instance_of(Symbol)
14
+ end
15
+ end
16
+
17
+ context "#criteria" do
18
+ should "convert conditions to criteria" do
19
+ FinderOptions.expects(:to_mongo_criteria).with(:foo => 1).returns({})
20
+ FinderOptions.new(:conditions => {:foo => 1}).criteria
21
+ end
22
+ end
23
+
24
+ context "#options" do
25
+ should "convert options to mongo options" do
26
+ FinderOptions.expects(:to_mongo_options).with(:order => 'foo asc', :select => 'foo,bar').returns({})
27
+ FinderOptions.new(:order => 'foo asc', :select => 'foo,bar').options
28
+ end
29
+ end
30
+
31
+ context "Converting conditions to criteria" do
32
+ should "work with simple criteria" do
33
+ FinderOptions.to_mongo_criteria(:foo => 'bar').should == {
34
+ :foo => 'bar'
35
+ }
36
+
37
+ FinderOptions.to_mongo_criteria(:foo => 'bar', :baz => 'wick').should == {
38
+ :foo => 'bar',
39
+ :baz => 'wick'
40
+ }
41
+ end
42
+
43
+ should "convert id to _id" do
44
+ FinderOptions.to_mongo_criteria(:id => '1').should == {
45
+ :_id => '1'
46
+ }
47
+ end
48
+
49
+ should "use $in for arrays" do
50
+ FinderOptions.to_mongo_criteria(:foo => [1,2,3]).should == {
51
+ :foo => {'$in' => [1,2,3]}
52
+ }
53
+ end
54
+
55
+ should "not use $in for arrays if already using array operator" do
56
+ FinderOptions.to_mongo_criteria(:foo => {'$all' => [1,2,3]}).should == {
57
+ :foo => {'$all' => [1,2,3]}
58
+ }
59
+
60
+ FinderOptions.to_mongo_criteria(:foo => {'$any' => [1,2,3]}).should == {
61
+ :foo => {'$any' => [1,2,3]}
62
+ }
63
+ end
64
+
65
+ should "work arbitrarily deep" do
66
+ FinderOptions.to_mongo_criteria(:foo => {:bar => [1,2,3]}).should == {
67
+ :foo => {:bar => {'$in' => [1,2,3]}}
68
+ }
69
+
70
+ FinderOptions.to_mongo_criteria(:foo => {:bar => {'$any' => [1,2,3]}}).should == {
71
+ :foo => {:bar => {'$any' => [1,2,3]}}
72
+ }
73
+ end
74
+ end
75
+
76
+ context "ordering" do
77
+ should "single field with ascending direction" do
78
+ sort = [['foo', 1]]
79
+ FinderOptions.to_mongo_options(:order => 'foo asc')[:sort].should == sort
80
+ FinderOptions.to_mongo_options(:order => 'foo ASC')[:sort].should == sort
81
+ end
82
+
83
+ should "single field with descending direction" do
84
+ sort = [['foo', -1]]
85
+ FinderOptions.to_mongo_options(:order => 'foo desc')[:sort].should == sort
86
+ FinderOptions.to_mongo_options(:order => 'foo DESC')[:sort].should == sort
87
+ end
88
+
89
+ should "convert field without direction to ascending" do
90
+ sort = [['foo', 1]]
91
+ FinderOptions.to_mongo_options(:order => 'foo')[:sort].should == sort
92
+ end
93
+
94
+ should "convert multiple fields with directions" do
95
+ sort = [['foo', -1], ['bar', 1], ['baz', -1]]
96
+ FinderOptions.to_mongo_options(:order => 'foo desc, bar asc, baz desc')[:sort].should == sort
97
+ end
98
+
99
+ should "convert multiple fields with some missing directions" do
100
+ sort = [['foo', -1], ['bar', 1], ['baz', 1]]
101
+ FinderOptions.to_mongo_options(:order => 'foo desc, bar, baz')[:sort].should == sort
102
+ end
103
+
104
+ should "just use sort if sort and order are present" do
105
+ sort = [['$natural', 1]]
106
+ FinderOptions.to_mongo_options(:sort => sort, :order => 'foo asc')[:sort].should == sort
107
+ end
108
+
109
+ should "convert natural in order to proper" do
110
+ sort = [['$natural', 1]]
111
+ FinderOptions.to_mongo_options(:order => '$natural asc')[:sort].should == sort
112
+ sort = [['$natural', -1]]
113
+ FinderOptions.to_mongo_options(:order => '$natural desc')[:sort].should == sort
114
+ end
115
+
116
+ should "work for natural order ascending" do
117
+ FinderOptions.to_mongo_options(:sort => {'$natural' => 1})[:sort]['$natural'].should == 1
118
+ end
119
+
120
+ should "work for natural order descending" do
121
+ FinderOptions.to_mongo_options(:sort => {'$natural' => -1})[:sort]['$natural'].should == -1
122
+ end
123
+ end
124
+
125
+ context "skip" do
126
+ should "default to 0" do
127
+ FinderOptions.to_mongo_options({})[:skip].should == 0
128
+ end
129
+
130
+ should "use skip provided" do
131
+ FinderOptions.to_mongo_options(:skip => 2)[:skip].should == 2
132
+ end
133
+
134
+ should "covert string to integer" do
135
+ FinderOptions.to_mongo_options(:skip => '2')[:skip].should == 2
136
+ end
137
+
138
+ should "convert offset to skip" do
139
+ FinderOptions.to_mongo_options(:offset => 1)[:skip].should == 1
140
+ end
141
+ end
142
+
143
+ context "limit" do
144
+ should "default to 0" do
145
+ FinderOptions.to_mongo_options({})[:limit].should == 0
146
+ end
147
+
148
+ should "use limit provided" do
149
+ FinderOptions.to_mongo_options(:limit => 2)[:limit].should == 2
150
+ end
151
+
152
+ should "covert string to integer" do
153
+ FinderOptions.to_mongo_options(:limit => '2')[:limit].should == 2
154
+ end
155
+ end
156
+
157
+ context "fields" do
158
+ should "default to nil" do
159
+ FinderOptions.to_mongo_options({})[:fields].should be(nil)
160
+ end
161
+
162
+ should "be converted to nil if empty string" do
163
+ FinderOptions.to_mongo_options(:fields => '')[:fields].should be(nil)
164
+ end
165
+
166
+ should "be converted to nil if []" do
167
+ FinderOptions.to_mongo_options(:fields => [])[:fields].should be(nil)
168
+ end
169
+
170
+ should "should work with array" do
171
+ FinderOptions.to_mongo_options({:fields => %w(a b)})[:fields].should == %w(a b)
172
+ end
173
+
174
+ should "convert comma separated list to array" do
175
+ FinderOptions.to_mongo_options({:fields => 'a, b'})[:fields].should == %w(a b)
176
+ end
177
+
178
+ should "also work as select" do
179
+ FinderOptions.new(:select => %w(a b)).options[:fields].should == %w(a b)
180
+ end
181
+ end
182
+
183
+ context "Condition auto-detection" do
184
+ should "know :conditions are criteria" do
185
+ finder = FinderOptions.new(:conditions => {:foo => 'bar'})
186
+ finder.criteria.should == {:foo => 'bar'}
187
+ finder.options.keys.should_not include(:conditions)
188
+ end
189
+
190
+ should "know fields is an option" do
191
+ finder = FinderOptions.new(:fields => ['foo'])
192
+ finder.options[:fields].should == ['foo']
193
+ finder.criteria.keys.should_not include(:fields)
194
+ end
195
+
196
+ # select gets converted to fields so just checking keys
197
+ should "know select is an option" do
198
+ finder = FinderOptions.new(:select => 'foo')
199
+ finder.options.keys.should include(:sort)
200
+ finder.criteria.keys.should_not include(:select)
201
+ finder.criteria.keys.should_not include(:fields)
202
+ end
203
+
204
+ should "know skip is an option" do
205
+ finder = FinderOptions.new(:skip => 10)
206
+ finder.options[:skip].should == 10
207
+ finder.criteria.keys.should_not include(:skip)
208
+ end
209
+
210
+ # offset gets converted to skip so just checking keys
211
+ should "know offset is an option" do
212
+ finder = FinderOptions.new(:offset => 10)
213
+ finder.options.keys.should include(:skip)
214
+ finder.criteria.keys.should_not include(:skip)
215
+ finder.criteria.keys.should_not include(:offset)
216
+ end
217
+
218
+ should "know limit is an option" do
219
+ finder = FinderOptions.new(:limit => 10)
220
+ finder.options[:limit].should == 10
221
+ finder.criteria.keys.should_not include(:limit)
222
+ end
223
+
224
+ should "know sort is an option" do
225
+ finder = FinderOptions.new(:sort => [['foo', 1]])
226
+ finder.options[:sort].should == [['foo', 1]]
227
+ finder.criteria.keys.should_not include(:sort)
228
+ end
229
+
230
+ # order gets converted to sort so just checking keys
231
+ should "know order is an option" do
232
+ finder = FinderOptions.new(:order => 'foo')
233
+ finder.options.keys.should include(:sort)
234
+ finder.criteria.keys.should_not include(:sort)
235
+ end
236
+
237
+ should "work with full range of things" do
238
+ finder_options = FinderOptions.new({
239
+ :foo => 'bar',
240
+ :baz => true,
241
+ :sort => [['foo', 1]],
242
+ :fields => ['foo', 'baz'],
243
+ :limit => 10,
244
+ :skip => 10,
245
+ })
246
+
247
+ finder_options.criteria.should == {
248
+ :foo => 'bar',
249
+ :baz => true,
250
+ }
251
+
252
+ finder_options.options.should == {
253
+ :sort => [['foo', 1]],
254
+ :fields => ['foo', 'baz'],
255
+ :limit => 10,
256
+ :skip => 10,
257
+ }
258
+ end
259
+ end
260
+
261
+ end # FinderOptionsTest
@@ -0,0 +1,172 @@
1
+ require 'test_helper'
2
+
3
+ class Address
4
+ include MongoMapper::EmbeddedDocument
5
+
6
+ key :address, String
7
+ key :city, String
8
+ key :state, String
9
+ key :zip, Integer
10
+ end
11
+
12
+ class FooType < Struct.new(:bar)
13
+ def self.to_mongo(value)
14
+ 'to_mongo'
15
+ end
16
+
17
+ def self.from_mongo(value)
18
+ 'from_mongo'
19
+ end
20
+ end
21
+
22
+ class KeyTest < Test::Unit::TestCase
23
+ include MongoMapper
24
+
25
+ context "Initializing a new key" do
26
+ should "allow setting the name" do
27
+ Key.new(:foo, String).name.should == 'foo'
28
+ end
29
+
30
+ should "allow setting the type" do
31
+ Key.new(:foo, Integer).type.should be(Integer)
32
+ end
33
+
34
+ should "allow setting options" do
35
+ Key.new(:foo, Integer, :required => true).options[:required].should be(true)
36
+ end
37
+
38
+ should "default options to {}" do
39
+ Key.new(:foo, Integer, nil).options.should == {}
40
+ end
41
+
42
+ should "symbolize option keys" do
43
+ Key.new(:foo, Integer, 'required' => true).options[:required].should be(true)
44
+ end
45
+
46
+ should "work with just name" do
47
+ key = Key.new(:foo)
48
+ key.name.should == 'foo'
49
+ end
50
+
51
+ should "work with name and type" do
52
+ key = Key.new(:foo, String)
53
+ key.name.should == 'foo'
54
+ key.type.should == String
55
+ end
56
+
57
+ should "work with name, type, and options" do
58
+ key = Key.new(:foo, String, :required => true)
59
+ key.name.should == 'foo'
60
+ key.type.should == String
61
+ key.options[:required].should be_true
62
+ end
63
+
64
+ should "work with name and options" do
65
+ key = Key.new(:foo, :required => true)
66
+ key.name.should == 'foo'
67
+ key.options[:required].should be_true
68
+ end
69
+ end
70
+
71
+ context "A key" do
72
+ should "be equal to another key with same name and type" do
73
+ Key.new(:name, String).should == Key.new(:name, String)
74
+ end
75
+
76
+ should "not be equal to another key with different name" do
77
+ Key.new(:name, String).should_not == Key.new(:foo, String)
78
+ end
79
+
80
+ should "not be equal to another key with different type" do
81
+ Key.new(:name, String).should_not == Key.new(:name, Integer)
82
+ end
83
+
84
+ should "know if it is a embedded_document" do
85
+ klass = Class.new do
86
+ include MongoMapper::EmbeddedDocument
87
+ end
88
+ Key.new(:name, klass).embeddable?.should be_true
89
+ end
90
+
91
+ should "know if it is not a embedded_document" do
92
+ Key.new(:name, String).embeddable?.should be_false
93
+ end
94
+
95
+ should "know if it is a number" do
96
+ Key.new(:age, Integer).number?.should be_true
97
+ Key.new(:age, Float).number?.should be_true
98
+ end
99
+
100
+ should "know if it is not a number" do
101
+ Key.new(:age, String).number?.should be_false
102
+ end
103
+ end
104
+
105
+ context "setting a value with a custom type" do
106
+ should "correctly typecast" do
107
+ key = Key.new(:foo, FooType)
108
+ key.set("something").should == 'to_mongo'
109
+ end
110
+
111
+ should "correctly typecast if object of that type is given" do
112
+ key = Key.new(:foo, FooType)
113
+ key.set(FooType.new('something')).should == 'to_mongo'
114
+ end
115
+ end
116
+
117
+ context "getting a value with a custom type" do
118
+ should "use #from_mongo to convert back to custom type" do
119
+ key = Key.new(:foo, FooType)
120
+ key.get('something').should == 'from_mongo'
121
+ end
122
+ end
123
+
124
+ context "getting a value" do
125
+ should "work with a type" do
126
+ key = Key.new(:foo, String)
127
+ key.get('bar').should == 'bar'
128
+ end
129
+
130
+ should "work without type" do
131
+ key = Key.new(:foo)
132
+ key.get([1, '2']).should == [1, '2']
133
+ key.get(false).should == false
134
+ key.get({}).should == {}
135
+ end
136
+
137
+ context "for a embedded_document" do
138
+ should "default to nil" do
139
+ key = Key.new(:foo, Address)
140
+ key.get(nil).should be_nil
141
+ end
142
+
143
+ should "return instance if instance" do
144
+ address = Address.new(:city => 'South Bend', :state => 'IN', :zip => 46544)
145
+ key = Key.new(:foo, Address)
146
+ key.get(address).should == address
147
+ end
148
+ end
149
+ end
150
+
151
+ context "getting a value with a default set" do
152
+ setup do
153
+ @key = Key.new(:foo, String, :default => 'baz')
154
+ end
155
+
156
+ should "return default value if value nil" do
157
+ @key.get(nil).should == 'baz'
158
+ end
159
+
160
+ should "return value if not blank" do
161
+ @key.get('foobar').should == 'foobar'
162
+ end
163
+
164
+ should "work with Boolean type and false value" do
165
+ Key.new(:active, Boolean, :default => false).get(nil).should be_false
166
+ end
167
+
168
+ should "work with Boolean type and true value" do
169
+ Key.new(:active, Boolean, :default => true).get(nil).should be_true
170
+ end
171
+ end
172
+ end # KeyTest
@@ -0,0 +1,28 @@
1
+ require 'test_helper'
2
+
3
+ class Address; end
4
+
5
+ class MongoMapperTest < Test::Unit::TestCase
6
+ should "be able to write and read connection" do
7
+ conn = Mongo::Connection.new
8
+ MongoMapper.connection = conn
9
+ MongoMapper.connection.should == conn
10
+ end
11
+
12
+ should "default connection to new mongo ruby driver" do
13
+ MongoMapper.connection = nil
14
+ MongoMapper.connection.should be_instance_of(Mongo::Connection)
15
+ end
16
+
17
+ should "be able to write and read default database" do
18
+ MongoMapper.database = DefaultDatabase
19
+ MongoMapper.database.should be_instance_of(Mongo::DB)
20
+ MongoMapper.database.name.should == DefaultDatabase
21
+ end
22
+
23
+ should "have document not found error" do
24
+ lambda {
25
+ MongoMapper::DocumentNotFound
26
+ }.should_not raise_error
27
+ end
28
+ end
@@ -0,0 +1,101 @@
1
+ require 'test_helper'
2
+
3
+ class Comment
4
+ include MongoMapper::Document
5
+
6
+ key :name, String
7
+ key :body, String
8
+
9
+ attr_accessor :callers
10
+ before_validation :record_callers
11
+
12
+ def after_validation
13
+ record_callers
14
+ end
15
+
16
+ def record_callers
17
+ callers << self.class if callers
18
+ end
19
+ end
20
+
21
+ class Article
22
+ include MongoMapper::Document
23
+
24
+ key :title, String
25
+ key :body, String
26
+ end
27
+
28
+ class CommentObserver < MongoMapper::Observer
29
+ attr_accessor :callers
30
+
31
+ def after_validation(model)
32
+ callers << self.class if callers
33
+ end
34
+ end
35
+
36
+ class AuditObserver < MongoMapper::Observer
37
+ observe Article, Comment
38
+ attr_reader :document
39
+
40
+ def after_validation(document)
41
+ @document = document
42
+ end
43
+ end
44
+
45
+ class GlobalObserver < MongoMapper::Observer
46
+ observe Article, Comment
47
+ attr_reader :document
48
+
49
+ def before_save(document)
50
+ @document = document
51
+ end
52
+ end
53
+
54
+ class NonAutomaticObserver < MongoMapper::Observer
55
+ observe Comment
56
+ attr_reader :comment
57
+
58
+ def after_validation(comment)
59
+ @comment = comment
60
+ end
61
+ end
62
+
63
+ class ObserverTest < Test::Unit::TestCase
64
+ should "fire model callbacks before observer" do
65
+ callers = []
66
+ comment = Comment.new
67
+ comment.callers = callers
68
+
69
+ CommentObserver.instance.callers = callers
70
+
71
+ comment.valid?
72
+ callers.should == [Comment, Comment, CommentObserver]
73
+ end
74
+
75
+ should "automatically observe model based on name when possible" do
76
+ CommentObserver.observed_class.should == Comment
77
+ end
78
+
79
+ should "be able to observe other models using observe" do
80
+ obs = NonAutomaticObserver.instance
81
+ comment = Comment.new(:name => 'John Nunemaker', :body => 'is awesome')
82
+ comment.valid?
83
+ obs.comment.name.should == 'John Nunemaker'
84
+ obs.comment.body.should == 'is awesome'
85
+ end
86
+
87
+ should "be able to observe multiple models" do
88
+ obs = AuditObserver.instance
89
+ comment = Comment.new(:name => 'Steve Smith', :body => 'is awesome')
90
+ comment.valid?
91
+
92
+ obs.document.name.should == 'Steve Smith'
93
+ obs.document.body.should == 'is awesome'
94
+
95
+ article = Article.new(:title => 'Ordered List Is Awesome', :body => 'Learn to accept it!')
96
+ article.valid?
97
+
98
+ obs.document.title.should == 'Ordered List Is Awesome'
99
+ obs.document.body.should == 'Learn to accept it!'
100
+ end
101
+ end
@@ -0,0 +1,109 @@
1
+ require 'test_helper'
2
+
3
+ class PaginationTest < Test::Unit::TestCase
4
+ context "Pagination proxy" do
5
+ include MongoMapper::Pagination
6
+
7
+ should "should have accessors for subject" do
8
+ subject = [1,2,3,4,5]
9
+ collection = PaginationProxy.new(25, 2)
10
+ collection.subject = subject
11
+ collection.subject.should == subject
12
+ end
13
+
14
+ should "delegate any methods not defined to the subject" do
15
+ subject = [1,2,3,4,5]
16
+ collection = PaginationProxy.new(25, 2, 10)
17
+ collection.subject = subject
18
+ collection.size.should == 5
19
+ collection.each_with_index do |value, i|
20
+ value.should == subject[i]
21
+ end
22
+ collection[0..2].should == [1,2,3]
23
+ collection.class.should == Array
24
+ end
25
+
26
+ should "return correct value for total_entries" do
27
+ PaginationProxy.new(25, 2, 10).total_entries.should == 25
28
+ PaginationProxy.new('25', 2, 10).total_entries.should == 25
29
+ end
30
+
31
+ should "return correct value for per_page" do
32
+ PaginationProxy.new(25, 2, 10).per_page.should == 10
33
+ PaginationProxy.new(25, 2, '10').per_page.should == 10
34
+ end
35
+
36
+ should "alias limit to per_page" do
37
+ PaginationProxy.new(100, 1, 300).limit.should == 300
38
+ end
39
+
40
+ should "set per_page to 25 if nil or blank" do
41
+ PaginationProxy.new(25, 2).per_page.should == 25
42
+ PaginationProxy.new(25, 2, '').per_page.should == 25
43
+ end
44
+
45
+ should "return correct value for current_page" do
46
+ PaginationProxy.new(25, 2, 10).current_page.should == 2
47
+ PaginationProxy.new(25, '2', 10).current_page.should == 2
48
+ end
49
+
50
+ should "not allow value less than 1 for current page" do
51
+ PaginationProxy.new(25, -1).current_page.should == 1
52
+ end
53
+
54
+ should "automatically calculate total_pages from total_entries and per page" do
55
+ PaginationProxy.new(25, 2, 10).total_pages.should == 3
56
+ end
57
+
58
+ should "know how many records to skip" do
59
+ PaginationProxy.new(25, 2, 10).skip.should == 10
60
+ end
61
+
62
+ context "previous_page" do
63
+ should "be nil if current page 1" do
64
+ PaginationProxy.new(25, 1, 10).previous_page.should be_nil
65
+ end
66
+
67
+ should "be one less than current page if current is > 1" do
68
+ PaginationProxy.new(25, 2, 10).previous_page.should == 1
69
+ end
70
+ end
71
+
72
+ context "next_page" do
73
+ should "be nil if current page is last page" do
74
+ PaginationProxy.new(25, 3, 10).next_page.should be_nil
75
+ end
76
+
77
+ should "work for any page that is not last" do
78
+ PaginationProxy.new(25, 1, 10).next_page.should == 2
79
+ PaginationProxy.new(25, 2, 10).next_page.should == 3
80
+ end
81
+ end
82
+
83
+ context "previous_page" do
84
+ should "be nil if current page is first page" do
85
+ PaginationProxy.new(25, 1, 10).previous_page.should be_nil
86
+ end
87
+
88
+ should "work for any page other than first" do
89
+ PaginationProxy.new(25, 2, 10).previous_page.should == 1
90
+ PaginationProxy.new(25, 3, 10).previous_page.should == 2
91
+ end
92
+ end
93
+
94
+ context "out_of_bounds?" do
95
+ should "be true if current_page is greater than total_pages" do
96
+ PaginationProxy.new(25, 10, 4).out_of_bounds?.should be_true
97
+ end
98
+
99
+ should "be false if current_page is less than total_pages" do
100
+ PaginationProxy.new(25, 10, 1).out_of_bounds?.should be_false
101
+ PaginationProxy.new(25, 2, 10).out_of_bounds?.should be_false
102
+ end
103
+
104
+ should "be false if current_page is equal to total_pages" do
105
+ PaginationProxy.new(25, 3, 10).out_of_bounds?.should be_false
106
+ end
107
+ end
108
+ end # end of pagination proxy
109
+ end # end of test case