haecksler 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +51 -0
- data/Rakefile +6 -0
- data/haecksler.gemspec +24 -0
- data/lib/haecksler.rb +5 -0
- data/lib/haecksler/column.rb +70 -0
- data/lib/haecksler/dsl.rb +62 -0
- data/lib/haecksler/row.rb +62 -0
- data/lib/haecksler/sheet.rb +32 -0
- data/lib/haecksler/version.rb +3 -0
- data/spec/column_spec.rb +90 -0
- data/spec/complete.txt +4 -0
- data/spec/dsl_spec.rb +87 -0
- data/spec/row_spec.rb +72 -0
- data/spec/sheet_spec.rb +51 -0
- data/spec/simple.txt +2 -0
- data/spec/spec_helper.rb +19 -0
- metadata +114 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7fac756e6245151603f1454fb9384c64cbe57ed0
|
4
|
+
data.tar.gz: 3429e573e1d61c725bdc051273ca7337e166eb9e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3a4acbbd1ae9b6ac447d0fa18675617e84392f64a2b6d0b9f24d6499fe6b5d4376d236b59de1af87094c1aab05d48203f673172525ee56d3f48952418d407e47
|
7
|
+
data.tar.gz: 8afb2a948a53866943cccb6f201d6850ae947f43d4584903af9f4c8c86b73c6aba57f64d9251a0a62033965972cddef6990e10399e88c34ea439ddef2d34a0fb
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Frank Falkenberg
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# Haecksler
|
2
|
+
|
3
|
+
[![Code Climate](https://codeclimate.com/github/falti/haecksler.png)](https://codeclimate.com/github/falti/haecksler)
|
4
|
+
[![Build Status](https://travis-ci.org/falti/haecksler.svg?branch=master)](https://travis-ci.org/falti/haecksler)
|
5
|
+
[![Dependency Status](https://gemnasium.com/falti/haecksler.svg)](https://gemnasium.com/falti/haecksler)
|
6
|
+
|
7
|
+
|
8
|
+
TODO: Write a gem description
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
gem 'haecksler'
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install haecksler
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
file = File.open(File.expand_path("../complete.txt",__FILE__))
|
28
|
+
|
29
|
+
result = Haecksler.chop(file) do |h|
|
30
|
+
|
31
|
+
h.header_trap {|header| header =~/^FILE/ }
|
32
|
+
h.header "HName", 4
|
33
|
+
h.header "HExtra", 6
|
34
|
+
|
35
|
+
h.column "Id", 2, :integer
|
36
|
+
h.column "Name", 10
|
37
|
+
h.column "Date", 8, :date
|
38
|
+
|
39
|
+
h.footer_trap {|footer| footer =~/^END/ }
|
40
|
+
h.footer "FFooter", 3
|
41
|
+
h.footer "FDate", 8, :date
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
## Contributing
|
46
|
+
|
47
|
+
1. Fork it ( https://github.com/[my-github-username]/haecksler/fork )
|
48
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
49
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
50
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
51
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/haecksler.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'haecksler/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "haecksler"
|
8
|
+
spec.version = Haecksler::VERSION
|
9
|
+
spec.authors = ["Frank Falkenberg"]
|
10
|
+
spec.email = ["faltibrain@gmail.com"]
|
11
|
+
spec.summary = %q{Library to parse fixed-length files}
|
12
|
+
spec.description = %q{Haecksler is the German word for a wood chipper}
|
13
|
+
spec.homepage = "https://github.com/falti/haecksler"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.5.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rspec", '~> 2.14'
|
24
|
+
end
|
data/lib/haecksler.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
module Haecksler
|
5
|
+
|
6
|
+
class TypeError
|
7
|
+
attr_reader :value, :type
|
8
|
+
|
9
|
+
def initialize(value, column)
|
10
|
+
@value = value
|
11
|
+
@type = column.type
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
"Could not parse '#{value}' to '#{type}"
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
class ParsedColumn < SimpleDelegator
|
21
|
+
attr_accessor :value
|
22
|
+
end
|
23
|
+
|
24
|
+
class Column
|
25
|
+
attr_reader :name, :size, :type, :date_format
|
26
|
+
|
27
|
+
DEFAULT_OPTIONS={type: :string, date_format: nil}
|
28
|
+
|
29
|
+
def initialize(options = {type: :string})
|
30
|
+
options = DEFAULT_OPTIONS.merge(options)
|
31
|
+
@name = options[:name]
|
32
|
+
@size = options[:size]
|
33
|
+
@type = options[:type]
|
34
|
+
@date_format = options[:date_format]
|
35
|
+
end
|
36
|
+
|
37
|
+
def parse(string_value)
|
38
|
+
parsed = ParsedColumn.new(self)
|
39
|
+
|
40
|
+
parsed.value = begin
|
41
|
+
case type
|
42
|
+
when :string
|
43
|
+
String(string_value).rstrip
|
44
|
+
when :integer
|
45
|
+
Integer(string_value)
|
46
|
+
when :float
|
47
|
+
Float(string_value)
|
48
|
+
when :date
|
49
|
+
if date_format.nil?
|
50
|
+
Date.parse(string_value)
|
51
|
+
else
|
52
|
+
Date.strptime(string_value, date_format)
|
53
|
+
end
|
54
|
+
when :datetime
|
55
|
+
if date_format.nil?
|
56
|
+
DateTime.parse(string_value)
|
57
|
+
else
|
58
|
+
DateTime.strptime(string_value, date_format)
|
59
|
+
end
|
60
|
+
else
|
61
|
+
nil
|
62
|
+
end
|
63
|
+
rescue
|
64
|
+
TypeError.new(string_value, self)
|
65
|
+
end
|
66
|
+
|
67
|
+
parsed
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Haecksler
|
2
|
+
|
3
|
+
def self.chop(input)
|
4
|
+
dsl = Dsl.new.chop(input)
|
5
|
+
yield dsl
|
6
|
+
dsl.parse!
|
7
|
+
end
|
8
|
+
|
9
|
+
class Dsl
|
10
|
+
|
11
|
+
def chop(input)
|
12
|
+
@input = input
|
13
|
+
@row = Row.new
|
14
|
+
@header_check = proc { false }
|
15
|
+
@header = false
|
16
|
+
@footer_check = proc { false }
|
17
|
+
@footer = false
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def column(name, size, type=:string, date_format=nil)
|
22
|
+
@row << _column(name, size, type, date_format)
|
23
|
+
end
|
24
|
+
|
25
|
+
def header_trap(&proc)
|
26
|
+
@header_check = proc
|
27
|
+
end
|
28
|
+
|
29
|
+
def footer_trap(&proc)
|
30
|
+
@footer_check = proc
|
31
|
+
end
|
32
|
+
|
33
|
+
def header(name, size, type=:string, date_format=nil)
|
34
|
+
@header ||= HeaderRow.new
|
35
|
+
@header << _column(name, size, type, date_format)
|
36
|
+
end
|
37
|
+
|
38
|
+
def footer(name, size, type=:string, date_format=nil)
|
39
|
+
@footer ||= FooterRow.new
|
40
|
+
@footer << _column(name, size, type, date_format)
|
41
|
+
end
|
42
|
+
|
43
|
+
def parse!
|
44
|
+
Sheet.new(@input, {
|
45
|
+
row: @row,
|
46
|
+
header_check: @header_check,
|
47
|
+
header: @header,
|
48
|
+
footer_check: @footer_check,
|
49
|
+
footer: @footer}
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
def _column(name, size, type, date_format)
|
55
|
+
Column.new({name: name, size: size, type: type, date_format: date_format})
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Haecksler
|
2
|
+
|
3
|
+
class Row
|
4
|
+
attr_reader :columns
|
5
|
+
|
6
|
+
def initialize(columns = [])
|
7
|
+
@columns = columns
|
8
|
+
end
|
9
|
+
|
10
|
+
def <<(column)
|
11
|
+
@columns << column
|
12
|
+
end
|
13
|
+
|
14
|
+
def [](key)
|
15
|
+
begin
|
16
|
+
@columns.find{|c| c.name == key }.value
|
17
|
+
rescue
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse(input)
|
23
|
+
|
24
|
+
indizes = columns.map(&:size).reduce([0]) do |memo,item|
|
25
|
+
memo << (memo.last.to_i + item)
|
26
|
+
memo
|
27
|
+
end
|
28
|
+
|
29
|
+
slices = input.split(//).each_with_index.slice_before { | element | indizes.include? element[1] }
|
30
|
+
|
31
|
+
parsed_columns = slices.map {|slice| slice.map{|i| i[0]}.join("")}.zip(columns).map do |text, column|
|
32
|
+
column.parse(text)
|
33
|
+
end
|
34
|
+
|
35
|
+
@columns = parsed_columns
|
36
|
+
|
37
|
+
self
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
def header?
|
42
|
+
false
|
43
|
+
end
|
44
|
+
|
45
|
+
def footer?
|
46
|
+
false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class HeaderRow < Row
|
51
|
+
def header?
|
52
|
+
true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class FooterRow < Row
|
57
|
+
def footer?
|
58
|
+
true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Haecksler
|
2
|
+
class Sheet
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
attr_reader :row
|
6
|
+
|
7
|
+
DEFAULT_OPTIONS={ header: false, footer: false, header_check: proc{ false }, footer_check: proc{ false } }
|
8
|
+
|
9
|
+
def initialize(input, options={})
|
10
|
+
options = DEFAULT_OPTIONS.merge(options)
|
11
|
+
@header = options[:header]
|
12
|
+
@footer = options[:footer]
|
13
|
+
@row = options[:row]
|
14
|
+
@input = input
|
15
|
+
@header_check = options[:header_check]
|
16
|
+
@footer_check = options[:footer_check]
|
17
|
+
end
|
18
|
+
|
19
|
+
def each
|
20
|
+
@input.lazy.each do |input|
|
21
|
+
if @header_check.call(input)
|
22
|
+
yield @header.parse(input.chomp)
|
23
|
+
elsif @footer_check.call(input)
|
24
|
+
yield @footer.parse(input.chomp)
|
25
|
+
else
|
26
|
+
yield @row.parse(input.chomp)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
data/spec/column_spec.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Haecksler
|
4
|
+
describe Column do
|
5
|
+
describe "a string column" do
|
6
|
+
subject do
|
7
|
+
Column.new(name: "First Name", size: 10, type: :string )
|
8
|
+
end
|
9
|
+
it "should require all options to be set" do
|
10
|
+
expect(subject).to be_a Column
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should parse a string column" do
|
14
|
+
parsed = subject.parse("Frank")
|
15
|
+
expect(parsed).to be_a ParsedColumn
|
16
|
+
expect(parsed.name).to eq("First Name")
|
17
|
+
expect(parsed.value).to eq "Frank"
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should trim trailing whitespace" do
|
21
|
+
expect(subject.parse("Frank ").value).to eq "Frank"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should keep leading whitespace" do
|
25
|
+
expect(subject.parse(" Frank ").value).to eq " Frank"
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "Integer column" do
|
31
|
+
|
32
|
+
subject do
|
33
|
+
Column.new(name: "I1", size: 2, type: :integer)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should handle integer column" do
|
37
|
+
expect(subject.parse("2 ").value).to eq 2
|
38
|
+
expect(subject.parse(" 2").value).to eq 2
|
39
|
+
expect(subject.parse("02").value).to eq 2
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should yield a TypeError for wrong type column" do
|
43
|
+
expect(subject.parse("x ").value).to be_a TypeError
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "Float column" do
|
49
|
+
subject do
|
50
|
+
Column.new(name: "I1", size: 3, type: :float)
|
51
|
+
end
|
52
|
+
it "should handle double column" do
|
53
|
+
expect(subject.parse("2 ").value).to eq 2.0
|
54
|
+
expect(subject.parse("2.0").value).to eq 2.0
|
55
|
+
expect(subject.parse("02").value).to eq 2.0
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should yield a TypeError for wrong type column" do
|
59
|
+
expect(subject.parse("x ").value).to be_a TypeError
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "Date column" do
|
64
|
+
subject do
|
65
|
+
Column.new(name: "I1", size: 8, type: :date)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should handle date column" do
|
69
|
+
expect(subject.parse("20130304").value).to eq Date.new(2013,3,4)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should respect date format" do
|
73
|
+
c = Column.new(name:"I2", size: 10, type: :date, date_format: '%d.%m.%Y')
|
74
|
+
expect(c.parse("03.12.2008").value).to eq Date.new(2008,12,3)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "DateTime column" do
|
79
|
+
subject do
|
80
|
+
Column.new(name: "I1", size: 8, type: :datetime)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should handle date column" do
|
84
|
+
expect(subject.parse("20130304").value).to eq DateTime.new(2013,3,4)
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
data/spec/complete.txt
ADDED
data/spec/dsl_spec.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Haecksler
|
4
|
+
|
5
|
+
describe Haecksler do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@data = [
|
9
|
+
"01Frank 20080305",
|
10
|
+
"02Sam 20091205"
|
11
|
+
]
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should work without header/footer" do
|
15
|
+
|
16
|
+
result = Haecksler.chop(@data) do |h|
|
17
|
+
h.column "Id", 2, :integer
|
18
|
+
h.column "Name", 10
|
19
|
+
h.column "Date", 8, :date
|
20
|
+
end
|
21
|
+
|
22
|
+
expect(result.first["Name"]).to eq "Frank"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should work with header" do
|
26
|
+
|
27
|
+
@data.unshift("HEADER01")
|
28
|
+
result = Haecksler.chop(@data) do |h|
|
29
|
+
h.header_trap {|header| header =~/^HEADER/ }
|
30
|
+
h.header "HName", 6
|
31
|
+
h.header "SomeNumber", 2, :integer
|
32
|
+
h.column "Id", 2, :integer
|
33
|
+
h.column "Name", 10
|
34
|
+
h.column "Date", 8, :date
|
35
|
+
end
|
36
|
+
header = result.first
|
37
|
+
|
38
|
+
expect(header["HName"]).to eq "HEADER"
|
39
|
+
expect(header["SomeNumber"]).to eq 1
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should work with footer" do
|
43
|
+
@data << "FOOTER02"
|
44
|
+
result = Haecksler.chop(@data) do |h|
|
45
|
+
h.footer_trap {|footer| footer =~/^FOOTER/ }
|
46
|
+
h.footer "footer", 6
|
47
|
+
h.footer "SomeNumber", 2, :integer
|
48
|
+
h.column "Id", 2, :integer
|
49
|
+
h.column "Name", 10
|
50
|
+
h.column "Date", 8, :date
|
51
|
+
end
|
52
|
+
|
53
|
+
footer = result.to_a.last
|
54
|
+
expect(footer["footer"]).to eq "FOOTER"
|
55
|
+
expect(footer["SomeNumber"]).to eq 2
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should work on full sample" do
|
59
|
+
file = File.open(File.expand_path("../complete.txt",__FILE__))
|
60
|
+
|
61
|
+
result = Haecksler.chop(file) do |h|
|
62
|
+
|
63
|
+
h.header_trap {|header| header =~/^FILE/ }
|
64
|
+
h.header "HName", 4
|
65
|
+
h.header "HExtra", 6
|
66
|
+
|
67
|
+
h.column "Id", 2, :integer
|
68
|
+
h.column "Name", 10
|
69
|
+
h.column "Date", 8, :date
|
70
|
+
|
71
|
+
h.footer_trap {|footer| footer =~/^END/ }
|
72
|
+
h.footer "FFooter", 3
|
73
|
+
h.footer "FDate", 8, :date
|
74
|
+
end.to_a
|
75
|
+
|
76
|
+
|
77
|
+
expect(result[0]).to be_a HeaderRow
|
78
|
+
expect(result[1]).to be_a Row
|
79
|
+
expect(result[2]).to be_a Row
|
80
|
+
expect(result[3]).to be_a FooterRow
|
81
|
+
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
data/spec/row_spec.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Haecksler
|
4
|
+
describe Row do
|
5
|
+
it "should initialize with empty columns" do
|
6
|
+
expect(subject.columns).to have(0).things
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should not be header or footer" do
|
10
|
+
expect(subject).not_to be_header
|
11
|
+
expect(subject).not_to be_footer
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should receive more columns" do
|
15
|
+
subject << Column.new(name: "Name", size: 10)
|
16
|
+
expect(subject.columns).to have(1).thing
|
17
|
+
subject << Column.new(name: "Id", size: 2)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should parse a row" do
|
21
|
+
subject << Column.new(name: "Name", size: 10)
|
22
|
+
subject << Column.new(name: "Id", size: 2)
|
23
|
+
|
24
|
+
parsed_result = subject.parse("Frank AB")
|
25
|
+
|
26
|
+
expect(parsed_result.columns).to have(2).things
|
27
|
+
|
28
|
+
expect(parsed_result.columns.first.value).to eq "Frank"
|
29
|
+
expect(parsed_result.columns.last.value).to eq "AB"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should parse a row with UTF" do
|
33
|
+
subject << Column.new(name: "Name", size: 10)
|
34
|
+
subject << Column.new(name: "Id", size: 2)
|
35
|
+
|
36
|
+
parsed_result = subject.parse("Fränk €B")
|
37
|
+
|
38
|
+
expect(parsed_result.columns).to have(2).things
|
39
|
+
|
40
|
+
expect(parsed_result.columns.first.value).to eq "Fränk"
|
41
|
+
expect(parsed_result.columns.last.value).to eq "€B"
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should have Hash like access" do
|
46
|
+
subject << Column.new(name: "Name", size: 3)
|
47
|
+
parsed_result = subject.parse("ABC")
|
48
|
+
expect(parsed_result["Name"]).to eq("ABC")
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should return nil for unknown key" do
|
52
|
+
subject << Column.new(name: "Name", size: 3)
|
53
|
+
parsed_result = subject.parse("ABC")
|
54
|
+
expect(parsed_result["Unknown"]).to be_nil
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
describe HeaderRow do
|
60
|
+
it "should behave as header" do
|
61
|
+
expect(subject).to be_header
|
62
|
+
expect(subject).not_to be_footer
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe FooterRow do
|
67
|
+
it "should behave as footer" do
|
68
|
+
expect(subject).not_to be_header
|
69
|
+
expect(subject).to be_footer
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/spec/sheet_spec.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Haecksler
|
4
|
+
describe Sheet do
|
5
|
+
before(:each) do
|
6
|
+
@data = [
|
7
|
+
"01Frank 20080305",
|
8
|
+
"02Sam 20091205"
|
9
|
+
]
|
10
|
+
@row = Row.new
|
11
|
+
@row << Column.new(name: "Id", size: 2, type: :integer)
|
12
|
+
@row << Column.new(name: "Name", size: 10)
|
13
|
+
@row << Column.new(name: "Date", size: 8, type: :date)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should parse some array" do
|
17
|
+
expect(Sheet.new(@data, row: @row)).to have(2).things
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should parse with header" do
|
21
|
+
@data = ["HEADER1"] + @data
|
22
|
+
header_row = Row.new
|
23
|
+
header_row << Column.new(name: "f1", size: 6)
|
24
|
+
header_row << Column.new(name: "f2", size: 1, type: :integer)
|
25
|
+
|
26
|
+
s = Sheet.new(@data, row: @row, header: header_row, header_check: proc{|line| line =~ /^HEADER/ })
|
27
|
+
|
28
|
+
expect(s).to be_an Enumerable
|
29
|
+
expect(s).to have(3).things
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "with a File" do
|
33
|
+
|
34
|
+
it "should process file without header" do
|
35
|
+
|
36
|
+
File.open(File.expand_path("../simple.txt",__FILE__)) do |f|
|
37
|
+
s = Sheet.new(f, row: @row)
|
38
|
+
expect(s).to be_an Enumerable
|
39
|
+
first = s.first
|
40
|
+
expect(first).not_to be_nil
|
41
|
+
expect(first["Name"]).to eq "Frank"
|
42
|
+
f.rewind
|
43
|
+
expect(s).to have(2).things
|
44
|
+
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/spec/simple.txt
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'haecksler'
|
2
|
+
|
3
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
4
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
5
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
6
|
+
# loaded once.
|
7
|
+
#
|
8
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
11
|
+
config.run_all_when_everything_filtered = true
|
12
|
+
config.filter_run :focus
|
13
|
+
|
14
|
+
# Run specs in random order to surface order dependencies. If you find an
|
15
|
+
# order dependency and want to debug it, you can fix the order by providing
|
16
|
+
# the seed, which is printed after each run.
|
17
|
+
# --seed 1234
|
18
|
+
config.order = 'random'
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: haecksler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Frank Falkenberg
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-04-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.5.3
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.5.3
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
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: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.14'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.14'
|
55
|
+
description: Haecksler is the German word for a wood chipper
|
56
|
+
email:
|
57
|
+
- faltibrain@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- .gitignore
|
63
|
+
- .rspec
|
64
|
+
- .travis.yml
|
65
|
+
- Gemfile
|
66
|
+
- LICENSE.txt
|
67
|
+
- README.md
|
68
|
+
- Rakefile
|
69
|
+
- haecksler.gemspec
|
70
|
+
- lib/haecksler.rb
|
71
|
+
- lib/haecksler/column.rb
|
72
|
+
- lib/haecksler/dsl.rb
|
73
|
+
- lib/haecksler/row.rb
|
74
|
+
- lib/haecksler/sheet.rb
|
75
|
+
- lib/haecksler/version.rb
|
76
|
+
- spec/column_spec.rb
|
77
|
+
- spec/complete.txt
|
78
|
+
- spec/dsl_spec.rb
|
79
|
+
- spec/row_spec.rb
|
80
|
+
- spec/sheet_spec.rb
|
81
|
+
- spec/simple.txt
|
82
|
+
- spec/spec_helper.rb
|
83
|
+
homepage: https://github.com/falti/haecksler
|
84
|
+
licenses:
|
85
|
+
- MIT
|
86
|
+
metadata: {}
|
87
|
+
post_install_message:
|
88
|
+
rdoc_options: []
|
89
|
+
require_paths:
|
90
|
+
- lib
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - '>='
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - '>='
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
requirements: []
|
102
|
+
rubyforge_project:
|
103
|
+
rubygems_version: 2.1.11
|
104
|
+
signing_key:
|
105
|
+
specification_version: 4
|
106
|
+
summary: Library to parse fixed-length files
|
107
|
+
test_files:
|
108
|
+
- spec/column_spec.rb
|
109
|
+
- spec/complete.txt
|
110
|
+
- spec/dsl_spec.rb
|
111
|
+
- spec/row_spec.rb
|
112
|
+
- spec/sheet_spec.rb
|
113
|
+
- spec/simple.txt
|
114
|
+
- spec/spec_helper.rb
|