FixedWidthFields 0.1
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.
- data/lib/fixedWidth.rb +13 -0
- data/lib/fixedWidth/base.rb +148 -0
- data/lib/fixedWidth/helpers.rb +11 -0
- data/test/testFixed.rb +99 -0
- metadata +48 -0
data/lib/fixedWidth.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#--
|
4
|
+
# Copyright 2006 by Brett Norris (norri_b@hotmail.com).
|
5
|
+
# All rights reserved.
|
6
|
+
|
7
|
+
# Permission is granted for use, copying, modification, distribution,
|
8
|
+
# and distribution of modified versions of this work as long as the
|
9
|
+
# above copyright notice is included.
|
10
|
+
#++
|
11
|
+
|
12
|
+
require 'fixedWidth/base'
|
13
|
+
require 'fixedWidth/helpers'
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'fixedWidth/helpers'
|
3
|
+
|
4
|
+
# The FixedWidthFields library is designed to allow
|
5
|
+
# files containing fixed-width fields to be created
|
6
|
+
# easily.
|
7
|
+
#
|
8
|
+
# Fixed-width fields are fields that are guaranteed to
|
9
|
+
# take up the specified number of characters when
|
10
|
+
# converted to a string.
|
11
|
+
#
|
12
|
+
# == Example
|
13
|
+
# Say that we want to create a class representing a
|
14
|
+
# Person and convert this to a fixed-width string
|
15
|
+
# easily.
|
16
|
+
#
|
17
|
+
# Create the class as follows:
|
18
|
+
# class Person < FixedWidthFields
|
19
|
+
# field :name, :width => 5
|
20
|
+
# field :age, :width => 3, :pad_with => '0'
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# Use it as follows:
|
24
|
+
# james = Person.new
|
25
|
+
# james.name = "JamesBond"
|
26
|
+
# james.age = 7
|
27
|
+
#
|
28
|
+
# james.to_s # => "James007"
|
29
|
+
#
|
30
|
+
# == Defining fixed width fields
|
31
|
+
#
|
32
|
+
# Parameters that must be used when defining fields are:
|
33
|
+
# * <tt>:width</tt> - the required width of the field
|
34
|
+
#
|
35
|
+
# Parameters that can be used when defining fields are:
|
36
|
+
# * <tt>:default</tt> - the default value that this field should take if it is not explicitly set
|
37
|
+
# * <tt>:pad_with</tt> - the character that should be used for padding the field if it is less than the required width (defaults to the space character)
|
38
|
+
# * <tt>:formatter</tt> - a <tt>Proc</tt> instance that can be used for formatting the field. This proc should expect one parameter (which will be set to the value of the field) and should return a string. If the string returned is greater than the specified width of the field, the field will be truncated.
|
39
|
+
|
40
|
+
class FixedWidthFields
|
41
|
+
# This class is used by the <tt>FixedWidthFields</tt> class to
|
42
|
+
# store the metadata associated with each fixed-width field. It is
|
43
|
+
# not intended for this class to be used seperately from the
|
44
|
+
# <tt>FixedWidthFields</tt> class.
|
45
|
+
class Field
|
46
|
+
# Contains the name of this fixed-width field (i.e. the
|
47
|
+
# name of the instance variable through which it is
|
48
|
+
# accessed)
|
49
|
+
attr_reader :name
|
50
|
+
|
51
|
+
# Create a new instance of a fixed-width field, accessed through
|
52
|
+
# instance variable <tt>name</tt> with defining parameters
|
53
|
+
# specified in <tt>params</tt>.
|
54
|
+
# See <tt>FixedWidthFields</tt> for a list of the valid
|
55
|
+
# parameters
|
56
|
+
def initialize(name, params)
|
57
|
+
@name, @params = name,params
|
58
|
+
validate_params
|
59
|
+
end
|
60
|
+
|
61
|
+
# Return the default value for this field (i.e. the value it
|
62
|
+
# takes if it is not explicitly set to another value)
|
63
|
+
def default
|
64
|
+
@params[:default]
|
65
|
+
end
|
66
|
+
|
67
|
+
# Applies the formatting to this field and returns the
|
68
|
+
# formatted field
|
69
|
+
def format_field(instance)
|
70
|
+
value = instance.send(@name) || @params[:default]
|
71
|
+
value = @params[:formatter].call(value) unless @params[:formatter].nil?
|
72
|
+
|
73
|
+
return justify_field(value)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Ensure that the parameters given when creating this field
|
77
|
+
# are valid
|
78
|
+
def validate_params
|
79
|
+
raise "field '#{name}' has no width specified" if @params[:width].nil?
|
80
|
+
end
|
81
|
+
|
82
|
+
# Ensure that the field is exactly the specified width
|
83
|
+
def justify_field(contents)
|
84
|
+
justify_char = @params[:pad_with] || ' '
|
85
|
+
contents.to_s.rjust(@params[:width], justify_char)[0,@params[:width]]
|
86
|
+
end
|
87
|
+
|
88
|
+
private :justify_field, :validate_params
|
89
|
+
end
|
90
|
+
|
91
|
+
# Define getter for class instance variable 'fields'
|
92
|
+
class << self
|
93
|
+
class_eval {
|
94
|
+
# An attribute stored in the metaclass. This is an array
|
95
|
+
# containing all of the fixed-width fields defined in
|
96
|
+
# this class.
|
97
|
+
attr_reader :fields
|
98
|
+
}
|
99
|
+
end
|
100
|
+
|
101
|
+
# Ensure that class instance variable 'fields' defaults to []
|
102
|
+
class_eval {
|
103
|
+
instance_variable_set("@fields", [])
|
104
|
+
}
|
105
|
+
|
106
|
+
# Convert all of the fields in the class into string form. Each field
|
107
|
+
# will be present in the order it was defined in the class and the
|
108
|
+
# width of each field will be exactly equal to the <tt>:width</tt>
|
109
|
+
# parameter supplied
|
110
|
+
def to_s
|
111
|
+
self.class.fields.inject("") {|result,field|
|
112
|
+
result += field.format_field(self)
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
# Defines an accessor for <tt>field</tt>.
|
117
|
+
# This will work in the expected way but will also ensure
|
118
|
+
# that the field can be converted to a fixed-width string
|
119
|
+
# when <tt>to_s</tt> is called on the defining class
|
120
|
+
# The <tt>formatting_params</tt> hash defines the formatting
|
121
|
+
# applied to this field when it is converted to a string.
|
122
|
+
# Valid values of <tt>formatting_params</tt> are as follows:
|
123
|
+
# * <tt>:width</tt> - the required width of the field
|
124
|
+
# * <tt>:default</tt> - the default value that this field should take if it is not explicitly set
|
125
|
+
# * <tt>:pad_with</tt> - the character that should be used for padding the field if it is less than the required width (defaults to the space character)
|
126
|
+
# * <tt>:formatter</tt> - a <tt>Proc</tt> instance that can be used for formatting the field. This proc should expect one parameter (which will be set to the value of the field) and should return a string. If the string returned is greater than the specified width of the field, the field will be truncated.
|
127
|
+
|
128
|
+
def self.field(field, formatting_params={})
|
129
|
+
attr_accessor(field.to_sym)
|
130
|
+
|
131
|
+
ensure_superclass_fields_present
|
132
|
+
@fields << Field.new(field.to_sym, formatting_params)
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
# This method does not need to be used directly
|
137
|
+
def initialize
|
138
|
+
self.class.ensure_superclass_fields_present if self.class.fields.nil?
|
139
|
+
self.class.fields.each {|field|
|
140
|
+
instance_variable_set("@#{field.name}", field.default)
|
141
|
+
}
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.ensure_superclass_fields_present
|
145
|
+
@fields ||= superclass.fields.dup
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class FixedWidthFields
|
2
|
+
# A helper method to convert a Time value into the format
|
3
|
+
# 'YYYYmmddHHMMSS'. It can be used in a FixedWidthField class
|
4
|
+
# by using :formatter => DateTimeFormatter
|
5
|
+
DateTimeFormatter = lambda {|t| t.strftime("%Y%m%d%H%M%S") }
|
6
|
+
|
7
|
+
# A helper method to convert a Time value into the format
|
8
|
+
# 'YYYYmmdd'. It can be used in a FixedWidthField class by
|
9
|
+
# using :formatter => DateFormatter
|
10
|
+
DateFormatter = lambda {|t| t.strftime("%Y%m%d") }
|
11
|
+
end
|
data/test/testFixed.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'test/unit'
|
3
|
+
require 'fixedWidth/base'
|
4
|
+
|
5
|
+
class TestFixed < Test::Unit::TestCase
|
6
|
+
class Person < FixedWidthFields
|
7
|
+
field :name, :width => 4, :default => "Bob"
|
8
|
+
field :age, :width => 2, :pad_with => '0'
|
9
|
+
end
|
10
|
+
|
11
|
+
class NameTlaFile < Person
|
12
|
+
field :tla, :width => 3
|
13
|
+
end
|
14
|
+
|
15
|
+
def testBaseClass
|
16
|
+
a = FixedWidthFields.new
|
17
|
+
assert_equal("", a.to_s)
|
18
|
+
end
|
19
|
+
|
20
|
+
def testTruncatedField
|
21
|
+
self.class.class_eval "remove_const :Name if const_defined? :Name"
|
22
|
+
self.class.class_eval "class Name < FixedWidthFields
|
23
|
+
field :name, :width => 4
|
24
|
+
end"
|
25
|
+
|
26
|
+
brian = Name.new
|
27
|
+
brian.name = "Brian"
|
28
|
+
|
29
|
+
assert_equal("Brian", brian.name)
|
30
|
+
assert_equal("Bria", brian.to_s)
|
31
|
+
end
|
32
|
+
|
33
|
+
def testJustifiedWithSpace
|
34
|
+
self.class.class_eval "remove_const :Name if const_defined? :Name"
|
35
|
+
self.class.class_eval "class Name < FixedWidthFields
|
36
|
+
field :name, :width => 5
|
37
|
+
end"
|
38
|
+
|
39
|
+
bob = Name.new
|
40
|
+
bob.name = "Bob"
|
41
|
+
|
42
|
+
assert_equal("Bob", bob.name)
|
43
|
+
assert_equal(" Bob", bob.to_s)
|
44
|
+
end
|
45
|
+
|
46
|
+
def testLeftJustifiedWithChar
|
47
|
+
self.class.class_eval "remove_const :Age if const_defined? :Age"
|
48
|
+
self.class.class_eval "class Age < FixedWidthFields
|
49
|
+
field :age, :width => 3, :pad_with => '0'
|
50
|
+
end"
|
51
|
+
|
52
|
+
bond = Age.new
|
53
|
+
bond.age = 7
|
54
|
+
assert_equal(7, bond.age)
|
55
|
+
assert_equal("007", bond.to_s)
|
56
|
+
end
|
57
|
+
|
58
|
+
def testDerivedClass
|
59
|
+
self.class.class_eval "remove_const :Name if const_defined? :Name"
|
60
|
+
self.class.class_eval "remove_const :NameAndAge if const_defined? :NameAndAge"
|
61
|
+
self.class.class_eval "class Name < FixedWidthFields
|
62
|
+
field :name, :width => 4
|
63
|
+
end"
|
64
|
+
self.class.class_eval "class NameAndAge < Name
|
65
|
+
field :age, :width => 3
|
66
|
+
end"
|
67
|
+
|
68
|
+
johnny = NameAndAge.new
|
69
|
+
johnny.name = "Johnny"
|
70
|
+
johnny.age = 27
|
71
|
+
|
72
|
+
assert_equal("John 27", johnny.to_s)
|
73
|
+
end
|
74
|
+
|
75
|
+
def testDefaultField
|
76
|
+
self.class.class_eval "remove_const :Name if const_defined? :Name"
|
77
|
+
self.class.class_eval "class Name < FixedWidthFields
|
78
|
+
field :name, :width => 5, :default => \"Bob\"
|
79
|
+
end"
|
80
|
+
|
81
|
+
bob = Name.new
|
82
|
+
assert_equal(" Bob", bob.to_s)
|
83
|
+
end
|
84
|
+
|
85
|
+
def testFormatter
|
86
|
+
self.class.class_eval "remove_const :FixedDate if const_defined? :FixedDate"
|
87
|
+
self.class.class_eval "class FixedDate < FixedWidthFields
|
88
|
+
field :time, :width => 14, :default => Time.now,
|
89
|
+
:formatter => FixedWidthFields::DateTimeFormatter
|
90
|
+
end"
|
91
|
+
|
92
|
+
date = FixedDate.new
|
93
|
+
aTime = Time.utc(2000,"jan",1,20,15,01)
|
94
|
+
date.time = aTime
|
95
|
+
|
96
|
+
assert_equal(aTime, date.time)
|
97
|
+
assert_equal("20000101201501", date.to_s)
|
98
|
+
end
|
99
|
+
end
|
metadata
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11
|
3
|
+
specification_version: 1
|
4
|
+
name: FixedWidthFields
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: "0.1"
|
7
|
+
date: 2006-06-22 00:00:00 +01:00
|
8
|
+
summary: Easily create files with fixed-width fields
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: norri_b@hotmail.com
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description: The FixedWidthFields library is designed to allow files containing fixed-width fields to be created easily.
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
authors:
|
29
|
+
- Brett Norris
|
30
|
+
files:
|
31
|
+
- lib/fixedWidth.rb
|
32
|
+
- lib/fixedWidth/base.rb
|
33
|
+
- lib/fixedWidth/helpers.rb
|
34
|
+
- test/testFixed.rb
|
35
|
+
test_files: []
|
36
|
+
|
37
|
+
rdoc_options: []
|
38
|
+
|
39
|
+
extra_rdoc_files: []
|
40
|
+
|
41
|
+
executables: []
|
42
|
+
|
43
|
+
extensions: []
|
44
|
+
|
45
|
+
requirements: []
|
46
|
+
|
47
|
+
dependencies: []
|
48
|
+
|