ssn_validator 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/History.txt +41 -0
- data/LICENSE +20 -0
- data/PostInstall.txt +29 -0
- data/README.rdoc +98 -0
- data/Rakefile +60 -0
- data/VERSION.yml +5 -0
- data/generators/death_master_file_migration/death_master_file_migration_generator.rb +12 -0
- data/generators/death_master_file_migration/templates/migration.rb +26 -0
- data/generators/ssn_validator_migration/ssn_validator_migration_generator.rb +12 -0
- data/generators/ssn_validator_migration/templates/migration.rb +18 -0
- data/lib/ssn_validator.rb +12 -0
- data/lib/ssn_validator/models/death_master_file.rb +5 -0
- data/lib/ssn_validator/models/death_master_file_loader.rb +235 -0
- data/lib/ssn_validator/models/ssn_high_group_code.rb +5 -0
- data/lib/ssn_validator/models/ssn_high_group_code_loader.rb +87 -0
- data/lib/ssn_validator/models/ssn_validator.rb +94 -0
- data/lib/ssn_validator/ntis.rb +9 -0
- data/lib/tasks/ssn_validator.rake +24 -0
- data/rdoc/classes/DeathMasterFile.html +111 -0
- data/rdoc/classes/DeathMasterFileLoader.html +298 -0
- data/rdoc/classes/SsnHighGroupCode.html +111 -0
- data/rdoc/classes/SsnHighGroupCodeLoader.html +202 -0
- data/rdoc/classes/SsnValidator.html +116 -0
- data/rdoc/classes/SsnValidator/Ntis.html +111 -0
- data/rdoc/classes/SsnValidator/Ssn.html +315 -0
- data/rdoc/created.rid +1 -0
- data/rdoc/files/LICENSE.html +129 -0
- data/rdoc/files/README_rdoc.html +262 -0
- data/rdoc/files/lib/ssn_validator/models/death_master_file_loader_rb.html +112 -0
- data/rdoc/files/lib/ssn_validator/models/death_master_file_rb.html +108 -0
- data/rdoc/files/lib/ssn_validator/models/ssn_high_group_code_loader_rb.html +108 -0
- data/rdoc/files/lib/ssn_validator/models/ssn_high_group_code_rb.html +108 -0
- data/rdoc/files/lib/ssn_validator/models/ssn_validator_rb.html +101 -0
- data/rdoc/files/lib/ssn_validator/ntis_rb.html +101 -0
- data/rdoc/files/lib/ssn_validator_rb.html +113 -0
- data/rdoc/fr_class_index.html +33 -0
- data/rdoc/fr_file_index.html +35 -0
- data/rdoc/fr_method_index.html +37 -0
- data/rdoc/index.html +24 -0
- data/rdoc/rdoc-style.css +208 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/ssn_validator.gemspec +130 -0
- data/test/files/test_dmf_funky_data_load.txt +6 -0
- data/test/files/test_dmf_initial_load.txt +5 -0
- data/test/files/test_dmf_update_load.txt +5 -0
- data/test/files/valid_csv_from_funky_data_file.txt +6 -0
- data/test/mocks/test/death_master_file_loader.rb +40 -0
- data/test/test_death_master_file_loader.rb +113 -0
- data/test/test_helper.rb +62 -0
- data/test/test_ssn_high_group_code_loader.rb +22 -0
- data/test/test_ssn_validator.rb +85 -0
- metadata +145 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
|
2
|
+
require 'net/http'
|
3
|
+
class SsnHighGroupCodeLoader
|
4
|
+
def self.load_all_high_group_codes_files
|
5
|
+
months = ['Jan','Feb','Mar','Apr','May','June','July','Aug','Sept','Oct','Nov','Dec']
|
6
|
+
run_file_date = SsnHighGroupCode.maximum(:as_of)
|
7
|
+
run_file_date = run_file_date ? run_file_date.next_month.beginning_of_month : Date.new(2003,11,01)
|
8
|
+
last_file_date = Date.today.beginning_of_month
|
9
|
+
while run_file_date <= last_file_date
|
10
|
+
file_processed = false
|
11
|
+
run_file_month = months[run_file_date.month - 1]
|
12
|
+
run_file_year = run_file_date.year
|
13
|
+
['','corrected'].each do |mod|
|
14
|
+
break if file_processed
|
15
|
+
['ssns','ssnvs'].each do |url_mod|
|
16
|
+
break if file_processed
|
17
|
+
(1..Date.today.day).each do |day|
|
18
|
+
string_day = day.to_s
|
19
|
+
string_day.insert(0,'0') if day < 10
|
20
|
+
string_year = run_file_year.to_s.last(2)
|
21
|
+
file_name = "HG#{run_file_month}#{string_day}#{string_year}#{mod}.txt"
|
22
|
+
text = Net::HTTP.get(URI.parse("http://www.socialsecurity.gov/employer/#{url_mod}/#{file_name}"))
|
23
|
+
unless text.include? 'File Not Found'
|
24
|
+
create_records(parse_text(text),extract_as_of_date(text))
|
25
|
+
run_file_date = run_file_date.next_month
|
26
|
+
file_processed = true
|
27
|
+
break
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
#Loads the most recent file from http://www.socialsecurity.gov/employer/ssns/highgroup.txt
|
36
|
+
def self.load_current_high_group_codes_file
|
37
|
+
text = Net::HTTP.get(URI.parse('http://www.socialsecurity.gov/employer/ssns/highgroup.txt'))
|
38
|
+
create_records(parse_text(text),extract_as_of_date(text))
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def self.already_loaded?(file_as_of_date)
|
45
|
+
SsnHighGroupCode.find_by_as_of(file_as_of_date)
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.create_records(area_groups,file_as_of)
|
49
|
+
if already_loaded?(file_as_of)
|
50
|
+
puts "File as of #{file_as_of} has already been loaded."
|
51
|
+
else
|
52
|
+
area_groups.each do |area_group|
|
53
|
+
SsnHighGroupCode.create(area_group.merge!(:as_of => file_as_of.to_s(:db)))
|
54
|
+
end
|
55
|
+
puts "File as of #{file_as_of} loaded."
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
#extract the date from the file in the format mm/dd/yy
|
60
|
+
def self.extract_as_of_date(text)
|
61
|
+
as_of_start_index = text =~ /\d\d\/\d\d\/\d\d/
|
62
|
+
Date.strptime($&,'%m/%d/%y') unless as_of_start_index.nil?
|
63
|
+
end
|
64
|
+
|
65
|
+
#The formatting of the file is a little bit messy. Sometimes tabs are
|
66
|
+
#used as delimiters and sometimes spaces are used as delimiters. Also, the asterisks indicating recent changes are not
|
67
|
+
#necessary for our purposes
|
68
|
+
#Returns an array of hashes.
|
69
|
+
def self.parse_text(text)
|
70
|
+
text.gsub!('*',' ')
|
71
|
+
text.gsub!(/\t/, ' ')
|
72
|
+
text_array = text.split(/\n/).compact
|
73
|
+
area_groups = []
|
74
|
+
text_array.each do |t|
|
75
|
+
t.gsub!(/\s+/,' ')
|
76
|
+
next if t =~ /[[:alpha:]]/ #skip over the header lines
|
77
|
+
|
78
|
+
if t =~ /\d\d\d \d\d/ #we want the lines with area group pairs
|
79
|
+
t.gsub(/\d\d\d \d\d/) do |s|
|
80
|
+
area_group = s.split(' ')
|
81
|
+
area_groups << {:area => area_group.first, :group => area_group.last}
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
return area_groups
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module SsnValidator
|
2
|
+
class Ssn
|
3
|
+
|
4
|
+
attr_reader :ssn,:area,:group,:serial_number,:as_of
|
5
|
+
attr_reader :errors
|
6
|
+
|
7
|
+
|
8
|
+
#Instantiate the object passing in a social security number.
|
9
|
+
#The ssn can be a string or integer, with or without the '-'s.
|
10
|
+
def initialize(ssn)
|
11
|
+
@errors = []
|
12
|
+
ssn = ssn.to_s
|
13
|
+
if ssn =~ /-/ && ssn !~ /\d\d\d-\d\d-\d\d\d\d/
|
14
|
+
@errors << 'Hyphen misplaced.'
|
15
|
+
end
|
16
|
+
|
17
|
+
ssn.gsub!('-','')
|
18
|
+
if ssn.to_s.size != 9
|
19
|
+
@errors << 'SSN not 9 digits long.'
|
20
|
+
end
|
21
|
+
|
22
|
+
if ssn =~ /\D/
|
23
|
+
@errors << 'Non-digit found.'
|
24
|
+
end
|
25
|
+
|
26
|
+
#known dummy numbers
|
27
|
+
if ["078051120","111111111","123456789","219099999","999999999"].include? ssn || (ssn >= "987654320" and ssn <= "987654329")
|
28
|
+
@errors << "Known dummy SSN."
|
29
|
+
end
|
30
|
+
#known invalid area, group and serial numbers
|
31
|
+
if ssn =~ /\d{3}00\d{4}|0000\Z/
|
32
|
+
@errors << "Invalid group or serial number."
|
33
|
+
end
|
34
|
+
|
35
|
+
@ssn = ssn
|
36
|
+
@area = ssn.first(3)
|
37
|
+
@group = ssn[3,2]
|
38
|
+
@serial_number = ssn.last(4)
|
39
|
+
|
40
|
+
if @errors.empty?
|
41
|
+
@ssn_high_group_code = SsnHighGroupCode.find_by_area(@area, :order => 'as_of desc')
|
42
|
+
if @ssn_high_group_code.nil?
|
43
|
+
@errors << "Area '#{@area}' has not been assigned."
|
44
|
+
else
|
45
|
+
@as_of = @ssn_high_group_code.as_of
|
46
|
+
|
47
|
+
define_group_ranks
|
48
|
+
|
49
|
+
if @group_ranks[@group] > @group_ranks[@ssn_high_group_code.group]
|
50
|
+
@errors << "Group '#{@group}' has not been assigned yet for area '#{@area}'"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
#Determines whether or not the passed in
|
59
|
+
#ssn passed all validations.
|
60
|
+
def valid?
|
61
|
+
@errors.empty?
|
62
|
+
end
|
63
|
+
|
64
|
+
#returns the death master record if there is one.
|
65
|
+
def death_master_file_record
|
66
|
+
DeathMasterFile.find_by_social_security_number(@ssn)
|
67
|
+
end
|
68
|
+
|
69
|
+
#Determines if the passed in ssn belongs to the deceased.
|
70
|
+
def death_master_file_hit?
|
71
|
+
!death_master_file_record.nil?
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def define_group_ranks
|
78
|
+
@group_ranks = {}
|
79
|
+
rank = 0
|
80
|
+
(1..9).step(2) do |group|
|
81
|
+
@group_ranks.merge!("0#{group.to_s}" => rank += 1)
|
82
|
+
end
|
83
|
+
(10..98).step(2) do |group|
|
84
|
+
@group_ranks.merge!(group.to_s => rank += 1)
|
85
|
+
end
|
86
|
+
(2..8).step(2) do |group|
|
87
|
+
@group_ranks.merge!("0#{group.to_s}" => rank += 1)
|
88
|
+
end
|
89
|
+
(11..99).step(2) do |group|
|
90
|
+
@group_ranks.merge!(group.to_s => rank += 1)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
|
2
|
+
namespace :ssn_validator do
|
3
|
+
desc "Loads the current file from http://www.socialsecurity.gov/employer/ssns/highgroup.txt if it hasn't already been loaded."
|
4
|
+
task :update_data => :environment do
|
5
|
+
SsnHighGroupCodeLoader.load_all_high_group_codes_files
|
6
|
+
end
|
7
|
+
|
8
|
+
namespace :death_master_file do
|
9
|
+
desc "Loads a death master file. Specify the path of the file: PATH=path. Specify the date of the data: AS_OF=YYYY-MM-DD. Optimized for Mysql databases."
|
10
|
+
task :load_file => :environment do
|
11
|
+
if ENV["PATH"] && ENV["AS_OF"]
|
12
|
+
DeathMasterFileLoader.new(ENV["PATH"],ENV["AS_OF"]).load_file
|
13
|
+
else
|
14
|
+
puts "You must specify the PATH and AS_OF variables: rake ssn_validator:death_master_file:load_file PATH='path/to/file' AS_OF='2009-03-01'"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Determines the most recent file that has been loaded, and loads all subsequent files in order from the dmf.ntis.gov website. Optimized for Mysql databases."
|
19
|
+
task :update_data => :environment do
|
20
|
+
DeathMasterFileLoader.load_update_files_from_web
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
2
|
+
<!DOCTYPE html
|
3
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
4
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
5
|
+
|
6
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
7
|
+
<head>
|
8
|
+
<title>Class: DeathMasterFile</title>
|
9
|
+
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
10
|
+
<meta http-equiv="Content-Script-Type" content="text/javascript" />
|
11
|
+
<link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
|
12
|
+
<script type="text/javascript">
|
13
|
+
// <![CDATA[
|
14
|
+
|
15
|
+
function popupCode( url ) {
|
16
|
+
window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
|
17
|
+
}
|
18
|
+
|
19
|
+
function toggleCode( id ) {
|
20
|
+
if ( document.getElementById )
|
21
|
+
elem = document.getElementById( id );
|
22
|
+
else if ( document.all )
|
23
|
+
elem = eval( "document.all." + id );
|
24
|
+
else
|
25
|
+
return false;
|
26
|
+
|
27
|
+
elemStyle = elem.style;
|
28
|
+
|
29
|
+
if ( elemStyle.display != "block" ) {
|
30
|
+
elemStyle.display = "block"
|
31
|
+
} else {
|
32
|
+
elemStyle.display = "none"
|
33
|
+
}
|
34
|
+
|
35
|
+
return true;
|
36
|
+
}
|
37
|
+
|
38
|
+
// Make codeblocks hidden by default
|
39
|
+
document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
|
40
|
+
|
41
|
+
// ]]>
|
42
|
+
</script>
|
43
|
+
|
44
|
+
</head>
|
45
|
+
<body>
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
<div id="classHeader">
|
50
|
+
<table class="header-table">
|
51
|
+
<tr class="top-aligned-row">
|
52
|
+
<td><strong>Class</strong></td>
|
53
|
+
<td class="class-name-in-header">DeathMasterFile</td>
|
54
|
+
</tr>
|
55
|
+
<tr class="top-aligned-row">
|
56
|
+
<td><strong>In:</strong></td>
|
57
|
+
<td>
|
58
|
+
<a href="../files/lib/ssn_validator/models/death_master_file_rb.html">
|
59
|
+
lib/ssn_validator/models/death_master_file.rb
|
60
|
+
</a>
|
61
|
+
<br />
|
62
|
+
</td>
|
63
|
+
</tr>
|
64
|
+
|
65
|
+
<tr class="top-aligned-row">
|
66
|
+
<td><strong>Parent:</strong></td>
|
67
|
+
<td>
|
68
|
+
ActiveRecord::Base
|
69
|
+
</td>
|
70
|
+
</tr>
|
71
|
+
</table>
|
72
|
+
</div>
|
73
|
+
<!-- banner header -->
|
74
|
+
|
75
|
+
<div id="bodyContent">
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
<div id="contextContent">
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
</div>
|
84
|
+
|
85
|
+
|
86
|
+
</div>
|
87
|
+
|
88
|
+
|
89
|
+
<!-- if includes -->
|
90
|
+
|
91
|
+
<div id="section">
|
92
|
+
|
93
|
+
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
|
100
|
+
<!-- if method_list -->
|
101
|
+
|
102
|
+
|
103
|
+
</div>
|
104
|
+
|
105
|
+
|
106
|
+
<div id="validator-badges">
|
107
|
+
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
|
108
|
+
</div>
|
109
|
+
|
110
|
+
</body>
|
111
|
+
</html>
|
@@ -0,0 +1,298 @@
|
|
1
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
2
|
+
<!DOCTYPE html
|
3
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
4
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
5
|
+
|
6
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
7
|
+
<head>
|
8
|
+
<title>Class: DeathMasterFileLoader</title>
|
9
|
+
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
10
|
+
<meta http-equiv="Content-Script-Type" content="text/javascript" />
|
11
|
+
<link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
|
12
|
+
<script type="text/javascript">
|
13
|
+
// <![CDATA[
|
14
|
+
|
15
|
+
function popupCode( url ) {
|
16
|
+
window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
|
17
|
+
}
|
18
|
+
|
19
|
+
function toggleCode( id ) {
|
20
|
+
if ( document.getElementById )
|
21
|
+
elem = document.getElementById( id );
|
22
|
+
else if ( document.all )
|
23
|
+
elem = eval( "document.all." + id );
|
24
|
+
else
|
25
|
+
return false;
|
26
|
+
|
27
|
+
elemStyle = elem.style;
|
28
|
+
|
29
|
+
if ( elemStyle.display != "block" ) {
|
30
|
+
elemStyle.display = "block"
|
31
|
+
} else {
|
32
|
+
elemStyle.display = "none"
|
33
|
+
}
|
34
|
+
|
35
|
+
return true;
|
36
|
+
}
|
37
|
+
|
38
|
+
// Make codeblocks hidden by default
|
39
|
+
document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
|
40
|
+
|
41
|
+
// ]]>
|
42
|
+
</script>
|
43
|
+
|
44
|
+
</head>
|
45
|
+
<body>
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
<div id="classHeader">
|
50
|
+
<table class="header-table">
|
51
|
+
<tr class="top-aligned-row">
|
52
|
+
<td><strong>Class</strong></td>
|
53
|
+
<td class="class-name-in-header">DeathMasterFileLoader</td>
|
54
|
+
</tr>
|
55
|
+
<tr class="top-aligned-row">
|
56
|
+
<td><strong>In:</strong></td>
|
57
|
+
<td>
|
58
|
+
<a href="../files/lib/ssn_validator/models/death_master_file_loader_rb.html">
|
59
|
+
lib/ssn_validator/models/death_master_file_loader.rb
|
60
|
+
</a>
|
61
|
+
<br />
|
62
|
+
</td>
|
63
|
+
</tr>
|
64
|
+
|
65
|
+
<tr class="top-aligned-row">
|
66
|
+
<td><strong>Parent:</strong></td>
|
67
|
+
<td>
|
68
|
+
Object
|
69
|
+
</td>
|
70
|
+
</tr>
|
71
|
+
</table>
|
72
|
+
</div>
|
73
|
+
<!-- banner header -->
|
74
|
+
|
75
|
+
<div id="bodyContent">
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
<div id="contextContent">
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
</div>
|
84
|
+
|
85
|
+
<div id="method-list">
|
86
|
+
<h3 class="section-bar">Methods</h3>
|
87
|
+
|
88
|
+
<div class="name-list">
|
89
|
+
<a href="#M000006">get_file_from_web</a>
|
90
|
+
<a href="#M000005">load_file</a>
|
91
|
+
<a href="#M000007">load_update_files_from_web</a>
|
92
|
+
<a href="#M000003">new</a>
|
93
|
+
<a href="#M000004">valid?</a>
|
94
|
+
</div>
|
95
|
+
</div>
|
96
|
+
|
97
|
+
</div>
|
98
|
+
|
99
|
+
|
100
|
+
<!-- if includes -->
|
101
|
+
|
102
|
+
<div id="section">
|
103
|
+
|
104
|
+
|
105
|
+
|
106
|
+
|
107
|
+
|
108
|
+
|
109
|
+
|
110
|
+
|
111
|
+
<!-- if method_list -->
|
112
|
+
<div id="methods">
|
113
|
+
<h3 class="section-bar">Public Class methods</h3>
|
114
|
+
|
115
|
+
<div id="method-M000007" class="method-detail">
|
116
|
+
<a name="M000007"></a>
|
117
|
+
|
118
|
+
<div class="method-heading">
|
119
|
+
<a href="#M000007" class="method-signature">
|
120
|
+
<span class="method-name">load_update_files_from_web</span><span class="method-args">()</span>
|
121
|
+
</a>
|
122
|
+
</div>
|
123
|
+
|
124
|
+
<div class="method-description">
|
125
|
+
<p>
|
126
|
+
Loads all the update files from dmf.ntis.gov. It starts with the last file
|
127
|
+
loaded, and loads each missing file in sequence up to the current file.
|
128
|
+
</p>
|
129
|
+
<p><a class="source-toggle" href="#"
|
130
|
+
onclick="toggleCode('M000007-source');return false;">[Source]</a></p>
|
131
|
+
<div class="method-source-code" id="M000007-source">
|
132
|
+
<pre>
|
133
|
+
<span class="ruby-comment cmt"># File lib/ssn_validator/models/death_master_file_loader.rb, line 67</span>
|
134
|
+
<span class="ruby-keyword kw">def</span> <span class="ruby-keyword kw">self</span>.<span class="ruby-identifier">load_update_files_from_web</span>
|
135
|
+
<span class="ruby-identifier">max_as_of</span> = <span class="ruby-constant">DeathMasterFile</span>.<span class="ruby-identifier">maximum</span>(<span class="ruby-identifier">:as_of</span>)
|
136
|
+
<span class="ruby-identifier">run_file_date</span> = <span class="ruby-identifier">max_as_of</span>.<span class="ruby-identifier">beginning_of_month</span>.<span class="ruby-identifier">next_month</span>
|
137
|
+
<span class="ruby-identifier">last_file_date</span> = <span class="ruby-constant">Date</span>.<span class="ruby-identifier">today</span>.<span class="ruby-identifier">beginning_of_month</span>
|
138
|
+
<span class="ruby-keyword kw">while</span> <span class="ruby-identifier">run_file_date</span> <span class="ruby-operator"><=</span> <span class="ruby-identifier">last_file_date</span>
|
139
|
+
<span class="ruby-identifier">url</span> = <span class="ruby-node">"https://dmf.ntis.gov/dmldata/monthly/MA#{run_file_date.strftime("%y%m%d")}"</span>
|
140
|
+
<span class="ruby-identifier">puts</span> <span class="ruby-node">"Loading file #{url}"</span>
|
141
|
+
<span class="ruby-constant">DeathMasterFileLoader</span>.<span class="ruby-identifier">new</span>(<span class="ruby-identifier">url</span>,<span class="ruby-identifier">run_file_date</span>.<span class="ruby-identifier">strftime</span>(<span class="ruby-value str">"%Y-%m-%d"</span>)).<span class="ruby-identifier">load_file</span>
|
142
|
+
<span class="ruby-identifier">run_file_date</span> <span class="ruby-operator">+=</span> <span class="ruby-value">1</span>.<span class="ruby-identifier">month</span>
|
143
|
+
<span class="ruby-keyword kw">end</span>
|
144
|
+
<span class="ruby-keyword kw">end</span>
|
145
|
+
</pre>
|
146
|
+
</div>
|
147
|
+
</div>
|
148
|
+
</div>
|
149
|
+
|
150
|
+
<div id="method-M000003" class="method-detail">
|
151
|
+
<a name="M000003"></a>
|
152
|
+
|
153
|
+
<div class="method-heading">
|
154
|
+
<a href="#M000003" class="method-signature">
|
155
|
+
<span class="method-name">new</span><span class="method-args">(path_or_url,file_as_of)</span>
|
156
|
+
</a>
|
157
|
+
</div>
|
158
|
+
|
159
|
+
<div class="method-description">
|
160
|
+
<p>
|
161
|
+
path_or_url is the full path to the file to load on disk, or the url of an
|
162
|
+
update file. as_of is a string in the formatt YYYY-MM-DD for which the file
|
163
|
+
data is accurate.
|
164
|
+
</p>
|
165
|
+
<p><a class="source-toggle" href="#"
|
166
|
+
onclick="toggleCode('M000003-source');return false;">[Source]</a></p>
|
167
|
+
<div class="method-source-code" id="M000003-source">
|
168
|
+
<pre>
|
169
|
+
<span class="ruby-comment cmt"># File lib/ssn_validator/models/death_master_file_loader.rb, line 11</span>
|
170
|
+
<span class="ruby-keyword kw">def</span> <span class="ruby-identifier">initialize</span>(<span class="ruby-identifier">path_or_url</span>,<span class="ruby-identifier">file_as_of</span>)
|
171
|
+
<span class="ruby-ivar">@file_path_or_url</span> = <span class="ruby-identifier">path_or_url</span>
|
172
|
+
<span class="ruby-ivar">@file_as_of</span> = <span class="ruby-identifier">file_as_of</span>
|
173
|
+
<span class="ruby-identifier">valid?</span>
|
174
|
+
<span class="ruby-keyword kw">end</span>
|
175
|
+
</pre>
|
176
|
+
</div>
|
177
|
+
</div>
|
178
|
+
</div>
|
179
|
+
|
180
|
+
<h3 class="section-bar">Public Instance methods</h3>
|
181
|
+
|
182
|
+
<div id="method-M000006" class="method-detail">
|
183
|
+
<a name="M000006"></a>
|
184
|
+
|
185
|
+
<div class="method-heading">
|
186
|
+
<a href="#M000006" class="method-signature">
|
187
|
+
<span class="method-name">get_file_from_web</span><span class="method-args">()</span>
|
188
|
+
</a>
|
189
|
+
</div>
|
190
|
+
|
191
|
+
<div class="method-description">
|
192
|
+
<p><a class="source-toggle" href="#"
|
193
|
+
onclick="toggleCode('M000006-source');return false;">[Source]</a></p>
|
194
|
+
<div class="method-source-code" id="M000006-source">
|
195
|
+
<pre>
|
196
|
+
<span class="ruby-comment cmt"># File lib/ssn_validator/models/death_master_file_loader.rb, line 46</span>
|
197
|
+
<span class="ruby-keyword kw">def</span> <span class="ruby-identifier">get_file_from_web</span>
|
198
|
+
<span class="ruby-identifier">uri</span> = <span class="ruby-constant">URI</span>.<span class="ruby-identifier">parse</span>(<span class="ruby-ivar">@file_path_or_url</span>)
|
199
|
+
|
200
|
+
<span class="ruby-identifier">request</span> = <span class="ruby-constant">Net</span><span class="ruby-operator">::</span><span class="ruby-constant">HTTP</span><span class="ruby-operator">::</span><span class="ruby-constant">Get</span>.<span class="ruby-identifier">new</span>(<span class="ruby-identifier">uri</span>.<span class="ruby-identifier">request_uri</span>)
|
201
|
+
<span class="ruby-identifier">request</span>.<span class="ruby-identifier">basic_auth</span>(<span class="ruby-constant">SsnValidator</span><span class="ruby-operator">::</span><span class="ruby-constant">Ntis</span>.<span class="ruby-identifier">user_name</span>,<span class="ruby-constant">SsnValidator</span><span class="ruby-operator">::</span><span class="ruby-constant">Ntis</span>.<span class="ruby-identifier">password</span>)
|
202
|
+
|
203
|
+
<span class="ruby-identifier">http</span> = <span class="ruby-constant">Net</span><span class="ruby-operator">::</span><span class="ruby-constant">HTTP</span>.<span class="ruby-identifier">new</span>(<span class="ruby-identifier">uri</span>.<span class="ruby-identifier">host</span>, <span class="ruby-identifier">uri</span>.<span class="ruby-identifier">port</span>)
|
204
|
+
<span class="ruby-identifier">http</span>.<span class="ruby-identifier">use_ssl</span> = (<span class="ruby-identifier">uri</span>.<span class="ruby-identifier">port</span> <span class="ruby-operator">==</span> <span class="ruby-value">443</span>)
|
205
|
+
<span class="ruby-identifier">http</span>.<span class="ruby-identifier">verify_mode</span> = <span class="ruby-constant">OpenSSL</span><span class="ruby-operator">::</span><span class="ruby-constant">SSL</span><span class="ruby-operator">::</span><span class="ruby-constant">VERIFY_NONE</span>
|
206
|
+
|
207
|
+
<span class="ruby-identifier">response</span> = <span class="ruby-identifier">http</span>.<span class="ruby-identifier">request</span>(<span class="ruby-identifier">request</span>)
|
208
|
+
|
209
|
+
<span class="ruby-identifier">raise</span>(<span class="ruby-constant">ArgumentError</span>, <span class="ruby-node">"Invalid URL: #{@file_path_or_url}"</span>) <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">response</span>.<span class="ruby-identifier">kind_of?</span>(<span class="ruby-constant">Net</span><span class="ruby-operator">::</span><span class="ruby-constant">HTTPNotFound</span>)
|
210
|
+
<span class="ruby-identifier">raise</span>(<span class="ruby-constant">ArgumentError</span>, <span class="ruby-value str">"Authorization Required: Invalid username or password. Set the variables SsnValidator::Ntis.user_name and SsnValidator::Ntis.password in your environment.rb file."</span>) <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">response</span>.<span class="ruby-identifier">kind_of?</span>(<span class="ruby-constant">Net</span><span class="ruby-operator">::</span><span class="ruby-constant">HTTPUnauthorized</span>)
|
211
|
+
|
212
|
+
<span class="ruby-keyword kw">return</span> <span class="ruby-identifier">response</span>.<span class="ruby-identifier">body</span>
|
213
|
+
<span class="ruby-keyword kw">end</span>
|
214
|
+
</pre>
|
215
|
+
</div>
|
216
|
+
</div>
|
217
|
+
</div>
|
218
|
+
|
219
|
+
<div id="method-M000005" class="method-detail">
|
220
|
+
<a name="M000005"></a>
|
221
|
+
|
222
|
+
<div class="method-heading">
|
223
|
+
<a href="#M000005" class="method-signature">
|
224
|
+
<span class="method-name">load_file</span><span class="method-args">()</span>
|
225
|
+
</a>
|
226
|
+
</div>
|
227
|
+
|
228
|
+
<div class="method-description">
|
229
|
+
<p><a class="source-toggle" href="#"
|
230
|
+
onclick="toggleCode('M000005-source');return false;">[Source]</a></p>
|
231
|
+
<div class="method-source-code" id="M000005-source">
|
232
|
+
<pre>
|
233
|
+
<span class="ruby-comment cmt"># File lib/ssn_validator/models/death_master_file_loader.rb, line 32</span>
|
234
|
+
<span class="ruby-keyword kw">def</span> <span class="ruby-identifier">load_file</span>
|
235
|
+
|
236
|
+
<span class="ruby-keyword kw">if</span> <span class="ruby-constant">DeathMasterFile</span>.<span class="ruby-identifier">connection</span>.<span class="ruby-identifier">kind_of?</span>(<span class="ruby-constant">ActiveRecord</span><span class="ruby-operator">::</span><span class="ruby-constant">ConnectionAdapters</span><span class="ruby-operator">::</span><span class="ruby-constant">MysqlAdapter</span>)
|
237
|
+
<span class="ruby-identifier">puts</span> <span class="ruby-value str">"Converting file to csv format for Mysql import. This could take several minutes."</span>
|
238
|
+
|
239
|
+
<span class="ruby-identifier">csv_file</span> = <span class="ruby-identifier">convert_file_to_csv</span>
|
240
|
+
|
241
|
+
<span class="ruby-identifier">bulk_mysql_update</span>(<span class="ruby-identifier">csv_file</span>)
|
242
|
+
<span class="ruby-keyword kw">else</span>
|
243
|
+
<span class="ruby-identifier">active_record_file_load</span>
|
244
|
+
<span class="ruby-keyword kw">end</span>
|
245
|
+
|
246
|
+
<span class="ruby-keyword kw">end</span>
|
247
|
+
</pre>
|
248
|
+
</div>
|
249
|
+
</div>
|
250
|
+
</div>
|
251
|
+
|
252
|
+
<div id="method-M000004" class="method-detail">
|
253
|
+
<a name="M000004"></a>
|
254
|
+
|
255
|
+
<div class="method-heading">
|
256
|
+
<a href="#M000004" class="method-signature">
|
257
|
+
<span class="method-name">valid?</span><span class="method-args">()</span>
|
258
|
+
</a>
|
259
|
+
</div>
|
260
|
+
|
261
|
+
<div class="method-description">
|
262
|
+
<p><a class="source-toggle" href="#"
|
263
|
+
onclick="toggleCode('M000004-source');return false;">[Source]</a></p>
|
264
|
+
<div class="method-source-code" id="M000004-source">
|
265
|
+
<pre>
|
266
|
+
<span class="ruby-comment cmt"># File lib/ssn_validator/models/death_master_file_loader.rb, line 17</span>
|
267
|
+
<span class="ruby-keyword kw">def</span> <span class="ruby-identifier">valid?</span>
|
268
|
+
<span class="ruby-identifier">raise</span>(<span class="ruby-constant">ArgumentError</span>, <span class="ruby-value str">"path_or_url not specified"</span>) <span class="ruby-keyword kw">unless</span> <span class="ruby-ivar">@file_path_or_url</span>
|
269
|
+
<span class="ruby-identifier">raise</span>(<span class="ruby-constant">ArgumentError</span>, <span class="ruby-value str">"as_of not specified"</span>) <span class="ruby-keyword kw">unless</span> <span class="ruby-ivar">@file_as_of</span>
|
270
|
+
<span class="ruby-identifier">max_as_of</span> = <span class="ruby-constant">DeathMasterFile</span>.<span class="ruby-identifier">maximum</span>(<span class="ruby-identifier">:as_of</span>)
|
271
|
+
<span class="ruby-identifier">raise</span>(<span class="ruby-constant">ArgumentError</span>, <span class="ruby-node">"A more recent file has already been processed. DB as_of date #{max_as_of}"</span>) <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">max_as_of</span> <span class="ruby-operator">&&</span> (<span class="ruby-identifier">max_as_of</span> <span class="ruby-operator">>=</span> <span class="ruby-ivar">@file_as_of</span>.<span class="ruby-identifier">to_date</span>)
|
272
|
+
|
273
|
+
<span class="ruby-keyword kw">if</span> <span class="ruby-constant">File</span>.<span class="ruby-identifier">exists?</span>(<span class="ruby-ivar">@file_path_or_url</span>)
|
274
|
+
<span class="ruby-ivar">@download_file</span> = <span class="ruby-constant">File</span>.<span class="ruby-identifier">open</span>(<span class="ruby-ivar">@file_path_or_url</span>)
|
275
|
+
<span class="ruby-keyword kw">elsif</span> <span class="ruby-constant">URI</span>.<span class="ruby-identifier">parse</span>(<span class="ruby-ivar">@file_path_or_url</span>).<span class="ruby-identifier">kind_of?</span>(<span class="ruby-constant">URI</span><span class="ruby-operator">::</span><span class="ruby-constant">HTTP</span>)
|
276
|
+
<span class="ruby-ivar">@download_file</span> = <span class="ruby-identifier">get_file_from_web</span>
|
277
|
+
<span class="ruby-keyword kw">else</span>
|
278
|
+
<span class="ruby-identifier">raise</span>(<span class="ruby-constant">Errno</span><span class="ruby-operator">::</span><span class="ruby-constant">ENOENT</span>, <span class="ruby-ivar">@file_path_or_url</span>)
|
279
|
+
<span class="ruby-keyword kw">end</span>
|
280
|
+
<span class="ruby-keyword kw">end</span>
|
281
|
+
</pre>
|
282
|
+
</div>
|
283
|
+
</div>
|
284
|
+
</div>
|
285
|
+
|
286
|
+
|
287
|
+
</div>
|
288
|
+
|
289
|
+
|
290
|
+
</div>
|
291
|
+
|
292
|
+
|
293
|
+
<div id="validator-badges">
|
294
|
+
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
|
295
|
+
</div>
|
296
|
+
|
297
|
+
</body>
|
298
|
+
</html>
|