rack-trade_tracker 0.1.3

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f3f85ee71138c76c5ac68fd3ff519a6829a177d2
4
+ data.tar.gz: 653d8f2b1e06fb5e36dc6b78f2c7bf34375bcb55
5
+ SHA512:
6
+ metadata.gz: a08bb9c02b1f192e47f168ee5f8f3f6abd5e1d7e9c5ac25b155a34cc746c974813d1e34c7fe86039a2c6b43524df94239afafd1fcacfccadc018e225b0161a88
7
+ data.tar.gz: 0e96ef4287638b1e31e7dcea710658e1210870b3599f0152ccdf4f7b2b350b3d45009c9078fcccfbbf26d8c804c428d2fa6fc96ca8d729eb2a7c9f4ffaa8a553
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,67 @@
1
+ # Rack::TradeTracker
2
+
3
+ The `Rack::TradeTracker` gem is for use with the Trade Tracker affiliate network.
4
+
5
+ The gem provides a [Rack middleware](http://guides.rubyonrails.org/rails_on_rack.html) component to handle Trade Tracker's redirect mechanism.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'rack-trade_tracker'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install rack-trade_tracker
22
+
23
+ ## Usage
24
+
25
+ Note that `domain:` and `path:` are required options and you will get an error if you don't provide these:
26
+ - Replace `'your-domain'` with your domain name minus `www`; e.g. `clickmechanic.com`.
27
+ - Replace `'your-path'` with the target path you have agreed with Trade Tracker; e.g. `/repair` (note the leading `/`)
28
+
29
+ > The gem makes no assumptions about where and how you implement the Trade Tracker JS script. You will need to do this yourself.
30
+
31
+ ### `config.ru`
32
+ If you are running a basic Rack app, you can configure the middleware in your `config.ru` file:
33
+ ```ruby
34
+ use Rack::TradeTracker, domain: 'your-domain', path: '/your_path'
35
+ ```
36
+
37
+ ### Rails
38
+ If you are using Rails, you can configure the rack middleware in `config/application.rb`, or one of the `config/environments/<environment>.rb` files, using one of the provided helper methods:
39
+ ```Ruby
40
+ config.middleware.use('Rack::TradeTracker', domain: 'your-domain', path: 'your-path')
41
+
42
+ # or
43
+ config.middleware.insert_before(existing_middleware, 'Rack::TradeTracker', domain: 'your-domain', path: 'your-path')
44
+
45
+ # or
46
+ config.middleware.insert_after(existing_middleware, 'Rack::TradeTracker', domain: 'your-domain', path: 'your-path')
47
+ ```
48
+
49
+
50
+
51
+ ## Development
52
+
53
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
54
+
55
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
56
+
57
+ ## Contributing
58
+
59
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ClickMechanic/rack-trade_tracker. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
60
+
61
+ ## License
62
+
63
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
64
+
65
+ ## Code of Conduct
66
+
67
+ Everyone interacting in the Rack::TradeTracker project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/ClickMechanic/rack-trade_tracker/blob/master/CODE_OF_CONDUCT.md).
@@ -0,0 +1,27 @@
1
+ require_relative "trade_tracker/version"
2
+ require_relative "trade_tracker/parameters"
3
+ require_relative "trade_tracker/handler"
4
+
5
+ module Rack
6
+
7
+ class TradeTracker
8
+ TRACKBACK_URL = 'http://tc.tradetracker.net'.freeze
9
+
10
+ InitializationError = Class.new(RuntimeError)
11
+
12
+ def initialize(app, options = {})
13
+ @app = app
14
+ raise InitializationError.new('options must include :domain') unless (@domain = options[:domain])
15
+ raise InitializationError.new('options must include :path') unless (@path = options[:path])
16
+ end
17
+
18
+ def call(env)
19
+ Handler.new(domain, path, app).call(env)
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader :app, :domain, :path
25
+ end
26
+
27
+ end
@@ -0,0 +1,52 @@
1
+ module Rack
2
+ class TradeTracker
3
+
4
+ class Cookie
5
+ NAME = 'TT2_%{campaign_id}'.freeze
6
+ DIGEST_PARAMS = [:campaign_id, :material_id, :affiliate_id, :reference].freeze
7
+ VALUE_PARAMS = [:material_id, :affiliate_id, :reference].freeze
8
+ PATH = '/'.freeze
9
+
10
+ def initialize(domain, parameters)
11
+ @domain, @parameters = domain, parameters
12
+ end
13
+
14
+ def name
15
+ NAME % params_hash
16
+ end
17
+
18
+ def checksum
19
+ source = "CHK_#{DIGEST_PARAMS.map { |param| params_hash[param] }.join('::')}"
20
+ Digest::MD5.hexdigest(source)
21
+ end
22
+
23
+ def timestamp
24
+ Time.now.to_i
25
+ end
26
+
27
+ def value
28
+ VALUE_PARAMS.map { |param| params_hash[param] }.tap do |attributes|
29
+ attributes << checksum << timestamp
30
+ end.join('::')
31
+ end
32
+
33
+ def as_hash
34
+ {
35
+ value: value,
36
+ domain: ".#{domain}",
37
+ path: PATH,
38
+ expires: 1.year.from_now
39
+ }
40
+ end
41
+
42
+ private
43
+
44
+ attr_reader :domain, :parameters
45
+
46
+ def params_hash
47
+ @_params_hash ||= parameters.to_hash
48
+ end
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,100 @@
1
+ require 'active_support/core_ext/integer/time'
2
+
3
+ require_relative 'cookie'
4
+
5
+ module Rack
6
+ class TradeTracker
7
+
8
+ class Handler
9
+ PARAMS_MAP = {campaign_id: :c,
10
+ material_id: :m,
11
+ affiliate_id: :a,
12
+ reference: :r,
13
+ redirect_url: :u}.freeze
14
+
15
+ LOGGER_REGEX = /logger/i
16
+
17
+ def initialize(domain, path, app)
18
+ @domain = domain
19
+ @path = path
20
+ @app = app
21
+ end
22
+
23
+ def call(env)
24
+ @env = env
25
+ @request = Rack::Request.new(env)
26
+
27
+ return @app.call(env) unless matches_path?
28
+
29
+ begin
30
+ redirect
31
+ rescue Parameters::MissingParametersError
32
+ redirect_to_root
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ attr_reader :domain, :path, :app, :env, :request, :cookie
39
+
40
+ def matches_path?
41
+ request.path == path
42
+ end
43
+
44
+ def parameters
45
+ @_parameters ||= Parameters.new(request.params)
46
+ end
47
+
48
+ def params_hash
49
+ @_params_hash ||= parameters.to_hash
50
+ end
51
+
52
+ def redirect_to_root
53
+ response(302, {'Location' => request.base_url} ) do
54
+ log("Redirecting to root as Trade Tracker parameters missing", :error)
55
+ end
56
+ end
57
+
58
+ def redirect
59
+ response(301, {'Location' => redirect_url} ) do |response|
60
+ set_cookie(response)
61
+ set_p3p_header(response)
62
+ log("Redirecting to Trade Tracker with cookie: #{URI.encode(cookie.value)}")
63
+ end
64
+ end
65
+
66
+ def redirect_url
67
+ url = URI(TRACKBACK_URL)
68
+ params = PARAMS_MAP.keys.each_with_object({}) { |param, result| result[PARAMS_MAP[param]] = params_hash[param] }
69
+ url.query = params.map { |k,v| "#{k}=#{URI.encode(v)}" }.join('&')
70
+ url.to_s
71
+ end
72
+
73
+ def response(status, header)
74
+ Rack::Response.new([], status, header).tap do |response|
75
+ yield response if block_given?
76
+ end.finish
77
+ end
78
+
79
+ def set_cookie(response)
80
+ @cookie ||= Cookie.new(domain, parameters)
81
+ response.set_cookie(cookie.name, cookie.as_hash)
82
+ end
83
+
84
+ def set_p3p_header(response)
85
+ response.headers['P3P'] = 'CP="ALL PUR DSP CUR ADMi DEVi CONi OUR COR IND"'
86
+ end
87
+
88
+ def log(message, level = :info)
89
+ return unless logger
90
+
91
+ logger.send(level, message) if logger.respond_to?(level)
92
+ end
93
+
94
+ def logger
95
+ @logger ||= env.find { |key, _| LOGGER_REGEX.match(key) }&.[] 1
96
+ end
97
+ end
98
+
99
+ end
100
+ end
@@ -0,0 +1,40 @@
1
+ require 'active_support/core_ext/string'
2
+
3
+ require_relative 'parameters/paired'
4
+ require_relative 'parameters/delimited'
5
+
6
+ module Rack
7
+ class TradeTracker
8
+ class Parameters
9
+ CAMPAIGN_ID_PARAM = 'campaignID'.freeze
10
+ TT_PARAM = 'tt'.freeze
11
+ MISSING_PARAM_VALUE = ''.freeze
12
+ PERMITTED_PARAMS = %w(campaignID materialID affiliateID reference).freeze
13
+
14
+ MissingParametersError = Class.new(RuntimeError)
15
+
16
+
17
+ def initialize(params)
18
+ @params = params
19
+ if params.include?(CAMPAIGN_ID_PARAM)
20
+ extend Paired
21
+ elsif params.include?(TT_PARAM)
22
+ extend Delimited
23
+ else
24
+ fail MissingParametersError.new("URL must include either '#{CAMPAIGN_ID_PARAM}' or '#{TT_PARAM}' parameter")
25
+ end
26
+ end
27
+
28
+ def to_hash
29
+ PERMITTED_PARAMS.each_with_object({}) do |param, result|
30
+ key = param.underscore.to_sym
31
+ result[key] = send(key)
32
+ end.merge(redirect_url: redirect_url)
33
+ end
34
+
35
+ private
36
+
37
+ attr_reader :params
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,32 @@
1
+ require_relative '../parameters'
2
+
3
+ module Rack
4
+ class TradeTracker
5
+ class Parameters
6
+
7
+ module Delimited
8
+ DELIMITER = '_'.freeze
9
+ REDIRECT_PARAM = 'r'.freeze
10
+
11
+ def self.extended(base)
12
+ values = base.instance_eval do
13
+ param = params[TT_PARAM]
14
+ param.present? ? param.split(DELIMITER) : []
15
+ end
16
+
17
+ PERMITTED_PARAMS.each_with_index do |param, index|
18
+ define_method param.underscore do
19
+ values[index] || MISSING_PARAM_VALUE
20
+ end
21
+ end
22
+ end
23
+
24
+
25
+ def redirect_url
26
+ params[REDIRECT_PARAM] || MISSING_PARAM_VALUE
27
+ end
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,23 @@
1
+ require_relative '../parameters'
2
+
3
+ module Rack
4
+ class TradeTracker
5
+ class Parameters
6
+
7
+ module Paired
8
+ REDIRECT_PARAM = 'redirectURL'.freeze
9
+
10
+ def self.extended(base)
11
+ params = base.send(:params)
12
+
13
+ (PERMITTED_PARAMS.dup << REDIRECT_PARAM).each do |param|
14
+ define_method param.underscore do
15
+ params[param] || MISSING_PARAM_VALUE
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ module Rack
2
+ class TradeTracker
3
+ VERSION = "0.1.3"
4
+ end
5
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Rack::TradeTracker::Cookie do
4
+ let(:params_hash) { {campaign_id: 'ABCDEF', material_id: '123456', affiliate_id: 'ABC123', reference: 'ref'} }
5
+ let(:parameters) { double :parameters, params_hash.merge(to_hash: params_hash) }
6
+ let(:domain) { 'test.com' }
7
+ let(:time_now) { Time.now }
8
+ let(:digest) { Digest::MD5.hexdigest('CHK_ABCDEF::123456::ABC123::ref') }
9
+
10
+ before { allow(Time).to receive(:now).and_return(time_now) }
11
+
12
+ subject { Rack::TradeTracker::Cookie.new(domain,parameters) }
13
+
14
+ it 'is named after the campaign_id' do
15
+ expect(subject.name).to eq 'TT2_ABCDEF'
16
+ end
17
+
18
+ it 'generates a checksum' do
19
+ expect(subject.checksum).to eq digest
20
+ end
21
+
22
+ it 'generates a UNIX timestamp' do
23
+ expect(subject.timestamp).to eq time_now.to_i
24
+ end
25
+
26
+ describe '#value' do
27
+ it 'combines material_id, affiliate_id, reference, checkSum and timeStamp' do
28
+ expected = "123456::ABC123::ref::#{digest}::#{time_now.to_i}"
29
+ expect(subject.value).to eq expected
30
+ end
31
+ end
32
+
33
+ describe 'as_hash' do
34
+ it 'includes the value' do
35
+ expect(subject.as_hash[:value]).to eq subject.value
36
+ end
37
+ it 'includes the domain' do
38
+ expect(subject.as_hash[:domain]).to eq ".#{domain}"
39
+ end
40
+ it 'includes the path' do
41
+ expect(subject.as_hash[:path]).to eq '/'
42
+ end
43
+ it 'includes the expiry' do
44
+ expect(subject.as_hash[:expires]).to eq time_now + 1.year
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,135 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Rack::TradeTracker::Handler do
4
+ let(:app) { ->(env) { [200, env, 'app'] } }
5
+ let(:domain) { 'test.com' }
6
+ let(:path) { '/path' }
7
+
8
+ subject { Rack::TradeTracker::Handler.new(domain, path, app) }
9
+
10
+ describe 'call' do
11
+ let(:env) { env_for(url) }
12
+
13
+ context 'with an alternate path' do
14
+ let(:url) { 'http://www.example.com/some-other-path' }
15
+
16
+ it 'passes the call along' do
17
+ expect(app).to receive(:call).with(env)
18
+ subject.call(env)
19
+ end
20
+ end
21
+
22
+ context 'with a matching path' do
23
+ let(:url) { URI.escape("http://www.example.com/path?#{params}") }
24
+ let(:cookie) { double :cookie, name: 'TT2_ABCDEF', value: '123456::ABC123::ref', as_hash: {value: '123456::ABC123::ref',
25
+ expires: 1.year.from_now,
26
+ path: '/',
27
+ domain: domain} }
28
+
29
+ shared_examples 'redirects with cookie' do |redirect_url|
30
+ attr_reader :status, :headers, :body, :trackback_url, :query
31
+
32
+ before do
33
+ allow(Rack::TradeTracker::Cookie).to receive(:new).and_return(cookie)
34
+ @status, @headers, @body = subject.call(env)
35
+ url = URI(headers['Location'])
36
+ @trackback_url = URI::HTTP.build(host: url.host).to_s
37
+ @query = url.query.split('&').map { |attr| attr.split('=', -1) }.to_h if url.query
38
+ end
39
+
40
+ it 'redirects to the trackback URL' do
41
+ expect(status).to eq 301
42
+ expect(trackback_url).to eq Rack::TradeTracker::TRACKBACK_URL
43
+ end
44
+
45
+ it 'includes the campaign_id parameter' do
46
+ expect(query['c']).to eq 'ABCDEF'
47
+ end
48
+
49
+ it 'includes the material_id parameter' do
50
+ expect(query['m']).to eq '123456'
51
+ end
52
+
53
+ it 'includes the affiliate_id parameter' do
54
+ expect(status).to eq 301
55
+ expect(query['a']).to eq 'ABC123'
56
+ end
57
+
58
+ it 'includes the redirect_url parameter' do
59
+ expect(status).to eq 301
60
+ expect(query['u']).to eq redirect_url
61
+ end
62
+
63
+ it 'creates the Trade Tracker cookie' do
64
+ cookie_value = "123456%3A%3AABC123%3A%3Aref; domain=test.com; path=/; expires=#{Rack::Utils.rfc2822(cookie.as_hash[:expires].utc)}"
65
+ expect(headers['set-cookie']).to eq "#{cookie.name}=#{cookie_value}"
66
+ end
67
+
68
+ it 'adds the P3P header' do
69
+ expect(headers['P3P']).to eq 'CP="ALL PUR DSP CUR ADMi DEVi CONi OUR COR IND"'
70
+ end
71
+
72
+ context 'with a logger defined in the rack env' do
73
+ let(:logger) { double :logger, info: nil }
74
+
75
+ before { env['rack.logger'] = logger }
76
+
77
+ it 'logs the redirect' do
78
+ subject.call(env)
79
+ expect(logger).to have_received(:info).with("Redirecting to Trade Tracker with cookie: #{URI.encode('123456::ABC123::ref')}")
80
+ end
81
+ end
82
+ end
83
+
84
+ context 'with paired parameters' do
85
+ include_examples 'redirects with cookie', 'www.your-proper-url.com' do
86
+ let(:params) { 'campaignID=ABCDEF&materialID=123456&affiliateID=ABC123&redirectURL=www.your-proper-url.com' }
87
+ end
88
+
89
+ context 'with missing redirect URL' do
90
+ include_examples 'redirects with cookie', '' do
91
+ let(:params) { 'campaignID=ABCDEF&materialID=123456&affiliateID=ABC123' }
92
+ end
93
+ end
94
+ end
95
+
96
+ context 'with delimited parameters' do
97
+ include_examples 'redirects with cookie', 'www.your-proper-url.com' do
98
+ let(:params) { 'tt=ABCDEF_123456_ABC123_ref&r=www.your-proper-url.com' }
99
+ end
100
+
101
+ context 'with missing redirect URL' do
102
+ include_examples 'redirects with cookie', '' do
103
+ let(:params) { 'tt=ABCDEF_123456_ABC123_ref' }
104
+ end
105
+ end
106
+ end
107
+
108
+ context 'with missing campaignID and tt parameters' do
109
+ let(:params) { '' }
110
+
111
+ it 'redirects to root with 302' do
112
+ status, headers, body = subject.call(env)
113
+ expect(status).to eq 302
114
+ expect(headers['Location']).to eq 'http://www.example.com'
115
+ end
116
+
117
+ it 'does not forward the request' do
118
+ expect(app).not_to receive(:call)
119
+ subject.call(env)
120
+ end
121
+
122
+ context 'with a logger defined in the rack env' do
123
+ let(:logger) { double :logger, error: nil }
124
+
125
+ before { env['rack.logger'] = logger }
126
+
127
+ it 'logs the redirect' do
128
+ subject.call(env)
129
+ expect(logger).to have_received(:error).with('Redirecting to root as Trade Tracker parameters missing')
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Rack::TradeTracker::Parameters do
4
+ let(:request) { double :request, params: params }
5
+ subject { Rack::TradeTracker::Parameters.new(request.params) }
6
+
7
+ context 'when request includes campaignID parameter' do
8
+ let(:params) { {'campaignID' => 'a-campaign-id',
9
+ 'materialID' => 'a-material-id',
10
+ 'affiliateID' => 'an-affiliate-id',
11
+ 'redirectURL' => 'www.your-proper-url.com',
12
+ }}
13
+
14
+ it 'extracts the parameters correctly' do
15
+ params.each do |key, value|
16
+ expect(subject.send(key.underscore)).to eq value
17
+ end
18
+ end
19
+
20
+ it 'converts to a hash' do
21
+ expected = {campaign_id: subject.campaign_id,
22
+ material_id: subject.material_id,
23
+ affiliate_id: subject.affiliate_id,
24
+ reference: subject.reference,
25
+ redirect_url: subject.redirect_url}
26
+
27
+ expect(subject.to_hash).to eq expected
28
+ end
29
+
30
+ context 'with a missing parameter' do
31
+ before { params.delete('materialID') }
32
+
33
+ it 'renders empty string for the missing parameter' do
34
+ expect(subject.material_id).to eq ''
35
+ end
36
+ end
37
+ end
38
+
39
+ context 'when request includes tt parameter' do
40
+ (1..4).each do |num_params|
41
+ context "with #{num_params} values" do
42
+ let(:provided_params) { Rack::TradeTracker::Parameters::PERMITTED_PARAMS[0..(num_params - 1)] }
43
+ let(:params) { {'tt' => num_params.times.map(&:to_s).join('_'), 'r' => 'www.your-proper-url.com'} }
44
+
45
+ it 'extracts the parameters correctly' do
46
+ provided_params.each_with_index do |param, index|
47
+ expect(subject.send(param.underscore)).to eq index.to_s
48
+ end
49
+ end
50
+
51
+ it 'converts to a hash' do
52
+ expected = {campaign_id: subject.campaign_id,
53
+ material_id: subject.material_id,
54
+ affiliate_id: subject.affiliate_id,
55
+ reference: subject.reference,
56
+ redirect_url: subject.redirect_url}
57
+
58
+ expect(subject.to_hash).to eq expected
59
+ end
60
+
61
+ it 'extracts the redirect url' do
62
+ expect(subject.redirect_url).to eq 'www.your-proper-url.com'
63
+ end
64
+ end
65
+ end
66
+
67
+ context 'with missing tt and campaignID parameters' do
68
+ let(:params) { {} }
69
+
70
+ it 'fails with MissingParametersError' do
71
+ expect{ subject }.to raise_error Rack::TradeTracker::Parameters::MissingParametersError
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Rack::TradeTracker do
4
+ let(:app) { ->(env) { [200, env, 'app'] } }
5
+ let(:domain) { 'test.com' }
6
+ let(:path) { '/path' }
7
+
8
+ subject { Rack::TradeTracker.new(app, domain: domain, path: path) }
9
+
10
+ it 'has a version number' do
11
+ expect(Rack::TradeTracker::VERSION).not_to be nil
12
+ end
13
+
14
+ it 'requires a domain' do
15
+ expect { Rack::TradeTracker.new(app, path: path) }.to raise_error(Rack::TradeTracker::InitializationError)
16
+ end
17
+
18
+ it 'requires a path' do
19
+ expect { Rack::TradeTracker.new(app, domain: domain) }.to raise_error(Rack::TradeTracker::InitializationError)
20
+ end
21
+
22
+ describe 'call' do
23
+ let(:env) { env_for(url) }
24
+ let(:url) { 'http://www.example.com/path' }
25
+
26
+ it 'delegates to the Handler' do
27
+ handler = double(:handler)
28
+ allow(Rack::TradeTracker::Handler).to receive(:new).with(domain, path, app).and_return(handler)
29
+ expect(handler).to receive(:call).with(env)
30
+ subject.call(env)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,23 @@
1
+ require "bundler/setup"
2
+ require 'rack/mock'
3
+ require "rack/trade_tracker"
4
+
5
+ module Helpers
6
+ def env_for(url)
7
+ Rack::MockRequest.env_for(url)
8
+ end
9
+ end
10
+
11
+ RSpec.configure do |config|
12
+ # Enable flags like --only-failures and --next-failure
13
+ config.example_status_persistence_file_path = ".rspec_status"
14
+
15
+ # Disable RSpec exposing methods globally on `Module` and `main`
16
+ config.disable_monkey_patching!
17
+
18
+ config.expect_with :rspec do |c|
19
+ c.syntax = :expect
20
+ end
21
+
22
+ config.include Helpers
23
+ end
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-trade_tracker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.3
5
+ platform: ruby
6
+ authors:
7
+ - Ben Forrest
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-08-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.15'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.15'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec_junit_formatter
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: activesupport
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rack
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: The Rack::TradeTracker gem is for use with the Trade Tracker affiliate
98
+ network. The gem provides a Rack middleware component to handle Trade Tracker's
99
+ redirect mechanism.
100
+ email:
101
+ - ben@clickmechanic.com
102
+ executables: []
103
+ extensions: []
104
+ extra_rdoc_files: []
105
+ files:
106
+ - Rakefile
107
+ - Readme.md
108
+ - lib/rack/trade_tracker.rb
109
+ - lib/rack/trade_tracker/cookie.rb
110
+ - lib/rack/trade_tracker/handler.rb
111
+ - lib/rack/trade_tracker/parameters.rb
112
+ - lib/rack/trade_tracker/parameters/delimited.rb
113
+ - lib/rack/trade_tracker/parameters/paired.rb
114
+ - lib/rack/trade_tracker/version.rb
115
+ - spec/rack/trade_tracker/cookie_spec.rb
116
+ - spec/rack/trade_tracker/handler_spec.rb
117
+ - spec/rack/trade_tracker/parameters_spec.rb
118
+ - spec/rack/trade_tracker_spec.rb
119
+ - spec/spec_helper.rb
120
+ homepage: https://github.com/ClickMechanic/rack-trade_tracker
121
+ licenses:
122
+ - MIT
123
+ metadata:
124
+ allowed_push_host: https://rubygems.org
125
+ post_install_message:
126
+ rdoc_options: []
127
+ require_paths:
128
+ - lib
129
+ required_ruby_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ requirements: []
140
+ rubyforge_project:
141
+ rubygems_version: 2.6.12
142
+ signing_key:
143
+ specification_version: 4
144
+ summary: Provides TradeTracker redirect endpoint as Rack middleware
145
+ test_files: []