melissa 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|