metro_2 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6da54305e9214a4064d44b76cda323168e1f41ab
4
+ data.tar.gz: beeb5466eb619c9c8a48e089b597b7afb919219b
5
+ SHA512:
6
+ metadata.gz: e7553fab682842f16f9d998989754998713c0fbbfa4d83c75cab97255b16b739954d3bed5cd7f24c9df02cb45cfdd248bfde766989c4d78f1896ed8a82d51ede
7
+ data.tar.gz: 072b5f4387953315956212371cfe6d88a7909a0c100c3b8ed103613616e684672635ec86d064d6ea5b3476408966e034aa8ab5d1c783e6470a63f837bb62f630
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --colour
2
+
3
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in metro_2.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Brian Mascarenhas
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # Metro2
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'metro_2'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install metro_2
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it ( https://github.com/[my-github-username]/metro_2/fork )
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+ Bundler.require
6
+ require 'metro_2/version'
7
+
8
+ require 'rspec/core/rake_task'
9
+
10
+ RSpec::Core::RakeTask.new(:spec)
11
+
12
+ task :default => :spec
13
+
14
+ task :build do
15
+ system 'gem build metro_2.gemspec'
16
+ end
17
+
data/lib/metro_2.rb ADDED
@@ -0,0 +1,60 @@
1
+ require 'metro_2/version'
2
+
3
+ module Metro2
4
+
5
+ ALPHANUMERIC = /\A([[:alnum:]]|\s)+\z/
6
+ ALPHANUMERIC_PLUS_DASH = /\A([[:alnum:]]|\s|\-)+\z/
7
+ ALPHANUMERIC_PLUS_DOT_DASH_SLASH = /\A([[:alnum:]]|\s|\-|\.|\\|\/)+\z/
8
+ NUMERIC = /\A\d+\.?\d*\z/
9
+
10
+ FIXED_LENGTH = 426
11
+
12
+ def self.alphanumeric_to_metro2(val, required_length, permitted_chars)
13
+ # Left justified and blank-filled
14
+ val = val.to_s
15
+
16
+ return ' ' * required_length if val.empty?
17
+
18
+ unless !!(val =~ permitted_chars)
19
+ raise ArgumentError.new("Content (#{val}) contains invalid characters")
20
+ end
21
+
22
+ if val.size > required_length
23
+ val[0..(required_length-1)]
24
+ else
25
+ val + (' ' * (required_length - val.size))
26
+ end
27
+ end
28
+
29
+ def self.numeric_to_metro2(val, required_length, is_monetary)
30
+ # Right justified and zero-filled
31
+ val = val.to_s
32
+
33
+ return '0' * required_length if val.empty?
34
+
35
+ unless !!(val =~ Metro2::NUMERIC)
36
+ raise ArgumentError.new("field (#{val}) must be numeric")
37
+ end
38
+
39
+ decimal_index = val.index('.')
40
+ val = val[0..(decimal_index - 1)] if decimal_index
41
+
42
+ # any value above 1 billion gets set to 999,999,999
43
+ return '9' * required_length if is_monetary && val.to_f >= 1000000000
44
+ if val.size > required_length
45
+ raise ArgumentError.new("numeric field (#{val}) is too long (max #{required_length})")
46
+ end
47
+
48
+ ('0' * (required_length - val.size)) + val
49
+ end
50
+ end
51
+
52
+ require 'metro_2/fields'
53
+ require 'metro_2/metro2_file'
54
+
55
+ # Require records files
56
+ require 'metro_2/records/record'
57
+
58
+ Dir.new(File.dirname(__FILE__) + '/metro_2/records').each do |file|
59
+ require('metro_2/records/' + File.basename(file)) if File.extname(file) == ".rb"
60
+ end
@@ -0,0 +1,122 @@
1
+ module Metro2
2
+ module Fields
3
+
4
+ def alphanumeric_field(name, required_length, permitted_chars = Metro2::ALPHANUMERIC)
5
+ fields << name
6
+
7
+ # getter
8
+ define_method name do
9
+ instance_variable_get("@#{name}")
10
+ end
11
+
12
+ # setter (includes validations)
13
+ define_method "#{name}=" do | val |
14
+ instance_variable_set("@#{name}", val)
15
+ end
16
+
17
+ # to_metro2
18
+ define_method "#{name}_to_metro2" do
19
+ val = instance_variable_get("@#{name}")
20
+ Metro2.alphanumeric_to_metro2(val, required_length, permitted_chars)
21
+ end
22
+ end
23
+
24
+ def numeric_field(name, required_length, is_monetary = false)
25
+ fields << name
26
+
27
+ # getter
28
+ define_method name do
29
+ instance_variable_get("@#{name}")
30
+ end
31
+
32
+ # setter (includes validations)
33
+ define_method "#{name}=" do | val |
34
+ instance_variable_set("@#{name}", val)
35
+ end
36
+
37
+ # to_metro2
38
+ define_method "#{name}_to_metro2" do
39
+ val = instance_variable_get("@#{name}")
40
+ Metro2.numeric_to_metro2(val, required_length, is_monetary)
41
+ end
42
+ end
43
+
44
+ def alphanumeric_const_field(name, required_length, val, permitted_chars = Metro2::ALPHANUMERIC)
45
+ fields << name
46
+
47
+ # getter
48
+ define_method name do
49
+ val
50
+ end
51
+
52
+ # to_metro2
53
+
54
+ define_method "#{name}_to_metro2" do
55
+ Metro2.alphanumeric_to_metro2(val, required_length, permitted_chars)
56
+ end
57
+ end
58
+
59
+ def numeric_const_field(name, required_length, val, is_monetary = false)
60
+ fields << name
61
+
62
+ # getter
63
+ define_method name do
64
+ val
65
+ end
66
+
67
+ # to_metro2
68
+ define_method "#{name}_to_metro2" do
69
+ Metro2.numeric_to_metro2(val, required_length, is_monetary)
70
+ end
71
+ end
72
+
73
+ def monetary_field(name)
74
+ numeric_field(name, 9, true)
75
+ end
76
+
77
+ def date_field(name)
78
+ fields << name
79
+
80
+ # getter
81
+ define_method name do
82
+ instance_variable_get("@#{name}")
83
+ end
84
+
85
+ # setter (includes validations)
86
+ define_method "#{name}=" do | val |
87
+ instance_variable_set("@#{name}", val)
88
+ end
89
+
90
+ # to_metro2
91
+ define_method "#{name}_to_metro2" do
92
+ # Right justified and zero-filled
93
+ val = instance_variable_get("@#{name}")
94
+ val = val.strftime('%m%d%Y') if val
95
+ Metro2.numeric_to_metro2(val, 8, false)
96
+ end
97
+ end
98
+
99
+ def timestamp_field(name)
100
+ fields << name
101
+
102
+ # getter
103
+ define_method name do
104
+ instance_variable_get("@#{name}")
105
+ end
106
+
107
+ # setter (includes validations)
108
+ define_method "#{name}=" do | val |
109
+ instance_variable_set("@#{name}", val)
110
+ end
111
+
112
+ # to_metro2
113
+ define_method "#{name}_to_metro2" do
114
+ # Right justified and zero-filled
115
+ val = instance_variable_get("@#{name}")
116
+ val = val.strftime('%m%d%Y%H%M%S') if val
117
+ Metro2.numeric_to_metro2(val, 14, false)
118
+ end
119
+ end
120
+ end
121
+
122
+ end
@@ -0,0 +1,76 @@
1
+ require 'date'
2
+
3
+ module Metro2
4
+ class Metro2File
5
+ include Fields
6
+
7
+ attr_reader :base_segments
8
+ attr_reader :header
9
+ attr_reader :trailer
10
+
11
+ def initialize
12
+ @base_segments = []
13
+ @header = Records::HeaderSegment.new
14
+ end
15
+
16
+ def to_s
17
+ segments = []
18
+ segments << @header
19
+ @base_segments.each { |base| segments << base }
20
+ @trailer ||= trailer_from_base_segments
21
+ segments << @trailer
22
+
23
+ segments.collect { |r| r.to_metro2 }.join("\n") + "\n"
24
+ end
25
+
26
+ def trailer_from_base_segments
27
+ status_code_count = Hash.new(0)
28
+ num_ssn = 0
29
+ num_dob = 0
30
+ num_telephone = 0
31
+ num_ecoa_code_z = 0
32
+
33
+ @base_segments.each do |base|
34
+ status_code_count[base.account_status.upcase] += 1
35
+ num_ssn += 1 if base.social_security_number
36
+ num_dob += 1 if base.date_of_birth
37
+ num_telephone += 1 if base.telephone_number
38
+ num_ecoa_code_z += 1 if base.ecoa_code == 'Z'
39
+ end
40
+
41
+ trailer = Records::TrailerSegment.new
42
+ trailer.total_base_records = @base_segments.size
43
+ trailer.total_status_code_df = status_code_count['DF']
44
+ trailer.total_status_code_df = status_code_count['DA']
45
+ trailer.total_status_code_df = status_code_count['05']
46
+ trailer.total_status_code_df = status_code_count['11']
47
+ trailer.total_status_code_df = status_code_count['13']
48
+ trailer.total_status_code_df = status_code_count['61']
49
+ trailer.total_status_code_df = status_code_count['62']
50
+ trailer.total_status_code_df = status_code_count['63']
51
+ trailer.total_status_code_df = status_code_count['64']
52
+ trailer.total_status_code_df = status_code_count['65']
53
+ trailer.total_status_code_df = status_code_count['71']
54
+ trailer.total_status_code_df = status_code_count['78']
55
+ trailer.total_status_code_df = status_code_count['80']
56
+ trailer.total_status_code_df = status_code_count['82']
57
+ trailer.total_status_code_df = status_code_count['83']
58
+ trailer.total_status_code_df = status_code_count['84']
59
+ trailer.total_status_code_df = status_code_count['88']
60
+ trailer.total_status_code_df = status_code_count['89']
61
+ trailer.total_status_code_df = status_code_count['93']
62
+ trailer.total_status_code_df = status_code_count['94']
63
+ trailer.total_status_code_df = status_code_count['95']
64
+ trailer.total_status_code_df = status_code_count['96']
65
+ trailer.total_status_code_df = status_code_count['97']
66
+ trailer.ecoa_code_z = num_ecoa_code_z
67
+ trailer.total_social_security_numbers = num_ssn
68
+ trailer.total_social_security_numbers_in_base = num_ssn
69
+ trailer.total_date_of_births = num_dob
70
+ trailer.total_date_of_births_in_base = num_dob
71
+ trailer.total_telephome_numbers = num_telephone
72
+ trailer
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,54 @@
1
+ module Metro2::Records
2
+ class BaseSegment < Record
3
+ @fields = []
4
+
5
+ numeric_const_field :record_descriptor_word, 4, Metro2::FIXED_LENGTH
6
+ alphanumeric_const_field :processing_indicator, 1, 1 # always 1
7
+ timestamp_field :time_stamp
8
+ numeric_field :correction_indicator, 1
9
+ alphanumeric_field :identification_number, 20
10
+ alphanumeric_field :cycle_number, 2
11
+ alphanumeric_field :consumer_account_number, 30
12
+ alphanumeric_field :portfolio_type, 1
13
+ alphanumeric_field :account_type, 2
14
+ date_field :date_opened
15
+ monetary_field :credit_limit
16
+ monetary_field :highest_credit_or_loan_amount
17
+ alphanumeric_field :terms_duration, 3
18
+ alphanumeric_field :terms_frequency, 1
19
+ monetary_field :scheduled_monthly_payment_amount
20
+ monetary_field :actual_payment_amount
21
+ alphanumeric_field :account_status, 2
22
+ alphanumeric_field :payment_rating, 1
23
+ alphanumeric_field :payment_history_profile, 24
24
+ alphanumeric_field :special_comment, 2
25
+ alphanumeric_field :compliance_condition_code, 2
26
+ monetary_field :current_balance
27
+ monetary_field :amount_past_due
28
+ monetary_field :original_charge_off_amount
29
+ date_field :account_information_date
30
+ date_field :first_delinquency_date
31
+ date_field :closed_date
32
+ date_field :last_payment_date
33
+ alphanumeric_field :interest_type_indicator, 1
34
+ alphanumeric_const_field :reserved, 16, nil # reserved - blank fill
35
+ alphanumeric_field :consumer_transaction_type, 1
36
+ alphanumeric_field :surname, 25, Metro2::ALPHANUMERIC_PLUS_DASH
37
+ alphanumeric_field :first_name, 20, Metro2::ALPHANUMERIC_PLUS_DASH
38
+ alphanumeric_field :middle_name, 20, Metro2::ALPHANUMERIC_PLUS_DASH
39
+ alphanumeric_field :generation_code, 1
40
+ numeric_field :social_security_number, 9
41
+ date_field :date_of_birth
42
+ numeric_field :telephone_number, 10
43
+ alphanumeric_field :ecoa_code, 1
44
+ alphanumeric_field :consumer_information_indicator, 2
45
+ alphanumeric_field :country_code, 2
46
+ alphanumeric_field :address_1, 32, Metro2::ALPHANUMERIC_PLUS_DOT_DASH_SLASH
47
+ alphanumeric_field :address_2, 32, Metro2::ALPHANUMERIC_PLUS_DOT_DASH_SLASH
48
+ alphanumeric_field :city, 20
49
+ alphanumeric_field :state, 2
50
+ alphanumeric_field :postal_code, 9
51
+ alphanumeric_field :address_indicator, 1
52
+ alphanumeric_field :residence_code, 1
53
+ end
54
+ end
@@ -0,0 +1,23 @@
1
+ module Metro2::Records
2
+ class HeaderSegment < Record
3
+ @fields = []
4
+
5
+ numeric_const_field :record_descriptor_word, 4, Metro2::FIXED_LENGTH
6
+ alphanumeric_const_field :record_identifier, 6, 'HEADER'
7
+ alphanumeric_field :cycle_number, 2
8
+ alphanumeric_field :innovis_program_identifier, 10
9
+ alphanumeric_field :equifax_program_identifier, 10
10
+ alphanumeric_field :experian_program_identifier, 5
11
+ alphanumeric_field :transunion_program_identifier, 10
12
+ date_field :activity_date
13
+ date_field :created_date
14
+ date_field :program_date
15
+ numeric_field :program_revision_date, 8
16
+ alphanumeric_field :reporter_name, 40
17
+ alphanumeric_field :reporter_address, 96, Metro2::ALPHANUMERIC_PLUS_DOT_DASH_SLASH
18
+ numeric_field :reporter_telephone_number, 10
19
+ alphanumeric_const_field :software_vendor_name, 40, 'Upstart Engineer metro 2 gem'
20
+ alphanumeric_const_field :software_version_number, 5, Metro2::version_string
21
+ alphanumeric_const_field :reserved, 156, nil
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ module Metro2
2
+ module Records
3
+ class Record
4
+ @fields = []
5
+
6
+ class << self
7
+ def fields
8
+ @fields
9
+ end
10
+ end
11
+
12
+ extend(Fields)
13
+
14
+ def to_metro2
15
+ self.class.fields.collect { |f| send("#{f}_to_metro2") }.join
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,53 @@
1
+ module Metro2::Records
2
+ class TrailerSegment < Record
3
+ @fields = []
4
+
5
+ numeric_const_field :record_descriptor_word, 4, Metro2::FIXED_LENGTH
6
+ alphanumeric_const_field :record_identifier, 7, 'TRAILER'
7
+ numeric_field :total_base_records, 9
8
+ alphanumeric_const_field :reserved, 9, nil
9
+ numeric_field :total_status_code_df, 9
10
+ numeric_field :total_j1_segments, 9
11
+ numeric_field :total_j2_segments, 9
12
+ numeric_field :block_count, 9
13
+ numeric_field :total_status_code_da, 9
14
+ numeric_field :total_status_code_05, 9
15
+ numeric_field :total_status_code_11, 9
16
+ numeric_field :total_status_code_13, 9
17
+ numeric_field :total_status_code_61, 9
18
+ numeric_field :total_status_code_62, 9
19
+ numeric_field :total_status_code_63, 9
20
+ numeric_field :total_status_code_64, 9
21
+ numeric_field :total_status_code_65, 9
22
+ numeric_field :total_status_code_71, 9
23
+ numeric_field :total_status_code_78, 9
24
+ numeric_field :total_status_code_80, 9
25
+ numeric_field :total_status_code_82, 9
26
+ numeric_field :total_status_code_83, 9
27
+ numeric_field :total_status_code_84, 9
28
+ numeric_field :total_status_code_88, 9
29
+ numeric_field :total_status_code_89, 9
30
+ numeric_field :total_status_code_93, 9
31
+ numeric_field :total_status_code_94, 9
32
+ numeric_field :total_status_code_95, 9
33
+ numeric_field :total_status_code_96, 9
34
+ numeric_field :total_status_code_97, 9
35
+ numeric_field :ecoa_code_z, 9
36
+ numeric_field :total_n1_segments, 9
37
+ numeric_field :total_k1_segments, 9
38
+ numeric_field :total_k2_segments, 9
39
+ numeric_field :total_k3_segments, 9
40
+ numeric_field :total_k4_segments, 9
41
+ numeric_field :total_l1_segments, 9
42
+ numeric_field :total_social_security_numbers, 9
43
+ numeric_field :total_social_security_numbers_in_base, 9
44
+ numeric_field :total_social_security_numbers_in_j1, 9
45
+ numeric_field :total_social_security_numbers_in_j2, 9
46
+ numeric_field :total_date_of_births, 9
47
+ numeric_field :total_date_of_births_in_base, 9
48
+ numeric_field :total_date_of_births_in_j1, 9
49
+ numeric_field :total_date_of_births_in_j2, 9
50
+ numeric_field :total_telephome_numbers, 9
51
+ alphanumeric_const_field :reserved_2, 19, nil
52
+ end
53
+ end
@@ -0,0 +1,8 @@
1
+ module Metro2
2
+ VERSION = "1.0.0"
3
+
4
+ def self.version_string
5
+ str = VERSION.split('.')
6
+ str[0].rjust(2, '0') + str[1].ljust(2, '0') + str[2]
7
+ end
8
+ end
data/metro_2.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'metro_2/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "metro_2"
8
+ spec.version = Metro2::VERSION
9
+ spec.authors = ["Brian Mascarenhas"]
10
+ spec.email = ["brian@upstart.com"]
11
+ spec.summary = "Create Metro 2 format files for credit reporting"
12
+ spec.description = "Create Metro 2 format files for credit reporting"
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rspec", "~> 2.13"
24
+ end
@@ -0,0 +1,160 @@
1
+ require 'spec_helper'
2
+
3
+ describe Metro2::Records::BaseSegment do
4
+ before do
5
+ @base = Metro2::Records::BaseSegment.new
6
+ @base.time_stamp = Time.new(2014, 9, 15, 17, 7, 45)
7
+ @base.identification_number = 'REPORTERXYZ'
8
+ @base.cycle_number = 1
9
+ @base.consumer_account_number = 'ABC123'
10
+ @base.portfolio_type = 'I'
11
+ @base.account_type = '01'
12
+ @base.date_opened = Date.new(2013, 4, 1)
13
+ @base.highest_credit_or_loan_amount = 25000
14
+ @base.terms_duration = 36
15
+ @base.terms_frequency = 'M'
16
+ @base.scheduled_monthly_payment_amount = 817.8
17
+ @base.actual_payment_amount = 817.8
18
+ @base.account_status = '11'
19
+ @base.payment_history_profile = '00000000000000000BBBBBBB'
20
+ @base.current_balance = 11111
21
+ @base.account_information_date = Date.new(2014, 9, 1)
22
+ @base.last_payment_date = Date.new(2014, 8, 1)
23
+ @base.interest_type_indicator = 'F'
24
+ @base.surname = 'Simpson'
25
+ @base.first_name = 'Homer'
26
+ @base.middle_name = 'Jay'
27
+ @base.social_security_number = '333224444'
28
+ @base.date_of_birth = Date.new(1987, 4, 19)
29
+ @base.telephone_number = '5555555555'
30
+ @base.ecoa_code = 1
31
+ @base.country_code = 'US'
32
+ @base.address_1 = '742 Evergreen Terrace'
33
+ @base.city = 'Springfield'
34
+ @base.state = 'IL'
35
+ @base.postal_code = '54321'
36
+ @base.address_indicator = 'N'
37
+ @base.residence_code = 'O'
38
+ end
39
+
40
+ context '#to_metro2' do
41
+ it 'should generate base segment string' do
42
+ exp = [
43
+ '0426',
44
+ '1',
45
+ '09152014170745',
46
+ '0',
47
+ 'REPORTERXYZ'.ljust(20, ' '),
48
+ '1 ',
49
+ 'ABC123'.ljust(30, ' '),
50
+ 'I',
51
+ '01',
52
+ '04012013',
53
+ '0' * 9,
54
+ '000025000',
55
+ '36 ',
56
+ 'M',
57
+ '000000817',
58
+ '000000817',
59
+ '11',
60
+ ' ',
61
+ '00000000000000000BBBBBBB',
62
+ ' ',
63
+ ' ',
64
+ '000011111',
65
+ '000000000',
66
+ '000000000',
67
+ '09012014',
68
+ '00000000',
69
+ '00000000',
70
+ '08012014',
71
+ 'F',
72
+ ' ' * 16,
73
+ ' ',
74
+ 'Simpson'.ljust(25, ' '),
75
+ 'Homer'.ljust(20, ' '),
76
+ 'Jay'.ljust(20, ' '),
77
+ ' ',
78
+ '333224444',
79
+ '04191987',
80
+ '5555555555',
81
+ '1',
82
+ ' ',
83
+ 'US',
84
+ '742 Evergreen Terrace'.ljust(32, ' '),
85
+ ' ' * 32,
86
+ 'Springfield'.ljust(20, ' '),
87
+ 'IL',
88
+ '54321 ',
89
+ 'N',
90
+ 'O',
91
+ ''
92
+ ]
93
+ base_str = @base.to_metro2
94
+ expect(base_str).to eql(exp.join(''))
95
+ expect(base_str.size).to eql(Metro2::FIXED_LENGTH)
96
+ end
97
+ end
98
+
99
+ context 'alphanumerics' do
100
+ describe 'alphanumeric with symbols' do
101
+ it 'should raise an error' do
102
+ @base.surname = 'B@d name'
103
+ expect{@base.surname_to_metro2}.to raise_error(ArgumentError)
104
+ end
105
+ end
106
+
107
+ describe 'alphanumeric with dashes' do
108
+ it 'should not raise an error' do
109
+ @base.surname = 'Name A-ok'
110
+ expect{@base.surname_to_metro2}.not_to raise_error
111
+ end
112
+ end
113
+
114
+ describe 'really long alphanumeric' do
115
+ it 'should be truncated' do
116
+ @base.surname = 'Veryveryveryveryverylongname'
117
+ expect(@base.surname_to_metro2).to eql('Veryveryveryveryverylongn')
118
+ end
119
+ end
120
+
121
+ describe 'alphanumeric with dots and slashes' do
122
+ it 'should be truncated' do
123
+ @base.address_1 = 'Test Address /1.'
124
+ expect(@base.address_1_to_metro2).to eql('Test Address /1.'.ljust(32, ' '))
125
+ end
126
+ end
127
+ end
128
+
129
+ context 'numerics' do
130
+ describe 'numeric with alphas' do
131
+ it 'should raise an error' do
132
+ @base.telephone_number = 'abc5555555'
133
+ expect{@base.telephone_number_to_metro2}.to raise_error(ArgumentError)
134
+ end
135
+ end
136
+
137
+ describe 'numeric with symbols' do
138
+ it 'should raise an error' do
139
+ @base.telephone_number = '+555555555'
140
+ expect{@base.telephone_number_to_metro2}.to raise_error(ArgumentError)
141
+ end
142
+ end
143
+
144
+ describe 'numeric that is too long' do
145
+ it 'should raise an error' do
146
+ @base.telephone_number = '12345678901'
147
+ expect{@base.telephone_number_to_metro2}.to raise_error(ArgumentError)
148
+ end
149
+ end
150
+ end
151
+
152
+ context 'monetary field' do
153
+ describe 'more than one billion' do
154
+ it 'should fill with all 9s' do
155
+ @base.credit_limit = '1000000001'
156
+ expect(@base.credit_limit_to_metro2).to eql('999999999')
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ describe Metro2::Records::HeaderSegment do
4
+ before(:each) do
5
+ @header = Metro2::Records::HeaderSegment.new
6
+ @header.cycle_number = 15
7
+ @header.equifax_program_identifier = 'EFAXID'
8
+ @header.transunion_program_identifier = 'TRANSUNION'
9
+ @header.activity_date = Date.new(2014,9,14)
10
+ @header.created_date = Date.new(2014,9,15)
11
+ @header.program_date = Date.new(2014,9,1)
12
+ @header.program_revision_date = '01'
13
+ @header.reporter_name = 'Credit Reporter'
14
+ @header.reporter_address = '123 Report Dr Address CA 91111'
15
+ @header.reporter_telephone_number = '5555555555'
16
+ end
17
+
18
+ describe '#to_metro2' do
19
+ it 'should generate header segment string' do
20
+ exp = [
21
+ '0426',
22
+ 'HEADER',
23
+ '15',
24
+ ' ',
25
+ 'EFAXID ',
26
+ ' ',
27
+ 'TRANSUNION',
28
+ '09142014',
29
+ '09152014',
30
+ '09012014',
31
+ '00000001',
32
+ 'Credit Reporter'.ljust(40, ' '),
33
+ '123 Report Dr Address CA 91111'.ljust(96, ' '),
34
+ '5555555555',
35
+ 'Upstart Engineer metro 2 gem'.ljust(40, ' '),
36
+ '01000',
37
+ ' ' * 156
38
+ ]
39
+ header_str = @header.to_metro2
40
+ expect(header_str).to eql(exp.join(''))
41
+ expect(header_str.size).to eql(Metro2::FIXED_LENGTH)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ describe Metro2::Records::TrailerSegment do
4
+ before(:each) do
5
+ @trailer = Metro2::Records::TrailerSegment.new
6
+ @trailer.total_base_records = 1
7
+ @trailer.total_status_code_11 = 1
8
+ @trailer.total_social_security_numbers = 1
9
+ @trailer.total_social_security_numbers_in_base = 1
10
+ @trailer.total_date_of_births = 1
11
+ @trailer.total_date_of_births_in_base = 1
12
+ @trailer.total_telephome_numbers = 1
13
+ end
14
+
15
+ describe '#to_metro2' do
16
+ it 'should generate trailer segment string' do
17
+ exp = [
18
+ '0426',
19
+ 'TRAILER',
20
+ '000000001',
21
+ ' ' * 9,
22
+ '0' * 9,
23
+ '0' * 9,
24
+ '0' * 9,
25
+ '0' * 9,
26
+ '0' * 9,
27
+ '0' * 9,
28
+ '000000001',
29
+ '0' * 9,
30
+ '0' * 9,
31
+ '0' * 9,
32
+ '0' * 9,
33
+ '0' * 9,
34
+ '0' * 9,
35
+ '0' * 9,
36
+ '0' * 9,
37
+ '0' * 9,
38
+ '0' * 9,
39
+ '0' * 9,
40
+ '0' * 9,
41
+ '0' * 9,
42
+ '0' * 9,
43
+ '0' * 9,
44
+ '0' * 9,
45
+ '0' * 9,
46
+ '0' * 9,
47
+ '0' * 9,
48
+ '0' * 9,
49
+ '0' * 9,
50
+ '0' * 9,
51
+ '0' * 9,
52
+ '0' * 9,
53
+ '0' * 9,
54
+ '0' * 9,
55
+ '000000001',
56
+ '000000001',
57
+ '0' * 9,
58
+ '0' * 9,
59
+ '000000001',
60
+ '000000001',
61
+ '0' * 9,
62
+ '0' * 9,
63
+ '000000001',
64
+ ' ' * 19
65
+ ]
66
+ trailer_str = @trailer.to_metro2
67
+ expect(trailer_str).to eql(exp.join(''))
68
+ expect(trailer_str.size).to eql(Metro2::FIXED_LENGTH)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,8 @@
1
+ require 'bundler/setup'
2
+ Bundler.require
3
+
4
+ require 'metro_2'
5
+
6
+ RSpec.configure do |config|
7
+ # some (optional) config here
8
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: metro_2
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Brian Mascarenhas
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.13'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.13'
55
+ description: Create Metro 2 format files for credit reporting
56
+ email:
57
+ - brian@upstart.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".rspec"
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - lib/metro_2.rb
69
+ - lib/metro_2/fields.rb
70
+ - lib/metro_2/metro2_file.rb
71
+ - lib/metro_2/records/base_segment.rb
72
+ - lib/metro_2/records/header_segment.rb
73
+ - lib/metro_2/records/record.rb
74
+ - lib/metro_2/records/trailer_segment.rb
75
+ - lib/metro_2/version.rb
76
+ - metro_2.gemspec
77
+ - spec/records/base_segment_spec.rb
78
+ - spec/records/header_segment_spec.rb
79
+ - spec/records/trailer_segment_spec.rb
80
+ - spec/spec_helper.rb
81
+ homepage: ''
82
+ licenses:
83
+ - MIT
84
+ metadata: {}
85
+ post_install_message:
86
+ rdoc_options: []
87
+ require_paths:
88
+ - lib
89
+ required_ruby_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ required_rubygems_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubyforge_project:
101
+ rubygems_version: 2.4.1
102
+ signing_key:
103
+ specification_version: 4
104
+ summary: Create Metro 2 format files for credit reporting
105
+ test_files:
106
+ - spec/records/base_segment_spec.rb
107
+ - spec/records/header_segment_spec.rb
108
+ - spec/records/trailer_segment_spec.rb
109
+ - spec/spec_helper.rb