tsv 0.0.3 → 1.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.
- checksums.yaml +4 -4
- data/.travis.yml +4 -3
- data/CHANGELOG.md +7 -2
- data/Gemfile +6 -4
- data/README.md +8 -3
- data/lib/tsv.rb +4 -4
- data/lib/tsv/{cyclist.rb → table.rb} +7 -17
- data/lib/tsv/version.rb +1 -1
- data/spec/{support/cyclist_generic.rb → lib/tsv/table_spec.rb} +21 -11
- data/spec/lib/tsv_spec.rb +67 -15
- metadata +5 -9
- data/spec/lib/tsv/file_cyclist_spec.rb +0 -34
- data/spec/lib/tsv/string_cyclist_spec.rb +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 901a06d59683d6bb8df05d6298bf0157ef09dac2
|
4
|
+
data.tar.gz: 76f1f731eb6d4bf236bfac4349c503fa5b734296
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b68ee097e32ef0c00b4066b1bcc4cc21efccde77a7af13661a1b7c108387ff1081fa4cd1a772eb4cb63871c2ff95baa786f21f262be04e2f8e30e1774063f21
|
7
|
+
data.tar.gz: 2643de24f05a2f19a0302954007720664f4af744266ddc0252152b467d1debecd8c4fa4f87010586662a5b6951ed68ab7764b4ab651baa1ccfebf1b85001fdbe
|
data/.travis.yml
CHANGED
@@ -9,7 +9,8 @@ rvm:
|
|
9
9
|
- 2.0.0
|
10
10
|
- 2.1.1
|
11
11
|
- 2.1.2
|
12
|
-
-
|
12
|
+
- 2.2.0
|
13
|
+
- rbx-2.5.1
|
13
14
|
- jruby
|
14
15
|
|
15
16
|
# Part of test suite - building gem and trying to require it via ruby -e
|
@@ -18,6 +19,6 @@ script: >
|
|
18
19
|
rake build&&gem install pkg/tsv*.gem&&ruby -e 'require "tsv"; TSV.parse_file("spec/fixtures/example.tsv").to_a'&&rake
|
19
20
|
|
20
21
|
matrix:
|
21
|
-
allow_failures:
|
22
|
-
- rvm: rbx-2.
|
22
|
+
allow_failures:
|
23
|
+
- rvm: rbx-2.5.1
|
23
24
|
- rvm: jruby
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file.
|
|
3
3
|
|
4
4
|
## [Unreleased][unreleased]
|
5
5
|
|
6
|
+
## [1.0.0] - 2015-02-14
|
7
|
+
### Changed
|
8
|
+
- Reworked Cyclist into Table
|
9
|
+
|
6
10
|
## [0.0.3] - 2014-12-26
|
7
11
|
### Fixed
|
8
12
|
- Fixed case with empty column contents in TSV
|
@@ -12,13 +16,14 @@ All notable changes to this project will be documented in this file.
|
|
12
16
|
|
13
17
|
## [0.0.2] - 2014-08-13
|
14
18
|
### Changed
|
15
|
-
- Internal
|
19
|
+
- Internal refactoring
|
16
20
|
|
17
21
|
### Added
|
18
22
|
- Testing built gem integrity via CI
|
19
23
|
|
20
24
|
Changelog format taken from [keep-a-changelog](https://github.com/olivierlacan/keep-a-changelog)
|
21
25
|
|
22
|
-
[unreleased]: https://github.com/mimimi/ruby-tsv/compare/
|
26
|
+
[unreleased]: https://github.com/mimimi/ruby-tsv/compare/v1.0.0...master
|
27
|
+
[1.0.0]: https://github.com/mimimi/ruby-tsv/compare/v0.0.3...v1.0.0
|
23
28
|
[0.0.3]: https://github.com/mimimi/ruby-tsv/compare/v0.0.2...v0.0.3
|
24
29
|
[0.0.2]: https://github.com/mimimi/ruby-tsv/compare/v0.0.1...v0.0.2
|
data/Gemfile
CHANGED
@@ -3,7 +3,9 @@ source 'https://rubygems.org'
|
|
3
3
|
# Specify your gem's dependencies in tsv.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
-
|
7
|
-
gem "
|
8
|
-
gem "
|
9
|
-
gem "
|
6
|
+
group "test" do
|
7
|
+
gem "codeclimate-test-reporter", require: nil
|
8
|
+
gem "rake"
|
9
|
+
gem "rspec", "~> 3.1.0"
|
10
|
+
gem "pry"
|
11
|
+
end
|
data/README.md
CHANGED
@@ -27,16 +27,21 @@ Or install it yourself as:
|
|
27
27
|
|
28
28
|
#### TSV::parse
|
29
29
|
|
30
|
-
`TSV.parse` accepts
|
30
|
+
`TSV.parse` accepts basically anything that can enumerate over lines, for example:
|
31
|
+
|
32
|
+
* TSV as a whole string
|
33
|
+
* any IO object - a TSV file pre-opened with `File.open`, `StringIO` buffer containing TSV data, etc
|
34
|
+
|
35
|
+
It returns a lazy enumerator, yielding TSV::Row objects on demand.
|
31
36
|
|
32
37
|
#### TSV::parse_file
|
33
38
|
|
34
39
|
`TSV.parse_file` accepts path to TSV file, returning lazy enumerator, yielding TSV::Row objects on demand
|
35
40
|
`TSV.parse_file` is also aliased as `[]`, allowing for `TSV[filename]` syntax
|
36
41
|
|
37
|
-
#### TSV::
|
42
|
+
#### TSV::Table
|
38
43
|
|
39
|
-
While TSV specification requires headers, popular use doesn't necessarily adhere. In order to cope both `TSV::parse` and `TSV::parse_file` return
|
44
|
+
While TSV specification requires headers, popular use doesn't necessarily adhere. In order to cope both `TSV::parse` and `TSV::parse_file` return `TSV::Table` object, that apart from acting as enumerator exposes two additional methods: `#with_headers` and `#without_headers`. Neither method preserves read position by design.
|
40
45
|
|
41
46
|
#### TSV::Row
|
42
47
|
|
data/lib/tsv.rb
CHANGED
@@ -2,17 +2,17 @@ require 'forwardable'
|
|
2
2
|
|
3
3
|
require "tsv/version"
|
4
4
|
require "tsv/row"
|
5
|
-
require "tsv/
|
5
|
+
require "tsv/table"
|
6
6
|
|
7
7
|
module TSV
|
8
8
|
extend self
|
9
9
|
|
10
10
|
def parse(content, opts = {}, &block)
|
11
|
-
TSV::
|
11
|
+
TSV::Table.new(content, opts, &block)
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def parse_file(filename, opts = {}, &block)
|
15
|
-
TSV::
|
15
|
+
TSV::Table.new(File.new(filename, 'r'), opts, &block)
|
16
16
|
end
|
17
17
|
|
18
18
|
alias :[] :parse_file
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module TSV
|
2
|
-
class
|
2
|
+
class Table
|
3
3
|
extend Forwardable
|
4
4
|
|
5
5
|
def_delegators :enumerator, *Enumerator.instance_methods(false)
|
@@ -8,8 +8,8 @@ module TSV
|
|
8
8
|
attr_accessor :source, :header
|
9
9
|
|
10
10
|
def initialize(source, params = {}, &block)
|
11
|
-
self.header
|
12
|
-
self.source = source
|
11
|
+
self.header = params.fetch(:header, true)
|
12
|
+
self.source = source
|
13
13
|
self.enumerator.each(&block) if block_given?
|
14
14
|
end
|
15
15
|
|
@@ -44,6 +44,10 @@ module TSV
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
+
def data_enumerator
|
48
|
+
source.each_line
|
49
|
+
end
|
50
|
+
|
47
51
|
protected
|
48
52
|
|
49
53
|
def generate_row_from(str)
|
@@ -54,18 +58,4 @@ module TSV
|
|
54
58
|
(0...example_line.length).to_a.map(&:to_s)
|
55
59
|
end
|
56
60
|
end
|
57
|
-
|
58
|
-
class FileCyclist < Cyclist
|
59
|
-
alias :filepath :source
|
60
|
-
|
61
|
-
def data_enumerator
|
62
|
-
File.new(self.source).each_line
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
class StringCyclist < Cyclist
|
67
|
-
def data_enumerator
|
68
|
-
source.each_line
|
69
|
-
end
|
70
|
-
end
|
71
61
|
end
|
data/lib/tsv/version.rb
CHANGED
@@ -1,4 +1,14 @@
|
|
1
|
-
|
1
|
+
require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper.rb')
|
2
|
+
|
3
|
+
describe TSV::Table do
|
4
|
+
let(:source) { IO.read(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', filename)) }
|
5
|
+
let(:filename) { 'example.tsv' }
|
6
|
+
|
7
|
+
let(:header) { true }
|
8
|
+
let(:parameters) { { header: header } }
|
9
|
+
|
10
|
+
subject(:table) { TSV::Table.new(source, parameters) }
|
11
|
+
|
2
12
|
describe "::new" do
|
3
13
|
it "initializes header to true by default" do
|
4
14
|
expect(subject.header).to be true
|
@@ -25,8 +35,8 @@ shared_examples_for "Cyclist" do
|
|
25
35
|
end
|
26
36
|
|
27
37
|
describe "#enumerator" do
|
28
|
-
it { expect(
|
29
|
-
subject {
|
38
|
+
it { expect(table.enumerator).to be_a_kind_of(Enumerator) }
|
39
|
+
subject { table.enumerator.to_a }
|
30
40
|
|
31
41
|
context "string is empty" do
|
32
42
|
let(:filename) { 'empty.tsv' }
|
@@ -83,17 +93,17 @@ shared_examples_for "Cyclist" do
|
|
83
93
|
end
|
84
94
|
|
85
95
|
describe "#with_header" do
|
86
|
-
subject {
|
87
|
-
|
88
|
-
it "returns a
|
96
|
+
subject { table.with_header }
|
97
|
+
|
98
|
+
it "returns a Table with header option set to true" do
|
89
99
|
expect(subject.header).to be true
|
90
100
|
end
|
91
101
|
end
|
92
102
|
|
93
103
|
describe "#without_header" do
|
94
|
-
subject {
|
104
|
+
subject { table.without_header }
|
95
105
|
|
96
|
-
it "returns a
|
106
|
+
it "returns a Table with header option set to false" do
|
97
107
|
expect(subject.header).to be false
|
98
108
|
end
|
99
109
|
end
|
@@ -101,9 +111,9 @@ shared_examples_for "Cyclist" do
|
|
101
111
|
describe "enumerator interfaces" do
|
102
112
|
( Enumerable.instance_methods(false) + Enumerator.instance_methods(false) ).each do |name|
|
103
113
|
it "delegates #{name} to enumerator" do
|
104
|
-
expect(
|
105
|
-
|
114
|
+
expect(table.enumerator).to receive(name)
|
115
|
+
table.send(name)
|
106
116
|
end
|
107
117
|
end
|
108
118
|
end
|
109
|
-
end
|
119
|
+
end
|
data/spec/lib/tsv_spec.rb
CHANGED
@@ -5,28 +5,55 @@ describe TSV do
|
|
5
5
|
|
6
6
|
describe "#parse" do
|
7
7
|
let(:header) { nil }
|
8
|
-
let(:content) { IO.read(File.join(File.dirname(__FILE__), '..', 'fixtures', filename)) }
|
9
8
|
let(:parameters) { { header: header } }
|
10
9
|
|
11
|
-
|
10
|
+
context "given a string with content" do
|
11
|
+
let(:content) { IO.read(File.join(File.dirname(__FILE__), '..', 'fixtures', filename)) }
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
subject { TSV.parse(content, parameters) }
|
14
|
+
|
15
|
+
it "returns Table initialized with given data" do
|
16
|
+
expect(subject).to be_a TSV::Table
|
17
|
+
expect(subject.source).to eq(content)
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when block is given" do
|
21
|
+
it "passes block to Table" do
|
22
|
+
data = []
|
23
|
+
|
24
|
+
TSV.parse(content) do |i|
|
25
|
+
data.push i
|
26
|
+
end
|
27
|
+
|
28
|
+
headers = %w{first second third}
|
29
|
+
expect(data).to eq [ TSV::Row.new( ['0', '1', '2'], headers ),
|
30
|
+
TSV::Row.new( ['one', 'two', 'three'], headers ),
|
31
|
+
TSV::Row.new( ['weird data', 's@mthin#', 'else'], headers ) ]
|
32
|
+
end
|
33
|
+
end
|
16
34
|
end
|
17
35
|
|
18
|
-
context "
|
19
|
-
|
36
|
+
context "given a opened IO object" do
|
37
|
+
let(:content) { File.open(File.join(File.dirname(__FILE__), '..', 'fixtures', filename), 'r') }
|
38
|
+
|
39
|
+
subject { TSV.parse(content, parameters) }
|
40
|
+
|
41
|
+
it "returns Table initialized with given data" do
|
42
|
+
expect(subject).to be_a TSV::Table
|
43
|
+
expect(subject.source).to eq(content)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "can properly parse file" do
|
20
47
|
data = []
|
21
|
-
|
22
|
-
TSV.parse(content) do |i|
|
48
|
+
|
49
|
+
TSV.parse(content).each do |i|
|
23
50
|
data.push i
|
24
51
|
end
|
25
52
|
|
26
53
|
headers = %w{first second third}
|
27
54
|
expect(data).to eq [ TSV::Row.new( ['0', '1', '2'], headers ),
|
28
|
-
|
29
|
-
|
55
|
+
TSV::Row.new( ['one', 'two', 'three'], headers ),
|
56
|
+
TSV::Row.new( ['weird data', 's@mthin#', 'else'], headers ) ]
|
30
57
|
end
|
31
58
|
end
|
32
59
|
end
|
@@ -36,13 +63,16 @@ describe TSV do
|
|
36
63
|
|
37
64
|
subject { TSV.parse_file tsv_path }
|
38
65
|
|
39
|
-
|
40
|
-
|
41
|
-
|
66
|
+
context "when no block is given" do
|
67
|
+
it "returns Table initialized with File object" do
|
68
|
+
expect(subject).to be_a TSV::Table
|
69
|
+
expect(subject.source).to be_kind_of(File)
|
70
|
+
expect(subject.source.path).to eq(tsv_path)
|
71
|
+
end
|
42
72
|
end
|
43
73
|
|
44
74
|
context "when block is given" do
|
45
|
-
it "passes block to
|
75
|
+
it "passes block to Table" do
|
46
76
|
data = []
|
47
77
|
|
48
78
|
TSV.parse_file(tsv_path) do |i|
|
@@ -55,5 +85,27 @@ describe TSV do
|
|
55
85
|
TSV::Row.new( ['weird data', 's@mthin#', 'else'], headers ) ]
|
56
86
|
end
|
57
87
|
end
|
88
|
+
|
89
|
+
context "when accessing unavailable files" do
|
90
|
+
subject { lambda { TSV.parse_file(tsv_path).to_a } }
|
91
|
+
|
92
|
+
context "when file is not found" do
|
93
|
+
let(:tsv_path) { "AManThatWasntThere.tsv" }
|
94
|
+
|
95
|
+
it "returns FileNotFoundException" do
|
96
|
+
expect(subject).to raise_error(Errno::ENOENT)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "intermediate file handle" do
|
102
|
+
it "raises IOError on write attempt" do
|
103
|
+
tempfile = Tempfile.new('tsv_test')
|
104
|
+
handle = TSV.parse_file(tempfile.path).source
|
105
|
+
|
106
|
+
expect{ handle.puts('test string please ignore') }.to raise_error(IOError, 'not opened for writing')
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
58
110
|
end
|
59
111
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tsv
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dmytro Soltys
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2015-02-14 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Streamed TSV parser
|
15
15
|
email:
|
@@ -28,19 +28,17 @@ files:
|
|
28
28
|
- README.md
|
29
29
|
- Rakefile
|
30
30
|
- lib/tsv.rb
|
31
|
-
- lib/tsv/cyclist.rb
|
32
31
|
- lib/tsv/row.rb
|
32
|
+
- lib/tsv/table.rb
|
33
33
|
- lib/tsv/version.rb
|
34
34
|
- spec/fixtures/broken.tsv
|
35
35
|
- spec/fixtures/empty-trailing.tsv
|
36
36
|
- spec/fixtures/empty.tsv
|
37
37
|
- spec/fixtures/example.tsv
|
38
|
-
- spec/lib/tsv/file_cyclist_spec.rb
|
39
38
|
- spec/lib/tsv/row_spec.rb
|
40
|
-
- spec/lib/tsv/
|
39
|
+
- spec/lib/tsv/table_spec.rb
|
41
40
|
- spec/lib/tsv_spec.rb
|
42
41
|
- spec/spec_helper.rb
|
43
|
-
- spec/support/cyclist_generic.rb
|
44
42
|
- spec/tsv_integration_spec.rb
|
45
43
|
- tsv.gemspec
|
46
44
|
homepage: ''
|
@@ -73,10 +71,8 @@ test_files:
|
|
73
71
|
- spec/fixtures/empty-trailing.tsv
|
74
72
|
- spec/fixtures/empty.tsv
|
75
73
|
- spec/fixtures/example.tsv
|
76
|
-
- spec/lib/tsv/file_cyclist_spec.rb
|
77
74
|
- spec/lib/tsv/row_spec.rb
|
78
|
-
- spec/lib/tsv/
|
75
|
+
- spec/lib/tsv/table_spec.rb
|
79
76
|
- spec/lib/tsv_spec.rb
|
80
77
|
- spec/spec_helper.rb
|
81
|
-
- spec/support/cyclist_generic.rb
|
82
78
|
- spec/tsv_integration_spec.rb
|
@@ -1,34 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper.rb')
|
2
|
-
|
3
|
-
describe TSV::FileCyclist do
|
4
|
-
let(:tsv_path) { File.join(File.dirname(__FILE__), '..', '..', 'fixtures', filename) }
|
5
|
-
let(:source) { tsv_path }
|
6
|
-
let(:filename) { 'example.tsv' }
|
7
|
-
|
8
|
-
let(:header) { true }
|
9
|
-
let(:parameters) { { header: header } }
|
10
|
-
|
11
|
-
subject(:cyclist) { TSV::FileCyclist.new(source, parameters) }
|
12
|
-
|
13
|
-
it_behaves_like "Cyclist"
|
14
|
-
|
15
|
-
describe "accessing unavailable files" do
|
16
|
-
subject { lambda { TSV::FileCyclist.new(tsv_path).to_a } }
|
17
|
-
|
18
|
-
context "when file is not found" do
|
19
|
-
let(:tsv_path) { "AManThatWasntThere.tsv" }
|
20
|
-
|
21
|
-
it "returns FileNotFoundException" do
|
22
|
-
expect(subject).to raise_error(Errno::ENOENT)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
context "when filename is nil" do
|
27
|
-
let(:tsv_path) { nil }
|
28
|
-
|
29
|
-
it "returns FileNameInvalidException" do
|
30
|
-
expect(subject).to raise_error(Errno::ENOENT)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
@@ -1,13 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper.rb')
|
2
|
-
|
3
|
-
describe TSV::StringCyclist do
|
4
|
-
let(:source) { IO.read(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', filename)) }
|
5
|
-
let(:filename) { 'example.tsv' }
|
6
|
-
|
7
|
-
let(:header) { true }
|
8
|
-
let(:parameters) { { header: header } }
|
9
|
-
|
10
|
-
subject(:cyclist) { TSV::StringCyclist.new(source, parameters) }
|
11
|
-
|
12
|
-
it_behaves_like "Cyclist"
|
13
|
-
end
|