spackle-ruby 0.0.1 → 0.0.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 +4 -4
- data/Gemfile +4 -3
- data/Gemfile.lock +4 -4
- data/README.md +93 -2
- data/Rakefile +11 -4
- data/lib/spackle/customer.rb +36 -10
- data/lib/spackle/spackle_configuration.rb +20 -3
- data/lib/spackle/stores/base.rb +11 -0
- data/lib/spackle/{dynamodb.rb → stores/dynamodb.rb} +39 -17
- data/lib/spackle/stores/file.rb +28 -0
- data/lib/spackle/stores/memory.rb +21 -0
- data/lib/spackle/util.rb +10 -4
- data/lib/spackle/waiters.rb +37 -0
- data/lib/spackle.rb +11 -11
- data/spackle.gemspec +2 -2
- metadata +9 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e8cf2b94103517a295249a12015de47bba73211680e6414e171df2bc9ab18ceb
|
4
|
+
data.tar.gz: 694bb847e82273d30bb5f7e325bdb795e56a5d4555bcefe01783dc597d22c3d6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e8e7b93be2dc27f5b823741bed3c29b05113811fb37ae6769e89cf323eb5f6b34c2f6aa1d402e15b064dae86e6864ac155cf6f3fb565fa3c873107020119384c
|
7
|
+
data.tar.gz: 0e4f7073e81f0bba5a572f9ff5e1ad9670cbf0f5e5ec9afc93d3de20c2c2d0cfe476208a232403aaa61046abed6f1e826c3b98fdd9e373bff61d0410067fcbb7
|
data/Gemfile
CHANGED
@@ -4,8 +4,9 @@ source "https://rubygems.org"
|
|
4
4
|
|
5
5
|
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
6
6
|
|
7
|
-
gem
|
7
|
+
gem "aws-sdk", "~> 3"
|
8
8
|
gem "rake", "~> 13.0"
|
9
|
-
gem "test-unit", "~> 3.5"
|
10
|
-
|
11
9
|
gem "nokogiri", "~> 1.13"
|
10
|
+
gem "minitest", "~> 5.18"
|
11
|
+
|
12
|
+
gem "stripe", "~> 8.3"
|
data/Gemfile.lock
CHANGED
@@ -1356,23 +1356,23 @@ GEM
|
|
1356
1356
|
aws-eventstream (~> 1, >= 1.0.2)
|
1357
1357
|
jmespath (1.6.2)
|
1358
1358
|
mini_portile2 (2.8.1)
|
1359
|
+
minitest (5.18.0)
|
1359
1360
|
nokogiri (1.13.10)
|
1360
1361
|
mini_portile2 (~> 2.8.0)
|
1361
1362
|
racc (~> 1.4)
|
1362
|
-
power_assert (2.0.3)
|
1363
1363
|
racc (1.6.2)
|
1364
1364
|
rake (13.0.6)
|
1365
|
-
|
1366
|
-
power_assert
|
1365
|
+
stripe (8.3.0)
|
1367
1366
|
|
1368
1367
|
PLATFORMS
|
1369
1368
|
ruby
|
1370
1369
|
|
1371
1370
|
DEPENDENCIES
|
1372
1371
|
aws-sdk (~> 3)
|
1372
|
+
minitest (~> 5.18)
|
1373
1373
|
nokogiri (~> 1.13)
|
1374
1374
|
rake (~> 13.0)
|
1375
|
-
|
1375
|
+
stripe (~> 8.3)
|
1376
1376
|
|
1377
1377
|
BUNDLED WITH
|
1378
1378
|
1.17.2
|
data/README.md
CHANGED
@@ -21,7 +21,7 @@ gem install spackle-ruby
|
|
21
21
|
```ruby
|
22
22
|
source 'https://rubygems.org'
|
23
23
|
|
24
|
-
gem 'spackle'
|
24
|
+
gem 'spackle-ruby'
|
25
25
|
```
|
26
26
|
|
27
27
|
### Configure your environment
|
@@ -63,10 +63,37 @@ customer.enabled("feature_key")
|
|
63
63
|
customer.limit("feature_key")
|
64
64
|
```
|
65
65
|
|
66
|
+
### Examine a customer's subscriptions
|
67
|
+
|
68
|
+
A customer's current subscriptions are available on the `subscriptions` property. These are valid `Stripe::Subscription` objects as defined in the [Stripe Ruby library](https://stripe.com/docs/api/subscriptions/object?lang=ruby).
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
customer.subscriptions
|
72
|
+
```
|
73
|
+
|
74
|
+
## Waiters
|
75
|
+
|
76
|
+
There is a brief delay between when an action takes place in Stripe and when it is reflected in Spackle. To account for this, Spackle provides a `Waiters` module that can be used to wait for a Stripe object to be updated and replicated.
|
77
|
+
|
78
|
+
1. Wait for a customer to be created
|
79
|
+
```ruby
|
80
|
+
Spackle::Waiters.wait_for_customer("cus_00000000")
|
81
|
+
```
|
82
|
+
2. Wait for a subscription to be created
|
83
|
+
```ruby
|
84
|
+
Spackle::Waiters.wait_for_subscription("cus_000000000", "sub_00000000")
|
85
|
+
```
|
86
|
+
3. Wait for a subscription to be updated
|
87
|
+
```ruby
|
88
|
+
Spackle::Waiters.wait_for_subscription("cus_000000000", "sub_00000000", status: "active")
|
89
|
+
```
|
90
|
+
|
91
|
+
These will block until Spackle is updated with the latest information from Stripe or until a timeout occurs.
|
92
|
+
|
66
93
|
## Logging
|
67
94
|
The Spackle Ruby library emits logs as it performs various internal tasks. You can control the verbosity of Spackle's logging a few different ways:
|
68
95
|
|
69
|
-
1. Set the environment variable SPACKLE_LOG to the value `debug`, `info`, or `error`
|
96
|
+
1. Set the environment variable SPACKLE_LOG to the value `debug`, `info`, `warn` or `error`
|
70
97
|
|
71
98
|
```sh
|
72
99
|
$ export SPACKLE_LOG=debug
|
@@ -77,3 +104,67 @@ The Spackle Ruby library emits logs as it performs various internal tasks. You c
|
|
77
104
|
```ruby
|
78
105
|
Spackle.log_level = 'debug'
|
79
106
|
```
|
107
|
+
|
108
|
+
## Usage in development environments
|
109
|
+
In production, Spackle requires a valid Stripe customer. However, that is not development environments where state needs to be controlled. As an alternative, you can use a file store to test your application with seed data.
|
110
|
+
|
111
|
+
```json
|
112
|
+
/app/spackle.json
|
113
|
+
|
114
|
+
{
|
115
|
+
"cus_000000000": {
|
116
|
+
"features": [
|
117
|
+
{
|
118
|
+
"key": "flag_feature",
|
119
|
+
"value_flag": true
|
120
|
+
},
|
121
|
+
{
|
122
|
+
"key": "limit_feature",
|
123
|
+
"value_limit": 100
|
124
|
+
}
|
125
|
+
],
|
126
|
+
"subscriptions": [
|
127
|
+
{
|
128
|
+
"id": "sub_000000000",
|
129
|
+
"status": "trialing",
|
130
|
+
"quantity": 1
|
131
|
+
}
|
132
|
+
]
|
133
|
+
}
|
134
|
+
}
|
135
|
+
```
|
136
|
+
|
137
|
+
Then configure the file store in your application:
|
138
|
+
|
139
|
+
```ruby
|
140
|
+
Spackle.store = Spackle::FileStore.new('/app/spackle.json')
|
141
|
+
```
|
142
|
+
|
143
|
+
## Usage in test environments
|
144
|
+
|
145
|
+
In production, Spackle requires a valid Stripe customer. However, that is not ideal in testing or some development environments. As an alternative, you can use an in-memory store to test your application with seed data.
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
Spackle.store = Spackle::MemoryStore.new()
|
149
|
+
Spackle.store.set_customer_data("cus_000000000", {
|
150
|
+
"features": [
|
151
|
+
{
|
152
|
+
"key": "flag_feature",
|
153
|
+
"value_flag": True,
|
154
|
+
},
|
155
|
+
{
|
156
|
+
"key": "limit_feature",
|
157
|
+
"value_limit": 100,
|
158
|
+
},
|
159
|
+
],
|
160
|
+
"subscriptions": [
|
161
|
+
{
|
162
|
+
"id": "sub_000000000",
|
163
|
+
"status": "trialing",
|
164
|
+
"quantity": 1,
|
165
|
+
}
|
166
|
+
]
|
167
|
+
})
|
168
|
+
```
|
169
|
+
|
170
|
+
**Note:** The in-memory store is not thread-safe and state will reset on each application restart.
|
data/Rakefile
CHANGED
@@ -1,7 +1,14 @@
|
|
1
|
-
require "
|
1
|
+
require "minitest/test_task"
|
2
2
|
|
3
|
-
|
3
|
+
Minitest::TestTask.create # named test, sensible defaults
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
# or more explicitly:
|
6
|
+
|
7
|
+
Minitest::TestTask.create(:test) do |t|
|
8
|
+
t.libs << "test"
|
9
|
+
t.libs << "lib"
|
10
|
+
t.warning = false
|
11
|
+
t.test_globs = ["test/**/*_test.rb"]
|
7
12
|
end
|
13
|
+
|
14
|
+
task :default => :test
|
data/lib/spackle/customer.rb
CHANGED
@@ -1,38 +1,64 @@
|
|
1
|
+
require 'stripe'
|
2
|
+
|
1
3
|
module Spackle
|
2
4
|
class Customer
|
3
|
-
|
5
|
+
attr_accessor :id
|
6
|
+
attr_accessor :data
|
4
7
|
|
5
8
|
def self.retrieve(id)
|
6
9
|
Util.log_debug("Retrieving customer data for #{id}")
|
7
|
-
data = Spackle.
|
8
|
-
'CustomerId' => id
|
9
|
-
})
|
10
|
+
data = Spackle.store.get_customer_data(id)
|
10
11
|
Util.log_debug("Retrieved customer data for #{id}: #{data}")
|
11
|
-
Customer.new(data)
|
12
|
+
Customer.new(id, data)
|
12
13
|
end
|
13
14
|
|
14
|
-
def initialize(data)
|
15
|
+
def initialize(id, data)
|
16
|
+
@id = id
|
15
17
|
@data = data
|
16
18
|
end
|
17
19
|
|
20
|
+
def features
|
21
|
+
return @data['features']
|
22
|
+
end
|
23
|
+
|
24
|
+
def subscriptions
|
25
|
+
subscriptions = []
|
26
|
+
|
27
|
+
@data['subscriptions'].each do |s|
|
28
|
+
subscription = Stripe::Subscription.new(s['id'])
|
29
|
+
subscription.update_attributes(s)
|
30
|
+
subscriptions.push(subscription)
|
31
|
+
end
|
32
|
+
|
33
|
+
subscriptions
|
34
|
+
end
|
35
|
+
|
36
|
+
def flag_features
|
37
|
+
features.select { |f| f['type'] == 0 }
|
38
|
+
end
|
39
|
+
|
40
|
+
def limit_features
|
41
|
+
features.select { |f| f['type'] == 1 }
|
42
|
+
end
|
43
|
+
|
18
44
|
def enabled(key)
|
19
|
-
|
45
|
+
flag_features.each do |f|
|
20
46
|
if f['key'] == key
|
21
47
|
return f['value_flag']
|
22
48
|
end
|
23
49
|
end
|
24
50
|
|
25
|
-
|
51
|
+
raise SpackleError.new "Flag feature #{key} not found"
|
26
52
|
end
|
27
53
|
|
28
54
|
def limit(key)
|
29
55
|
@data['features'].each do |f|
|
30
56
|
if f['key'] == key
|
31
|
-
return f['value_limit']
|
57
|
+
return f['value_limit'] || Float::INFINITY
|
32
58
|
end
|
33
59
|
end
|
34
60
|
|
35
|
-
|
61
|
+
raise SpackleError.new "Limit feature #{key} not found"
|
36
62
|
end
|
37
63
|
end
|
38
64
|
end
|
@@ -4,18 +4,35 @@ module Spackle
|
|
4
4
|
class SpackleConfiguration
|
5
5
|
attr_accessor :api_key
|
6
6
|
attr_accessor :api_base
|
7
|
-
attr_accessor :log_level
|
8
7
|
attr_reader :logger
|
8
|
+
attr_reader :version
|
9
9
|
|
10
10
|
def initialize
|
11
|
-
@api_base = 'https://api.spackle.so'
|
12
|
-
@log_level = Logger::
|
11
|
+
@api_base = 'https://api.spackle.so/v1'
|
12
|
+
@log_level = Logger::WARN
|
13
13
|
@logger = Logger.new(STDOUT, level: @log_level)
|
14
|
+
@version = 1
|
15
|
+
@store = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def log_level()
|
19
|
+
@log_level
|
14
20
|
end
|
15
21
|
|
16
22
|
def log_level=(level)
|
17
23
|
@log_level = level
|
18
24
|
@logger.level = level
|
19
25
|
end
|
26
|
+
|
27
|
+
def store()
|
28
|
+
if @store == nil
|
29
|
+
@store = DynamoDBStore.new
|
30
|
+
end
|
31
|
+
@store
|
32
|
+
end
|
33
|
+
|
34
|
+
def store=(store)
|
35
|
+
@store = store
|
36
|
+
end
|
20
37
|
end
|
21
38
|
end
|
@@ -1,21 +1,41 @@
|
|
1
1
|
require 'aws-sdk'
|
2
2
|
require 'net/http'
|
3
3
|
require 'json'
|
4
|
+
require 'logger'
|
4
5
|
|
5
6
|
module Spackle
|
6
|
-
class
|
7
|
+
class DynamoDBStore < BaseStore
|
7
8
|
@client = nil
|
8
|
-
@
|
9
|
-
@table_name = nil
|
10
|
-
@aws_region = nil
|
9
|
+
@store_config = {}
|
11
10
|
|
12
|
-
def initialize
|
13
|
-
@
|
11
|
+
def initialize(client = nil, store_config = nil)
|
12
|
+
@store_config = store_config || {}
|
13
|
+
@client = client || bootstrap_client
|
14
14
|
end
|
15
15
|
|
16
|
+
def get_customer_data(id)
|
17
|
+
data = query({
|
18
|
+
key_condition_expression: 'CustomerId = :customer_id',
|
19
|
+
filter_expression: 'Version = :version',
|
20
|
+
expression_attribute_values: {
|
21
|
+
':customer_id' => id,
|
22
|
+
':version' => Spackle.version
|
23
|
+
},
|
24
|
+
limit: 1
|
25
|
+
})
|
26
|
+
|
27
|
+
if not data.items.any?
|
28
|
+
raise SpackleError.new "Customer #{id} not found"
|
29
|
+
end
|
30
|
+
|
31
|
+
JSON.parse(data.items[0]['State'])
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
16
36
|
def get_item(key)
|
17
37
|
key = key.merge({
|
18
|
-
'AccountId' => @identity_id,
|
38
|
+
'AccountId' => @store_config['identity_id'],
|
19
39
|
})
|
20
40
|
|
21
41
|
response = @client.get_item({
|
@@ -26,12 +46,18 @@ module Spackle
|
|
26
46
|
JSON.parse(response.item['State'])
|
27
47
|
end
|
28
48
|
|
29
|
-
|
30
|
-
|
49
|
+
def query(query)
|
50
|
+
query[:table_name] = @store_config['table_name']
|
51
|
+
query[:key_condition_expression] = 'AccountId = :account_id AND ' + query[:key_condition_expression]
|
52
|
+
query[:expression_attribute_values] = query[:expression_attribute_values].merge({
|
53
|
+
':account_id' => @store_config['identity_id']
|
54
|
+
})
|
55
|
+
@client.query(query)
|
56
|
+
end
|
31
57
|
|
32
58
|
def bootstrap_client
|
33
59
|
Util.log_debug('Bootstrapping DynamoDB client...')
|
34
|
-
uri = URI(Spackle.api_base + '/
|
60
|
+
uri = URI(Spackle.api_base + '/sessions')
|
35
61
|
https = Net::HTTP.new(uri.host, uri.port)
|
36
62
|
https.use_ssl = true
|
37
63
|
|
@@ -42,17 +68,13 @@ module Spackle
|
|
42
68
|
data = JSON.parse(response.body)
|
43
69
|
Util.log_debug("Created session: #{data}")
|
44
70
|
|
45
|
-
@
|
46
|
-
@table_name = data['table_name']
|
47
|
-
@aws_region = data['aws_region']
|
48
|
-
|
71
|
+
@store_config = data['adapter']
|
49
72
|
credentials = SpackleCredentials.new(
|
50
|
-
|
51
|
-
|
73
|
+
@store_config['role_arn'],
|
74
|
+
@store_config['token']
|
52
75
|
)
|
53
76
|
|
54
77
|
Aws::DynamoDB::Client.new(
|
55
|
-
region: @aws_region,
|
56
78
|
credentials: credentials,
|
57
79
|
)
|
58
80
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Spackle
|
2
|
+
class FileStore < BaseStore
|
3
|
+
def initialize(path)
|
4
|
+
@path = path
|
5
|
+
end
|
6
|
+
|
7
|
+
def get_customer_data(id)
|
8
|
+
content = File.read(@path)
|
9
|
+
data = JSON.parse(content)
|
10
|
+
data[id]
|
11
|
+
end
|
12
|
+
|
13
|
+
def set_customer_data(id, customer_data)
|
14
|
+
data = {}
|
15
|
+
if File.exist?(@path)
|
16
|
+
content = File.read(@path)
|
17
|
+
data = JSON.parse(content)
|
18
|
+
end
|
19
|
+
|
20
|
+
if !data.has_key?(id)
|
21
|
+
raise SpackleError.new "Customer #{id} not found"
|
22
|
+
end
|
23
|
+
|
24
|
+
data[id] = customer_data
|
25
|
+
File.write(@path, JSON.pretty_generate(data))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Spackle
|
2
|
+
class MemoryStore < BaseStore
|
3
|
+
@data = {}
|
4
|
+
|
5
|
+
def initialize()
|
6
|
+
@data = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def get_customer_data(id)
|
10
|
+
if !@data.has_key?(id)
|
11
|
+
raise SpackleError.new "Customer #{id} not found"
|
12
|
+
end
|
13
|
+
|
14
|
+
@data[id]
|
15
|
+
end
|
16
|
+
|
17
|
+
def set_customer_data(id, customer_data)
|
18
|
+
@data[id] = customer_data
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/spackle/util.rb
CHANGED
@@ -1,15 +1,21 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
1
3
|
module Spackle
|
2
4
|
module Util
|
3
|
-
def self.
|
4
|
-
Spackle.logger.
|
5
|
+
def self.log_debug(message)
|
6
|
+
Spackle.logger.debug(message)
|
5
7
|
end
|
6
8
|
|
7
9
|
def self.log_info(message)
|
8
10
|
Spackle.logger.info(message)
|
9
11
|
end
|
10
12
|
|
11
|
-
def self.
|
12
|
-
Spackle.logger.
|
13
|
+
def self.log_warn(message)
|
14
|
+
Spackle.logger.warn(message)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.log_error(message)
|
18
|
+
Spackle.logger.error(message)
|
13
19
|
end
|
14
20
|
end
|
15
21
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Spackle
|
4
|
+
module Waiters
|
5
|
+
def self.wait_for_customer(customer_id, timeout = 15)
|
6
|
+
start = Time.now.to_i
|
7
|
+
while Time.now.to_i - start < timeout do
|
8
|
+
begin
|
9
|
+
return Spackle::Customer.retrieve(customer_id)
|
10
|
+
rescue SpackleError
|
11
|
+
sleep 1
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
raise SpackleError.new "Timeout waiting for customer #{customer_id}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.wait_for_subscription(customer_id, subscription_id, timeout=15, **filters)
|
19
|
+
start = Time.now.to_i
|
20
|
+
while Time.now.to_i - start < timeout do
|
21
|
+
begin
|
22
|
+
customer = Spackle::Customer.retrieve(customer_id)
|
23
|
+
customer.subscriptions.each do |s|
|
24
|
+
if s.id == subscription_id and filters.all? { |k, v| s.send(k) == v }
|
25
|
+
return s
|
26
|
+
end
|
27
|
+
end
|
28
|
+
sleep 1
|
29
|
+
rescue SpackleError
|
30
|
+
sleep 1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
raise SpackleError.new "Timeout waiting for subscription #{subscription_id}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/spackle.rb
CHANGED
@@ -2,17 +2,23 @@ require 'logger'
|
|
2
2
|
require 'forwardable'
|
3
3
|
|
4
4
|
require 'spackle/customer'
|
5
|
-
require 'spackle/dynamodb'
|
6
5
|
require 'spackle/spackle_configuration'
|
7
6
|
require 'spackle/util'
|
7
|
+
require 'spackle/waiters'
|
8
|
+
|
9
|
+
require 'spackle/stores/base'
|
10
|
+
require 'spackle/stores/dynamodb'
|
11
|
+
require 'spackle/stores/file'
|
12
|
+
require 'spackle/stores/memory'
|
8
13
|
|
9
14
|
module Spackle
|
10
15
|
@config = Spackle::SpackleConfiguration.new
|
11
16
|
@client = nil
|
12
17
|
|
13
18
|
LEVEL_DEBUG = Logger::DEBUG
|
14
|
-
LEVEL_ERROR = Logger::ERROR
|
15
19
|
LEVEL_INFO = Logger::INFO
|
20
|
+
LEVEL_WARN = Logger::WARN
|
21
|
+
LEVEL_ERROR = Logger::ERROR
|
16
22
|
|
17
23
|
class << self
|
18
24
|
extend Forwardable
|
@@ -22,18 +28,12 @@ module Spackle
|
|
22
28
|
def_delegators :@config, :api_key, :api_key=
|
23
29
|
def_delegators :@config, :api_base, :api_base=
|
24
30
|
def_delegators :@config, :log_level, :log_level=
|
31
|
+
def_delegators :@config, :store, :store=
|
25
32
|
def_delegators :@config, :logger, :logger=
|
33
|
+
def_delegators :@config, :version, :version=
|
26
34
|
end
|
27
35
|
|
28
|
-
|
29
|
-
unless Spackle.api_key.nil?
|
30
|
-
@client ||= Spackle::DynamoDB.new()
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.bootstrap
|
35
|
-
self.client
|
36
|
-
nil
|
36
|
+
class SpackleError < StandardError
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
data/spackle.gemspec
CHANGED
@@ -2,9 +2,9 @@ $LOAD_PATH.unshift(::File.join(::File.dirname(__FILE__), "lib"))
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "spackle-ruby"
|
5
|
-
s.version = "0.0.
|
5
|
+
s.version = "0.0.3"
|
6
6
|
s.summary = "Spackle Ruby gem"
|
7
|
-
s.description = "Spackle is the easiest way to integrate your Ruby app with Stripe Billing." \
|
7
|
+
s.description = "Spackle is the easiest way to integrate your Ruby app with Stripe Billing. " \
|
8
8
|
"See https://www.spackle.so for details."
|
9
9
|
s.authors = ["Spackle"]
|
10
10
|
s.email = "support@spackle.so"
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spackle-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Spackle
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-03-06 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description: Spackle is the easiest way to integrate your Ruby app with Stripe Billing.
|
14
|
-
https://www.spackle.so for details.
|
13
|
+
description: Spackle is the easiest way to integrate your Ruby app with Stripe Billing.
|
14
|
+
See https://www.spackle.so for details.
|
15
15
|
email: support@spackle.so
|
16
16
|
executables:
|
17
17
|
- spackle-console
|
@@ -26,9 +26,13 @@ files:
|
|
26
26
|
- bin/spackle-console
|
27
27
|
- lib/spackle.rb
|
28
28
|
- lib/spackle/customer.rb
|
29
|
-
- lib/spackle/dynamodb.rb
|
30
29
|
- lib/spackle/spackle_configuration.rb
|
30
|
+
- lib/spackle/stores/base.rb
|
31
|
+
- lib/spackle/stores/dynamodb.rb
|
32
|
+
- lib/spackle/stores/file.rb
|
33
|
+
- lib/spackle/stores/memory.rb
|
31
34
|
- lib/spackle/util.rb
|
35
|
+
- lib/spackle/waiters.rb
|
32
36
|
- spackle.gemspec
|
33
37
|
homepage: https://docs.spackle.so/ruby
|
34
38
|
licenses:
|