sequel_core 1.5.1 → 2.0.0

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 (68) hide show
  1. data/CHANGELOG +116 -0
  2. data/COPYING +19 -19
  3. data/README +83 -32
  4. data/Rakefile +9 -20
  5. data/bin/sequel +43 -112
  6. data/doc/cheat_sheet.rdoc +225 -0
  7. data/doc/dataset_filtering.rdoc +257 -0
  8. data/lib/sequel_core/adapters/adapter_skeleton.rb +4 -2
  9. data/lib/sequel_core/adapters/ado.rb +3 -1
  10. data/lib/sequel_core/adapters/db2.rb +4 -2
  11. data/lib/sequel_core/adapters/dbi.rb +127 -113
  12. data/lib/sequel_core/adapters/informix.rb +4 -2
  13. data/lib/sequel_core/adapters/jdbc.rb +5 -3
  14. data/lib/sequel_core/adapters/mysql.rb +112 -46
  15. data/lib/sequel_core/adapters/odbc.rb +5 -7
  16. data/lib/sequel_core/adapters/odbc_mssql.rb +12 -3
  17. data/lib/sequel_core/adapters/openbase.rb +3 -1
  18. data/lib/sequel_core/adapters/oracle.rb +11 -9
  19. data/lib/sequel_core/adapters/postgres.rb +261 -262
  20. data/lib/sequel_core/adapters/sqlite.rb +72 -22
  21. data/lib/sequel_core/connection_pool.rb +140 -73
  22. data/lib/sequel_core/core_ext.rb +201 -66
  23. data/lib/sequel_core/core_sql.rb +123 -153
  24. data/lib/sequel_core/database/schema.rb +156 -0
  25. data/lib/sequel_core/database.rb +321 -338
  26. data/lib/sequel_core/dataset/callback.rb +11 -12
  27. data/lib/sequel_core/dataset/convenience.rb +213 -240
  28. data/lib/sequel_core/dataset/pagination.rb +58 -43
  29. data/lib/sequel_core/dataset/parse_tree_sequelizer.rb +331 -0
  30. data/lib/sequel_core/dataset/query.rb +41 -0
  31. data/lib/sequel_core/dataset/schema.rb +15 -0
  32. data/lib/sequel_core/dataset/sequelizer.rb +41 -373
  33. data/lib/sequel_core/dataset/sql.rb +741 -632
  34. data/lib/sequel_core/dataset.rb +183 -168
  35. data/lib/sequel_core/deprecated.rb +1 -169
  36. data/lib/sequel_core/exceptions.rb +24 -19
  37. data/lib/sequel_core/migration.rb +44 -52
  38. data/lib/sequel_core/object_graph.rb +43 -42
  39. data/lib/sequel_core/pretty_table.rb +71 -76
  40. data/lib/sequel_core/schema/generator.rb +163 -105
  41. data/lib/sequel_core/schema/sql.rb +250 -93
  42. data/lib/sequel_core/schema.rb +2 -8
  43. data/lib/sequel_core/sql.rb +394 -0
  44. data/lib/sequel_core/worker.rb +37 -27
  45. data/lib/sequel_core.rb +99 -45
  46. data/spec/adapters/informix_spec.rb +0 -1
  47. data/spec/adapters/mysql_spec.rb +177 -124
  48. data/spec/adapters/oracle_spec.rb +0 -1
  49. data/spec/adapters/postgres_spec.rb +98 -58
  50. data/spec/adapters/sqlite_spec.rb +45 -4
  51. data/spec/blockless_filters_spec.rb +269 -0
  52. data/spec/connection_pool_spec.rb +21 -18
  53. data/spec/core_ext_spec.rb +169 -19
  54. data/spec/core_sql_spec.rb +56 -49
  55. data/spec/database_spec.rb +78 -17
  56. data/spec/dataset_spec.rb +300 -428
  57. data/spec/migration_spec.rb +1 -1
  58. data/spec/object_graph_spec.rb +5 -11
  59. data/spec/rcov.opts +1 -1
  60. data/spec/schema_generator_spec.rb +16 -4
  61. data/spec/schema_spec.rb +89 -10
  62. data/spec/sequelizer_spec.rb +56 -56
  63. data/spec/spec.opts +0 -5
  64. data/spec/spec_config.rb +7 -0
  65. data/spec/spec_config.rb.example +5 -5
  66. data/spec/spec_helper.rb +6 -0
  67. data/spec/worker_spec.rb +1 -1
  68. metadata +78 -63
@@ -0,0 +1,269 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ context "Blockless Ruby Filters" do
4
+ before do
5
+ db = Sequel::Database.new
6
+ db.quote_identifiers = false
7
+ @d = db[:items]
8
+ def @d.l(*args)
9
+ literal(filter_expr(*args))
10
+ end
11
+ end
12
+
13
+ it "should support boolean columns directly" do
14
+ @d.l(:x).should == 'x'
15
+ end
16
+
17
+ it "should support NOT via Symbol#~" do
18
+ @d.l(~:x).should == 'NOT x'
19
+ end
20
+
21
+ it "should support qualified columns" do
22
+ @d.l(:x__y).should == 'x.y'
23
+ @d.l(~:x__y).should == 'NOT x.y'
24
+ end
25
+
26
+ it "should support NOT with SQL functions" do
27
+ @d.l(~:is_blah[]).should == 'NOT is_blah()'
28
+ @d.l(~:is_blah[:x]).should == 'NOT is_blah(x)'
29
+ @d.l(~:is_blah[:x__y]).should == 'NOT is_blah(x.y)'
30
+ @d.l(~:is_blah[:x, :x__y]).should == 'NOT is_blah(x, x.y)'
31
+ end
32
+
33
+ it "should handle multiple ~" do
34
+ @d.l(~~:x).should == 'x'
35
+ @d.l(~~~:x).should == 'NOT x'
36
+ @d.l(~~(:x > 100)).should == '(x > 100)'
37
+ @d.l(~~(:x & :y)).should == '(x AND y)'
38
+ @d.l(~~(:x | :y)).should == '(x OR y)'
39
+ end
40
+
41
+ it "should support >, <, >=, and <= via Symbol#>,<,>=,<=" do
42
+ @d.l(:x > 100).should == '(x > 100)'
43
+ @d.l(:x < 100.01).should == '(x < 100.01)'
44
+ @d.l(:x >= 100000000000000000000000000000000000).should == '(x >= 100000000000000000000000000000000000)'
45
+ @d.l(:x <= 100).should == '(x <= 100)'
46
+ end
47
+
48
+ it "should support negation of >, <, >=, and <= via Symbol#~" do
49
+ @d.l(~(:x > 100)).should == '(x <= 100)'
50
+ @d.l(~(:x < 100.01)).should == '(x >= 100.01)'
51
+ @d.l(~(:x >= 100000000000000000000000000000000000)).should == '(x < 100000000000000000000000000000000000)'
52
+ @d.l(~(:x <= 100)).should == '(x > 100)'
53
+ end
54
+
55
+ it "should support = via Hash" do
56
+ @d.l(:x => 100).should == '(x = 100)'
57
+ @d.l(:x => 'a').should == '(x = \'a\')'
58
+ @d.l(:x => true).should == '(x = \'t\')'
59
+ @d.l(:x => false).should == '(x = \'f\')'
60
+ @d.l(:x => nil).should == '(x IS NULL)'
61
+ @d.l(:x => [1,2,3]).should == '(x IN (1, 2, 3))'
62
+ end
63
+
64
+ it "should support != via Hash#~" do
65
+ @d.l(~{:x => 100}).should == '(x != 100)'
66
+ @d.l(~{:x => 'a'}).should == '(x != \'a\')'
67
+ @d.l(~{:x => true}).should == '(x != \'t\')'
68
+ @d.l(~{:x => false}).should == '(x != \'f\')'
69
+ @d.l(~{:x => nil}).should == '(x IS NOT NULL)'
70
+ end
71
+
72
+ it "should support ~ via Hash and Regexp (if supported by database)" do
73
+ @d.l(:x => /blah/).should == '(x ~ \'blah\')'
74
+ end
75
+
76
+ it "should support !~ via Hash#~ and Regexp" do
77
+ @d.l(~{:x => /blah/}).should == '(x !~ \'blah\')'
78
+ end
79
+
80
+ it "should support LIKE via Symbol#like" do
81
+ @d.l(:x.like('a')).should == '(x LIKE \'a\')'
82
+ @d.l(:x.like(/a/)).should == '(x ~ \'a\')'
83
+ @d.l(:x.like('a', 'b')).should == '((x LIKE \'a\') OR (x LIKE \'b\'))'
84
+ @d.l(:x.like(/a/, /b/)).should == '((x ~ \'a\') OR (x ~ \'b\'))'
85
+ @d.l(:x.like('a', /b/)).should == '((x LIKE \'a\') OR (x ~ \'b\'))'
86
+ end
87
+
88
+ it "should support NOT LIKE via Symbol#like and Symbol#~" do
89
+ @d.l(~:x.like('a')).should == '(x NOT LIKE \'a\')'
90
+ @d.l(~:x.like(/a/)).should == '(x !~ \'a\')'
91
+ @d.l(~:x.like('a', 'b')).should == '((x NOT LIKE \'a\') AND (x NOT LIKE \'b\'))'
92
+ @d.l(~:x.like(/a/, /b/)).should == '((x !~ \'a\') AND (x !~ \'b\'))'
93
+ @d.l(~:x.like('a', /b/)).should == '((x NOT LIKE \'a\') AND (x !~ \'b\'))'
94
+ end
95
+
96
+ it "should support negating ranges via Hash#~ and Range" do
97
+ @d.l(~{:x => 1..5}).should == '((x < 1) OR (x > 5))'
98
+ @d.l(~{:x => 1...5}).should == '((x < 1) OR (x >= 5))'
99
+ end
100
+
101
+ it "should support negating NOT IN via Hash#~ and Dataset or Array" do
102
+ @d.l(~{:x => @d.select(:i)}).should == '(x NOT IN (SELECT i FROM items))'
103
+ @d.l(~{:x => [1,2,3]}).should == '(x NOT IN (1, 2, 3))'
104
+ end
105
+
106
+ it "should support + - * / via Symbol#+,-,*,/" do
107
+ @d.l(:x + 1 > 100).should == '((x + 1) > 100)'
108
+ @d.l((:x * :y) < 100.01).should == '((x * y) < 100.01)'
109
+ @d.l((:x - :y/2) >= 100000000000000000000000000000000000).should == '((x - (y / 2)) >= 100000000000000000000000000000000000)'
110
+ @d.l((((:x - :y)/(:x + :y))*:z) <= 100).should == '((((x - y) / (x + y)) * z) <= 100)'
111
+ @d.l(~((((:x - :y)/(:x + :y))*:z) <= 100)).should == '((((x - y) / (x + y)) * z) > 100)'
112
+ end
113
+
114
+ it "should not allow negation of non-boolean expressions" do
115
+ proc{~(:x + 1 > 100)}.should_not raise_error
116
+ proc{~(:x + 1)}.should raise_error(Sequel::Error)
117
+ end
118
+
119
+ it "should not allow mathematical, inequality, or string operations on true, false, or nil" do
120
+ proc{:x + 1}.should_not raise_error
121
+ proc{:x - true}.should raise_error(Sequel::Error)
122
+ proc{:x / false}.should raise_error(Sequel::Error)
123
+ proc{:x * nil}.should raise_error(Sequel::Error)
124
+ proc{:x > 1}.should_not raise_error
125
+ proc{:x < true}.should raise_error(Sequel::Error)
126
+ proc{:x >= false}.should raise_error(Sequel::Error)
127
+ proc{:x <= nil}.should raise_error(Sequel::Error)
128
+ proc{[:x, nil].sql_string_join}.should raise_error(Sequel::Error)
129
+ end
130
+
131
+ it "should not allow mathematical, inequality, or string operations on boolean complex expressions" do
132
+ proc{:x + (:y + 1)}.should_not raise_error
133
+ proc{:x - (~:y)}.should raise_error(Sequel::Error)
134
+ proc{:x / (:y & :z)}.should raise_error(Sequel::Error)
135
+ proc{:x * (:y | :z)}.should raise_error(Sequel::Error)
136
+ proc{:x > (:y > 5)}.should raise_error(Sequel::Error)
137
+ proc{:x < (:y < 5)}.should raise_error(Sequel::Error)
138
+ proc{:x >= (:y >= 5)}.should raise_error(Sequel::Error)
139
+ proc{:x <= (:y <= 5)}.should raise_error(Sequel::Error)
140
+ proc{:x > {:y => nil}}.should raise_error(Sequel::Error)
141
+ proc{:x < ~{:y => nil}}.should raise_error(Sequel::Error)
142
+ proc{:x >= {:y => 5}}.should raise_error(Sequel::Error)
143
+ proc{:x <= ~{:y => 5}}.should raise_error(Sequel::Error)
144
+ proc{:x >= {:y => [1,2,3]}}.should raise_error(Sequel::Error)
145
+ proc{:x <= ~{:y => [1,2,3]}}.should raise_error(Sequel::Error)
146
+ proc{:x + :y.like('a')}.should raise_error(Sequel::Error)
147
+ proc{:x - :y.like(/a/)}.should raise_error(Sequel::Error)
148
+ proc{:x * :y.like(/a/i)}.should raise_error(Sequel::Error)
149
+ proc{:x + ~:y.like('a')}.should raise_error(Sequel::Error)
150
+ proc{:x - ~:y.like(/a/)}.should raise_error(Sequel::Error)
151
+ proc{:x * ~:y.like(/a/i)}.should raise_error(Sequel::Error)
152
+ proc{[:x, ~:y.like(/a/i)].sql_string_join}.should raise_error(Sequel::Error)
153
+ end
154
+
155
+ it "should support AND conditions via &" do
156
+ @d.l(:x & :y).should == '(x AND y)'
157
+ @d.l(:x & :y & :z).should == '((x AND y) AND z)'
158
+ @d.l(:x & {:y => :z}).should == '(x AND (y = z))'
159
+ @d.l({:y => :z} & :x).should == '((y = z) AND x)'
160
+ @d.l({:x => :a} & {:y => :z}).should == '((x = a) AND (y = z))'
161
+ @d.l((:x > 200) & (:y < 200)).should == '((x > 200) AND (y < 200))'
162
+ @d.l(:x & ~:y).should == '(x AND NOT y)'
163
+ @d.l(~:x & :y).should == '(NOT x AND y)'
164
+ @d.l(~:x & ~:y).should == '(NOT x AND NOT y)'
165
+ end
166
+
167
+ it "should support OR conditions via |" do
168
+ @d.l(:x | :y).should == '(x OR y)'
169
+ @d.l(:x | :y | :z).should == '((x OR y) OR z)'
170
+ @d.l(:x | {:y => :z}).should == '(x OR (y = z))'
171
+ @d.l({:y => :z} | :x).should == '((y = z) OR x)'
172
+ @d.l({:x => :a} | {:y => :z}).should == '((x = a) OR (y = z))'
173
+ @d.l((:x > 200) | (:y < 200)).should == '((x > 200) OR (y < 200))'
174
+ end
175
+
176
+ it "should support & | combinations" do
177
+ @d.l((:x | :y) & :z).should == '((x OR y) AND z)'
178
+ @d.l(:x | (:y & :z)).should == '(x OR (y AND z))'
179
+ @d.l((:x & :w) | (:y & :z)).should == '((x AND w) OR (y AND z))'
180
+ end
181
+
182
+ it "should support & | with ~" do
183
+ @d.l(~((:x | :y) & :z)).should == '((NOT x AND NOT y) OR NOT z)'
184
+ @d.l(~(:x | (:y & :z))).should == '(NOT x AND (NOT y OR NOT z))'
185
+ @d.l(~((:x & :w) | (:y & :z))).should == '((NOT x OR NOT w) AND (NOT y OR NOT z))'
186
+ @d.l(~((:x > 200) | (:y & :z))).should == '((x <= 200) AND (NOT y OR NOT z))'
187
+ end
188
+
189
+ it "should support LiteralString" do
190
+ @d.l('x'.lit).should == '(x)'
191
+ @d.l(~'x'.lit).should == 'NOT x'
192
+ @d.l(~~'x'.lit).should == '(x)'
193
+ @d.l(~(('x'.lit | :y) & :z)).should == '((NOT x AND NOT y) OR NOT z)'
194
+ @d.l(~(:x | 'y'.lit)).should == '(NOT x AND NOT y)'
195
+ @d.l(~('x'.lit & 'y'.lit)).should == '(NOT x OR NOT y)'
196
+ @d.l({'y'.lit => 'z'.lit} & 'x'.lit).should == '((y = z) AND x)'
197
+ @d.l(('x'.lit > 200) & ('y'.lit < 200)).should == '((x > 200) AND (y < 200))'
198
+ @d.l(~('x'.lit + 1 > 100)).should == '((x + 1) <= 100)'
199
+ @d.l('x'.lit.like(/a/)).should == '(x ~ \'a\')'
200
+ @d.l('x'.lit + 1 > 100).should == '((x + 1) > 100)'
201
+ @d.l(('x'.lit * :y) < 100.01).should == '((x * y) < 100.01)'
202
+ @d.l(('x'.lit - :y/2) >= 100000000000000000000000000000000000).should == '((x - (y / 2)) >= 100000000000000000000000000000000000)'
203
+ @d.l(('z'.lit * (('x'.lit / :y)/(:x + :y))) <= 100).should == '((z * ((x / y) / (x + y))) <= 100)'
204
+ @d.l(~(((('x'.lit - :y)/(:x + :y))*:z) <= 100)).should == '((((x - y) / (x + y)) * z) > 100)'
205
+ end
206
+
207
+ it "should support hashes by ANDing the conditions" do
208
+ @d.l(:x => 100, :y => 'a')[1...-1].split(' AND ').sort.should == ['(x = 100)', '(y = \'a\')']
209
+ @d.l(:x => true, :y => false)[1...-1].split(' AND ').sort.should == ['(x = \'t\')', '(y = \'f\')']
210
+ @d.l(:x => nil, :y => [1,2,3])[1...-1].split(' AND ').sort.should == ['(x IS NULL)', '(y IN (1, 2, 3))']
211
+ end
212
+
213
+ it "should support sql_negate on hashes" do
214
+ @d.l({:x => 100, :y => 'a'}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x != 100)', '(y != \'a\')']
215
+ @d.l({:x => true, :y => false}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x != \'t\')', '(y != \'f\')']
216
+ @d.l({:x => nil, :y => [1,2,3]}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x IS NOT NULL)', '(y NOT IN (1, 2, 3))']
217
+ end
218
+
219
+ it "should support ~ on hashes" do
220
+ @d.l(~{:x => 100, :y => 'a'})[1...-1].split(' OR ').sort.should == ['(x != 100)', '(y != \'a\')']
221
+ @d.l(~{:x => true, :y => false})[1...-1].split(' OR ').sort.should == ['(x != \'t\')', '(y != \'f\')']
222
+ @d.l(~{:x => nil, :y => [1,2,3]})[1...-1].split(' OR ').sort.should == ['(x IS NOT NULL)', '(y NOT IN (1, 2, 3))']
223
+ end
224
+
225
+ it "should support sql_or on hashes" do
226
+ @d.l({:x => 100, :y => 'a'}.sql_or)[1...-1].split(' OR ').sort.should == ['(x = 100)', '(y = \'a\')']
227
+ @d.l({:x => true, :y => false}.sql_or)[1...-1].split(' OR ').sort.should == ['(x = \'t\')', '(y = \'f\')']
228
+ @d.l({:x => nil, :y => [1,2,3]}.sql_or)[1...-1].split(' OR ').sort.should == ['(x IS NULL)', '(y IN (1, 2, 3))']
229
+ end
230
+
231
+ it "should support arrays with all two pairs the same as hashes" do
232
+ @d.l([[:x, 100],[:y, 'a']]).should == '((x = 100) AND (y = \'a\'))'
233
+ @d.l([[:x, true], [:y, false]]).should == '((x = \'t\') AND (y = \'f\'))'
234
+ @d.l([[:x, nil], [:y, [1,2,3]]]).should == '((x IS NULL) AND (y IN (1, 2, 3)))'
235
+ end
236
+
237
+ it "should support sql_negate on arrays with all two pairs" do
238
+ @d.l([[:x, 100],[:y, 'a']].sql_negate).should == '((x != 100) AND (y != \'a\'))'
239
+ @d.l([[:x, true], [:y, false]].sql_negate).should == '((x != \'t\') AND (y != \'f\'))'
240
+ @d.l([[:x, nil], [:y, [1,2,3]]].sql_negate).should == '((x IS NOT NULL) AND (y NOT IN (1, 2, 3)))'
241
+ end
242
+
243
+ it "should support ~ on arrays with all two pairs" do
244
+ @d.l(~[[:x, 100],[:y, 'a']]).should == '((x != 100) OR (y != \'a\'))'
245
+ @d.l(~[[:x, true], [:y, false]]).should == '((x != \'t\') OR (y != \'f\'))'
246
+ @d.l(~[[:x, nil], [:y, [1,2,3]]]).should == '((x IS NOT NULL) OR (y NOT IN (1, 2, 3)))'
247
+ end
248
+
249
+ it "should support sql_or on arrays with all two pairs" do
250
+ @d.l([[:x, 100],[:y, 'a']].sql_or).should == '((x = 100) OR (y = \'a\'))'
251
+ @d.l([[:x, true], [:y, false]].sql_or).should == '((x = \'t\') OR (y = \'f\'))'
252
+ @d.l([[:x, nil], [:y, [1,2,3]]].sql_or).should == '((x IS NULL) OR (y IN (1, 2, 3)))'
253
+ end
254
+
255
+ it "should support Array#sql_string_join for concatenation of SQL strings" do
256
+ @d.l([:x].sql_string_join).should == '(x)'
257
+ @d.l([:x].sql_string_join(', ')).should == '(x)'
258
+ @d.l([:x, :y].sql_string_join).should == '(x || y)'
259
+ @d.l([:x, :y].sql_string_join(', ')).should == "(x || ', ' || y)"
260
+ @d.l([:x[1], :y|1].sql_string_join).should == '(x(1) || y[1])'
261
+ @d.l([:x[1], 'y.z'.lit].sql_string_join(', ')).should == "(x(1) || ', ' || y.z)"
262
+ @d.l([:x, 1, :y].sql_string_join).should == "(x || '1' || y)"
263
+ @d.l([:x, 1, :y].sql_string_join(', ')).should == "(x || ', ' || '1' || ', ' || y)"
264
+ @d.l([:x, 1, :y].sql_string_join(:y__z)).should == "(x || y.z || '1' || y.z || y)"
265
+ @d.l([:x, 1, :y].sql_string_join(1)).should == "(x || '1' || '1' || '1' || y)"
266
+ @d.l([:x, :y].sql_string_join('y.x || x.y'.lit)).should == "(x || y.x || x.y || y)"
267
+ @d.l([[:x, :y].sql_string_join, [:a, :b].sql_string_join].sql_string_join).should == "((x || y) || (a || b))"
268
+ end
269
+ end
@@ -1,8 +1,10 @@
1
1
  require File.join(File.dirname(__FILE__), 'spec_helper')
2
+ CONNECTION_POOL_DEFAULTS = {:pool_timeout=>5, :pool_sleep_time=>0.001,
3
+ :pool_reuse_connections=>:allow, :pool_convert_exceptions=>true, :max_connections=>4}
2
4
 
3
5
  context "An empty ConnectionPool" do
4
6
  setup do
5
- @cpool = ConnectionPool.new
7
+ @cpool = ConnectionPool.new(CONNECTION_POOL_DEFAULTS)
6
8
  end
7
9
 
8
10
  specify "should have no available connections" do
@@ -10,7 +12,7 @@ context "An empty ConnectionPool" do
10
12
  end
11
13
 
12
14
  specify "should have no allocated connections" do
13
- @cpool.allocated.should == {}
15
+ @cpool.allocated.should == []
14
16
  end
15
17
 
16
18
  specify "should have a created_count of zero" do
@@ -21,21 +23,22 @@ end
21
23
  context "A connection pool handling connections" do
22
24
  setup do
23
25
  @max_size = 2
24
- @cpool = ConnectionPool.new(@max_size) {:got_connection}
26
+ @cpool = ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>@max_size)) {:got_connection}
25
27
  end
26
28
 
27
29
  specify "#hold should increment #created_count" do
28
30
  @cpool.hold do
29
31
  @cpool.created_count.should == 1
30
- @cpool.hold {@cpool.created_count.should == 1}
32
+ @cpool.hold {@cpool.created_count.should == 2}
33
+ @cpool.hold {@cpool.hold {@cpool.created_count.should == 2}}
31
34
  end
32
35
  end
33
36
 
34
- specify "#hold should add the connection to the #allocated hash" do
37
+ specify "#hold should add the connection to the #allocated array" do
35
38
  @cpool.hold do
36
39
  @cpool.allocated.size.should == 1
37
40
 
38
- @cpool.allocated.values.should == [:got_connection]
41
+ @cpool.allocated.should == [[Thread.current, :got_connection]]
39
42
  end
40
43
  end
41
44
 
@@ -73,7 +76,7 @@ end
73
76
 
74
77
  context "ConnectionPool#hold" do
75
78
  setup do
76
- @pool = ConnectionPool.new {DummyConnection.new}
79
+ @pool = ConnectionPool.new(CONNECTION_POOL_DEFAULTS) {DummyConnection.new}
77
80
  end
78
81
 
79
82
  specify "should pass the result of the connection maker proc to the supplied block" do
@@ -109,7 +112,7 @@ end
109
112
 
110
113
  context "ConnectionPool#connection_proc" do
111
114
  setup do
112
- @pool = ConnectionPool.new
115
+ @pool = ConnectionPool.new(CONNECTION_POOL_DEFAULTS)
113
116
  end
114
117
 
115
118
  specify "should be nil if no block is supplied to the pool" do
@@ -128,7 +131,7 @@ end
128
131
  context "A connection pool with a max size of 1" do
129
132
  setup do
130
133
  @invoked_count = 0
131
- @pool = ConnectionPool.new(1) {@invoked_count += 1; 'herro'}
134
+ @pool = ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>1)) {@invoked_count += 1; 'herro'}
132
135
  end
133
136
 
134
137
  specify "should let only one thread access the connection at any time" do
@@ -151,7 +154,7 @@ context "A connection pool with a max size of 1" do
151
154
  c2.should be_nil
152
155
 
153
156
  @pool.available_connections.should be_empty
154
- @pool.allocated.should == {t1 => cc}
157
+ @pool.allocated.should == [[t1, cc]]
155
158
 
156
159
  cc.gsub!('rr', 'll')
157
160
  sleep 0.5
@@ -163,7 +166,7 @@ context "A connection pool with a max size of 1" do
163
166
  c2.should == 'hello'
164
167
 
165
168
  @pool.available_connections.should be_empty
166
- @pool.allocated.should == {t2 => cc}
169
+ @pool.allocated.should == [[t2, cc]]
167
170
 
168
171
  cc.gsub!('ll', 'rr')
169
172
  sleep 0.5
@@ -204,7 +207,7 @@ end
204
207
  context "A connection pool with a max size of 5" do
205
208
  setup do
206
209
  @invoked_count = 0
207
- @pool = ConnectionPool.new(5) {@invoked_count += 1}
210
+ @pool = ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5)) {@invoked_count += 1}
208
211
  end
209
212
 
210
213
  specify "should let five threads simultaneously access separate connections" do
@@ -219,8 +222,8 @@ context "A connection pool with a max size of 5" do
219
222
  @invoked_count.should == 5
220
223
  @pool.size.should == 5
221
224
  @pool.available_connections.should be_empty
222
- @pool.allocated.should == {threads[0] => 1, threads[1] => 2, threads[2] => 3,
223
- threads[3] => 4, threads[4] => 5}
225
+ i = 0
226
+ @pool.allocated.should == threads.collect{|t| [t,i+=1]}
224
227
 
225
228
  threads[0].raise "your'e dead"
226
229
  sleep 0.1
@@ -229,7 +232,7 @@ context "A connection pool with a max size of 5" do
229
232
  sleep 0.1
230
233
 
231
234
  @pool.available_connections.should == [1, 4]
232
- @pool.allocated.should == {threads[1] => 2, threads[2] => 3, threads[4] => 5}
235
+ @pool.allocated.should == [[threads[1], 2], [threads[2], 3], [threads[4], 5]]
233
236
 
234
237
  stop = true
235
238
  sleep 0.2
@@ -274,7 +277,7 @@ end
274
277
  context "ConnectionPool#disconnect" do
275
278
  setup do
276
279
  @count = 0
277
- @pool = ConnectionPool.new(5) {{:id => @count += 1}}
280
+ @pool = ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5)) {{:id => @count += 1}}
278
281
  end
279
282
 
280
283
  specify "should invoke the given block for each available connection" do
@@ -338,7 +341,7 @@ end
338
341
 
339
342
  context "SingleThreadedPool" do
340
343
  setup do
341
- @pool = SingleThreadedPool.new {1234}
344
+ @pool = SingleThreadedPool.new(CONNECTION_POOL_DEFAULTS){1234}
342
345
  end
343
346
 
344
347
  specify "should provide a #hold method" do
@@ -355,4 +358,4 @@ context "SingleThreadedPool" do
355
358
  conn.should == 1234
356
359
  @pool.conn.should be_nil
357
360
  end
358
- end
361
+ end
@@ -1,19 +1,169 @@
1
- require File.join(File.dirname(__FILE__), 'spec_helper')
2
-
3
- context "Enumerable#send_each" do
4
- specify "should send the supplied method to each item" do
5
- a = ['abbc', 'bbccdd', 'hebtre']
6
- a.send_each(:gsub!, 'b', '_')
7
- a.should == ['a__c', '__ccdd', 'he_tre']
8
- end
9
- end
10
-
11
- context "Range#interval" do
12
- specify "should return the interval between the beginning and end of the range" do
13
- (1..10).interval.should == 9
14
-
15
- r = rand(100000) + 10
16
- t1 = Time.now; t2 = t1 + r
17
- (t1..t2).interval.should == r
18
- end
19
- end
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ context "Array#extract_options!" do
4
+ specify "should pop the last item if it is a hash" do
5
+ a = [1,2,{1=>2}]
6
+ a.extract_options!.should == {1=>2}
7
+ a.should == [1,2]
8
+ end
9
+
10
+ specify "should return an empty hash if the last item is not a hash" do
11
+ a = [1,2]
12
+ a.extract_options!.should == {}
13
+ a.should == [1,2]
14
+ end
15
+ end
16
+
17
+ context "Enumerable#send_each" do
18
+ specify "should send the supplied method to each item" do
19
+ a = ['abbc', 'bbccdd', 'hebtre']
20
+ a.send_each(:gsub!, 'b', '_')
21
+ a.should == ['a__c', '__ccdd', 'he_tre']
22
+ end
23
+ end
24
+
25
+ context "Range#interval" do
26
+ specify "should return the interval between the beginning and end for an inclusive range" do
27
+ (1..10).interval.should == 9
28
+
29
+ r = rand(100000) + 10
30
+ t1 = Time.now; t2 = t1 + r
31
+ (t1..t2).interval.should == r
32
+ end
33
+
34
+ specify "should return the interval between the beginning and end for an exclusive range" do
35
+ (1...10).interval.should == 8
36
+
37
+ r = rand(100000) + 10
38
+ t1 = Time.now; t2 = t1 + r
39
+ (t1...t2).interval.should == r - 1
40
+ end
41
+ end
42
+
43
+ context "Module#class_attr_reader" do
44
+ specify "it should create instance methods that call class methods of the same name" do
45
+ @c = Class.new do
46
+ def self.x; 1; end
47
+ class_attr_reader :x
48
+ end
49
+ @c.new.x.should == 1
50
+ def @c.x; 2; end
51
+ @c.new.x.should == 2
52
+ end
53
+ end
54
+
55
+ context "Module#metaalias" do
56
+ specify "it should create aliases of singleton/class methods" do
57
+ @c = Class.new do
58
+ def self.x; 1; end
59
+ metaalias :y, :x
60
+ end
61
+ @c.y.should == 1
62
+ def @c.x; 2; end
63
+ @c.y.should == 1
64
+ end
65
+ end
66
+
67
+ context "Module#metaattr_reader" do
68
+ specify "it should create attr_readers of singleton/class methods" do
69
+ @c = Class.new do
70
+ @y = 1
71
+ @x = 2
72
+ metaattr_reader :y, :x
73
+ end
74
+ @c.y.should == 1
75
+ @c.x.should == 2
76
+ end
77
+ end
78
+
79
+ context "Module#metaprivate" do
80
+ specify "it should create aliases of singleton/class methods" do
81
+ @c = Class.new do
82
+ def self.x; 1; end
83
+ end
84
+ @c.x.should == 1
85
+ @c.class_eval do
86
+ metaprivate :x
87
+ end
88
+ proc{@c.x}.should raise_error(NoMethodError)
89
+ end
90
+ end
91
+
92
+ context "Object#is_one_of?" do
93
+ specify "it should be true if the object is one of the classes" do
94
+ 1.is_one_of?(Numeric, Array).should == true
95
+ [].is_one_of?(Numeric, Array).should == true
96
+ {}.is_one_of?(Numeric, Enumerable).should == true
97
+ end
98
+
99
+ specify "it should be false if the object is not one of the classes" do
100
+ 'a'.is_one_of?(Numeric, Array).should == false
101
+ Object.new.is_one_of?(Numeric, Array).should == false
102
+ end
103
+ end
104
+
105
+ context "Object#blank?" do
106
+ specify "it should be true if the object responds true to empty?" do
107
+ [].blank?.should == true
108
+ {}.blank?.should == true
109
+ o = Object.new
110
+ def o.empty?; true; end
111
+ o.blank?.should == true
112
+ end
113
+
114
+ specify "it should be false if the object doesn't respond true to empty?" do
115
+ [2].blank?.should == false
116
+ {1=>2}.blank?.should == false
117
+ Object.new.blank?.should == false
118
+ end
119
+ end
120
+
121
+ context "Numeric#blank?" do
122
+ specify "it should always be false" do
123
+ 1.blank?.should == false
124
+ 0.blank?.should == false
125
+ -1.blank?.should == false
126
+ 1.0.blank?.should == false
127
+ 0.0.blank?.should == false
128
+ -1.0.blank?.should == false
129
+ 10000000000000000.blank?.should == false
130
+ -10000000000000000.blank?.should == false
131
+ 10000000000000000.0.blank?.should == false
132
+ -10000000000000000.0.blank?.should == false
133
+ end
134
+ end
135
+
136
+ context "NilClass#blank?" do
137
+ specify "it should always be true" do
138
+ nil.blank?.should == true
139
+ end
140
+ end
141
+
142
+ context "TrueClass#blank?" do
143
+ specify "it should always be false" do
144
+ true.blank?.should == false
145
+ end
146
+ end
147
+
148
+ context "FalseClass#blank?" do
149
+ specify "it should always be true" do
150
+ false.blank?.should == true
151
+ end
152
+ end
153
+
154
+ context "FalseClass#blank?" do
155
+ specify "it should be true if the string is empty" do
156
+ ''.blank?.should == true
157
+ end
158
+ specify "it should be true if the string is composed of just whitespace" do
159
+ ' '.blank?.should == true
160
+ "\r\n\t".blank?.should == true
161
+ (' '*4000).blank?.should == true
162
+ ("\r\n\t"*4000).blank?.should == true
163
+ end
164
+ specify "it should be false if the string has any non whitespace characters" do
165
+ '1'.blank?.should == false
166
+ ("\r\n\t"*4000 + 'a').blank?.should == false
167
+ ("\r\na\t"*4000).blank?.should == false
168
+ end
169
+ end