melissadata 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.
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