fixy 0.0.3 → 0.0.4

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: 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