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.
@@ -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
@@ -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
+