samurai 0.0.5 → 0.2.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 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: []