melissa 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.jruby-version +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +50 -0
- data/LICENSE +22 -0
- data/README.md +142 -0
- data/Rakefile +8 -0
- data/config/melissa +2 -0
- data/lib/melissa.rb +57 -0
- data/lib/melissa/addr_obj.rb +92 -0
- data/lib/melissa/addr_obj_live.rb +117 -0
- data/lib/melissa/addr_obj_mock.rb +46 -0
- data/lib/melissa/config.rb +63 -0
- data/lib/melissa/geo_point.rb +75 -0
- data/lib/melissa/geo_point_live.rb +126 -0
- data/lib/melissa/geo_point_mock.rb +28 -0
- data/lib/melissa/railtie.rb +11 -0
- data/lib/melissa/version.rb +3 -0
- data/melissa.gemspec +21 -0
- data/test/addr_obj_test.rb +109 -0
- data/test/geo_point_test.rb +65 -0
- data/test/melissa_test.rb +76 -0
- data/test/test_helper.rb +3 -0
- metadata +116 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: fb291d59288648da0db3f3c32dd53dc59fe4fb51
|
4
|
+
data.tar.gz: c3108433ae2a69e654267e172b77cbee2e546258
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7adf1de091986fe471e96f2b090feeab46d88bff99ba672b464319e469ea905b2d3965eb9ceffa314b7bdaff95431b09161c501df5f732e1e04b9641d9098c3c
|
7
|
+
data.tar.gz: 6f02f3f05fb70f0d4d9eb13e3ccded9465e6c603c70a6f10597d3370a2a3a648c983625de481291ed0fead33566dc561a6df4ec8b40eed797d913d4a5ba3615a
|
data/.gitignore
ADDED
data/.jruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
jruby-1.7.9
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.2
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
melissa (0.0.1)
|
5
|
+
activesupport
|
6
|
+
ffi
|
7
|
+
minitest
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
activesupport (4.2.0)
|
13
|
+
i18n (~> 0.7)
|
14
|
+
json (~> 1.7, >= 1.7.7)
|
15
|
+
minitest (~> 5.1)
|
16
|
+
thread_safe (~> 0.3, >= 0.3.4)
|
17
|
+
tzinfo (~> 1.1)
|
18
|
+
ansi (1.5.0)
|
19
|
+
builder (3.2.2)
|
20
|
+
ffi (1.9.6)
|
21
|
+
ffi (1.9.6-java)
|
22
|
+
i18n (0.7.0)
|
23
|
+
json (1.8.2)
|
24
|
+
json (1.8.2-java)
|
25
|
+
minitest (5.4.0)
|
26
|
+
minitest-reporters (1.0.8)
|
27
|
+
ansi
|
28
|
+
builder
|
29
|
+
minitest (>= 5.0)
|
30
|
+
ruby-progressbar
|
31
|
+
minitest-stub_any_instance (1.0.0)
|
32
|
+
rake (10.4.2)
|
33
|
+
ruby-progressbar (1.7.1)
|
34
|
+
shoulda-context (1.2.1)
|
35
|
+
thread_safe (0.3.4)
|
36
|
+
thread_safe (0.3.4-java)
|
37
|
+
tzinfo (1.2.2)
|
38
|
+
thread_safe (~> 0.1)
|
39
|
+
|
40
|
+
PLATFORMS
|
41
|
+
java
|
42
|
+
ruby
|
43
|
+
|
44
|
+
DEPENDENCIES
|
45
|
+
melissa!
|
46
|
+
minitest
|
47
|
+
minitest-reporters
|
48
|
+
minitest-stub_any_instance
|
49
|
+
rake
|
50
|
+
shoulda-context
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Svetlana Marinskaya
|
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,142 @@
|
|
1
|
+
# Melissa
|
2
|
+
|
3
|
+
Configurable interface to Melissa Data Address and GeoCoder objects
|
4
|
+
|
5
|
+
##Description
|
6
|
+
|
7
|
+
Melissa Gem allows you to use ruby wrappers for Melissa Data's AddrObj and GeoPoint objects or use the mock objects depending on configuration.
|
8
|
+
|
9
|
+
Address Object’s functionality is divided into four interfaces, AddressCheck, Parse,
|
10
|
+
StreetData, and Data. We are using AddressCheck Interface.
|
11
|
+
|
12
|
+
The AddressCheck Interface verifies and standardizes your address data using the
|
13
|
+
most current data from the U. S. Postal Service®. The programming logic used by
|
14
|
+
AddressCheck is CASS Certified™. This stringent certification ensures the quality of
|
15
|
+
the data that is passed through the AddressCheck Interface and must be renewed
|
16
|
+
every year.
|
17
|
+
|
18
|
+
The GeoCoder Object enables you to access geographic data using your
|
19
|
+
ZIP Code™ and optional Plus4. You will be able to obtain latitude and
|
20
|
+
longitude geographic coordinates, census tract and block numbers, as well as
|
21
|
+
county name and FIPS numbers.
|
22
|
+
|
23
|
+
The Standard version of GeoCoder Object includes GeoPoints 11-digit
|
24
|
+
(ZIP + 4 + 2) doorstop geolocation data on over 121,827,000 addresses in
|
25
|
+
the United States.
|
26
|
+
GeoPoints data is multi-sourced, including interpolated points mathematically
|
27
|
+
calculated for valid addresses where no GeoPoints data is found, and covers
|
28
|
+
95 percent of all U.S. delivery addresses, business and residential.
|
29
|
+
|
30
|
+
|
31
|
+
## Installation
|
32
|
+
|
33
|
+
Add this line to your application's Gemfile:
|
34
|
+
|
35
|
+
gem 'melissa'
|
36
|
+
|
37
|
+
And then execute:
|
38
|
+
|
39
|
+
$ bundle
|
40
|
+
|
41
|
+
Or install it yourself as:
|
42
|
+
|
43
|
+
$ gem install melissa
|
44
|
+
|
45
|
+
## Usage
|
46
|
+
|
47
|
+
It is recommended to read the following config options from environment variables
|
48
|
+
From Melissa Data documentation:
|
49
|
+
The license string should be entered as an environment variable named
|
50
|
+
MD_LICENSE. This allows you to update your license string without editing
|
51
|
+
and recompiling your code
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
self.config_path = ENV['MELISSA_CONFIG_PATH'] if ENV['MELISSA_CONFIG_PATH']
|
55
|
+
self.home = ENV['MELISSA_HOME'] if ENV['MELISSA_HOME']
|
56
|
+
@data_path = ENV['MELISSA_DATA_PATH'] if ENV['MELISSA_DATA_PATH']
|
57
|
+
@addr_obj_lib = ENV['MELISSA_ADDR_OBJ_LIB'] if ENV['MELISSA_ADDR_OBJ_LIB']
|
58
|
+
@geo_point_lib = ENV['MELISSA_GEO_POINT_LIB'] if ENV['MELISSA_GEO_POINT_LIB']
|
59
|
+
@license = ENV['MD_LICENSE'] if ENV['MD_LICENSE']
|
60
|
+
```
|
61
|
+
It is also possible to set HOME and LICENSE variables in configuration file, which can be accesses
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
Melissa.configure do |config|
|
65
|
+
config.config_path = "/etc/config/melissa"
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
A suite number can be passed at the end of the values passed to :address
|
70
|
+
option, or as the parameter of either the :address2 or the :suite option.
|
71
|
+
If the value passed to the :address option cannot be verified, Address Object
|
72
|
+
will attempt to verify the value passed via the :address2 option. See Address
|
73
|
+
Handling in Melissa Data Documentation for more information.
|
74
|
+
If you use :zip option, :city and :state parameters are optional.
|
75
|
+
Likewise, if :city and :state are populated, :zip is optional. If possible, it is the
|
76
|
+
best practice to pass all three values if possible, because Address Object will use
|
77
|
+
the values to validate each other.
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
#create AddrObj
|
81
|
+
valid_addr_obj = ::Melissa.addr_obj(
|
82
|
+
:address => '9802 Brompton Dr',
|
83
|
+
:city => 'Tampa',
|
84
|
+
:state => 'Fl',
|
85
|
+
:zip => '33626'
|
86
|
+
)
|
87
|
+
#use it to get deliverypoint
|
88
|
+
deliverypoint = valid_addr_obj.delivery_point
|
89
|
+
|
90
|
+
#create GeoPoint Object
|
91
|
+
geo_point_obj = ::Melissa.geo_point(valid_addr_obj)
|
92
|
+
#use it
|
93
|
+
latitude = geo_point_obj.latitude
|
94
|
+
longitude= geo_point_obj.longitude
|
95
|
+
#or
|
96
|
+
geo_point_obj = ::Melissa.geo_point(:zip => 'zip', :plus4 => 'plus4', :delivery_point_code => 'delivery_point_code')
|
97
|
+
|
98
|
+
```
|
99
|
+
|
100
|
+
The calls to Melissa Data library will be attempted only if Melissa Data library is loaded.
|
101
|
+
Otherwise mock objects will be used. This way there is no need to install Melissa Data library on development machine.
|
102
|
+
The following rules are used in mocking AddrObj Library:
|
103
|
+
1. if zip_code is present, addres object is valid.
|
104
|
+
2. to mock delivery point: "#{zip_code}1234#{last 2 digits of zip code}".
|
105
|
+
For example, zip_code = 33613 => delivery_point = 33613123413
|
106
|
+
|
107
|
+
Mocked GeoPoint object will return following values:
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
@latitude = 36.20687
|
111
|
+
@longitude = -115.27857
|
112
|
+
@time_zone_code = '08'
|
113
|
+
@resultcodes = ['AS01']
|
114
|
+
@is_valid = true
|
115
|
+
```
|
116
|
+
|
117
|
+
## Meta
|
118
|
+
|
119
|
+
* Code: `git clone git://github.com/smarinskaya/melissa.git`
|
120
|
+
* Home: <https://github.com/smarinskaya/Melissa>
|
121
|
+
* Bugs: <http://github.com/smarinskaya/Melissa/issues>
|
122
|
+
* Gems: TODO
|
123
|
+
|
124
|
+
|
125
|
+
## Authors
|
126
|
+
|
127
|
+
1. [Brad Pardee](https://github.com/bpardee)
|
128
|
+
2. [Svetlana Marinskaya](https://github.com/smarinskaya)
|
129
|
+
|
130
|
+
|
131
|
+
##Aknowlegments
|
132
|
+
|
133
|
+
Configuration pattern is developed based on Brandon Hilkert blog
|
134
|
+
http://brandonhilkert.com/blog/ruby-gem-configuration-patterns/
|
135
|
+
|
136
|
+
## Contributing
|
137
|
+
|
138
|
+
1. Fork it
|
139
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
140
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
141
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
142
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/config/melissa
ADDED
data/lib/melissa.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
module Melissa
|
2
|
+
|
3
|
+
class << self
|
4
|
+
attr_writer :config
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.addr_obj(attrs)
|
8
|
+
if config.mode == :live
|
9
|
+
raise LoadError, "Melissa AddrObj was not loaded!" unless config.addr_obj_lib_loaded
|
10
|
+
AddrObjLive.new(attrs)
|
11
|
+
else
|
12
|
+
AddrObjMock.new(attrs)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.geo_point(attrs)
|
17
|
+
if config.mode == :live
|
18
|
+
raise LoadError, "Melissa GeoPoint object was not loaded!" unless config.geo_point_lib_loaded
|
19
|
+
GeoPointLive.new(attrs)
|
20
|
+
else
|
21
|
+
GeoPointMock.new(attrs)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.config
|
26
|
+
@config ||= Config.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.reset
|
30
|
+
@config = Config.new
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.configure
|
34
|
+
yield(config)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
require 'melissa/railtie' if defined?(Rails)
|
39
|
+
|
40
|
+
require "melissa/version"
|
41
|
+
require "melissa/config"
|
42
|
+
require 'melissa/addr_obj'
|
43
|
+
require 'melissa/geo_point'
|
44
|
+
require 'melissa/addr_obj_live'
|
45
|
+
require 'melissa/geo_point_live'
|
46
|
+
require 'melissa/addr_obj_mock'
|
47
|
+
require 'melissa/geo_point_mock'
|
48
|
+
|
49
|
+
|
50
|
+
#valid_address_obj = ::Melissa.adrr_obj(:address => 'valid street', :city => 'Tampa', :state => 'FL', :zip => '33626')
|
51
|
+
#puts "addr=#{valid_address_obj.address}"
|
52
|
+
#puts "deliverypoint=#{valid_address_obj.delivery_point}"
|
53
|
+
|
54
|
+
#g = ::Melissa.geo_point(valid_address_obj)
|
55
|
+
#puts "lat,long=#{g.latitude},#{g.longitude}"
|
56
|
+
#or
|
57
|
+
#g = ::Melissa.geo_point(:zip => 'zip', :plus4 => 'plus4', :delivery_point_code => 'delivery_point_code')
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'active_support/all' #TODO I can narrow down this
|
2
|
+
|
3
|
+
module Melissa
|
4
|
+
class AddrObj
|
5
|
+
AddressStruct = Struct.new(:number, :pre_directional, :name, :suffix, :post_directional)
|
6
|
+
|
7
|
+
@@melissa_attributes = %w(
|
8
|
+
Company
|
9
|
+
LastName
|
10
|
+
Address
|
11
|
+
Address2
|
12
|
+
Suite
|
13
|
+
City
|
14
|
+
CityAbbreviation
|
15
|
+
State
|
16
|
+
Zip
|
17
|
+
Plus4
|
18
|
+
CarrierRoute
|
19
|
+
DeliveryPointCode
|
20
|
+
DeliveryPointCheckDigit
|
21
|
+
CountyFips
|
22
|
+
CountyName
|
23
|
+
AddressTypeCode
|
24
|
+
AddressTypeString
|
25
|
+
Urbanization
|
26
|
+
CongressionalDistrict
|
27
|
+
LACS
|
28
|
+
LACSLinkIndicator
|
29
|
+
RBDI
|
30
|
+
PrivateMailbox
|
31
|
+
TimeZoneCode
|
32
|
+
TimeZone
|
33
|
+
Msa
|
34
|
+
Pmsa
|
35
|
+
DefaultFlagIndicator
|
36
|
+
SuiteStatus
|
37
|
+
EWSFlag
|
38
|
+
CMRA
|
39
|
+
DsfNoStats
|
40
|
+
DsfVacant
|
41
|
+
CountryCode
|
42
|
+
ZipType
|
43
|
+
FalseTable
|
44
|
+
DPVFootnotes
|
45
|
+
LACSLinkReturnCode
|
46
|
+
SuiteLinkReturnCode
|
47
|
+
ELotNumber
|
48
|
+
ELotOrder
|
49
|
+
)
|
50
|
+
|
51
|
+
# See http://www.melissadata.com/lookups/resultcodes.asp
|
52
|
+
@@good_codes = ['AS01', 'AS02']
|
53
|
+
@@bad_codes = ['AC02', 'AC03']
|
54
|
+
|
55
|
+
def delivery_point
|
56
|
+
"#{zip}#{plus4}#{delivery_point_code}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def time_zone_offset
|
60
|
+
GeoPoint.time_zone_offset(self.time_zone_code, self.state)
|
61
|
+
end
|
62
|
+
|
63
|
+
def address_struct
|
64
|
+
@address_struct = begin
|
65
|
+
if valid?
|
66
|
+
if address_type_string == 'Street' || address_type_string == 'Highrise'
|
67
|
+
match = self.address.match /^(\S+)\s?(N|NE|E|SE|S|SW|W|NW|) (\S.*?)\s?(N|NE|E|SE|S|SW|W|NW|)$/
|
68
|
+
end
|
69
|
+
elsif self.address
|
70
|
+
match = self.address.match /^(\d\S*)\s?(N|NE|E|SE|S|SW|W|NW|) (\S.*?)\s?(N|NE|E|SE|S|SW|W|NW|)$/
|
71
|
+
end
|
72
|
+
if match
|
73
|
+
# Parse out the optional suffix
|
74
|
+
street_match = match[3].match /(\S.*?)( [A-Za-z]{2,4}|)$/
|
75
|
+
if street_match
|
76
|
+
name, suffix = street_match[1], street_match[2].strip
|
77
|
+
else
|
78
|
+
name, suffix = match[3], ''
|
79
|
+
end
|
80
|
+
AddressStruct.new(match[1], match[2], name, suffix, match[4])
|
81
|
+
elsif self.address
|
82
|
+
AddressStruct.new('', '', self.address, '', '')
|
83
|
+
else
|
84
|
+
AddressStruct.new
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module Melissa
|
4
|
+
class AddrObjLive < AddrObj
|
5
|
+
begin
|
6
|
+
extend FFI::Library
|
7
|
+
|
8
|
+
ffi_lib Melissa.config.addr_obj_lib if defined?(FFI)
|
9
|
+
attr_functions = @@melissa_attributes.map { |name| ["mdAddrGet#{name}".to_sym, [:pointer], :string] }
|
10
|
+
|
11
|
+
functions = attr_functions + [
|
12
|
+
# method # parameters # return
|
13
|
+
[:mdAddrCreate, [], :pointer],
|
14
|
+
[:mdAddrSetLicenseString, [:pointer, :string], :int],
|
15
|
+
[:mdAddrSetPathToUSFiles, [:pointer, :string], :void],
|
16
|
+
[:mdAddrInitializeDataFiles, [:pointer], :int],
|
17
|
+
[:mdAddrClearProperties, [:pointer], :void],
|
18
|
+
[:mdAddrSetCompany, [:pointer, :string], :void],
|
19
|
+
[:mdAddrSetAddress, [:pointer, :string], :void],
|
20
|
+
[:mdAddrSetAddress2, [:pointer, :string], :void],
|
21
|
+
[:mdAddrSetSuite, [:pointer, :string], :void],
|
22
|
+
[:mdAddrSetCity, [:pointer, :string], :void],
|
23
|
+
[:mdAddrSetState, [:pointer, :string], :void],
|
24
|
+
[:mdAddrSetZip, [:pointer, :string], :void],
|
25
|
+
[:mdAddrSetUrbanization, [:pointer, :string], :void],
|
26
|
+
[:mdAddrSetCountryCode, [:pointer, :string], :void],
|
27
|
+
[:mdAddrVerifyAddress, [:pointer], :int],
|
28
|
+
[:mdAddrGetResults, [:pointer], :string],
|
29
|
+
[:mdAddrDestroy, [:pointer], :void],
|
30
|
+
[:mdAddrGetLicenseExpirationDate, [:pointer], :string],
|
31
|
+
[:mdAddrGetExpirationDate, [:pointer], :string],
|
32
|
+
]
|
33
|
+
|
34
|
+
functions.each do |func|
|
35
|
+
begin
|
36
|
+
attach_function(*func)
|
37
|
+
rescue Object => e
|
38
|
+
raise "Could not attach #{func}, #{e.message}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
attr_reader *@@melissa_attributes.map { |name| name.underscore.to_sym }
|
43
|
+
|
44
|
+
# Get all the attributes out up-front so we can destroy the h_addr_lib object
|
45
|
+
class_eval <<-EOS
|
46
|
+
define_method(:fill_attributes) do |h_addr_lib|
|
47
|
+
#{@@melissa_attributes.map { |name| "@#{name.underscore} = mdAddrGet#{name}(h_addr_lib)" }.join("\n")}
|
48
|
+
end
|
49
|
+
EOS
|
50
|
+
|
51
|
+
def self.with_mdaddr
|
52
|
+
h_addr_lib = mdAddrCreate
|
53
|
+
mdAddrSetLicenseString(h_addr_lib, Melissa.config.license)
|
54
|
+
mdAddrSetPathToUSFiles(h_addr_lib, Melissa.config.data_path)
|
55
|
+
mdAddrInitializeDataFiles(h_addr_lib)
|
56
|
+
yield h_addr_lib
|
57
|
+
ensure
|
58
|
+
mdAddrDestroy(h_addr_lib)
|
59
|
+
end
|
60
|
+
|
61
|
+
#This function returns a date value corresponding to the date when the current license
|
62
|
+
#string expires.
|
63
|
+
|
64
|
+
def self.license_expiration_date
|
65
|
+
Date.parse(with_mdaddr { |h_addr_lib| mdAddrGetLicenseExpirationDate(h_addr_lib) })
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.days_until_license_expiration
|
69
|
+
#I compare Date objects. I think it is more accurate.
|
70
|
+
#self.license_expiration_date returns string in format: "YYYY-MM-DD"
|
71
|
+
(self.license_expiration_date - Date.today).to_i
|
72
|
+
end
|
73
|
+
|
74
|
+
# U.S. Only — This function returns a date value representing the
|
75
|
+
# date when the current U.S. data files expire. This date enables you to confirm that the
|
76
|
+
# data files you are using are the latest available.
|
77
|
+
|
78
|
+
def self.data_expiration_date
|
79
|
+
Date.strptime(with_mdaddr { |h_addr_lib| mdAddrGetExpirationDate(h_addr_lib) }, '%m-%d-%Y')
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.days_until_data_expiration
|
83
|
+
(self.data_expiration_date - Date.today).to_i
|
84
|
+
end
|
85
|
+
|
86
|
+
def initialize(opts)
|
87
|
+
self.class.with_mdaddr do |h_addr_lib|
|
88
|
+
# clear any properties from a previous call
|
89
|
+
mdAddrClearProperties(h_addr_lib)
|
90
|
+
|
91
|
+
mdAddrSetCompany(h_addr_lib, opts[:company] || '');
|
92
|
+
mdAddrSetAddress(h_addr_lib, opts[:address] || '');
|
93
|
+
mdAddrSetAddress2(h_addr_lib, opts[:address2] || '');
|
94
|
+
mdAddrSetSuite(h_addr_lib, opts[:suite] || '');
|
95
|
+
mdAddrSetCity(h_addr_lib, opts[:city] || '');
|
96
|
+
mdAddrSetState(h_addr_lib, opts[:state] || '');
|
97
|
+
mdAddrSetZip(h_addr_lib, opts[:zip] || '');
|
98
|
+
mdAddrSetUrbanization(h_addr_lib, opts[:urbanization] || '');
|
99
|
+
mdAddrSetCountryCode(h_addr_lib, opts[:country_code] || '');
|
100
|
+
mdAddrVerifyAddress(h_addr_lib);
|
101
|
+
|
102
|
+
@resultcodes = mdAddrGetResults(h_addr_lib).split(',')
|
103
|
+
fill_attributes(h_addr_lib)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def valid?
|
108
|
+
# Make sure there is at least 1 good code and no bad codes
|
109
|
+
(@resultcodes & @@good_codes).present? && (@resultcodes & @@bad_codes).empty?
|
110
|
+
end
|
111
|
+
rescue LoadError => e
|
112
|
+
Melissa.config.addr_obj_lib_loaded = false
|
113
|
+
else
|
114
|
+
Melissa.config.addr_obj_lib_loaded = true
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# Fake out Melissa data in Dev and Test environments. For local tests, and for Release and Hotfix
|
2
|
+
module Melissa
|
3
|
+
class AddrObjMock < AddrObj
|
4
|
+
|
5
|
+
# Since we're faking it, create accessors that just return the corresponding opts value except the ones we dummy in the ctor
|
6
|
+
@@melissa_attributes.each do |name|
|
7
|
+
name = name.underscore
|
8
|
+
class_eval <<-EOS
|
9
|
+
define_method(:#{name}) do
|
10
|
+
@#{name} ||= (@opts[:#{name}] || nil)
|
11
|
+
end
|
12
|
+
EOS
|
13
|
+
end
|
14
|
+
|
15
|
+
#Mock
|
16
|
+
def initialize(opts)
|
17
|
+
@opts = opts
|
18
|
+
#@urbanization = opts[:urbanization] || ''
|
19
|
+
@resultcodes = ['AS01']
|
20
|
+
@address_type_string = 'Street'
|
21
|
+
end
|
22
|
+
|
23
|
+
#Mock
|
24
|
+
def delivery_point_code
|
25
|
+
point_code = nil
|
26
|
+
point_code = self.zip[3..5] if self.zip.present?
|
27
|
+
return point_code
|
28
|
+
end
|
29
|
+
|
30
|
+
#Mock
|
31
|
+
def delivery_point_check_digit
|
32
|
+
self.city && (self.city.sum % 10).to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
#Mock
|
36
|
+
def plus4
|
37
|
+
return '1234'
|
38
|
+
end
|
39
|
+
|
40
|
+
#Mock
|
41
|
+
def valid?
|
42
|
+
#we will mock delivery point if zip code is present.
|
43
|
+
return self.zip.present?
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Melissa
|
4
|
+
|
5
|
+
MODES = [:mock, :live]
|
6
|
+
|
7
|
+
class Config
|
8
|
+
|
9
|
+
attr_accessor :mode, :license, :data_path, :addr_obj_lib, :addr_obj_lib_loaded
|
10
|
+
attr_accessor :geo_point_lib, :geo_point_lib_loaded
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
#It is recommended to read the following config options from environment variables
|
14
|
+
#From Melissa Data documentation:
|
15
|
+
#The license string should be entered as an environment variable named
|
16
|
+
#MD_LICENSE. This allows you to update your license string without editing
|
17
|
+
#and recompiling your code
|
18
|
+
|
19
|
+
self.config_path = ENV['MELISSA_CONFIG_PATH'] if ENV['MELISSA_CONFIG_PATH']
|
20
|
+
self.home = ENV['MELISSA_HOME'] if ENV['MELISSA_HOME']
|
21
|
+
@data_path = ENV['MELISSA_DATA_PATH'] if ENV['MELISSA_DATA_PATH']
|
22
|
+
@addr_obj_lib = ENV['MELISSA_ADDR_OBJ_LIB'] if ENV['MELISSA_ADDR_OBJ_LIB']
|
23
|
+
@geo_point_lib = ENV['MELISSA_GEO_POINT_LIB'] if ENV['MELISSA_GEO_POINT_LIB']
|
24
|
+
@license = ENV['MD_LICENSE'] if ENV['MD_LICENSE']
|
25
|
+
end
|
26
|
+
|
27
|
+
#you can configure config_path from your code using:
|
28
|
+
# Melissa.configure do |config|
|
29
|
+
# config.config_path = "/etc/config/melissa"
|
30
|
+
# end
|
31
|
+
def config_path=(config_path)
|
32
|
+
File.open(config_path, 'r') do |fin|
|
33
|
+
fin.each do |line|
|
34
|
+
line.strip!
|
35
|
+
next if line.empty? || line[0] == '#'
|
36
|
+
equal_index = line.index('=')
|
37
|
+
key = line[0, equal_index].strip.downcase
|
38
|
+
value = line[(equal_index+1)..-1].strip
|
39
|
+
send("#{key}=", value)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
rescue Errno::ENOENT
|
43
|
+
raise "Configuration file couldn't be found. We need #{config_path}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def home=(home)
|
47
|
+
@addr_obj_lib = "#{home}/AddrObj/libmdAddr.so"
|
48
|
+
@geo_point_lib = "#{home}/GeoObj/libmdGeo.so"
|
49
|
+
@data_path = "#{home}/data"
|
50
|
+
end
|
51
|
+
|
52
|
+
def addr_obj_lib_loaded=(value)
|
53
|
+
@addr_obj_lib_loaded = value
|
54
|
+
@mode ||= :live if value
|
55
|
+
end
|
56
|
+
|
57
|
+
def geo_point_library_loaded=(value)
|
58
|
+
@geo_point_lib_loaded = value
|
59
|
+
@mode ||= :live if value
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require "melissa/config"
|
2
|
+
|
3
|
+
module Melissa
|
4
|
+
class GeoPoint
|
5
|
+
@@melissa_attributes = %w(
|
6
|
+
Latitude
|
7
|
+
Longitude
|
8
|
+
CensusTract
|
9
|
+
CensusBlock
|
10
|
+
CountyFips
|
11
|
+
CountyName
|
12
|
+
PlaceCode
|
13
|
+
PlaceName
|
14
|
+
TimeZoneCode
|
15
|
+
TimeZone
|
16
|
+
CBSACode
|
17
|
+
CBSATitle
|
18
|
+
CBSALevel
|
19
|
+
CBSADivisionCode
|
20
|
+
CBSADivisionTitle
|
21
|
+
CBSADivisionLevel
|
22
|
+
)
|
23
|
+
|
24
|
+
@@codes = {
|
25
|
+
'GS01' => 'Record was coded to the ZIP + 4 centroid (U.S.) or or the full 6-digit Postal Code level (Canada).',
|
26
|
+
'GS02' => 'Record was coded to the ZIP + 2 centroid.',
|
27
|
+
'GS03' => 'Record was coded to the 5-digit ZIP Code centroid (U.S.) or or the first 3-digit Postal Code level (Canada).',
|
28
|
+
'GS05' => 'Record was coded to rooftop level.(Available On-Premise only)',
|
29
|
+
'GS06' => 'Record was coded to interpolated rooftop level.(Available On-Premise only)*',
|
30
|
+
'GE01' => 'ZIP Code Error. An invalid ZIP Code was entered.',
|
31
|
+
'GE02' => 'ZIP Code not found. The submitted ZIP Code was not found in the database.',
|
32
|
+
'GE03' => 'Demo Mode. GeoCoder Object is in Demo Mode and a ZIP Code outside the demo range was detected.',
|
33
|
+
'GE04' => 'The GeoCoder Object data files are expired. Please update with the latest data files.',
|
34
|
+
'GE05' => 'Geocoding for the country of input record is disabled for your license. Please contact your sales representative to enable.',
|
35
|
+
}
|
36
|
+
|
37
|
+
# See http://www.melissadata.com/lookups/resultcodes.asp
|
38
|
+
@@good_codes = ['GS01', 'GS02', 'GS03', 'GS05', 'GS06']
|
39
|
+
#@@bad_codes = ['GE01', 'GE02']
|
40
|
+
@@fatal_codes = ['GE03', 'GE04', 'GE05']
|
41
|
+
|
42
|
+
@@time_zones = {
|
43
|
+
'04' => 'Atlantic/Bermuda',
|
44
|
+
'05' => 'US/Eastern',
|
45
|
+
'06' => 'US/Central',
|
46
|
+
'07' => 'US/Mountain',
|
47
|
+
'08' => 'US/Pacific',
|
48
|
+
'09' => 'US/Alaska',
|
49
|
+
'10' => 'US/Hawaii',
|
50
|
+
'11' => 'US/Samoa',
|
51
|
+
'13' => 'Pacific/Majuro',
|
52
|
+
'14' => 'Pacific/Guam',
|
53
|
+
'15' => 'Pacific/Palau'
|
54
|
+
}
|
55
|
+
|
56
|
+
def valid?
|
57
|
+
# Make sure there is at least 1 good code
|
58
|
+
@is_valid
|
59
|
+
end
|
60
|
+
|
61
|
+
def time_zone_offset
|
62
|
+
GeoPoint.time_zone_offset(self.time_zone_code, @addr_obj.state)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Hack for AddrObj to share code
|
66
|
+
def self.time_zone_offset(time_zone_code, state=nil)
|
67
|
+
time_zone = @@time_zones[time_zone_code]
|
68
|
+
return nil unless time_zone
|
69
|
+
time_zone = 'US/Arizona' if state == 'AZ'
|
70
|
+
return Time.now.in_time_zone(time_zone).utc_offset / -60
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module Melissa
|
4
|
+
class GeoPointLive < GeoPoint
|
5
|
+
extend FFI::Library
|
6
|
+
|
7
|
+
begin
|
8
|
+
ffi_lib Melissa.config.geo_point_lib
|
9
|
+
attr_functions = @@melissa_attributes.map { |name| ["mdGeoGet#{name}".to_sym, [:pointer], :string] }
|
10
|
+
|
11
|
+
functions = attr_functions + [
|
12
|
+
# method # parameters # return
|
13
|
+
[:mdGeoCreate, [], :pointer],
|
14
|
+
[:mdGeoSetLicenseString, [:pointer, :string], :int],
|
15
|
+
[:mdGeoSetPathToGeoCodeDataFiles, [:pointer, :string], :void],
|
16
|
+
[:mdGeoSetPathToGeoPointDataFiles, [:pointer, :string], :void],
|
17
|
+
[:mdGeoInitializeDataFiles, [:pointer], :int],
|
18
|
+
[:mdGeoGeoPoint, [:pointer, :string, :string, :string], :int],
|
19
|
+
[:mdGeoGetResults, [:pointer], :string],
|
20
|
+
[:mdGeoDestroy, [:pointer], :void],
|
21
|
+
[:mdGeoGetLicenseExpirationDate, [:pointer], :string],
|
22
|
+
[:mdGeoGetExpirationDate, [:pointer], :string],
|
23
|
+
]
|
24
|
+
|
25
|
+
functions.each do |func|
|
26
|
+
begin
|
27
|
+
attach_function(*func)
|
28
|
+
rescue Object => e
|
29
|
+
raise "Could not attach #{func}, #{e.message}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_reader *@@melissa_attributes.map { |name| name.underscore.to_sym }
|
34
|
+
|
35
|
+
# Get all the attributes out up-front so we can destroy the mdGeo object
|
36
|
+
class_eval <<-EOS
|
37
|
+
define_method(:fill_attributes) do |mdGeo|
|
38
|
+
#{@@melissa_attributes.map { |name| "@#{name.underscore} = mdGeoGet#{name}(mdGeo)" }.join("\n")}
|
39
|
+
end
|
40
|
+
EOS
|
41
|
+
|
42
|
+
def self.with_mdgeo
|
43
|
+
mdGeo = mdGeoCreate
|
44
|
+
mdGeoSetLicenseString(mdGeo, Melissa.config.license)
|
45
|
+
mdGeoSetPathToGeoCodeDataFiles(mdGeo, Melissa.config.data_path)
|
46
|
+
mdGeoSetPathToGeoPointDataFiles(mdGeo, Melissa.config.data_path)
|
47
|
+
result = mdGeoInitializeDataFiles(mdGeo)
|
48
|
+
if result != 0
|
49
|
+
raise mdGeoGetInitializeErrorString(mdGeo)
|
50
|
+
end
|
51
|
+
yield mdGeo
|
52
|
+
ensure
|
53
|
+
mdGeoDestroy(mdGeo) if mdGeo
|
54
|
+
end
|
55
|
+
|
56
|
+
#This function returns a date value corresponding to the date when the current license
|
57
|
+
#string expires.
|
58
|
+
def self.license_expiration_date
|
59
|
+
Date.parse(with_mdgeo { |mdGeo| mdGeoGetLicenseExpirationDate(mdGeo) })
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.days_until_license_expiration
|
63
|
+
#I compare Date objects. I think it is more accurate.
|
64
|
+
#self.license_expiration_date returns string in format: "YYYY-MM-DD"
|
65
|
+
(self.license_expiration_date - Date.today).to_i
|
66
|
+
end
|
67
|
+
|
68
|
+
# his function returns a date value representing the
|
69
|
+
# date when the current data files expire. This date enables you to confirm that the
|
70
|
+
# data files you are using are the latest available.
|
71
|
+
def self.expiration_date
|
72
|
+
Date.parse(with_mdgeo { |mdGeo| mdGeoGetExpirationDate(mdGeo)})
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.days_until_data_expiration
|
76
|
+
#I compare Date objects. I think it is more accurate.
|
77
|
+
#self.license_expiration_date returns string in format: "YYYY-MM-DD"
|
78
|
+
(self.expiration_date - Date.today).to_i
|
79
|
+
end
|
80
|
+
|
81
|
+
def initialize(opts)
|
82
|
+
@is_valid = false
|
83
|
+
|
84
|
+
self.class.with_mdgeo do |mdGeo|
|
85
|
+
if opts.kind_of?(AddrObj)
|
86
|
+
mdGeoGeoPoint(mdGeo, opts.zip || '', opts.plus4 || '', opts.delivery_point_code || '')
|
87
|
+
elsif opts.kind_of?(Hash)
|
88
|
+
mdGeoGeoPoint(mdGeo, opts[:zip] || '', opts[:plus4] || '', opts[:delivery_point_code] || '')
|
89
|
+
else
|
90
|
+
raise "Invalid call to GeoPoint, unknown object #{opts.inspect}"
|
91
|
+
end
|
92
|
+
@resultcodes = mdGeoGetResults(mdGeo).split(',')
|
93
|
+
fatals = @resultcodes & @@fatal_codes
|
94
|
+
@is_valid = fatals.blank?
|
95
|
+
if @is_valid
|
96
|
+
fill_attributes(mdGeo)
|
97
|
+
# Convert from strings to actual types
|
98
|
+
if @latitude.blank?
|
99
|
+
@latitude = nil
|
100
|
+
else
|
101
|
+
@latitude = @latitude.to_f
|
102
|
+
end
|
103
|
+
if @longitude.blank?
|
104
|
+
@longitude = nil
|
105
|
+
else
|
106
|
+
@longitude = @longitude.to_f
|
107
|
+
end
|
108
|
+
if @latitude == 0.0 && @longitude == 0.0
|
109
|
+
@latitude = nil
|
110
|
+
@longitude = nil
|
111
|
+
@is_valid = false
|
112
|
+
end
|
113
|
+
else
|
114
|
+
fatals.each do |fatal_code|
|
115
|
+
raise "FATAL ERROR Melissa GeoPoint returned #{fatal_code}-#{@@codes[fatal_code]}"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
rescue LoadError => e
|
121
|
+
Melissa.config.geo_point_library_loaded = false
|
122
|
+
else
|
123
|
+
Melissa.config.geo_point_library_loaded = true
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Melissa
|
2
|
+
class GeoPointMock < GeoPoint
|
3
|
+
# Since we're faking it, create accessors that just return the corresponding opts value except the ones we dummy in the ctor
|
4
|
+
@@melissa_attributes.each do |name|
|
5
|
+
name = name.underscore
|
6
|
+
class_eval <<-EOS
|
7
|
+
define_method(:#{name}) do
|
8
|
+
@#{name} ||= (@opts[:#{name}] || '')
|
9
|
+
end
|
10
|
+
EOS
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(addr_obj)
|
14
|
+
@is_valid = false
|
15
|
+
|
16
|
+
if addr_obj.kind_of?(AddrObj)
|
17
|
+
@addr_obj = addr_obj
|
18
|
+
else
|
19
|
+
raise "Invalid call to GeoPoint, unknown object #{addr_obj.inspect}"
|
20
|
+
end
|
21
|
+
@latitude = 36.20687
|
22
|
+
@longitude = -115.27857
|
23
|
+
@time_zone_code = '08'
|
24
|
+
@resultcodes = ['AS01']
|
25
|
+
@is_valid = true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Melissa
|
2
|
+
class Railtie < Rails::Railtie #:nodoc:
|
3
|
+
# Make the Melissa config available in the Rails application config
|
4
|
+
config.before_configuration do
|
5
|
+
config_file = Rails.root.join('config', 'melissa.txt')
|
6
|
+
if config_file.file?
|
7
|
+
Melissa.config.config_path = config_file
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/melissa.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/melissa/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ['Brad Pardee', 'Svetlana Marinskaya']
|
6
|
+
gem.email = ['bradpardee@gmail.com', 'svetlana.marinskaya@gmail.com']
|
7
|
+
gem.description = %q{Configurable interface to Melissa Data Address and GeoPoint objects}
|
8
|
+
gem.summary = %q{Melissa allows you to use ruby wrappers for Melissa Data's AddrObj and GeoPoint objects or use the mock objects depending on configuration.}
|
9
|
+
gem.homepage = "https://github.com/smarinskaya/Melissa"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "melissa"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Melissa::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency 'activesupport' # added to support underscore method.
|
19
|
+
gem.add_dependency 'minitest' # added as a dependency of activesupport and for testing.
|
20
|
+
gem.add_dependency 'ffi' #used for converting c libraries to ruby
|
21
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class AddrObjTest < Minitest::Test
|
4
|
+
describe Melissa::AddrObj do
|
5
|
+
|
6
|
+
describe "live mode" do
|
7
|
+
before do
|
8
|
+
Melissa.config.mode = :live if Melissa.config.addr_obj_lib_loaded
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "valid?" do
|
12
|
+
it 'handles valid data' do
|
13
|
+
skip "Not run in mock mode" unless Melissa.config.mode == :live
|
14
|
+
valid_address = Melissa.addr_obj(
|
15
|
+
:address => '2517 Surfwood Dr',
|
16
|
+
:city => 'Las Vegas',
|
17
|
+
:state => 'NV',
|
18
|
+
:zip => '89128'
|
19
|
+
)
|
20
|
+
assert valid_address.valid?
|
21
|
+
assert_equal '2517 Surfwood Dr', valid_address.address
|
22
|
+
assert_equal 'Las Vegas', valid_address.city
|
23
|
+
assert_equal '89128718217', valid_address.delivery_point
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'flags invalid data' do
|
27
|
+
skip "Not run in mock mode" unless Melissa.config.mode == :live
|
28
|
+
# Zip points to Schenectady, NY
|
29
|
+
invalid_address = Melissa.addr_obj(
|
30
|
+
:address => '123 Who Dr',
|
31
|
+
:city => 'WhoVille',
|
32
|
+
:state => 'IN',
|
33
|
+
:zip => '12345'
|
34
|
+
)
|
35
|
+
assert !invalid_address.valid?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "delivery_point" do
|
40
|
+
it 'sets delivery point for valid data' do
|
41
|
+
skip "Not run in mock mode" unless Melissa.config.mode == :live
|
42
|
+
valid_address = Melissa.addr_obj(
|
43
|
+
:address => '2517 Surfwood Dr',
|
44
|
+
:city => 'Las Vegas',
|
45
|
+
:state => 'NV',
|
46
|
+
:zip => '89128'
|
47
|
+
)
|
48
|
+
assert_equal '89128718217', valid_address.delivery_point
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe 'number of days till licence expires' do
|
53
|
+
it 'checks if we have more than 30 days till license expiration date' do
|
54
|
+
skip "Not run in mock mode" unless Melissa.config.mode == :live
|
55
|
+
valid_address = Melissa.addr_obj(
|
56
|
+
:address => '2517 Surfwood Dr',
|
57
|
+
:city => 'Las Vegas',
|
58
|
+
:state => 'NV',
|
59
|
+
:zip => '89128'
|
60
|
+
)
|
61
|
+
assert_operator 30, :<, valid_address.class.days_until_license_expiration
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "mock mode" do
|
67
|
+
before do
|
68
|
+
Melissa.config.mode = :mock
|
69
|
+
end
|
70
|
+
describe "valid?" do
|
71
|
+
it 'handles valid data' do
|
72
|
+
valid_address = Melissa.addr_obj(
|
73
|
+
:address => '9802 Brompton Dr',
|
74
|
+
:city => 'Tampa',
|
75
|
+
:state => 'Fl',
|
76
|
+
:zip => '33626'
|
77
|
+
)
|
78
|
+
assert valid_address.valid?
|
79
|
+
assert_equal '9802 Brompton Dr', valid_address.address
|
80
|
+
assert_equal 'Tampa', valid_address.city
|
81
|
+
assert_equal '33626123426', valid_address.delivery_point
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'flags invalid data' do
|
85
|
+
# Zip points to Schenectady, NY
|
86
|
+
invalid_address = Melissa.addr_obj(
|
87
|
+
:address => '123 Who Dr',
|
88
|
+
:city => 'WhoVille',
|
89
|
+
:state => 'IN',
|
90
|
+
:zip => ''
|
91
|
+
)
|
92
|
+
assert !invalid_address.valid?
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "delivery_point" do
|
97
|
+
it 'sets delivery point for valid data' do
|
98
|
+
valid_address = Melissa.addr_obj(
|
99
|
+
:address => '9802 Brompton Dr',
|
100
|
+
:city => 'Tampa',
|
101
|
+
:state => 'Fl',
|
102
|
+
:zip => '33626'
|
103
|
+
)
|
104
|
+
assert_equal '33626123426', valid_address.delivery_point
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
#require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class GeoPointTest < Minitest::Test
|
5
|
+
|
6
|
+
describe Melissa::GeoPoint do
|
7
|
+
before do
|
8
|
+
Melissa.config.mode = :live if Melissa.config.addr_obj_lib_loaded
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'valid?' do
|
12
|
+
it 'creates valid GeoPoint object from valid Address Object' do
|
13
|
+
skip "Not run in mock mode" unless Melissa.config.mode == :live
|
14
|
+
valid_addr_obj = Melissa.addr_obj(
|
15
|
+
:address => '2517 SURFWOOD DR',
|
16
|
+
:city => 'LAS VEGAS',
|
17
|
+
:state => 'NV',
|
18
|
+
:zip => '89128'
|
19
|
+
)
|
20
|
+
geo_point_obj = Melissa.geo_point(valid_addr_obj)
|
21
|
+
assert geo_point_obj.valid?
|
22
|
+
assert_includes 36.2..36.3, geo_point_obj.latitude
|
23
|
+
assert_includes -115.3..-115.2, geo_point_obj.longitude
|
24
|
+
# offset = Time.now.in_time_zone('US/Eastern').dst? ? 240 : 300
|
25
|
+
# assert_equal offset, geo_point.time_zone_offset
|
26
|
+
#For the address above:
|
27
|
+
#g.time_zone_offset
|
28
|
+
#=> 480
|
29
|
+
end
|
30
|
+
it 'creates valid GeoPoint object from the Hash' do
|
31
|
+
skip "Not run in mock mode" unless Melissa.config.mode == :live
|
32
|
+
geo_point_obj= Melissa.geo_point(
|
33
|
+
:zip => '89128',
|
34
|
+
:plus4 => '7182',
|
35
|
+
:delivery_point_code => '17'
|
36
|
+
)
|
37
|
+
|
38
|
+
assert geo_point_obj.valid?
|
39
|
+
assert_includes 36.2..36.3, geo_point_obj.latitude
|
40
|
+
assert_includes -115.3..-115.2, geo_point_obj.longitude
|
41
|
+
# offset = Time.now.in_time_zone('US/Eastern').dst? ? 240 : 300
|
42
|
+
# assert_equal offset, geo_point.time_zone_offset
|
43
|
+
#For the address above:
|
44
|
+
#g.time_zone_offset
|
45
|
+
#=> 480
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'number of days till licence expires' do
|
50
|
+
it 'checks if we have more than 30 days till license expiration date' do
|
51
|
+
skip "Not run in mock mode" unless Melissa.config.mode == :live
|
52
|
+
valid_addr_obj = Melissa.addr_obj(
|
53
|
+
:address => '2517 SURFWOOD DR',
|
54
|
+
:city => 'LAS VEGAS',
|
55
|
+
:state => 'NV',
|
56
|
+
:zip => '89128'
|
57
|
+
)
|
58
|
+
geo_point = Melissa.geo_point(valid_addr_obj)
|
59
|
+
assert_operator 30, :<, geo_point.class.days_until_license_expiration
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class MelissaTest < Minitest::Test
|
4
|
+
|
5
|
+
describe 'Melissa.addr_obj' do
|
6
|
+
before do
|
7
|
+
Melissa.config.mode = :live if Melissa.config.addr_obj_lib_loaded
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "live mode" do
|
11
|
+
it 'initializes AddrObjLive object' do
|
12
|
+
skip "Not run in mock mode" unless Melissa.config.mode == :live
|
13
|
+
valid_address = Melissa.addr_obj(
|
14
|
+
:address => '9802 Brompton Dr',
|
15
|
+
:city => 'Tampa',
|
16
|
+
:state => 'Fl',
|
17
|
+
:zip => '33626'
|
18
|
+
)
|
19
|
+
assert_kind_of Melissa::AddrObjLive, valid_address
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "mock mode" do
|
24
|
+
before do
|
25
|
+
Melissa.config.mode = :mock
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'initializes AddrObjMock object' do
|
29
|
+
valid_address = Melissa.addr_obj(
|
30
|
+
:address => '9802 Brompton Dr',
|
31
|
+
:city => 'Tampa',
|
32
|
+
:state => 'Fl',
|
33
|
+
:zip => '33626'
|
34
|
+
)
|
35
|
+
assert_kind_of Melissa::AddrObjMock, valid_address
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe 'Melissa.geo_point' do
|
41
|
+
before do
|
42
|
+
Melissa.config.mode = :live if Melissa.config.addr_obj_lib_loaded
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "live mode" do
|
46
|
+
it 'initializes GeoPointLive object' do
|
47
|
+
skip "Not run in mock mode" unless Melissa.config.mode == :live
|
48
|
+
valid_addr_obj = Melissa.addr_obj(
|
49
|
+
:address => '9802 Brompton Dr',
|
50
|
+
:city => 'Tampa',
|
51
|
+
:state => 'Fl',
|
52
|
+
:zip => '33626'
|
53
|
+
)
|
54
|
+
geo_point_obj = Melissa.geo_point(valid_addr_obj)
|
55
|
+
assert_kind_of Melissa::GeoPointLive, geo_point_obj
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "mock mode" do
|
60
|
+
before do
|
61
|
+
Melissa.config.mode = :mock
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'initializes GeoPointMock object' do
|
65
|
+
valid_addr_obj = Melissa.addr_obj(
|
66
|
+
:address => '9802 Brompton Dr',
|
67
|
+
:city => 'Tampa',
|
68
|
+
:state => 'Fl',
|
69
|
+
:zip => '33626'
|
70
|
+
)
|
71
|
+
geo_point_obj = Melissa.geo_point(valid_addr_obj)
|
72
|
+
assert_kind_of Melissa::GeoPointMock, geo_point_obj
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: melissa
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brad Pardee
|
8
|
+
- Svetlana Marinskaya
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-04-17 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activesupport
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: minitest
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: ffi
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :runtime
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
description: Configurable interface to Melissa Data Address and GeoPoint objects
|
57
|
+
email:
|
58
|
+
- bradpardee@gmail.com
|
59
|
+
- svetlana.marinskaya@gmail.com
|
60
|
+
executables: []
|
61
|
+
extensions: []
|
62
|
+
extra_rdoc_files: []
|
63
|
+
files:
|
64
|
+
- ".gitignore"
|
65
|
+
- ".jruby-version"
|
66
|
+
- ".ruby-version"
|
67
|
+
- Gemfile
|
68
|
+
- Gemfile.lock
|
69
|
+
- LICENSE
|
70
|
+
- README.md
|
71
|
+
- Rakefile
|
72
|
+
- config/melissa
|
73
|
+
- lib/melissa.rb
|
74
|
+
- lib/melissa/addr_obj.rb
|
75
|
+
- lib/melissa/addr_obj_live.rb
|
76
|
+
- lib/melissa/addr_obj_mock.rb
|
77
|
+
- lib/melissa/config.rb
|
78
|
+
- lib/melissa/geo_point.rb
|
79
|
+
- lib/melissa/geo_point_live.rb
|
80
|
+
- lib/melissa/geo_point_mock.rb
|
81
|
+
- lib/melissa/railtie.rb
|
82
|
+
- lib/melissa/version.rb
|
83
|
+
- melissa.gemspec
|
84
|
+
- test/addr_obj_test.rb
|
85
|
+
- test/geo_point_test.rb
|
86
|
+
- test/melissa_test.rb
|
87
|
+
- test/test_helper.rb
|
88
|
+
homepage: https://github.com/smarinskaya/Melissa
|
89
|
+
licenses: []
|
90
|
+
metadata: {}
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
requirements: []
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 2.2.2
|
108
|
+
signing_key:
|
109
|
+
specification_version: 4
|
110
|
+
summary: Melissa allows you to use ruby wrappers for Melissa Data's AddrObj and GeoPoint
|
111
|
+
objects or use the mock objects depending on configuration.
|
112
|
+
test_files:
|
113
|
+
- test/addr_obj_test.rb
|
114
|
+
- test/geo_point_test.rb
|
115
|
+
- test/melissa_test.rb
|
116
|
+
- test/test_helper.rb
|