nacha 0.1.8 → 0.1.10

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
  SHA256:
3
- metadata.gz: 8e70f9ad804c23687e8b3c9b6aa0fed4327554a98bdad5419a84dfe9f5d7f459
4
- data.tar.gz: 475cc33a0528eda1b5c55f670f87537ea8f7a6610b7943304738e09f4740bae1
3
+ metadata.gz: 6d8625f3af750aa7ba6e526909ad823f6020b761ab740616e82650f856585a13
4
+ data.tar.gz: 459d7359527c582eddf7d46770b2527896d465db86be48a1f6a994bc8d15471d
5
5
  SHA512:
6
- metadata.gz: 7b5d4c12e34b8eda4e97fd6a1ee4fa082217f967ac75893195566091673196346b544bc262d1ad789f136f55c28d1b4002495ae859474776200841d06fc10a21
7
- data.tar.gz: 98f8cb7134340a7088946dfe1904b1e11c485676f9ad7369bf299e20aa23af45323bb12dd7d0ba2d2064ff7fcffa8a9a9639ca4e885e09fa89c5f9b191d73dea
6
+ metadata.gz: fb31a6b021d3a7b7752f079651bfc5d2f78d5623883ab91201e76853273c3002c1d4a0423d971d5c75a2c38b03faee3e31d64d7cf82cb28f632c4c4174a6526b
7
+ data.tar.gz: 2aaf5af05547d0e0f10afb1f2a310e70b69e11c359979df5d238389c7800ab3f76ff163a5f35275162809f44b923603c2ed69658c96fe11e7f86eb8cbdf204cf
data/.rubocop.yml CHANGED
@@ -3,7 +3,7 @@ inherit_gem:
3
3
  - rubocop-default.yml
4
4
 
5
5
  AllCops:
6
- TargetRubyVersion: 2.5
6
+ TargetRubyVersion: 3.2
7
7
  Exclude:
8
8
  - 'tmp/**/*'
9
9
  - 'bin/**/*'
data/CHANGELOG.md CHANGED
@@ -7,6 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.1.10] - 2025-07-01
11
+
12
+ - Added ability to get a list of possible record types and
13
+ the ability parse just 1 record
14
+
15
+ - Fixed a bug where AdvFileControl did not have the FileControlRecordType
16
+ included
17
+
18
+ ## [0.1.9] - 2025-06-25
19
+
20
+ - Fixed AdvFileHeaer definition to include constant `ADV FILE` mentioned in the
21
+ NACHA documentation
22
+
23
+ - Added automatic debugger gem selection based on ruby version (ruby or jruby)
24
+
25
+ - Fixed Nacha.ach_record_types to have the correct list of record types by moving
26
+ the Nacha.add_ach_record_type(...) call above a possible return
27
+
28
+ - Added contentEditable to the generate HTML
29
+
30
+ - Added AdvFileHeader as one of the first records that should be found
31
+
32
+ - Removed a bunch of versions from nacha.gemspec
33
+
10
34
  ## [0.1.8] - 2025-06-24
11
35
 
12
36
  - Now parses filler records correctly (fixed definition)
data/README.md CHANGED
@@ -60,7 +60,7 @@ API may change at any time. Pull requests welcomed
60
60
 
61
61
  ```
62
62
  nacha parse ach_file.ach > ach_file.html`
63
-
63
+ ```
64
64
 
65
65
  ## Discussion
66
66
 
data/exe/nacha CHANGED
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
-
4
3
  require 'thor'
5
4
  require 'nacha' # Assuming this loads the Nacha gem
6
5
 
data/lib/nacha/field.rb CHANGED
@@ -187,7 +187,7 @@ class Nacha::Field
187
187
  field_classes += ['error'] if errors.any?
188
188
 
189
189
  ach_string = to_ach.gsub(' ', ' ')
190
- "<span data-field-name=\"#{@name}\" class=\"#{field_classes.join(' ')}\" data-name=\"#{@name}\">#{ach_string}" +
190
+ "<span data-field-name=\"#{@name}\" contentEditable=true class=\"#{field_classes.join(' ')}\" data-name=\"#{@name}\">#{ach_string}" +
191
191
  tooltip_text.to_s +
192
192
  "</span>"
193
193
  end
data/lib/nacha/parser.rb CHANGED
@@ -3,25 +3,38 @@
3
3
  require 'nacha'
4
4
  require 'nacha/parser_context'
5
5
 
6
+ # Nacha Parser - deal with figuring out what record type a line is
6
7
  class Nacha::Parser
7
- DEFAULT_RECORD_TYPES = ['Nacha::Record::FileHeader',
8
- 'Nacha::Record::Filler'].freeze
8
+ DEFAULT_RECORD_TYPES = ['Nacha::Record::AdvFileHeader',
9
+ 'Nacha::Record::FileHeader',
10
+ 'Nacha::Record::Filler'].freeze
9
11
 
10
12
  attr_reader :context
11
13
 
12
14
  def initialize
13
15
  @context = Nacha::ParserContext.new
14
- reset!
15
16
  end
16
17
 
17
- def reset!; end
18
-
19
18
  def parse_file(file)
20
19
  @context.parser_started_at = Time.now
21
20
  @context.file_name = file
22
21
  parse_string(file.read)
23
22
  end
24
23
 
24
+ def detect_possible_record_types(line)
25
+ Nacha.ach_record_types.map do |record_type|
26
+ record_type if record_type.matcher =~ line
27
+ end.compact
28
+ end
29
+
30
+ def parse_line(line)
31
+ record_types = detect_possible_record_types(line)
32
+
33
+ records = record_types.map do |record_type|
34
+
35
+ end
36
+ end
37
+
25
38
  def parse_string(str)
26
39
  line_num = -1
27
40
  records = []
@@ -39,11 +52,10 @@ class Nacha::Parser
39
52
  def process(line, line_num, previous = nil)
40
53
  @context.line_errors = []
41
54
  parent = previous
42
- record = nil
43
55
 
44
56
  record_types = valid_record_types(parent)
45
57
  while record_types
46
- record = parse_by_types(line, record_types)
58
+ record = parse_first_by_types(line, record_types)
47
59
  break if record || !parent
48
60
  record.validate if record
49
61
  parent = parent.parent
@@ -67,11 +79,21 @@ class Nacha::Parser
67
79
  child.parent = parent
68
80
  end
69
81
 
70
- def parse_by_types(line, record_types)
82
+ def parse_first_by_types(line, record_types)
71
83
  record_types.detect do |rt|
72
- record_type = Object.const_get(rt)
84
+ record_type = rt.is_a?(Class) ? rt : Object.const_get(rt)
85
+ record = nil
73
86
  record = record_type.parse(line) if record_type.matcher =~ line
74
87
  return record if record
75
88
  end
76
89
  end
90
+
91
+ def parse_all_by_types(line, record_types)
92
+ record_types.map do |rt|
93
+ record_type = rt.is_a?(Class) ? rt : Object.const_get(rt)
94
+ record = nil
95
+ record = record_type.parse(line) if record_type.matcher =~ line
96
+ record
97
+ end.compact
98
+ end
77
99
  end
@@ -6,6 +6,8 @@ require 'nacha/record/batch_control_record_type.rb'
6
6
 
7
7
  module Nacha
8
8
  module Record
9
+
10
+ # The AdvBatchControl record is used to control the batch of adv entry detail records.
9
11
  class AdvBatchControl < Nacha::Record::Base
10
12
  nacha_field :record_type_code, inclusion: 'M', contents: 'C8', position: 1..1
11
13
  nacha_field :service_class_code, inclusion: 'M', contents: 'Numeric', position: 2..4
@@ -7,6 +7,7 @@ require 'nacha/record/file_control_record_type.rb'
7
7
  module Nacha
8
8
  module Record
9
9
  class AdvFileControl < Nacha::Record::Base
10
+ include FileControlRecordType
10
11
  nacha_field :record_type_code, inclusion: 'M', contents: 'C9', position: 1..1
11
12
  nacha_field :batch_count, inclusion: 'M', contents: 'Numeric', position: 2..7
12
13
  nacha_field :block_count, inclusion: 'M', contents: 'Numeric', position: 8..13
@@ -15,10 +16,6 @@ module Nacha
15
16
  nacha_field :total_debit_entry_dollar_amount_in_file, inclusion: 'M', contents: '$$$$$$$$$$¢¢', position: 32..51
16
17
  nacha_field :total_credit_entry_dollar_amount_in_file, inclusion: 'M', contents: '$$$$$$$$$$¢¢', position: 52..71
17
18
  nacha_field :reserved, inclusion: 'M', contents: 'C', position: 72..94
18
-
19
- # def initialize
20
- # create_fields_from_definition
21
- # end
22
19
  end
23
20
  end
24
21
  end
@@ -20,7 +20,7 @@ module Nacha
20
20
  nacha_field :format_code, inclusion: 'M', contents: 'C1', position: 40..40
21
21
  nacha_field :immediate_destination_name, inclusion: 'M', contents: 'Alphameric', position: 41..63
22
22
  nacha_field :immediate_origin_name, inclusion: 'M', contents: 'Alphameric', position: 64..86
23
- nacha_field :reference_code, inclusion: 'M', contents: 'Alphameric', position: 87..94
23
+ nacha_field :reference_code, inclusion: 'M', contents: 'CADV FILE', position: 87..94
24
24
  end
25
25
  end
26
26
  end
@@ -30,6 +30,7 @@ module Nacha
30
30
 
31
31
  class << self
32
32
  def nacha_field(name, inclusion:, contents:, position:)
33
+ Nacha.add_ach_record_type(self)
33
34
  definition[name] = { inclusion: inclusion,
34
35
  contents: contents,
35
36
  position: position,
@@ -39,7 +40,6 @@ module Nacha
39
40
 
40
41
  validations[name] ||= []
41
42
  validations[name] << validation_method
42
- Nacha.add_ach_record_type(self)
43
43
  end
44
44
 
45
45
  def definition
@@ -120,6 +120,10 @@ module Nacha
120
120
  rec.validate
121
121
  rec
122
122
  end
123
+
124
+ def record_type
125
+ Nacha.record_name(self)
126
+ end
123
127
  end # end class methods
124
128
 
125
129
  def original_input_line=(line)
@@ -134,7 +138,7 @@ module Nacha
134
138
  end
135
139
 
136
140
  def record_type
137
- Nacha.record_name(self.class)
141
+ self.class.record_type
138
142
  end
139
143
 
140
144
  def human_name
@@ -144,6 +148,7 @@ module Nacha
144
148
  def to_h
145
149
  { nacha_record_type: record_type,
146
150
  metadata: {
151
+ klass: self.class.name,
147
152
  errors: errors,
148
153
  line_number: @line_number,
149
154
  original_input_line: original_input_line
@@ -5,9 +5,11 @@ require 'nacha/record/file_header_record_type.rb'
5
5
 
6
6
  module Nacha
7
7
  module Record
8
+
9
+ # The FileHeader record is the first record in a
10
+ # Nacha file and contains information about the file itself.
8
11
  class FileHeader < Nacha::Record::Base
9
12
  include FileHeaderRecordType
10
-
11
13
  nacha_field :record_type_code, inclusion: 'M', contents: 'C1', position: 1..1
12
14
  nacha_field :priority_code, inclusion: 'R', contents: 'Numeric', position: 2..3
13
15
  nacha_field :immediate_destination, inclusion: 'M', contents: 'bTTTTAAAAC', position: 4..13
data/lib/nacha/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Nacha
4
- VERSION = '0.1.8'
4
+ VERSION = '0.1.10'
5
5
  end
data/lib/nacha.rb CHANGED
@@ -1,5 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Uncomment to use debugger
4
+ # if RUBY_ENGINE == 'ruby'
5
+ # require "byebug"
6
+ # end
7
+ #
8
+ # if RUBY_ENGINE == 'jruby'
9
+ # require "pry-nav"
10
+ # end
11
+
3
12
  require 'yaml'
4
13
  require 'nacha/version'
5
14
  require 'nacha/aba_number'
@@ -7,6 +16,10 @@ require 'nacha/ach_date'
7
16
  require 'nacha/field'
8
17
  require 'nacha/numeric'
9
18
 
19
+ # Nacha is a Ruby gem for parsing, validating, and generating NACHA
20
+ # (National Automated Clearing House Association) files.
21
+ # It provides a structured way to work with ACH (Automated Clearing House) records,
22
+ # including various entry detail, addenda, batch, and file control records.
10
23
  module Nacha
11
24
  STANDARD_ENTRY_CLASS_CODES = %w[ACK ADV ARC ATX BOC CCD PPD CIE
12
25
  COR CTX DNE ENR IAT POP POS SHR
@@ -20,17 +33,37 @@ module Nacha
20
33
  48 49 55 56 82 84 86 88].freeze
21
34
 
22
35
  TRANSACTION_CODES = (CREDIT_TRANSACTION_CODES + DEBIT_TRANSACTION_CODES).freeze
23
- @@ach_record_types = []
24
36
 
25
- def self.add_ach_record_type(klass)
26
- @@ach_record_types << klass unless @@ach_record_types.include?(klass)
27
- end
37
+ class << self
38
+ # Adds a new ACH record type class to the list of defined record types.
39
+ # This is used internally by the parser to determine which record classes
40
+ # are available for parsing a NACHA file. As the `nacha_field` method is
41
+ # executed for each of the record types, these record types are added to
42
+ # the Nacha module's class variable `@@ach_record_types`.
43
+ #
44
+ # @param klass [Class, String] The record class or its name (as a String) to add.
45
+ # @return [void]
46
+ def add_ach_record_type(klass)
47
+ return unless klass
28
48
 
29
- def self.ach_record_types
30
- @@ach_record_types
31
- end
49
+ klass = klass.to_s
50
+ @ach_record_types ||= []
51
+ @ach_record_types << klass unless @ach_record_types.include?(klass)
52
+ end
32
53
 
33
- class << self
54
+ # Returns an array of all currently registered ACH record type class names.
55
+ #
56
+ # @return [Array<String>] An array of strings representing the names of ACH record classes.
57
+ def ach_record_types
58
+ @ach_record_types || []
59
+ end
60
+
61
+ # Parses a NACHA file or string into a structured object representation.
62
+ #
63
+ # @param object [String, File, IO] The input to parse, either a string containing
64
+ # NACHA data or an IO object (e.g., a File) representing the NACHA file.
65
+ # @return [Nacha::Record::Base] The parsed NACHA file object, typically a FileHeader record
66
+ # with nested batch and entry detail records.
34
67
  def parse(object)
35
68
  parser = Nacha::Parser.new
36
69
  if object.is_a?(String)
@@ -40,10 +73,21 @@ module Nacha
40
73
  end
41
74
  end
42
75
 
76
+ # Converts a given string into a underscored, lowercase record name.
77
+ # This is typically used to derive a human-readable or programmatic
78
+ # name from a class name or similar string.
79
+ #
80
+ # @param str [String] The string to convert.
81
+ # @return [String] The underscored and lowercased record name.
43
82
  def record_name(str)
44
83
  underscore(str.to_s).split('/').last
45
84
  end
46
85
 
86
+ # Converts a camel-cased string to its underscore equivalent.
87
+ # This method handles module namespaces (::) by converting them to slashes.
88
+ #
89
+ # @param str [String] The string to underscore.
90
+ # @return [String] The underscored string.
47
91
  def underscore(str)
48
92
  str.gsub(/::/, '/').
49
93
  gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
@@ -54,6 +98,18 @@ module Nacha
54
98
  end
55
99
  end
56
100
 
101
+ # Load all record types from nacha/record/*.rb and nacha/record/**/*.rb
102
+ # This will ensure that all record classes are loaded before the parser is used
103
+
104
+ require 'nacha/record/base'
105
+ require 'nacha/record/file_header_record_type'
106
+ require 'nacha/record/file_control_record_type'
107
+ require 'nacha/record/detail_record_type'
108
+
109
+ # Ensure that the record types are loaded before the parser is used
110
+ # This is necessary because the parser relies on the record types being defined
111
+ # and available in the Nacha module.
112
+
57
113
  Gem.find_files('nacha/record/*.rb').reject{|f| f =~ /\/spec\//}.each do |file|
58
114
  require File.expand_path(file)
59
115
  end
@@ -62,5 +118,6 @@ Gem.find_files('nacha/record/**/*.rb').reject{|f| f =~ /\/spec\//}.each do |file
62
118
  require File.expand_path(file)
63
119
  end
64
120
 
65
- require 'nacha/parser'
121
+ # Load the parser after the records have been defined
66
122
 
123
+ require 'nacha/parser'
data/nacha.gemspec CHANGED
@@ -23,15 +23,21 @@ Gem::Specification.new do |spec|
23
23
  spec.require_paths = ["lib"]
24
24
  spec.add_dependency 'bigdecimal'
25
25
 
26
- spec.add_development_dependency "bundler", "~> 2.0"
27
- spec.add_development_dependency "byebug"
26
+ spec.add_development_dependency "bundler"
27
+ # Conditionally add byebug only for MRI Ruby
28
+ if RUBY_ENGINE == 'ruby'
29
+ spec.add_development_dependency "byebug"
30
+ end
31
+ if RUBY_ENGINE == 'jruby'
32
+ spec.add_development_dependency "pry-nav"
33
+ end
28
34
  spec.add_development_dependency "pry"
29
35
  spec.add_development_dependency "factory_bot"
30
36
  spec.add_development_dependency "gitlab-styles"
31
37
  spec.add_development_dependency "guard"
32
38
  spec.add_development_dependency "guard-rspec"
33
- spec.add_development_dependency "rake", "~> 10.0"
34
- spec.add_development_dependency "rspec", "~> 3.0"
39
+ spec.add_development_dependency "rake"
40
+ spec.add_development_dependency "rspec"
35
41
  spec.add_development_dependency "rubocop"
36
42
  spec.add_development_dependency 'rubocop-performance'
37
43
  spec.add_development_dependency 'rubocop-rspec'
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nacha
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - David H. Wilkins
8
+ autorequire:
8
9
  bindir: exe
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2025-07-02 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: bigdecimal
@@ -27,16 +28,16 @@ dependencies:
27
28
  name: bundler
28
29
  requirement: !ruby/object:Gem::Requirement
29
30
  requirements:
30
- - - "~>"
31
+ - - ">="
31
32
  - !ruby/object:Gem::Version
32
- version: '2.0'
33
+ version: '0'
33
34
  type: :development
34
35
  prerelease: false
35
36
  version_requirements: !ruby/object:Gem::Requirement
36
37
  requirements:
37
- - - "~>"
38
+ - - ">="
38
39
  - !ruby/object:Gem::Version
39
- version: '2.0'
40
+ version: '0'
40
41
  - !ruby/object:Gem::Dependency
41
42
  name: byebug
42
43
  requirement: !ruby/object:Gem::Requirement
@@ -125,30 +126,30 @@ dependencies:
125
126
  name: rake
126
127
  requirement: !ruby/object:Gem::Requirement
127
128
  requirements:
128
- - - "~>"
129
+ - - ">="
129
130
  - !ruby/object:Gem::Version
130
- version: '10.0'
131
+ version: '0'
131
132
  type: :development
132
133
  prerelease: false
133
134
  version_requirements: !ruby/object:Gem::Requirement
134
135
  requirements:
135
- - - "~>"
136
+ - - ">="
136
137
  - !ruby/object:Gem::Version
137
- version: '10.0'
138
+ version: '0'
138
139
  - !ruby/object:Gem::Dependency
139
140
  name: rspec
140
141
  requirement: !ruby/object:Gem::Requirement
141
142
  requirements:
142
- - - "~>"
143
+ - - ">="
143
144
  - !ruby/object:Gem::Version
144
- version: '3.0'
145
+ version: '0'
145
146
  type: :development
146
147
  prerelease: false
147
148
  version_requirements: !ruby/object:Gem::Requirement
148
149
  requirements:
149
- - - "~>"
150
+ - - ">="
150
151
  - !ruby/object:Gem::Version
151
- version: '3.0'
152
+ version: '0'
152
153
  - !ruby/object:Gem::Dependency
153
154
  name: rubocop
154
155
  requirement: !ruby/object:Gem::Requirement
@@ -306,6 +307,7 @@ homepage: https://github.com/dwilkins/nacha
306
307
  licenses:
307
308
  - MIT
308
309
  metadata: {}
310
+ post_install_message:
309
311
  rdoc_options: []
310
312
  require_paths:
311
313
  - lib
@@ -320,7 +322,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
320
322
  - !ruby/object:Gem::Version
321
323
  version: '0'
322
324
  requirements: []
323
- rubygems_version: 3.6.7
325
+ rubygems_version: 3.4.19
326
+ signing_key:
324
327
  specification_version: 4
325
328
  summary: Ruby parser for ACH files.
326
329
  test_files: []