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,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