carrier_info 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in carrier_info.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Sean Devine
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,29 @@
1
+ # CarrierInfo
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'carrier_info'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install carrier_info
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'carrier_info/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "carrier_info"
8
+ gem.version = CarrierInfo::VERSION
9
+ gem.authors = ["Sean Devine"]
10
+ gem.email = ["barelyknown@icloud.com"]
11
+ gem.description = %q{Fetch carrier info off the internet}
12
+ gem.summary = %q{Fetch carrier info off the internet}
13
+ gem.homepage = "https://github.com/buytruckload/carrier_info"
14
+ gem.add_dependency 'nokogiri'
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+ end
@@ -0,0 +1,66 @@
1
+ module CarrierInfo
2
+ class Carrier
3
+
4
+ class << self
5
+ attr_accessor :sources
6
+ end
7
+
8
+ def self.load_sources
9
+ self.sources = []
10
+ Dir.new(File.dirname(__FILE__) + "/sources").each do |file|
11
+ unless File.directory?(file)
12
+ self.sources << ("CarrierInfo::Sources::" + file.split(".")[0].camelize).constantize
13
+ end
14
+ end
15
+ end
16
+ load_sources
17
+
18
+ attr_accessor :docket_prefix, :docket_number, :usdot_number, :legal_name, :dba_name, :phone, :power_units,
19
+ :drivers, :duns_number, :state_id_number, :mcs_150_form_date,
20
+ :mcs_150_mileage, :mcs_150_mileage_year, :out_of_service_date, :safer_active,
21
+ :operating_status, :entity_type, :physical_street, :physical_city, :physical_state,
22
+ :physical_postal_code, :mailing_street, :mailing_city, :mailing_state,
23
+ :mailing_postal_code, :safer_last_updated
24
+
25
+ # Operation Classification (http://safer.fmcsa.dot.gov/saferhelp.aspx#Class)
26
+ attr_accessor :classification_authorized_for_hire, :classification_exempt_for_hire,
27
+ :classification_private_property, :classification_private_passenger_business,
28
+ :classification_private_passenger_non_business, :classification_migrant,
29
+ :classification_us_mail, :classification_federal_government, :classification_state_government,
30
+ :classification_local_government, :classification_indian_tribe, :classification_other
31
+
32
+ # Carrier Operation (http://safer.fmcsa.dot.gov/saferhelp.aspx#CarrierOP)
33
+ attr_accessor :interstate, :instrastate_non_hazardous, :intrastate_hazardous
34
+
35
+ # Equipment Type
36
+ attr_accessor :equipment_vans, :equipment_household_vans, :equipment_flatbeds, :equipment_car_carriers,
37
+ :equipment_tow_trucks, :equipment_mobile_homes, :equipment_reefers, :equipment_tanks,
38
+ :equipment_intermodal_containers, :equipment_buses, :equipment_livestock_rack,
39
+ :equipment_hopper_bottom, :equipment_coal_trailers, :equipment_garbage_trucks,
40
+ :equipment_beverage_trucks, :equipment_utility_trucks,
41
+ :equipment_well_trucks
42
+
43
+ def initialize(args={})
44
+ self.docket_number = args[:docket_number]
45
+ self.usdot_number = args[:usdot_number]
46
+ end
47
+
48
+ def equipment_names
49
+ self.methods.select { |var| var =~ /equipment_.+[^=]\Z/ && var != :equipment_names }
50
+ end
51
+
52
+ def classification_names
53
+ self.methods.select { |var| var =~ /classification_.+[^=]\Z/ && var != :classification_names }
54
+ end
55
+
56
+ def sources
57
+ self.class.sources.collect { |source| source.new(self) }
58
+ end
59
+
60
+ def parse_all_sources!
61
+ sources.each(&:parse!)
62
+ self
63
+ end
64
+
65
+ end
66
+ end
@@ -0,0 +1,261 @@
1
+ module CarrierInfo
2
+ module Sources
3
+ class Safer
4
+
5
+ EQUIPMENT_CARGO_CARRIED = {
6
+ equipment_vans: ["General Freight", "US Mail", "Paper Products"],
7
+ equipment_household_vans: ["Household Goods"],
8
+ equipment_flatbeds: ["Metal: sheets, coils, rolls", "Logs, Poles, Beams, Lumber", "Building Materials", "Construction", "Machinery, Large Objects"],
9
+ equipment_car_carriers: ["Motor Vehicles"],
10
+ equipment_tow_trucks: ["Drive/Tow away"],
11
+ equipment_mobile_homes: ["Mobile Homes"],
12
+ equipment_reefers: ["Fresh Produce", "Meat", "Refrigerated Food"],
13
+ equipment_tanks: ["Liquids/Gases", "Chemicals"],
14
+ equipment_intermodal_containers: ["Intermodal Cont."],
15
+ equipment_buses: ["Passengers"],
16
+ equipment_livestock_rack: ["Livestock"],
17
+ equipment_hopper_bottom: ["Commodities Dry Bulk", "Grain, Feed, Hay", "Agricultural/Farm Supplies"],
18
+ equipment_coal_trailers: ["Coal/Coke"],
19
+ equipment_garbage_trucks: ["Garbage/Refuse"],
20
+ equipment_beverage_trucks: ["Beverages"],
21
+ equipment_utility_trucks: ["Utilities"],
22
+ equipment_well_trucks: ["Water Well"]
23
+ }
24
+
25
+ CLASSIFICATION_LABEL = {
26
+ classification_authorized_for_hire: "Auth. For Hire",
27
+ classification_exempt_for_hire: "Exempt For Hire",
28
+ classification_private_property: "Private(Property)",
29
+ classification_private_passenger_business: "Priv. Pass. (Business)",
30
+ classification_private_passenger_non_business: "Priv. Pass.(Non-business)",
31
+ classification_migrant: "Migrant",
32
+ classification_us_mail: "U.S. Mail",
33
+ classification_federal_government: "Fed. Gov't",
34
+ classification_state_government: "State Gov't",
35
+ classification_local_government: "Local Gov't",
36
+ classification_indian_tribe: "Indian Nation",
37
+ classification_other: "Other"
38
+ }
39
+
40
+ attr_accessor :content, :carrier
41
+
42
+ def initialize(carrier)
43
+ @carrier = carrier
44
+ end
45
+
46
+ def query_param
47
+ carrier.usdot_number ? "USDOT" : "MC_MX"
48
+ end
49
+
50
+ def query_string
51
+ carrier.usdot_number || carrier.docket_number
52
+ end
53
+
54
+ def request_params
55
+ params = {
56
+ query_param: query_param,
57
+ query_string: query_string,
58
+ searchtype: 'ANY',
59
+ query_type: 'queryCarrierSnapshot',
60
+ button1: 'Search'
61
+ }
62
+ end
63
+
64
+ def response
65
+ @response ||= request_response
66
+ end
67
+
68
+ def request_response
69
+ Nokogiri::HTML(Net::HTTP.post_form(URI.parse('http://safer.fmcsa.dot.gov/query.asp'), request_params).body)
70
+ end
71
+
72
+ def parse!
73
+ carrier.safer_active = parse_safer_active
74
+ if carrier.safer_active
75
+ carrier.usdot_number = parse_usdot_number
76
+ carrier.docket_prefix = parse_docket_prefix
77
+ carrier.docket_number = parse_docket_number
78
+ carrier.legal_name = parse_legal_name
79
+ carrier.dba_name = parse_dba_name
80
+ carrier.phone = parse_phone
81
+ carrier.power_units = parse_power_units
82
+ carrier.drivers = parse_drivers
83
+ carrier.duns_number = parse_duns_number
84
+ carrier.state_id_number = parse_state_id_number
85
+ carrier.mcs_150_form_date = parse_mcs_150_form_date
86
+ carrier.mcs_150_mileage = parse_mcs_150_mileage
87
+ carrier.mcs_150_mileage_year = parse_mcs_150_mileage_year
88
+ carrier.out_of_service_date = parse_out_of_service_date
89
+ carrier.operating_status = parse_operating_status
90
+ carrier.entity_type = parse_entity_type
91
+ [:physical, :mailing].each do |type|
92
+ [:street, :city, :state, :postal_code].each do |address|
93
+ carrier.send("#{type}_#{address}=", parse_address(type, address))
94
+ end
95
+ end
96
+ carrier.equipment_names.each do |equipment_name|
97
+ carrier.send("#{equipment_name}=", parse_equipment(equipment_name))
98
+ end
99
+ carrier.interstate = parse_interstate
100
+ carrier.instrastate_non_hazardous = parse_intrastate_non_hazardous
101
+ carrier.intrastate_hazardous = parse_intrastate_hazardous
102
+ carrier.classification_names.each do |classification_name|
103
+ carrier.send("#{classification_name}=", parse_classification(classification_name))
104
+ end
105
+ carrier.safer_last_updated = parse_safer_last_updated
106
+ end
107
+ end
108
+
109
+
110
+ def parse_standard_info_field(name, args={})
111
+ value = response.xpath("//a[text()='#{name}:']").find do |field|
112
+ field.attr("class") == "querylabel"
113
+ end.parent.next_element.text.gsub(/[\u0080-\u00ff]/,"").strip
114
+ if args[:integer]
115
+ value.gsub!(/\D/, "")
116
+ value = value.to_i
117
+ end
118
+ value
119
+ end
120
+
121
+ def parse_legal_name
122
+ parse_standard_info_field("Legal Name")
123
+ end
124
+
125
+ def parse_dba_name
126
+ parse_standard_info_field("DBA Name")
127
+ end
128
+
129
+ def parse_phone
130
+ parse_standard_info_field("Phone")
131
+ end
132
+
133
+ def parse_power_units
134
+ parse_standard_info_field("Power Units", integer: true)
135
+ end
136
+
137
+ def parse_drivers
138
+ parse_standard_info_field("Drivers", integer: true)
139
+ end
140
+
141
+ def parse_usdot_number
142
+ parse_standard_info_field("USDOT Number", integer: true)
143
+ end
144
+
145
+ def parse_docket_prefix
146
+ docket = parse_standard_info_field("MC or MX Number")
147
+ docket.split("-")[0] if docket =~ /-/
148
+ end
149
+
150
+ def parse_docket_number
151
+ docket = parse_standard_info_field("MC or MX Number")
152
+ docket.split("-")[1].to_i if docket =~ /-/
153
+ end
154
+
155
+ def parse_duns_number
156
+ duns = parse_standard_info_field("DUNS Number", integer: true)
157
+ duns == 0 ? nil : duns
158
+ end
159
+
160
+ def parse_state_id_number
161
+ parse_standard_info_field("State Carrier ID Number")
162
+ end
163
+
164
+ def parse_mcs_150_form_date
165
+ date_parts = parse_standard_info_field("MCS-150 Form Date").split("/").collect(&:to_i)
166
+ Date.new(date_parts[2], date_parts[0], date_parts[1]) if date_parts.count == 3
167
+ end
168
+
169
+ def parse_mcs_150_mileage
170
+ parts = parse_standard_info_field("MCS-150 Mileage (Year)").split(" ")
171
+ parts[0].gsub(/\D/,"").to_i if parts.count == 2
172
+ end
173
+
174
+ def parse_mcs_150_mileage_year
175
+ parts = parse_standard_info_field("MCS-150 Mileage (Year)").split(" ")
176
+ parts[1].gsub(/\D/,"").to_i if parts.count == 2
177
+ end
178
+
179
+ def parse_out_of_service_date
180
+ parse_standard_info_field("Out of Service Date")
181
+ # date_parts = parse_standard_info_field("Out of Service Date").split("/").collect(&:to_i)
182
+ # Date.new(date_parts[2], date_parts[0], date_parts[1]) if date_parts.count == 3
183
+ end
184
+
185
+ def parse_safer_active
186
+ !(response.xpath("//text()='Record Inactive'") || response.xpath("//text()='Record Not Found'"))
187
+ end
188
+
189
+ def parse_operating_status
190
+ parse_standard_info_field("Operating Status")
191
+ end
192
+
193
+ def parse_entity_type
194
+ parse_standard_info_field("Entity Type")
195
+ end
196
+
197
+ def parse_address(type, part)
198
+ address = parse_standard_info_field("#{type.to_s.titleize} Address")
199
+ send("parse_#{part}", address)
200
+ end
201
+
202
+ def parse_street(address)
203
+ address.split("\n")[0].strip
204
+ end
205
+
206
+ def parse_city(address)
207
+ address.split("\n")[1].split(",")[0].strip
208
+ end
209
+
210
+ def parse_state(address)
211
+ address.split("\n")[1].split(",")[1].strip =~ /\A(\w*)\s*(\S*)\s*\Z/
212
+ $1
213
+ end
214
+
215
+ def parse_postal_code(address)
216
+ address.split("\n")[1].split(",")[1].strip =~ /\A(\w*)\s*(\S*)\s*\Z/
217
+ $2
218
+ end
219
+
220
+ def parse_equipment(equipment_name)
221
+ !!EQUIPMENT_CARGO_CARRIED[equipment_name].find do |cargo_carried|
222
+ check_box = response.xpath("//font[text()='#{cargo_carried}']").first.parent.previous_element
223
+ check_box.text == "X" ? true : false
224
+ end
225
+ end
226
+
227
+ def parse_checkbox_field(field_name)
228
+ if label = response.xpath(%Q(//font[text()="#{field_name}"])).first
229
+ check_box = label.parent.previous_element
230
+ check_box.text == "X" ? true : false
231
+ else
232
+ false
233
+ end
234
+ end
235
+
236
+ def parse_interstate
237
+ parse_checkbox_field("Interstate")
238
+ end
239
+
240
+ def parse_intrastate_non_hazardous
241
+ parse_checkbox_field("Intrastate Only (Non-HM)")
242
+ end
243
+
244
+ def parse_intrastate_hazardous
245
+ parse_checkbox_field("Intrastate Only (HM)")
246
+ end
247
+
248
+ def parse_classification(classification_name)
249
+ parse_checkbox_field(CLASSIFICATION_LABEL[classification_name])
250
+ end
251
+
252
+ def parse_safer_last_updated
253
+ if last_updated = response.at_xpath("//b[starts-with(.,'The information below reflects the content')]").xpath("./font").text.strip
254
+ date_parts = last_updated.split("/").collect(&:to_i)
255
+ Date.new(date_parts[2], date_parts[0], date_parts[1]) if date_parts.count == 3
256
+ end
257
+ end
258
+
259
+ end
260
+ end
261
+ end
@@ -0,0 +1 @@
1
+ require 'carrier_info/sources/safer'
@@ -0,0 +1,3 @@
1
+ module CarrierInfo
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,6 @@
1
+ require 'net/http'
2
+ require 'nokogiri'
3
+ require 'active_support/all'
4
+ require "carrier_info/version"
5
+ require "carrier_info/sources"
6
+ require "carrier_info/carrier"
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: carrier_info
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sean Devine
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-31 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: nokogiri
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: Fetch carrier info off the internet
31
+ email:
32
+ - barelyknown@icloud.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - Gemfile
39
+ - LICENSE.txt
40
+ - README.md
41
+ - Rakefile
42
+ - carrier_info.gemspec
43
+ - lib/carrier_info.rb
44
+ - lib/carrier_info/carrier.rb
45
+ - lib/carrier_info/sources.rb
46
+ - lib/carrier_info/sources/safer.rb
47
+ - lib/carrier_info/version.rb
48
+ homepage: https://github.com/buytruckload/carrier_info
49
+ licenses: []
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ! '>='
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 1.8.24
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: Fetch carrier info off the internet
72
+ test_files: []