tribune_recurly_api 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/recurly_api.rb +22 -0
- data/lib/recurly_api/client.rb +142 -0
- data/lib/recurly_api/client/accounts.rb +25 -0
- data/lib/recurly_api/client/other_requests.rb +17 -0
- data/lib/recurly_api/client/plans.rb +32 -0
- data/lib/recurly_api/client/subscriptions.rb +98 -0
- data/lib/recurly_api/version.rb +6 -0
- data/lib/tribune_recurly_api.rb +3 -0
- metadata +93 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0b9eafd5553b067ea352e854a202c773f0565c728b0fd89c1b8775702f36ee29
|
4
|
+
data.tar.gz: 73269fbd07f54d384a52a04bdc3602c1162386cf942763e2becd16b336a728a9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0765af740d352b35433b5fe4b0ab2b4b0c19428b776c4f69c42dac223f7290d839dc1c4a0345f4cbb53d057d306250ed94708f6743df027d6f16fc227b95015f
|
7
|
+
data.tar.gz: cb56612cea6cd6584ecbaae4c31d31d3935167dc7b31c71abd1be887b6fde12b2cbc26b664ad4ecb7ba923b575c2a09bf00915ef1ba28eaf012b270e7bb0baf2
|
data/lib/recurly_api.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'recurly_api/version'
|
4
|
+
require 'recurly_api/client'
|
5
|
+
# some info goes here..
|
6
|
+
module RecurlyApi
|
7
|
+
class Error < StandardError; end
|
8
|
+
|
9
|
+
# RecurlyApi.logger.debug("I'm a debug log")
|
10
|
+
# logger.info("I'm an info log")
|
11
|
+
# logger.warn("I'm a warn log")
|
12
|
+
# logger.error("I'm an error log: error message")
|
13
|
+
# logger.fatal("I'm a fatal log")
|
14
|
+
def self.logger
|
15
|
+
# @@logger ||= defined?(Rails) ? Rails.logger : Logger.new(STDOUT)
|
16
|
+
@@logger ||= Logger.new(STDOUT)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.logger=(logger)
|
20
|
+
@@logger = logger
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
require 'rest-client'
|
4
|
+
require 'json'
|
5
|
+
module RecurlyApi
|
6
|
+
# Wrapper class to connect Recurly API end-points
|
7
|
+
class Client
|
8
|
+
# Requesting API end-points
|
9
|
+
require_relative './client/accounts'
|
10
|
+
require_relative './client/plans'
|
11
|
+
require_relative './client/subscriptions'
|
12
|
+
require_relative './client/other_requests.rb'
|
13
|
+
|
14
|
+
API_DEFAULTS = { base_host: 'v3.recurly.com',
|
15
|
+
api_version: 'v2021-02-25' }.freeze
|
16
|
+
# request for The number of records to return per page
|
17
|
+
RECORDS_LIMIT = 20
|
18
|
+
RATE_LIMIT_MAX_RETRIES = 3
|
19
|
+
|
20
|
+
attr_accessor :site_id, :authorization_key, :base_host,
|
21
|
+
:api_version, :api_endpoint, :ratelimit_retries
|
22
|
+
|
23
|
+
# Initialize a client.
|
24
|
+
# KeyWord args are optional while initializing and defaults to the values present in recurly_config.yml,
|
25
|
+
# Ex: If you want to use custom 'api_version' instead predefined, initialize client as below,
|
26
|
+
# rc = RecurlyApi::Client.new(api_version: 'v2019-10-10')
|
27
|
+
# @param authorization_key [String] Required, Recurly API auth key.
|
28
|
+
# @param site_id [String] Required, ex: 'subdomain-tribune' for https://tribune.recurly.com
|
29
|
+
# @param base_host [String] Optional, default: v3.recurly.com
|
30
|
+
# @param api_version [String] Optional, Recurly api_version ex: 'v2021-02-25' | 'v2019-10-10'
|
31
|
+
# @param ratelimit_retries [Integer] Optional, retry limit for rate limit exceeds, default: 3
|
32
|
+
def initialize(authorization_key: nil,
|
33
|
+
site_id: nil,
|
34
|
+
base_host: nil,
|
35
|
+
api_version: nil,
|
36
|
+
ratelimit_retries: RATE_LIMIT_MAX_RETRIES)
|
37
|
+
@authorization_key = authorization_key
|
38
|
+
@site_id = site_id
|
39
|
+
raise ArgumentError, "'authorization_key' must be set to a non-nil value" if @authorization_key.nil?
|
40
|
+
raise ArgumentError, "'site_id' must be set to a non-nil value" if @site_id.nil?
|
41
|
+
|
42
|
+
@base_host = base_host || API_DEFAULTS[:base_host]
|
43
|
+
@api_version = api_version || API_DEFAULTS[:api_version]
|
44
|
+
@api_endpoint = "https://#{@base_host}/sites/#{@site_id}"
|
45
|
+
@ratelimit_retries = ratelimit_retries
|
46
|
+
end
|
47
|
+
|
48
|
+
# request Recurly V3 API (v2021-02-25)(https://developers.recurly.com/api/v2021-02-25/)
|
49
|
+
# @param path [String] path for API call -> ex: 'plans/{plan_id}', 'accounts/{account_id}'.
|
50
|
+
# @param http_method [Symbol] request method -> ex: get | post | put | delete.
|
51
|
+
# @param params [Hash] query parameters -> ex: { limit: 20, order: :asc etc }
|
52
|
+
# @param payload [Hash] request body parameters( for post, put etc..)
|
53
|
+
# @param add_headers [Hash] additional headers if any ex: User-Agent etc..
|
54
|
+
# RestClient retry { https://blog.appsignal.com/2018/05/16/ensure-retry-and-reraise-exceptions-in-ruby.html }
|
55
|
+
def request_api(path:, http_method: :get, params: {}, payload: {}, add_headers: {})
|
56
|
+
raise ArgumentError, "'request path' must be set to a non-nil value" if path.nil?
|
57
|
+
|
58
|
+
max_retries = ratelimit_retries # max count to retry if rate limit requests are exceeded.
|
59
|
+
retry_count = 0
|
60
|
+
delay = 1 # in seconds
|
61
|
+
end_point = "#{api_endpoint}/#{path}"
|
62
|
+
headers = ensure_request_headers(add_headers).merge!(params: params)
|
63
|
+
resp = RestClient::Request.execute(method: http_method,
|
64
|
+
url: end_point,
|
65
|
+
payload: payload.empty? ? payload : payload.to_json,
|
66
|
+
headers: headers)
|
67
|
+
rescue RestClient::ExceptionWithResponse => e
|
68
|
+
e.response
|
69
|
+
rescue RestClient::Exception => e
|
70
|
+
# Timed out reading data from server
|
71
|
+
e.response
|
72
|
+
rescue StandardError => e
|
73
|
+
raise e.message
|
74
|
+
else
|
75
|
+
begin
|
76
|
+
raise 'API Rate limit exceeded' if rate_limit_exceeded?(resp)
|
77
|
+
rescue StandardError => _e
|
78
|
+
RecurlyApi.logger.error "API Rate limit exceeded retrying again. Retries left: #{max_retries - retry_count}"
|
79
|
+
sleep delay += retry_count
|
80
|
+
retry_count += 1
|
81
|
+
retry if retry_count < max_retries
|
82
|
+
end
|
83
|
+
resp
|
84
|
+
end
|
85
|
+
|
86
|
+
def ensure_request_headers(add_headers)
|
87
|
+
accept_header = "application/vnd.recurly.#{api_version}+json"
|
88
|
+
{ "Authorization": authorization_key,
|
89
|
+
"Content-Type": 'application/json',
|
90
|
+
accept: accept_header }.merge!(add_headers)
|
91
|
+
end
|
92
|
+
|
93
|
+
def handle_response!(resp, payload_name: :data, single_node: false)
|
94
|
+
if rate_limit_exceeded?(resp)
|
95
|
+
handle_rate_limit_exceed(resp)
|
96
|
+
else
|
97
|
+
json_body = JSON.parse(resp.body)
|
98
|
+
if json_body['error']
|
99
|
+
handle_error_response(resp.code, json_body)
|
100
|
+
else
|
101
|
+
{ success: true, status: resp.code,
|
102
|
+
"#{payload_name}": single_node ? json_body : json_body['data'] }
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def handle_error_response(code, json_body)
|
108
|
+
{ success: false, status: code,
|
109
|
+
error: json_body['error']['type'],
|
110
|
+
message: json_body['error']['message'] }
|
111
|
+
end
|
112
|
+
|
113
|
+
# Recurly rate limiting
|
114
|
+
# { https://developers.recurly.com/api/v2019-10-10/#section/Getting-Started/Limits }
|
115
|
+
# The rate limit is calculated over a sliding 5 minute window.
|
116
|
+
# This means a production site could make 4,000 requests within one minute and not hit the rate limit
|
117
|
+
# so long as the site made less than 1,000 requests during the prior 4 minute
|
118
|
+
# --------------
|
119
|
+
# Response Headers that returned related to rate limiting by Recurly.
|
120
|
+
# x_ratelimit_limit: The maximum number of requests available in the current time frame(5-minite window)
|
121
|
+
# x_ratelimit_remaining: the number of requests left for the 5-minute window
|
122
|
+
# x_ratelimit_reset: the remaining window before the rate limit resets, in UNIX Epoch seconds
|
123
|
+
|
124
|
+
# Check if rate limit exceeded or not using resp status code OR x_ratelimit_remaining header
|
125
|
+
def rate_limit_exceeded?(resp)
|
126
|
+
ratelimit_remaining = resp.headers[:x_ratelimit_remaining]
|
127
|
+
resp.code.eql?(429) || (ratelimit_remaining && ratelimit_remaining.to_i < 1)
|
128
|
+
end
|
129
|
+
|
130
|
+
def handle_rate_limit_exceed(resp)
|
131
|
+
resp_headers = resp.headers
|
132
|
+
rate_limit_info = { limit: resp_headers[:x_ratelimit_limit],
|
133
|
+
remaining: resp_headers[:x_ratelimit_remaining],
|
134
|
+
reset_time_seconds: resp_headers[:x_ratelimit_reset],
|
135
|
+
reset_time: DateTime.strptime(resp_headers[:x_ratelimit_reset], '%s') }
|
136
|
+
{ success: false, status: 429,
|
137
|
+
error: 'Recurly API Rate limit exceeded',
|
138
|
+
message: 'Too Many Requests, See rate-limiting for more info',
|
139
|
+
rate_limit_info: rate_limit_info }
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RecurlyApi
|
4
|
+
# API requests to fetch Accounts related data
|
5
|
+
class Client
|
6
|
+
# Fetch Account Info--
|
7
|
+
# { https://developers.recurly.com/api/v2021-02-25/index.html#operation/get_account }
|
8
|
+
# @param ssor_id [String] Required, Account ID(SsorID) or code.
|
9
|
+
# For ID no prefix is used e.g. +e28zov4fw0v2+. For code use prefix +code-+, e.g. +code-bob+.
|
10
|
+
def account_info(ssor_id:)
|
11
|
+
resp = request_api(path: "accounts/#{ssor_id}")
|
12
|
+
handle_response!(resp, payload_name: :account_info, single_node: true)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Deactivate account ---
|
16
|
+
# { https://developers.recurly.com/api/v2021-02-25/index.html#operation/deactivate_account }
|
17
|
+
# @param ssor_id [String] Required, Account ID(SsorID) or code.
|
18
|
+
# For ID no prefix is used e.g. +e28zov4fw0v2+. For code use prefix +code-+, e.g. +code-bob+.
|
19
|
+
def deactivate_account(ssor_id:)
|
20
|
+
path = "accounts/#{ssor_id}"
|
21
|
+
resp = request_api(path: path, http_method: :delete)
|
22
|
+
handle_response!(resp, payload_name: :account_info, single_node: true)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RecurlyApi
|
4
|
+
# This class fetches the data of Recurly API end-points
|
5
|
+
class Client
|
6
|
+
# Show the coupon redemptions for an account --
|
7
|
+
# { https://developers.recurly.com/api/v2021-02-25/index.html#tag/coupon_redemption }
|
8
|
+
# @param ssor_id [String] Recurly Account ID(SsorID) or code.
|
9
|
+
# For ID no prefix is used e.g. +e28zov4fw0v2+. For code use prefix +code-+, e.g. +code-bob+.
|
10
|
+
def coupon_redemptions(ssor_id:)
|
11
|
+
resp = request_api(path: "accounts/#{ssor_id}/coupon_redemptions")
|
12
|
+
handle_response!(resp, payload_name: :coupon_redemptions, single_node: true)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Other request any.....
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RecurlyApi
|
4
|
+
# API requests to fetch Plans related data
|
5
|
+
class Client
|
6
|
+
# List a site's plans
|
7
|
+
# { https://developers.recurly.com/api/v2021-02-25/index.html#operation/list_plans }
|
8
|
+
# @param params [Hash] Optional query string parameters:
|
9
|
+
# :ids [String] Filter results by their IDs. Up to 200 IDs can be passed at once using
|
10
|
+
# commas as separators, e.g. +ids=h1at4d57xlmy,gyqgg0d3v9n1,jrsm5b4yefg6+.
|
11
|
+
# :limit [Integer] Limit number of records 1-200.
|
12
|
+
# :order [String] Sort order.
|
13
|
+
# :sort [String] Sort field. You *really* only want to sort by +updated_at+ in ascending
|
14
|
+
# ex:
|
15
|
+
# params = { limit: 2, order: :asc, .....}
|
16
|
+
# ex: client.list_plans(params)
|
17
|
+
def list_plans(**params)
|
18
|
+
resp = request_api(path: 'plans', params: params)
|
19
|
+
# handle_response(resp, payload_name: :plans)
|
20
|
+
handle_response!(resp)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Fetch Plan Info--
|
24
|
+
# { https://developers.recurly.com/api/v2021-02-25/index.html#operation/get_plan}
|
25
|
+
# @param plan_id [String] Plan ID or code.
|
26
|
+
# For ID no prefix is used e.g. +e28zov4fw0v2+. For code use prefix +code-+, e.g. +code-gold+.
|
27
|
+
def plan_info(plan_id:)
|
28
|
+
resp = request_api(path: "plans/#{plan_id}")
|
29
|
+
handle_response!(resp, payload_name: :plan_info, single_node: true)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RecurlyApi
|
4
|
+
# API requests to fetch Subscriptions related data
|
5
|
+
class Client
|
6
|
+
# Fetch Account Subscriptions ---
|
7
|
+
# { https://developers.recurly.com/api/v2019-10-10/index.html#operation/list_account_subscriptions }
|
8
|
+
# @param ssor_id [String] Account ID(SsorID) or code.
|
9
|
+
# For ID no prefix is used e.g. +e28zov4fw0v2+. For code use prefix +code-+, e.g. +code-gold+.
|
10
|
+
# For SsorID no prefix is required
|
11
|
+
# @param params [Hash] Optional query string parameters
|
12
|
+
def account_subscriptions(ssor_id:, **params)
|
13
|
+
path = "accounts/#{ssor_id}/subscriptions"
|
14
|
+
resp = request_api(path: path, params: params)
|
15
|
+
handle_response!(resp)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Checking if user already has subscription OR
|
19
|
+
# Checking if user has a subscription for particular plan by its code
|
20
|
+
# ---------------
|
21
|
+
# @param ssor_id [String] required, Recurly Account Code(i.e SsorID)
|
22
|
+
# @prams plan_code [String] optional,
|
23
|
+
# - if present then checks if user has subscription for that particular plan by its code
|
24
|
+
# Usage ex:
|
25
|
+
# client.check_user_subscription(ssor_id: '4900-0272-6875', plan_code: '000150d03d')
|
26
|
+
# response => { :success=>true, :status=>200, :has_subscription=>true }
|
27
|
+
def check_user_subscription(ssor_id:, plan_code: nil)
|
28
|
+
resp = account_subscriptions(ssor_id: "code-#{ssor_id}")
|
29
|
+
if resp[:success]
|
30
|
+
has_subscription = false
|
31
|
+
subs = resp[:data]
|
32
|
+
has_subscription = true if subs.any?
|
33
|
+
if plan_code
|
34
|
+
sub = subs.detect { |s| s['plan']['code'].eql?(plan_code) }
|
35
|
+
has_subscription = sub ? true : false
|
36
|
+
end
|
37
|
+
{ success: true, status: 200, has_subscription: has_subscription }
|
38
|
+
else
|
39
|
+
resp
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# List a site's subscriptions
|
44
|
+
# { https://developers.recurly.com/api/v2021-02-25/#operation/list_account_subscriptions }
|
45
|
+
# @param params [Hash] Optional query string parameters:
|
46
|
+
# :ids [String] Filter results by their IDs. Up to 200 IDs can be passed at once using
|
47
|
+
# commas as separators, e.g. +ids=h1at4d57xlmy,gyqgg0d3v9n1,jrsm5b4yefg6+.
|
48
|
+
# :limit [Integer] Limit number of records 1-200.
|
49
|
+
# :order [String] Sort order.
|
50
|
+
# :sort [String] Sort field. You *really* only want to sort by +updated_at+ in ascending
|
51
|
+
# ex:
|
52
|
+
# params = { limit: RECORDS_LIMIT, order: :asc, .....}
|
53
|
+
# ex: client.site_subscriptions(params)
|
54
|
+
def site_subscriptions(**params)
|
55
|
+
resp = request_api(path: 'subscriptions', params: params)
|
56
|
+
handle_response!(resp)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Create subscription(new purchase) by ssor_id(Recurly Account code)
|
60
|
+
# { https://developers.recurly.com/api/v2021-02-25/index.html#operation/create_purchase }
|
61
|
+
# @param ssor_id [String] Required, user SSOR_ID (i.e. Reculry Account Code)
|
62
|
+
# @param plan_code [String] Required, plan_code or ID
|
63
|
+
# @param billing_token [String] Required, token genereted by recurlyjs while checkout
|
64
|
+
# @param gateway_code [String] Optional,
|
65
|
+
# Payment gateway identifier to be used for the purchase transaction
|
66
|
+
# ( required only if handling Braintree Multiple Merchant accounts )
|
67
|
+
# @param account_info [Hash] Optional query parameters(user provided info while checkout)
|
68
|
+
# :first_name [String], user First Name
|
69
|
+
# :last_name [String], user Last Name
|
70
|
+
# :email [String] user Email
|
71
|
+
# TODO: fetch user email, first_name, last_name by ssor_id connecting to SsorClient
|
72
|
+
# Better to pass first_name, last_name, email fetched from Checkout Page,
|
73
|
+
# instead of extra DB call to SSOR to get the user details
|
74
|
+
def create_subscription(ssor_id:, billing_token:, plan_code:,
|
75
|
+
gateway_code: nil, account_info: {})
|
76
|
+
account = { code: ssor_id,
|
77
|
+
billing_info: { token_id: billing_token } }
|
78
|
+
purchase_payload = { currency: 'USD',
|
79
|
+
account: account.merge!(account_info),
|
80
|
+
subscriptions: [{ plan_code: plan_code }] }
|
81
|
+
purchase_payload[:gateway_code] = gateway_code if gateway_code
|
82
|
+
path = 'purchases'
|
83
|
+
resp = request_api(path: path, http_method: :post,
|
84
|
+
payload: purchase_payload)
|
85
|
+
handle_response!(resp, payload_name: :purchase_info, single_node: true)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Cancel a subscription by its id or UUID
|
89
|
+
# @param sub_id_or_uuid [String] Required
|
90
|
+
# Subscription ID or UUID. For ID no prefix is used e.g. e28zov4fw0v2.
|
91
|
+
# For UUID use prefix uuid-, e.g. uuid-123457890
|
92
|
+
def cancel_subscription(sub_id_or_uuid)
|
93
|
+
path = "subscriptions/#{sub_id_or_uuid}/cancel"
|
94
|
+
resp = request_api(path: path, http_method: :put)
|
95
|
+
handle_response!(resp, payload_name: :subscription_info, single_node: true)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tribune_recurly_api
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- udevulapally
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-06-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '10.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '10.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rest-client
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.8.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.8.0
|
55
|
+
description: Wrapper for connecting to Recurly V3 API.
|
56
|
+
email:
|
57
|
+
- udevulapally@tribpub.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- lib/recurly_api.rb
|
63
|
+
- lib/recurly_api/client.rb
|
64
|
+
- lib/recurly_api/client/accounts.rb
|
65
|
+
- lib/recurly_api/client/other_requests.rb
|
66
|
+
- lib/recurly_api/client/plans.rb
|
67
|
+
- lib/recurly_api/client/subscriptions.rb
|
68
|
+
- lib/recurly_api/version.rb
|
69
|
+
- lib/tribune_recurly_api.rb
|
70
|
+
homepage:
|
71
|
+
licenses: []
|
72
|
+
metadata:
|
73
|
+
allowed_push_host: https://rubygems.org/
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options: []
|
76
|
+
require_paths:
|
77
|
+
- lib
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
requirements: []
|
89
|
+
rubygems_version: 3.1.4
|
90
|
+
signing_key:
|
91
|
+
specification_version: 4
|
92
|
+
summary: Tribune's Ruby Client for Recurly's API integration..
|
93
|
+
test_files: []
|