duns-lookup 0.0.3
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.
- data/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +28 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/doc/classes/Duns.html +265 -0
- data/doc/classes/Duns.src/M000001.html +22 -0
- data/doc/classes/Duns.src/M000002.html +21 -0
- data/doc/classes/Duns.src/M000003.html +24 -0
- data/doc/classes/Duns.src/M000004.html +18 -0
- data/doc/classes/Duns.src/M000005.html +22 -0
- data/doc/classes/Duns.src/M000006.html +20 -0
- data/doc/classes/DunsError.html +111 -0
- data/doc/created.rid +1 -0
- data/doc/files/lib/duns-lookup_rb.html +110 -0
- data/doc/fr_class_index.html +28 -0
- data/doc/fr_file_index.html +27 -0
- data/doc/fr_method_index.html +32 -0
- data/doc/index.html +24 -0
- data/doc/rdoc-style.css +208 -0
- data/duns-lookup.gemspec +71 -0
- data/lib/duns-lookup.rb +99 -0
- data/spec/duns-lookup_spec.rb +35 -0
- data/spec/spec_helper.rb +25 -0
- metadata +100 -0
data/duns-lookup.gemspec
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{duns-lookup}
|
8
|
+
s.version = "0.0.3"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Kali Donovan"]
|
12
|
+
s.date = %q{2009-10-14}
|
13
|
+
s.description = %q{Provides a small wrapper around the Dun & Bradstreet website to retrieve business information from DUNS numbers.}
|
14
|
+
s.email = %q{kali.donovan@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"doc/classes/Duns.html",
|
27
|
+
"doc/classes/Duns.src/M000001.html",
|
28
|
+
"doc/classes/Duns.src/M000002.html",
|
29
|
+
"doc/classes/Duns.src/M000003.html",
|
30
|
+
"doc/classes/Duns.src/M000004.html",
|
31
|
+
"doc/classes/Duns.src/M000005.html",
|
32
|
+
"doc/classes/Duns.src/M000006.html",
|
33
|
+
"doc/classes/DunsError.html",
|
34
|
+
"doc/created.rid",
|
35
|
+
"doc/files/lib/duns-lookup_rb.html",
|
36
|
+
"doc/fr_class_index.html",
|
37
|
+
"doc/fr_file_index.html",
|
38
|
+
"doc/fr_method_index.html",
|
39
|
+
"doc/index.html",
|
40
|
+
"doc/rdoc-style.css",
|
41
|
+
"duns-lookup.gemspec",
|
42
|
+
"lib/duns-lookup.rb",
|
43
|
+
"spec/duns-lookup_spec.rb",
|
44
|
+
"spec/spec_helper.rb"
|
45
|
+
]
|
46
|
+
s.homepage = %q{http://github.com/kdonovan/duns-lookup}
|
47
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
48
|
+
s.require_paths = ["lib"]
|
49
|
+
s.rubygems_version = %q{1.3.5}
|
50
|
+
s.summary = %q{Wrapper for looking up Dun & Bradstreet numbers (DUNS)}
|
51
|
+
s.test_files = [
|
52
|
+
"spec/duns-lookup_spec.rb",
|
53
|
+
"spec/spec_helper.rb"
|
54
|
+
]
|
55
|
+
|
56
|
+
if s.respond_to? :specification_version then
|
57
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
58
|
+
s.specification_version = 3
|
59
|
+
|
60
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
61
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
62
|
+
s.add_runtime_dependency(%q<mechanize>, [">= 0"])
|
63
|
+
else
|
64
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
65
|
+
s.add_dependency(%q<mechanize>, [">= 0"])
|
66
|
+
end
|
67
|
+
else
|
68
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
69
|
+
s.add_dependency(%q<mechanize>, [">= 0"])
|
70
|
+
end
|
71
|
+
end
|
data/lib/duns-lookup.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
class DunsError < Exception
|
2
|
+
end
|
3
|
+
|
4
|
+
# = Synopsis
|
5
|
+
# The Duns library provides a small wrapper around the Dun & Bradstreet
|
6
|
+
# website's advanced search functionality. Currently it only implements
|
7
|
+
# searching for company by DUNS number.
|
8
|
+
#
|
9
|
+
# == Example
|
10
|
+
# require 'rubygems'
|
11
|
+
# require 'kdonovan-duns-lookup'
|
12
|
+
#
|
13
|
+
# Duns.lookup_duns( *invalid_number* )
|
14
|
+
# # => nil
|
15
|
+
# Duns.lookup_duns( *some_valid_number* )
|
16
|
+
# # => {:name => *a_name*, :address => *an_address*}
|
17
|
+
|
18
|
+
class Duns
|
19
|
+
require 'rubygems'
|
20
|
+
require 'open-uri'
|
21
|
+
require 'mechanize'
|
22
|
+
|
23
|
+
# D&B homepage URL
|
24
|
+
@@dnb_homepage = 'http://smallbusiness.dnb.com/'
|
25
|
+
|
26
|
+
# The URI for D&B advanced search
|
27
|
+
@@dnb_advanced_search = 'https://smallbusiness.dnb.com/ePlatform/servlet/AdvancedCompanySearch?storeId=10001&catalogId=70001?storeId=10001&catalogId=70001'
|
28
|
+
|
29
|
+
# Our Mechanize agent
|
30
|
+
@@agent = WWW::Mechanize.new
|
31
|
+
@@agent.user_agent_alias = 'Windows IE 7'
|
32
|
+
|
33
|
+
####
|
34
|
+
# Look up a given DUNS number in the D&B database.
|
35
|
+
# If the number is found, returns a hash with :name and :address keys.
|
36
|
+
# Otherwise, returns nil.
|
37
|
+
#
|
38
|
+
def self.lookup_duns(number)
|
39
|
+
form = @@agent.get( @@dnb_advanced_search ).form('DunsSearchForm')
|
40
|
+
form.dunsNumber = enforce_duns_formatting(number)
|
41
|
+
page = @@agent.submit(form)
|
42
|
+
|
43
|
+
extract_search_results(page)
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
####
|
48
|
+
# Updates the internal URL used as the base for advanced searches.
|
49
|
+
#
|
50
|
+
# The D&B website uses lots of extraneous (to us) URL params, and I have no idea what they all mean.
|
51
|
+
# If the base URL stops working, this method will try to set a new one by visiting the main page and
|
52
|
+
# finding & clicking an Advanced Search link.
|
53
|
+
#
|
54
|
+
# This is mostly a precaution, but if searches stop working a good first bet would be to try running this
|
55
|
+
# method. If search is still broken, something actually changed in the D&B HTML and we'll need to retool
|
56
|
+
# the gem.
|
57
|
+
#
|
58
|
+
def self.update_advanced_search_url
|
59
|
+
page = @@agent.get( @@dnb_homepage )
|
60
|
+
advanced_link = page.links.find{|l| l.text.match(/search/i) && l.uri.to_s.match(/AdvancedCompanySearch/)}
|
61
|
+
raise(DunsError, "Unable to find an advanced search link at: #{@@dnb_homepage}") if advanced_link.nil?
|
62
|
+
@@dnb_advanced_search = advanced_link.uri.to_s
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
protected
|
67
|
+
|
68
|
+
# Given a search page, extract the results
|
69
|
+
def self.extract_search_results(page)
|
70
|
+
return nil if page.search('div.text-red').size > 0
|
71
|
+
|
72
|
+
# Given a DUNS number search, we only expect one result. For other search types (when/if implemented), loop over all TRs returned in this table
|
73
|
+
company_name = extract_name( page.search("//table[@id='SearchResultsTable']//tr[1]/td[2]") )
|
74
|
+
company_address = extract_address( page.search("//table[@id='SearchResultsTable']//tr[1]/td[3]") )
|
75
|
+
|
76
|
+
{:name => company_name, :address => company_address}
|
77
|
+
end
|
78
|
+
|
79
|
+
# Retrieve an address from the proper D&B HTML for the td element
|
80
|
+
def self.extract_address(td)
|
81
|
+
td.text.gsub(/\s{2,}/, ' ')
|
82
|
+
end
|
83
|
+
|
84
|
+
# Retrieve a name from the proper D&B HTML for the td element
|
85
|
+
def self.extract_name(td)
|
86
|
+
raw_text = td.text.gsub(/\s{2,}/, ' ')
|
87
|
+
with_js = raw_text.match(/var companyName=escape(.+?)var companyAddr/)[1] # First get the surrounding js, to ensure we don't get confused by e.g. a ) in the company name
|
88
|
+
|
89
|
+
# Now we have e.g. >> ('NORTH TEXAS CIRCUIT BOARD CO., INC.'); << and we need to strip off the extraneous stuff
|
90
|
+
with_js[2..-5]
|
91
|
+
end
|
92
|
+
|
93
|
+
# Strip out non-numeric characters, and raise error if remaining number is still invalid
|
94
|
+
def self.enforce_duns_formatting(orig_number)
|
95
|
+
number = orig_number.to_s.gsub(/\D/, '')
|
96
|
+
raise(DunsError, "Received invalid DUNS number (must be 9 digits): #{orig_number}") unless number.length == 9
|
97
|
+
return number
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "DunsLookup" do
|
4
|
+
context "Searching by DUNS number" do
|
5
|
+
it "should raise an exception when invalid DUNS numbers are supplied" do
|
6
|
+
lambda { Duns.lookup_duns('123') }.should raise_error(DunsError)
|
7
|
+
lambda { Duns.lookup_duns('abcdefghi') }.should raise_error(DunsError)
|
8
|
+
lambda { Duns.lookup_duns('123abc---') }.should raise_error(DunsError)
|
9
|
+
lambda { Duns.lookup_duns('') }.should raise_error(DunsError)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should not raise an exception when a valid DUNS number is supplied" do
|
13
|
+
lambda { Duns.lookup_duns('123456789') }.should_not raise_error(DunsError)
|
14
|
+
lambda { Duns.lookup_duns('123 456 789') }.should_not raise_error(DunsError)
|
15
|
+
lambda { Duns.lookup_duns('123-456-789') }.should_not raise_error(DunsError)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "Returns no results where there shouldn't be any" do
|
19
|
+
Duns.lookup_duns( fake_duns[:number] ).should be_nil
|
20
|
+
end
|
21
|
+
|
22
|
+
it "Should properly extract company name and address when a valid result is found" do
|
23
|
+
unless real_duns[:number] && real_duns[:name] && real_duns[:address]
|
24
|
+
raise "Must provide information from an existing company to validates results are correct. Edit #real_duns in spec_helper.rb"
|
25
|
+
end
|
26
|
+
|
27
|
+
results = Duns.lookup_duns( real_duns[:number] )
|
28
|
+
results.should_not be_nil
|
29
|
+
results.should be_a_kind_of Hash
|
30
|
+
|
31
|
+
results[:name].should == real_duns[:name]
|
32
|
+
results[:address].should == real_duns[:address]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
require 'duns-lookup'
|
4
|
+
require 'spec'
|
5
|
+
require 'spec/autorun'
|
6
|
+
|
7
|
+
Spec::Runner.configure do |config|
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
# TODO -- to run the specs, input valid information from a real company here
|
12
|
+
# Try looking up your business by hand first to see exactly the format used by the D&B website
|
13
|
+
# (for instance punctuation matters, as in the abbreviations of CO and INC below)
|
14
|
+
def real_duns
|
15
|
+
{
|
16
|
+
:number => nil, # Enter the company's DUNS number
|
17
|
+
:name => nil, # Enter the official company name, ALL UPPER CASE: FOO WIDGET CO., INC.
|
18
|
+
:address => nil # Enter the officially registered address, ALL UPPER CASE: 123 W MAIN ST, SAN FRANCISCO, CA
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
# A valid, but non-existant DUNS number
|
23
|
+
def fake_duns
|
24
|
+
{:number => '123456789'}
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: duns-lookup
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kali Donovan
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-14 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: mechanize
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
description: Provides a small wrapper around the Dun & Bradstreet website to retrieve business information from DUNS numbers.
|
36
|
+
email: kali.donovan@gmail.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- LICENSE
|
43
|
+
- README.rdoc
|
44
|
+
files:
|
45
|
+
- .document
|
46
|
+
- .gitignore
|
47
|
+
- LICENSE
|
48
|
+
- README.rdoc
|
49
|
+
- Rakefile
|
50
|
+
- VERSION
|
51
|
+
- doc/classes/Duns.html
|
52
|
+
- doc/classes/Duns.src/M000001.html
|
53
|
+
- doc/classes/Duns.src/M000002.html
|
54
|
+
- doc/classes/Duns.src/M000003.html
|
55
|
+
- doc/classes/Duns.src/M000004.html
|
56
|
+
- doc/classes/Duns.src/M000005.html
|
57
|
+
- doc/classes/Duns.src/M000006.html
|
58
|
+
- doc/classes/DunsError.html
|
59
|
+
- doc/created.rid
|
60
|
+
- doc/files/lib/duns-lookup_rb.html
|
61
|
+
- doc/fr_class_index.html
|
62
|
+
- doc/fr_file_index.html
|
63
|
+
- doc/fr_method_index.html
|
64
|
+
- doc/index.html
|
65
|
+
- doc/rdoc-style.css
|
66
|
+
- duns-lookup.gemspec
|
67
|
+
- lib/duns-lookup.rb
|
68
|
+
- spec/duns-lookup_spec.rb
|
69
|
+
- spec/spec_helper.rb
|
70
|
+
has_rdoc: true
|
71
|
+
homepage: http://github.com/kdonovan/duns-lookup
|
72
|
+
licenses: []
|
73
|
+
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options:
|
76
|
+
- --charset=UTF-8
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: "0"
|
84
|
+
version:
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: "0"
|
90
|
+
version:
|
91
|
+
requirements: []
|
92
|
+
|
93
|
+
rubyforge_project:
|
94
|
+
rubygems_version: 1.3.5
|
95
|
+
signing_key:
|
96
|
+
specification_version: 3
|
97
|
+
summary: Wrapper for looking up Dun & Bradstreet numbers (DUNS)
|
98
|
+
test_files:
|
99
|
+
- spec/duns-lookup_spec.rb
|
100
|
+
- spec/spec_helper.rb
|