spackle-ruby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Bolder Research, LLC
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,79 @@
1
+ # Spackle Ruby Library
2
+
3
+ [![CI](https://github.com/spackleso/spackle-ruby/actions/workflows/test.yml/badge.svg)](https://github.com/spackleso/spackle-ruby/actions/workflows/test.yml)
4
+
5
+ The Spackle Ruby library provides optimized access to billing aware flags created on the Spackle platform.
6
+
7
+ ## Documentation
8
+
9
+ See the [Ruby API docs](https://docs.spackle.so/ruby).
10
+
11
+ ## Setup
12
+
13
+ ### Install the Spackle library
14
+
15
+ ```sh
16
+ gem install spackle-ruby
17
+ ```
18
+
19
+ ### Bundler
20
+
21
+ ```ruby
22
+ source 'https://rubygems.org'
23
+
24
+ gem 'spackle'
25
+ ```
26
+
27
+ ### Configure your environment
28
+ In order to use Spackle, you need to configure your API key on the `Spackle` module. You can find your API key in Spackle app [settings page](https://dashboard.stripe.com/settings/apps/so.spackle.stripe).
29
+
30
+ ```ruby
31
+ require 'spackle'
32
+
33
+ Spackle.api_key = "<api key>"
34
+ ```
35
+
36
+ ### Bootstrap the client (optional)
37
+
38
+ The Spackle client requires a single initialization step that includes a network request. To front load this process, you can call the `bootstrap` method in your codebase.
39
+
40
+ ```ruby
41
+ Spackle.bootstrap()
42
+ ```
43
+
44
+ ## Usage
45
+
46
+ ### Fetch a customer
47
+
48
+ Spackle uses stripe ids as references to customer features.
49
+
50
+ ```ruby
51
+ customer = Spackle::Customer.retrieve("cus_00000000")
52
+ ```
53
+
54
+ ### Verify feature access
55
+
56
+ ```ruby
57
+ customer.enabled("feature_key")
58
+ ```
59
+
60
+ ### Fetch a feature limit
61
+
62
+ ```ruby
63
+ customer.limit("feature_key")
64
+ ```
65
+
66
+ ## Logging
67
+ 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
+
69
+ 1. Set the environment variable SPACKLE_LOG to the value `debug`, `info`, or `error`
70
+
71
+ ```sh
72
+ $ export SPACKLE_LOG=debug
73
+ ```
74
+
75
+ 2. Set Spackle.log_level:
76
+
77
+ ```ruby
78
+ Spackle.log_level = 'debug'
79
+ ```
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "rake/testtask"
2
+
3
+ task default: %i[test]
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.pattern = "./test/**/*_test.rb"
7
+ end
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # frozen_string_literal: true
4
+
5
+ require "irb"
6
+ require "irb/completion"
7
+
8
+ require "#{::File.dirname(__FILE__)}/../lib/spackle"
9
+
10
+ # Config IRB to enable --simple-prompt and auto indent
11
+ IRB.conf[:PROMPT_MODE] = :SIMPLE
12
+ IRB.conf[:AUTO_INDENT] = true
13
+
14
+ puts "Loaded gem 'spackle'"
15
+
16
+ IRB.start
@@ -0,0 +1,38 @@
1
+ module Spackle
2
+ class Customer
3
+ @data = nil
4
+
5
+ def self.retrieve(id)
6
+ Util.log_debug("Retrieving customer data for #{id}")
7
+ data = Spackle.client.get_item({
8
+ 'CustomerId' => id
9
+ })
10
+ Util.log_debug("Retrieved customer data for #{id}: #{data}")
11
+ Customer.new(data)
12
+ end
13
+
14
+ def initialize(data)
15
+ @data = data
16
+ end
17
+
18
+ def enabled(key)
19
+ @data['features'].each do |f|
20
+ if f['key'] == key
21
+ return f['value_flag']
22
+ end
23
+ end
24
+
25
+ return false
26
+ end
27
+
28
+ def limit(key)
29
+ @data['features'].each do |f|
30
+ if f['key'] == key
31
+ return f['value_limit']
32
+ end
33
+ end
34
+
35
+ return 0
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,92 @@
1
+ require 'aws-sdk'
2
+ require 'net/http'
3
+ require 'json'
4
+
5
+ module Spackle
6
+ class DynamoDB
7
+ @client = nil
8
+ @identity_id = nil
9
+ @table_name = nil
10
+ @aws_region = nil
11
+
12
+ def initialize
13
+ @client = bootstrap_client
14
+ end
15
+
16
+ def get_item(key)
17
+ key = key.merge({
18
+ 'AccountId' => @identity_id,
19
+ })
20
+
21
+ response = @client.get_item({
22
+ table_name: @table_name,
23
+ key: key
24
+ })
25
+
26
+ JSON.parse(response.item['State'])
27
+ end
28
+
29
+ private
30
+
31
+
32
+ def bootstrap_client
33
+ Util.log_debug('Bootstrapping DynamoDB client...')
34
+ uri = URI(Spackle.api_base + '/auth/session')
35
+ https = Net::HTTP.new(uri.host, uri.port)
36
+ https.use_ssl = true
37
+
38
+ request = Net::HTTP::Post.new(uri.path)
39
+ request['Authorization'] = 'Bearer ' + Spackle.api_key
40
+
41
+ response = https.request(request)
42
+ data = JSON.parse(response.body)
43
+ Util.log_debug("Created session: #{data}")
44
+
45
+ @identity_id = data['identity_id']
46
+ @table_name = data['table_name']
47
+ @aws_region = data['aws_region']
48
+
49
+ credentials = SpackleCredentials.new(
50
+ data['role_arn'],
51
+ data['token']
52
+ )
53
+
54
+ Aws::DynamoDB::Client.new(
55
+ region: @aws_region,
56
+ credentials: credentials,
57
+ )
58
+ end
59
+ end
60
+
61
+ class SpackleCredentials
62
+ include Aws::CredentialProvider
63
+ include Aws::RefreshingCredentials
64
+
65
+ @role_arn = nil
66
+ @token = nil
67
+
68
+ def initialize(role_arn, token)
69
+ @client = Aws::STS::Client.new(:credentials => false)
70
+ @role_arn = role_arn
71
+ @token = token
72
+ super()
73
+ end
74
+
75
+ private
76
+
77
+ def refresh
78
+ Util.log_debug('Refreshing DynamoDB credentials...')
79
+ c = @client.assume_role_with_web_identity({
80
+ role_arn: @role_arn,
81
+ role_session_name: Base64.strict_encode64(SecureRandom.uuid),
82
+ web_identity_token: @token
83
+ }).credentials
84
+ @credentials = Aws::Credentials.new(
85
+ c.access_key_id,
86
+ c.secret_access_key,
87
+ c.session_token
88
+ )
89
+ @expiration = c.expiration
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,21 @@
1
+ require 'logger'
2
+
3
+ module Spackle
4
+ class SpackleConfiguration
5
+ attr_accessor :api_key
6
+ attr_accessor :api_base
7
+ attr_accessor :log_level
8
+ attr_reader :logger
9
+
10
+ def initialize
11
+ @api_base = 'https://api.spackle.so'
12
+ @log_level = Logger::INFO
13
+ @logger = Logger.new(STDOUT, level: @log_level)
14
+ end
15
+
16
+ def log_level=(level)
17
+ @log_level = level
18
+ @logger.level = level
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ module Spackle
2
+ module Util
3
+ def self.log_error(message)
4
+ Spackle.logger.error(message)
5
+ end
6
+
7
+ def self.log_info(message)
8
+ Spackle.logger.info(message)
9
+ end
10
+
11
+ def self.log_debug(message)
12
+ Spackle.logger.debug(message)
13
+ end
14
+ end
15
+ end
data/lib/spackle.rb ADDED
@@ -0,0 +1,40 @@
1
+ require 'logger'
2
+ require 'forwardable'
3
+
4
+ require 'spackle/customer'
5
+ require 'spackle/dynamodb'
6
+ require 'spackle/spackle_configuration'
7
+ require 'spackle/util'
8
+
9
+ module Spackle
10
+ @config = Spackle::SpackleConfiguration.new
11
+ @client = nil
12
+
13
+ LEVEL_DEBUG = Logger::DEBUG
14
+ LEVEL_ERROR = Logger::ERROR
15
+ LEVEL_INFO = Logger::INFO
16
+
17
+ class << self
18
+ extend Forwardable
19
+
20
+ attr_reader :config
21
+
22
+ def_delegators :@config, :api_key, :api_key=
23
+ def_delegators :@config, :api_base, :api_base=
24
+ def_delegators :@config, :log_level, :log_level=
25
+ def_delegators :@config, :logger, :logger=
26
+ end
27
+
28
+ def self.client
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
37
+ end
38
+ end
39
+
40
+ Spackle.log_level = ENV["SPACKLE_LOG"] unless ENV["SPACKLE_LOG"].nil?
data/spackle.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ $LOAD_PATH.unshift(::File.join(::File.dirname(__FILE__), "lib"))
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "spackle-ruby"
5
+ s.version = "0.0.1"
6
+ s.summary = "Spackle Ruby gem"
7
+ s.description = "Spackle is the easiest way to integrate your Ruby app with Stripe Billing." \
8
+ "See https://www.spackle.so for details."
9
+ s.authors = ["Spackle"]
10
+ s.email = "support@spackle.so"
11
+ s.homepage = "https://docs.spackle.so/ruby"
12
+ s.license = "MIT"
13
+ s.metadata = {
14
+ "bug_tracker_uri" => "https://github.com/spackleso/spackle-ruby/issues",
15
+ "documentation_uri" => "https://docs.spackle.so/ruby",
16
+ "github_repo" => "ssh://github.com/spackleso/spackle-ruby",
17
+ "homepage_uri" => "https://docs.spackle.so/ruby",
18
+ "source_code_uri" => "https://github.com/spackleso/spackle-ruby",
19
+ }
20
+
21
+ ignored = Regexp.union(
22
+ /\A\.editorconfig/,
23
+ /\A\.git/,
24
+ /\A\.rubocop/,
25
+ /\A\.travis.yml/,
26
+ /\A\.vscode/,
27
+ /\Atest/
28
+ )
29
+ s.files = `git ls-files`.split("\n").reject { |f| ignored.match(f) }
30
+ s.executables = `git ls-files -- bin/*`.split("\n")
31
+ .map { |f| ::File.basename(f) }
32
+ s.require_paths = ["lib"]
33
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spackle-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Spackle
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-01-08 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Spackle is the easiest way to integrate your Ruby app with Stripe Billing.See
14
+ https://www.spackle.so for details.
15
+ email: support@spackle.so
16
+ executables:
17
+ - spackle-console
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - Gemfile
22
+ - Gemfile.lock
23
+ - LICENSE
24
+ - README.md
25
+ - Rakefile
26
+ - bin/spackle-console
27
+ - lib/spackle.rb
28
+ - lib/spackle/customer.rb
29
+ - lib/spackle/dynamodb.rb
30
+ - lib/spackle/spackle_configuration.rb
31
+ - lib/spackle/util.rb
32
+ - spackle.gemspec
33
+ homepage: https://docs.spackle.so/ruby
34
+ licenses:
35
+ - MIT
36
+ metadata:
37
+ bug_tracker_uri: https://github.com/spackleso/spackle-ruby/issues
38
+ documentation_uri: https://docs.spackle.so/ruby
39
+ github_repo: ssh://github.com/spackleso/spackle-ruby
40
+ homepage_uri: https://docs.spackle.so/ruby
41
+ source_code_uri: https://github.com/spackleso/spackle-ruby
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubygems_version: 3.0.3.1
58
+ signing_key:
59
+ specification_version: 4
60
+ summary: Spackle Ruby gem
61
+ test_files: []