Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New custom_method DSL for defining custom API request methods as static methods #754

Merged
merged 2 commits into from
Apr 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ inherit_from: .rubocop_todo.yml

AllCops:
DisplayCopNames: true
TargetRubyVersion: 2.0
TargetRubyVersion: 2.1
ob-stripe marked this conversation as resolved.
Show resolved Hide resolved

Layout/CaseIndentation:
EnforcedStyle: end
Expand Down
1 change: 1 addition & 0 deletions lib/stripe.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
require "stripe/country_spec"
require "stripe/coupon"
require "stripe/customer"
require "stripe/discount"
require "stripe/dispute"
require "stripe/ephemeral_key"
require "stripe/event"
Expand Down
2 changes: 2 additions & 0 deletions lib/stripe/account.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class Account < APIResource

OBJECT_NAME = "account".freeze

custom_method :reject, http_verb: :post

save_nested_resource :external_account
nested_resource_class_methods :external_account,
operations: %i[create retrieve update delete list]
remi-stripe marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
24 changes: 24 additions & 0 deletions lib/stripe/api_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,30 @@ def self.save_nested_resource(name)
end
end

# Adds a custom method to a resource class. This is used to add support for
# non-CRUDL API requests, e.g. capturing charges. custom_method takes the
ob-stripe marked this conversation as resolved.
Show resolved Hide resolved
# following parameters:
# - name: the name of the custom method to create (as a symbol)
# - http_verb: the HTTP verb for the API request (:get, :post, or :delete)
# - http_path: the path to append to the resource's URL. If not provided,
# the name is used as the path
#
# For example, this call:
# custom_method :capture, http_verb: post
# adds a `capture` class method to the resource class that, when called,
# will send a POST request to `/v1/<object_name>/capture`.
ob-stripe marked this conversation as resolved.
Show resolved Hide resolved
def self.custom_method(name, http_verb:, http_path: nil)
unless %i[get post delete].include?(http_verb)
raise ArgumentError, "Invalid http_verb value: #{http_verb.inspect}. Should be one of :get, :post or :delete."
remi-stripe marked this conversation as resolved.
Show resolved Hide resolved
end
http_path ||= name.to_s
define_singleton_method(name) do |id, params = {}, opts = {}|
url = "#{resource_url}/#{CGI.escape(id)}/#{CGI.escape(http_path)}"
resp, opts = request(http_verb, url, params, opts)
Util.convert_to_stripe_object(resp.data, opts)
end
end

def resource_url
unless (id = self["id"])
raise InvalidRequestError.new("Could not determine which URL to request: #{self.class} instance has invalid ID: #{id.inspect}", "id")
Expand Down
2 changes: 2 additions & 0 deletions lib/stripe/charge.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ class Charge < APIResource

OBJECT_NAME = "charge".freeze

custom_method :capture, http_verb: :post

def refund(params = {}, opts = {})
# Old versions of charge objects included a `refunds` field that was just
# a vanilla array instead of a Stripe list object.
Expand Down
2 changes: 2 additions & 0 deletions lib/stripe/customer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class Customer < APIResource

OBJECT_NAME = "customer".freeze

custom_method :delete_discount, http_verb: :delete, http_path: "discount"

remi-stripe marked this conversation as resolved.
Show resolved Hide resolved
save_nested_resource :source
nested_resource_class_methods :source,
operations: %i[create retrieve update delete list]
Expand Down
7 changes: 7 additions & 0 deletions lib/stripe/discount.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

module Stripe
class Discount < StripeObject
OBJECT_NAME = "discount".freeze
end
end
ob-stripe marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 2 additions & 0 deletions lib/stripe/dispute.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ class Dispute < APIResource

OBJECT_NAME = "dispute".freeze

custom_method :close, http_verb: :post

def close(params = {}, opts = {})
resp, opts = request(:post, close_url, params, opts)
initialize_from(resp.data, opts)
Expand Down
6 changes: 6 additions & 0 deletions lib/stripe/invoice.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ class Invoice < APIResource

OBJECT_NAME = "invoice".freeze

custom_method :finalize_invoice, http_verb: :post, http_path: "finalize"
custom_method :mark_uncollectible, http_verb: :post
custom_method :pay, http_verb: :post
custom_method :send_invoice, http_verb: :post, http_path: "send"
custom_method :void_invoice, http_verb: :post, http_path: "void"

def finalize_invoice(params = {}, opts = {})
url = resource_url + "/finalize"
resp, opts = request(:post, url, params, opts)
Expand Down
3 changes: 3 additions & 0 deletions lib/stripe/issuing/authorization.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ class Authorization < Stripe::APIResource

OBJECT_NAME = "issuing.authorization".freeze

custom_method :approve, http_verb: :post
custom_method :decline, http_verb: :post

def approve(params = {}, opts = {})
resp, opts = request(:post, resource_url + "/approve", params, opts)
initialize_from(resp.data, opts)
Expand Down
2 changes: 2 additions & 0 deletions lib/stripe/issuing/card.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ class Card < Stripe::APIResource

OBJECT_NAME = "issuing.card".freeze

custom_method :details, http_verb: :get

def details(params = {}, opts = {})
resp, opts = request(:get, resource_url + "/details", params, opts)
Util.convert_to_stripe_object(resp.data, opts)
Expand Down
3 changes: 3 additions & 0 deletions lib/stripe/order.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ class Order < APIResource

OBJECT_NAME = "order".freeze

custom_method :pay, http_verb: :post
custom_method :return_order, http_verb: :post, http_path: "returns"

def pay(params, opts = {})
resp, opts = request(:post, pay_url, params, opts)
initialize_from(resp.data, opts)
Expand Down
4 changes: 4 additions & 0 deletions lib/stripe/payment_intent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ class PaymentIntent < APIResource

OBJECT_NAME = "payment_intent".freeze

custom_method :cancel, http_verb: :post
custom_method :capture, http_verb: :post
custom_method :confirm, http_verb: :post

def cancel(params = {}, opts = {})
resp, opts = request(:post, resource_url + "/cancel", params, opts)
initialize_from(resp.data, opts)
Expand Down
3 changes: 3 additions & 0 deletions lib/stripe/payment_method.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ class PaymentMethod < APIResource

OBJECT_NAME = "payment_method".freeze

custom_method :attach, http_verb: :post
custom_method :detach, http_verb: :post

def attach(params = {}, opts = {})
url = resource_url + "/attach"
resp, opts = request(:post, url, params, opts)
Expand Down
2 changes: 2 additions & 0 deletions lib/stripe/payout.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ class Payout < APIResource

OBJECT_NAME = "payout".freeze

custom_method :cancel, http_verb: :post

def cancel
resp, api_key = request(:post, cancel_url)
initialize_from(resp.data, api_key)
Expand Down
2 changes: 2 additions & 0 deletions lib/stripe/review.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ class Review < APIResource

OBJECT_NAME = "review".freeze

custom_method :approve, http_verb: :post

def approve(params = {}, opts = {})
resp, opts = request(:post, resource_url + "/approve", params, opts)
initialize_from(resp.data, opts)
Expand Down
2 changes: 2 additions & 0 deletions lib/stripe/source.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ class Source < APIResource

OBJECT_NAME = "source".freeze

custom_method :verify, http_verb: :post

def detach(params = {}, opts = {})
if !respond_to?(:customer) || customer.nil? || customer.empty?
raise NotImplementedError,
Expand Down
2 changes: 2 additions & 0 deletions lib/stripe/subscription.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ class Subscription < APIResource

OBJECT_NAME = "subscription".freeze

custom_method :delete_discount, http_verb: :delete, http_path: "discount"

save_nested_resource :source

def delete_discount
Expand Down
3 changes: 3 additions & 0 deletions lib/stripe/subscription_schedule.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ class SubscriptionSchedule < APIResource

OBJECT_NAME = "subscription_schedule".freeze

custom_method :cancel, http_verb: :post
custom_method :release, http_verb: :post

nested_resource_class_methods :revision,
operations: %i[retrieve list]

Expand Down
2 changes: 2 additions & 0 deletions lib/stripe/topup.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ class Topup < APIResource

OBJECT_NAME = "topup".freeze

custom_method :cancel, http_verb: :post

def cancel
resp, api_key = request(:post, resource_url + "/cancel")
initialize_from(resp.data, api_key)
Expand Down
2 changes: 2 additions & 0 deletions lib/stripe/transfer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ class Transfer < APIResource

OBJECT_NAME = "transfer".freeze

custom_method :cancel, http_verb: :post
ob-stripe marked this conversation as resolved.
Show resolved Hide resolved

nested_resource_class_methods :reversal, operations: %i[create retrieve update list]

def cancel
Expand Down
1 change: 1 addition & 0 deletions lib/stripe/util.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ def self.object_classes # rubocop:disable Metrics/MethodLength
CountrySpec::OBJECT_NAME => CountrySpec,
Coupon::OBJECT_NAME => Coupon,
Customer::OBJECT_NAME => Customer,
Discount::OBJECT_NAME => Discount,
Dispute::OBJECT_NAME => Dispute,
EphemeralKey::OBJECT_NAME => EphemeralKey,
Event::OBJECT_NAME => Event,
Expand Down
19 changes: 11 additions & 8 deletions test/stripe/account_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,18 @@ class AccountTest < Test::Unit::TestCase
end

should "be rejectable" do
account_data = { id: "acct_foo" }
stub_request(:get, "#{Stripe.api_base}/v1/accounts/acct_foo")
.to_return(body: JSON.generate(account_data))

stub_request(:post, "#{Stripe.api_base}/v1/accounts/acct_foo/reject")
.to_return(body: JSON.generate(account_data))

account = Stripe::Account.retrieve("acct_foo")
account.reject(reason: "fraud")
account = account.reject(reason: "fraud")
assert_requested :post, "#{Stripe.api_base}/v1/accounts/#{account.id}/reject"
assert account.is_a?(Stripe::Account)
end

context ".reject" do
should "reject the account" do
account = Stripe::Account.reject("acct_foo", reason: "fraud")
assert_requested :post, "#{Stripe.api_base}/v1/accounts/#{account.id}/reject"
assert account.is_a?(Stripe::Account)
end
end

should "be creatable" do
Expand Down
21 changes: 21 additions & 0 deletions test/stripe/charge_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,27 @@ class ChargeTest < Test::Unit::TestCase
assert charge.is_a?(Stripe::Charge)
end

context "#capture" do
should "capture the charge" do
charge = Stripe::Charge.retrieve("ch_123")
charge = charge.capture(amount: 100)
assert_requested :post,
"#{Stripe.api_base}/v1/charges/ch_123/capture",
body: { amount: 100 }
assert charge.is_a?(Stripe::Charge)
end
end

context ".capture" do
should "capture the charge" do
charge = Stripe::Charge.capture("ch_123", amount: 100)
ob-stripe marked this conversation as resolved.
Show resolved Hide resolved
assert_requested :post,
"#{Stripe.api_base}/v1/charges/ch_123/capture",
body: { amount: 100 }
assert charge.is_a?(Stripe::Charge)
end
end

ob-stripe marked this conversation as resolved.
Show resolved Hide resolved
context "#mark_as_fraudulent" do
should "charges should be able to be marked as fraudulent" do
charge = Stripe::Charge.retrieve("ch_123")
Expand Down
16 changes: 12 additions & 4 deletions test/stripe/customer_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class CustomerTest < Test::Unit::TestCase
should "create a new subscription" do
customer = Stripe::Customer.retrieve("cus_123")
subscription = customer.create_subscription(items: [{ plan: "silver" }])
assert_requested :post, "#{Stripe.api_base}/v1/customers/#{customer.id}/subscriptions"
assert subscription.is_a?(Stripe::Subscription)
end
end
Expand All @@ -55,6 +56,7 @@ class CustomerTest < Test::Unit::TestCase
should "create a new invoice" do
customer = Stripe::Customer.retrieve("cus_123")
invoice = customer.create_upcoming_invoice
assert_requested :post, "#{Stripe.api_base}/v1/invoices"
assert invoice.is_a?(Stripe::Invoice)
end
end
Expand Down Expand Up @@ -88,11 +90,17 @@ class CustomerTest < Test::Unit::TestCase
context "#delete_discount" do
should "delete a discount" do
customer = Stripe::Customer.retrieve("cus_123")
customer = customer.delete_discount
assert_requested :delete, "#{Stripe.api_base}/v1/customers/#{customer.id}/discount"
assert customer.is_a?(Stripe::Customer)
end
end

stub_request(:delete, "#{Stripe.api_base}/v1/customers/#{customer.id}/discount")
.to_return(body: JSON.generate(object: "customer"))
discount = customer.delete_discount
assert discount.is_a?(Stripe::Customer)
context ".delete_discount" do
should "delete a discount" do
discount = Stripe::Customer.delete_discount("cus_123")
assert_requested :delete, "#{Stripe.api_base}/v1/customers/cus_123/discount"
assert discount.is_a?(Stripe::Discount)
end
end

Expand Down
9 changes: 9 additions & 0 deletions test/stripe/dispute_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ class DisputeTest < Test::Unit::TestCase
dispute.close
assert_requested :post,
"#{Stripe.api_base}/v1/disputes/#{dispute.id}/close"
assert dispute.is_a?(Stripe::Dispute)
end
end

context ".close" do
should "close a dispute" do
dispute = Stripe::Dispute.close("dp_123")
assert_requested :post, "#{Stripe.api_base}/v1/disputes/dp_123/close"
assert dispute.is_a?(Stripe::Dispute)
end
end
end
Expand Down
Loading