rover-df 0.1.1 → 0.2.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b003d311b623fdd38fee4c6fa76129ad4bba042e8193c1872928cb05085daad3
4
- data.tar.gz: d0c8c04b2a8aec3ea5b7616cbcda61f03a12c96fc8f9a0c7aa29fc898948b759
3
+ metadata.gz: 0a96f5fa610232beb50eb2d22cd87b52627dfda44139e618fb0fa5d82f4d90fa
4
+ data.tar.gz: 899ae175705f7195a994c0bfd19fd021334404d07440f05153c08be5fa08c11b
5
5
  SHA512:
6
- metadata.gz: 8033d8ae9e5fb8c8e767ba68897d37745cc5d35a7a82cb2847e2b1d2c3adf8eeb406914cd47949d8f4c3f21307617ab550f435e7a5c257fe1187ed47dd943829
7
- data.tar.gz: acfdca4ad081e2722c4b5269824de123d26aadab28532837d2bfc717c2ca263f73dc4335963beae654b24d4c17cebbefdcce761a946f391340a306c9ca2a8c9b
6
+ metadata.gz: dc61f769ce5bac5fcda65dcc25fb940f7bf9f81ac168029748b5ccf8bfb896008f0836f9523ca3785e22782dff3f4d8dccc19ae823f944391c47df41fd88b3ec
7
+ data.tar.gz: 5a0c7e5e77233ef8bf7b4df23d711ec22a2e85165715ca330344a0b6cd5bef99e571256496e9c6f6037bf0fc0c771b4e951d91f0a85c17211127649d6e246878
data/CHANGELOG.md CHANGED
@@ -1,3 +1,33 @@
1
+ ## 0.2.4 (2021-06-03)
2
+
3
+ - Added grouping for `std` and `var`
4
+ - Fixed `==` for data frames
5
+ - Fixed error with `first` and `last` for data frames
6
+ - Fixed error with `last` when vector size is smaller than `n`
7
+
8
+ ## 0.2.3 (2021-02-08)
9
+
10
+ - Added `select`, `reject`, and `map!` methods to vectors
11
+
12
+ ## 0.2.2 (2021-01-01)
13
+
14
+ - Added line, pie, area, and bar charts
15
+ - Added `|` and `^` for vectors
16
+ - Fixed typecasting with `map`
17
+
18
+ ## 0.2.1 (2020-11-23)
19
+
20
+ - Added `plot` method to data frames
21
+ - Improved error message when too few headers
22
+
23
+ ## 0.2.0 (2020-08-17)
24
+
25
+ - Added `numeric?` and `zip` methods to vectors
26
+ - Changed group calculations to return a data frame instead of a hash
27
+ - Changed `each_row` to return enumerator
28
+ - Improved inspect
29
+ - Fixed `any?`, `all?`, and `uniq` for boolean vectors
30
+
1
31
  ## 0.1.1 (2020-06-10)
2
32
 
3
33
  - Added methods and options for types
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2020 Andrew Kane
1
+ Copyright (c) 2020-2021 Andrew Kane
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -4,7 +4,9 @@ Simple, powerful data frames for Ruby
4
4
 
5
5
  :mountain: Designed for data exploration and machine learning, and powered by [Numo](https://github.com/ruby-numo/numo-narray)
6
6
 
7
- [![Build Status](https://travis-ci.org/ankane/rover.svg?branch=master)](https://travis-ci.org/ankane/rover)
7
+ :evergreen_tree: Uses [Vega](https://github.com/ankane/vega) for visualization
8
+
9
+ [![Build Status](https://github.com/ankane/rover/workflows/build/badge.svg?branch=master)](https://github.com/ankane/rover/actions)
8
10
 
9
11
  ## Installation
10
12
 
@@ -121,30 +123,53 @@ df[1..3]
121
123
  df[[1, 4, 5]]
122
124
  ```
123
125
 
126
+ Iterate over rows
127
+
128
+ ```ruby
129
+ df.each_row { |row| ... }
130
+ ```
131
+
132
+ Iterate over a column
133
+
134
+ ```ruby
135
+ df[:a].each { |item| ... }
136
+ # or
137
+ df[:a].each_with_index { |item, index| ... }
138
+ ```
139
+
124
140
  ## Filtering
125
141
 
126
142
  Filter on a condition
127
143
 
128
144
  ```ruby
145
+ df[df[:a] == 100]
146
+ df[df[:a] != 100]
129
147
  df[df[:a] > 100]
148
+ df[df[:a] >= 100]
149
+ df[df[:a] < 100]
150
+ df[df[:a] <= 100]
130
151
  ```
131
152
 
132
- And
153
+ In
133
154
 
134
155
  ```ruby
135
- df[df[:a] > 100 & df[:b] == "one"]
156
+ df[df[:a].in?([1, 2, 3])]
157
+ df[df[:a].in?(1..3)]
158
+ df[df[:a].in?(["a", "b", "c"])]
136
159
  ```
137
160
 
138
- Or
161
+ Not in
139
162
 
140
163
  ```ruby
141
- df[df[:a] > 100 | df[:b] == "one"]
164
+ df[!df[:a].in?([1, 2, 3])]
142
165
  ```
143
166
 
144
- Not
167
+ And, or, and exclusive or
145
168
 
146
169
  ```ruby
147
- df[df[:a] != 100]
170
+ df[(df[:a] > 100) & (df[:b] == "one")] # and
171
+ df[(df[:a] > 100) | (df[:b] == "one")] # or
172
+ df[(df[:a] > 100) ^ (df[:b] == "one")] # xor
148
173
  ```
149
174
 
150
175
  ## Operations
@@ -170,6 +195,8 @@ df[:a].median
170
195
  df[:a].percentile(90)
171
196
  df[:a].min
172
197
  df[:a].max
198
+ df[:a].std
199
+ df[:a].var
173
200
  ```
174
201
 
175
202
  Count occurrences
@@ -204,6 +231,26 @@ Multiple groups
204
231
  df.group([:a, :b]).count
205
232
  ```
206
233
 
234
+ ## Visualization
235
+
236
+ Add [Vega](https://github.com/ankane/vega) to your application’s Gemfile:
237
+
238
+ ```ruby
239
+ gem 'vega'
240
+ ```
241
+
242
+ And use:
243
+
244
+ ```ruby
245
+ df.plot(:a, :b)
246
+ ```
247
+
248
+ Specify the chart type (`line`, `pie`, `column`, `bar`, `area`, or `scatter`)
249
+
250
+ ```ruby
251
+ df.plot(:a, :b, type: "pie")
252
+ ```
253
+
207
254
  ## Updating Data
208
255
 
209
256
  Add a new column
@@ -228,6 +275,14 @@ df[:a][0..2] = 1
228
275
  df[:a][0..2] = [1, 2, 3]
229
276
  ```
230
277
 
278
+ Update all elements
279
+
280
+ ```ruby
281
+ df[:a] = df[:a].map { |v| v.gsub("a", "b") }
282
+ # or
283
+ df[:a].map! { |v| v.gsub("a", "b") }
284
+ ```
285
+
231
286
  Update elements matching a condition
232
287
 
233
288
  ```ruby
@@ -340,7 +395,7 @@ df.to_csv
340
395
 
341
396
  ## Types
342
397
 
343
- Pass column types when creating a data frame
398
+ You can specify column types when creating a data frame
344
399
 
345
400
  ```ruby
346
401
  Rover::DataFrame.new(data, types: {"a" => :int, "b" => :float})
data/lib/rover.rb CHANGED
@@ -11,12 +11,12 @@ module Rover
11
11
  class << self
12
12
  def read_csv(path, types: nil, **options)
13
13
  require "csv"
14
- csv_to_df(CSV.read(path, **csv_options(options)), types: types)
14
+ csv_to_df(CSV.read(path, **csv_options(options)), types: types, headers: options[:headers])
15
15
  end
16
16
 
17
17
  def parse_csv(str, types: nil, **options)
18
18
  require "csv"
19
- csv_to_df(CSV.parse(str, **csv_options(options)), types: types)
19
+ csv_to_df(CSV.parse(str, **csv_options(options)), types: types, headers: options[:headers])
20
20
  end
21
21
 
22
22
  private
@@ -28,7 +28,11 @@ module Rover
28
28
  options
29
29
  end
30
30
 
31
- def csv_to_df(table, types: nil)
31
+ def csv_to_df(table, types: nil, headers: nil)
32
+ if headers && headers.size < table.headers.size
33
+ raise ArgumentError, "Expected #{table.headers.size} headers, got #{headers.size}"
34
+ end
35
+
32
36
  table.by_col!
33
37
  data = {}
34
38
  table.each do |k, v|
@@ -72,6 +72,7 @@ module Rover
72
72
  # multiple columns
73
73
  df = DataFrame.new
74
74
  where.each do |k|
75
+ check_column(k, true)
75
76
  df[k] = @vectors[k]
76
77
  end
77
78
  df
@@ -81,8 +82,9 @@ module Rover
81
82
  end
82
83
  end
83
84
 
84
- # return each row as a hash
85
85
  def each_row
86
+ return enum_for(:each_row) unless block_given?
87
+
86
88
  size.times do |i|
87
89
  yield @vectors.map { |k, v| [k, v[i]] }.to_h
88
90
  end
@@ -161,7 +163,7 @@ module Rover
161
163
  last(n)
162
164
  end
163
165
 
164
- def first(n = nil)
166
+ def first(n = 1)
165
167
  new_vectors = {}
166
168
  @vectors.each do |k, v|
167
169
  new_vectors[k] = v.first(n)
@@ -169,7 +171,7 @@ module Rover
169
171
  DataFrame.new(new_vectors)
170
172
  end
171
173
 
172
- def last(n = nil)
174
+ def last(n = 1)
173
175
  new_vectors = {}
174
176
  @vectors.each do |k, v|
175
177
  new_vectors[k] = v.last(n)
@@ -236,7 +238,12 @@ module Rover
236
238
  # for IRuby
237
239
  def to_html
238
240
  require "iruby"
239
- IRuby::HTML.table(to_h)
241
+ if size > 7
242
+ # pass 8 rows so maxrows is applied
243
+ IRuby::HTML.table((self[0..4] + self[-4..-1]).to_h, maxrows: 7)
244
+ else
245
+ IRuby::HTML.table(to_h)
246
+ end
240
247
  end
241
248
 
242
249
  # TODO handle long text better
@@ -247,18 +254,19 @@ module Rover
247
254
  line_start = 0
248
255
  spaces = 2
249
256
 
257
+ summarize = size >= 30
258
+
250
259
  @vectors.each do |k, v|
251
- v = v.first(5).to_a
260
+ v = summarize ? v.first(5).to_a + ["..."] + v.last(5).to_a : v.to_a
252
261
  width = ([k] + v).map(&:to_s).map(&:size).max
253
262
  width = 3 if width < 3
254
263
 
255
264
  if lines.empty? || lines[-2].map { |l| l.size + spaces }.sum + width > 120
256
265
  line_start = lines.size
257
266
  lines << []
258
- [size, 5].min.times do |i|
267
+ v.size.times do |i|
259
268
  lines << []
260
269
  end
261
- lines << [] if size > 5
262
270
  lines << []
263
271
  end
264
272
 
@@ -266,7 +274,6 @@ module Rover
266
274
  v.each_with_index do |v2, i|
267
275
  lines[line_start + 1 + i] << "%#{width}s" % v2.to_s
268
276
  end
269
- lines[line_start + 6] << "%#{width}s" % "..." if size > 5
270
277
  end
271
278
 
272
279
  lines.pop
@@ -290,11 +297,11 @@ module Rover
290
297
  dup.sort_by!(&block)
291
298
  end
292
299
 
293
- def group(columns)
294
- Group.new(self, columns)
300
+ def group(*columns)
301
+ Group.new(self, columns.flatten)
295
302
  end
296
303
 
297
- [:max, :min, :median, :mean, :percentile, :sum].each do |name|
304
+ [:max, :min, :median, :mean, :percentile, :sum, :std, :var].each do |name|
298
305
  define_method(name) do |column, *args|
299
306
  check_column(column)
300
307
  self[column].send(name, *args)
@@ -353,7 +360,89 @@ module Rover
353
360
  def ==(other)
354
361
  size == other.size &&
355
362
  keys == other.keys &&
356
- keys.all? { |k| self[k] == other[k] }
363
+ keys.all? { |k| self[k].to_numo == other[k].to_numo }
364
+ end
365
+
366
+ def plot(x = nil, y = nil, type: nil)
367
+ require "vega"
368
+
369
+ raise ArgumentError, "Must specify columns" if keys.size != 2 && (!x || !y)
370
+ x ||= keys[0]
371
+ y ||= keys[1]
372
+ type ||= begin
373
+ if self[x].numeric? && self[y].numeric?
374
+ "scatter"
375
+ elsif types[x] == :object && self[y].numeric?
376
+ "column"
377
+ else
378
+ raise "Cannot determine type. Use the type option."
379
+ end
380
+ end
381
+ data = self[[x, y]]
382
+
383
+ case type
384
+ when "line", "area"
385
+ x_type =
386
+ if data[x].numeric?
387
+ "quantitative"
388
+ elsif data[x].all? { |v| v.is_a?(Date) || v.is_a?(Time) }
389
+ "temporal"
390
+ else
391
+ "nominal"
392
+ end
393
+
394
+ scale = x_type == "temporal" ? {type: "utc"} : {}
395
+
396
+ Vega.lite
397
+ .data(data)
398
+ .mark(type: type, tooltip: true, interpolate: "cardinal", point: {size: 60})
399
+ .encoding(
400
+ x: {field: x, type: x_type, scale: scale},
401
+ y: {field: y, type: "quantitative"}
402
+ )
403
+ .config(axis: {labelFontSize: 12})
404
+ when "pie"
405
+ Vega.lite
406
+ .data(data)
407
+ .mark(type: "arc", tooltip: true)
408
+ .encoding(
409
+ color: {field: x, type: "nominal", sort: "none", axis: {title: nil}, legend: {labelFontSize: 12}},
410
+ theta: {field: y, type: "quantitative"}
411
+ )
412
+ .view(stroke: nil)
413
+ when "column"
414
+ Vega.lite
415
+ .data(data)
416
+ .mark(type: "bar", tooltip: true)
417
+ .encoding(
418
+ # TODO determine label angle
419
+ x: {field: x, type: "nominal", sort: "none", axis: {labelAngle: 0}},
420
+ y: {field: y, type: "quantitative"}
421
+ )
422
+ .config(axis: {labelFontSize: 12})
423
+ when "bar"
424
+ Vega.lite
425
+ .data(data)
426
+ .mark(type: "bar", tooltip: true)
427
+ .encoding(
428
+ # TODO determine label angle
429
+ y: {field: x, type: "nominal", sort: "none", axis: {labelAngle: 0}},
430
+ x: {field: y, type: "quantitative"}
431
+ )
432
+ .config(axis: {labelFontSize: 12})
433
+ when "scatter"
434
+ Vega.lite
435
+ .data(data)
436
+ .mark(type: "circle", tooltip: true)
437
+ .encoding(
438
+ x: {field: x, type: "quantitative", scale: {zero: false}},
439
+ y: {field: y, type: "quantitative", scale: {zero: false}},
440
+ size: {value: 60}
441
+ )
442
+ .config(axis: {labelFontSize: 12})
443
+ else
444
+ raise ArgumentError, "Invalid type: #{type}"
445
+ end
357
446
  end
358
447
 
359
448
  private
@@ -418,8 +507,20 @@ module Rover
418
507
  raise ArgumentError, "Missing keys: #{missing_keys.join(", ")}" if missing_keys.any?
419
508
  end
420
509
 
421
- def check_column(key)
422
- raise ArgumentError, "Missing column: #{key}" unless include?(key)
510
+ # TODO in 0.3.0
511
+ # always use did_you_mean
512
+ def check_column(key, did_you_mean = false)
513
+ unless include?(key)
514
+ if did_you_mean
515
+ if RUBY_VERSION.to_f >= 2.6
516
+ raise KeyError.new("Missing column: #{key}", receiver: self, key: key)
517
+ else
518
+ raise KeyError.new("Missing column: #{key}")
519
+ end
520
+ else
521
+ raise ArgumentError, "Missing column: #{key}"
522
+ end
523
+ end
423
524
  end
424
525
 
425
526
  def to_vector(v, size: nil, type: nil)
data/lib/rover/group.rb CHANGED
@@ -2,16 +2,23 @@ module Rover
2
2
  class Group
3
3
  def initialize(df, columns)
4
4
  @df = df
5
- @columns = Array(columns)
5
+ @columns = columns
6
6
  end
7
7
 
8
- [:count, :max, :min, :mean, :median, :percentile, :sum].each do |name|
8
+ def group(*columns)
9
+ Group.new(@df, @columns + columns.flatten)
10
+ end
11
+
12
+ [:count, :max, :min, :mean, :median, :percentile, :sum, :std, :var].each do |name|
9
13
  define_method(name) do |*args|
10
- result = {}
14
+ n = [name, args.first].compact.join("_")
15
+
16
+ rows = []
11
17
  grouped_dfs.each do |k, df|
12
- result[k] = df.send(name, *args)
18
+ rows << k.merge(n => df.send(name, *args))
13
19
  end
14
- result
20
+
21
+ DataFrame.new(rows)
15
22
  end
16
23
  end
17
24
 
@@ -26,21 +33,15 @@ module Rover
26
33
  raise ArgumentError, "Missing keys: #{missing_keys.join(", ")}" if missing_keys.any?
27
34
 
28
35
  groups = Hash.new { |hash, key| hash[key] = [] }
29
- if @columns.size == 1
30
- @df[@columns.first].each_with_index do |v, i|
31
- groups[v] << i
32
- end
33
- else
34
- i = 0
35
- @df.each_row do |row|
36
- groups[@columns.map { |c| row[c] }] << i
37
- i += 1
38
- end
36
+ i = 0
37
+ @df.each_row do |row|
38
+ groups[row.slice(*@columns)] << i
39
+ i += 1
39
40
  end
40
41
 
41
42
  result = {}
42
- groups.each do |k, indexes|
43
- result[k] = @df[indexes]
43
+ groups.keys.each do |k|
44
+ result[k] = @df[groups[k]]
44
45
  end
45
46
  result
46
47
  end
data/lib/rover/vector.rb CHANGED
@@ -44,6 +44,10 @@ module Rover
44
44
  a
45
45
  end
46
46
 
47
+ def numeric?
48
+ ![:object, :bool].include?(type)
49
+ end
50
+
47
51
  def size
48
52
  @data.size
49
53
  end
@@ -51,7 +55,7 @@ module Rover
51
55
  alias_method :count, :size
52
56
 
53
57
  def uniq
54
- Vector.new(@data.to_a.uniq)
58
+ Vector.new(to_a.uniq)
55
59
  end
56
60
 
57
61
  def missing
@@ -87,11 +91,11 @@ module Rover
87
91
  @data[k] = v
88
92
  end
89
93
 
90
- %w(+ - * / % ** &).each do |op|
94
+ %w(+ - * / % ** & | ^).each do |op|
91
95
  define_method(op) do |other|
92
96
  other = other.to_numo if other.is_a?(Vector)
93
97
  # TODO better logic
94
- if @data.is_a?(Numo::RObject)
98
+ if @data.is_a?(Numo::RObject) && !other.is_a?(Numo::RObject)
95
99
  map { |v| v.send(op, other) }
96
100
  else
97
101
  Vector.new(@data.send(op, other))
@@ -157,9 +161,22 @@ module Rover
157
161
  end
158
162
 
159
163
  def map(&block)
160
- mapped = @data.map(&block)
161
- mapped = mapped.to_a if mapped.is_a?(Numo::RObject) # re-evaluate cast
162
- Vector.new(mapped)
164
+ # convert to Ruby first to cast properly
165
+ # https://github.com/ruby-numo/numo-narray/issues/181
166
+ Vector.new(@data.to_a.map(&block))
167
+ end
168
+
169
+ def map!(&block)
170
+ @data = cast_data(@data.to_a.map(&block))
171
+ self
172
+ end
173
+
174
+ def select(&block)
175
+ Vector.new(@data.to_a.select(&block))
176
+ end
177
+
178
+ def reject(&block)
179
+ Vector.new(@data.to_a.reject(&block))
163
180
  end
164
181
 
165
182
  def tally
@@ -226,11 +243,15 @@ module Rover
226
243
  end
227
244
 
228
245
  def all?(&block)
229
- @data.to_a.all?(&block)
246
+ to_a.all?(&block)
230
247
  end
231
248
 
232
249
  def any?(&block)
233
- @data.to_a.any?(&block)
250
+ to_a.any?(&block)
251
+ end
252
+
253
+ def zip(other, &block)
254
+ to_a.zip(other.to_a, &block)
234
255
  end
235
256
 
236
257
  def first(n = 1)
@@ -242,7 +263,11 @@ module Rover
242
263
  end
243
264
 
244
265
  def last(n = 1)
245
- Vector.new(@data[-n..-1])
266
+ if n >= size
267
+ Vector.new(@data)
268
+ else
269
+ Vector.new(@data[-n..-1])
270
+ end
246
271
  end
247
272
 
248
273
  def take(n)
@@ -298,7 +323,12 @@ module Rover
298
323
  # for IRuby
299
324
  def to_html
300
325
  require "iruby"
301
- IRuby::HTML.table(to_a)
326
+ if size > 7
327
+ # pass 8 rows so maxrows is applied
328
+ IRuby::HTML.table(first(4).to_a + last(4).to_a, maxrows: 7)
329
+ else
330
+ IRuby::HTML.table(to_a)
331
+ end
302
332
  end
303
333
 
304
334
  private
data/lib/rover/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Rover
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.4"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rover-df
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-10 00:00:00.000000000 Z
11
+ date: 2021-06-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: numo-narray
@@ -16,100 +16,16 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.9.1.7
19
+ version: 0.9.1.9
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 0.9.1.7
27
- - !ruby/object:Gem::Dependency
28
- name: bundler
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: rake
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: minitest
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '5'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '5'
69
- - !ruby/object:Gem::Dependency
70
- name: activerecord
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '5'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '5'
83
- - !ruby/object:Gem::Dependency
84
- name: sqlite3
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: iruby
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- description:
112
- email: andrew@chartkick.com
26
+ version: 0.9.1.9
27
+ description:
28
+ email: andrew@ankane.org
113
29
  executables: []
114
30
  extensions: []
115
31
  extra_rdoc_files: []
@@ -127,7 +43,7 @@ homepage: https://github.com/ankane/rover
127
43
  licenses:
128
44
  - MIT
129
45
  metadata: {}
130
- post_install_message:
46
+ post_install_message:
131
47
  rdoc_options: []
132
48
  require_paths:
133
49
  - lib
@@ -142,8 +58,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
142
58
  - !ruby/object:Gem::Version
143
59
  version: '0'
144
60
  requirements: []
145
- rubygems_version: 3.1.2
146
- signing_key:
61
+ rubygems_version: 3.2.3
62
+ signing_key:
147
63
  specification_version: 4
148
64
  summary: Simple, powerful data frames for Ruby
149
65
  test_files: []