leadtune 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.
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ *~
5
+ .#*
6
+ doc/
7
+ html/
8
+ TAGS
9
+ tags
10
+ .yardoc/
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --colour
2
+ --format
3
+ nested
data/Gemfile ADDED
@@ -0,0 +1,31 @@
1
+ # LeadTune API Ruby Gem
2
+ #
3
+ # http://github.com/leadtune/leadtune-ruby
4
+ # Eric Wollesen (mailto:devs@leadtune.com)
5
+ # Copyright 2010 LeadTune LLC
6
+
7
+ source :gemcutter
8
+
9
+ unless RUBY_PLATFORM == "java"
10
+ case RUBY_VERSION
11
+ when /^1.9.2/
12
+ gem "ruby-debug19"
13
+ when /^1.8/
14
+ gem "ruby-debug"
15
+ end
16
+ end
17
+
18
+ gem "rake"
19
+ gem "cucumber"
20
+ gem "rdoc"
21
+ gem "rspec", "2.0.0.beta.19"
22
+ gem "rspec-core", "2.0.0.beta.19"
23
+ gem "rspec-expectations", "2.0.0.beta.19"
24
+ gem "rspec-mocks"
25
+ gem "json"
26
+ gem "activemodel"
27
+ gem "curb"
28
+ gem "rack"
29
+ gem "tcpsocket-wait"
30
+ gem "webmock", :git => "http://github.com/phiggins/webmock.git"
31
+ gem "tcpsocket-wait"
data/Gemfile.lock ADDED
@@ -0,0 +1,72 @@
1
+ GIT
2
+ remote: http://github.com/phiggins/webmock.git
3
+ revision: 68a0708b9e55648252315bd9ec8f5f30ace0d132
4
+ specs:
5
+ webmock (1.3.5)
6
+ addressable (>= 2.1.1)
7
+ crack (>= 0.1.7)
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ activemodel (3.0.0)
13
+ activesupport (= 3.0.0)
14
+ builder (~> 2.1.2)
15
+ i18n (~> 0.4.1)
16
+ activesupport (3.0.0)
17
+ addressable (2.2.1)
18
+ builder (2.1.2)
19
+ columnize (0.3.1)
20
+ crack (0.1.8)
21
+ cucumber (0.8.5)
22
+ builder (~> 2.1.2)
23
+ diff-lcs (~> 1.1.2)
24
+ gherkin (~> 2.1.4)
25
+ json_pure (~> 1.4.3)
26
+ term-ansicolor (~> 1.0.4)
27
+ curb (0.7.8)
28
+ diff-lcs (1.1.2)
29
+ gherkin (2.1.5)
30
+ trollop (~> 1.16.2)
31
+ i18n (0.4.1)
32
+ json (1.4.6)
33
+ json_pure (1.4.6)
34
+ linecache (0.43)
35
+ rack (1.2.1)
36
+ rake (0.8.7)
37
+ rdoc (2.5.11)
38
+ rspec (2.0.0.beta.19)
39
+ rspec-core (= 2.0.0.beta.19)
40
+ rspec-expectations (= 2.0.0.beta.19)
41
+ rspec-mocks (= 2.0.0.beta.19)
42
+ rspec-core (2.0.0.beta.19)
43
+ rspec-expectations (2.0.0.beta.19)
44
+ diff-lcs (>= 1.1.2)
45
+ rspec-mocks (2.0.0.beta.19)
46
+ ruby-debug (0.10.3)
47
+ columnize (>= 0.1)
48
+ ruby-debug-base (~> 0.10.3.0)
49
+ ruby-debug-base (0.10.3)
50
+ linecache (>= 0.3)
51
+ tcpsocket-wait (1.0.0)
52
+ term-ansicolor (1.0.5)
53
+ trollop (1.16.2)
54
+
55
+ PLATFORMS
56
+ ruby
57
+
58
+ DEPENDENCIES
59
+ activemodel
60
+ cucumber
61
+ curb
62
+ json
63
+ rack
64
+ rake
65
+ rdoc
66
+ rspec (= 2.0.0.beta.19)
67
+ rspec-core (= 2.0.0.beta.19)
68
+ rspec-expectations (= 2.0.0.beta.19)
69
+ rspec-mocks
70
+ ruby-debug
71
+ tcpsocket-wait
72
+ webmock!
data/README.rdoc ADDED
@@ -0,0 +1,94 @@
1
+ = LeadTune API Ruby Gem
2
+
3
+ http://github.com/leadtune/leadtune-ruby
4
+
5
+ Copyright 2010 LeadTune, LLC
6
+
7
+ Eric Wollesen (mailto:devs@leadtune.com)
8
+
9
+ For details about the LeadTune API, see: http://leadtune.com/api
10
+
11
+ == Configuration
12
+
13
+ Authentication credentials can be specified by any of several methods, as
14
+ detailed below. Available configuration values include:
15
+
16
+ * username
17
+ * password
18
+ * organization
19
+
20
+ === Configuration File
21
+
22
+ The configuration file can be specified when calling Prospect#new. If no
23
+ file is specified, the gem will also look for +leadtune.yml+ in the
24
+ current directory.
25
+
26
+ ==== Format
27
+
28
+ The configuration file is a YAML file, an example of which is:
29
+ username: me@mycorp.com
30
+ password: my_secret
31
+ organization: MYC
32
+
33
+ === Environment Variables
34
+
35
+ Your LeadTune username, password, and organization can be specified in the
36
+ +LEADTUNE_USERNAME+, +LEADTUNE_PASSWORD+, and +LEADTUNE_ORGANIZATION+
37
+ environment variables. <em>These values take precedence over values read
38
+ from the configuration file.</em>
39
+
40
+ === Factors Hash
41
+
42
+ When initializing your Leadtune::Prospect, you can include your username,
43
+ password, and organization along with any factors you wish to
44
+ submit. <em>These values take precedence over values read from environment
45
+ variables, or the configuration file.</em>
46
+
47
+ === Instance Methods
48
+
49
+ You can also set your username, password, and organization by calling the
50
+ Leadtune::Prospect object's #username=, #password=, and #organization=
51
+ methods. <em>These values take precedence over values read from
52
+ environment variables, a configuration file, or the factors hash.</em>
53
+
54
+ == Example Usage
55
+
56
+ An attempt was made to allow for an ActiveModel-like interface.
57
+
58
+ require "rubygems"
59
+ require "leadtune"
60
+
61
+ prospect = Leadtune::Prospect.post({
62
+ :username => "admin@loleads.com" # required (See Leadtune::Config)
63
+ :password => "secret" # required (See Leadtune::Config)
64
+ :organization => "LOL", # required (See Leadtune::Config)
65
+ :event => "offers_prepared", # required
66
+ :email => "test@example.com" # required
67
+ :target_buyers => ["TB-LOL", "AcmeU",] # required
68
+ # ... include optional factors here, see http://leadtune.com/factors for details
69
+ })
70
+
71
+ <em>Or alternatively</em>
72
+
73
+ prospect = Leadtune::Prospect.post do |p|
74
+ p.event = "offers_prepared"
75
+ p.email = "test@example.com"
76
+ ... and so on
77
+ end
78
+
79
+ <em>Or even</em>
80
+
81
+ prospect = Leadtune::Prospect.new
82
+ prospect.event = "offers_prepared"
83
+ prosepct.email = "test@example.com"
84
+ ... and so on
85
+ prospect.post
86
+
87
+ == Automatic Environment Determination
88
+
89
+ At initialization, an attempt is made to determine your application's current
90
+ environment. If a rack or rails production environment is detected, prospects
91
+ will be posted to LeadTune's production host. Otherwise prospects will be
92
+ posted to LeadTune's sandbox host. The application environment can be
93
+ overriden via the +APP_ENV+ environment variable, which takes precedence over
94
+ all other methods.
data/Rakefile ADDED
@@ -0,0 +1,42 @@
1
+ # -*- ruby -*-
2
+
3
+ # LeadTune API Ruby Gem
4
+ #
5
+ # http://github.com/leadtune/leadtune-ruby
6
+ # Eric Wollesen (mailto:devs@leadtune.com)
7
+ # Copyright 2010 LeadTune LLC
8
+
9
+ require 'bundler'
10
+ Bundler.setup
11
+ Bundler::GemHelper.install_tasks
12
+
13
+ require 'rake'
14
+ require 'yaml'
15
+
16
+ require 'rake/rdoctask'
17
+ require 'rspec/core/rake_task'
18
+ require 'cucumber/rake/task'
19
+
20
+ RSpec::Core::RakeTask.new
21
+ Cucumber::Rake::Task.new
22
+ Rake::RDocTask.new(:rdoc) do |rd|
23
+ rd.options << "-t LeadTune API Ruby Gem"
24
+ rd.options << "--exclude=Gemfile"
25
+ rd.options << "--exclude=TAGS"
26
+ rd.options << "--exclude=Rakefile"
27
+ rd.options << "--exclude=spec/"
28
+ end
29
+
30
+ desc 'clobber generated files'
31
+ task :clobber => [:clobber_rdoc,] do
32
+ rm_rf "pkg"
33
+ rm_rf "tmp"
34
+ rm_rf "doc"
35
+ end
36
+
37
+ task :hudson => [:spec, :rdoc,]
38
+
39
+ task :default => [:spec, :cucumber,]
40
+
41
+
42
+
data/leadtune.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8; mode: ruby; -*-
2
+
3
+ # LeadTune API Ruby Gem
4
+ #
5
+ # http://github.com/leadtune/leadtune-ruby
6
+ # Eric Wollesen (mailto:devs@leadtune.com)
7
+ # Copyright 2010 LeadTune LLC
8
+
9
+ require File.expand_path("../lib/leadtune/version", __FILE__)
10
+
11
+ Gem::Specification.new do |s|
12
+ s.name = "leadtune"
13
+ s.version = Leadtune::VERSION
14
+ s.platform = Gem::Platform::RUBY
15
+ s.authors = ["Eric Wollesen"]
16
+ s.email = ["devs@leadtune.com"]
17
+ s.homepage = "http://github.com/leadtune/leadtune-ruby"
18
+ s.summary = "LeadTune Ruby API Gem"
19
+ s.description = "LeadTune Ruby API Gem"
20
+
21
+ s.required_rubygems_version = ">= 1.3.6"
22
+
23
+ s.add_development_dependency "bundler", ">= 1.0.0"
24
+
25
+ s.files = `git ls-files`.split("\n")
26
+ s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
27
+ s.require_path = 'lib'
28
+ end
@@ -0,0 +1,12 @@
1
+ # LeadTune API Ruby Gem
2
+ #
3
+ # http://github.com/leadtune/leadtune-ruby
4
+ # Eric Wollesen (mailto:devs@leadtune.com)
5
+ # Copyright 2010 LeadTune LLC
6
+
7
+ class Array
8
+ # stolen from ActiveSupport
9
+ def extract_options!
10
+ last.is_a?(::Hash) ? pop : {}
11
+ end
12
+ end
@@ -0,0 +1,34 @@
1
+ # LeadTune API Ruby Gem
2
+ #
3
+ # http://github.com/leadtune/leadtune-ruby
4
+ # Eric Wollesen (mailto:devs@leadtune.com)
5
+ # Copyright 2010 LeadTune LLC
6
+
7
+ class Hash
8
+ # File merb/core_ext/hash.rb, line 87
9
+ def to_params
10
+ params = ''
11
+ stack = []
12
+
13
+ each do |k, v|
14
+ if v.is_a?(Hash)
15
+ stack << [k,v]
16
+ else
17
+ params << "#{k}=#{v}&"
18
+ end
19
+ end
20
+
21
+ stack.each do |parent, hash|
22
+ hash.each do |k, v|
23
+ if v.is_a?(Hash)
24
+ stack << ["#{parent}[#{k}]", v]
25
+ else
26
+ params << "#{parent}[#{k}]=#{v}&"
27
+ end
28
+ end
29
+ end
30
+
31
+ params.chop! # trailing &
32
+ params
33
+ end
34
+ end
@@ -0,0 +1,17 @@
1
+ # LeadTune API Ruby Gem
2
+ #
3
+ # http://github.com/leadtune/leadtune-ruby
4
+ # Eric Wollesen (mailto:devs@leadtune.com)
5
+ # Copyright 2010 LeadTune LLC
6
+
7
+ # Extends Array by adding a few convenience methods for find duplicate,
8
+ # or non-duplicate appraisals.
9
+ class Leadtune::Appraisals < Array
10
+ def non_duplicates
11
+ find_all {|a| 0 < a["value"]}
12
+ end
13
+
14
+ def duplicates
15
+ find_all {|a| 0 == a["value"]}
16
+ end
17
+ end
@@ -0,0 +1,89 @@
1
+ # LeadTune API Ruby Gem
2
+ #
3
+ # http://github.com/leadtune/leadtune-ruby
4
+ # Eric Wollesen (mailto:devs@leadtune.com)
5
+ # Copyright 2010 LeadTune LLC
6
+
7
+ module Leadtune
8
+
9
+ class Config #:nodoc:all
10
+
11
+ attr_accessor :environment, :leadtune_host, :username, :password, :timeout
12
+
13
+ def initialize(config_file=nil)
14
+ load_config_file_values(config_file)
15
+ end
16
+
17
+ def username
18
+ @username ||= ENV["LEADTUNE_USERNAME"] || @config_file_values["username"]
19
+ end
20
+
21
+ def password
22
+ @password ||= ENV["LEADTUNE_PASSWORD"] || @config_file_values["password"]
23
+ end
24
+
25
+ def timeout
26
+ @timeout ||= (ENV["LEADTUNE_TIMEOUT"] ||
27
+ @config_file_values["timeout"] ||
28
+ DEFAULT_TIMEOUT).to_i
29
+ end
30
+
31
+ def organization
32
+ ENV["LEADTUNE_ORGANIZATION"] || @config_file_values["organization"]
33
+ end
34
+
35
+ def leadtune_host
36
+ @leadtune_host ||= (ENV["LEADTUNE_HOST"] ||
37
+ @config_file_values["host"] ||
38
+ LEADTUNE_HOSTS[environment])
39
+ end
40
+
41
+ def environment
42
+ @environment ||= production_environment_detected? ? :production : :sandbox
43
+ end
44
+
45
+ def production_environment_detected?
46
+ if ENV.include?("APP_ENV")
47
+ "production" == ENV["APP_ENV"]
48
+ else
49
+ defined?(Rails) && Rails.env.production? ||
50
+ "production" == ENV["RACK_ENV"] ||
51
+ "production" == ENV["RAILS_ENV"] ||
52
+ defined?(RAILS_ENV) && "production" == RAILS_ENV
53
+ end
54
+ end
55
+
56
+
57
+ private
58
+
59
+ def load_config_file_values(config_file)
60
+ @config_file_values = {}
61
+
62
+ find_config_file(config_file) do |config_file|
63
+ @config_file_values = YAML::load(config_file)
64
+ end
65
+ end
66
+
67
+ def find_config_file(config_file)
68
+ case config_file
69
+ when String
70
+ yield File.open(config_file)
71
+ when File, StringIO
72
+ yield config_file
73
+ when nil
74
+ if File.exist?("leadtune.yml")
75
+ yield File.open("leadtune.yml")
76
+ end
77
+ end
78
+ end
79
+
80
+
81
+ DEFAULT_TIMEOUT = 5
82
+ LEADTUNE_HOST_SANDBOX = "https://sandbox-appraiser.leadtune.com".freeze
83
+ LEADTUNE_HOST_PRODUCTION = "https://appraiser.leadtune.com".freeze
84
+ LEADTUNE_HOSTS = {
85
+ :production => LEADTUNE_HOST_PRODUCTION,
86
+ :sandbox => LEADTUNE_HOST_SANDBOX,
87
+ }
88
+ end
89
+ end
@@ -0,0 +1,237 @@
1
+ # LeadTune API Ruby Gem
2
+ #
3
+ # http://github.com/leadtune/leadtune-ruby
4
+ # Eric Wollesen (mailto:devs@leadtune.com)
5
+ # Copyright 2010 LeadTune LLC
6
+
7
+ require "yaml"
8
+ require "curb"
9
+ require "uri"
10
+
11
+ require "leadtune/appraisals"
12
+ require "leadtune/rest"
13
+ require "leadtune/config"
14
+
15
+
16
+ module Leadtune
17
+
18
+ # Simplify the process of submitting prospects to LeadTune for duplicate
19
+ # checking and appraisal.
20
+ #
21
+ # For details about the LeadTune API, see: http://leadtune.com/api
22
+ #
23
+ # == Dynamic Factor Access
24
+ #
25
+ # Getter and setter methods are dynamically defined for factors as they're
26
+ # set. See http://leadtune.com/factors for a list of LeadTune recognized
27
+ # factors.
28
+
29
+ class Prospect
30
+ attr_accessor :decision #:nodoc:
31
+
32
+ # Initialize a new Leadtune::Prospect object.
33
+ #
34
+ # [+config_file+] An optional filename or a file-like object
35
+ # [+factors+] A hash of factors with which to initialize the Prospect
36
+
37
+ def initialize(*args, &block)
38
+ @factors = {}
39
+ @decision = nil
40
+ @config = Config.new(args.first)
41
+ @rest = Rest.new(@config)
42
+
43
+ load_options_and_factors(args.extract_options!)
44
+ block.call(self) if block_given?
45
+ end
46
+
47
+ # Get a prospect from the LeadTune Appraiser service.
48
+ #
49
+ # Raises a Leadtune::LeadtuneError if a non-2XX response is received.
50
+
51
+ def self.get(options={}, &block)
52
+ new(options, &block).get
53
+ end
54
+
55
+ # Post a prospect to the LeadTune Appraiser service.
56
+ #
57
+ # Raises a Leadtune::LeadtuneError if a non-2XX response is received.
58
+
59
+ def self.post(options={}, &block)
60
+ new(options, &block).post
61
+ end
62
+
63
+ # Update a prospect from the LeadTune Appraiser service.
64
+ #
65
+ # Raises a Leadtune::LeadtuneError if a non-2XX response is received.
66
+
67
+ def self.put(options={}, &block)
68
+ new(options, &block).put
69
+ end
70
+
71
+ # Get a prospect from the LeadTune Appraiser service.
72
+ #
73
+ # Raises a Leadtune::LeadtuneError if a non-2XX response is received.
74
+
75
+ def get
76
+ json = @rest.get(post_data)
77
+ parse_response(json)
78
+ self
79
+ end
80
+
81
+ # Post this prospect to the LeadTune Appraiser service.
82
+ #
83
+ # Raises a Leadtune::LeadtuneError if a non-2XX response is received.
84
+
85
+ def post
86
+ json = @rest.post(post_data)
87
+ parse_response(json)
88
+ self
89
+ end
90
+
91
+ # Update a prospect from the LeadTune Appraiser service.
92
+ #
93
+ # Raises a Leadtune::LeadtuneError if a non-2XX response is received.
94
+
95
+ def put
96
+ json = @rest.put(post_data)
97
+ parse_response(json)
98
+ self
99
+ end
100
+
101
+ # The unique +decision_id+ for this prospect.
102
+
103
+ def decision_id
104
+ @decision ||= {}
105
+ @decision["decision_id"]
106
+ end
107
+
108
+ # The appraisals for this Prospect.
109
+ #
110
+ # The Array returned has been extended to include two methods,
111
+ # +duplicates+ and +non_duplicates+. Each returns the appraisals of the
112
+ # target_buyers for whom this lead is or is not a known duplicate.
113
+
114
+ def appraisals
115
+ @decision ||= {}
116
+ @decision["appraisals"]
117
+ end
118
+
119
+ # Return a hash of the factors specified for this Prospect.
120
+
121
+ def factors
122
+ @factors
123
+ end
124
+
125
+ # Assign an array of organization codes for the prospect's target buyers.
126
+
127
+ def target_buyers=(target_buyers)
128
+ unless target_buyers.is_a?(Array)
129
+ raise ArgumentError.new("target_buyers must be an Array")
130
+ end
131
+
132
+ @decision = {"target_buyers" => target_buyers}
133
+ end
134
+
135
+ # Return an array of organization codes for the prospect's target buyers.
136
+
137
+ def target_buyers
138
+ @decision ||= {}
139
+ @decision["target_buyers"] ||= []
140
+ end
141
+
142
+ def organization #:nodoc:
143
+ @factors["organization"] ||= @config.organization
144
+ end
145
+
146
+ def prospect_id #:nodoc:
147
+ @factors["prospect_id"]
148
+ end
149
+
150
+ def prospect_ref #:nodoc:
151
+ @factors["prospect_ref"]
152
+ end
153
+
154
+ def leadtune_host=(host) #:nodoc:
155
+ @config.leadtune_host = host
156
+ end
157
+
158
+ def leadtune_host #:nodoc:
159
+ @config.leadtune_host
160
+ end
161
+
162
+ def username=(username)
163
+ @config.username = username
164
+ end
165
+
166
+ def password=(password)
167
+ @config.password = password
168
+ end
169
+
170
+
171
+ private
172
+
173
+ def post_data #:nodoc:
174
+ @factors.merge("decision" => decision)
175
+ end
176
+
177
+ def load_options_and_factors(options) #:nodoc:
178
+ load_options(options)
179
+ load_factors(options)
180
+ end
181
+
182
+ def load_options(options) #:nodoc:
183
+ @rest.username = options.delete("username") if options["username"]
184
+ @rest.password = options.delete("password") if options["password"]
185
+ @config.timeout = options.delete("timeout") if options["timeout"]
186
+ @config.leadtune_host = options.delete("timeout") if options["leadtune_host"]
187
+ end
188
+
189
+ def load_factors(factors) #:nodoc:
190
+ factors.each_pair do |key, value|
191
+ self.send("#{key}=", value)
192
+ end
193
+ end
194
+
195
+ def parse_response(response) #:nodoc:
196
+ load_decision(response)
197
+ load_factors(response)
198
+ end
199
+
200
+ def load_decision(response) #:nodoc:
201
+ return unless response.include?("decision")
202
+
203
+ @decision = response.delete("decision")
204
+ if @decision.include?("appraisals")
205
+ @decision["appraisals"] = Appraisals.new(@decision["appraisals"])
206
+ end
207
+ end
208
+
209
+ def method_missing(name, *args, &block) #:nodoc:
210
+ if /=$/ === name.to_s
211
+ memoize_new_factor(name)
212
+ self.send(name, *args, &block)
213
+ else
214
+ super
215
+ end
216
+ end
217
+
218
+ def memoize_new_factor(name) #:nodoc:
219
+ getter_name = name.to_s.sub(/=$/, "")
220
+
221
+ self.class.class_eval do
222
+ define_method(name) do |value|
223
+ @factors[getter_name] = value
224
+ end
225
+ end
226
+
227
+ unless respond_to?(getter_name)
228
+ self.class.class_eval do
229
+ define_method(getter_name) do
230
+ @factors[getter_name]
231
+ end
232
+ end
233
+ end
234
+ end
235
+
236
+ end
237
+ end