tablestakes 0.9.4 → 0.10.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d469293fdfb6e377ce2dbdc2eff758511d9e37c6
4
- data.tar.gz: 4bc603714a7674830b9246232a7c878e81bc343c
3
+ metadata.gz: 8bd18629eb73a93ba19287533d8b493f524e0bd7
4
+ data.tar.gz: 0e18ca987924cc39fd4472a2b82f4c45b2b2c2d3
5
5
  SHA512:
6
- metadata.gz: 48615113c3f2324ec8cf88d835ba8a480564b60c275c97ec6d83061cb007920db9e527a048fc8e4668072de1507e2cd82ffc9a7077d95dc1270c234ec2869b7e
7
- data.tar.gz: 4bf01417604256a1ec73ae21ef8a2697534d3c6e7ef9a6a060d8611bbf0daaa38e6cce8f0f6bfa34e26f19311f296abdb9a0e1b3944bd17d17613ec840ffc1fc
6
+ metadata.gz: fbde53ed596e58e5e95d753b71a0ccb53214d362b152803703a72e154fe462c34d540b5a5f18be099357fa674593d9770dc18dd40e695b6a3d4c2cf5e7b05e17
7
+ data.tar.gz: 433d41010b0d2661d133cfdff0bf1b681f3927a43ef9b7dc0af0cc8d30e9ce6eb5ff724ebe643bfee9e629d0e14d63088f54cc09194c35fc0bd41cd298ba3950
data/README.md CHANGED
@@ -165,9 +165,10 @@ the `Table#sub` method provides a way to eliminate common garbage from
165
165
  your data such as stray characters.
166
166
 
167
167
  ```ruby
168
- cities.sub("2012 land area", /.*sq mi/, '') # deletes 'sq mi' from the 2012 land area field
168
+ cities.sub("2012 land area", /(.*) sq mi/, '\1') # deletes ' sq mi' from the end of the 2012 land area field
169
169
  ```
170
170
 
171
+
171
172
  `Table#sub` takes a regular expression and a substitute string, which
172
173
  gives some flexibility in how data is updated. Note that this is
173
174
  a method which modifies the table object.
@@ -16,7 +16,6 @@
16
16
  # serving as the header names.
17
17
 
18
18
  class Table
19
- include Enumerable
20
19
 
21
20
  # The headers attribute contains the table headers used to reference
22
21
  # columns in the +Table+. All headers are represented as +String+ types.
@@ -54,6 +53,7 @@ class Table
54
53
  # a string, then read_file
55
54
  read_file(input)
56
55
  elsif input.respond_to?(:headers)
56
+ @headers = input.headers.dup
57
57
  input.each {|row| add_row(row) }
58
58
  end
59
59
  # else create empty +Table+
@@ -63,13 +63,23 @@ class Table
63
63
  # for its calling block.
64
64
  #
65
65
  def each
66
- @table[@headers.first].each_index do |index|
67
- nextrow = []
68
- @headers.each do |col|
69
- nextrow << @table[col][index].clone
66
+
67
+ if block_given?
68
+ @table[@headers.first].each_index do |index|
69
+ nextrow = []
70
+ @headers.each do |col|
71
+ begin
72
+ nextrow << @table[col][index].clone
73
+ rescue
74
+ nextrow << @table[col][index]
75
+ end
76
+ end
77
+ yield nextrow
70
78
  end
71
- yield nextrow
79
+ else
80
+ self.to_enum(:each)
72
81
  end
82
+
73
83
  end
74
84
 
75
85
  # Return a copy of a column from the table, identified by column name.
@@ -78,12 +88,7 @@ class Table
78
88
  # ==== Attributes
79
89
  # +colname+:: +String+ to identify the name of the column
80
90
  def column(colname)
81
- # return empty Array if column name not found
82
- unless @table.has_key?(colname)
83
- Array.new()
84
- else
85
- Array(@table[colname])
86
- end
91
+ Array(get_col(colname))
87
92
  end
88
93
 
89
94
  # Return a copy of a row from the table as an +Array+, given an index
@@ -116,8 +121,6 @@ class Table
116
121
  args.flatten!
117
122
  colname = args.shift
118
123
  column_vals = args
119
- else
120
- raise ArgumentError, "Invalid Arguments to add_column"
121
124
  end
122
125
  # check arguments
123
126
  raise ArgumentError, "Duplicate Column Name!" if @table.has_key?(colname)
@@ -186,8 +189,6 @@ class Table
186
189
  def add_row(*row)
187
190
  if row.kind_of? Array
188
191
  row = row.flatten
189
- else
190
- raise ArgumentError, "Invalid Arguments to add_row"
191
192
  end
192
193
  if @headers.empty?
193
194
  @headers = row
@@ -245,6 +246,10 @@ class Table
245
246
  # +orig_name+:: +String+ current header name
246
247
  # +new_name+:: +String+ indicating new header name
247
248
  def rename_header(orig_name, new_name)
249
+ raise ArgumentError, "Original Column name type invalid" unless orig_name.kind_of? String
250
+ raise ArgumentError, "New Column name type invalid" unless new_name.kind_of? String
251
+ raise ArgumentError, "Column Name does not exist!" unless @headers.include? orig_name
252
+
248
253
  update_header(orig_name, new_name)
249
254
  return self
250
255
  end
@@ -467,7 +472,6 @@ class Table
467
472
  raise ArgumentError, "Invalid table!" unless table2.is_a?(Table)
468
473
  raise ArgumentError, "Invalid column name" unless @table.has_key?(colname)
469
474
  raise ArgumentError, "Invalid column name" unless table2.headers.include?(col2name)
470
- t2_col_index = table2.headers.index(col2name)
471
475
 
472
476
  dedupe_headers(table2, colname)
473
477
 
@@ -495,27 +499,28 @@ class Table
495
499
  # in the given column. Raises ArgumentError if the column is not found.
496
500
  #
497
501
  # ==== Attributes
498
- # +colname+:: +String+ to identify the column to join on
499
- # +re+:: +Regexp+ to match the value in the selected column
500
- # +replace+:: OPTIONAL +String+ or +Hash+ to specify the replacement text for the given +Regexp+
502
+ # +colname+:: +String+ to identify the column to substitute on
503
+ # +match+:: OPTIONAL +String+ or +Regexp+ to match the value in the selected column
504
+ # +replace+:: OPTIONAL +String+ or +Hash+ to specify the replacement text for the given match value
501
505
  # +&block+:: OPTIONAL block to execute against matching values
502
506
  #
503
507
  # ==== Examples
504
508
  # cities.sub("Population", /(.*?),(.*?)/, '\1\2') # eliminate commas
505
509
  # capitals.sub("State", /NY/, "New York") # replace acronym with full name
510
+ # capitals.sub("State", /North|South/, {"North" => "South", "South" => "North"}) # Northern states for Southern and vice-versa
506
511
  # capitals.sub("State") { |state| state.downcase } # Lowercase for all values
507
512
  #
508
- def sub(colname, re=nil, replace=nil, &block)
513
+ def sub(colname, match=nil, replace=nil, &block)
509
514
  # check arguments
510
- raise ArgumentError, "No regular expression to match against" unless re
515
+ raise ArgumentError, "No regular expression to match against" unless match || block_given?
511
516
  raise ArgumentError, "Invalid column name" unless @table.has_key?(colname)
512
- replace_str = ""
513
- if replace.respond_to?(:fetch)
514
- replace_str = replace.fetch(re)
515
- elsif replace.respond_to?(:to_str)
516
- replace_str = replace.to_str
517
- else
518
- raise ArgumentError, "Replacement must be String or Hash"
517
+
518
+ if ! block_given?
519
+ if ! (String.try_convert(match) || Regexp.try_convert(match))
520
+ raise ArgumentError, "Match expression must be String or Regexp"
521
+ elsif ! (replace.respond_to?(:fetch) || replace.respond_to?(:to_str))
522
+ raise ArgumentError, "Replacement must be String or Hash"
523
+ end
519
524
  end
520
525
 
521
526
  result = Table.new([@headers])
@@ -525,7 +530,7 @@ class Table
525
530
  if block_given?
526
531
  row[col_index] = block.call row[col_index]
527
532
  else
528
- row[col_index] = row[col_index].sub(re, replace_str)
533
+ row[col_index] = row[col_index].sub(match, replace)
529
534
  end
530
535
  result.add_row(row)
531
536
  end
@@ -647,7 +652,8 @@ class Table
647
652
 
648
653
  def get_row(index)
649
654
  result = []
650
- if index >= @table[@headers.first].length
655
+ if index >= @table[@headers.first].length ||
656
+ index < -(@table[@headers.first].length)
651
657
  return result
652
658
  end
653
659
  @headers.each { |col| result << @table[col][index].to_s }
@@ -662,7 +668,12 @@ class Table
662
668
  end
663
669
 
664
670
  def get_col(colname)
665
- Array.new(@table[colname])
671
+ # return empty Array if column name not found
672
+ unless @table.has_key?(colname)
673
+ Array.new()
674
+ else
675
+ Array(@table[colname])
676
+ end
666
677
  end
667
678
 
668
679
  def append_col(colname, column_vals)
@@ -4,10 +4,10 @@
4
4
  require 'simplecov'
5
5
  require 'coveralls'
6
6
 
7
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
7
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
8
8
  SimpleCov::Formatter::HTMLFormatter,
9
9
  Coveralls::SimpleCov::Formatter
10
- ]
10
+ ])
11
11
  SimpleCov.start
12
12
 
13
13
  require 'factory_girl'
@@ -11,6 +11,7 @@ describe "Table" do
11
11
  describe ".new" do
12
12
  let(:t) { Table.new('test.tab') }
13
13
  let(:empty) { Table.new() }
14
+ let(:copy) { Table.new(Table.new('test.tab')) }
14
15
 
15
16
  it "reads a file and create a table" do
16
17
  expect(t).to be_a(Table)
@@ -18,12 +19,39 @@ describe "Table" do
18
19
  it "creates a table if no file was given" do
19
20
  expect(empty).to be_a(Table)
20
21
  end
22
+ it "creates a table from another table" do
23
+ expect(copy).to be_a(Table)
24
+ expect(copy.headers).to eq(t.headers)
25
+ expect(copy.count).to eq(t.count)
26
+ end
21
27
  it "errors when the file is not found" do
22
28
  expect{Table.new('sillyfile.txt')}.to raise_error(Errno::ENOENT)
23
29
  end
24
30
 
25
31
  end
32
+
33
+ describe ".column" do
34
+ let(:test) { FactoryGirl.build(:table) }
35
+
36
+ it "returns a column when given a valid header" do
37
+ expect(test.column('Name')).to be_a(Array)
38
+ end
39
+ it "returns an empty Array when given an invalid header" do
40
+ expect(test.column('NotName')).to eq(Array.new)
41
+ end
42
+ end
26
43
 
44
+ describe ".row" do
45
+ let(:test) { FactoryGirl.build(:table) }
46
+
47
+ it "returns a row when given a valid index" do
48
+ expect(test.row(2)).to be_a(Array)
49
+ end
50
+ it "returns an empty Array when given an invalid index" do
51
+ expect(test.row(4)).to eq(Array.new)
52
+ end
53
+ end
54
+
27
55
  describe ".empty?" do
28
56
  let(:test) { Table.new('test.tab') }
29
57
  let(:empty) { Table.new() }
@@ -36,6 +64,28 @@ describe "Table" do
36
64
  end
37
65
  end
38
66
 
67
+ describe ".each" do
68
+ let (:test) { FactoryGirl.build(:table) }
69
+ let (:test_fixnum) {
70
+ Table.new('test.tab') << ["Phil", "567 Vine", "567-432-1234", 3 ]
71
+ }
72
+
73
+ it "returns an Enumerator if not given a block" do
74
+ expect(test.each).to be_a(Enumerator)
75
+ end
76
+ it "returns a clone of a row" do
77
+ h = test.each.first
78
+ expect(h).not_to equal(test.row 0)
79
+ expect(h).to eq(test.row 0)
80
+ end
81
+ it "returns a row that can't be cloned" do
82
+ a = test_fixnum.each
83
+ a.next
84
+ a.next
85
+ expect(a.next).to eq(test_fixnum.row(2))
86
+ end
87
+ end
88
+
39
89
  describe ".add_column" do
40
90
  let(:test) { FactoryGirl.build(:table) }
41
91
  let(:newcol) { ["A", "B", "C"] }
@@ -55,7 +105,7 @@ describe "Table" do
55
105
  expect { test.add_column("Name", newcol) }.to raise_error(ArgumentError)
56
106
  end
57
107
  it "raises an ArgumentError when given a column with the wrong length" do
58
- expect { test.add_column("Name", newcol << "D") }.to raise_error(ArgumentError)
108
+ expect { test.add_column("NewName", newcol << "D") }.to raise_error(ArgumentError)
59
109
  end
60
110
  it "adds a column when given an Array" do
61
111
  expect(test.add_column(headercol).headers).to include("TestCol")
@@ -96,6 +146,9 @@ describe "Table" do
96
146
  it "returns itself when appending an empty table" do
97
147
  expect(test1.append(empty).count).to eq(3)
98
148
  end
149
+ it "raises an ArgumentError when not given a table" do
150
+ expect { test1.append('') }.to raise_error(ArgumentError)
151
+ end
99
152
  it "raises an ArgumentError when given a table with the wrong headers" do
100
153
  expect { test1.append(cities) }.to raise_error(ArgumentError)
101
154
  end
@@ -150,6 +203,38 @@ describe "Table" do
150
203
  end
151
204
  end
152
205
 
206
+ describe ".rename_header" do
207
+ let (:test) { FactoryGirl.build(:table) }
208
+
209
+ it "raises an ArgumentError when given a column name with invalid type" do
210
+ expect { test.rename_header(:Name, "FirstName") }.to raise_error(ArgumentError)
211
+ end
212
+ it "raises an ArgumentError when given a new name with invalid type" do
213
+ expect { test.rename_header("Name", :FirstName) }.to raise_error(ArgumentError)
214
+ end
215
+ it "raises an ArgumentError when given an invalid column name" do
216
+ expect { test.rename_header("NName", "FirstName") }.to raise_error(ArgumentError)
217
+ end
218
+ it "returns a table with an updated header" do
219
+ expect(test.rename_header("Name", "FirstName").headers).to include("FirstName")
220
+ end
221
+
222
+ end
223
+
224
+ describe ".to_s" do
225
+ let (:test) { FactoryGirl.build(:table) }
226
+
227
+ it "returns a String" do
228
+ expect(test.to_s).to be_a(String)
229
+ end
230
+ it "returns a String with the same number of rows" do
231
+ expect(test.to_s.split("\n").count).to eq(test.count + 1)
232
+ end
233
+ it "returns a String with the same number of columns" do
234
+ expect(test.to_s.split("\n")[0].split("\t").count).to eq(test.headers.count)
235
+ end
236
+ end
237
+
153
238
  describe ".count" do
154
239
  let(:t) { FactoryGirl.build(:table) }
155
240
  let(:empty) { Table.new() }
@@ -260,12 +345,23 @@ describe "Table" do
260
345
 
261
346
  describe ".sub" do
262
347
  let (:cities) { Table.new('cities.txt') }
348
+ let (:capitals) { Table.new('capitals.txt') }
263
349
 
264
350
  it "returns an instance of Table" do
265
351
  expect(cities.sub("State", /Jersey/, "York")).to be_a(Table)
266
352
  end
267
- it "substitutes the values in a given field" do
268
- expect(cities.sub("State", /Jersey/, "York").column("State")).to include("New York")
353
+ it "substitutes the values in a given field when matching Regexp" do
354
+ expect(cities.sub("State", /Jersey/, "York").column("State")).not_to include("New Jersey")
355
+ end
356
+ it "substitutes the values in a given field when matching String" do
357
+ expect(cities.sub("State", "Jersey", "York").column("State")).not_to include("New Jersey")
358
+ end
359
+ it "substitutes the values in a given field when provided with a block" do
360
+ expect(cities.sub("State") {|state| state.upcase}.column("State")).to include("NEW JERSEY")
361
+ end
362
+ it "substitutes the values in a given field when provided with a replacement Hash" do
363
+ expect(capitals.sub("State", /North|South|East|West/, {"North"=>"South",
364
+ "South"=>"North", "West" => "East", "East"=>"West" }).column("State")).to include("East Virginia")
269
365
  end
270
366
  it "raises ArgumentError when the given arguments don't match a column" do
271
367
  expect {cities.sub("Silly", /NJ/, "NY") }.to raise_error(ArgumentError)
@@ -273,6 +369,9 @@ describe "Table" do
273
369
  it "raises ArgumentError when not given a Match string" do
274
370
  expect {cities.sub("State") }.to raise_error(ArgumentError)
275
371
  end
372
+ it "raises ArgumentError when Match expression is not a String or Regexp" do
373
+ expect {cities.sub("State",:New, "Old") }.to raise_error(ArgumentError)
374
+ end
276
375
  it "raises ArgumentError when replacement is not a String or Hash" do
277
376
  expect {cities.sub("State", /New/, 9)}.to raise_error(ArgumentError)
278
377
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tablestakes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.4
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - J.B. Folkerts
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-06-21 00:00:00.000000000 Z
11
+ date: 2016-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '3.2'
19
+ version: '3.5'
20
20
  type: :development
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: '3.2'
26
+ version: '3.5'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rspec-its
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -44,70 +44,70 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '3.2'
47
+ version: '3.5'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '3.2'
54
+ version: '3.5'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec-expectations
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '3.2'
61
+ version: '3.5'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '3.2'
68
+ version: '3.5'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: factory_girl
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '4.4'
75
+ version: '4.7'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '4.4'
82
+ version: '4.7'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: simplecov
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0.9'
89
+ version: '0.12'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0.9'
96
+ version: '0.12'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: coveralls
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '0.8'
103
+ version: 0.8.15
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '0.8'
110
+ version: 0.8.15
111
111
  description: A simple implementation of Tables, for use in summing, joining, slicing
112
112
  and dicing data tables
113
113
  email: jbf@pentambic.com
@@ -161,7 +161,7 @@ files:
161
161
  - spec/spec_helper.rb
162
162
  - spec/table_spec.rb
163
163
  - test.tab
164
- homepage: http://rubygems.org/gems/tablestakes
164
+ homepage: https://rubygems.org/gems/tablestakes
165
165
  licenses:
166
166
  - MIT
167
167
  metadata: {}