ach_builder 0.2.1 → 0.2.2

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.
@@ -45,8 +45,11 @@ module ACH
45
45
 
46
46
  has_many :batches, :proc_defaults => lambda{ {:batch_number => batches.length + 1} }
47
47
 
48
- # Opens a +filename+ and passes it's handler to the ACH::Reader object, which uses it as
49
- # enum to scan for ACH contents line by line.
48
+ # Open a +filename+ and pass its handler to the ACH::Reader object,
49
+ # which uses it as an enum to scan for ACH contents line by line.
50
+ #
51
+ # @param [String] filename
52
+ # @return [ACH::File]
50
53
  def self.read(filename)
51
54
  ::File.open(filename) do |fh|
52
55
  Reader.new(fh).to_ach
@@ -2,50 +2,70 @@ module ACH
2
2
  # This module hosts all the methods required for building string representation of an ACH file,
3
3
  # and writing it to an actual file in the filesystem. Included by the ACH::File.
4
4
  module File::Builder
5
- # Returns amount of +batches+ in file
5
+ # Return amount of +batches+ in file.
6
+ #
7
+ # @return [Fixnum]
6
8
  def batch_count
7
9
  batches.length
8
10
  end
9
11
 
10
- # Returns amount of blocks, used in count. This amount is based on <tt>blocking factor</tt>,
12
+ # Return amount of blocks, used in count. This amount is based on <tt>blocking factor</tt>,
11
13
  # which is usually equals to 10, and on overall amount of records in a file. Return value
12
14
  # represents the least amount of blocks taken by records in file.
15
+ #
16
+ # @return [Fixnum]
13
17
  def block_count
14
18
  (record_count.to_f / Constants::BLOCKING_FACTOR).ceil
15
19
  end
16
20
 
17
- # Returns total amount of +entry+ and +addenda+ records of all batches within file.
21
+ # Return total amount of +entry+ and +addenda+ records of all batches within file.
22
+ #
23
+ # @return [Fixnum]
18
24
  def file_entry_addenda_count
19
25
  batches.map{ |batch| batch.entry_addenda_count }.inject(&:+) || 0
20
26
  end
21
27
 
22
- # Returns sum of +entry_hash+ values of all batches within self
28
+ # Return sum of +entry_hash+ values of all batches within self.
29
+ #
30
+ # @return [Fixnum]
23
31
  def entry_hash
24
32
  batch_sum_of(:entry_hash)
25
33
  end
26
34
 
27
- # Returns sum of +total_debit_amount+ values of all batches within self
35
+ # Return sum of +total_debit_amount+ values of all batches within +self+.
36
+ #
37
+ # @return [Fixnum]
28
38
  def total_debit_amount
29
39
  batch_sum_of(:total_debit_amount)
30
40
  end
31
41
 
32
- # Returns sum of +total_credit_amount+ values of all batches within self
42
+ # Return sum of +total_credit_amount+ values of all batches within +self+.
43
+ #
44
+ # @return [Fixnum]
33
45
  def total_credit_amount
34
46
  batch_sum_of(:total_credit_amount)
35
47
  end
36
48
 
37
- # Returns complete string representation of a ACH file by converting each interval record
38
- # to a string and joining the result by <tt>Constants::ROWS_DELIMITER</tt>
49
+ # Return a complete string representation of an ACH file by converting each
50
+ # interval record to a string and joining the result by
51
+ # +ACH::Constants::ROWS_DELIMITER+.
52
+ #
53
+ # @return [String]
39
54
  def to_s!
40
55
  to_ach.map(&:to_s!).join(Constants::ROWS_DELIMITER)
41
56
  end
42
57
 
43
- # Returns total amount of records hosted by a file.
58
+ # Return total amount of records hosted by a file.
59
+ #
60
+ # @return [Fixnum]
44
61
  def record_count
45
62
  2 + batch_count * 2 + file_entry_addenda_count
46
63
  end
47
64
 
48
- # Writes string representation of self to passed +filename+
65
+ # Write string representation of self to passed +filename+.
66
+ #
67
+ # @param [String] filename
68
+ # @return [::File]
49
69
  def write(filename)
50
70
  return false unless valid?
51
71
  ::File.open(filename, 'w') do |fh|
@@ -53,29 +73,38 @@ module ACH
53
73
  end
54
74
  end
55
75
 
56
- # Helper method for calculating different properties of batches within file
76
+ # Helper method for calculating different properties of batches within file.
77
+ #
78
+ # @param [String] meth
79
+ # @return [Fixnum]
57
80
  def batch_sum_of(meth)
58
81
  batches.map(&meth).compact.inject(&:+)
59
82
  end
60
83
  private :batch_sum_of
61
84
 
62
- # Returns well-fetched array of all ACH records in the file, appending proper
85
+ # Return well-fetched array of all ACH records in the file, appending proper
63
86
  # amount, based on number of blocks, of tail records to it.
87
+ #
88
+ # @return [Array<ACH::Record::Base>]
64
89
  def to_ach
65
90
  head = [ header ]
66
91
  head.unshift(transmission_header) if have_transmission_header?
67
92
  head + batches.map(&:to_ach).flatten + [control] + tail
68
93
  end
69
94
 
70
- # Returns array of ACH::Record::Tail records, based on +tails_count+
95
+ # Return array of ACH::Record::Tail records, based on +tails_count+.
96
+ #
97
+ # @return [Array<ACH::Record::Tail>]
71
98
  def tail
72
- [ Record::Tail.new ] * tails_count
99
+ [Record::Tail.new] * tails_count
73
100
  end
74
101
 
75
- # Returns amount of ACH::Record::Tail records, required to append to
102
+ # Return amount of ACH::Record::Tail records, required to append to
76
103
  # string representation of a file to match proper amount of blocks.
104
+ #
105
+ # @return [Fixnum]
77
106
  def tails_count
78
107
  block_count * Constants::BLOCKING_FACTOR - record_count
79
108
  end
80
109
  end
81
- end
110
+ end
@@ -7,10 +7,16 @@ module ACH
7
7
  class File::Reader
8
8
  include Constants
9
9
 
10
+ # Initialize reader.
11
+ #
12
+ # @param [#each] enum
10
13
  def initialize(enum)
11
14
  @enum = enum
12
15
  end
13
16
 
17
+ # Build a {ACH::File} object using data obtained from +@enum+ source.
18
+ #
19
+ # @return [ACH::File]
14
20
  def to_ach
15
21
  header_line, batch_lines, control_line = ach_data
16
22
 
@@ -39,6 +45,9 @@ module ACH
39
45
  end
40
46
  end
41
47
 
48
+ # Process the source and return header batch and control records.
49
+ #
50
+ # @return [Array<ACH::Record::Base, Array>]
42
51
  def ach_data
43
52
  process! unless processed?
44
53
 
@@ -46,6 +55,10 @@ module ACH
46
55
  end
47
56
  private :ach_data
48
57
 
58
+ # Process each line by iterating over strings in +@enum+ source one by one and
59
+ # generating ACH information corresponding to record line.
60
+ #
61
+ # @return [true]
49
62
  def process!
50
63
  each_line do |record_type, line|
51
64
  case record_type
@@ -68,11 +81,16 @@ module ACH
68
81
  end
69
82
  private :process!
70
83
 
84
+ # Return +true+ if +@enum+ has been processed.
85
+ #
86
+ # @return [Boolean]
71
87
  def processed?
72
88
  !!@processed
73
89
  end
74
90
  private :processed?
75
91
 
92
+ # Iterate over +enum+ and yield first symbol of the string as
93
+ # record type and string itself.
76
94
  def each_line
77
95
  @enum.each do |line|
78
96
  yield line[0..0].to_i, line.chomp
@@ -80,21 +98,34 @@ module ACH
80
98
  end
81
99
  private :each_line
82
100
 
101
+ # Return array of batches in hash representation.
102
+ #
103
+ # @return [Array<Hash>]
83
104
  def batches
84
105
  @batches ||= []
85
106
  end
86
107
  private :batches
87
108
 
109
+ # Add a new hash representation of a batch to the batch list
110
+ # to be filled out during processing.
111
+ #
112
+ # @return [Array<Hash>]
88
113
  def initialize_batch!
89
114
  batches << {:entries => [], :addendas => {}}
90
115
  end
91
116
  private :initialize_batch!
92
117
 
118
+ # Current (the last one) batch to fill.
119
+ #
120
+ # @return [Hash]
93
121
  def current_batch
94
122
  batches.last
95
123
  end
96
124
  private :current_batch
97
125
 
126
+ # Current (the last one) entry string of the last batch that was processed.
127
+ #
128
+ # @return [String]
98
129
  def current_entry
99
130
  current_batch[:entries].last
100
131
  end
@@ -22,8 +22,9 @@ module ACH
22
22
  module File::TransmissionHeader
23
23
  extend ActiveSupport::Concern
24
24
 
25
- # Raised when (descendant of) ACH File tries to redeclare it's +TransmissionHeader+
25
+ # Raised when (descendant of) ACH File tries to redeclare it's +TransmissionHeader+.
26
26
  class RedefinedTransmissionHeaderError < RuntimeError
27
+ # Initialize error with descriptive message.
27
28
  def initialize
28
29
  super "TransmissionHeader record may be defined only once"
29
30
  end
@@ -31,13 +32,19 @@ module ACH
31
32
 
32
33
  # Raised when +TransmissionHeader+ is declared with no fields in it
33
34
  class EmptyTransmissionHeaderError < RuntimeError
35
+ # Initialize error with descriptive message.
34
36
  def initialize
35
37
  super "Transmission_header should declare it's fields"
36
38
  end
37
39
  end
38
40
 
41
+ # Class macros.
39
42
  module ClassMethods
40
- # Defines and declares +TransmissionHeader+ class within scope of +self+
43
+ # Defines and declares +TransmissionHeader+ class within scope of +self+.
44
+ #
45
+ # @return [Boolean]
46
+ # @raise [RedefinedTransmissionHeaderError]
47
+ # @raise [EmptyTransmissionHeaderError]
41
48
  def transmission_header(&block)
42
49
  raise RedefinedTransmissionHeaderError if have_transmission_header?
43
50
 
@@ -50,27 +57,34 @@ module ACH
50
57
  end
51
58
 
52
59
  # Returns +true+ if +TransmissionHeader+ is defined within scope of the class.
60
+ #
61
+ # @return [Boolean]
53
62
  def have_transmission_header?
54
63
  @have_transmission_header
55
64
  end
56
65
  end
57
66
 
58
67
  # Helper instance method. Returns +true+ if +TransmissionHeader+ is defined within
59
- # scope of it's class
68
+ # scope of it's class.
69
+ #
70
+ # @return [Boolean]
60
71
  def have_transmission_header?
61
72
  self.class.have_transmission_header?
62
73
  end
63
74
 
64
75
  # Builds +TransmissionHeader+ record for self. Yields it to +block+, if passed.
65
76
  # Returns nil if no +TransmissionHeader+ is defined within scope of class.
66
- def transmission_header(fields = {}, &block)
77
+ #
78
+ # @param [Hash] fields
79
+ # @return [ACH::File::TransmissionHeader]
80
+ def transmission_header(fields = {})
67
81
  return nil unless have_transmission_header?
68
82
 
69
83
  merged_fields = fields_for(self.class::TransmissionHeader).merge(fields)
70
84
 
71
85
  @transmission_header ||= self.class::TransmissionHeader.new(merged_fields)
72
86
  @transmission_header.tap do |head|
73
- head.instance_eval(&block) if block
87
+ head.instance_eval(&Proc.new) if block_given?
74
88
  end
75
89
  end
76
90
  end
@@ -1,5 +1,5 @@
1
1
  module ACH
2
- # Every field should be formatted with its own rule so Formatter take care about it.
2
+ # Ensures that every field is formatted with its own rule.
3
3
  # Rules are defined in ACH::RULES constant.
4
4
  #
5
5
  # == Rule Format
@@ -80,40 +80,62 @@ module ACH
80
80
  :entry_details_sequence_num => '->7'
81
81
  }
82
82
 
83
- # Returns +true+ if +field_name+ is one of the keys of +RULES+
83
+ # Return +true+ if +field_name+ is one of the keys of +RULES+.
84
+ #
85
+ # @param [Symbol] field_name
86
+ # @return [Boolean]
84
87
  def self.defined?(field_name)
85
88
  RULES.key?(field_name)
86
89
  end
87
90
 
88
- # Adds +field+ with corresponding +format+ to +RULES+
91
+ # Add a +field+ with corresponding +format+ to +RULES+.
92
+ #
93
+ # @param [Symbol] field
94
+ # @param [String] format
95
+ # @return [Hash]
89
96
  def self.define(field, format)
90
97
  RULES[field] = format
91
98
  end
92
99
 
93
- # If missing method name is one of the defined rules, passes its name
94
- # and the rest of arguments to the +format+ method
100
+ # If missing method name is one of the defined rules, pass its name
101
+ # and the rest of arguments to the +format+ method.
102
+ #
103
+ # @param [Symbol] meth
104
+ # @param [*Object] args
95
105
  def self.method_missing(meth, *args)
96
106
  self.defined?(meth) ? format(meth, *args) : super
97
107
  end
98
108
 
99
- # Formats +value+ using the rule defined by +field_name+ format
109
+ # Format the +value+ using the rule defined by +field_name+ format.
110
+ #
111
+ # @param [Symbol] field_name
112
+ # @param [String] value
113
+ # @return [String]
100
114
  def self.format(field_name, value)
101
115
  rule_for_field(field_name).call(value)
102
116
  end
103
117
 
104
- # Returns ACH::Formatter::Rule rule, built from the corresponding format
105
- # definition of a +field+
118
+ # Return ACH::Formatter::Rule rule, built from the corresponding format
119
+ # definition of a +field+.
120
+ #
121
+ # @param [Symbol] field
122
+ # @return [ACH::Formatter::Rule]
106
123
  def self.rule_for_field(field)
107
124
  compiled_rules[field] ||= Rule.new(RULES[field])
108
125
  end
109
126
 
110
- # Returns a hash of all rules that have been built at the moment of method call
127
+ # Return a hash of all rules that have been built at the moment of method call.
128
+ #
129
+ # @return [Hash]
111
130
  def self.compiled_rules
112
131
  @compiled_rules ||= {}
113
132
  end
114
133
 
115
- # Returns a regular expression that can be used to split string into matched parts,
116
- # that will correspond to passed +fields+ parameter. Used for ACH reading purposes
134
+ # Return a regular expression that can be used to split string into matched parts,
135
+ # that will correspond to passed +fields+ parameter. Used for ACH reading purposes.
136
+ #
137
+ # @param [Array<Symbol>] fields
138
+ # @return [Regexp]
117
139
  def self.matcher_for(fields)
118
140
  /^#{fields.map{ |f| "(.{#{rule_for_field(f).length}})" }.join}$/
119
141
  end
@@ -8,9 +8,12 @@ module ACH
8
8
 
9
9
  attr_reader :length
10
10
 
11
- # Initializes instance with formatting data. Parses passed string for formatting
12
- # values, such as width, justification, etc. As the result, builds a Proc object
13
- # that will be used to format passed string according to formatting rule.
11
+ # Initialize the instance with the formatting data. Parses the given string
12
+ # for formatting values, such as width, justification, etc. With the result,
13
+ # it builds a Proc object to be used to format the given string according
14
+ # to the formatting rule.
15
+ #
16
+ # @param [ACH::Formatter::Rule] rule
14
17
  def initialize(rule)
15
18
  just, width, pad, transf = rule.match(RULE_PARSER_REGEX)[1..-1]
16
19
  @length = width.to_i
@@ -27,37 +27,56 @@ module ACH
27
27
  class Base
28
28
  include Validations
29
29
  include Constants
30
-
30
+
31
31
  # Raises when unknown field passed to ACH::Record::Base.fields method.
32
32
  class UnknownFieldError < ArgumentError
33
+ # Initialize error with descriptive message.
34
+ #
35
+ # @param [Symbol] field
36
+ # @param [String] class_name
33
37
  def initialize(field, class_name)
34
38
  super "Unrecognized field '#{field}' in class #{class_name}"
35
39
  end
36
40
  end
37
-
41
+
38
42
  # Raises when value of record's field is not specified and there is no
39
43
  # default value.
40
44
  class EmptyFieldError < ArgumentError
45
+ # Initialize error with descriptive message.
46
+ #
47
+ # @param [Symbol] field
48
+ # @param [ACH::Record::Base] record
41
49
  def initialize(field, record)
42
50
  super "Empty field '#{field}' for #{record}"
43
51
  end
44
52
  end
45
-
46
- # Specifies fields of the record. Order is important. All fields
53
+
54
+ # Specify the fields of the record. Order is important. All fields
47
55
  # must be declared in ACH::Formatter +RULES+. See class description
48
- # for example
56
+ # for example.
57
+ #
58
+ # @param [*Symbol] field_names
59
+ # @return [Array<Symbol>]
49
60
  def self.fields(*field_names)
50
61
  return @fields if field_names.empty?
51
62
  @fields = field_names
52
63
  @fields.each{ |field| define_field_methods(field) }
53
64
  end
54
-
55
- # Sets default values for fields. See class description for example
65
+
66
+ # Set default values for fields. See class description for example.
67
+ #
68
+ # @param [Hash, nil] default_values
69
+ # @return [Hash]
56
70
  def self.defaults(default_values = nil)
57
71
  return @defaults if default_values.nil?
58
72
  @defaults = default_values.freeze
59
73
  end
60
74
 
75
+ # Define accessor methods for a given field name if it can be found
76
+ # in the keys of {ACH::Formatter::RULES}.
77
+ #
78
+ # @param [Symbol] field
79
+ # @raise [UnknownFieldError]
61
80
  def self.define_field_methods(field)
62
81
  raise UnknownFieldError.new(field, name) unless Formatter::RULES.key?(field)
63
82
  define_method(field) do |*args|
@@ -69,20 +88,31 @@ module ACH
69
88
  end
70
89
  private_class_method :define_field_methods
71
90
 
91
+ # Build a new instance of a record from its string representation.
92
+ #
93
+ # @param [String] string
94
+ # @return [ACH::Record::Base]
72
95
  def self.from_s(string)
73
96
  field_matcher_regexp = Formatter.matcher_for(fields)
74
97
  new Hash[*fields.zip(string.match(field_matcher_regexp)[1..-1]).flatten]
75
98
  end
76
-
77
- def initialize(fields = {}, &block)
99
+
100
+ # Initialize object with field values. If block is given, it will be
101
+ # evaluated in context of isntance.
102
+ #
103
+ # @param [Hash] fields
104
+ def initialize(fields = {})
78
105
  defaults.each do |key, value|
79
106
  self.fields[key] = Proc === value ? value.call : value
80
107
  end
81
108
  self.fields.merge!(fields)
82
- instance_eval(&block) if block
109
+ instance_eval(&Proc.new) if block_given?
83
110
  end
84
-
85
- # Builds a string from record object.
111
+
112
+ # Build a string from record object.
113
+ #
114
+ # @return [Stirng]
115
+ # @raise [EmptyFieldError]
86
116
  def to_s!
87
117
  self.class.fields.map do |name|
88
118
  raise EmptyFieldError.new(name, self) if @fields[name].nil?
@@ -90,16 +120,26 @@ module ACH
90
120
  end.join
91
121
  end
92
122
 
93
- # Returns a hash where key is field's name and value is field's value.
123
+ # Return a hash where key is the field's name and value is the field's value.
124
+ #
125
+ # @return [Hash]
94
126
  def fields
95
127
  @fields ||= {}
96
128
  end
97
129
 
130
+ # Return field default values defined in class.
131
+ #
132
+ # @return [Hash]
98
133
  def defaults
99
134
  self.class.defaults
100
135
  end
101
136
  private :defaults
102
-
137
+
138
+ # Delegate bracket-assignment to +fields+.
139
+ #
140
+ # @param [Symbol] name
141
+ # @param [String] val
142
+ # @return [String]
103
143
  def []=(name, val)
104
144
  fields[name] = val
105
145
  end