headache 0.1.4 → 1.0.0

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: 4d1bedb69c5748306c258fa087ba1195015aaca6
4
- data.tar.gz: 559aa917ee1ad1a409763f5d65c2455ad2e2d611
3
+ metadata.gz: 80f79889e015c7a29218886c2beebc3b2cb74402
4
+ data.tar.gz: 632e5c29ed41d97e1d01993e66ae7cdd76380a93
5
5
  SHA512:
6
- metadata.gz: d9a5081de1beb93da9a5d2ce2e24a726b3491b96595dfcf88197598a4fd1d6bf72f2e20fad68360524fe1d0502d1e015429c4c1bab721efa33585f19e5ce116b
7
- data.tar.gz: 78c8b7ae9aafb80c608b96b13168857ced74f7ebfd54ca634cd424bf1dd9da473024e32bf2ededdb0aecca45776c356d5b91b086b7fd4f3d78e805d2d1edd340
6
+ metadata.gz: 1d59922f2b2bd1ba75043ccc16d703af3da7961f0c6ccbb8077e1ca8a0284274eac95174bd19536d1beeea40ded6fb69abad283002bf984b6262167c57f4ff84
7
+ data.tar.gz: dc9e297eb06621ff5e39a339cc1620d153f415f0b813f7e3261d2d959712472818f51ac453f731c2a6481ab9fe91ac1837c2d3e502ac2d386cc5ade4f3e3e580
data/headache.gemspec CHANGED
@@ -23,4 +23,5 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency 'factory_girl', '~> 4.5'
24
24
  spec.add_development_dependency 'bundler', '~> 1.10'
25
25
  spec.add_development_dependency 'rake', '~> 10.0'
26
+ spec.add_development_dependency 'pry', '~> 0.10'
26
27
  end
@@ -8,25 +8,9 @@ module Headache
8
8
  :entry_class_code, :entry_description, :descriptive_date,
9
9
  :total_debit, :total_credit, :entry_hash
10
10
 
11
- @@record_classes = { header: Record::BatchHeader,
12
- control: Record::BatchControl }
13
-
14
- def self.header=(klass)
15
- set_class :header, klass
16
- end
17
-
18
- def self.control=(klass)
19
- set_class :control, klass
20
- end
21
-
22
- def self.set_class(type, klass)
23
- fail "unknown record class: #{type}" unless @@record_classes[type].present?
24
- @@record_classes[type] = klass
25
- end
26
-
27
11
  def parse(records)
28
- @header = @@record_classes[:header].new(self, @document).parse(records.shift)
29
- @control = @@record_classes[:control].new(self, @document).parse(records.pop)
12
+ @header = Record::BatchHeader.new(self, @document).parse(records.shift)
13
+ @control = Record::BatchControl.new(self, @document).parse(records.pop)
30
14
  records.each { |r| @members << Headache::Record::Entry.new(self, @document).parse(r) }
31
15
  self
32
16
  end
@@ -47,21 +31,21 @@ module Headache
47
31
  def self.type_from_service_code(code)
48
32
  return :credit if code.to_s == '220'
49
33
  return :debit if code.to_s == '225'
50
- fail "unknown service code: #{code.inspect} (expecting 220 or 225)"
34
+ fail Headache::UnknownServiceCode, "unknown service code: #{code.inspect} (expecting 220 or 225)"
51
35
  end
52
36
 
53
37
  def service_code
54
38
  return '220' if type == :credit
55
39
  return '225' if type == :debit
56
- fail "unknown batch type: #{type.inspect} (expecting :credit or :debit)"
40
+ fail Headache::UnknownBatchType, "unknown batch type: #{type.inspect} (expecting :credit or :debit)"
57
41
  end
58
42
 
59
43
  def header
60
- @header ||= @@record_classes[:header].new self, @document
44
+ @header ||= Record::BatchHeader.new self, @document
61
45
  end
62
46
 
63
47
  def control
64
- @control ||= @@record_classes[:control].new self, @document
48
+ @control ||= Record::BatchControl.new self, @documentec
65
49
  end
66
50
 
67
51
  def entries
@@ -73,8 +57,8 @@ module Headache
73
57
  end
74
58
 
75
59
  def to_h
76
- { batch_header: @header.to_h,
77
- entries: @members.to_a.map(&:to_h),
60
+ { batch_header: @header.to_h,
61
+ entries: @members.to_a.map(&:to_h),
78
62
  batch_control: @control.to_h }
79
63
  end
80
64
 
@@ -103,6 +87,5 @@ module Headache
103
87
  def total_credit
104
88
  @total_credit || entries.map(&:amount).select { |amt| (amt || 0) > 0 }.sum
105
89
  end
106
-
107
90
  end
108
91
  end
@@ -2,89 +2,28 @@ module Headache
2
2
  class Document < Fixy::Document
3
3
  attr_reader :batches
4
4
 
5
- LINE_SEPARATOR = "\r\n"
6
-
7
5
  delegate :add_entry, :'<<', to: :first_batch
8
6
 
9
- @@record_classes = { batch: Batch,
10
- header: Record::FileHeader,
11
- control: Record::FileControl }
12
-
13
- def self.header_class
14
- @@record_classes[:header]
15
- end
16
-
17
- def self.control_class
18
- @@record_classes[:control]
19
- end
20
-
21
- def self.header=(klass)
22
- set_class :header, klass
23
- end
24
-
25
- def self.control=(klass)
26
- set_class :control, klass
27
- end
28
-
29
- def self.extract_lines(string_or_file)
30
- string = string_or_file.respond_to?(:read) ? string_or_file.read : string_or_file
31
- string.split(LINE_SEPARATOR).reject { |line| line == Headache::Record::Overflow.new.generate.strip }
32
- end
33
-
34
- def self.cleanse_records(records)
35
- invalid_lines = records.reject { |line| Headache::Record::FileHeader.record_type_codes.values.include?(line.first.to_i) }
36
- raise "uknown record type(s): #{invalid_lines.map(&:first).inspect}" if invalid_lines.any?
37
- records
38
- end
39
-
40
- def self.parse(string_or_file)
41
- records = cleanse_records(extract_lines string_or_file)
42
- header = header_class.new(nil).parse(records.shift)
43
- control = control_class.new(nil).parse(records.pop)
44
- batches = get_batches(records).map { |b| Headache::Batch.new(self).parse(b) }
45
- new header, control, batches
46
- end
47
-
48
- def self.get_batches(records)
49
- batches = []
50
- batch = []
51
- records.each do |line|
52
- if line.starts_with?(Headache::Record::BatchHeader.record_type_codes[:batch_header].to_s)
53
- batches << batch unless batches.empty? && batch == []
54
- batch = [line]
55
- else
56
- batch << line
57
- end
58
- end
59
- batches << batch
60
- end
61
-
62
- def self.set_class(type, klass)
63
- fail "unknown record class: #{type}" unless @@record_classes[type].present?
64
- @@record_classes[type] = klass
65
- end
66
-
67
7
  def initialize(header = nil, control = nil, batches = [])
68
8
  @header = header
69
9
  @control = control
70
10
  @batches = batches
71
- @header.document = self unless @header.nil?
72
- @control.document = self unless @control.nil?
11
+ [@header, @control].each { |r| r.try :document=, self }
73
12
  end
74
13
 
75
14
  def first_batch
76
- add_batch @@record_classes[:batch].new(self) if @batches.empty?
15
+ add_batch Batch.new(self) if @batches.empty?
77
16
  @batches.first
78
17
  end
79
18
 
80
19
  def batch
81
- fail 'multiple batches detected, be more explicit or use first_batch' if @batches.count > 1
20
+ fail Headache::AmbiguousBatch, 'multiple batches detected, be more explicit or use first_batch' if @batches.count > 1
82
21
  first_batch
83
22
  end
84
23
 
85
24
  def add_batch(batch)
86
25
  batch.document = self
87
- @batches << batch # @@record_classes[:batch].new(self)
26
+ @batches << batch
88
27
  end
89
28
 
90
29
  def <<(batch)
@@ -97,17 +36,17 @@ module Headache
97
36
  end
98
37
 
99
38
  def header
100
- @header ||= @@record_classes[:header].new self
39
+ @header ||= Record::FileHeader.new self
101
40
  end
102
41
 
103
42
  def control
104
- @control ||= @@record_classes[:control].new self
43
+ @control ||= Record::FileControl.new self
105
44
  end
106
45
 
107
46
  def records
108
- ([ header ] << batches.map do |batch|
109
- [ batch.header, batch.entries, batch.control ]
110
- end << control).flatten # .compact
47
+ ([header] << batches.map do |batch|
48
+ [batch.header, batch.entries, batch.control]
49
+ end << control).flatten
111
50
  end
112
51
 
113
52
  def lines
@@ -119,8 +58,8 @@ module Headache
119
58
  end
120
59
 
121
60
  def to_h
122
- { file_header: @header.to_h,
123
- batches: @batches.map(&:to_h),
61
+ { file_header: @header.to_h,
62
+ batches: @batches.map(&:to_h),
124
63
  file_control: @control.to_h }
125
64
  end
126
65
 
@@ -134,6 +73,5 @@ module Headache
134
73
  append_record control
135
74
  overflow_lines_needed.times { append_record Record::Overflow.new }
136
75
  end
137
-
138
76
  end
139
77
  end
@@ -0,0 +1,51 @@
1
+ module Headache
2
+ class DocumentParser
3
+ LINE_SEPARATOR = "\r\n".freeze
4
+
5
+ def initialize(string_or_file)
6
+ @ach_string = string_or_file.respond_to?(:read) ? string_or_file.read : string_or_file
7
+ end
8
+
9
+ def parse
10
+ fail Headache::InvalidRecordType, invalid_fail_message if invalid_ach?
11
+
12
+ Headache::Document.new(
13
+ Record::FileHeader.new(nil).parse(records.shift),
14
+ Record::FileControl.new(nil).parse(records.pop),
15
+ get_batches.map { |b| Headache::Batch.new(self).parse(b) }
16
+ )
17
+ end
18
+
19
+ protected
20
+
21
+ def records
22
+ @records ||= @ach_string.split(LINE_SEPARATOR).reject { |record| record == Headache::Record::Overflow.new.generate.strip }
23
+ end
24
+
25
+ def invalid_fail_message
26
+ "unknown record type(s): #{invalid_records.map(&:first).inspect}"
27
+ end
28
+
29
+ def invalid_ach?
30
+ invalid_records.any?
31
+ end
32
+
33
+ def invalid_records
34
+ @invalid_records ||= records.reject { |record| Headache::Record::FileHeader.record_type_codes.values.include?(record.first.to_i) }
35
+ end
36
+
37
+ def get_batches
38
+ batches = []
39
+ batch = []
40
+ records.each do |record|
41
+ if record.starts_with?(Headache::Record::BatchHeader.record_type_codes[:batch_header].to_s)
42
+ batches << batch unless batches.empty? && batch == []
43
+ batch = [record]
44
+ else
45
+ batch << record
46
+ end
47
+ end
48
+ batches << batch
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,16 @@
1
+ module Headache
2
+ class Exception < ::RuntimeError
3
+ end
4
+
5
+ class InvalidRecordType < Headache::Exception
6
+ end
7
+
8
+ class AmbiguousBatch < Headache::Exception
9
+ end
10
+
11
+ class UnknownServiceCode < Headache::Exception
12
+ end
13
+
14
+ class UnknownBatchType < Headache::Exception
15
+ end
16
+ end
@@ -36,7 +36,7 @@ module Headache
36
36
  if input.is_a?(String) || input.is_a?(Fixnum)
37
37
  chars = input.to_s.chars
38
38
  minutes = chars.pop(2).join.to_i
39
- hours = chars.join.to_i
39
+ hours = chars.first(2).join.to_i
40
40
  input = Time.new 0, 1, 1, hours, minutes
41
41
  end
42
42
  fail "input #{input.inspect} does not respond to #strftime!" unless input.respond_to?(:strftime)
@@ -36,7 +36,7 @@ module Headache
36
36
  end
37
37
 
38
38
  def to_h
39
- str = self.generate.gsub Headache::Document::LINE_SEPARATOR, ''
39
+ str = self.generate.gsub Headache::DocumentParser::LINE_SEPARATOR, ''
40
40
  self.class.parse_fields(str)
41
41
  end
42
42
 
@@ -1,3 +1,3 @@
1
1
  module Headache
2
- VERSION = "0.1.4"
2
+ VERSION = "1.0.0"
3
3
  end
data/lib/headache.rb CHANGED
@@ -4,9 +4,11 @@ require 'active_support/concern'
4
4
  require 'active_support/core_ext/string'
5
5
  require 'active_support/core_ext/enumerable'
6
6
 
7
+ require 'headache/exception'
7
8
  require 'headache/formatters'
8
9
  require 'headache/definitions'
9
10
  require 'headache/record/base'
10
11
  require 'headache/records'
11
12
  require 'headache/batch'
12
13
  require 'headache/document'
14
+ require 'headache/document_parser'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: headache
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Payoff, Inc.
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2015-12-09 00:00:00.000000000 Z
12
+ date: 2016-04-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: fixy
@@ -109,6 +109,20 @@ dependencies:
109
109
  - - "~>"
110
110
  - !ruby/object:Gem::Version
111
111
  version: '10.0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: pry
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - "~>"
117
+ - !ruby/object:Gem::Version
118
+ version: '0.10'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: '0.10'
112
126
  description: Take the pain out of building ACH files. Wraps the Fixy gem for building
113
127
  fixed-with ACH files as specified by NACHA.
114
128
  email:
@@ -136,6 +150,8 @@ files:
136
150
  - lib/headache/definition/file_header.rb
137
151
  - lib/headache/definitions.rb
138
152
  - lib/headache/document.rb
153
+ - lib/headache/document_parser.rb
154
+ - lib/headache/exception.rb
139
155
  - lib/headache/formatters.rb
140
156
  - lib/headache/record/base.rb
141
157
  - lib/headache/record/batch_control.rb
@@ -166,9 +182,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
166
182
  version: '0'
167
183
  requirements: []
168
184
  rubyforge_project:
169
- rubygems_version: 2.4.5.1
185
+ rubygems_version: 2.4.7
170
186
  signing_key:
171
187
  specification_version: 4
172
188
  summary: Take the pain out of building ACH files.
173
189
  test_files: []
174
- has_rdoc: