leadtune 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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