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,79 @@
1
+ module MelissaData::NativeObject
2
+ class Base
3
+ attr_reader :obj, :license, :input, :output, :result_codes, :results_string
4
+ attr_writer :data_dir
5
+
6
+ def initialize(opts={})
7
+ @license = opts[:license] || "DEMO"
8
+
9
+ unless obj.SetLicenseString(@license)
10
+ @license = "DEMO"
11
+ puts "Invalid License: Running in DEMO MODE."
12
+ end
13
+
14
+ if obj.respond_to?(:InitializeDataFiles) && obj.InitializeDataFiles != 0
15
+ raise obj.GetInitializeErrorString
16
+ end
17
+ end
18
+
19
+ # Example: geo.process(:zip => '84108')
20
+ # - If invalid input (required fields are missing), return {}
21
+ # - Call subclass's parse_input - this should call methods on the MelissaData object
22
+ # - Call subclass's assign_values - pull out information from the object into the output hash
23
+ # - Processes result codes
24
+ def process(opts={})
25
+ @input = @defaults.merge(opts)
26
+ return {} unless valid_input?
27
+
28
+ parse_input
29
+ @results_string = obj.GetResults.to_s
30
+ assign_values
31
+ process_result_codes
32
+
33
+ output.reduce({}) do |hsh,pair|
34
+ val = pair.last
35
+ val.strip! if val.respond_to?(:strip)
36
+ hsh[pair.first] = val if val.present?
37
+ hsh
38
+ end
39
+ end
40
+
41
+ def parse_input
42
+ raise "Needs to be overridden"
43
+ end
44
+
45
+ def assign_values
46
+ @output = {}
47
+ end
48
+
49
+ def valid_input?
50
+ @required_fields.blank? || input.any?{ |k,v| @required_fields.include?(k) && v.present? }
51
+ end
52
+
53
+ def process_result_codes
54
+ status_messages = []
55
+ error_messages = []
56
+
57
+ @results_string.split(",").each do |lookup|
58
+ if (match = @result_codes.detect{ |c,m| c == lookup })
59
+ code, message = *match
60
+
61
+ if code[1] == 'E'
62
+ error_messages << message
63
+ else
64
+ status_messages << message
65
+ end
66
+ end
67
+ end
68
+
69
+ output[:result_codes] = @results_string
70
+ output[:messages] = {}
71
+ output[:messages][:status] = status_messages if status_messages.present?
72
+ output[:messages][:error] = error_messages if error_messages.present?
73
+ end
74
+
75
+ def data_dir
76
+ @data_dir ||= '/opt/melissa_data/data'
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,33 @@
1
+ module MelissaData::NativeObject
2
+
3
+ class Client
4
+ attr_reader :license
5
+
6
+ def initialize(license='INVALID LICENSE')
7
+ @license = license
8
+ @email_object = MelissaData::Email.new(:license => license)
9
+ end
10
+
11
+ def process_email(email=nil)
12
+ email ||= ''
13
+ output = {}
14
+ input = {:email => email.to_s}
15
+ output = @email_object.process(input)
16
+ output.delete_if{ |k,v| v.to_s.strip == "" }
17
+ output
18
+ end
19
+
20
+ def email_build_number
21
+ @email_object.obj.GetBuildNumber
22
+ end
23
+
24
+ def version
25
+ MelissaData::VERSION
26
+ end
27
+
28
+ def address
29
+ "SharedObjects"
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,61 @@
1
+ module MelissaData::NativeObject
2
+ class Email < Base
3
+ def initialize(opts={})
4
+ @obj = MdEmailRubyWrapper::MdEmail.new
5
+ obj.SetPathToEmailFiles(data_dir)
6
+ obj.SetCorrectSyntax(1) # Enable/disable syntax correction
7
+ obj.SetStandardizeCasing(1) # Enable/disable lowercasing of email
8
+ obj.SetDatabaseLookup(1) # Enable/disable lookups against internal database of known domain names
9
+ obj.SetMXLookup(0) # Enable/disable DNS lookups for MX records (slower - but can be more accurate)
10
+ obj.SetUpdateDomain(1)
11
+
12
+ @result_codes = [
13
+ ['ES01', "Valid domain name"],
14
+ ['ES02', "Invalid domain name"],
15
+ ['ES03', "Domain name could not be verified"],
16
+ ['ES10', "Syntax was changed/corrected"],
17
+ ['ES11', "Top level domain was changed"],
18
+ ['ES12', "Domain name spelling was corrected"],
19
+ ['ES13', "Domain name was updated"],
20
+ ['EE01', "Syntax error in email address"],
21
+ ['EE02', "Top level domain not found"],
22
+ ['EE03', "Mail server not found"]
23
+ ]
24
+
25
+ @defaults = {
26
+ :email => ''
27
+ }
28
+
29
+ # At least one of these needs to be present
30
+ @required_fields = [:email]
31
+
32
+ super
33
+ end
34
+
35
+ def parse_input
36
+ obj.VerifyEmail(input[:email].to_s)
37
+ end
38
+
39
+ def assign_values
40
+ @output = {
41
+ :mailbox_name => obj.GetMailBoxName,
42
+ :domain_name => obj.GetDomainName,
43
+ :top_level_domain => obj.GetTopLevelDomain,
44
+ :top_level_domain_description => obj.GetTopLevelDomainDescription,
45
+ :email => obj.GetEmailAddress,
46
+ :lookup_code => obj.GetStatusCode
47
+ }
48
+
49
+ # V - Verified
50
+ # U - Unverified - not confirmed by lookup, but was not in the invalid domains list
51
+ # X - Bad email address - either not located by MX lookup, or was on the invalid domains list
52
+ if output[:lookup_code] == 'U'
53
+ obj.SetMXLookup(1)
54
+ obj.VerifyEmail(input[:email])
55
+ obj.SetMXLookup(0)
56
+
57
+ process_result_codes
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,61 @@
1
+ module MelissaData::NativeObject
2
+ class Geo < Base
3
+ def initialize(opts={})
4
+ @obj = MdGeoRubyWrapper::MdGeo.new
5
+ obj.SetPathToGeoCodeDataFiles(data_dir)
6
+ obj.SetPathToGeoPointDataFiles(data_dir)
7
+
8
+ @result_codes = [
9
+ ['GS01', "Geocoded to ZIP+4"],
10
+ ['GS02', "Geocoded to ZIP+2"],
11
+ ['GS03', "Geocoded to ZIP"],
12
+ ['GS05', "Geocoded to rooftop level"],
13
+ ['GS06', "Geocoded to interpolated rooftop level"],
14
+ ['GE01', "Invalid zip code"],
15
+ ['GE02', "Zip code not found"],
16
+ ['GE03', "Demo mode"],
17
+ ['GE04', "Expired database"]
18
+ ]
19
+
20
+ @defaults = {
21
+ :zip => '',
22
+ :plus4 => ''
23
+ }
24
+
25
+ # At least one of these needs to be present
26
+ @required_fields = [:zip]
27
+
28
+ super
29
+ end
30
+
31
+ def parse_input
32
+ if ((dpc = input[:delivery_point_code]) || (dpc = input[:dpc])).present?
33
+ obj.GeoPoint(input[:zip].to_s, input[:plus4].to_s, dpc.to_s)
34
+ else
35
+ obj.GeoCode(input[:zip].to_s, input[:plus4].to_s)
36
+ end
37
+ end
38
+
39
+ def assign_values
40
+ @output = {
41
+ :lat => obj.GetLatitude,
42
+ :lng => obj.GetLongitude,
43
+ :county_name => obj.GetCountyName,
44
+ :county_fips => obj.GetCountyFips,
45
+ :census_tract => obj.GetCensusTract,
46
+ :census_block => obj.GetCensusBlock,
47
+ :place_name => obj.GetPlaceName,
48
+ :place_code => obj.GetPlaceCode,
49
+ :time_zone => obj.GetTimeZone,
50
+ :time_zone_code => obj.GetTimeZoneCode,
51
+
52
+ :cbsa_code => obj.GetCBSACode,
53
+ :cbsa_level => obj.GetCBSALevel,
54
+ :cbsa_title => obj.GetCBSATitle,
55
+ :cbsa_division_code => obj.GetCBSADivisionCode,
56
+ :cbsa_division_title => obj.GetCBSADivisionTitle,
57
+ :cbsa_division_level => obj.GetCBSADivisionLevel
58
+ }
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,41 @@
1
+ module MelissaData::NativeObject
2
+ class IpLocator < Base
3
+ def initialize(opts={})
4
+ @obj = MdIpLocatorRubyWrapper::MdIpLocator.new
5
+ obj.SetPathToIpLocatorFiles(data_dir)
6
+
7
+ @result_codes = [
8
+ ['IS01', "IP Address found in database"],
9
+ ['IS02', "IP Address unknown"],
10
+ ['IE01', "IP Address was empty or not well formed"]
11
+ ]
12
+
13
+ @defaults = {
14
+ :ip => ''
15
+ }
16
+
17
+ # At least one of these needs to be present
18
+ @required_fields = [:ip]
19
+
20
+ super
21
+ end
22
+
23
+ def parse_input
24
+ obj.LocateIpAddress(input[:ip].to_s)
25
+ end
26
+
27
+ def assign_values
28
+ @output = {
29
+ :domain_name => obj.GetDomainName,
30
+ :isp => obj.GetISP,
31
+ :city => obj.GetCity,
32
+ :region => obj.GetRegion,
33
+ :zip => obj.GetZip,
34
+ :country => obj.GetCountry,
35
+ :country_abbrev => obj.GetCountryAbbreviation,
36
+ :lat => obj.GetLatitude,
37
+ :lng => obj.GetLongitude
38
+ }
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,74 @@
1
+ module MelissaData::NativeObject
2
+ class Name < Base
3
+ def initialize(opts={})
4
+ @obj = MdNameRubyWrapper::MdName.new
5
+ obj.SetPathToNameFiles(data_dir)
6
+
7
+ @result_codes = [
8
+ ['NS01', "Parsing was successful"],
9
+ ['NS02', "There was a parse error"],
10
+ ['NS03', "The spelling of the FirstName field was corrected"],
11
+ ['NS04', "The spelling of the FirstName2 field was corrected"],
12
+ ['NE01', "Two names were detected but the FullName string was not in a recognized format"],
13
+ ['NE02', "Multiple first names - could not accurately genderize"],
14
+ ['NE03', "A vulgarity was detected in the first name"],
15
+ ['NE04', "The name contained words found on the list of nuisance names [such as Mickey Mouse]"],
16
+ ['NE05', "The name contained words normally found in a company name"],
17
+ ['NE06', "The named contained a non-alphabetic character"]
18
+ ]
19
+
20
+ @defaults = {
21
+ :first_name => '',
22
+ :last_name => ''
23
+ }
24
+
25
+ # At least one of these needs to be present
26
+ @required_fields = [:first_name, :last_name, :full_name]
27
+
28
+ # 0 - don't correct spelling of first name
29
+ # 1 - attempt to correct common misspellings of first name
30
+ obj.SetFirstNameSpellingCorrection(1)
31
+
32
+ # Formatting of the FullName input
33
+ # 1 - Definitely Full
34
+ # 2 - Very Likely Full
35
+ # 3 - Probably Full
36
+ # 4 - Varying (default)
37
+ # 5 - Probably Inverse
38
+ # 6 - Very Likely Inverse
39
+ # 7 - Definitely Inverse
40
+ # 8 - Mixed First Name
41
+ # 9 - Mixed Last Name
42
+ obj.SetPrimaryNameHint(1)
43
+
44
+ super
45
+ end
46
+
47
+ def parse_input
48
+ input[:full_name] = ("%s %s" % [input[:first_name], input[:last_name]]) if input[:full_name].blank?
49
+ obj.ClearProperties
50
+ obj.SetFullName input[:full_name].to_s
51
+ obj.Parse
52
+ end
53
+
54
+ def assign_values
55
+ genders = {
56
+ 'M' => 'Male',
57
+ 'F' => 'Female',
58
+ 'U' => 'Unknown first name',
59
+ 'N' => 'Neutral first name'
60
+ }
61
+
62
+ @output = {
63
+ :prefix => obj.GetPrefix,
64
+ :first_name => obj.GetFirstName,
65
+ :middle_name => obj.GetMiddleName,
66
+ :last_name => obj.GetLastName,
67
+ :suffix => obj.GetSuffix,
68
+ :gender => obj.GetGender,
69
+ :gender_string => genders[obj.GetGender]
70
+ }
71
+ # status_messages << "First name spelling was corrected" if name_obj.GetChangeCode == 1
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,96 @@
1
+ module MelissaData::NativeObject
2
+ class Phone < Base
3
+ def initialize(opts={})
4
+ @obj = MdPhoneRubyWrapper::MdPhone.new
5
+ if obj.Initialize(data_dir) != 0
6
+ raise obj.GetInitializeErrorString
7
+ end
8
+
9
+ @result_codes = [
10
+ ["PS01", "10 digit match"],
11
+ ["PS02", "7 digit match"],
12
+ ["PS03", "Corrected Area Code"],
13
+ ["PS04", "Outside Demo Range"],
14
+ ["PS05", "Expired Database"],
15
+ ["PS06", "Updated Area Code"],
16
+ ["PS07", "Exchange Type: Cell Phone"],
17
+ ["PS08", "Exchange Type: Land Line"],
18
+ ["PS09", "Exchange Type: VOIP"],
19
+ ["PS10", "Phone Type: Residential"],
20
+ ["PS11", "Phone Type: Business"],
21
+ ["PS12", "Phone Type: Small Business or Home Office"],
22
+ ["PE01", "Bad area code"],
23
+ ["PE02", "Blank phone number"],
24
+ ["PE03", "Bad phone number - too many or too few digits"],
25
+ ["PE04", "Multiple phone matches"],
26
+ ["PE05", "Bad prefix - does not exist in the database"],
27
+ ["PE06", "Bad zip code"]
28
+ ]
29
+
30
+ @defaults = {
31
+ :phone => '',
32
+ :zip => ''
33
+ }
34
+
35
+ # At least one of these needs to be present
36
+ @required_fields = [:phone]
37
+
38
+ super
39
+ end
40
+
41
+ def parse_input
42
+ obj.Lookup(input[:phone].to_s, input[:zip].to_s)
43
+ end
44
+
45
+ def assign_values
46
+ @output = {
47
+ :lat => obj.GetLatitude,
48
+ :lng => obj.GetLongitude,
49
+ :city => obj.GetCity,
50
+ :state => obj.GetState,
51
+ :county_name => obj.GetCountyName,
52
+ :county_fips => obj.GetCountyFips,
53
+ :country_code => obj.GetCountryCode,
54
+ :time_zone => obj.GetTimeZone,
55
+ :time_zone_code => obj.GetTimeZoneCode,
56
+ :msa => obj.GetMsa,
57
+ :pmsa => obj.GetPmsa,
58
+ :time_zone => obj.GetTimeZone,
59
+ :time_zone_code => obj.GetTimeZoneCode,
60
+ :area_code => obj.GetAreaCode,
61
+ :prefix => obj.GetPrefix,
62
+ :suffix => obj.GetSuffix,
63
+ :extension => obj.GetExtension
64
+ }
65
+
66
+ codes = result_codes.split(',')
67
+ output[:exchange_type] = if codes.include?('PS07')
68
+ 'Cell Phone'
69
+
70
+ elsif codes.include?('PS08')
71
+ 'Land Line'
72
+
73
+ elsif codes.include?('PS09')
74
+ 'VOIP'
75
+ end
76
+
77
+ output[:phone_type] = if codes.include?('PS07')
78
+ 'Residential'
79
+
80
+ elsif codes.include?('PS07')
81
+ 'Business'
82
+
83
+ elsif codes.include?('PS07')
84
+ 'Small Business or Home Office'
85
+ end
86
+
87
+ # if opts[:zip].present?
88
+ # phone_obj.CorrectAreaCode(opts[:phone], opts[:zip])
89
+ # hsh[:new_area_code] = phone_obj.GetNewAreaCode
90
+ # end
91
+
92
+ output[:formatted_phone] = "(#{output[:area_code]}) #{output[:prefix]}-#{output[:suffix]}"
93
+ output[:formatted_phone] << " x#{output[:extension]}" if output[:extension].present?
94
+ end
95
+ end
96
+ end