fixy 0.0.3 → 0.0.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 +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +54 -10
- data/lib/fixy/document.rb +5 -1
- data/lib/fixy/record.rb +40 -7
- data/lib/fixy/version.rb +1 -1
- data/spec/fixtures/debug_parsed_record.txt +2 -0
- data/spec/fixy/document_spec.rb +31 -19
- data/spec/fixy/record_spec.rb +77 -0
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: da0096eb40aeacfe04cf63c2389ca65064fcbae5
|
4
|
+
data.tar.gz: 9e0721a2d0987f29d7fea9a33cfd99e8c1658b4b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ecbac0ae5a1a21134cacf33dd911a88c0c8b908617ee4c5261920a13bd224e1ed07311ec62da655a6d021b39b1cef4dd0664999f0397c3bbf936ceb9ba3fc202
|
7
|
+
data.tar.gz: 0fedb296e3d9952edb107169a4c8fa15285155d817d6e7ee2a2a25f66552537fca9e7cb1272c44779c1ebe373005c62a09254e4d2e015431d9db02f53d090a01
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
[](https://travis-ci.org/Chetane/fixy)
|
2
|
+
|
1
3
|
## fixy
|
2
4
|
|
3
5
|
Library for generating fixed width flat file documents.
|
@@ -85,6 +87,13 @@ class PersonRecord < Fixy::Record
|
|
85
87
|
end
|
86
88
|
```
|
87
89
|
|
90
|
+
You can also specify the field definition and field value together by passing a block to `field`.
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
|
94
|
+
field(:first_name, 10, '1-10', :alphanumeric) { @first_name }
|
95
|
+
```
|
96
|
+
|
88
97
|
Given a record definition, you can generate a single line (e.g. for testing purposes):
|
89
98
|
|
90
99
|
```ruby
|
@@ -98,6 +107,24 @@ PersonRecord.new('Sarah', 'Kerrigan').generate
|
|
98
107
|
|
99
108
|
Most of the time however, you will not have to call `generate` directly, as the document will take care of that part.
|
100
109
|
|
110
|
+
|
111
|
+
### Parsing existing records
|
112
|
+
|
113
|
+
There is limited support for parsing existing records and documents. Because the formatters are currently uni-directionals, formatted values are extracted.
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
PersonRecord.parse "Sarah Kerrigan "
|
117
|
+
|
118
|
+
# This will generate the following hash
|
119
|
+
# {
|
120
|
+
# :fields => [
|
121
|
+
# { :name => :first_name, :value => "Sarah "},
|
122
|
+
# { :name => :last_name, :value => "Kerrigan "}
|
123
|
+
# ],
|
124
|
+
# :record => "Sarah Kerrigan \n"
|
125
|
+
# }
|
126
|
+
```
|
127
|
+
|
101
128
|
## Document definition
|
102
129
|
|
103
130
|
A document is composed of a multitude of records (instances of a `Fixy::Record`). Because some document specification require earlier records to contain a count of upcoming records, both appending and prepending records is supported during a document definition. Below is an example of a document, based on the record defined in the previous section.
|
@@ -112,6 +139,23 @@ class PeopleDocument < Fixy::Document
|
|
112
139
|
end
|
113
140
|
```
|
114
141
|
|
142
|
+
### Document definition using existing records
|
143
|
+
|
144
|
+
Occasionally, it is useful to generate a document using existing records. This is particularly handy when generating debug documents (detailed in the next section).
|
145
|
+
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
class ParsedPeopleDocument < Fixy::Document
|
149
|
+
def build
|
150
|
+
parse_record IdentityRecord, 'Arcturus Mengsk '
|
151
|
+
parse_record IdentityRecord, 'Sarah Kerrigan '
|
152
|
+
parse_record IdentityRecord, 'Jim Raynor '
|
153
|
+
end
|
154
|
+
end
|
155
|
+
```
|
156
|
+
|
157
|
+
|
158
|
+
|
115
159
|
## Generating a document
|
116
160
|
|
117
161
|
With records and documents defined, generating documents is a breeze:
|
@@ -150,16 +194,16 @@ An example for formatter definition:
|
|
150
194
|
```ruby
|
151
195
|
|
152
196
|
module Fixy
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
197
|
+
module Formatter
|
198
|
+
module Numeric
|
199
|
+
def format_numeric(input, length)
|
200
|
+
input = input.to_s
|
201
|
+
raise ArgumentError, "Invalid Input (only digits are accepted)" unless input =~ /^\d+$/
|
202
|
+
raise ArgumentError, "Not enough length (input: #{input}, length: #{length})" if input.length > length
|
203
|
+
input.rjust(length, '0')
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
163
207
|
end
|
164
208
|
```
|
165
209
|
|
data/lib/fixy/document.rb
CHANGED
data/lib/fixy/record.rb
CHANGED
@@ -62,13 +62,50 @@ module Fixy
|
|
62
62
|
{}
|
63
63
|
end
|
64
64
|
end
|
65
|
-
end
|
66
65
|
|
67
|
-
|
66
|
+
# Parse an existing record
|
67
|
+
def parse(record, debug = false)
|
68
|
+
raise ArgumentError, 'Record must be a string' unless record.is_a? String
|
69
|
+
|
70
|
+
unless record.length == record_length
|
71
|
+
raise ArgumentError, "Record length is invalid (Expected #{record_length})"
|
72
|
+
end
|
73
|
+
|
74
|
+
decorator = debug ? Fixy::Decorator::Debug : Fixy::Decorator::Default
|
75
|
+
fields = []
|
76
|
+
output = ''
|
77
|
+
current_position = 1
|
78
|
+
current_record = 1
|
79
|
+
|
80
|
+
while current_position <= record_length do
|
81
|
+
|
82
|
+
field = record_fields[current_position]
|
83
|
+
raise StandardError, "Undefined field for position #{current_position}" unless field
|
84
|
+
|
85
|
+
# Extract field data from existing record
|
86
|
+
from = field[:from] - 1
|
87
|
+
to = field[:to] - 1
|
88
|
+
method = field[:name]
|
89
|
+
value = record[from..to]
|
90
|
+
|
91
|
+
formatted_value = decorator.field(value, current_record, current_position, method, field[:size], field[:type])
|
92
|
+
output << formatted_value
|
93
|
+
fields << { name: method, value: value }
|
94
|
+
|
95
|
+
current_position = field[:to] + 1
|
96
|
+
current_record += 1
|
97
|
+
end
|
98
|
+
|
99
|
+
# Documentation mandates that every record ends with new line.
|
100
|
+
output << "\n"
|
101
|
+
|
102
|
+
{ fields: fields, record: decorator.record(output) }
|
103
|
+
end
|
104
|
+
end
|
68
105
|
|
69
106
|
# Generate the entry based on the record structure
|
70
107
|
def generate(debug = false)
|
71
|
-
|
108
|
+
decorator = debug ? Fixy::Decorator::Debug : Fixy::Decorator::Default
|
72
109
|
output = ''
|
73
110
|
current_position = 1
|
74
111
|
current_record = 1
|
@@ -107,9 +144,5 @@ module Fixy
|
|
107
144
|
def record_fields
|
108
145
|
self.class.record_fields
|
109
146
|
end
|
110
|
-
|
111
|
-
def decorator
|
112
|
-
debug_mode ? Fixy::Decorator::Debug : Fixy::Decorator::Default
|
113
|
-
end
|
114
147
|
end
|
115
148
|
end
|
data/lib/fixy/version.rb
CHANGED
data/spec/fixy/document_spec.rb
CHANGED
@@ -10,33 +10,45 @@ describe 'Defining a Document' do
|
|
10
10
|
end
|
11
11
|
|
12
12
|
context 'when a build action is defined' do
|
13
|
-
|
13
|
+
class IdentityRecord < Fixy::Record
|
14
|
+
set_record_length 20
|
15
|
+
include Fixy::Formatter::Alphanumeric
|
16
|
+
field :first_name, 10, '1-10' , :alphanumeric
|
17
|
+
field :last_name , 10, '11-20', :alphanumeric
|
14
18
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
field :last_name , 10, '11-20', :alphanumeric
|
19
|
+
def initialize(first_name, last_name)
|
20
|
+
@first_name = first_name
|
21
|
+
@last_name = last_name
|
22
|
+
end
|
20
23
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
24
|
+
field_value :first_name, -> { @first_name }
|
25
|
+
field_value :last_name , -> { @last_name }
|
26
|
+
end
|
25
27
|
|
26
|
-
|
27
|
-
|
28
|
+
class PeopleDocument < Fixy::Document
|
29
|
+
def build
|
30
|
+
append_record IdentityRecord.new('Sarah', 'Kerrigan')
|
31
|
+
append_record IdentityRecord.new('Jim', 'Raynor')
|
32
|
+
prepend_record IdentityRecord.new('Arcturus', 'Mengsk')
|
28
33
|
end
|
34
|
+
end
|
29
35
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
36
|
+
class ParsedPeopleDocument < Fixy::Document
|
37
|
+
def build
|
38
|
+
parse_record IdentityRecord, 'Arcturus Mengsk '
|
39
|
+
parse_record IdentityRecord, 'Sarah Kerrigan '
|
40
|
+
parse_record IdentityRecord, 'Jim Raynor '
|
36
41
|
end
|
42
|
+
end
|
37
43
|
|
38
|
-
|
44
|
+
it 'should generate fixed width document' do
|
45
|
+
PeopleDocument.new.generate.should eq "Arcturus Mengsk \nSarah Kerrigan \nJim Raynor \n"
|
39
46
|
PeopleDocument.new.generate(true).should eq File.read('spec/fixtures/debug_document.txt')
|
40
47
|
end
|
48
|
+
|
49
|
+
it 'should parse fixed width document' do
|
50
|
+
ParsedPeopleDocument.new.generate.should eq "Arcturus Mengsk \nSarah Kerrigan \nJim Raynor \n"
|
51
|
+
ParsedPeopleDocument.new.generate(true).should eq File.read('spec/fixtures/debug_document.txt')
|
52
|
+
end
|
41
53
|
end
|
42
54
|
end
|
data/spec/fixy/record_spec.rb
CHANGED
@@ -169,3 +169,80 @@ describe 'Generating a Record' do
|
|
169
169
|
end
|
170
170
|
end
|
171
171
|
end
|
172
|
+
|
173
|
+
describe 'Parsing a record' do
|
174
|
+
context 'when properly defined' do
|
175
|
+
let(:record) { "Sarah Kerrigan " }
|
176
|
+
class PersonRecordK < Fixy::Record
|
177
|
+
include Fixy::Formatter::Alphanumeric
|
178
|
+
|
179
|
+
set_record_length 20
|
180
|
+
|
181
|
+
field :first_name, 10, '1-10' , :alphanumeric
|
182
|
+
field :last_name , 10, '11-20', :alphanumeric
|
183
|
+
|
184
|
+
field_value :first_name, -> { 'Sarah' }
|
185
|
+
|
186
|
+
def last_name
|
187
|
+
'Kerrigan'
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'should generate fixed width record' do
|
192
|
+
PersonRecordE.parse(record).should eq({
|
193
|
+
record: (record + "\n"),
|
194
|
+
fields: [
|
195
|
+
{ name: :first_name, value: 'Sarah '},
|
196
|
+
{ name: :last_name, value: 'Kerrigan '}
|
197
|
+
]
|
198
|
+
})
|
199
|
+
end
|
200
|
+
|
201
|
+
context 'when using the debug flag' do
|
202
|
+
it 'should produce a debug log' do
|
203
|
+
PersonRecordE.parse(record, true).should eq({
|
204
|
+
record: File.read('spec/fixtures/debug_parsed_record.txt'),
|
205
|
+
fields: [
|
206
|
+
{ name: :first_name, value: 'Sarah '},
|
207
|
+
{ name: :last_name, value: 'Kerrigan '}
|
208
|
+
]
|
209
|
+
})
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
context 'when invalid record provided' do
|
214
|
+
context 'with a non-string record type' do
|
215
|
+
it 'should raise an error' do
|
216
|
+
expect {
|
217
|
+
PersonRecordE.parse(nil, true)
|
218
|
+
}.to raise_error(StandardError, 'Record must be a string')
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
context 'with an invalid record length' do
|
223
|
+
it 'should raise an error' do
|
224
|
+
expect {
|
225
|
+
PersonRecordE.parse('', true)
|
226
|
+
}.to raise_error(StandardError, 'Record length is invalid (Expected 20)')
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
context 'when definition is incomplete (e.g. undefined columns)' do
|
233
|
+
it 'should raise an error' do
|
234
|
+
class PersonRecordL < Fixy::Record
|
235
|
+
include Fixy::Formatter::Alphanumeric
|
236
|
+
set_record_length 20
|
237
|
+
field :first_name, 10, '1-10' , :alphanumeric
|
238
|
+
field :last_name , 8, '11-18', :alphanumeric
|
239
|
+
field_value :first_name, -> { 'Sarah' }
|
240
|
+
field_value :last_name, -> { 'Kerrigan' }
|
241
|
+
end
|
242
|
+
|
243
|
+
expect {
|
244
|
+
PersonRecordL.parse(' ' * 20)
|
245
|
+
}.to raise_error(StandardError, "Undefined field for position 19")
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fixy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Omar Skalli
|
@@ -74,6 +74,7 @@ files:
|
|
74
74
|
- lib/fixy/record.rb
|
75
75
|
- lib/fixy/version.rb
|
76
76
|
- spec/fixtures/debug_document.txt
|
77
|
+
- spec/fixtures/debug_parsed_record.txt
|
77
78
|
- spec/fixtures/debug_record.txt
|
78
79
|
- spec/fixy/document_spec.rb
|
79
80
|
- spec/fixy/record_spec.rb
|
@@ -104,6 +105,7 @@ specification_version: 4
|
|
104
105
|
summary: Provides a DSL for defining, generating, and debugging fixed width documents.
|
105
106
|
test_files:
|
106
107
|
- spec/fixtures/debug_document.txt
|
108
|
+
- spec/fixtures/debug_parsed_record.txt
|
107
109
|
- spec/fixtures/debug_record.txt
|
108
110
|
- spec/fixy/document_spec.rb
|
109
111
|
- spec/fixy/record_spec.rb
|