sequel_core 1.0.10 → 1.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,21 @@
1
+ === 1.1 (2008-02-15)
2
+
3
+ * Fixed Dataset#join_table to support joining of datasets (#156).
4
+
5
+ * Changed Dataset#empty? to use EXISTS condition instead of counting records, for much better performance (#158).
6
+
7
+ * Implemented insertion of multiple records in a single statement for postgres adapter. This feature is available only in postgres 8.2 and newer.
8
+
9
+ * Implemented Postgres::Database#server_version.
10
+
11
+ * Implemented Database#get, short for dataset.get(...).
12
+
13
+ * Refactored Dataset#multi_insert, added #import alias, added support for calling #multi_insert using array of columns and array of value arrays (thanks David Lee).
14
+
15
+ * Implemented Dataset#get, a replacement for select(column).first[column].
16
+
17
+ * Implemented Dataset#grep method, poor man's text search.
18
+
1
19
  === 1.0.10 (2008-02-13)
2
20
 
3
21
  * Fixed Datset#group_and_count to work inside a query block (#152).
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ include FileUtils
9
9
  # Configuration
10
10
  ##############################################################################
11
11
  NAME = "sequel_core"
12
- VERS = "1.0.10"
12
+ VERS = "1.1"
13
13
  CLEAN.include ["**/.*.sw?", "pkg/*", ".config", "doc/*", "coverage/*"]
14
14
  RDOC_OPTS = [
15
15
  "--quiet",
@@ -358,33 +358,10 @@ module Sequel
358
358
  self
359
359
  end
360
360
 
361
- def multi_insert_sql(keys, array)
362
- values = array.map {|r| "(#{literal(keys.map {|k| r[k]})})"}.join(COMMA_SEPARATOR)
363
- columns = keys.map {|c| literal(c)}.join(COMMA_SEPARATOR)
364
- "INSERT INTO #{@opts[:from]} (#{columns}) VALUES #{values}"
365
- end
366
-
367
- # Inserts multiple records into the associated table. This method can be
368
- # to efficiently insert a large amounts of records into a table. Inserts
369
- # are automatically wrapped in a transaction. If the :commit_every
370
- # option is specified, the method will generate a separate transaction
371
- # for each batch of records, e.g.:
372
- #
373
- # dataset.multi_insert(list, :commit_every => 1000)
374
- def multi_insert(list, opts = {})
375
- keys = list.first.keys
376
-
377
- if every = (opts[:commit_every] || opts[:slice])
378
- list.each_slice(every) do |s|
379
- @db.transaction do
380
- @db.execute(multi_insert_sql(keys, s))
381
- end
382
- end
383
- else
384
- @db.transaction do
385
- @db.execute(multi_insert_sql(keys, list))
386
- end
387
- end
361
+ def multi_insert_sql(columns, values)
362
+ columns = literal(columns)
363
+ values = values.map {|r| "(#{literal(r)})"}.join(COMMA_SEPARATOR)
364
+ ["INSERT INTO #{@opts[:from]} (#{columns}) VALUES #{values}"]
388
365
  end
389
366
  end
390
367
  end
@@ -263,6 +263,17 @@ module Sequel
263
263
  end
264
264
  end
265
265
 
266
+ def server_version
267
+ @server_version ||= pool.hold do |conn|
268
+ if conn.respond_to?(:server_version)
269
+ pool.hold {|c| c.server_version}
270
+ else
271
+ get(:version[]) =~ /PostgreSQL (\d+)\.(\d+)\.(\d+)/
272
+ ($1.to_i * 10000) + ($2.to_i * 100) + $3.to_i
273
+ end
274
+ end
275
+ end
276
+
266
277
  def execute_insert(sql, table, values)
267
278
  @logger.info(sql) if @logger
268
279
  @pool.hold do |conn|
@@ -428,7 +439,16 @@ module Sequel
428
439
  end
429
440
  end
430
441
  end
431
-
442
+
443
+ def multi_insert_sql(columns, values)
444
+ return super if @db.server_version < 80200
445
+
446
+ # postgresql 8.2 introduces support for insert
447
+ columns = literal(columns)
448
+ values = values.map {|r| "(#{literal(r)})"}.join(COMMA_SEPARATOR)
449
+ ["INSERT INTO #{@opts[:from]} (#{columns}) VALUES #{values}"]
450
+ end
451
+
432
452
  def insert(*values)
433
453
  @db.execute_insert(insert_sql(*values), @opts[:from],
434
454
  values.size == 1 ? values.first : values)
@@ -135,6 +135,17 @@ module Sequel
135
135
  (String === args.first) ? fetch(*args) : from(*args)
136
136
  end
137
137
 
138
+ # Returns a single value from the database, e.g.:
139
+ #
140
+ # # SELECT 1
141
+ # DB.get(1) #=> 1
142
+ #
143
+ # # SELECT version()
144
+ # DB.get(:version[]) #=> ...
145
+ def get(expr)
146
+ dataset.get(expr)
147
+ end
148
+
138
149
  # Raises a Sequel::Error::NotImplemented. This method is overriden in descendants.
139
150
  def execute(sql)
140
151
  raise NotImplementedError, "#execute should be overriden by adapters"
@@ -8,9 +8,10 @@ module Sequel
8
8
  each {|a| block[a.to_hash]}
9
9
  end
10
10
 
11
- # Returns true if the record count is 0
11
+ # Returns true if no records exists in the dataset
12
12
  def empty?
13
- count == 0
13
+ db.dataset.where(exists).get(1) == nil
14
+ # count == 0
14
15
  end
15
16
 
16
17
  # Returns the first record in the dataset.
@@ -29,6 +30,10 @@ module Sequel
29
30
  each(opts) {|r| @columns = nil; return r.values.first}
30
31
  nil
31
32
  end
33
+
34
+ def get(column)
35
+ select(column).single_value
36
+ end
32
37
 
33
38
  # Returns the first record in the dataset. If the num argument is specified,
34
39
  # an array is returned with the first <i>num</i> records.
@@ -217,29 +222,49 @@ module Sequel
217
222
  records.each {|r| csv << "#{r.join(COMMA_SEPARATOR)}\r\n"}
218
223
  csv
219
224
  end
220
-
225
+
221
226
  # Inserts multiple records into the associated table. This method can be
222
227
  # to efficiently insert a large amounts of records into a table. Inserts
223
- # are automatically wrapped in a transaction. If the :commit_every
224
- # or :slice option is specified, the method will generate a separate
225
- # transaction for each batch of records, e.g.:
228
+ # are automatically wrapped in a transaction.
229
+ #
230
+ # This method can be called either with an array of hashes:
231
+ #
232
+ # dataset.multi_insert({:x => 1}, {:x => 2})
226
233
  #
227
- # dataset.multi_insert(list, :commit_every => 1000)
228
- def multi_insert(list, opts = {})
229
- if every = (opts[:commit_every] || opts[:slice])
230
- list.each_slice(every) do |s|
231
- @db.transaction do
232
- s.each {|r| @db.execute(insert_sql(r))}
233
- # @db.execute(s.map {|r| insert_sql(r)}.join)
234
- end
235
- end
234
+ # Or with a columns array and an array of value arrays:
235
+ #
236
+ # dataset.multi_insert([:x, :y], [[1, 2], [3, 4]])
237
+ #
238
+ # The method also accepts a :slice or :commit_every option that specifies
239
+ # the number of records to insert per transaction. This is useful especially
240
+ # when inserting a large number of records, e.g.:
241
+ #
242
+ # # this will commit every 50 records
243
+ # dataset.multi_insert(lots_of_records, :slice => 50)
244
+ def multi_insert(*args)
245
+ if args[0].is_a?(Array) && args[1].is_a?(Array)
246
+ columns, values, opts = *args
236
247
  else
237
- @db.transaction do
238
- # @db.execute(list.map {|r| insert_sql(r)}.join)
239
- list.each {|r| @db.execute(insert_sql(r))}
248
+ # we assume that an array of hashes is given
249
+ hashes, opts = *args
250
+ columns = hashes.first.keys
251
+ # convert the hashes into arrays
252
+ values = hashes.map {|h| columns.map {|c| h[c]}}
253
+ end
254
+
255
+ slice_size = opts && (opts[:commit_every] || opts[:slice])
256
+
257
+ if slice_size
258
+ values.each_slice(slice_size) do |slice|
259
+ statements = multi_insert_sql(columns, slice)
260
+ @db.transaction {statements.each {|st| @db.execute(st)}}
240
261
  end
262
+ else
263
+ statements = multi_insert_sql(columns, values)
264
+ @db.transaction {statements.each {|st| @db.execute(st)}}
241
265
  end
242
266
  end
267
+ alias_method :import, :multi_insert
243
268
 
244
269
  module QueryBlockCopy #:nodoc:
245
270
  def each(*args); raise Error, "#each cannot be invoked inside a query block."; end
@@ -18,7 +18,9 @@ module Sequel
18
18
  if s =~ QUALIFIED_REGEXP
19
19
  return column
20
20
  else
21
- if (table =~ ALIASED_REGEXP)
21
+ if table.is_a?(Dataset)
22
+ table = :t1
23
+ elsif (table =~ ALIASED_REGEXP)
22
24
  table = $2
23
25
  end
24
26
  Sequel::SQL::QualifiedColumnRef.new(table, column)
@@ -341,6 +343,14 @@ module Sequel
341
343
  filter(*cond, &block)
342
344
  end
343
345
  end
346
+
347
+ def grep(cols, terms)
348
+ conds = [];
349
+ cols = [cols] unless cols.is_a?(Array)
350
+ terms = [terms] unless terms.is_a?(Array)
351
+ cols.each {|c| terms.each {|t| conds << match_expr(c, t)}}
352
+ filter(conds.join(' OR '))
353
+ end
344
354
 
345
355
  # Adds a UNION clause using a second dataset object. If all is true the
346
356
  # clause used is UNION ALL, which may return duplicate rows.
@@ -380,6 +390,9 @@ module Sequel
380
390
  v = qualified_column_name(v, @opts[:last_joined_table] || first_source) if v.is_a?(Symbol)
381
391
  join_conditions[k] = v
382
392
  end
393
+ if table.is_a?(Dataset)
394
+ table = "(#{table.sql}) t1"
395
+ end
383
396
  " #{join_type} #{table} ON #{expression_list(join_conditions)}"
384
397
  end
385
398
 
@@ -524,6 +537,19 @@ module Sequel
524
537
  end
525
538
  end
526
539
  end
540
+
541
+ # Returns an array of insert statements for inserting multiple records.
542
+ # This method is used by #multi_insert to format insert statements and
543
+ # expects a keys array and and an array of value arrays.
544
+ #
545
+ # This method may be overriden by descendants.
546
+ def multi_insert_sql(columns, values)
547
+ table = @opts[:from]
548
+ columns = literal(columns)
549
+ values.map do |r|
550
+ "INSERT INTO #{table} (#{columns}) VALUES (#{literal(r)})"
551
+ end
552
+ end
527
553
 
528
554
  # Formats an UPDATE statement using the given values.
529
555
  #
@@ -600,9 +626,10 @@ module Sequel
600
626
 
601
627
  # Returns an EXISTS clause for the dataset.
602
628
  #
603
- # dataset.exists #=> "EXISTS (SELECT 1 FROM items)"
629
+ # DB.select(1).where(DB[:items].exists).sql
630
+ # #=> "SELECT 1 WHERE EXISTS (SELECT * FROM items)"
604
631
  def exists(opts = nil)
605
- "EXISTS (#{sql({:select => [1]}.merge(opts || {}))})"
632
+ "EXISTS (#{select_sql(opts)})"
606
633
  end
607
634
 
608
635
  # If given an integer, the dataset will contain only the first l results.
@@ -537,4 +537,19 @@ context "MySQL::Dataset#multi_insert" do
537
537
  {:name => nil, :value => 4}
538
538
  ]
539
539
  end
540
+
541
+ specify "should support inserting using columns and values arrays" do
542
+ @d.multi_insert([:name, :value], [['abc', 1], ['def', 2]])
543
+
544
+ MYSQL_DB.sqls.should == [
545
+ 'BEGIN',
546
+ "INSERT INTO items (`name`, `value`) VALUES ('abc', 1), ('def', 2)",
547
+ 'COMMIT'
548
+ ]
549
+
550
+ @d.all.should == [
551
+ {:name => 'abc', :value => 1},
552
+ {:name => 'def', :value => 2}
553
+ ]
554
+ end
540
555
  end
@@ -24,6 +24,10 @@ context "A PostgreSQL database" do
24
24
  @db.disconnect
25
25
  @db.pool.size.should == 0
26
26
  end
27
+
28
+ specify "should provide the server version" do
29
+ @db.server_version.should > 70000
30
+ end
27
31
  end
28
32
 
29
33
  context "A PostgreSQL dataset" do
@@ -246,7 +250,7 @@ context "A PostgreSQL database" do
246
250
  end
247
251
  end
248
252
 
249
- context "A PostgreSSQL database" do
253
+ context "A PostgreSQL database" do
250
254
  setup do
251
255
  end
252
256
 
@@ -284,4 +288,33 @@ context "A PostgreSSQL database" do
284
288
  PGSQL_DB[:posts].full_text_search(:title, 'ruby', :language => 'french').sql.should ==
285
289
  "SELECT * FROM posts WHERE (to_tsvector('french', \"title\") @@ to_tsquery('french', 'ruby'))"
286
290
  end
291
+ end
292
+
293
+ context "Postgres::Dataset#multi_insert_sql / #import" do
294
+ setup do
295
+ @ds = PGSQL_DB[:test]
296
+ end
297
+
298
+ specify "should return separate insert statements if server_version < 80200" do
299
+ @ds.db.meta_def(:server_version) {80199}
300
+
301
+ @ds.multi_insert_sql([:x, :y], [[1, 2], [3, 4]]).should == [
302
+ 'INSERT INTO test ("x", "y") VALUES (1, 2)',
303
+ 'INSERT INTO test ("x", "y") VALUES (3, 4)'
304
+ ]
305
+ end
306
+
307
+ specify "should a single insert statement if server_version >= 80200" do
308
+ @ds.db.meta_def(:server_version) {80200}
309
+
310
+ @ds.multi_insert_sql([:x, :y], [[1, 2], [3, 4]]).should == [
311
+ 'INSERT INTO test ("x", "y") VALUES (1, 2), (3, 4)'
312
+ ]
313
+
314
+ @ds.db.meta_def(:server_version) {80201}
315
+
316
+ @ds.multi_insert_sql([:x, :y], [[1, 2], [3, 4]]).should == [
317
+ 'INSERT INTO test ("x", "y") VALUES (1, 2), (3, 4)'
318
+ ]
319
+ end
287
320
  end
@@ -846,4 +846,26 @@ context "Database#inspect" do
846
846
  specify "should include the class name and the connection url" do
847
847
  @db.inspect.should == '#<DummyDatabase: "blah://blahblah/blah">'
848
848
  end
849
+ end
850
+
851
+ context "Database#get" do
852
+ setup do
853
+ @c = Class.new(DummyDatabase) do
854
+ def dataset
855
+ ds = super
856
+ ds.meta_def(:get) {|c| @db.execute select(c).sql; c}
857
+ ds
858
+ end
859
+ end
860
+
861
+ @db = @c.new
862
+ end
863
+
864
+ specify "should use Dataset#get to get a single value" do
865
+ @db.get(1).should == 1
866
+ @db.sqls.last.should == 'SELECT 1'
867
+
868
+ @db.get(:version[])
869
+ @db.sqls.last.should == 'SELECT version()'
870
+ end
849
871
  end
data/spec/dataset_spec.rb CHANGED
@@ -342,7 +342,7 @@ context "Dataset#where" do
342
342
  specify "should accept a subquery for an EXISTS clause" do
343
343
  a = @dataset.filter {:price < 100}
344
344
  @dataset.filter(a.exists).sql.should ==
345
- 'SELECT * FROM test WHERE EXISTS (SELECT 1 FROM test WHERE (price < 100))'
345
+ 'SELECT * FROM test WHERE EXISTS (SELECT * FROM test WHERE (price < 100))'
346
346
  end
347
347
 
348
348
  specify "should accept proc expressions" do
@@ -1048,22 +1048,34 @@ context "Dataset#group_and_count" do
1048
1048
  end
1049
1049
 
1050
1050
  context "Dataset#empty?" do
1051
- specify "should return true if #count == 0" do
1052
- @c = Class.new(Sequel::Dataset) do
1053
- def count
1054
- 0
1051
+ specify "should return true if records exist in the dataset" do
1052
+ @db = Sequel::Database.new
1053
+ @db.meta_def(:execute) {|sql| puts "blah";@sqls ||=[]; @sqls << sql}
1054
+ @db.meta_def(:sqls) {@sqls ||= []}
1055
+
1056
+ $cccc = Class.new(Sequel::Dataset) do
1057
+ def fetch_rows(sql)
1058
+ @db.execute(sql)
1059
+ yield(:x => 'blah')
1055
1060
  end
1056
1061
  end
1057
- @dataset = @c.new(nil).from(:test)
1058
- @dataset.empty?.should be_true
1059
-
1060
- @c = Class.new(Sequel::Dataset) do
1061
- def count
1062
- 1
1063
- end
1062
+
1063
+ @db.meta_def(:dataset) do
1064
+ $cccc.new(self)
1064
1065
  end
1065
- @dataset = @c.new(nil).from(:test)
1066
- @dataset.empty?.should be_false
1066
+
1067
+ @dataset = Sequel::Dataset.new(@db).from(:test)
1068
+
1069
+ @dataset.should_not be_empty
1070
+ @db.sqls.last.should == 'SELECT 1 WHERE EXISTS (SELECT * FROM test)'
1071
+
1072
+ @db.meta_def(:dataset) do
1073
+ ds = $cccc.new(self)
1074
+ ds.meta_def(:get) {|c| nil}
1075
+ ds
1076
+ end
1077
+
1078
+ @dataset.should be_empty
1067
1079
  end
1068
1080
  end
1069
1081
 
@@ -1170,6 +1182,17 @@ context "Dataset#join_table" do
1170
1182
  should raise_error(Sequel::Error)
1171
1183
  end
1172
1184
 
1185
+ specify "should support joining datasets" do
1186
+ ds = Sequel::Dataset.new(nil).from(:categories)
1187
+
1188
+ @d.join_table(:left_outer, ds, :item_id => :id).sql.should ==
1189
+ 'SELECT * FROM items LEFT OUTER JOIN (SELECT * FROM categories) t1 ON (t1.item_id = items.id)'
1190
+
1191
+ ds.filter!(:active => true)
1192
+
1193
+ @d.join_table(:left_outer, ds, :item_id => :id).sql.should ==
1194
+ 'SELECT * FROM items LEFT OUTER JOIN (SELECT * FROM categories WHERE (active = \'t\')) t1 ON (t1.item_id = items.id)'
1195
+ end
1173
1196
  end
1174
1197
 
1175
1198
  context "Dataset#[]=" do
@@ -1575,7 +1598,34 @@ context "Dataset#single_value" do
1575
1598
  specify "should return nil" do
1576
1599
  @e.single_value.should be_nil
1577
1600
  end
1601
+ end
1578
1602
 
1603
+ context "Dataset#get" do
1604
+ setup do
1605
+ @c = Class.new(Sequel::Dataset) do
1606
+ attr_reader :last_sql
1607
+
1608
+ def fetch_rows(sql)
1609
+ @last_sql = sql
1610
+ yield(:name => sql)
1611
+ end
1612
+ end
1613
+
1614
+ @d = @c.new(nil).from(:test)
1615
+ end
1616
+
1617
+ specify "should select the specified column and fetch its value" do
1618
+ @d.get(:name).should == "SELECT name FROM test"
1619
+ @d.get(:abc).should == "SELECT abc FROM test" # the first available value is returned always
1620
+ end
1621
+
1622
+ specify "should work with filters" do
1623
+ @d.filter(:id => 1).get(:name).should == "SELECT name FROM test WHERE (id = 1)"
1624
+ end
1625
+
1626
+ specify "should work with aliased fields" do
1627
+ @d.get(:x__b.as(:name)).should == "SELECT x.b AS name FROM test"
1628
+ end
1579
1629
  end
1580
1630
 
1581
1631
  context "Dataset#set_row_proc" do
@@ -2085,6 +2135,42 @@ context "Dataset#multi_insert" do
2085
2135
  'COMMIT'
2086
2136
  ]
2087
2137
  end
2138
+
2139
+ specify "should accept a columns array and a values array" do
2140
+ @ds.multi_insert([:x, :y], [[1, 2], [3, 4]])
2141
+ @db.sqls.should == [
2142
+ 'BEGIN',
2143
+ "INSERT INTO items (x, y) VALUES (1, 2)",
2144
+ "INSERT INTO items (x, y) VALUES (3, 4)",
2145
+ 'COMMIT'
2146
+ ]
2147
+ end
2148
+
2149
+ specify "should accept a columns array and a values array with slice option" do
2150
+ @ds.multi_insert([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice => 2)
2151
+ @db.sqls.should == [
2152
+ 'BEGIN',
2153
+ "INSERT INTO items (x, y) VALUES (1, 2)",
2154
+ "INSERT INTO items (x, y) VALUES (3, 4)",
2155
+ 'COMMIT',
2156
+ 'BEGIN',
2157
+ "INSERT INTO items (x, y) VALUES (5, 6)",
2158
+ 'COMMIT'
2159
+ ]
2160
+ end
2161
+
2162
+ specify "should be aliased by #import" do
2163
+ @ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice => 2)
2164
+ @db.sqls.should == [
2165
+ 'BEGIN',
2166
+ "INSERT INTO items (x, y) VALUES (1, 2)",
2167
+ "INSERT INTO items (x, y) VALUES (3, 4)",
2168
+ 'COMMIT',
2169
+ 'BEGIN',
2170
+ "INSERT INTO items (x, y) VALUES (5, 6)",
2171
+ 'COMMIT'
2172
+ ]
2173
+ end
2088
2174
  end
2089
2175
 
2090
2176
  context "Dataset#query" do
@@ -2698,3 +2784,48 @@ context "Dataset#all" do
2698
2784
  a.should == [1, 3, "SELECT * FROM items"]
2699
2785
  end
2700
2786
  end
2787
+
2788
+ context "Dataset#grep" do
2789
+ setup do
2790
+ @ds = Sequel::Dataset.new(nil).from(:posts)
2791
+ end
2792
+
2793
+ specify "should format a SQL filter correctly" do
2794
+ @ds.grep(:title, 'ruby').sql.should ==
2795
+ "SELECT * FROM posts WHERE (title LIKE 'ruby')"
2796
+ end
2797
+
2798
+ specify "should support multiple columns" do
2799
+ @ds.grep([:title, :body], 'ruby').sql.should ==
2800
+ "SELECT * FROM posts WHERE ((title LIKE 'ruby') OR (body LIKE 'ruby'))"
2801
+ end
2802
+
2803
+ specify "should support multiple search terms" do
2804
+ @ds.grep(:title, ['abc', 'def']).sql.should ==
2805
+ "SELECT * FROM posts WHERE ((title LIKE 'abc') OR (title LIKE 'def'))"
2806
+ end
2807
+
2808
+ specify "should support multiple columns and search terms" do
2809
+ @ds.grep([:title, :body], ['abc', 'def']).sql.should ==
2810
+ "SELECT * FROM posts WHERE ((title LIKE 'abc') OR (title LIKE 'def') OR (body LIKE 'abc') OR (body LIKE 'def'))"
2811
+ end
2812
+
2813
+ specify "should support regexps if the dataset allows it" do
2814
+ @ds.meta_def(:match_expr) do |l, r|
2815
+ case r
2816
+ when String
2817
+ "(#{literal(l)} LIKE #{literal(r)})"
2818
+ when Regexp
2819
+ "(#{literal(l)} =~ #{literal(r.source)})"
2820
+ else
2821
+ raise Sequel::Error, "Unsupported match pattern class (#{r.class})."
2822
+ end
2823
+ end
2824
+
2825
+ @ds.grep(:title, /ruby/).sql.should ==
2826
+ "SELECT * FROM posts WHERE (title =~ 'ruby')"
2827
+
2828
+ @ds.grep(:title, [/^ruby/, 'ruby']).sql.should ==
2829
+ "SELECT * FROM posts WHERE ((title =~ '^ruby') OR (title LIKE 'ruby'))"
2830
+ end
2831
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel_core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.10
4
+ version: "1.1"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-02-14 00:00:00 +02:00
12
+ date: 2008-02-15 00:00:00 +02:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency