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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9262fa93a8633148f73159bacbbcb4d21ed4b408
4
- data.tar.gz: 8994b5cd70ce533762cab617358e21f69cf12547
3
+ metadata.gz: da0096eb40aeacfe04cf63c2389ca65064fcbae5
4
+ data.tar.gz: 9e0721a2d0987f29d7fea9a33cfd99e8c1658b4b
5
5
  SHA512:
6
- metadata.gz: ff5b8c0e48810b780fa12ef0eaa2c64c4ca4c7a3a36790808cc31b09d260149e83158eaab624231311e368842b4192d550b1ba176be6fb7e87141faaedaf14d4
7
- data.tar.gz: 17ed2f4d5c446805a342181736bcf4e6c1f672b20e8b16b3f184d1c66f6fc4bde028e85ce7e4e439251162ef7931c5f907908799d31fc49c5054061f34a363d6
6
+ metadata.gz: ecbac0ae5a1a21134cacf33dd911a88c0c8b908617ee4c5261920a13bd224e1ed07311ec62da655a6d021b39b1cef4dd0664999f0397c3bbf936ceb9ba3fc202
7
+ data.tar.gz: 0fedb296e3d9952edb107169a4c8fa15285155d817d6e7ee2a2a25f66552537fca9e7cb1272c44779c1ebe373005c62a09254e4d2e015431d9db02f53d090a01
@@ -1,3 +1,7 @@
1
+ ## v0.0.4
2
+
3
+ * Basic support for parsing records
4
+
1
5
  ## v0.0.3
2
6
 
3
7
  * Allow passing block to field to define field_value
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ [![Build Status](https://travis-ci.org/Chetane/fixy.svg?branch=master)](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
- module Formatter
154
- module Numeric
155
- def format_numeric(input, length)
156
- input = input.to_s
157
- raise ArgumentError, "Invalid Input (only digits are accepted)" unless input =~ /^\d+$/
158
- raise ArgumentError, "Not enough length (input: #{input}, length: #{length})" if input.length > length
159
- input.rjust(length, '0')
160
- end
161
- end
162
- end
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
 
@@ -36,5 +36,9 @@ module Fixy
36
36
  def append_record(record)
37
37
  @content << record.generate(debug_mode)
38
38
  end
39
+
40
+ def parse_record(klass, record)
41
+ @content << klass.parse(record, debug_mode)[:record]
42
+ end
39
43
  end
40
- end
44
+ end
@@ -62,13 +62,50 @@ module Fixy
62
62
  {}
63
63
  end
64
64
  end
65
- end
66
65
 
67
- attr_accessor :debug_mode
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
- @debug_mode = debug
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
@@ -1,3 +1,3 @@
1
1
  module Fixy
2
- VERSION = '0.0.3'
2
+ VERSION = '0.0.4'
3
3
  end
@@ -0,0 +1,2 @@
1
+ <div><pre><span class='odd' data-column='1' data-method='first_name' data-size='10' data-format='alphanumeric'>Sarah </span><span class='even' data-column='11' data-method='last_name' data-size='10' data-format='alphanumeric'>Kerrigan </span>
2
+ </pre></div>
@@ -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
- it 'should generate fixed width document' do
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
- class IdentityRecord < Fixy::Record
16
- set_record_length 20
17
- include Fixy::Formatter::Alphanumeric
18
- field :first_name, 10, '1-10' , :alphanumeric
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
- def initialize(first_name, last_name)
22
- @first_name = first_name
23
- @last_name = last_name
24
- end
24
+ field_value :first_name, -> { @first_name }
25
+ field_value :last_name , -> { @last_name }
26
+ end
25
27
 
26
- field_value :first_name, -> { @first_name }
27
- field_value :last_name , -> { @last_name }
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
- class PeopleDocument < Fixy::Document
31
- def build
32
- append_record IdentityRecord.new('Sarah', 'Kerrigan')
33
- append_record IdentityRecord.new('Jim', 'Raynor')
34
- prepend_record IdentityRecord.new('Arcturus', 'Mengsk')
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
- PeopleDocument.new.generate "Arcturus Mengsk \nSarah Kerrigan \nJim Raynor "
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
@@ -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.3
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