melissadata 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/Gemfile +31 -0
  2. data/Gemfile.lock +69 -0
  3. data/Guardfile +6 -0
  4. data/README.md +5 -0
  5. data/Rakefile +47 -0
  6. data/Vagrantfile +17 -0
  7. data/bin/md +4 -0
  8. data/bin/md-rpc +9 -0
  9. data/bin/md-server +18 -0
  10. data/bin/melissadata +4 -0
  11. data/lib/md.rb +4 -0
  12. data/lib/melissadata.rb +2 -0
  13. data/lib/melissadata/cli.rb +45 -0
  14. data/lib/melissadata/command.rb +9 -0
  15. data/lib/melissadata/command/base.rb +104 -0
  16. data/lib/melissadata/command/helpers.rb +12 -0
  17. data/lib/melissadata/command/package.rb +83 -0
  18. data/lib/melissadata/constants.rb +14 -0
  19. data/lib/melissadata/env.rb +92 -0
  20. data/lib/melissadata/errors.rb +83 -0
  21. data/lib/melissadata/melissadata.rb +164 -0
  22. data/lib/melissadata/native_object.rb +19 -0
  23. data/lib/melissadata/native_object/address.rb +124 -0
  24. data/lib/melissadata/native_object/base.rb +79 -0
  25. data/lib/melissadata/native_object/client.rb +33 -0
  26. data/lib/melissadata/native_object/email.rb +61 -0
  27. data/lib/melissadata/native_object/geo.rb +61 -0
  28. data/lib/melissadata/native_object/ip_locator.rb +41 -0
  29. data/lib/melissadata/native_object/name.rb +74 -0
  30. data/lib/melissadata/native_object/phone.rb +96 -0
  31. data/lib/melissadata/prev/command_old.rb +80 -0
  32. data/lib/melissadata/prev/shared_objects.rb +54 -0
  33. data/lib/melissadata/rpc.rb +39 -0
  34. data/lib/melissadata/version.rb +3 -0
  35. data/melissadata.gemspec +40 -0
  36. data/pkg/melissa-data-0.0.1.gem +0 -0
  37. data/pkg/melissa-data-0.0.2.gem +0 -0
  38. data/pkg/melissa-data-0.0.3.gem +0 -0
  39. data/pkg/melissadata-0.0.1.gem +0 -0
  40. data/spec/locales/en.yml +8 -0
  41. data/spec/melissadata/cli_spec.rb +34 -0
  42. data/spec/melissadata/command/package_spec.rb +22 -0
  43. data/spec/melissadata/env_spec.rb +55 -0
  44. data/spec/spec_helper.rb +33 -0
  45. data/templates/config.rb +20 -0
  46. data/templates/locales/en.yml +4 -0
  47. metadata +316 -0
@@ -0,0 +1,14 @@
1
+ module MelissaData
2
+ # Constants used by the system to access data.
3
+ module Constants
4
+ # Default execution address
5
+ DEFAULT_ADDRESS = '0.0.0.0'
6
+
7
+ # Default execution port
8
+ DEFAULT_PORT = 6000
9
+ end
10
+ end
11
+
12
+ module MelissaData
13
+ include Constants
14
+ end
@@ -0,0 +1,92 @@
1
+ module MelissaData
2
+ # MelissaData::Env also provides access to the logger, configuration information
3
+ # and anything else set into the config data during initialization.
4
+ class Env < Hash
5
+ include Constants
6
+
7
+ # Create a new MelissaData::Env object
8
+ #
9
+ # @return [MelissaData::Env] The MelissaData::Env object
10
+ def initialize
11
+ self[:start_time] = Time.now.to_f
12
+ self[:time] = Time.now.to_f
13
+ self[:trace] = []
14
+ end
15
+
16
+ # Add a trace timer with the given name into the environment. The tracer will
17
+ # provide information on the amount of time since the previous call to {#trace}
18
+ # or since the MelissaData::Env object was initialized.
19
+ #
20
+ # @example
21
+ # trace("initialize hash")
22
+ # ....
23
+ # trace("Do something else")
24
+ #
25
+ # @param name [String] The name of the trace to add
26
+ def trace(name)
27
+ self[:trace].push([name, "%.2f" % ((Time.now.to_f - self[:time]) * 1000)])
28
+ self[:time] = Time.now.to_f
29
+ end
30
+
31
+ # Retrieve the tracer stats for this request environment. This can then be
32
+ # returned in the headers hash to in development to provide some simple
33
+ # timing information for the various API components.
34
+ #
35
+ # @example
36
+ # [200, {}, {:meta => {:trace => env.trace_stats}}, {}]
37
+ #
38
+ # @return [Array] Array of [name, time] pairs with a Total entry added.
39
+ def trace_stats
40
+ self[:trace] + [['total', self[:trace].collect { |s| s[1].to_f }.inject(:+).to_s]]
41
+ end
42
+
43
+ # Convenience method for accessing the rack.logger item in the environment.
44
+ #
45
+ # @return [Logger] The logger object
46
+ def logger
47
+ return @logger if @logger
48
+
49
+ # Figure out where the output should go to.
50
+ output = nil
51
+ if ENV["MELISSADATA_LOG"] == "STDOUT"
52
+ output = STDOUT
53
+ elsif ENV["MELISSADATA_LOG"] == "NULL"
54
+ output = nil
55
+ elsif ENV["MELISSADATA_LOG"]
56
+ output = ENV["MELISSADATA_LOG"]
57
+ else
58
+ output = nil #log_path.join("#{Time.now.to_i}.log")
59
+ end
60
+
61
+ # Create the logger and custom formatter
62
+ @logger = Logger.new(output)
63
+ @logger.formatter = Proc.new do |severity, datetime, progname, msg|
64
+ "#{datetime} - #{progname} - [#{resource}] #{msg}\n"
65
+ end
66
+
67
+ @logger
68
+ end
69
+
70
+ # @param name [Symbol] The method to check if we respond to it.
71
+ # @return [Boolean] True if the Env responds to the method, false otherwise
72
+ def respond_to?(name)
73
+ return true if has_key?(name.to_s)
74
+ return true if self['config'] && self['config'].has_key?(name.to_s)
75
+ super
76
+ end
77
+
78
+ # The MelissaData::Env will provide any of it's keys as a method. It will also provide
79
+ # any of the keys in the config object as methods. The methods will return
80
+ # the value of the key. If the key doesn't exist in either hash this will
81
+ # fall back to the standard method_missing implementation.
82
+ #
83
+ # @param name [Symbol] The method to look for
84
+ # @param args The arguments
85
+ # @param blk A block
86
+ def method_missing(name, *args, &blk)
87
+ return self[name.to_s] if has_key?(name.to_s)
88
+ return self['config'][name.to_s] if self['config'] && self['config'].has_key?(name.to_s)
89
+ super(name, *args, &blk)
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,83 @@
1
+ # This file contains all of the internal errors in MelissaData's core
2
+ # commands, actions, etc.
3
+
4
+ module MelissaData
5
+ # This module contains all of the internal errors in MelissaData's core.
6
+ # These errors are _expected_ errors and as such don't typically represent
7
+ # bugs in MelissaData itself. These are meant as a way to detect errors and
8
+ # display them in a user-friendly way.
9
+ #
10
+ # # Defining a new Error
11
+ #
12
+ # To define a new error, inherit from {MelissaDataError}, which lets MelissaData
13
+ # know that this is an expected error, and also gives you some helpers for
14
+ # providing exit codes and error messages. An example is shown below, then
15
+ # it is explained:
16
+ #
17
+ # class MyError < MelissaData::Errors::MelissaDataError
18
+ # error_key "my_error"
19
+ # end
20
+ #
21
+ # This creates an error with an I18n error key of "my_error." {MelissaDataError}
22
+ # uses I18n to look up error messages, in the "melissadata.errors" namespace. So
23
+ # in the above, the error message would be the translation of "melissadata.errors.my_error"
24
+ #
25
+ # If you don't want to use I18n, you can override the {#initialize} method and
26
+ # set your own error message.
27
+ #
28
+ # # Raising an Error
29
+ #
30
+ # To raise an error, it is nothing special, just raise it like any normal
31
+ # exception:
32
+ #
33
+ # raise MyError.new
34
+ #
35
+ # Eventually this exception will bubble out to the `melissadata` binary which
36
+ # will show a nice error message. And if it is raised in the middle of a
37
+ # middleware sequence, then {Action::Warden} will catch it and begin the
38
+ # recovery process prior to exiting.
39
+ module Errors
40
+ # Main superclass of any errors in MelissaData. This provides some
41
+ # convenience methods for setting the error key. The error key is
42
+ # used as a default message from I18n.
43
+ class MelissaDataError < StandardError
44
+ def self.error_key(key=nil, namespace=nil)
45
+ define_method(:error_key) { key }
46
+ error_namespace(namespace) if namespace
47
+ end
48
+
49
+ def self.error_namespace(namespace)
50
+ define_method(:error_namespace) { namespace }
51
+ end
52
+
53
+ def initialize(message=nil, *args)
54
+ message = { :_key => message } if message && !message.is_a?(Hash)
55
+ message = { :_key => error_key, :_namespace => error_namespace }.merge(message || {})
56
+ message = translate_error(message)
57
+
58
+ super
59
+ end
60
+
61
+ # The default error namespace which is used for the error key.
62
+ # This can be overridden here or by calling the "error_namespace"
63
+ # class method.
64
+ def error_namespace; "melissadata.errors"; end
65
+
66
+ # The key for the error message. This should be set using the
67
+ # {error_key} method but can be overridden here if needed.
68
+ def error_key; nil; end
69
+
70
+ protected
71
+
72
+ def translate_error(opts)
73
+ return nil if !opts[:_key]
74
+ I18n.t("#{opts[:_namespace]}.#{opts[:_key]}", opts)
75
+ end
76
+ end
77
+
78
+ class DiscNotFound < MelissaDataError
79
+ error_key(:disc_not_found)
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,164 @@
1
+ $LOAD_PATH.unshift File.expand_path('..', File.dirname(__FILE__)) unless $LOAD_PATH.include?(File.expand_path('..', File.dirname(__FILE__)))
2
+ require 'pathname'
3
+ require 'i18n'
4
+ require 'thor'
5
+ require 'thor/group'
6
+ require 'thor/actions'
7
+ require 'active_support/core_ext'
8
+
9
+ module MelissaData
10
+ module_function
11
+
12
+ autoload :Env, 'melissadata/env'
13
+ autoload :CLI, 'melissadata/cli'
14
+ autoload :Errors, 'melissadata/errors'
15
+ autoload :Constants, 'melissadata/constants'
16
+
17
+ ENVIRONMENTS = [:development, :production, :test, :staging]
18
+
19
+ # Retrieves the current melissadata environment
20
+ #
21
+ # @return [String] the current environment
22
+ def env
23
+ @env or fail "environment has not been set"
24
+ end
25
+
26
+ # Sets the current melissadata environment
27
+ #
28
+ # @param [String|Symbol] env the environment symbol of [dev | development | prod | production | test]
29
+ def env=(e)
30
+ es = case(e.to_sym)
31
+ when :dev then :development
32
+ when :prod then :production
33
+ else e.to_sym
34
+ end
35
+
36
+ if ENVIRONMENTS.include?(es)
37
+ @env = es
38
+ else
39
+ fail "did not recognize environment: #{e}, expected one of: #{ENVIRONMENTS.join(', ')}"
40
+ end
41
+ end
42
+
43
+ # Determines if we are in the production environment
44
+ #
45
+ # @return [Boolean] true if current environment is production, false otherwise
46
+ def prod?
47
+ env == :production
48
+ end
49
+
50
+ # Determines if we are in the development environment
51
+ #
52
+ # @return [Boolean] true if current environment is development, false otherwise
53
+ def dev?
54
+ env == :development
55
+ end
56
+
57
+ # Determines if we are in the test environment
58
+ #
59
+ # @return [Boolean] true if current environment is test, false otherwise
60
+ def test?
61
+ env == :test
62
+ end
63
+
64
+ # Determines if we are in the staging environment
65
+ #
66
+ # @return [Boolean] true if current environment is staging.
67
+ def staging?
68
+ env == :staging
69
+ end
70
+
71
+ def gem_root
72
+ @gem_root ||= Pathname.new(File.expand_path('../../../', __FILE__))
73
+ end
74
+ end
75
+
76
+ I18n.load_path << File.expand_path("templates/locales/en.yml", MelissaData.gem_root)
77
+
78
+ require 'melissadata/command'
79
+ require 'melissadata/version'
80
+
81
+
82
+ # require 'rubygems'
83
+ # require 'active_support/core_ext'
84
+ # require 'melissadata/constants'
85
+ # require 'melissadata/commands'
86
+ # require 'melissadata/exceptions'
87
+
88
+ # module MelissaData
89
+ # module_function
90
+
91
+ # ENVIRONMENTS = [:development, :production, :vagrant, :test, :staging]
92
+
93
+ # # Retrieves the current MelissaData environment
94
+ # #
95
+ # # @return [String] the current environment
96
+ # def env
97
+ # @env or fail "environment has not been set"
98
+ # end
99
+
100
+ # # Sets the current MelissaData environment
101
+ # #
102
+ # # @param [String|Symbol] env the environment symbol of [dev | development | prod | production | test]
103
+ # def env=(e)
104
+ # es = case(e.to_sym)
105
+ # when :dev then :development
106
+ # when :prod then :production
107
+ # else e.to_sym
108
+ # end
109
+
110
+ # if ENVIRONMENTS.include?(es)
111
+ # @env = es
112
+ # else
113
+ # fail "did not recognize environment: #{e}, expected one of: #{ENVIRONMENTS.join(', ')}"
114
+ # end
115
+ # end
116
+
117
+ # def client=(c)
118
+ # @client = c
119
+ # end
120
+
121
+ # def client
122
+ # raise "Client has not yet been setup" if @client.nil?
123
+ # @client
124
+ # end
125
+
126
+ # def lib_path
127
+ # @lib_path ||= File.dirname(__FILE__)
128
+ # end
129
+
130
+ # # Determines if we are in the production environment
131
+ # #
132
+ # # @return [Boolean] true if current environment is production, false otherwise
133
+ # def prod?
134
+ # env == :production
135
+ # end
136
+
137
+ # # Determines if we are in the development environment
138
+ # #
139
+ # # @return [Boolean] true if current environment is development, false otherwise
140
+ # def dev?
141
+ # env == :development
142
+ # end
143
+
144
+ # # Determines if we are in the test environment
145
+ # #
146
+ # # @return [Boolean] true if current environment is test, false otherwise
147
+ # def test?
148
+ # env == :test
149
+ # end
150
+
151
+ # # Determines if we are in the staging environment
152
+ # #
153
+ # # @return [Boolean] true if current environment is staging.
154
+ # def staging?
155
+ # env == :staging
156
+ # end
157
+
158
+ # # Determines if we are in the vagrant environment
159
+ # #
160
+ # # @return [Boolean] true if current environment is vagrant.
161
+ # def vagrant?
162
+ # env == :vagrant
163
+ # end
164
+ # end
@@ -0,0 +1,19 @@
1
+ module MelissaData
2
+ module NativeObject
3
+ autoload :Base, 'melissadata/native_object/base'
4
+ autoload :Client, 'melissadata/native_object/client'
5
+
6
+ autoload :Address, 'melissadata/native_object/address'
7
+ autoload :Email, 'melissadata/native_object/email'
8
+ autoload :Geo, 'melissadata/native_object/geo'
9
+ autoload :IpLocator, 'melissadata/native_object/ip_locator'
10
+ autoload :Name, 'melissadata/native_object/name'
11
+ autoload :Phone, 'melissadata/native_object/phone'
12
+ end
13
+ end
14
+
15
+ %w[
16
+ mdAddrRubyWrapper mdEmailRubyWrapper mdGeoRubyWrapper mdNameRubyWrapper mdPhoneRubyWrapper mdIpLocatorRubyWrapper
17
+ ].each do |obj|
18
+ require File.join('/opt/melissadata/lib', obj)
19
+ end
@@ -0,0 +1,124 @@
1
+ module MelissaData::NativeObject
2
+ class Address < Base
3
+ def initialize(opts={})
4
+ @obj = MdAddrRubyWrapper::MdAddr.new
5
+ obj.SetPathToUSFiles(data_dir)
6
+ obj.SetUseUSPSPreferredCityNames(1)
7
+
8
+ @result_codes = [
9
+ ['AS01', "Address matched to postal database"],
10
+ ['AS09', "Foreign postal code detected"],
11
+ ['AS10', "Address matched to CMRA"],
12
+ ['AS12', "Address deliverable by non-USPS carriers"],
13
+ ['AS13', "Address has been updated by LACS"],
14
+ ['AS14', "Suite appended by SuiteLink"],
15
+ ['AS15', "Suite appended by AddressPlus"],
16
+ ['AS16', "Address is vacant"],
17
+ ['AS17', "Alternate delivery"],
18
+ ['AE01', "Zip code"],
19
+ ['AE02', "Unknown street"],
20
+ ['AE03', "Component mismatch"],
21
+ ['AE04', "Non-deliverable address"],
22
+ ['AE05', "Multiple match"],
23
+ ['AE06', "Early warning system error"],
24
+ ['AE07', "Missing minimum address input"],
25
+ ['AE08', "Suite range invalid"],
26
+ ['AE09', "Suite range missing"],
27
+ ['AE10', "Primary range invalid"],
28
+ ['AE11', "Primary range missing"],
29
+ ['AE12', "PO, HC, or RR box number invalid"],
30
+ ['AE13', "PO, HC, or RR box number missing"],
31
+ ['AE14', "CMRA secondary missing"],
32
+ ['AE15', "Demo mode"],
33
+ ['AE16', "Expired database"]
34
+ ]
35
+
36
+ @defaults = {
37
+ :company => '',
38
+ :address => '',
39
+ :address2 => '',
40
+ :city => '',
41
+ :state => '',
42
+ :zip => '',
43
+ :last_name => ''
44
+ }
45
+
46
+ # At least one of these needs to be present
47
+ @required_fields = [:address, :city, :state, :zip]
48
+
49
+ super
50
+ end
51
+
52
+ def parse_input
53
+ obj.ClearProperties
54
+ obj.SetCompany input[:company].to_s
55
+ obj.SetAddress input[:address].to_s
56
+ obj.SetAddress2 input[:address2].to_s
57
+ obj.SetCity input[:city].to_s
58
+ obj.SetState input[:state].to_s
59
+ obj.SetZip input[:zip].to_s
60
+ obj.SetLastName input[:last_name].to_s
61
+
62
+ obj.VerifyAddress
63
+ end
64
+
65
+ def assign_values
66
+ @output = {
67
+ :company => obj.GetCompany,
68
+ :address => obj.GetAddress,
69
+ :address2 => obj.GetAddress2,
70
+ :suite => obj.GetSuite,
71
+ :city => obj.GetCity,
72
+ :state => obj.GetState,
73
+ :zip => obj.GetZip,
74
+ :plus4 => obj.GetPlus4,
75
+ :country_code => obj.GetCountryCode,
76
+ :urbanization => obj.GetUrbanization,
77
+
78
+ :parsed_address_range => obj.GetParsedAddressRange,
79
+ :parsed_pre_direction => obj.GetParsedPreDirection,
80
+ :parsed_street_name => obj.GetParsedStreetName,
81
+ :parsed_post_direction => obj.GetParsedPostDirection,
82
+ :parsed_suffix => obj.GetParsedSuffix,
83
+ :parsed_suite_name => obj.GetParsedSuiteName,
84
+ :parsed_suite_range => obj.GetParsedSuiteRange,
85
+ :parsed_garbage => obj.GetParsedGarbage,
86
+ :parsed_private_mailbox_name => obj.GetParsedPrivateMailboxName,
87
+ :parsed_private_mailbox_number => obj.GetParsedPrivateMailboxNumber,
88
+
89
+ :carrier_route => obj.GetCarrierRoute,
90
+ :delivery_point_code => obj.GetDeliveryPointCode,
91
+ :delivery_point_check_digit => obj.GetDeliveryPointCheckDigit,
92
+
93
+ :address_type_code => obj.GetAddressTypeCode,
94
+ :address_type_string => obj.GetAddressTypeString,
95
+
96
+ :city_abbrev => obj.GetCityAbbreviation,
97
+
98
+ :cmra => obj.GetCMRA, # Commercial Mail Receiving Agency
99
+ :private_mailbox => obj.GetPrivateMailbox, # mailbox number at the CMRA
100
+
101
+ :msa => obj.GetMsa,
102
+ :pmsa => obj.GetPmsa,
103
+
104
+ :time_zone => obj.GetTimeZone,
105
+ :time_zone_code => obj.GetTimeZoneCode,
106
+
107
+ :county_name => obj.GetCountyName,
108
+ :county_fips => obj.GetCountyFips,
109
+ :congressional_district => obj.GetCongressionalDistrict,
110
+ :zip_type_code => obj.GetZipType
111
+ }
112
+
113
+ output[:zip_type] = case output[:zip_type_code]
114
+ when 'P' then 'PO Boxes only'
115
+ when 'U' then 'Unique - organization or government'
116
+ when 'M' then 'Military'
117
+ else 'Standard'
118
+ end
119
+
120
+ output[:zip9] = "#{output[:zip]}-#{output[:plus4]}" if output[:plus4].present?
121
+ output[:zip11] = "#{output[:zip9]}-#{output[:delivery_point_code]}" if output[:delivery_point_code].present?
122
+ end
123
+ end
124
+ end