tablestakes 0.9.4 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
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: {}