nacha 0.1.0 → 0.1.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
  SHA256:
3
- metadata.gz: 1411753b1afc7c81a9e3875ec1541986d8b461afd5d0daae835879d17776ea7c
4
- data.tar.gz: 38fbcd4d7e222177dfc8bdce195991d13716ae669ca4649a7cf4e3428ab646d0
3
+ metadata.gz: d6d958fcc8edde96b13f6545611fb4fc86a751f4945955fe2f4960344bacc1ff
4
+ data.tar.gz: 6b9cbe9d4d61638f847595d76316b78263bf7b807ef1ed6c78f11e66348c7bc6
5
5
  SHA512:
6
- metadata.gz: 34e0fe3b791e0a47f9bef29898815b5d7fccac762ec21cbf227e3896a6dc8933d0a68349ff4cd661a65bff4f886b68fd22a31236dfdc6984d21c27b83d12d295
7
- data.tar.gz: 2f53f2b8ed728dc2778a1c78461fefb8dd22ddd8fe5d8ccefad1deff50931924e11af55b4a5edcbe1880455de7019b3434a0a42ceff8c12f99a3d8bdc75ac14e
6
+ metadata.gz: 4d559ecb5008d9e71e5c958dbc3400d35da7247c2a3f85f727adf50be020ac56c6b0ca30d470eff1247f45df05e94a603bc0754192ed7fc0baeee937abcd32ee
7
+ data.tar.gz: 718bebf3b746d052cfa2ad0c4e3390b1fef291dd16a588f25e493b1ef9f336c97ad4392951e6fe743aa5e4085430bed2b649940f7c2770733abc31c4f70b3c1e
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.4
1
+ 3.4.4
data/Gemfile CHANGED
@@ -2,8 +2,3 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in nacha.gemspec
4
4
  gemspec
5
-
6
- gem 'pry-byebug', group: %i[development test]
7
- gem 'pry-highlight', group: %i[development test]
8
- gem 'pry-remote', group: %i[development test]
9
- gem 'pry-stack_explorer', group: %i[development test]
data/README.md CHANGED
@@ -30,11 +30,10 @@ Or install it yourself as:
30
30
  API may change at any time. Pull requests welcomed
31
31
 
32
32
 
33
- `"101 124000054 1240000540907021214A094101ZIONS FIRST NATIONAL BAZIONS FIRST NATIONAL BA 1"`
34
33
 
35
34
  ```ruby
36
- ach_records = Nacha.parse(ach_file)
37
-
35
+ ach_string = "101 124000054 1240000540907021214A094101ZIONS FIRST NATIONAL BAZIONS FIRST NATIONAL BA 1"
36
+ ach_records = Nacha::Parser.parse_string(ach_string)
38
37
  ach_records[0].class # => Nacha::Record::FileHeaderRecord
39
38
 
40
39
  ach_records[0].to_json
@@ -57,6 +56,10 @@ API may change at any time. Pull requests welcomed
57
56
  }
58
57
  ```
59
58
 
59
+ ## Parse an ach file into an HTML file
60
+
61
+ ```
62
+ nacha parse ach_file.ach > ach_file.html`
60
63
 
61
64
  ## Development
62
65
 
data/bin/console CHANGED
@@ -6,9 +6,6 @@ require "nacha"
6
6
  # You can add fixtures and/or initialization code here to make experimenting
7
7
  # with your gem easier. You can also use a different console, if you like.
8
8
 
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
9
 
13
10
  require "irb"
14
11
  IRB.start(__FILE__)
data/exe/nacha ADDED
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'thor'
4
+ require 'nacha' # Assuming this loads the Nacha gem
5
+
6
+ module Nacha
7
+ class CLI < Thor
8
+
9
+ TEMPLATES_DIR = File.join(Gem::Specification.find_by_name("nacha").gem_dir,
10
+ "templates").freeze
11
+
12
+ HTML_PREAMBLE_FILE = File.join(TEMPLATES_DIR, "html_preamble.html")
13
+ HTML_POSTAMBLE_FILE = File.join(TEMPLATES_DIR, "html_postamble.html")
14
+
15
+ desc "parse FILE", "Parse an ACH file"
16
+ def parse(file_path)
17
+ begin
18
+ unless File.exist?(file_path)
19
+ puts "Error: File not found at #{file_path}"
20
+ exit 1
21
+ end
22
+
23
+ ach_file = [Nacha.parse(File.open(file_path)).first] # Use Nacha.parse
24
+
25
+ # TODO: Determine a user-friendly way to output the parsed data.
26
+ # For now, let's print the records.
27
+ if ach_file && ach_file.is_a?(Array) && !ach_file.empty?
28
+ output_html(file_path, ach_file)
29
+ else
30
+ puts "Could not parse the file or the file was empty."
31
+ end
32
+ rescue StandardError => e
33
+ puts "An error occurred during parsing: #{e.message}"
34
+ puts e.backtrace.join("\n")
35
+ exit 1
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def output_html(file_path, ach_file)
42
+ puts html_preamble
43
+ puts "<h1>Successfully parsed #{file_path}</h1>\n"
44
+ display_child(0, ach_file.first, 0) # Display the first record
45
+ puts html_postamble
46
+ end
47
+
48
+ def html_preamble
49
+ @html_preamble ||= File.read(HTML_PREAMBLE_FILE)
50
+ end
51
+
52
+ def html_postamble
53
+ @html_postamble ||= File.read(HTML_POSTAMBLE_FILE)
54
+ end
55
+
56
+ def display_child(level, record, index)
57
+ # Attempt to call a summary or to_s method if it exists,
58
+ # otherwise inspect the record.
59
+ level_indent = ' ' * level.to_i
60
+ puts "<html>"
61
+ puts record.to_html
62
+ if record.respond_to?(:children) && record.children.any?
63
+ if record.children.any?
64
+ record.children.each_with_index do |child_record, child_index|
65
+ display_child(level + 1, child_record, child_index)
66
+ end
67
+ end
68
+ end
69
+ puts "</html>"
70
+ end
71
+ end
72
+ end
73
+
74
+ Nacha::CLI.start(ARGV)
@@ -4,14 +4,41 @@ require 'date'
4
4
  # A Date object to handle some of the Ach formatted dates
5
5
 
6
6
  class Nacha::AchDate < Date
7
- def self.new(date_str)
8
- if date_str.is_a? String
9
- strptime(date_str, '%y%m%d')
10
- elsif date_str.is_a? Date
11
- date_str.dup
7
+ def self.new(*args)
8
+ year, month, day = nil
9
+
10
+ case args[0]
11
+ when String
12
+ date_str = args[0]
13
+ # Use Date.strptime to parse the string into a temporary Date object
14
+ temp_date = Date.strptime(date_str, '%y%m%d')
15
+ year, month, day = temp_date.year, temp_date.month, temp_date.day
16
+ when Date
17
+ original_date = args[0]
18
+ year, month, day = original_date.year, original_date.month, original_date.day
19
+ when Integer # If it's a year integer, assume (year, month, day) or single Julian day
20
+ # If 3 arguments (year, month, day) are provided like Date.new(2023, 10, 26)
21
+ if args.length == 3 && args.all? { |arg| arg.is_a?(Integer) }
22
+ year, month, day = args[0], args[1], args[2]
23
+ else
24
+ # Fallback for other Date.new arguments like (jd) - let super handle directly
25
+ return super(*args) # IMPORTANT: Call super to create the instance
26
+ end
12
27
  else
13
- super(date_str)
28
+ # If it's none of the above, pass arguments directly to Date.new.
29
+ # This handles cases like Date.new(2459918) (Julian day) or other Date constructors.
30
+ return super(*args)
14
31
  end
32
+
33
+ # If year, month, day were successfully parsed, create a Nacha::AchDate instance
34
+ # by calling the parent's `new` with the explicit components.
35
+ # `super()` in this context will call `Date.new(year, month, day)` but for *your* class.
36
+ # This works because `Date.new` is designed to be effectively `allocate.initialize`.
37
+ super(year, month, day)
38
+
39
+ rescue ArgumentError => e
40
+ # Catch errors that might arise from strptime or invalid date components
41
+ raise ArgumentError, "Invalid date format for Nacha::AchDate: #{args.inspect}. Original error: #{e.message}"
15
42
  end
16
43
 
17
44
  def to_s
data/lib/nacha/field.rb CHANGED
@@ -1,15 +1,15 @@
1
1
  # coding: utf-8
2
- require 'pry'
2
+ # frozen_string_literal: true
3
+
3
4
  require 'bigdecimal'
4
5
  require 'nacha/numeric'
5
6
  require 'nacha/aba_number'
6
7
  require 'nacha/ach_date'
7
8
 
8
9
  class Nacha::Field
9
-
10
- attr_accessor :inclusion, :contents, :position
11
- attr_accessor :data, :name, :errors
12
- attr_reader :input_data
10
+ attr_accessor :inclusion, :position
11
+ attr_accessor :name, :errors
12
+ attr_reader :contents, :data, :input_data
13
13
  attr_reader :data_type
14
14
  attr_reader :validator
15
15
  attr_reader :justification
@@ -17,17 +17,17 @@ class Nacha::Field
17
17
  attr_reader :output_conversion
18
18
  attr_reader :json_output
19
19
 
20
- def initialize opts = {}
20
+ def initialize(opts = {})
21
21
  @data_type = String
22
22
  @errors = []
23
- @name = 'Unknown'.freeze
23
+ @name = 'Unknown'
24
24
  @justification = :ljust
25
- @fill_character = ' '.freeze
25
+ @fill_character = ' '
26
26
  @json_output = [:to_s]
27
27
  @output_conversion = [:to_s]
28
- opts.each do |k,v|
28
+ opts.each do |k, v|
29
29
  setter = "#{k}="
30
- if(respond_to?(setter))
30
+ if respond_to?(setter)
31
31
  send(setter, v) unless v.nil?
32
32
  end
33
33
  end
@@ -35,99 +35,111 @@ class Nacha::Field
35
35
 
36
36
  # CXXX Constant
37
37
  #
38
- def contents= val
38
+ def contents=(val)
39
39
  @contents = val
40
40
  case @contents
41
- when /\AC(.*)\z/ # Constant
42
- @data = $1
41
+ when /\AC(.*)\z/ # Constant
42
+ @data = Regexp.last_match(1)
43
43
  when /Numeric/
44
44
  @data_type = Nacha::Numeric
45
45
  @justification = :rjust
46
46
  @json_output = [[:to_i]]
47
47
  @output_conversion = [:to_i]
48
- @fill_character = '0'.freeze
48
+ @fill_character = '0'
49
49
  when /.?TTTTAAAAC/
50
50
  @data_type = Nacha::AbaNumber
51
51
  @validator = :valid?
52
52
  @justification = :rjust
53
53
  @output_conversion = [:to_s]
54
- @fill_character = ' '.freeze
54
+ @fill_character = ' '
55
55
  when 'YYMMDD'
56
56
  @data_type = Nacha::AchDate
57
57
  @justification = :rjust
58
58
  @validator = :valid?
59
59
  @json_output = [[:iso8601]]
60
60
  @output_conversion = [:to_s]
61
- @fill_character = ' '.freeze
61
+ @fill_character = ' '
62
62
  when 'Alphameric'
63
63
  @data_type = String
64
64
  @justification = :ljust
65
65
  @output_conversion = [:to_s]
66
- @fill_character = ' '.freeze
67
- when /\$+\¢\¢/
66
+ @fill_character = ' '
67
+ when /\$+\u00a2\u00a2/
68
68
  @data_type = Nacha::Numeric
69
69
  @justification = :rjust
70
- @json_output = [[:to_i],[:/,100.0]]
70
+ @json_output = [[:to_i], [:/, 100.0]]
71
71
  @output_conversion = [:to_i]
72
- @fill_character = '0'.freeze
72
+ @fill_character = '0'
73
73
  end
74
74
  end
75
75
 
76
- def data= val
76
+ def data=(val)
77
77
  @data = @data_type.new(val)
78
78
  @input_data = val
79
79
  end
80
80
 
81
81
  def mandatory?
82
- @inclusion == 'M'.freeze
82
+ @inclusion == 'M'
83
83
  end
84
84
 
85
85
  def required?
86
- @inclusion == 'R'.freeze
86
+ @inclusion == 'R'
87
87
  end
88
88
 
89
89
  def optional?
90
- @inclusion == 'O'.freeze
90
+ @inclusion == 'O'
91
91
  end
92
92
 
93
93
  def valid?
94
94
  @valid = inclusion && contents && position
95
- if(@validator && @data)
96
- @valid &&= @data.send(@validator)
97
- end
95
+ @valid &&= @data.send(@validator) if @validator && @data
98
96
  @valid
99
97
  end
100
98
 
101
- def add_error err_string
99
+ def add_error(err_string)
102
100
  errors << err_string
103
101
  end
104
102
 
105
- def self.unpack_str(definition = { })
106
- if(definition[:contents] =~ /(Numeric|\$+\¢\¢)/)
107
- 'a'.freeze
103
+ def self.unpack_str(definition = {})
104
+ if definition[:contents] =~ /(Numeric|\$+\u00a2\u00a2)/
105
+ 'a'
108
106
  else
109
- 'A'.freeze
107
+ 'A'
110
108
  end + definition[:position].size.to_s
111
109
  end
112
110
 
113
111
  def to_ach
114
112
  str = to_s
115
113
  fill_char = @fill_character
116
- fill_char = ' '.freeze unless str
117
- str ||= ''.freeze
118
- str.send(justification,position.count, fill_char)
114
+ fill_char = ' ' unless str
115
+ str ||= ''
116
+ str.send(justification, position.count, fill_char)
119
117
  end
120
118
 
121
119
  def to_json_output
122
- if(@json_output)
123
- @json_output.reduce(@data) { |output, operation|
120
+ if @json_output
121
+ @json_output.reduce(@data) do |output, operation|
124
122
  output = output.send(*operation) if output
125
- }
123
+ end
126
124
  else
127
125
  to_s
128
126
  end
129
127
  end
130
128
 
129
+ def human_name
130
+ # @human_name ||= @name.to_s.gsub('_', ' ').capitalize
131
+ @human_name ||= @name.to_s.split('_').map(&:capitalize).join(' ')
132
+ end
133
+
134
+ def to_html
135
+ tooltip_text = "<span class=\"tooltiptext\" >#{human_name}</span>"
136
+ field_classes = "nacha-field tooltip data-field-name=\"#{@name}\""
137
+ ach_string = to_ach.gsub(' ', '&nbsp;')
138
+ "<span class=\"#{field_classes}\" data-name=\"#{@name}\">#{ach_string}" +
139
+ tooltip_text.to_s +
140
+ "</span>"
141
+ end
142
+
131
143
  def to_s
132
144
  @data.send(*output_conversion).to_s
133
145
  end
@@ -135,5 +147,4 @@ class Nacha::Field
135
147
  def raw
136
148
  @data
137
149
  end
138
-
139
150
  end
data/lib/nacha/numeric.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  class Nacha::Numeric
3
- attr_accessor :value
4
- def initialize(val = nil)
3
+ def initialize val = nil
5
4
  self.value = val
6
5
  end
7
6
 
@@ -20,7 +19,7 @@ class Nacha::Numeric
20
19
  def value=(val)
21
20
  if val.is_a?(String)
22
21
  @value = val.dup
23
- if !val.strip.empty?
22
+ if(val.strip.length > 0)
24
23
  @value = BigDecimal(val.strip)
25
24
  @op_value = @value
26
25
  else
@@ -30,15 +29,13 @@ class Nacha::Numeric
30
29
  @value = BigDecimal(val)
31
30
  @op_value = @value
32
31
  end
33
- @value
34
32
  end
35
33
 
36
34
  def to_s
37
35
  @value ? @value.to_s : nil
38
36
  end
39
37
 
40
- def respond_to?(method_name, include_private = false)
41
- puts "In respond_to? #{method_name}"
38
+ def respond_to_missing?(method_name, include_private = false)
42
39
  @op_value.respond_to? method_name
43
40
  end
44
41
 
@@ -47,14 +44,15 @@ class Nacha::Numeric
47
44
  # should be checked to see if the operation is valid for it, not
48
45
  # necessarily the potentially string @value
49
46
  def method_missing(method_name, *args, &block)
50
- puts "In method_missing for #{method_name} value_class = #{@value.class}, op_value_class = #{@op_value.class}"
51
47
  if @op_value.respond_to? method_name
52
48
  old_op_value = @op_value.dup
53
49
  if /!\z/.match?(method_name.to_s)
50
+ # rubocop:disable GitlabSecurity/PublicSend
54
51
  @op_value.send(method_name, *args, &block)
55
52
  return_value = @op_value
56
53
  else
57
54
  return_value = @op_value.send(method_name, *args, &block)
55
+ # rubocop:enable GitlabSecurity/PublicSend
58
56
  end
59
57
  if old_op_value != return_value
60
58
  @value = return_value
data/lib/nacha/parser.rb CHANGED
@@ -11,12 +11,7 @@ class Nacha::Parser
11
11
  def reset!; end
12
12
 
13
13
  def parse_file(file)
14
- parent = nil
15
- records = []
16
- File.foreach(file).with_index do |line, line_num|
17
- records << process(line, line_num, records.last)
18
- parent = records.last if records.lasts.class.child_record_types.any?
19
- end
14
+ parse_string(file.read)
20
15
  end
21
16
 
22
17
  def parse_string(str)
@@ -41,6 +36,7 @@ class Nacha::Parser
41
36
  parent = parent.parent
42
37
  record_types = valid_record_types(parent)
43
38
  end
39
+ record.line_number = line_num if record
44
40
  add_child(parent, record)
45
41
  record
46
42
  end
@@ -7,23 +7,22 @@ require 'nacha/record/validations/field_validations'
7
7
  module Nacha
8
8
  module Record
9
9
  class Base
10
- include FieldValidations
10
+ include Validations::FieldValidations
11
11
 
12
12
  attr_accessor :children, :parent, :fields
13
- attr_reader :definition, :name
14
- attr_reader :validations
15
-
16
- @@unpack_str = nil
17
- # @@matcher = nil
13
+ attr_reader :name, :validations
14
+ attr_accessor :line_number
18
15
 
19
16
  def initialize(opts = {})
20
17
  @children = []
21
18
  create_fields_from_definition
22
19
  opts.each do |k, v|
23
20
  setter = "#{k}="
24
- if respond_to?(setter)
25
- send(setter, v) unless v.nil?
26
- end
21
+ next unless respond_to? setter
22
+
23
+ # rubocop:disable GitlabSecurity/PublicSend
24
+ send(setter, v) unless v.nil?
25
+ # rubocop:enable GitlabSecurity/PublicSend
27
26
  end
28
27
  end
29
28
 
@@ -55,6 +54,15 @@ module Nacha
55
54
  end.join
56
55
  end
57
56
 
57
+ def to_html
58
+ "<div style=\"font-family: monospace;\"class='nacha-record tooltip #{record_type}'>" +
59
+ "<span class='tooltiptext'>#{record_type}</span>" +
60
+ "<span class='nacha-field' data-name='record-number'>#{"%05d" % [line_number]}&nbsp;|&nbsp</span>" +
61
+ @fields.keys.collect do |key|
62
+ @fields[key].to_html
63
+ end.join + "</div>"
64
+ end
65
+
58
66
  def inspect
59
67
  "#<#{self.class.name}> #{to_h}"
60
68
  end
@@ -63,12 +71,12 @@ module Nacha
63
71
  definition[name] = { inclusion: inclusion,
64
72
  contents: contents,
65
73
  position: position,
66
- name: name }
74
+ name: name}
67
75
  validation_method = "valid_#{name}".to_sym
68
- if respond_to?(validation_method)
69
- validations[name] ||= []
70
- validations[name] << validation_method
71
- end
76
+ return unless respond_to?(validation_method)
77
+
78
+ validations[name] ||= []
79
+ validations[name] << validation_method
72
80
  end
73
81
 
74
82
  def self.definition
@@ -79,8 +87,8 @@ module Nacha
79
87
  @validations ||= {}
80
88
  end
81
89
 
82
- def self.nacha_record_name(record_name)
83
- @nacha_record_name = record_name
90
+ class << self
91
+ attr_reader :nacha_record_name
84
92
  end
85
93
 
86
94
  def definition
@@ -89,23 +97,27 @@ module Nacha
89
97
 
90
98
  def validate
91
99
  self.class.definition.keys.map do |field|
92
- if self.class.validations[field]
93
- field_data = send(field)
94
- send(self.class.validations[:field], field_data)
95
- end
100
+ next unless self.class.validations[field]
101
+
102
+ # rubocop:disable GitlabSecurity/PublicSend
103
+ field_data = send(field)
104
+ send(self.class.validations[:field], field_data)
105
+ # rubocop:enable GitlabSecurity/PublicSend
96
106
  end
97
107
  end
98
108
 
99
109
  # look for invalid fields, if none, then return true
100
110
  def valid?
101
- !self.class.definition.keys.map do |field_sym|
111
+ statuses = self.class.definition.keys.map do |field_sym|
112
+ # rubocop:disable GitlabSecurity/PublicSend
102
113
  field = send(field_sym)
103
- next unless field.mandatory?
114
+ # rubocop:enable GitlabSecurity/PublicSend
115
+ next true unless field.mandatory?
104
116
 
105
117
  ## TODO: levels of validity with 'R' and 'O' fields
106
-
107
118
  field.valid?
108
- end.detect { |valid| valid == false }
119
+ end
120
+ !statuses.detect { |valid| valid == false }
109
121
  end
110
122
 
111
123
  def debit?
@@ -146,6 +158,7 @@ module Nacha
146
158
 
147
159
  def respond_to?(method_name, include_private = false)
148
160
  field_name = method_name.to_s.gsub(/=$/, '').to_sym
161
+
149
162
  definition[field_name] || super
150
163
  end
151
164
 
@@ -155,7 +168,9 @@ module Nacha
155
168
  if @fields[field_name]
156
169
  if is_assignment
157
170
  # @fields[field_name].send(:data=,*args)
158
- @fields[field_name].send(:data=, *args)
171
+ # rubocop:disable GitlabSecurity/PublicSend
172
+ @fields[field_name].public_send(:data=, *args)
173
+ # rubocop:enable GitlabSecurity/PublicSend
159
174
  @dirty = true
160
175
  else
161
176
  # @fields[field_name].data
@@ -3,29 +3,31 @@
3
3
 
4
4
  module Nacha
5
5
  module Record
6
- module FieldValidations
7
- def self.included(base)
8
- base.extend ClassMethods
9
- end
10
- module ClassMethods
11
- def check_field_error(field, message = nil, condition = nil)
12
- (block_given? ? yield : condition) || (field.add_error("'#{field.data}' is invalid") && false)
6
+ module Validations
7
+ module FieldValidations
8
+ def self.included base
9
+ base.extend ClassMethods
13
10
  end
11
+ module ClassMethods
12
+ def check_field_error(field, message = nil, condition = nil)
13
+ (block_given? ? yield : condition) || (field.add_error("'#{field.data}' is invalid") && false)
14
+ end
14
15
 
15
- def valid_service_class_code(field)
16
- check_field_error(field) { SERVICE_CLASS_CODES.include? field.to_s }
17
- end
16
+ def valid_service_class_code field
17
+ check_field_error(field) { SERVICE_CLASS_CODES.include? field.to_s }
18
+ end
18
19
 
19
- def valid_standard_entry_class_code(field)
20
- check_field_error(field) { STANDARD_ENTRY_CLASS_CODES.include? field.data }
21
- end
20
+ def valid_standard_entry_class_code field
21
+ check_field_error(field) { STANDARD_ENTRY_CLASS_CODES.include? field.data }
22
+ end
22
23
 
23
- def valid_transaction_code(field)
24
- check_field_error(field) { TRANSACTION_CODES.include? field.to_s }
25
- end
24
+ def valid_transaction_code field
25
+ check_field_error(field) { TRANSACTION_CODES.include? field.to_s }
26
+ end
26
27
 
27
- def valid_receiving_dfi_identification(field)
28
- check_field_error(field) { field.valid? }
28
+ def valid_receiving_dfi_identification field
29
+ check_field_error(field) { field.valid? }
30
+ end
29
31
  end
30
32
  end
31
33
  end
@@ -3,12 +3,13 @@
3
3
 
4
4
  module Nacha
5
5
  module Record
6
- module RecordValidations
7
- def self.included(base)
8
- base.extend ClassMethods
9
- end
10
-
11
- module ClassMethods
6
+ module Validations
7
+ module RecordValidations
8
+ def self.included base
9
+ base.extend ClassMethods
10
+ end
11
+ module ClassMethods
12
+ end
12
13
  end
13
14
  end
14
15
  end
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.0'
4
+ VERSION = '0.1.2'
5
5
  end
data/lib/nacha.rb CHANGED
@@ -7,11 +7,11 @@ require 'nacha/ach_date'
7
7
  require 'nacha/field'
8
8
  require 'nacha/numeric'
9
9
 
10
- Dir['lib/nacha/record/*.rb'].each do |file|
10
+ Gem.find_files('nacha/record/*.rb').reject{|f| f =~ /\/spec\//}.each do |file|
11
11
  require File.expand_path(file)
12
12
  end
13
13
 
14
- Dir['lib/nacha/record/**/*.rb'].each do |file|
14
+ Gem.find_files('nacha/record/**/*.rb').reject{|f| f =~ /\/spec\//}.each do |file|
15
15
  require File.expand_path(file)
16
16
  end
17
17
 
@@ -30,16 +30,26 @@ module Nacha
30
30
  48 49 55 56 82 84 86 88].freeze
31
31
 
32
32
  TRANSACTION_CODES = (CREDIT_TRANSACTION_CODES + DEBIT_TRANSACTION_CODES).freeze
33
-
34
- def self.record_name(str)
35
- underscore(str.to_s).split('/').last
36
- end
37
-
38
- def self.underscore(str)
39
- str.gsub(/::/, '/')
40
- .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
41
- .gsub(/([a-z\d])([A-Z])/, '\1_\2')
42
- .tr('-', '_')
43
- .downcase
33
+ class << self
34
+ def parse(object)
35
+ parser = Nacha::Parser.new
36
+ if object.is_a?(String)
37
+ parser.parse_string(object)
38
+ else
39
+ parser.parse_file(object)
40
+ end
41
+ end
42
+
43
+ def record_name(str)
44
+ underscore(str.to_s).split('/').last
45
+ end
46
+
47
+ def underscore(str)
48
+ str.gsub(/::/, '/').
49
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
50
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
51
+ tr('-', '_').
52
+ downcase
53
+ end
44
54
  end
45
55
  end
data/nacha.gemspec CHANGED
@@ -21,18 +21,16 @@ Gem::Specification.new do |spec|
21
21
  spec.bindir = "exe"
22
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
23
  spec.require_paths = ["lib"]
24
+ spec.add_dependency 'bigdecimal'
24
25
 
25
26
  spec.add_development_dependency "bundler", "~> 2.0"
26
- spec.add_development_dependency "byebug"
27
27
  spec.add_development_dependency "factory_bot"
28
28
  spec.add_development_dependency "gitlab-styles"
29
29
  spec.add_development_dependency "guard"
30
30
  spec.add_development_dependency "guard-rspec"
31
- spec.add_development_dependency "pry", "~> 0.10"
32
- spec.add_development_dependency "pry-doc", "~> 0.10"
33
31
  spec.add_development_dependency "rake", "~> 10.0"
34
32
  spec.add_development_dependency "rspec", "~> 3.0"
35
- spec.add_development_dependency "rubocop", '~> 0.69.0'
36
- spec.add_development_dependency 'rubocop-performance', '~> 1.1.0'
37
- spec.add_development_dependency 'rubocop-rspec', '~> 1.22.1'
33
+ spec.add_development_dependency "rubocop"
34
+ spec.add_development_dependency 'rubocop-performance'
35
+ spec.add_development_dependency 'rubocop-rspec'
38
36
  end
@@ -0,0 +1 @@
1
+ </body></html>
@@ -0,0 +1,68 @@
1
+ <!DOCTYPE html>
2
+ <html lang='en'>
3
+ <head>
4
+ <meta charset='UTF-8'>
5
+ <meta name='viewport' content='width=device-width, initial-scale=1.0'>
6
+ <title>NACHA File Parser</title>
7
+
8
+ <style>
9
+ body {
10
+ font-family: Arial, sans-serif;
11
+ }
12
+ body, h1, h2, h3, p {
13
+ margin: 0;
14
+ padding: 0;
15
+ }
16
+ body {
17
+ padding: 20px;
18
+ }
19
+ h1 {
20
+
21
+ font-size: 24px;
22
+ margin-bottom: 20px;
23
+ }
24
+
25
+ span.nacha-field:hover {
26
+ background-color: yellow;
27
+ }
28
+
29
+ .tooltip {
30
+ position: relative;
31
+ display: inline-block;
32
+ /* border-bottom: 1px dotted black; *//* If you want dots under the hoverable text */
33
+ }
34
+
35
+ /* Tooltip text */
36
+ .tooltip > .tooltiptext {
37
+ visibility: hidden;
38
+ /* width: 120px; */
39
+ background-color: black;
40
+ color: #fff;
41
+ text-align: center;
42
+ padding: 5px 5px;
43
+ border-radius: 6px;
44
+
45
+ top: 100%;
46
+ left: 50%;
47
+
48
+ /* Position the tooltip text - see examples below! */
49
+ position: absolute;
50
+ z-index: 1;
51
+ }
52
+
53
+ .nacha-record > .tooltiptext {
54
+ top: -50%;
55
+ left: 100%;
56
+ background-color: gray;
57
+ }
58
+
59
+ /* Show the tooltip text when you mouse over the tooltip container */
60
+ .tooltip:hover > .tooltiptext {
61
+ visibility: visible;
62
+ }
63
+
64
+
65
+ </style>
66
+ </head>
67
+ <body>
68
+ <h1>NACHA File Parser</h1>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nacha
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David H. Wilkins
@@ -10,33 +10,33 @@ cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
- name: bundler
13
+ name: bigdecimal
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
- - - "~>"
16
+ - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: '2.0'
19
- type: :development
18
+ version: '0'
19
+ type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
- - - "~>"
23
+ - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: '2.0'
25
+ version: '0'
26
26
  - !ruby/object:Gem::Dependency
27
- name: byebug
27
+ name: bundler
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
- - - ">="
30
+ - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '0'
32
+ version: '2.0'
33
33
  type: :development
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - ">="
37
+ - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '0'
39
+ version: '2.0'
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: factory_bot
42
42
  requirement: !ruby/object:Gem::Requirement
@@ -93,34 +93,6 @@ dependencies:
93
93
  - - ">="
94
94
  - !ruby/object:Gem::Version
95
95
  version: '0'
96
- - !ruby/object:Gem::Dependency
97
- name: pry
98
- requirement: !ruby/object:Gem::Requirement
99
- requirements:
100
- - - "~>"
101
- - !ruby/object:Gem::Version
102
- version: '0.10'
103
- type: :development
104
- prerelease: false
105
- version_requirements: !ruby/object:Gem::Requirement
106
- requirements:
107
- - - "~>"
108
- - !ruby/object:Gem::Version
109
- version: '0.10'
110
- - !ruby/object:Gem::Dependency
111
- name: pry-doc
112
- requirement: !ruby/object:Gem::Requirement
113
- requirements:
114
- - - "~>"
115
- - !ruby/object:Gem::Version
116
- version: '0.10'
117
- type: :development
118
- prerelease: false
119
- version_requirements: !ruby/object:Gem::Requirement
120
- requirements:
121
- - - "~>"
122
- - !ruby/object:Gem::Version
123
- version: '0.10'
124
96
  - !ruby/object:Gem::Dependency
125
97
  name: rake
126
98
  requirement: !ruby/object:Gem::Requirement
@@ -153,48 +125,49 @@ dependencies:
153
125
  name: rubocop
154
126
  requirement: !ruby/object:Gem::Requirement
155
127
  requirements:
156
- - - "~>"
128
+ - - ">="
157
129
  - !ruby/object:Gem::Version
158
- version: 0.69.0
130
+ version: '0'
159
131
  type: :development
160
132
  prerelease: false
161
133
  version_requirements: !ruby/object:Gem::Requirement
162
134
  requirements:
163
- - - "~>"
135
+ - - ">="
164
136
  - !ruby/object:Gem::Version
165
- version: 0.69.0
137
+ version: '0'
166
138
  - !ruby/object:Gem::Dependency
167
139
  name: rubocop-performance
168
140
  requirement: !ruby/object:Gem::Requirement
169
141
  requirements:
170
- - - "~>"
142
+ - - ">="
171
143
  - !ruby/object:Gem::Version
172
- version: 1.1.0
144
+ version: '0'
173
145
  type: :development
174
146
  prerelease: false
175
147
  version_requirements: !ruby/object:Gem::Requirement
176
148
  requirements:
177
- - - "~>"
149
+ - - ">="
178
150
  - !ruby/object:Gem::Version
179
- version: 1.1.0
151
+ version: '0'
180
152
  - !ruby/object:Gem::Dependency
181
153
  name: rubocop-rspec
182
154
  requirement: !ruby/object:Gem::Requirement
183
155
  requirements:
184
- - - "~>"
156
+ - - ">="
185
157
  - !ruby/object:Gem::Version
186
- version: 1.22.1
158
+ version: '0'
187
159
  type: :development
188
160
  prerelease: false
189
161
  version_requirements: !ruby/object:Gem::Requirement
190
162
  requirements:
191
- - - "~>"
163
+ - - ">="
192
164
  - !ruby/object:Gem::Version
193
- version: 1.22.1
165
+ version: '0'
194
166
  description: Ruby parser for ACH files.
195
167
  email:
196
168
  - dwilkins@conecuh.com
197
- executables: []
169
+ executables:
170
+ - nacha
198
171
  extensions: []
199
172
  extra_rdoc_files: []
200
173
  files:
@@ -213,6 +186,7 @@ files:
213
186
  - Rakefile
214
187
  - bin/console
215
188
  - bin/setup
189
+ - exe/nacha
216
190
  - lib/nacha.rb
217
191
  - lib/nacha/aba_number.rb
218
192
  - lib/nacha/ach_date.rb
@@ -280,6 +254,8 @@ files:
280
254
  - lib/nacha/record/xck_entry_detail.rb
281
255
  - lib/nacha/version.rb
282
256
  - nacha.gemspec
257
+ - templates/html_postamble.html
258
+ - templates/html_preamble.html
283
259
  homepage: https://github.com/dwilkins/nacha
284
260
  licenses:
285
261
  - MIT