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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a6370b31599af5467812e5b45be57e99c5e19a32
4
- data.tar.gz: 326db2ed6596c13a95ad0deeb8b5a9881270e857
3
+ metadata.gz: 13b50247a53e8f32fca29c49375e6d700bd039bf
4
+ data.tar.gz: 84d5a95e03d5f96f1a591c47d23e748cc613c1ca
5
5
  SHA512:
6
- metadata.gz: a039dc192619a516cdf9c09fdefe33dde1505655c6b67c9bdacfd7ab47301a5586b1d1b5cd01292ef244cbd1fece3aa81b7344a9c4168f40e0a68d6694ac31f5
7
- data.tar.gz: 5175200c43de130adb641b6d6c3d247b860b6e186cf2ff9ecc871dae6d95f0465f189a04f9d0e8f2430c811b77c74ad6272bbdea8b8109f6d667037aafce5fff
6
+ metadata.gz: 6442a48f3ac4122b01339c4f95d5b4306efe21437834633211ca5bb16495cb2e07a8a08e59f8a28406a898c80101fdd05e3c8269152bb8d679876dd79c6974b4
7
+ data.tar.gz: 65e1c78ea5211a84b37394cfa84c2ef296cc6248291139f26d7a72bebd1c152189d3a1bce1903c5f950869832b3785a01a1adc16050594c79d08dcbef8c4d62e
@@ -1 +1 @@
1
- 2.0.0-p247
1
+ 2.0.0
data/Gemfile CHANGED
@@ -4,10 +4,10 @@ source "https://rubygems.org"
4
4
  # Specify your gem's dependencies in ach_builder.gemspec
5
5
  gem 'i18n'
6
6
  gemspec
7
- gem 'rspec'
8
7
 
9
8
  group :development, :test do
10
9
  gem 'rspec'
10
+ gem 'yard'
11
11
 
12
12
  gem "simplecov" , :require => false
13
13
  gem 'simplecov-rcov-text', :require => false
@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
6
6
  s.name = "ach_builder"
7
7
  s.version = ACH::VERSION
8
8
  s.authors = ["TMX Credit", "Artem Kuzko", "Sergey Potapov"]
9
- s.email = ["rubygems@tmxcredit.com", "AKuzko@sphereconsultinginc.com", "SPotapov@sphereconsultinginc.com"]
9
+ s.email = ["rubygems@tmxcredit.com", "AKuzko@sphereconsultinginc.com", "blake131313@gmail.com"]
10
10
  s.homepage = "https://github.com/TMXCredit/ach_builder"
11
11
  s.summary = "Ruby tools for building ACH files"
12
12
  s.description = "Ruby tools for building ACH (Automated Clearing House) files"
@@ -2,49 +2,66 @@ module ACH
2
2
  # Supports building a string representation of a particular instance of an
3
3
  # ACH batch. Supports building ACH lines. Included by ACH::File.
4
4
  module Batch::Builder
5
- # Returns +true+ if any of internal ACH entries has 'credit' transaction code
5
+ # Returns +true+ if any of internal ACH entries has 'credit' transaction code.
6
+ #
7
+ # @return [Boolean]
6
8
  def has_credit?
7
9
  entries.any?(&:credit?)
8
10
  end
9
11
 
10
- # Returns +true+ if any internal ACH entry has 'debit' transaction code
12
+ # Returns +true+ if any internal ACH entry has 'debit' transaction code.
13
+ #
14
+ # @return [Boolean]
11
15
  def has_debit?
12
16
  entries.any?(&:debit?)
13
17
  end
14
18
 
15
- # Returns total amount of entry and addenda records within batch
19
+ # Returns total amount of entry and addenda records within batch.
20
+ #
21
+ # @return [Fixnum]
16
22
  def entry_addenda_count
17
23
  entries.size + addendas.values.flatten.size
18
24
  end
19
25
 
20
26
  # Returns 'hashed' representation of all entries within batch. See NACHA
21
- # documentation for more details on entry hash
27
+ # documentation for more details on entry hash.
28
+ #
29
+ # @return [Fixnum]
22
30
  def entry_hash
23
31
  entries.map{ |entry| entry.routing_number.to_i / 10 }.compact.inject(&:+)
24
32
  end
25
33
 
26
- # Returns total amount of all 'debit' entries within a batch
34
+ # Returns total amount of all 'debit' entries within a batch.
35
+ #
36
+ # @return [Fixnum]
27
37
  def total_debit_amount
28
38
  amount_sum_for(:debit?)
29
39
  end
30
40
 
31
- # Returns total amount of all 'credit' entries within a batch
41
+ # Returns total amount of all 'credit' entries within a batch.
42
+ #
43
+ # @return [Fixnum]
32
44
  def total_credit_amount
33
45
  amount_sum_for(:credit?)
34
46
  end
35
47
 
36
- # Returns ACH record objects that represent the batch
48
+ # Returns ACH record objects that represent the batch.
49
+ #
50
+ # @return [Array<ACH::Record::Base>]
37
51
  def to_ach
38
52
  [header] + fetch_entries + [control]
39
53
  end
40
54
 
41
- # Helper method executed just before building a header record for the batch
55
+ # Helper method executed just before building a header record for the batch.
42
56
  def before_header
43
57
  attributes[:service_class_code] ||= (has_debit? && has_credit? ? 200 : has_debit? ? 225 : 220)
44
58
  end
45
59
  private :before_header
46
60
 
47
61
  # Helper method, returns total amount of all entries within a batch, filtered by +meth+
62
+ #
63
+ # @param [Symbol] meth
64
+ # @return [Fixnum]
48
65
  def amount_sum_for(meth)
49
66
  entries.select(&meth).map{ |entry| entry.amount.to_i }.compact.inject(&:+) || 0
50
67
  end
@@ -52,6 +69,8 @@ module ACH
52
69
 
53
70
  # Fetches all internal records (entries and addendas) in right order, i.e. addenda records
54
71
  # should be positioned right after corresponding entry records.
72
+ #
73
+ # @return [Array<ACH::Record::Base>]
55
74
  def fetch_entries
56
75
  entries.inject([]){ |all, entry| all << entry << addendas[entry] }.flatten.compact
57
76
  end
@@ -19,7 +19,11 @@ module ACH
19
19
 
20
20
  # Exception raised on attempt to assign a value to nonexistent field.
21
21
  class UnknownAttributeError < ArgumentError
22
- def initialize field, obj
22
+ # Initialize error with field and component.
23
+ #
24
+ # @param [String] field
25
+ # @param [ACH::Component] obj
26
+ def initialize(field, obj)
23
27
  super "Unrecognized attribute '#{field}' for #{obj}"
24
28
  end
25
29
  end
@@ -31,6 +35,9 @@ module ACH
31
35
 
32
36
  attr_reader :attributes
33
37
 
38
+ # When inherited, clone class-related properties.
39
+ #
40
+ # @param [Class] klass
34
41
  def self.inherited(klass)
35
42
  klass.default_attributes = default_attributes.dup
36
43
  klass.after_initialize_hooks = after_initialize_hooks.dup
@@ -46,6 +53,9 @@ module ACH
46
53
  # header record.
47
54
  #
48
55
  # Note that default values may be overwritten when building records.
56
+ #
57
+ # @param [Symbol] meth
58
+ # @param [*Object] args
49
59
  def self.method_missing(meth, *args)
50
60
  if Formatter.defined?(meth)
51
61
  default_attributes[meth] = args.first
@@ -54,16 +64,28 @@ module ACH
54
64
  end
55
65
  end
56
66
 
57
- def initialize(fields = {}, &block)
58
- @attributes = {}.merge(self.class.default_attributes)
67
+ # Initialize component with field values. If block is given, it is evaluated in context
68
+ # of component, allowing setting fields via method calls and declarations of nested
69
+ # components.
70
+ #
71
+ # @param [Hash] fields
72
+ # @raise [UnknownAttributeError]
73
+ def initialize(fields = {})
74
+ @attributes = self.class.default_attributes.dup
59
75
  fields.each do |name, value|
60
76
  raise UnknownAttributeError.new(name, self) unless Formatter.defined?(name)
61
77
  @attributes[name] = value
62
78
  end
63
79
  after_initialize
64
- instance_eval(&block) if block
80
+ instance_eval(&Proc.new) if block_given?
65
81
  end
66
82
 
83
+ # Missing messages are treated as accessor methods for a component if their
84
+ # message name is defined by {ACH::Formatter}.
85
+ #
86
+ # @param [Symbol] meth
87
+ # @param [*Object] args
88
+ # @return [String]
67
89
  def method_missing(meth, *args)
68
90
  if Formatter.defined?(meth)
69
91
  args.empty? ? @attributes[meth] : (@attributes[meth] = args.first)
@@ -72,7 +94,9 @@ module ACH
72
94
  end
73
95
  end
74
96
 
75
- def before_header # :nodoc:
97
+ # Hook that is called whenever component header record is created. To be
98
+ # overridden in subclasses.
99
+ def before_header
76
100
  end
77
101
  private :before_header
78
102
 
@@ -92,19 +116,26 @@ module ACH
92
116
  # == Example 3
93
117
  #
94
118
  # header # => just returns a header object
95
- def header(fields = {}, &block)
119
+ def header(fields = {})
96
120
  before_header
97
121
  merged_fields = fields_for(self.class::Header).merge(fields)
98
122
  @header ||= self.class::Header.new(merged_fields)
99
123
  @header.tap do |head|
100
- head.instance_eval(&block) if block
124
+ head.instance_eval(&Proc.new) if block_given?
101
125
  end
102
126
  end
103
127
 
104
- def build_header(str) # :nodoc:
128
+ # Build a component (+File+ or +Batch+) related +Header+ record from a given string.
129
+ #
130
+ # @param [String] str
131
+ # @return [ACH::Record::Base]
132
+ def build_header(str)
105
133
  @header = self.class::Header.from_s(str)
106
134
  end
107
135
 
136
+ # Build a component-related +Control+ record.
137
+ #
138
+ # @return [ACH::Record::Base]
108
139
  def control
109
140
  @control ||= begin
110
141
  klass = self.class::Control
@@ -113,10 +144,19 @@ module ACH
113
144
  end
114
145
  end
115
146
 
116
- def build_control(str) # :nodoc:
147
+ # Build a component-related +Control+ record from a given string.
148
+ #
149
+ # @param [String] str
150
+ # @return [ACH::Record::Base]
151
+ def build_control(str)
117
152
  @control = self.class::Control.from_s(str)
118
153
  end
119
-
154
+
155
+ # Return a set of fields, that is a subset of +attributes+ that can be used to
156
+ # initialize an instance of a +klass+. +Component+ uses +attributes+ itself.
157
+ #
158
+ # @param [Class] klass
159
+ # @return [Hash]
120
160
  def fields_for(klass)
121
161
  if klass < Component
122
162
  attributes
@@ -126,11 +166,13 @@ module ACH
126
166
  end
127
167
  end
128
168
 
129
- def after_initialize # :nodoc:
169
+ # Execute all +Proc+ objects contained in the +after_initialize_hooks+
170
+ # array in the context of the object.
171
+ def after_initialize
130
172
  self.class.after_initialize_hooks.each{ |hook| instance_exec(&hook) }
131
173
  end
132
174
 
133
- # Creates has many association.
175
+ # Creates a has_many association.
134
176
  #
135
177
  # == Example
136
178
  #
@@ -147,6 +189,9 @@ module ACH
147
189
  # The example above extends File with #batches and #batch instance methods:
148
190
  # * #batch is used to add new instance of Batch.
149
191
  # * #batches is used to get an array of batches which belong to file.
192
+ #
193
+ # @param [Symbol] plural_name
194
+ # @param [Hash] options
150
195
  def self.has_many(plural_name, options = {})
151
196
  association = HasManyAssociation.new(plural_name, options)
152
197
 
@@ -25,6 +25,10 @@ module ACH
25
25
  # created after Entry records. Each new Addenda record will be attached
26
26
  # to the latest Entry record.
27
27
  class NoLinkError < ArgumentError
28
+ # Initialize the error with a descriptive message.
29
+ #
30
+ # @param [String] link
31
+ # @param [Class] klass
28
32
  def initialize(link, klass)
29
33
  super "No #{link} was found to attach a new #{klass}"
30
34
  end
@@ -33,6 +37,10 @@ module ACH
33
37
  # Exception thrown if an association object, assigned for particular
34
38
  # owner object, is used to assign to another owner object
35
39
  class DoubleAssignmentError < StandardError
40
+ # Initialize the error with a descriptive message.
41
+ #
42
+ # @param [String] name
43
+ # @param [ACH::Component] owner
36
44
  def initialize(name, owner)
37
45
  super "Association #{name} has alredy been assigned to #{owner}"
38
46
  end
@@ -41,14 +49,23 @@ module ACH
41
49
  attr_reader :name, :linked_to, :proc_defaults
42
50
  private :linked_to, :proc_defaults
43
51
 
52
+ # Initialize the association with a plural name and options.
53
+ #
54
+ # @param [String] plural_name
55
+ # @param [Hash] options
56
+ # @option options [Symbol] :linked_to plural name of records to link associated ones
57
+ # @option options [Proc] :proc_defaults
44
58
  def initialize(plural_name, options = {})
45
59
  @name = plural_name.to_s
46
60
  @linked_to, @proc_defaults = options.values_at(:linked_to, :proc_defaults)
47
61
  end
48
62
 
49
- # Clones +self+ and assigns +owner+ to clone. Also, for newly created
63
+ # Clone +self+ and assign +owner+ to clone. Also, for newly created
50
64
  # clone association that has owner, aliases main methods so that +owner+
51
65
  # may delegate to them.
66
+ #
67
+ # @param [ACH::Component] owner
68
+ # @raise [DoubleAssignmentError]
52
69
  def for(owner)
53
70
  raise DoubleAssignmentError.new(@name, @owner) if @owner
54
71
 
@@ -63,51 +80,63 @@ module ACH
63
80
  end
64
81
  end
65
82
 
66
- # Returns an array of methods to be delegated by +owner+ of the association.
83
+ # Return an array of methods to be delegated by +owner+ of the association.
67
84
  # For example, for association named :items, it will include:
68
85
  # * +build_item+ - for instantiating Item from the string (used by parsing functionality)
69
86
  # * +item+ - for instantiating Item during common ACH File creation
70
- # * +items+ - that returns set of Item objects
87
+ # * +items+ - that returns set of Item objects.
88
+ #
89
+ # @return [Array<String>]
71
90
  def delegation_methods
72
91
  ["build_#{singular_name}", singular_name, name]
73
92
  end
74
93
 
75
- # Uses <tt>klass#from_s</tt> to instantiate object from a string. Thus, +klass+ should be
94
+ # Use <tt>klass#from_s</tt> to instantiate object from a string. Thus, +klass+ should be
76
95
  # descendant of ACH::Record::Base. Then pushes object to appropriate container.
96
+ #
97
+ # @param [String] str
98
+ # @return [Array<ACH::Record::Base>]
77
99
  def build(str)
78
100
  obj = klass.from_s(str)
79
101
  container_for_associated << obj
80
102
  end
81
103
 
82
- # Creates associated object using common to ACH controls pattern, and pushes it to
83
- # appropriate container. For example, for :items association, this method is
104
+ # Create an associated object using common to ACH controls pattern, and push it to
105
+ # an appropriate container. For example, for :items association, this method is
84
106
  # aliased to +item+, so you will have:
107
+ #
85
108
  # item(:code => 'WEB') do
86
109
  # other_code 'BEW'
87
110
  # # ...
88
111
  # end
89
- def create(*args, &block)
112
+ #
113
+ # @param [*Object] args
114
+ # @return [Object] instance of a class under ACH namespace
115
+ def create(*args)
90
116
  fields = args.first || {}
91
117
 
92
118
  defaults = proc_defaults ? @owner.instance_exec(&proc_defaults) : {}
93
119
 
94
120
  klass.new(@owner.fields_for(klass).merge(defaults).merge(fields)).tap do |component|
95
- component.instance_eval(&block) if block
121
+ component.instance_eval(&Proc.new) if block_given?
96
122
  container_for_associated << component
97
123
  end
98
124
  end
99
125
 
100
- # Returns main container for association. For plain (without :linked_to option), it is
126
+ # Return the main container for association. For plain (without :linked_to option), it is
101
127
  # array. For linked associations, it is a hash, which keys are records from linking
102
- # associations, and values are arrays for association's objects
128
+ # associations, and values are arrays for association's objects.
129
+ #
130
+ # @return [Hash, Array]
103
131
  def container
104
132
  @container ||= linked? ? {} : []
105
133
  end
106
134
 
107
- # Returns array for associated object to be pushed in. For plain associations, it is
108
- # equivalent to +container+. For linked associations, uses +@owner+ and linking
109
- # association's name to get the latest record from linking associations. If it does
110
- # not exist, +NoLinkError+ will be raised.
135
+ # Return an array onto which the associated object may be be pushed. For
136
+ # plain associations, it is equivalent to +container+. For linked
137
+ # associations, uses +@owner+ and linking association's name to get the
138
+ # latest record from linking associations. If it does not exist,
139
+ # +NoLinkError+ will be raised.
111
140
  #
112
141
  # Example:
113
142
  # class Batch < ACH::Component
@@ -124,6 +153,9 @@ module ACH
124
153
  # batch.entries # => [<Entry, amount=100>, <Entry, amount=200>]
125
154
  # batch.addendas # => {<Entry, amount=100> => [<Addenda, text='Foo'>],
126
155
  # # <Entry, amount=200> => [<Addenda, text='Bar'>, <Addenda, text='Baz'>]}
156
+ #
157
+ # @return [Array]
158
+ # @raise [NoLinkError]
127
159
  def container_for_associated
128
160
  return container unless linked?
129
161
 
@@ -132,21 +164,27 @@ module ACH
132
164
  container[last_link] ||= []
133
165
  end
134
166
 
135
- # Returns +true+ if association is linked to another association (thus, it's records must
136
- # be preceded by other association's records). Returns +false+ otherwise
167
+ # Return +true+ if the association is linked to another association (thus, its records must
168
+ # be preceded by other association's records). Returns +false+ otherwise.
169
+ #
170
+ # @return [Boolean]
137
171
  def linked?
138
172
  !!linked_to
139
173
  end
140
174
  private :linked?
141
175
 
142
- # Returns +klass+ that corresponds to association name. Should be defined either in
143
- # ACH module, or in ACH::Record module
176
+ # Return +klass+ that corresponds to the association name. Should be defined either in
177
+ # ACH module, or in ACH::Record module.
178
+ #
179
+ # @return [Class]
144
180
  def klass
145
181
  @klass ||= ACH.to_const(@name.classify.to_sym)
146
182
  end
147
183
  private :klass
148
184
 
149
- # Returns singular name of the association
185
+ # Return the singular name of the association.
186
+ #
187
+ # @return [String]
150
188
  def singular_name
151
189
  @singular_name ||= name.singularize
152
190
  end
@@ -1,4 +1,5 @@
1
1
  module ACH
2
+ # This module is a simple namespace for constants used in ACH routines.
2
3
  module Constants
3
4
  # The length of each record in characters.
4
5
  RECORD_SIZE = 94
@@ -11,11 +12,17 @@ module ACH
11
12
  # This character must be used to delimit each row.
12
13
  ROWS_DELIMITER = "\n"
13
14
 
15
+ # ACH defined value of File Header record.
14
16
  FILE_HEADER_RECORD_TYPE = 1
17
+ # ACH defined value of File Control record.
15
18
  FILE_CONTROL_RECORD_TYPE = 9
19
+ # ACH defined value of Batch Header record.
16
20
  BATCH_HEADER_RECORD_TYPE = 5
21
+ # ACH defined value of Batch Entry record.
17
22
  BATCH_ENTRY_RECORD_TYPE = 6
23
+ # ACH defined value of Batch Addenda record.
18
24
  BATCH_ADDENDA_RECORD_TYPE = 7
25
+ # ACH defined value of Batch Control record.
19
26
  BATCH_CONTROL_RECORD_TYPE = 8
20
27
  end
21
- end
28
+ end