Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' into dev

  • Loading branch information...
commit df00503ff12e9030fc684542ff8c03af6ee75050 2 parents 4136dc0 + 32b4fd1
@tomblomfield tomblomfield authored
View
9 .gitignore
@@ -1,5 +1,10 @@
-lib/irb_seed.rb
-lib/seed.rb
+lib/*seed*.rb
lib/example.rb
+lib/*test*.rb
doc/
+Gemfile.lock
+gocardless*.gem
.yardoc
+.yardopts
+gocardless-*.gem
+gocardless-ruby.zip
View
3  .yardopts
@@ -1,3 +0,0 @@
---exclude lib/gocardless/utils.rb
---exclude lib/*seed*.rb
---exclude lib/example.rb
View
12 Gemfile
@@ -0,0 +1,12 @@
+source :rubygems
+
+gemspec
+
+group :development do
+ gem "guard", "~> 0.8.8"
+ if RUBY_PLATFORM.downcase.include?("darwin")
+ gem "guard-rspec", "~> 0.5.4"
+ gem "rb-fsevent", "~> 0.4.3.1"
+ gem "growl_notify", "~> 0.0.3"
+ end
+end
View
6 Guardfile
@@ -0,0 +1,6 @@
+guard 'rspec', :version => 2, :cli => '--color --format doc' do
+ watch(%r{^spec/.+_spec\.rb$})
+ watch(%r{^lib/gocardless/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
+ watch('lib/gocardless.rb') { "spec/gocardless_spec.rb" }
+ watch('spec/spec_helper.rb') { "spec" }
+end
View
22 LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2011 GoCardless
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
View
320 README.md
@@ -1,317 +1,15 @@
+![GoCardless](https://gocardless.com/resources/logo.png)
-# GoCardless Ruby Client
-
-
-## Introduction
+## GoCardless Ruby Client Library
The GoCardless Ruby client provides a simple Ruby interface to the GoCardless
-API. This document covers the usage of the Ruby library. For information on the
-structure of the API itself, or for details on particular API resources, read
-the [API overview](http://docs.gocardless.com/api/index.html).
-
-### Using the API Sandbox
-
-By default, the {GoCardless::Client client} will use
-`https://www.gocardless.com` as the base URL. To use the API sandbox, you need
-to set the base URL to `https://sandbox.gocardless.com`:
-
- GoCardless::Client.base_url = 'https://sandbox.gocardless.com'
-
-This will force all requests to use the sandbox rather than the main site.
-
-### Getting Started
-
-To use the GoCardless API, you'll need to register a new app in the Developer
-Panel. Registering an app provides you with an app ID and an app secret. These
-are both required to access the API.
-
-To start with, you'll need to create an instance of the {GoCardless::Client}
-class, providing your app id and app secret as arguments to the constructor:
-
- client = GoCardless::Client.new(APP_ID, APP_SECRET)
-
-
-## <a name="link-merchant-account">Linking a Merchant Account with the App</a>
-
-Every instance of the GoCardless::Client accesses the API on behalf of *one*
-merchant.
-
-For this to happen, the merchant must go through a brief authorization process
-to generate an access token, which you may then use to act on behalf of the
-merchant via the API. Note that an app may have access tokens for many merchant
-accounts, but you must create a new instance of GoCardless::Client for each
-merchant.
-
-To authorize an app, the merchant must be redirected to the GoCardless servers,
-where they will be presented with a page that allows them to link their account
-with the app. The URL to which the the merchant is sent contains information
-about the app, as well as the URL (`redirect_uri`) where the merchant should be
-sent back to once they've completed the process. The Ruby client library takes
-care of most of this - only the `redirect_uri` must be provided:
-
- auth_url = client.new_merchant_url(:redirect_uri => 'http://mywebsite.com/cb')
-
-(`new_merchant_url` is an alias for `authorize_url`, for OAuth followers)
-
-More detail can be found in the [API docs](http://docs.gocardless.com/api/index.html).
-
-The merchant must then be redirect to the generated `auth_url`, where they will
-complete a short process to give the app access to their account. If the
-merchant hasn't already created a merchant account on GoCardless, they will be
-prompted to do so first.
-
-Once the merchant has authorized the app, they will be redirected back to the
-URL specified earlier (`http://mywebsite.com/cb` in the example above). The
-API servers will include an "authorization code" as a query string parameter
-(`code`):
-
- auth_code = params[:code]
-
-This authorization code may be exchanged for an access token, which may be used
-to access the merchant's account through the API. You can use the
-{GoCardless::Client client} object to perform the exchange. The `redirect_uri`
-that you used in the previous step must also be provided.
-
-Note: providing `redirect_uri` is a OAuth 2.0 requirement to prevent attacks
-based on the modification of `redirect_uri` during the earlier
-`authorization_url` stage.
-
- client.fetch_access_token(auth_code, :redirect_uri => 'http://mywebsite.com/cb')
-
- new_token = client.access_token
-
-The {GoCardless::Client#fetch_access_token fetch_access_token} method will set
-`client.access_token` and return that `access_token`. You should store this
-access token alongside the merchant's record in your database for future use.
-
-You can also find the merchant's access token in the [Developer
-Panel](https://sandbox.gocardless.com/) and set it manually on the client
-instance;
-
- client.access_token = "qU9OXphbgi51hr5ryeQcY9N3e1wZ77PEoSqJulf2pR79DH53a+wtFMJxlco30y4t manage_merchant:74"
-
-Note: ensure `manage_merchant:merchant_id` (the scope) is included if you are
-entering the access token manually
-
-To check whether your client is correctly configured, call `client.merchant` -
-this should successfully return a {GoCardless::Merchant Merchant} object.
-
-## Creating new Subscriptions, Pre-Authorizations and One-Off Payments
-
-To create new subscriptions, you must have correctly configured the client
-object with *both* App ID/Secret and a merchant's access token (see above on
-["Linking a Merchant Account"](#link-merchant-account)</a>).
-
-To set up new subscriptions, pre-authorizations and one-off payments between a
-user and merchant account, you need to send the user to the GoCardless Connect
-site to approve the process. This is broadly similar to the process for linking
-merchant accounts with an app; the principal difference being the absence of a
-resulting access token here.
-
-Certain attributes for are required for each type of resource, while others are
-optional - see the [API documentation](https://sandbox.gocardless.com/) for
-full details.
-
-These attributes are sent as query-string arguments. For security purposes, the
-request must also contain a `timestamp`, `nonce` (randomly-generated value),
-`merchant_id` and a `signature`. The {GoCardless::Client client} object takes
-care of this security, so you simply need to provide the relevant attributes;
-
- url = client.new_subscription_url(:interval_unit => :week,
- :interval_length => 1,
- :amount => "30.00",
- :description => 'Premium membership')
-
-Note: The amount should be provided as a string in pounds and pence (e.g.
-`'29.50'` for £29.50).
-
-Redirecting a user to `url` will take them to a page where they can authorize a
-subscription of £30 every week. Once they have authorized the subscription,
-they will be taken back to the `redirect_uri` specified on the app in the
-Developer Panel. Optionally, you may provide a different `redirect_uri`,
-although the host must match your app `redirect_uri`.
-
-After the user has authorized the subscription, he will be sent back to
-the `redirect_uri`, with some additional query string parameters appended.
-These parameters will contain information about the resource (subscription,
- pre authorization or bill) that has just been created.
-
-Important: Before the resource may be considered active, the app *must* confirm
-it via the API. To do so, pass a hash of parameters received above to the
-{GoCardless::Client#confirm\_resource} method on the {GoCardless::Client
-client} object.
-
-Example:
-
-The app receives the user back at the url
-
-http://mysite.com/confirm?resource_id=35&resource_type=subscription&resource_uri=https%3A%2F%2Fwww.gocardless.com%2Fapi%2Fv1%2Fsubscriptions%2F35&signature=bbf5b6d6d889a0a9af29adaa52175b219ad913bc194a56aadec0b0e994b0a15f
-
-The params are:
-
- params = {
- :resource_id => 35,
- :resource_type => "subscription",
- :resource_uri => "https://www.gocardless.com/api/v1/subscroptions/35"
- :signature => "bbf5b6d6d889a0a9af29adaa52175b219ad913bc194a56aadec0b0e994b0a15f"
- }
-
-You should pass these params into {GoCardless::Client#confirm_resource confirm_resource}
-
- subscription = client.confirm_resource(params)
-
-The confirmed resource object (e.g. {GoCardless::Subscription subscription})
-will be returned.
-
-Note: {GoCardless::Client#confirm_resource confirm_resource} is an important
-method. First, it validates that the resource parameters received at
-`redirect_uri` have not been tampered with by verifying the signature against
-one generated by the app secret. Second, it sends a request to the API server
-to tell it to confirm the resource creation. If a resource is not confirmed, it
-will be removed from the database after a short period of time.
-
-## Creating bills
-
-The GoCardless API may also be used to create and modify bills under an
-existing PreAuthorization. To create a bill, use the
-{GoCardless::PreAuthorization#create_bill create\_bill} method on
-{GoCardless::PreAuthorization PreAuthorization} objects, providing the amount
-in pounds and pence as the only argument:
-
- bill = pre_authorization.create_bill(:amount => "15.00")
- bill # => <GoCardless::Bill ...>
-
-
-## Retrieving Data from the API
-
-To create new subscriptions, you must have correctly configured the client
-object with *both* App ID/Secret and a merchant's access token (see above on
-["Linking a Merchant Account"](#link-merchant-account)</a>).
-
-Once your {GoCardless::Client client} has a valid access token, you may request
-data about the merchant associated with the token. To access the merchant's
-information, use the `merchant` attribute on the client object. This returns an
-instance of {GoCardless::Merchant}:
-
- merchant = client.merchant # => <GoCardless::Merchant ...>
- merchant.name # => "Harry's Burritos"
-
-The {GoCardless::Merchant merchant} object also provides access to related
-data, such as {GoCardless::Bill bills}, {GoCardless::Subscription
-subscriptions} and {GoCardless::PreAuthorization pre-authorizations}:
-
- merchant.bills # => [<GoCardless::Bill>, ...]
- merchant.subscriptions # => [<GoCardless::Subscription>, ...]
- merchant.pre_authorizations # => [<GoCardless::PreAuthorization>, ...]
-
-These may also be filtered with various parameters:
-
- merchant.bills(:paid => true) # Only fetches paid bills
- merchant.subscriptions(:user_id => 1) # User 1's subscriptions
-
-See the [API documentation](https://sandbox.gocardless.com/) for full details
-of parameters that you can provide
-
-Note that each time you use the {GoCardless::Client#merchant merchant}
-attribute of {GoCardless::Client}, an API call will be made. To prevent many
-unnecessary calls to the API server, assign the {GoCardless::Merchant merchant}
-object to a variable and use that instead:
-
- # Rather than this (6 API calls):
- client.merchant.bills
- client.merchant.subscriptions
- client.merchant.pre_authorizations
-
- # Do this (4 API calls):
- merchant = client.merchant
- merchant.bills
- merchant.subscriptions
- merchant.pre_authorizations
-
-To lookup instances of each resource type by id, accessor methods are provided
-on {GoCardless::Client client} objects:
-
- client.subscription(5) # => <GoCardless::Subscription ...>
- client.payment(10) # => <GoCardless::Payment ...>
-
-Some resources also have defined sub-resources. For example, bills are defined
-as sub-resources of subscriptions. When a {GoCardless::Resource Resource} is
-instantiated, methods will be created if any sub-resources are defined. These
-methods return an array of sub-resource objects:
-
- subscription = merchant.subscriptions.first
- subscription.bills # => [<GoCardless::Bill>, ...]
-
-## Example usage
-
-This process can be carried out in an IRB shell for testing
-
- require 'gocardless'
-
- # Set the `base_url` to sandbox if used in testing
- GoCardless::Client.base_url = "https://sandbox.gocardless.com"
-
- # These are found in the GoCardless "app" interface in the Developer Panel
- APP_ID = '3QmpV5yi8Ii9Rc2uCwalWRsqkpibtk5ISOk/F+oyzrOoNpjGguZ4IRn2379agARS'
- APP_SECRET = '8oCITH2AVhaUYqJ+5hjyt8JUlSo5m/WTYLH8E/GO+TrBWdRK45lvoRt/zetr+t5Y'
-
- # Create a new instance of the GoCardless API client
- client = GoCardless::Client.new(APP_ID, APP_SECRET)
-
- # Generate the OAuth 'authorize endpoint' URL
- url = client.new_merchant_url(:redirect_uri => 'http://mywebsite.com/cb')
-
- # Now, redirect the user (merchant) to 'url'. In Rails this would
- # look like:
- #
- # redirect_to url
- #
- # They will be presented with a screen where they confirm the link between
- # their merchant account and the app. Once they are done, they will be
- # redirected back to the 'redirect_uri' provided.
-
- # Now you need to retrieve the authorization code from the query string
- # parameters:
- #
- # auth_code = params[:auth_code]
- #
- # Then exchange the authorization code for an access token:
-
- client.fetch_access_token(auth_code, :redirect_uri => 'http://mywebsite.com/cb')
-
- # The access token should be saved to the database alongside the merchant.
- # You can get the access token using 'client.access_token'
-
- # To check the API client is correctly associated with a merchant account
- client.merchant # => <GoCardless::Merchant ...>
-
- # To create a new subscription (or pre_authorization or one-off bill),
- # generate the appropriate URL:
- url = client.new_subscription_url(:interval_unit => :week,
- :interval_length => 6,
- :amount => "30.00",
- :description => 'Premium membership')
-
- # The client allows you to look up most resources by their id
- client.subscription(5) # => <GoCardless::Subscription ...>
- client.pre_authorization(5) # => <GoCardless::PreAuthorization ...>
- client.bill(5) # => <GoCardless::Bill ...>
- client.payment(5) # => <GoCardless::Payment ...>
-
- # Retrieve referenced resources directly from resource objects
- subscription = client.subscription(5)
- subscription.merchant # => <GoCardless::Merchant ...>
+API.
- # Then redirect the user to the URL:
- #
- # redirect_to url
- #
- # When the user is redirected back to your site, you need to confirm the
- # new subscription (assuming params is a hash of the query-string parameters):
- subscription = client.confirm_resource(params)
+If you want to use the library as an individual merchant, refer to the
+[merchant guide](https://gocardless.com/docs/ruby/merchant_client_guide). If
+you want to support multiple merchant accounts, see the
+[partner guide](https://gocardless.com/docs/ruby/partner_client_guide).
- # Create a new bill via the API under a pre_authorization.
- # No user interaction is needed beyond the initial pre_authorization
- pre_authorization = client.pre_authorization(7)
- pre_authorization.create_bill(500) # £5.00 bill
+The full API reference is available at on
+[rubydoc.info](http://rubydoc.info/github/gocardless/gocardless-ruby/master/frames).
View
6 Rakefile
@@ -0,0 +1,6 @@
+require 'yard'
+
+YARD::Rake::YardocTask.new do |t|
+ t.files = ['lib/**/*.rb'].reject { |f| f.match(/seed|example/) }
+end
+
View
8 gocardless.gemspec
@@ -1,15 +1,17 @@
require File.expand_path('../lib/gocardless/version', __FILE__)
Gem::Specification.new do |gem|
- gem.add_runtime_dependency 'oauth2', '~> 0.5.0.rc1'
- gem.add_runtime_dependency 'json', '~> 1.5.3'
+ gem.add_runtime_dependency "oauth2", "~> 0.5.0.rc1"
+ gem.add_runtime_dependency "json", "~> 1.5.3"
gem.add_development_dependency 'rspec', '~> 2.6'
gem.add_development_dependency 'mocha', '~> 0.9.12'
+ gem.add_development_dependency "yard", "~> 0.7.3"
+ gem.add_development_dependency "redcarpet", "~> 1.17.2"
gem.authors = ["Harry Marr"]
gem.description = %q{A Ruby wrapper for the GoCardless API}
- gem.email = ['harry@groupay.co.uk']
+ gem.email = ['harry@gocardless.com']
gem.files = `git ls-files`.split("\n")
gem.homepage = 'https://github.com/gocardless/gocardless-ruby'
gem.name = 'gocardless'
View
20 lib/gocardless.rb
@@ -9,4 +9,24 @@ module GoCardless
require 'gocardless/payment'
require 'gocardless/merchant'
require 'gocardless/client'
+
+ class << self
+ attr_accessor :environment
+ attr_reader :account_details, :client
+
+ def account_details=(details)
+ raise ClientError.new("You must provide a token") unless details[:token]
+ @account_details = details
+ @client = Client.new(details)
+ end
+
+ %w(new_subscription_url new_pre_authorization_url new_bill_url confirm_resource).each do |name|
+ class_eval <<-EOM
+ def #{name}(*args)
+ raise ClientError.new('Need to set account_details first') unless @client
+ @client.send(:#{name}, *args)
+ end
+ EOM
+ end
+ end
end
View
6 lib/gocardless/bill.rb
@@ -16,8 +16,8 @@ class Bill < Resource
date_accessor :created_at
def source
- klass = GoCardless.const_get(source_type.to_s.camelize)
- klass.find(@client, @source_id)
+ klass = GoCardless.const_get(Utils.camelize(source_type.to_s))
+ klass.find_with_client(client, @source_id)
end
def source=(obj)
@@ -27,7 +27,7 @@ def source=(obj)
"PreAuthorization")
end
@source_id = obj.id
- @source_type = klass.underscore
+ @source_type = Utils.underscore(klass)
end
def save
View
45 lib/gocardless/client.rb
@@ -1,13 +1,17 @@
- 'rubygems'
+require 'rubygems'
require 'json'
require 'oauth2'
require 'openssl'
require 'uri'
require 'cgi'
+require 'time'
module GoCardless
class Client
- DEFAULT_BASE_URL = 'https://www.gocardless.com'
+ BASE_URLS = {
+ :production => 'https://gocardless.com',
+ :sandbox => 'https://sandbox.gocardless.com',
+ }
API_PATH = '/api/v1'
class << self
@@ -16,7 +20,7 @@ def base_url=(url)
end
def base_url
- @base_url || DEFAULT_BASE_URL
+ @base_url || BASE_URLS[GoCardless.environment || :production]
end
def api_url
@@ -24,13 +28,18 @@ def api_url
end
end
- def initialize(app_id, app_secret, token = nil)
- @app_id = app_id
- @app_secret = app_secret
- @oauth_client = OAuth2::Client.new(app_id, app_secret,
+ def initialize(args = {})
+ Utils.symbolize_keys! args
+ @app_id = args[:app_id]
+ @app_secret = args[:app_secret]
+ raise ClientError.new("You must provide an app_id") unless @app_id
+ raise ClientError.new("You must provide an app_secret") unless @app_secret
+
+ @oauth_client = OAuth2::Client.new(@app_id, @app_secret,
:site => self.class.base_url,
:token_url => '/oauth/access_token')
- self.access_token = token if token
+
+ self.access_token = args[:token] if args[:token]
end
# Generate the OAuth authorize url
@@ -113,42 +122,42 @@ def api_put(path, data = {})
# @return [Merchant] the merchant associated with the client's access token
def merchant
raise ClientError, 'Access token missing' unless @access_token
- Merchant.new(self, api_get("/merchants/#{merchant_id}"))
+ Merchant.new_with_client(self, api_get("/merchants/#{merchant_id}"))
end
# @method subscripton(id)
# @param [String] id of the subscription
# @return [Subscription] the subscription matching the id requested
def subscription(id)
- Subscription.find(self, id)
+ Subscription.find_with_client(self, id)
end
# @method pre_authorization(id)
# @param [String] id of the pre_authorization
# @return [PreAuthorization] the pre_authorization matching the id requested
def pre_authorization(id)
- PreAuthorization.find(self, id)
+ PreAuthorization.find_with_client(self, id)
end
# @method user(id)
# @param [String] id of the user
# @return [User] the User matching the id requested
def user(id)
- User.find(self, id)
+ User.find_with_client(self, id)
end
# @method bill(id)
# @param [String] id of the bill
# @return [Bill] the Bill matching the id requested
def bill(id)
- Bill.find(self, id)
+ Bill.find_with_client(self, id)
end
# @method payment(id)
# @param [String] id of the payment
# @return [Payment] the payment matching the id requested
def payment(id)
- Payment.find(self, id)
+ Payment.find_with_client(self, id)
end
# Create a new bill under a given pre-authorization
@@ -157,7 +166,7 @@ def payment(id)
# @param [Hash] attrs must include +:pre_authorization_id+ and +:amount+
# @return [Bill] the created bill object
def create_bill(attrs)
- Bill.new(self, attrs).save
+ Bill.new_with_client(self, attrs).save
end
# Generate the URL for creating a new subscription. The parameters passed
@@ -204,7 +213,7 @@ def new_bill_url(params)
# @param [Hash] params the response parameters returned by the API server
# @return [Resource] the confirmed resource object
def confirm_resource(params)
- params = params.symbolize_keys
+ params = Utils.symbolize_keys(params)
# Only pull out the relevant parameters, other won't be included in the
# signature so will cause false negatives
keys = [:resource_id, :resource_type, :resource_uri, :state, :signature]
@@ -228,8 +237,8 @@ def confirm_resource(params)
:headers => headers)
# Initialize the correct class according to the resource's type
- klass = GoCardless.const_get(params[:resource_type].camelize)
- klass.find(self, params[:resource_id])
+ klass = GoCardless.const_get(Utils.camelize(params[:resource_type]))
+ klass.find_with_client(self, params[:resource_id])
else
raise SignatureError, 'An invalid signature was detected'
end
View
10 lib/gocardless/merchant.rb
@@ -12,35 +12,35 @@ class Merchant < Resource
def subscriptions(params = {})
path = "/merchants/#{self.id}/subscriptions"
@client.api_get(path, params).map do |attrs|
- GoCardless::Subscription.new(@client, attrs)
+ GoCardless::Subscription.new_with_client(@client, attrs)
end
end
def pre_authorizations(params = {})
path = "/merchants/#{self.id}/pre_authorizations"
@client.api_get(path, params).map do |attrs|
- GoCardless::PreAuthorization.new(@client, attrs)
+ GoCardless::PreAuthorization.new_with_client(@client, attrs)
end
end
def users(params = {})
path = "/merchants/#{self.id}/users"
@client.api_get(path, params).map do |attrs|
- GoCardless::User.new(@client, attrs)
+ GoCardless::User.new_with_client(@client, attrs)
end
end
def bills(params = {})
path = "/merchants/#{self.id}/bills"
@client.api_get(path, params).map do |attrs|
- GoCardless::Bill.new(@client, attrs)
+ GoCardless::Bill.new_with_client(@client, attrs)
end
end
def payments(params = {})
path = "/merchants/#{self.id}/payments"
@client.api_get(path, params).map do |attrs|
- GoCardless::Payment.new(@client, attrs)
+ GoCardless::Payment.new_with_client(@client, attrs)
end
end
end
View
2  lib/gocardless/pre_authorization.rb
@@ -14,7 +14,7 @@ class PreAuthorization < Resource
# @option attrs [amount] amount the bill amount in pence
# @return [Bill] the created bill object
def create_bill(attrs)
- Bill.new(@client, attrs.merge(:source => self)).save
+ Bill.new_with_client(client, attrs.merge(:source => self)).save
end
end
end
View
46 lib/gocardless/resource.rb
@@ -2,9 +2,7 @@
module GoCardless
class Resource
- def initialize(client, hash = {})
- @client = client
-
+ def initialize(hash = {})
# Handle sub resources
sub_resource_uris = hash.delete('sub_resource_uris')
unless sub_resource_uris.nil?
@@ -27,28 +25,43 @@ def initialize(client, hash = {})
metaclass.send(:define_method, name) do |*args|
# 'name' will be something like 'bills', convert it to Bill and
# look up the resource class with that name
- klass = GoCardless.const_get(name.to_s.singularize.camelize)
+ class_name = Utils.camelize(Utils.singularize(name.to_s))
+ klass = GoCardless.const_get(class_name)
# Convert the results to instances of the looked-up class
params = args.first || {}
query = default_query.nil? ? nil : default_query.merge(params)
client.api_get(path, query).map do |attrs|
- klass.new(client, attrs)
+ klass.new(attrs).tap { |m| m.client = client }
end
end
end
end
# Set resource attribute values
- hash.each { |key,val| send("#{key}=", val) }
+ hash.each { |key,val| send("#{key}=", val) if respond_to?("#{key}=") }
end
+ attr_writer :client
+
class << self
attr_accessor :endpoint
- def find(client, id)
+ def new_with_client(client, attrs = {})
+ self.new(attrs).tap { |obj| obj.client = client }
+ end
+
+ def find_with_client(client_obj, id)
path = endpoint.gsub(':id', id.to_s)
- data = client.api_get(path)
- self.new(client, data)
+ data = client_obj.api_get(path)
+ obj = self.new(data)
+ obj.client = client_obj
+ obj
+ end
+
+ def find(id)
+ message = "Merchant details not found, set GoCardless.account_details"
+ raise Error, message unless GoCardless.client
+ self.find_with_client(GoCardless.client, id)
end
def date_writer(*args)
@@ -76,8 +89,8 @@ def reference_reader(*args)
name = attr.to_s.sub(/_id$/, '')
define_method(name.to_sym) do
obj_id = instance_variable_get("@#{attr}")
- klass = GoCardless.const_get(name.camelize)
- klass.find(@client, obj_id)
+ klass = GoCardless.const_get(Utils.camelize(name))
+ klass.find_with_client(client, obj_id)
end
end
end
@@ -92,7 +105,7 @@ def reference_writer(*args)
name = attr.to_s.sub(/_id$/, '')
define_method("#{name}=".to_sym) do |obj|
- klass = GoCardless.const_get(name.camelize)
+ klass = GoCardless.const_get(Utils.camelize(name))
if !obj.is_a?(klass)
raise ArgumentError, "Object must be an instance of #{klass}"
end
@@ -132,6 +145,7 @@ def updatable?
def to_hash
attrs = instance_variables.map { |v| v.to_s.sub(/^@/, '') }
+ attrs.delete 'client'
Hash[attrs.select { |v| respond_to? v }.map { |v| [v.to_sym, send(v)] }]
end
@@ -157,6 +171,10 @@ def save
protected
+ def client
+ @client || GoCardless.client
+ end
+
def save_data(data)
method = if self.persisted?
raise "#{self.class} cannot be updated" unless self.class.updatable?
@@ -166,8 +184,8 @@ def save_data(data)
'post'
end
path = self.class.endpoint.gsub(':id', id.to_s)
- response = @client.send("api_#{method}", path, data)
- response.each { |key,val| send("#{key}=", val) } if response.is_a? Hash
+ response = client.send("api_#{method}", path, data)
+ response.each { |key,val| send("#{key}=", val) if respond_to?("#{key}=") } if response.is_a? Hash
end
end
end
View
46 lib/gocardless/utils.rb
@@ -1,30 +1,36 @@
-class String
- def camelize
- self.split('_').map(&:capitalize).join
- end
+module GoCardless
+ module Utils
+ class << self
- def underscore
- self.gsub(/(.)([A-Z])/) { "#{$1}_#{$2.downcase}" }.downcase
- end
+ # String Helpers
+ def camelize(str)
+ str.split('_').map(&:capitalize).join
+ end
- def singularize
- # This should probably be a bit more robust
- self.sub(/s$/, '').sub(/i$/, 'us')
- end
-end
+ def underscore(str)
+ str.gsub(/(.)([A-Z])/) { "#{$1}_#{$2.downcase}" }.downcase
+ end
+ def singularize(str)
+ # This should probably be a bit more robust
+ str.sub(/s$/, '').sub(/i$/, 'us')
+ end
-class Hash
- def symbolize_keys
- dup.symbolize_keys!
- end
+ # Hash Helpers
+ def symbolize_keys(hash)
+ symbolize_keys! hash.dup
+ end
+
+ def symbolize_keys!(hash)
+ hash.keys.each do |key|
+ sym_key = key.to_s.to_sym rescue key
+ hash[sym_key] = hash.delete(key) unless hash.key?(sym_key)
+ end
+ hash
+ end
- def symbolize_keys!
- self.keys.each do |key|
- self[(key.to_s.to_sym rescue key)] ||= self.delete(key)
end
- self
end
end
View
11 spec/bill_spec.rb
@@ -4,12 +4,13 @@
before :each do
@app_id = 'abc'
@app_secret = 'xyz'
- @client = GoCardless::Client.new(@app_id, @app_secret)
+ GoCardless.account_details = {:app_id => @app_id, :app_secret => @app_secret,
+ :token => 'xxx manage_merchant:1'}
+ @client = GoCardless.client
end
it "source getter works" do
- b = GoCardless::Bill.new(@client, :source_type => :subscription,
- :source_id => 123)
+ b = GoCardless::Bill.new(:source_type => :subscription, :source_id => 123)
@client.access_token = 'TOKEN manage_merchant:123'
stub_get(@client, :id => 123)
source = b.source
@@ -18,8 +19,8 @@
end
it "source setter works" do
- b = GoCardless::Bill.new(@client)
- b.source = GoCardless::Subscription.new(@client, :id => 123)
+ b = GoCardless::Bill.new
+ b.source = GoCardless::Subscription.new(:id => 123)
b.source_id.should == 123
b.source_type.should.to_s == 'subscription'
end
View
51 spec/client_spec.rb
@@ -4,10 +4,43 @@
before :each do
@app_id = 'abc'
@app_secret = 'xyz'
- @client = GoCardless::Client.new(@app_id, @app_secret)
@redirect_uri = 'http://test.com/cb'
end
+ describe ".base_url" do
+ it "returns the correct url for the production environment" do
+ GoCardless.environment = :production
+ GoCardless::Client.base_url.should == 'https://gocardless.com'
+ end
+
+ it "returns the correct url for the sandbox environment" do
+ GoCardless.environment = :sandbox
+ GoCardless::Client.base_url.should == 'https://sandbox.gocardless.com'
+ end
+
+ it "returns the correct url when it's set manually" do
+ GoCardless::Client.base_url = 'https://abc.gocardless.com'
+ GoCardless::Client.base_url.should == 'https://abc.gocardless.com'
+ end
+ end
+
+ describe "#new" do
+ it "without an app id should raise an error" do
+ lambda do
+ GoCardless::Client.new({:app_secret => @app_secret})
+ end.should raise_exception(GoCardless::ClientError)
+ end
+ it "without an app_secret should raise an error" do
+ lambda do
+ GoCardless::Client.new({:app_id => @app_id})
+ end.should raise_exception(GoCardless::ClientError)
+ end
+ end
+
+ before do
+ @client = GoCardless::Client.new({:app_id => @app_id, :app_secret => @app_secret})
+ end
+
describe "#authorize_url" do
it "fails without a redirect uri" do
lambda { @client.authorize_url }.should raise_exception(ArgumentError)
@@ -130,7 +163,7 @@
merchant_url = '/api/v1/merchants/123'
token.expects(:get).with { |p,o| p == merchant_url }.returns response
- GoCardless::Merchant.stubs(:new)
+ GoCardless::Merchant.stubs(:new_with_client)
@client.merchant
end
@@ -152,11 +185,11 @@
%w{subscription pre_authorization user bill payment}.each do |resource|
describe "##{resource}" do
- it "returns the correct #{resource.camelize} object" do
+ it "returns the correct #{GoCardless::Utils.camelize(resource)} object" do
@client.access_token = 'TOKEN manage_merchant:123'
stub_get(@client, {:id => 123})
obj = @client.send(resource, 123)
- obj.should be_a GoCardless.const_get(resource.camelize)
+ obj.should be_a GoCardless.const_get(GoCardless::Utils.camelize(resource))
obj.id.should == 123
end
end
@@ -238,8 +271,8 @@
it "returns the correct object when the signature is valid" do
@client.stubs(:request).returns(stub(:parsed => {}))
- subscription = GoCardless::Subscription.new @client
- GoCardless::Subscription.expects(:find).returns subscription
+ subscription = GoCardless::Subscription.new_with_client @client
+ GoCardless::Subscription.expects(:find_with_client).returns subscription
# confirm_resource should use the Subcription class because
# the :response_type is set to subscription
@@ -248,7 +281,7 @@
end
it "includes valid http basic credentials" do
- GoCardless::Subscription.stubs(:find)
+ GoCardless::Subscription.stubs(:find_with_client)
auth = 'Basic YWJjOnh5eg=='
@client.expects(:request).once.with do |type, path, opts|
opts.should include :headers
@@ -260,7 +293,7 @@
it "works with string params" do
@client.stubs(:request)
- GoCardless::Subscription.stubs(:find)
+ GoCardless::Subscription.stubs(:find_with_client)
params = Hash[@params.dup.map { |k,v| [k.to_s, v] }]
params.keys.each { |p| p.should be_a String }
# No ArgumentErrors should be raised
@@ -332,7 +365,7 @@ def get_params(url)
it "should include a timestamp" do
# Time.now returning Pacific time
- time = Time.local(0, 0, 0, 1, 1, 2011, 0, 0, false, 'PDT')
+ time = Time.parse('Sat Jan 01 00:00:00 -0800')
Time.expects(:now).returns time
params = get_params(@client.send(:new_limit_url, :subscription, :x => 1))
# Check that timezone is ISO formatted UTC
View
41 spec/gocardless_spec.rb
@@ -0,0 +1,41 @@
+require 'spec_helper'
+
+describe GoCardless do
+ before do
+ unset_ivar GoCardless, :client
+ unset_ivar GoCardless, :account_details
+ @details = {:app_id => 'X', :app_secret => 'X', :token => 'X manage_merchant:1'}
+ end
+
+ describe ".account_details=" do
+ it "creates a Client instance" do
+ GoCardless::Client.expects :new
+ subject.account_details = @details
+ end
+
+ it "gets upset if the token is missing" do
+ expect {
+ subject.account_details = @details.merge(:token => nil)
+ }.to raise_exception GoCardless::ClientError
+ end
+ end
+
+
+ describe "delegated methods" do
+ %w(new_subscription_url new_pre_authorization_url new_bill_url confirm_resource).each do |name|
+ it "#{name} delegates to @client" do
+ subject.account_details = @details
+ subject.instance_variable_get(:@client).expects(name.to_sym)
+ subject.send(name)
+ end
+
+ it "raises an exception if the account details aren't set" do
+ expect {
+ subject.send(name)
+ }.to raise_exception GoCardless::ClientError
+ end
+ end
+ end
+
+end
+
View
7 spec/merchant_spec.rb
@@ -4,7 +4,7 @@
before :each do
@app_id = 'abc'
@app_secret = 'xyz'
- @client = GoCardless::Client.new(@app_id, @app_secret)
+ @client = GoCardless::Client.new(:app_id => @app_id, :app_secret => @app_secret)
@client.access_token = 'TOKEN123 manage_merchant:123'
@redirect_uri = 'http://test.com/cb'
end
@@ -13,7 +13,7 @@
index_methods.each do |method|
it "##{method} works correctly" do
- merchant = GoCardless::Merchant.new(@client)
+ merchant = GoCardless::Merchant.new_with_client(@client)
data = [{:id => 1}, {:id => 2}]
stub_get(@client, data)
@@ -21,7 +21,8 @@
merchant.send(method).should be_a Array
merchant.send(method).length.should == 2
merchant.send(method).zip(data).each do |obj,attrs|
- obj.class.to_s.should == "GoCardless::#{method.to_s.camelize.sub(/s$/, '')}"
+ class_name = GoCardless::Utils.camelize(method.to_s).sub(/s$/, '')
+ obj.class.to_s.should == "GoCardless::#{class_name}"
attrs.each { |k,v| obj.send(k).should == v }
end
end
View
123 spec/resource_spec.rb
@@ -6,7 +6,7 @@
attr_accessor :id, :name, :uri
end
props = {:id => 1, :name => 'test', :uri => 'http://test'}
- resource = test_resource.new(mock, props)
+ resource = test_resource.new(props)
props.each { |k,v| resource.send(k).should == v }
end
@@ -16,8 +16,8 @@
date_writer :created_at, :modified_at
end
- test_resource.instance_methods.should include 'created_at='
- test_resource.instance_methods.should include 'modified_at='
+ test_resource.instance_methods.map(&:to_s).should include 'created_at='
+ test_resource.instance_methods.map(&:to_s).should include 'modified_at='
end
it "date writers work properly" do
@@ -25,7 +25,7 @@
date_writer :created_at
end
- resource = test_resource.new(nil)
+ resource = test_resource.new
time = '2011-12-12T12:00:00Z'
resource.created_at = time
date_time = resource.instance_variable_get(:@created_at)
@@ -40,10 +40,10 @@
date_accessor :created_at, :modified_at
end
- test_resource.instance_methods.should include 'created_at='
- test_resource.instance_methods.should include 'created_at'
- test_resource.instance_methods.should include 'modified_at='
- test_resource.instance_methods.should include 'modified_at'
+ test_resource.instance_methods.map(&:to_s).should include 'created_at='
+ test_resource.instance_methods.map(&:to_s).should include 'created_at'
+ test_resource.instance_methods.map(&:to_s).should include 'modified_at='
+ test_resource.instance_methods.map(&:to_s).should include 'modified_at'
end
it "date readers work properly" do
@@ -51,36 +51,55 @@
date_accessor :created_at
end
- resource = test_resource.new(nil)
+ resource = test_resource.new
date = DateTime.now
resource.instance_variable_set(:@created_at, date)
resource.created_at.should == date
end
end
- describe "#find" do
+ describe ".find_with_client" do
it "instantiates the correct object" do
test_resource = Class.new(GoCardless::Resource) do
self.endpoint = '/test/:id'
end
mock_client = mock
mock_client.expects(:api_get).returns({:id => 123})
- resource = test_resource.find(mock_client, 123)
+ resource = test_resource.find_with_client(mock_client, 123)
resource.should be_a test_resource
resource.id.should == 123
end
end
+ describe ".find" do
+ it "calls find with the default client" do
+ test_resource = Class.new(GoCardless::Resource) do
+ self.endpoint = '/test/:id'
+ end
+ GoCardless.stubs(:client => mock)
+ test_resource.expects(:find_with_client).with(GoCardless.client, 1)
+ test_resource.find(1)
+ unset_ivar GoCardless, :client
+ end
+
+ it "raises a helpful error when there is no default client" do
+ test_resource = Class.new(GoCardless::Resource) do
+ self.endpoint = '/test/:id'
+ end
+ expect { test_resource.find(1) }.to raise_error
+ end
+ end
+
describe "#reference_writer" do
it "creates reference writers properly" do
test_resource = Class.new(GoCardless::Resource) do
reference_writer :merchant_id, :user_id
end
- test_resource.instance_methods.should include 'merchant='
- test_resource.instance_methods.should include 'merchant_id='
- test_resource.instance_methods.should include 'user='
- test_resource.instance_methods.should include 'user_id='
+ test_resource.instance_methods.map(&:to_s).should include 'merchant='
+ test_resource.instance_methods.map(&:to_s).should include 'merchant_id='
+ test_resource.instance_methods.map(&:to_s).should include 'user='
+ test_resource.instance_methods.map(&:to_s).should include 'user_id='
end
it "direct assignment methods work properly" do
@@ -88,8 +107,8 @@
reference_writer :user_id
end
- resource = test_resource.new(nil)
- resource.user = GoCardless::User.new(nil, :id => 123)
+ resource = test_resource.new
+ resource.user = GoCardless::User.new(:id => 123)
resource.instance_variable_get(:@user_id).should == 123
end
@@ -106,7 +125,7 @@
reference_writer :user_id
end
expect do
- test_resource.new(nil).user = 'asdf'
+ test_resource.new.user = 'asdf'
end.to raise_exception ArgumentError
end
end
@@ -115,7 +134,7 @@
before :each do
@app_id = 'abc'
@app_secret = 'xyz'
- @client = GoCardless::Client.new(@app_id, @app_secret)
+ @client = GoCardless::Client.new(:app_id => @app_id, :app_secret => @app_secret)
@redirect_uri = 'http://test.com/cb'
end
@@ -124,10 +143,10 @@
reference_reader :merchant_id, :user_id
end
- test_resource.instance_methods.should include 'merchant'
- test_resource.instance_methods.should include 'merchant_id'
- test_resource.instance_methods.should include 'user'
- test_resource.instance_methods.should include 'user_id'
+ test_resource.instance_methods.map(&:to_s).should include 'merchant'
+ test_resource.instance_methods.map(&:to_s).should include 'merchant_id'
+ test_resource.instance_methods.map(&:to_s).should include 'user'
+ test_resource.instance_methods.map(&:to_s).should include 'user_id'
end
it "lookup methods work properly" do
@@ -135,7 +154,7 @@
reference_reader :user_id
end
- resource = test_resource.new(@client)
+ resource = test_resource.new_with_client(@client)
resource.instance_variable_set(:@user_id, 123)
@client.access_token = 'TOKEN manage_merchant:123'
stub_get(@client, {:id => 123})
@@ -159,20 +178,20 @@
reference_accessor :merchant_id, :user_id
end
- test_resource.instance_methods.should include 'merchant'
- test_resource.instance_methods.should include 'merchant_id'
- test_resource.instance_methods.should include 'user'
- test_resource.instance_methods.should include 'user_id'
- test_resource.instance_methods.should include 'merchant='
- test_resource.instance_methods.should include 'merchant_id='
- test_resource.instance_methods.should include 'user='
- test_resource.instance_methods.should include 'user_id='
+ test_resource.instance_methods.map(&:to_s).should include 'merchant'
+ test_resource.instance_methods.map(&:to_s).should include 'merchant_id'
+ test_resource.instance_methods.map(&:to_s).should include 'user'
+ test_resource.instance_methods.map(&:to_s).should include 'user_id'
+ test_resource.instance_methods.map(&:to_s).should include 'merchant='
+ test_resource.instance_methods.map(&:to_s).should include 'merchant_id='
+ test_resource.instance_methods.map(&:to_s).should include 'user='
+ test_resource.instance_methods.map(&:to_s).should include 'user_id='
end
end
it "#persisted? works" do
- GoCardless::Resource.new(nil).persisted?.should be_false
- GoCardless::Resource.new(nil, :id => 1).persisted?.should be_true
+ GoCardless::Resource.new.persisted?.should be_false
+ GoCardless::Resource.new(:id => 1).persisted?.should be_true
end
describe "#save" do
@@ -193,28 +212,28 @@
it "sends the correct data parameters" do
client = mock
data = {:x => 1, :y => 2}
- resource = @test_resource.new(client, data)
+ resource = @test_resource.new_with_client(client, data)
client.expects(:api_post).with(anything, data)
resource.save
end
it "sends the correct path" do
client = mock
- resource = @test_resource.new(client)
+ resource = @test_resource.new_with_client(client)
client.expects(:api_post).with('/test', anything)
resource.save
end
it "POSTs when not persisted" do
client = mock
- resource = @test_resource.new(client)
+ resource = @test_resource.new_with_client(client)
client.expects(:api_post)
resource.save
end
it "PUTs when already persisted" do
client = mock
- resource = @test_resource.new(client, :id => 1)
+ resource = @test_resource.new_with_client(client, :id => 1)
client.expects(:api_put)
resource.save
end
@@ -227,7 +246,7 @@
end
client = mock('client') { stubs :api_post }
- test_resource.new(client).save
+ test_resource.new_with_client(client).save
end
it "succeeds when persisted and update allowed" do
@@ -237,7 +256,7 @@
end
client = mock('client') { stubs :api_put }
- test_resource.new(client, :id => 1).save
+ test_resource.new_with_client(client, :id => 1).save
end
it "fails when not persisted and create not allowed" do
@@ -245,7 +264,7 @@
updatable
end
- expect { test_resource.new(mock).save }.to raise_error
+ expect { test_resource.new.save }.to raise_error
end
it "fails when persisted and update not allowed" do
@@ -253,7 +272,7 @@
creatable
end
- expect { test_resource.new(mock, :id => 1).save }.to raise_error
+ expect { test_resource.new(:id => 1).save }.to raise_error
end
end
@@ -263,7 +282,7 @@
end
attrs = {:id => 1, :uri => 'http:', :x => 'y'}
- resource = test_resource.new('CLIENT', attrs)
+ resource = test_resource.new_with_client(mock, attrs)
resource.to_hash.should == attrs
end
@@ -274,7 +293,7 @@
reference_accessor :person_id
end
- bill = test_resource.new(nil, {
+ bill = test_resource.new({
:amount => '10',
:when => DateTime.now,
:person_id => 15
@@ -324,20 +343,20 @@ class UpdatableResource < GoCardless::Resource
end
it "are defined on instances" do
- r = @test_resource.new(stub, @attrs)
+ r = @test_resource.new(@attrs)
r.should respond_to :bills
end
it "aren't defined for other instances of the class" do
- @test_resource.new(stub, @attrs)
- resource = @test_resource.new stub
+ @test_resource.new(@attrs)
+ resource = @test_resource.new
resource.should_not respond_to :bills
end
it "use the correct uri path" do
client = mock()
client.expects(:api_get).with('/api/bills/', anything).returns([])
- r = @test_resource.new(client, @attrs)
+ r = @test_resource.new_with_client(client, @attrs)
r.bills
end
@@ -345,14 +364,14 @@ class UpdatableResource < GoCardless::Resource
client = mock()
client.expects(:api_get).with('/bills/', anything).returns([])
uris = {'bills' => 'https://test.com/api/v123/bills/'}
- r = @test_resource.new(client, 'sub_resource_uris' => uris)
+ r = @test_resource.new_with_client(client, 'sub_resource_uris' => uris)
r.bills
end
it "use the correct query string params" do
client = mock()
client.expects(:api_get).with(anything, 'merchant_id' => '1').returns([])
- r = @test_resource.new(client, @attrs)
+ r = @test_resource.new_with_client(client, @attrs)
r.bills
end
@@ -360,13 +379,13 @@ class UpdatableResource < GoCardless::Resource
client = mock()
params = { 'merchant_id' => '1', :amount => '10.00' }
client.expects(:api_get).with(anything, params).returns([])
- r = @test_resource.new(client, @attrs)
+ r = @test_resource.new_with_client(client, @attrs)
r.bills(:amount => '10.00')
end
it "return instances of the correct resource class" do
client = stub(:api_get => [{:id => 1}])
- r = @test_resource.new(client, @attrs)
+ r = @test_resource.new_with_client(client, @attrs)
ret = r.bills
ret.should be_a Array
ret.first.should be_a GoCardless::Bill
View
4 spec/spec_helper.rb
@@ -14,3 +14,7 @@ def stub_get(client, data)
token.stubs(:get).returns response
end
+def unset_ivar(obj, var)
+ obj.instance_variable_set "@#{var}", nil if obj.instance_variable_get "@#{var}"
+end
+
View
87 spec/utils_spec.rb
@@ -1,52 +1,67 @@
require 'spec_helper'
-describe String do
- describe "#camelize" do
- it "converts underscored words to camel case" do
- "a_test_string".camelize.should == "ATestString"
- end
- end
+describe GoCardless::Utils do
- describe "#underscore" do
- it "converts camel case words to underscored form" do
- "ATestString".underscore.should == "a_test_string"
+ describe "string helpers" do
+ describe ".camelize" do
+ it "converts underscored words to camel case" do
+ GoCardless::Utils.camelize("a_test_string").should == "ATestString"
+ end
end
- end
- describe "#singularize" do
- it "removes trailing 's' characters" do
- "desks".singularize.should == "desk"
+ describe ".underscore" do
+ it "converts camel case words to underscored form" do
+ GoCardless::Utils.underscore("ATestString").should == "a_test_string"
+ end
end
- it "converts 'i' suffix to 'us'" do
- "cacti".singularize.should == "cactus"
+ describe ".singularize" do
+ it "removes trailing 's' characters" do
+ GoCardless::Utils.singularize("desks").should == "desk"
+ end
+
+ it "converts 'i' suffix to 'us'" do
+ GoCardless::Utils.singularize("cacti").should == "cactus"
+ end
end
end
-end
-describe Hash do
- describe "#symbolize_keys" do
- it "converts keys to symbols" do
- hash = {'string' => true, 123 => true, :symbol => true}
- keys = hash.symbolize_keys.keys
- keys.length.should == 3
- keys.should include :string
- keys.should include :'123'
- keys.should include :symbol
- end
+ describe "hash helpers" do
+ describe ".symbolize_keys" do
+ it "converts keys to symbols" do
+ hash = {'string' => true, 123 => true, :symbol => true}
+ keys = GoCardless::Utils.symbolize_keys(hash).keys
+ keys.length.should == 3
+ keys.should include :string
+ keys.should include :'123'
+ keys.should include :symbol
+ end
+
+ it "preserves the original hash" do
+ hash = {'string' => true}
+ GoCardless::Utils.symbolize_keys(hash)
+ hash.keys.should == ['string']
+ end
+
+ it "doesn't overwrite existing symbol keys" do
+ hash = {'x' => 1, :x => 2}
+ GoCardless::Utils.symbolize_keys(hash).should == hash
+ end
- it "preserves the original hash" do
- hash = {'string' => true}
- hash.symbolize_keys
- hash.keys.should == ['string']
+ it "works with sinatra params' default proc" do
+ hash = Hash.new {|hash,key| hash[key.to_s] if Symbol === key }
+ hash['x'] = 1
+ GoCardless::Utils.symbolize_keys(hash).should == {:x => 1}
+ end
end
- end
- describe "#symbolize_keys!" do
- it "modifies the original hash" do
- hash = {'string' => true}
- hash.symbolize_keys!
- hash.keys.should == [:string]
+ describe ".symbolize_keys!" do
+ it "modifies the original hash" do
+ hash = {'string' => true}
+ GoCardless::Utils.symbolize_keys!(hash)
+ hash.keys.should == [:string]
+ end
end
end
+
end
Please sign in to comment.
Something went wrong with that request. Please try again.