flat 0.1.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 +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +14 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +15 -0
- data/Gemfile +4 -0
- data/Guardfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +106 -0
- data/Rakefile +18 -0
- data/flat.gemspec +36 -0
- data/lib/flat/errors.rb +33 -0
- data/lib/flat/field.rb +171 -0
- data/lib/flat/file.rb +18 -0
- data/lib/flat/file_data.rb +123 -0
- data/lib/flat/layout.rb +30 -0
- data/lib/flat/read_operations.rb +50 -0
- data/lib/flat/record.rb +99 -0
- data/lib/flat/version.rb +3 -0
- data/lib/flat.rb +79 -0
- data/spec/flat_file_helper.rb +27 -0
- data/spec/lib/flat/field_spec.rb +126 -0
- data/spec/lib/flat/file_data_spec.rb +46 -0
- data/spec/lib/flat/file_spec.rb +5 -0
- data/spec/lib/flat/record_spec.rb +40 -0
- data/spec/lib/flat_spec.rb +28 -0
- data/spec/spec_helper.rb +17 -0
- metadata +247 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b8dda342a45881d96ffeec6a23b57f9697d820a0
|
4
|
+
data.tar.gz: 2d4a6c80305e3cf117f145d45ed789671e1934c7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 70a2839490d96e0dbcc8b32376c816b5f833bbd9935aa81b97bf79ed0ce7d3e21dbe916b7e2339de5c56bb14070af71a9da4b619707af96ddeabb62985794fea
|
7
|
+
data.tar.gz: faec279d9e961e3de45ad854527a4d4d5107c68720500b08c56d67c1364d0f12c4f7b4c9312df98b6bb12431a2903ad3848f363b97ba472205d4705c496626da
|
data/.coveralls.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
service_name: travis-ci
|
data/.gitignore
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
flat
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.2
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Mel Riffe
|
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,106 @@
|
|
1
|
+
# Flat
|
2
|
+
|
3
|
+
[](https://travis-ci.org/juicyparts/flat)
|
4
|
+
[](https://coveralls.io/r/juicyparts/flat)
|
5
|
+
|
6
|
+
Flat is a library to make processing Flat Flies as easy as CSV files. Easily process flat files with Flat. Specify the format in a subclass of Flat::File and read and write until the cows come home.
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
gem 'flat'
|
14
|
+
```
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install flat
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
A simple example for a flat file class for grabbing information about
|
27
|
+
people might look like this:
|
28
|
+
|
29
|
+
# Actual plain text, flat file data, 29 bytes
|
30
|
+
#
|
31
|
+
# 10 20
|
32
|
+
# 012345678901234567890123456789
|
33
|
+
# Walt Whitman 18190531
|
34
|
+
# Linus Torvalds 19691228
|
35
|
+
|
36
|
+
class People < Flat::File
|
37
|
+
|
38
|
+
add_field :first_name, width: 10, filter: :trim
|
39
|
+
add_field :last_name, width: 10, filter: ->(v) { v.strip }
|
40
|
+
add_field :birthday, width: 8, filter: BirthdayFilter
|
41
|
+
pad :autoname, width: 2
|
42
|
+
|
43
|
+
def self.trim(v)
|
44
|
+
v.trim
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
p = People.new
|
50
|
+
|
51
|
+
p.each_record(open('somefile.dat')) do |person|
|
52
|
+
|
53
|
+
puts "First Name: #{person.first_name}"
|
54
|
+
puts "Last Name : #{person.last_name}"
|
55
|
+
puts "Birthday : #{person.birthday}"
|
56
|
+
|
57
|
+
puts person.to_s
|
58
|
+
end
|
59
|
+
|
60
|
+
Consult the [RDocs](http://rubydoc.info/github/juicyparts/flat) for additional examples, and information on Filters and
|
61
|
+
Formatters.
|
62
|
+
|
63
|
+
## Contributing
|
64
|
+
|
65
|
+
1. Fork it ( https://github.com/juicyparts/flat/fork )
|
66
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
67
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
68
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
69
|
+
5. Create a new Pull Request
|
70
|
+
|
71
|
+
## Inspiration
|
72
|
+
|
73
|
+
I had been looking for a library to handle flat files in a manner similar to
|
74
|
+
the CSV library and stumbled upon the following:
|
75
|
+
|
76
|
+
* flat_filer (http://rubygems.org/gems/flat_filer)
|
77
|
+
* flat_filer (https://github.com/xforty/flat_filer)
|
78
|
+
* flat_filer (https://github.com/cheapRoc/flat_filer)
|
79
|
+
|
80
|
+
They all appeared to be abandoned so I decided to resurrect them with my own
|
81
|
+
spin on the implementation.
|
82
|
+
|
83
|
+
# LICENSE
|
84
|
+
|
85
|
+
Copyright (c) 2014 Mel Riffe
|
86
|
+
|
87
|
+
MIT License
|
88
|
+
|
89
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
90
|
+
a copy of this software and associated documentation files (the
|
91
|
+
"Software"), to deal in the Software without restriction, including
|
92
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
93
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
94
|
+
permit persons to whom the Software is furnished to do so, subject to
|
95
|
+
the following conditions:
|
96
|
+
|
97
|
+
The above copyright notice and this permission notice shall be
|
98
|
+
included in all copies or substantial portions of the Software.
|
99
|
+
|
100
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
101
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
102
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
103
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
104
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
105
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
106
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rspec/core/rake_task'
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'rdoc/task'
|
4
|
+
|
5
|
+
# Default directory to look in is `/specs`
|
6
|
+
# Run with `rake spec`
|
7
|
+
RSpec::Core::RakeTask.new(:spec) do |task|
|
8
|
+
task.rspec_opts = ['--color', '--format', 'documentation']
|
9
|
+
end
|
10
|
+
|
11
|
+
task :default => :spec
|
12
|
+
|
13
|
+
RDoc::Task.new(:rdoc => "doc", :clobber_rdoc => "doc:clean", :rerdoc => "doc:force") do |rdoc|
|
14
|
+
rdoc.rdoc_dir = 'doc'
|
15
|
+
rdoc.title = 'Flat Library Documentation'
|
16
|
+
rdoc.main = "README.md"
|
17
|
+
rdoc.rdoc_files.include("README.md", "lib/**/*.rb")
|
18
|
+
end
|
data/flat.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'flat/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "flat"
|
8
|
+
spec.version = Flat::VERSION
|
9
|
+
spec.authors = ["Mel Riffe"]
|
10
|
+
spec.email = ["mriffe@gmail.com"]
|
11
|
+
spec.summary = %q{Library to make processing Flat Flies as easy as CSV files.}
|
12
|
+
spec.description = %q{Easily process flat files with Flat. Specify the format in a subclass of Flat::File and read and write until the cows come home.}
|
13
|
+
spec.homepage = "http://rubydoc.info/github/juicyparts/flat"
|
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_runtime_dependency "extlib", "~> 0.9.0"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", ">= 1.6.2" # was "~> 1.7"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_development_dependency "rdoc", "~> 4.1.0"
|
26
|
+
|
27
|
+
spec.add_development_dependency "rspec", "~> 3.1.0"
|
28
|
+
spec.add_development_dependency "rspec-nc", "~> 0.2.0"
|
29
|
+
spec.add_development_dependency "guard", "~> 2.6.0"
|
30
|
+
spec.add_development_dependency "guard-rspec", "~> 4.3.0"
|
31
|
+
spec.add_development_dependency "pry", "~> 0.10.0"
|
32
|
+
spec.add_development_dependency "pry-remote", "~> 0.1.0"
|
33
|
+
spec.add_development_dependency "pry-nav", "~> 0.2.0"
|
34
|
+
|
35
|
+
spec.add_development_dependency "coveralls", "~> 0.7.0"
|
36
|
+
end
|
data/lib/flat/errors.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module Errors #:nodoc:
|
2
|
+
|
3
|
+
# = FlatFileError
|
4
|
+
#
|
5
|
+
# Generic error class and superclass of all other errors raised by Flat.
|
6
|
+
#
|
7
|
+
class FlatFileError < StandardError; end
|
8
|
+
|
9
|
+
# = LayoutConstructorError
|
10
|
+
#
|
11
|
+
# The specified layout definition was not valid.
|
12
|
+
#
|
13
|
+
class LayoutConstructorError < FlatFileError; end
|
14
|
+
|
15
|
+
# = RecordLengthError
|
16
|
+
#
|
17
|
+
# Generic error having to do with line lengths not meeting expectations.
|
18
|
+
#
|
19
|
+
class RecordLengthError < FlatFileError; end
|
20
|
+
|
21
|
+
# = ShortRecordError
|
22
|
+
#
|
23
|
+
# The incoming line was shorter than expections defined.
|
24
|
+
#
|
25
|
+
class ShortRecordError < RecordLengthError; end
|
26
|
+
|
27
|
+
# = LongRecordError
|
28
|
+
#
|
29
|
+
# The incoming line was longer than expections defined.
|
30
|
+
#
|
31
|
+
class LongRecordError < RecordLengthError; end
|
32
|
+
|
33
|
+
end # => module Errors
|
data/lib/flat/field.rb
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
##
|
2
|
+
# = Field
|
3
|
+
#
|
4
|
+
# A field definition tracks information that's necessary for
|
5
|
+
# FlatFile to process a particular field. This is typically
|
6
|
+
# added to a subclass of FlatFile like so:
|
7
|
+
#
|
8
|
+
# class SomeFile < FlatFile
|
9
|
+
# add_field :some_field_name, :width => 35
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
module Field
|
13
|
+
##
|
14
|
+
# = Class Methods
|
15
|
+
#
|
16
|
+
# Defines behavior for subclasses of Flat::File regarding the specification
|
17
|
+
# of the line structure contained in a flat file.
|
18
|
+
#
|
19
|
+
module ClassMethods
|
20
|
+
|
21
|
+
##
|
22
|
+
# Add a field to the FlatFile subclass. Options can include
|
23
|
+
#
|
24
|
+
# :width - number of characters in field (default 10)
|
25
|
+
# :filter - callack, lambda or code block for processing during reading
|
26
|
+
# :formatter - callback, lambda, or code block for processing during writing
|
27
|
+
#
|
28
|
+
# class SomeFile < FlatFile
|
29
|
+
# add_field :some_field_name, :width => 35
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# == Options
|
33
|
+
#
|
34
|
+
def add_field name = nil, options = {}, &block
|
35
|
+
fields << field_def = Field::Definition.new(name, options, self)
|
36
|
+
|
37
|
+
yield field_def if block_given?
|
38
|
+
|
39
|
+
pack_format << "A#{field_def.width}"
|
40
|
+
flat_file_data[:width] += field_def.width
|
41
|
+
# width += field_def.width # doesn't work for some reason
|
42
|
+
|
43
|
+
# TODO: Add a check here to ensure the Field has a name specified; it can be a String or Symbol
|
44
|
+
return field_def
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Add a pad field. To have the name auto generated, use :autoname for
|
49
|
+
# the name parameter. For options see +add_field+.
|
50
|
+
#
|
51
|
+
def pad name, options = {}
|
52
|
+
add_field ( name == :autoname ? new_pad_name : name ), options.merge( padding: true )
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
##
|
58
|
+
# Used to generate unique names for pad fields which use :autoname.
|
59
|
+
#
|
60
|
+
def new_pad_name #:nodoc:
|
61
|
+
"pad_#{unique_id}".to_sym
|
62
|
+
end
|
63
|
+
|
64
|
+
##
|
65
|
+
# Increments an id counter which is used to generate unique pad names
|
66
|
+
#
|
67
|
+
def unique_id #:nodoc:
|
68
|
+
@unique_id = (@unique_id || 0) + 1
|
69
|
+
end
|
70
|
+
|
71
|
+
end # => module ClassMethods
|
72
|
+
|
73
|
+
module InstanceMethods #:nodoc:
|
74
|
+
end # => module InstanceMethods
|
75
|
+
|
76
|
+
def self.included receiver #:nodoc:
|
77
|
+
receiver.extend ClassMethods
|
78
|
+
receiver.send :include, InstanceMethods
|
79
|
+
end
|
80
|
+
|
81
|
+
# = Definition
|
82
|
+
# Used in Flat::File subclasses to define how a Record is defined.
|
83
|
+
#
|
84
|
+
# class SomeFile < Flat::File
|
85
|
+
# add_field :some_field_name, :width => 35
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
class Definition #:nodoc:
|
89
|
+
attr_accessor :parent, :name, :width, :padding, :aggressive
|
90
|
+
attr_accessor :filters, :formatters, :map_in_proc
|
91
|
+
|
92
|
+
##
|
93
|
+
# Create a new FieldDef, having name and width. parent is a reference to the
|
94
|
+
# FlatFile subclass that contains this field definition. This reference is
|
95
|
+
# needed when calling filters if they are specified using a symbol.
|
96
|
+
#
|
97
|
+
# Options can be :padding (if present and a true value, field is marked as a
|
98
|
+
# pad field), :width, specify the field width, :formatter, specify a formatter,
|
99
|
+
# :filter, specify a filter.
|
100
|
+
#
|
101
|
+
def initialize name = null, options = {}, parent = {}
|
102
|
+
@parent, @name = parent, name
|
103
|
+
|
104
|
+
@width = options.fetch(:width, 10)
|
105
|
+
@padding = options.fetch(:padding, false)
|
106
|
+
@aggressive = options.fetch(:aggressive, false)
|
107
|
+
|
108
|
+
@filters = @formatters = Array.new
|
109
|
+
|
110
|
+
add_filter options[:filter]
|
111
|
+
add_formatter options[:formatter]
|
112
|
+
|
113
|
+
@map_in_proc = options[:map_in_proc]
|
114
|
+
end
|
115
|
+
|
116
|
+
def padding?
|
117
|
+
@padding
|
118
|
+
end
|
119
|
+
|
120
|
+
def aggressive?
|
121
|
+
@aggressive
|
122
|
+
end
|
123
|
+
|
124
|
+
##
|
125
|
+
# Add a filter. Filters are used for processing field data when a flat file is
|
126
|
+
# being processed. For fomratting the data when writing a flat file, see
|
127
|
+
# add_formatter
|
128
|
+
#
|
129
|
+
def add_filter filter = nil, &block
|
130
|
+
@filters.push( filter ) unless filter.blank?
|
131
|
+
@filters.push( block ) if block_given?
|
132
|
+
end
|
133
|
+
|
134
|
+
##
|
135
|
+
# Add a formatter. Formatters are used for formatting a field
|
136
|
+
# for rendering a record, or writing it to a file in the desired format.
|
137
|
+
#
|
138
|
+
def add_formatter formatter = nil, &block
|
139
|
+
@formatters.push( formatter ) unless formatter.blank?
|
140
|
+
@formatters.push( block ) if block_given?
|
141
|
+
end
|
142
|
+
|
143
|
+
##
|
144
|
+
# Passes value through the filters defined on this Field::Definition
|
145
|
+
#
|
146
|
+
def filter value
|
147
|
+
@filters.each do |filter|
|
148
|
+
value = case filter
|
149
|
+
when Symbol
|
150
|
+
@parent.public_send filter, value
|
151
|
+
when Proc
|
152
|
+
if filter.arity == 0
|
153
|
+
value
|
154
|
+
else
|
155
|
+
filter.call value
|
156
|
+
end
|
157
|
+
when Class, Object
|
158
|
+
unless filter.respond_to? 'filter'
|
159
|
+
value
|
160
|
+
else
|
161
|
+
filter.filter value
|
162
|
+
end
|
163
|
+
else
|
164
|
+
value
|
165
|
+
end
|
166
|
+
end
|
167
|
+
value
|
168
|
+
end
|
169
|
+
end # => class Definition
|
170
|
+
|
171
|
+
end # => module Field
|
data/lib/flat/file.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'flat/errors'
|
2
|
+
require 'flat/file_data'
|
3
|
+
require 'flat/field'
|
4
|
+
require 'flat/layout'
|
5
|
+
require 'flat/record'
|
6
|
+
require 'flat/read_operations'
|
7
|
+
|
8
|
+
# = Flat::File
|
9
|
+
#
|
10
|
+
class Flat::File
|
11
|
+
include Errors
|
12
|
+
include FileData
|
13
|
+
include Layout
|
14
|
+
include Field
|
15
|
+
include Record
|
16
|
+
include ReadOperations
|
17
|
+
|
18
|
+
end # => class Flat::File
|
@@ -0,0 +1,123 @@
|
|
1
|
+
##
|
2
|
+
# = FileData
|
3
|
+
#
|
4
|
+
# Defines structures and accessors for the internal FileData required by Flat::File
|
5
|
+
# and its successful operations.
|
6
|
+
#
|
7
|
+
module FileData
|
8
|
+
##
|
9
|
+
# = Class Methods
|
10
|
+
#
|
11
|
+
# Defines behavior for subclasses of Flat::File regarding the management of
|
12
|
+
# its internal data structures.
|
13
|
+
#
|
14
|
+
module ClassMethods
|
15
|
+
|
16
|
+
##
|
17
|
+
# Container for various points of data as defined in the Flat::File subclass.
|
18
|
+
#
|
19
|
+
# Returns a +Hash+ with the following keys:
|
20
|
+
# * +:width+ - The overall width, or length, of a line in the flat file.
|
21
|
+
# * +:pack_format+ - A format +String+ for use by String#unpack.
|
22
|
+
# * +:fields+ - An +Array+ of Field::Definitions
|
23
|
+
# * +:layouts+ - An +Array+ of Layout::Definitions
|
24
|
+
#
|
25
|
+
def flat_file_data
|
26
|
+
@data ||= {
|
27
|
+
:width => 0,
|
28
|
+
:pack_format => '',
|
29
|
+
:fields => [],
|
30
|
+
:layouts => [],
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# Convenience method for accessing <tt>flat_file_data[:fields]</tt>
|
36
|
+
#
|
37
|
+
# Returns an +Array+ of Field::Definitions
|
38
|
+
#
|
39
|
+
def fields
|
40
|
+
flat_file_data[:fields]
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Convenience method for accessing <tt>flat_file_data[:width]</tt>
|
45
|
+
#
|
46
|
+
# Returns the overall length of a line to text in the flat file.
|
47
|
+
#
|
48
|
+
def width
|
49
|
+
flat_file_data[:width]
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Added setter to support +=, -= constructs; also allows direct
|
54
|
+
# assignment.
|
55
|
+
#
|
56
|
+
def width=(value) #:nodoc:
|
57
|
+
flat_file_data[:width] = value
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# Convenience method for accessing <tt>flat_file_data[:pack_format]</tt>
|
62
|
+
#
|
63
|
+
# Returns a +String+ sutiable for use with String#unpack
|
64
|
+
#
|
65
|
+
def pack_format
|
66
|
+
flat_file_data[:pack_format]
|
67
|
+
end
|
68
|
+
|
69
|
+
##
|
70
|
+
# Convenience method for accessing <tt>flat_file_data[:layouts]</tt>
|
71
|
+
#
|
72
|
+
# Returns an +Array+ of Layout::Definitions
|
73
|
+
#
|
74
|
+
def layouts
|
75
|
+
flat_file_data[:layout]
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# Added for test purposes, primarily. DESTRUCTIVE!
|
80
|
+
#
|
81
|
+
def reset_file_data #:nodoc:
|
82
|
+
@data = nil
|
83
|
+
end
|
84
|
+
|
85
|
+
end # => module ClassMethods
|
86
|
+
|
87
|
+
##
|
88
|
+
# = Instance Methods
|
89
|
+
#
|
90
|
+
# Defines behavior for instances of subclasses of Flat::File regarding the
|
91
|
+
# accessing of its internal data structures.
|
92
|
+
#
|
93
|
+
module InstanceMethods
|
94
|
+
|
95
|
+
##
|
96
|
+
# Returns the +width+ of this Flat::File subclass as defined in its class
|
97
|
+
#
|
98
|
+
def width
|
99
|
+
self.class.width
|
100
|
+
end
|
101
|
+
|
102
|
+
##
|
103
|
+
# Returns the +pack_format+ of this Flat::File subclass as defined in its class
|
104
|
+
#
|
105
|
+
def pack_format
|
106
|
+
self.class.pack_format
|
107
|
+
end
|
108
|
+
|
109
|
+
##
|
110
|
+
# Returns the +fields+ of this Flat::File subclass as defined in its class
|
111
|
+
#
|
112
|
+
def fields
|
113
|
+
self.class.fields
|
114
|
+
end
|
115
|
+
|
116
|
+
end # => module InstanceMethods
|
117
|
+
|
118
|
+
def self.included receiver #:nodoc:
|
119
|
+
receiver.extend ClassMethods
|
120
|
+
receiver.send :include, InstanceMethods
|
121
|
+
end
|
122
|
+
|
123
|
+
end # => module FileData
|
data/lib/flat/layout.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# = Layout
|
2
|
+
# *EXPERIMENTAL*
|
3
|
+
#
|
4
|
+
# If a flat file contains several different record structures, defining
|
5
|
+
# more than one Layout::Definition allows Flat::File to easily process
|
6
|
+
# the file.
|
7
|
+
#
|
8
|
+
# *EXPERIMENTAL*
|
9
|
+
#
|
10
|
+
module Layout
|
11
|
+
module ClassMethods #:nodoc:
|
12
|
+
end # => module ClassMethods
|
13
|
+
|
14
|
+
module InstanceMethods #:nodoc:
|
15
|
+
end # => module InstanceMethods
|
16
|
+
|
17
|
+
def self.included receiver #:nodoc:
|
18
|
+
receiver.extend ClassMethods
|
19
|
+
receiver.send :include, InstanceMethods
|
20
|
+
end
|
21
|
+
|
22
|
+
# = Definition
|
23
|
+
# Add the ability to have multiple layouts per flat flat.
|
24
|
+
#
|
25
|
+
# EXPERIMENTAL
|
26
|
+
#
|
27
|
+
class Definition #:nodoc:
|
28
|
+
end # => class Definition
|
29
|
+
|
30
|
+
end # => module Layout
|
@@ -0,0 +1,50 @@
|
|
1
|
+
##
|
2
|
+
# = ReadOperations
|
3
|
+
#
|
4
|
+
# Defines functionality required for the successful reading, parsing and
|
5
|
+
# interpreting of a line of text contained in a flat file.
|
6
|
+
#
|
7
|
+
module ReadOperations
|
8
|
+
module ClassMethods #:nodoc:
|
9
|
+
end # => module ClassMethods
|
10
|
+
|
11
|
+
##
|
12
|
+
# = Instance Methods
|
13
|
+
#
|
14
|
+
# Defines behavior for instances of a subclass of Flat::File regarding the
|
15
|
+
# reading and parsing of the file contents, line by line.
|
16
|
+
#
|
17
|
+
module InstanceMethods
|
18
|
+
|
19
|
+
# Iterate through each record (each line of the data file). The passed
|
20
|
+
# block is passed a new Record representing the line.
|
21
|
+
#
|
22
|
+
# s = SomeFile.new
|
23
|
+
# s.each_record(open('/path/to/file')) do |r|
|
24
|
+
# puts r.first_name
|
25
|
+
# end
|
26
|
+
#--
|
27
|
+
# NOTE: Expects an open valid IO handle; opening and closing is out of scope
|
28
|
+
#++
|
29
|
+
#
|
30
|
+
def each_record io, &block
|
31
|
+
io.each_line do |line|
|
32
|
+
line.chop!
|
33
|
+
next if line.length.zero?
|
34
|
+
|
35
|
+
unless (self.width - line.length).zero?
|
36
|
+
raise Errors::RecordLengthError, "length is #{line.length} but should be #{self.width}"
|
37
|
+
end
|
38
|
+
|
39
|
+
yield create_record(line, io.lineno), line
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end # => module InstanceMethods
|
44
|
+
|
45
|
+
def self.included receiver #:nodoc:
|
46
|
+
receiver.extend ClassMethods
|
47
|
+
receiver.send :include, InstanceMethods
|
48
|
+
end
|
49
|
+
|
50
|
+
end # => module ReadOperations
|