FixedWidthFields 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+