headache 0.1.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: