samurai 0.0.5 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
1
  pkg/*
2
2
  *.gem
3
3
  .bundle
4
+ doc
5
+ TESTING
data/lib/samurai.rb CHANGED
@@ -1,36 +1,41 @@
1
+ # Author:: Graeme Rouse
2
+ # Copyright:: Copyright (c) 2011 Arizona Bay, LLC
3
+
1
4
  module Samurai
5
+ SITE = 'https://samurai.feefighters.com/v1/'
6
+ DEFAULT_OPTIONS = {:site => SITE}
2
7
 
3
- mattr_accessor :site
4
- @@site = case Rails.env
5
- when 'development'
6
- 'http://localhost:3002'
7
- when 'staging'
8
- 'http://staging.api.ubergateway.com'
9
- else
10
- 'http://api.ubergateway.com'
11
- end << '/v1/'
8
+ # Gets the provider site that the gem is configured to hit
9
+ def self.site # ::nodoc::
10
+ @@options[:site]
11
+ end
12
12
 
13
- mattr_accessor :merchant_key
14
- @@merchant_key = nil
13
+ def self.merchant_key # ::nodoc::
14
+ @@options[:merchant_key]
15
+ end
15
16
 
16
- mattr_accessor :merchant_password
17
- @@merchant_password = nil
17
+ def self.merchant_password # ::nodoc::
18
+ @@options[:merchant_password]
19
+ end
18
20
 
19
- mattr_accessor :gateway_token
20
- @@gateway_token = nil
21
+ def self.gateway_token # ::nodoc::
22
+ @@options[:gateway_token]
23
+ end
24
+
25
+ def self.options
26
+ @@options
27
+ end
21
28
 
22
- def self.setup_site(site, merchant_key, merchant_password, gateway_token = nil)
23
- site += '/v1/' unless site =~ /\/v1\/$/
24
- @@site = site
25
- @@merchant_key = merchant_key
26
- @@merchant_password = merchant_password
27
- @@gateway_token = gateway_token if gateway_token
29
+ def self.options=(value)
30
+ @@options = (value || {}).reverse_merge(DEFAULT_OPTIONS)
28
31
  Samurai::Base.setup_site!
29
32
  end
30
33
 
31
34
  end
32
35
 
36
+ require 'samurai/cacheable_by_token'
33
37
  require 'samurai/base'
34
38
  require 'samurai/gateway'
35
39
  require 'samurai/payment_method'
36
40
  require 'samurai/transaction'
41
+ require 'samurai/message'
data/lib/samurai/base.rb CHANGED
@@ -1,6 +1,11 @@
1
+ begin
2
+ require 'active_resource'
3
+ rescue LoadError
4
+ require 'activeresource' # for older versions of activeresource
5
+ end
1
6
  class Samurai::Base < ActiveResource::Base
2
-
3
- def self.setup_site!
7
+
8
+ def self.setup_site! # ::nodoc::
4
9
  self.site = Samurai.site
5
10
  self.user = Samurai.merchant_key
6
11
  self.password = Samurai.merchant_password
@@ -0,0 +1,38 @@
1
+ module Samurai::CacheableByToken
2
+
3
+ # The default cache stores the values for the duration of the request
4
+ # Different caching strategies can be employed to keep the data around longer:
5
+ # * class variables
6
+ # * Rails.cache
7
+ # * memecached
8
+ # * redis cache
9
+ def self.included(klass)
10
+ klass.send :cattr_accessor, :cache
11
+ klass.send :cache=, {}
12
+ klass.extend(ClassExtensions)
13
+ end
14
+
15
+ module ClassExtensions
16
+ # Override the ActiveResource +find+ method to query the cache before hitting the provider.
17
+ def find(*arguments)
18
+ token = arguments.first
19
+ if token.is_a?(String) && self.cache[token]
20
+ # cache hit
21
+ self.cache[token]
22
+ else
23
+ # cache miss
24
+ obj = super(*arguments)
25
+ self.cache[obj.id] = obj
26
+ end
27
+ end
28
+ end
29
+
30
+ # Overrides the ActiveResource +save+ method to update the current
31
+ # model in the cache
32
+ def save
33
+ super
34
+ # update self in the cache
35
+ self.class.cache[self.id] = self
36
+ end
37
+
38
+ end
@@ -1,27 +1,56 @@
1
1
  class Samurai::Gateway < Samurai::Base
2
-
2
+
3
+ # Returns the default gateway specified by Samurai.gateway_token if you passed it into Samurai.setup_site.
3
4
  def self.the_gateway
4
5
  Samurai::Gateway.new(:id => Samurai.gateway_token)
5
6
  end
6
7
 
7
- def purchase(payment_method_token, amount, descriptor)
8
+ # Convienince method that calls the purchase method on the defalt gateway.
9
+ def self.purchase(*args)
10
+ the_gateway.purchase(*args)
11
+ end
12
+
13
+ # Convienince method that calls the authorize method on the defalt gateway.
14
+ def self.authorize(*args)
15
+ the_gateway.authorize(*args)
16
+ end
17
+
18
+ # Convienience method to authorize and capture a payment_method for a particular amount in one transaction.
19
+ # Parameters:
20
+ # +payment_method_token+:: token identifying the payment method to authorize
21
+ # +amount+:: amount to authorize
22
+ # options:: an optional has of additional values to pass in accepted values are:
23
+ # *+descriptor+:: descriptor for the transaction
24
+ # *+custom+:: custom data, this data does not get passed to the gateway, it is stored within samurai.feefighters.com only
25
+ # *+customer_reference+:: an identifier for the customer, this will appear in the gateway if supported
26
+ # *+billing_reference::+ an indentifier for the purchase, this will appear in the gateway if supported
27
+ # Returns a Samurai::Transaction containing the gateway's response.
28
+ def purchase(payment_method_token, amount, options = {})
29
+ execute(:purchase, options.merge(:payment_method_token => payment_method_token, :amount => amount))
30
+ end
31
+
32
+ # Authorize a payment_method for a particular amount.
33
+ # Parameters:
34
+ # +payment_method_token+:: token identifying the payment method to authorize
35
+ # +amount+:: amount to authorize
36
+ # options:: an optional has of additional values to pass in accepted values are:
37
+ # *+descriptor+:: descriptor for the transaction
38
+ # *+custom+:: custom data, this data does not get passed to the gateway, it is stored within samurai.feefighters.com only
39
+ # *+customer_reference+:: an identifier for the customer, this will appear in the gateway if supported
40
+ # *+billing_reference::+ an indentifier for the purchase, this will appear in the gateway if supported
41
+ # Returns a Samurai::Transaction containing the gateway's response.
42
+ def authorize(payment_method_token, amount, options = {})
43
+ execute(:authorize, options.merge(:payment_method_token => payment_method_token, :amount => amount))
44
+ end
45
+
46
+ private
47
+
48
+ def execute(action, options = {})
49
+ transaction = Samurai::Transaction.transaction_payload(options)
8
50
  # send a purchase request
9
- resp = post(:purchase,
10
- :transaction => {
11
- :amount => amount,
12
- :type => 'purchase',
13
- :payment_method_token => payment_method_token,
14
- :currency_code => 'USD',
15
- :descriptor => descriptor
16
- }
17
- )
51
+ resp = post(action, {}, transaction)
18
52
  # return the response, wrapped in a Samurai::Transaction
19
53
  Samurai::Transaction.new.load_attributes_from_response(resp)
20
54
  end
21
-
22
- # TODO implement this functionality
23
- # def authorize
24
- # post(:authorize)
25
- # end
26
55
 
27
56
  end
@@ -0,0 +1,10 @@
1
+ class Samurai::Message < Samurai::Base # :nodoc:
2
+ def to_xml(options = {})
3
+ builder = options[:builder] || Builder::XmlMarkup.new(options)
4
+ builder.tag!(:message) do
5
+ self.attributes.each do |key, value|
6
+ builder.tag!(key, value)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -1,6 +1,8 @@
1
1
  class Samurai::PaymentMethod < Samurai::Base
2
2
 
3
- def id
3
+ include Samurai::CacheableByToken
4
+
5
+ def id # :nodoc:
4
6
  self.token
5
7
  end
6
8
 
@@ -8,6 +10,8 @@ class Samurai::PaymentMethod < Samurai::Base
8
10
  self.payment_method_token
9
11
  end
10
12
 
13
+ # Retains the payment method on samurai.feefighters.com. Retain a payment method if
14
+ # it will not be used immediately.
11
15
  def retain
12
16
  self.post(:retain)
13
17
  end
@@ -1,23 +1,54 @@
1
1
  class Samurai::Transaction < Samurai::Base
2
-
3
- def id
4
- self.reference_id
5
- end
6
2
 
7
- def token
3
+ include Samurai::CacheableByToken
4
+
5
+ # Alias for transaction_token
6
+ def id # :nodoc:
8
7
  transaction_token
9
8
  end
9
+ alias_method :token, :id
10
+
11
+ # Captures an authorization. Optionally specify an +amount+ to do a partial capture of the initial
12
+ # authorization. The default is to capture the full amount of the authroization.
13
+ def capture(amount = nil, options = {})
14
+ execute(:capture, {:amount => amount || self.amount}.reverse_merge(options))
15
+ end
10
16
 
11
- def capture
12
-
17
+ # Void this transaction. If the transaction has not yet been captured and settled it can be voided to
18
+ # prevent any funds from transfering.
19
+ def void(options = {})
20
+ execute(:void, options)
13
21
  end
14
22
 
15
- def void
16
-
23
+ # Create a credit or refund against the original transaction.
24
+ # Optionally accepts an +amount+ to credit, the default is to credit the full
25
+ # value of the original amount
26
+ def credit(amount = nil, options = {})
27
+ execute(:credit, {:amount => amount || self.amount}.reverse_merge(options))
17
28
  end
18
29
 
19
- def credit
20
-
30
+ private
31
+
32
+ def execute(action, options = {})
33
+ resp = post(action, {}, self.class.transaction_payload(options))
34
+ # return the response, wrapped in a Samurai::Transaction
35
+ Samurai::Transaction.new.load_attributes_from_response(resp)
36
+ end
37
+
38
+ # Builds an xml payload that represents the transaction data to submit to samuari.feefighters.com
39
+ def self.transaction_payload(options = {})
40
+ {
41
+ :amount => options[:amount],
42
+ :type => options[:type],
43
+ :payment_method_token => options[:payment_method_token],
44
+ :currency_code => options[:currency_code] || (options[:payment_method_token] && 'USD'), # currency code is only required for payloads that include the PMT
45
+ :descriptor => options[:descriptor],
46
+ :custom => options[:custom],
47
+ :customer_reference => options[:customer_reference],
48
+ :billing_reference => options[:billing_reference]
49
+ }.
50
+ reject{ |k,v| v.nil? }.
51
+ to_xml(:skip_instruct => true, :root => 'transaction', :dasherize => false)
21
52
  end
22
-
53
+
23
54
  end
@@ -1,3 +1,3 @@
1
1
  module Samurai
2
- VERSION = "0.0.5".freeze
2
+ VERSION = "0.2.1".freeze
3
3
  end
data/samurai.gemspec CHANGED
@@ -13,8 +13,12 @@ Gem::Specification.new do |s|
13
13
 
14
14
  s.required_rubygems_version = ">= 1.3.5"
15
15
  # s.rubyforge_project = "samurai"
16
+
17
+ s.add_dependency "activerecord", ">= 2.2.2"
16
18
 
17
19
  s.add_development_dependency "bundler", ">= 1.0.0"
20
+ s.add_development_dependency "rspec", ">= 2.6.0"
21
+ s.add_development_dependency 'fakeweb'
18
22
 
19
23
  s.files = `git ls-files`.split("\n")
20
24
  s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
@@ -0,0 +1,63 @@
1
+ require 'test/spec_helper'
2
+
3
+ describe "processing authorizations" do
4
+
5
+ before :each do
6
+ register_transaction_response(:type => 'authorize')
7
+ @authorization = Samurai::Gateway.authorize(PAYMENT_METHOD_TOKEN, @@seed)
8
+ end
9
+
10
+ it "should create a new authorization transaction" do
11
+ @authorization.gateway_response.success.should be_true
12
+ end
13
+
14
+ it "should find the authorization" do
15
+ register_transaction_response(:method => :get, :path => "transactions/#{@authorization.reference_id}", :type => 'authorize')
16
+ transaction = Samurai::Transaction.find(@authorization.reference_id)
17
+ transaction.reference_id.intern.should be_equal(@authorization.reference_id.intern)
18
+ end
19
+
20
+ it "should successfully capture" do
21
+ register_transaction_response(:method => :post, :path => "transactions/#{@authorization.id}/capture", :type => 'capture')
22
+ capture = @authorization.capture(@@seed)
23
+ capture.gateway_response.success.should be_true
24
+ end
25
+
26
+ it "should capture an authorization without specifying an amount" do
27
+ register_transaction_response(:method => :post, :path => "transactions/#{@authorization.id}/capture", :type => 'capture', :amount => @@seed)
28
+ capture = @authorization.capture
29
+ capture.amount.intern.should be_equal "#{@@seed}".intern
30
+ capture.gateway_response.success.should be_true
31
+ end
32
+
33
+ it "should partially capture an authorization" do
34
+ register_transaction_response(:method => :post, :path => "transactions/#{@authorization.id}/capture", :type => 'capture', :amount => @@seed - 1.0)
35
+ capture = @authorization.capture(@@seed - 1.0)
36
+ capture.amount.intern.should be_equal "#{@@seed - 1.0}".intern
37
+ capture.gateway_response.success.should be_true
38
+ end
39
+
40
+ it "should void an authorization" do
41
+ register_transaction_response(:method => :post, :path => "transactions/#{@authorization.id}/void", :type => 'void', :amount => @@seed)
42
+ void = @authorization.void
43
+ void.gateway_response.success.should be_true
44
+ end
45
+
46
+ it "should credit an authorization for the full amount by default" do
47
+ register_transaction_response(:method => :post, :path => "transactions/#{@authorization.id}/credit", :type => 'credit', :amount => @@seed, :success => 'false')
48
+ credit = @authorization.credit
49
+ credit.amount.intern.should be_equal "#{@@seed}".intern
50
+ pending "the response is not successful since the authorization hasn't settled" do
51
+ credit.gateway_response.success.should be_true
52
+ end
53
+ end
54
+
55
+ it "should partially credit an authorization" do
56
+ register_transaction_response(:method => :post, :path => "transactions/#{@authorization.id}/credit", :type => 'credit', :amount => @@seed - 1.0, :success => 'false')
57
+ credit = @authorization.credit(@@seed - 1.0)
58
+ credit.amount.intern.should be_equal "#{@@seed - 1.0}".intern
59
+ pending "the response is not successful since the authorization hasn't settled" do
60
+ credit.gateway_response.success.should be_true
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,37 @@
1
+ require 'test/spec_helper'
2
+
3
+ describe "Gateway actions" do
4
+
5
+ it "should return an empty gateway" do
6
+ gateway = Samurai::Gateway.the_gateway
7
+ gateway.should_not be_nil
8
+ end
9
+
10
+ it "should create a new purchase" do
11
+ register_transaction_response(:type => 'purchase')
12
+
13
+ purchase = Samurai::Gateway.purchase(PAYMENT_METHOD_TOKEN, @@seed)
14
+ purchase.gateway_response.success.should be_true
15
+ # FakeWeb.last_request
16
+ end
17
+
18
+ it "should create a new purchase with tracking data" do
19
+ register_transaction_response(:type => 'purchase')
20
+
21
+ purchase = Samurai::Gateway.purchase(PAYMENT_METHOD_TOKEN, @@seed, {
22
+ :descriptor => "A test purchase",
23
+ :custom => "some optional custom data",
24
+ :billing_reference => "ABC123",
25
+ :customer_reference => "Customer (123)"
26
+ })
27
+ purchase.gateway_response.success.should be_true
28
+ # FakeWeb.last_request
29
+ end
30
+
31
+ it "should create a non-new authorization" do
32
+ register_transaction_response(:type => 'authorize')
33
+ authorization = Samurai::Gateway.authorize(PAYMENT_METHOD_TOKEN, @@seed)
34
+ authorization.gateway_response.success.should be_true
35
+ end
36
+
37
+ end
@@ -0,0 +1,33 @@
1
+ require 'test/spec_helper'
2
+
3
+ describe "processing purchases" do
4
+
5
+ before :each do
6
+ register_transaction_response(:type => 'purchase')
7
+ @purchase = Samurai::Gateway.purchase(PAYMENT_METHOD_TOKEN, @@seed)
8
+ end
9
+
10
+ it "should process successfully" do
11
+ @purchase.gateway_response.success.should be_true
12
+ end
13
+
14
+ it "should be able to void a recent purchase" do
15
+ register_transaction_response(:method => :post, :path => "transactions/#{@purchase.id}/void", :type => 'void', :success => 'false')
16
+ void = @purchase.void
17
+ void.gateway_response.success.should be_true
18
+ end
19
+
20
+ it "should not be able to credit a recent purchase" do
21
+ register_transaction_response(:method => :post, :path => "transactions/#{@purchase.id}/credit", :type => 'void', :success => 'false')
22
+ credit = @purchase.credit
23
+ credit.gateway_response.success.should be_false
24
+ end
25
+
26
+ it "should be able to credit a settled purchase" do
27
+ pending "currently we cannot force settle a purchase, so can't test this properly" do
28
+ register_transaction_response(:method => :post, :path => "transactions/#{@purchase.id}/credit", :type => 'void', :success => 'false')
29
+ credit = @purchase.credit
30
+ credit.gateway_response.success.should be_true
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,91 @@
1
+ require 'ruby-debug'
2
+ Debugger.start
3
+ Debugger.settings[:autoeval] = true
4
+ Debugger.settings[:autolist] = 5
5
+ Debugger.settings[:reload_source_on_change] = true
6
+
7
+ SITE = ENV['site'] || 'http://localhost:3002/v1/'
8
+ USE_MOCK = !ENV['site']
9
+ PAYMENT_METHOD_TOKEN = ENV['payment_method_token'] || 'asdf'
10
+
11
+ RSpec.configure do |c|
12
+ c.before :all do
13
+ @@seed = rand(1000).to_f / 100.0
14
+ end
15
+ c.before :each do
16
+ @@seed += 1.0
17
+ end
18
+ end
19
+
20
+ require 'fakeweb'
21
+ FakeWeb.allow_net_connect = !USE_MOCK
22
+
23
+ require 'samurai'
24
+ Samurai.options = {
25
+ :site => SITE,
26
+ :merchant_key => ENV['merchant_key'] || 'e62c5a006cdd9908234193bc',
27
+ :merchant_password => ENV['merchant_password'] || '18e87d97b3a44b56fe07497e4812f14555db69df9e6ca16f',
28
+ :gateway_token => ENV['gateway_token'] || 'af762c3499f77c5f181650a7'
29
+ }
30
+
31
+ def register_transaction_response(options)
32
+ return unless USE_MOCK
33
+
34
+ options.symbolize_keys!
35
+
36
+ method = options[:method] && options[:method].to_sym || :post
37
+ type = options[:type]
38
+ path = options[:path] || "gateways/af762c3499f77c5f181650a7/#{type}"
39
+ payment_method_token = options[:payment_method_token] || PAYMENT_METHOD_TOKEN
40
+ amount = options[:amount] || 15.00
41
+ success = options[:success].blank? ? true : options[:success]
42
+
43
+ FakeWeb.register_uri(method,
44
+ "http://e62c5a006cdd9908234193bc:18e87d97b3a44b56fe07497e4812f14555db69df9e6ca16f@localhost:3002/v1/#{path}.xml",
45
+ :body => <<-EOF
46
+ <transaction>
47
+ <reference_id>3dcFjTC7LDjIjTY3nkKjBVZ8qkZ</reference_id>
48
+ <transaction_token>53VFyQKYBmN9vKfA9mHCTs79L9a</transaction_token>
49
+ <created_at type="datetime">2011-04-22T17:57:56Z</created_at>
50
+ <descriptor>Custom descriptor here if your gateway supports it.</descriptor>
51
+ <custom>Any value you like.</custom>
52
+ <transaction_type>#{type}</transaction_type>
53
+ <amount>#{amount}</amount>
54
+ <currency_code>USD</currency_code>
55
+ <gateway_token>af762c3499f77c5f181650a7</gateway_token>
56
+ <gateway_response>
57
+ <success type="boolean">#{success}</success>
58
+ <messages type="array">
59
+ <message class="error" context="gateway.avs" key="country_not_supported" />
60
+ <message class="error" context="input.cvv" key="too_short" />
61
+ </messages>
62
+ </gateway_response>
63
+ <payment_method>
64
+ <payment_method_token>#{payment_method_token}</payment_method_token>
65
+ <created_at type="datetime">2011-02-12T20:20:46Z</created_at>
66
+ <updated_at type="datetime">2011-04-22T17:57:30Z</updated_at>
67
+ <custom>Any value you want us to save with this payment method.</custom>
68
+ <is_retained type="boolean">true</is_retained>
69
+ <is_redacted type="boolean">false</is_redacted>
70
+ <is_sensitive_data_valid type="boolean">true</is_sensitive_data_valid>
71
+ <messages type="array">
72
+ <message class="error" context="input.cvv" key="too_long" />
73
+ <message class="error" context="input.card_number" key="failed_checksum" />
74
+ </messages>
75
+ <last_four_digits>1111</last_four_digits>
76
+ <card_type>visa</card_type>
77
+ <first_name>Bob</first_name>
78
+ <last_name>Smith</last_name>
79
+ <expiry_month type="integer">1</expiry_month>
80
+ <expiry_year type="integer">2020</expiry_year>
81
+ <address_1 nil="true"></address_1>
82
+ <address_2 nil="true"></address_2>
83
+ <city nil="true"></city>
84
+ <state nil="true"></state>
85
+ <zip nil="true"></zip>
86
+ <country nil="true"></country>
87
+ </payment_method>
88
+ </transaction>
89
+ EOF
90
+ )
91
+ end
metadata CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 0
9
- - 5
10
- version: 0.0.5
8
+ - 2
9
+ - 1
10
+ version: 0.2.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Graeme Rouse
@@ -16,13 +16,29 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2011-07-15 00:00:00 -07:00
19
+ date: 2011-07-20 00:00:00 -07:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
23
- name: bundler
23
+ name: activerecord
24
24
  prerelease: false
25
25
  requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 3
31
+ segments:
32
+ - 2
33
+ - 2
34
+ - 2
35
+ version: 2.2.2
36
+ type: :runtime
37
+ version_requirements: *id001
38
+ - !ruby/object:Gem::Dependency
39
+ name: bundler
40
+ prerelease: false
41
+ requirement: &id002 !ruby/object:Gem::Requirement
26
42
  none: false
27
43
  requirements:
28
44
  - - ">="
@@ -34,7 +50,37 @@ dependencies:
34
50
  - 0
35
51
  version: 1.0.0
36
52
  type: :development
37
- version_requirements: *id001
53
+ version_requirements: *id002
54
+ - !ruby/object:Gem::Dependency
55
+ name: rspec
56
+ prerelease: false
57
+ requirement: &id003 !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ hash: 23
63
+ segments:
64
+ - 2
65
+ - 6
66
+ - 0
67
+ version: 2.6.0
68
+ type: :development
69
+ version_requirements: *id003
70
+ - !ruby/object:Gem::Dependency
71
+ name: fakeweb
72
+ prerelease: false
73
+ requirement: &id004 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ hash: 3
79
+ segments:
80
+ - 0
81
+ version: "0"
82
+ type: :development
83
+ version_requirements: *id004
38
84
  description: If you are an online merchant and using samurai.feefighers.com, this gem will make your life easy. Integrate with the samuari.feefighters.com portal and process transaction.
39
85
  email:
40
86
  - graeme@ubergateway.com
@@ -52,11 +98,17 @@ files:
52
98
  - Rakefile
53
99
  - lib/samurai.rb
54
100
  - lib/samurai/base.rb
101
+ - lib/samurai/cacheable_by_token.rb
55
102
  - lib/samurai/gateway.rb
103
+ - lib/samurai/message.rb
56
104
  - lib/samurai/payment_method.rb
57
105
  - lib/samurai/transaction.rb
58
106
  - lib/samurai/version.rb
59
107
  - samurai.gemspec
108
+ - test/spec/authorization_spec.rb
109
+ - test/spec/gateway_spec.rb
110
+ - test/spec/purchase_spec.rb
111
+ - test/spec_helper.rb
60
112
  has_rdoc: true
61
113
  homepage: http://rubygems.org/gems/samurai
62
114
  licenses: []