bunny_app 1.18.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 53806b76d7adaa8bdb227a84f6a192c9044c0d21cc04d845a827c9222be45e16
4
+ data.tar.gz: 8046c1b3f43417f98ee878f2288b744effdb79a8dae47cc2bfa368057914d4f2
5
+ SHA512:
6
+ metadata.gz: 16a8f959c2b08b6e75b7a0d2aa70bcb4fb00c942e7f3e5ceadd4c3216b70c0ff1035d23fb0a43194612ca2e650360d6d6bd9890cb0d7fbec7b73a7454253e1db
7
+ data.tar.gz: 1b937249175ea0678f71dc1326e6f47507982ffa5bc90905156886ec9c661b1a97bf9919237098b87fc144287dd673fb5f72916c6dbbd9e9e2f853ae9c2a626a
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0 (10-Mar-2022)
4
+
5
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in bunny_app.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Bunny
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,141 @@
1
+ # bunny-ruby
2
+
3
+ Ruby SDK for Bunny
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'bunnyapp'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```sh
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```sh
22
+ $ gem install bunnyapp
23
+ ```
24
+
25
+ ## Getting Started
26
+
27
+ You can use this gem to send customized graphql queries to Bunny or use the built in convience methods.
28
+
29
+ First configure the Bunny client.
30
+
31
+ ```ruby
32
+ require 'bunny_app'
33
+
34
+ # We recommend using the client_id/secret of your Bunny client app
35
+ # this will enable automatic retries when the access token expires
36
+ BunnyApp.config do |c|
37
+ c.client_id = 'xxx'
38
+ c.client_secret = 'xxx'
39
+ c.scope = 'standard:read standard:write'
40
+ c.base_uri = 'https://<subdomain>.bunny.com'
41
+ end
42
+
43
+ # Alternately you can generate the access token outside of this sdk
44
+ # be aware that if your access_token expires an exception will be raised
45
+ BunnyApp.config do |c|
46
+ c.access_token = 'xxx'
47
+ c.base_uri = 'https://<subdomain>.bunny.com'
48
+ end
49
+ ```
50
+
51
+ > Remember! Don't commit secrets to source control!
52
+
53
+ ### Generate rails config
54
+
55
+ Create a config file at `config/initializers/bunny_app.rb`
56
+
57
+ ```sh
58
+ > bin/rails g bunny_app:install
59
+ ```
60
+
61
+ ### Track feature usage
62
+
63
+ If you have usage based billing or just want to track feature usage then use this method.
64
+
65
+ ```ruby
66
+ # Usage is tracked as if it just happened
67
+ json_response = BunnyApp::Usage.track(
68
+ quantity: 5, feature_code: 'products', tenant_code: '2')
69
+
70
+ # Usage is tracked using the date supplied
71
+ json_response = BunnyApp::Usage.track(
72
+ quantity: 5, feature_code: 'products', tenant_code: '2', usage_at: '2022-03-10')
73
+ ```
74
+
75
+ ### Custom queries & mutations
76
+
77
+ Alternately you can build and send your own custom graphql queries or mutations
78
+
79
+ ```ruby
80
+ query = <<-'GRAPHQL'
81
+ mutation featureUsageCreate ($attributes: FeatureUsageAttributes!) {
82
+ featureUsageCreate (attributes: $attributes) {
83
+ errors
84
+ featureUsage {
85
+ id
86
+ quantity
87
+ usageAt
88
+ tenant {
89
+ id
90
+ code
91
+ name
92
+ }
93
+ feature {
94
+ id
95
+ code
96
+ name
97
+ }
98
+ }
99
+ }
100
+ }
101
+ GRAPHQL
102
+
103
+ variables = {
104
+ attributes: {
105
+ quantity: 1,
106
+ usageAt: "2022-03-10",
107
+ tenantCode: "123456",
108
+ featureCode: "users"
109
+ }
110
+ }
111
+
112
+ json_response = BunnyApp.query(query, variables)
113
+ ```
114
+
115
+ ### Verify webhook signature
116
+
117
+ Bunny can send webhooks for key actions like a subscription change. When you get a webhook from Bunny you should verify the signature that is supplied in the `x-bunny-signature` header matches the payload.
118
+
119
+ ```ruby
120
+ payload = '{"type":"SubscriptionProvisioningChange","payload":{"subscription":{"id":27,"state":"trial","trial_start_date":"2022-06-04","trial_end_date":"2022-06-18","start_date":null,"end_date":null,"auto_renew":false,"account":{"id":33,"name":"Ondricka, Flatley and Kessler"},"tenant":null,"product":{"code":"stealth","name":"Stealth","description":null,"sku":null},"features":[{"code":"users","quantity":1},{"code":"crm","quantity":null}]}}}'
121
+
122
+ BunnyApp::Webhook.verify("8bd5aa9c6a96fbce9fc3065af6e9871ac19a1d0a", payload, "secret-key")
123
+ ```
124
+
125
+ ## Requirements
126
+
127
+ This gem requires Ruby 2.5+
128
+
129
+ ## Development
130
+
131
+ Run `bin/setup` to install dependencies.
132
+
133
+ Run `rake spec` to run the tests.
134
+
135
+ You can also run `bin/console` for an interactive prompt that will allow you to experiment.
136
+
137
+ Set IGNORE_SSL when running locally to ignore ssl warnings.
138
+
139
+ ```sh
140
+ > IGNORE_SSL=true bin/console
141
+ ```
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ require 'rake'
2
+
3
+ begin
4
+ require 'bundler/setup'
5
+ Bundler::GemHelper.install_tasks
6
+ rescue LoadError
7
+ puts 'although not required, bundler is recommended for running the tests'
8
+ end
9
+
10
+ task default: :spec
11
+
12
+ require 'rspec/core/rake_task'
13
+ RSpec::Core::RakeTask.new(:spec)
14
+
15
+ require 'rubocop/rake_task'
16
+ RuboCop::RakeTask.new do |task|
17
+ task.requires << 'rubocop-performance'
18
+ task.requires << 'rubocop-rspec'
19
+ end
data/bunny_app.gemspec ADDED
@@ -0,0 +1,41 @@
1
+ lib = File.expand_path('lib', __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'bunny_app/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'bunny_app'
7
+ spec.version = BunnyApp::VERSION
8
+ spec.authors = ['Bunny', 'Rich Chetwynd']
9
+ spec.email = ['support@bunny.com']
10
+
11
+ spec.summary = 'Ruby SDK for Bunny App'
12
+ spec.description = 'Use Bunny for SaaS subscription management, quoting, billing and CRM'
13
+ spec.homepage = 'https://github.com/bunny/bunny-ruby'
14
+ spec.license = 'MIT'
15
+ spec.platform = Gem::Platform::RUBY
16
+ spec.required_ruby_version = '>= 3.1.0'
17
+
18
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
19
+ # delete this section to allow pushing this gem to any host.
20
+ raise 'RubyGems 3.0 or newer is required to protect against public gem pushes.' unless spec.respond_to?(:metadata)
21
+
22
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
23
+ spec.metadata['rubygems_mfa_required'] = 'true'
24
+
25
+ spec.files = Dir['README.md', 'LICENSE', 'CHANGELOG.md', 'generators/**/*.rb',
26
+ 'lib/**/*.rb', 'lib/**/*.rake',
27
+ 'bunny_app.gemspec', 'Gemfile', 'Rakefile']
28
+
29
+ spec.executables = []
30
+ spec.require_paths = ['lib']
31
+
32
+ spec.add_runtime_dependency 'httparty', '~> 0.20'
33
+ spec.add_runtime_dependency 'json', '~> 2.6'
34
+
35
+ spec.add_development_dependency 'fakeweb', '~> 1.3'
36
+ spec.add_development_dependency 'rake', '~> 13.0'
37
+ spec.add_development_dependency 'rspec', '~> 3.6'
38
+ spec.add_development_dependency 'rubocop', '~> 1.26'
39
+ spec.add_development_dependency 'rubocop-performance', '~> 1.13'
40
+ spec.add_development_dependency 'rubocop-rspec', '~> 2.9'
41
+ end
@@ -0,0 +1,89 @@
1
+ require 'httparty'
2
+ require 'json'
3
+
4
+ module BunnyApp
5
+ class Client
6
+ include HTTParty
7
+
8
+ attr_accessor :headers
9
+
10
+ USER_AGENT = "BunnyApp Ruby v#{BunnyApp::VERSION}".freeze
11
+
12
+ def initialize
13
+ self.class.base_uri BunnyApp.base_uri
14
+ self.class.default_options.update(verify: verify_ssl)
15
+
16
+ BunnyApp.access_token ||= fetch_access_token
17
+ @headers = {
18
+ 'User-Agent' => USER_AGENT,
19
+ 'Content-Type' => 'application/json',
20
+ 'Authorization' => "Bearer #{BunnyApp.access_token}"
21
+ }
22
+ end
23
+
24
+ def fetch_access_token
25
+ body = URI.encode_www_form({
26
+ grant_type: 'client_credentials',
27
+ client_id: BunnyApp.client_id,
28
+ client_secret: BunnyApp.client_secret,
29
+ scope: BunnyApp.scope
30
+ })
31
+
32
+ headers = {
33
+ 'Content-Type' => 'application/x-www-form-urlencoded'
34
+ }
35
+
36
+ res = self.class.post('/oauth/token', headers:, body:)
37
+
38
+ case res.code.to_s
39
+ when /2[0-9][0-9]/ # HTTP 2xx
40
+ BunnyApp.retryable = true
41
+ res['access_token']
42
+ when /40[0-9]/
43
+ raise AuthorizationError, res.parsed_response['error_description']
44
+ else
45
+ raise ResponseError, res.body
46
+ end
47
+ end
48
+
49
+ def query(query, variables, retries = 0)
50
+ body = {
51
+ query:,
52
+ variables:
53
+ }.to_json
54
+
55
+ @headers['Authorization'] = "Bearer #{BunnyApp.access_token}"
56
+
57
+ res = self.class.post('/graphql', headers: @headers, body:)
58
+
59
+ case res.code.to_s
60
+ when /2[0-9][0-9]/ # HTTP 2xx
61
+ res.body
62
+ when /401/ # Access Token Expired
63
+ raise AuthorizationError, 'Invalid access token' unless BunnyApp.retryable
64
+ raise AuthorizationError, 'Invalid api credentials' if retries >= 1
65
+
66
+ BunnyApp.access_token = fetch_access_token
67
+ retries += 1
68
+ query(query, variables, retries)
69
+
70
+ when /403/ # HTTP 403
71
+ raise AuthorizationError, res.parsed_response['error_decscription']
72
+ else
73
+ raise ResponseError, res.body # HTTP 400, 500 etc
74
+ end
75
+ end
76
+
77
+ # Performs the api request within a new Thread, so it is non blocking.
78
+ # Consider it fire and forget
79
+ def query_async(query, variables)
80
+ Thread.new do
81
+ query(query, variables)
82
+ end
83
+ end
84
+
85
+ def verify_ssl
86
+ return true unless ENV['IGNORE_SSL']
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,7 @@
1
+ module BunnyApp
2
+ class AuthorizationError < StandardError
3
+ end
4
+
5
+ class ResponseError < StandardError
6
+ end
7
+ end
@@ -0,0 +1,27 @@
1
+ module BunnyApp
2
+ class Platform
3
+ @platform_create_mutation = <<-'GRAPHQL'
4
+ mutation platformCreate ($attributes: PlatformAttributes!) {
5
+ platformCreate (attributes: $attributes) {
6
+ platform {
7
+ id
8
+ name
9
+ code
10
+ }
11
+ errors
12
+ }
13
+ }
14
+ GRAPHQL
15
+
16
+ def self.create(name:, code:)
17
+ variables = {
18
+ attributes: {
19
+ name: name,
20
+ code: code
21
+ }
22
+ }
23
+
24
+ Client.new.query(@platform_create_mutation, variables)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,43 @@
1
+ module BunnyApp
2
+ class Subscription
3
+ @subscription_create_mutation = <<-'GRAPHQL'
4
+ mutation subscriptionCreate ($attributes: SubscriptionAttributes!) {
5
+ subscriptionCreate (attributes: $attributes) {
6
+ errors
7
+ subscription {
8
+ id
9
+ trialStartDate
10
+ trialEndDate
11
+ startDate
12
+ endDate
13
+ state
14
+ productPlan {
15
+ name
16
+ }
17
+ tenant {
18
+ code
19
+ name
20
+ }
21
+ }
22
+ }
23
+ }
24
+ GRAPHQL
25
+
26
+ def self.create(account_name:, first_name:, last_name:, email:, product_plan_code:, options: {})
27
+ variables = {
28
+ attributes: {
29
+ accountName: account_name,
30
+ firstName: first_name,
31
+ lastName: last_name,
32
+ email:,
33
+ productPlanCode: product_plan_code,
34
+ trialStartDate: options[:trial_start_date],
35
+ tenantCode: options[:tenant_code]&.to_s,
36
+ trial: options[:trial]
37
+ }
38
+ }
39
+
40
+ Client.new.query(@subscription_create_mutation, variables)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,34 @@
1
+ module BunnyApp
2
+ class Tenant
3
+ @tenant_create_mutation = <<-'GRAPHQL'
4
+ mutation tenantCreate ($attributes: TenantAttributes!, $subscriptionId: ID!) {
5
+ tenantCreate (attributes: $attributes, subscriptionId: $subscriptionId) {
6
+ tenant {
7
+ code
8
+ id
9
+ name
10
+ platform {
11
+ id
12
+ name
13
+ code
14
+ }
15
+ }
16
+ errors
17
+ }
18
+ }
19
+ GRAPHQL
20
+
21
+ def self.create(name:, code:, platform_code: 'main', subscription_id: nil)
22
+ variables = {
23
+ attributes: {
24
+ name:,
25
+ code:,
26
+ platformCode: platform_code
27
+ },
28
+ subscriptionId: subscription_id
29
+ }
30
+
31
+ Client.new.query(@tenant_create_mutation, variables)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,40 @@
1
+ module BunnyApp
2
+ class Usage
3
+ @feature_usage_create_mutation = <<-'GRAPHQL'
4
+ mutation featureUsageCreate ($attributes: FeatureUsageAttributes!) {
5
+ featureUsageCreate (attributes: $attributes) {
6
+ errors
7
+ featureUsage {
8
+ id
9
+ quantity
10
+ usageAt
11
+ tenant {
12
+ id
13
+ code
14
+ name
15
+ }
16
+ feature {
17
+ id
18
+ code
19
+ name
20
+ }
21
+ }
22
+ }
23
+ }
24
+ GRAPHQL
25
+
26
+ def self.track(quantity:, feature_code:, tenant_code:, usage_at: nil)
27
+ variables = {
28
+ attributes: {
29
+ quantity:,
30
+ featureCode: feature_code,
31
+ tenantCode: tenant_code
32
+ }
33
+ }
34
+
35
+ variables[:attributes][:usageAt] = usage_at unless usage_at.nil?
36
+
37
+ Client.new.query(@feature_usage_create_mutation, variables)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BunnyApp
4
+ VERSION = '1.18.0'
5
+ end
@@ -0,0 +1,13 @@
1
+ require 'openssl'
2
+ require 'base64'
3
+
4
+ module BunnyApp
5
+ class Webhook
6
+ def self.verify(signature, payload, signing_key)
7
+ digest = OpenSSL::Digest.new('sha1')
8
+ hash = OpenSSL::HMAC.hexdigest(digest, signing_key, payload)
9
+
10
+ OpenSSL.secure_compare(hash, signature)
11
+ end
12
+ end
13
+ end
data/lib/bunny_app.rb ADDED
@@ -0,0 +1,31 @@
1
+ require 'bunny_app/version'
2
+ require 'bunny_app/errors'
3
+ require 'bunny_app/client'
4
+ require 'bunny_app/usage'
5
+ require 'bunny_app/platform'
6
+ require 'bunny_app/tenant'
7
+ require 'bunny_app/subscription'
8
+ require 'bunny_app/webhook'
9
+
10
+ module BunnyApp
11
+ class << self
12
+ attr_accessor :client_id, :client_secret, :scope, :access_token, :retryable
13
+ attr_writer :base_uri
14
+
15
+ def config
16
+ yield self
17
+ end
18
+
19
+ def base_uri
20
+ @base_uri || 'https://api.bunny.com'
21
+ end
22
+
23
+ def query(query, variables)
24
+ Client.new.query(query, variables)
25
+ end
26
+
27
+ def query_async(query, variables)
28
+ Client.new.query_async(query, variables)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ require 'rails/generators'
2
+ require 'bunny_app'
3
+
4
+ module BunnyApp
5
+ class InstallGenerator < Rails::Generators::Base
6
+ desc 'This generator creates a configuration file for the Bunny ruby client inside config/initializers'
7
+ def create_configuration_file
8
+ initializer 'bunny_app.rb' do
9
+ <<~CONFIG
10
+ # Specifies configuration options for the Bunny gem.
11
+ BunnyApp.config do |c|
12
+
13
+ # This is where your API credentials go. You should almost certainly not have it
14
+ # committed to source control, but instead load it from a secret store.
15
+ c.client_id = ENV['BUNNY_APP_CLIENT_ID']
16
+ c.client_secret = ENV['BUNNY_APP_CLIENT_SECRET']
17
+ c.scope = ENV['BUNNY_APP_SCOPE']
18
+
19
+ # Base URI for the Bunny API
20
+ c.base_uri = 'https://<subdomain>.bunny.com'
21
+
22
+ # Optional.
23
+ # Use this instead of client_id/secret if you dont care about the token expiring
24
+ # c.access_token = ENV['BUNNY_APP_ACCESS_TOKEN']
25
+
26
+ end
27
+ CONFIG
28
+ end
29
+ end
30
+ end
31
+ end
metadata ADDED
@@ -0,0 +1,174 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bunny_app
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.18.0
5
+ platform: ruby
6
+ authors:
7
+ - Bunny
8
+ - Rich Chetwynd
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2022-08-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: httparty
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '0.20'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '0.20'
28
+ - !ruby/object:Gem::Dependency
29
+ name: json
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '2.6'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '2.6'
42
+ - !ruby/object:Gem::Dependency
43
+ name: fakeweb
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '1.3'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '1.3'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rake
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '13.0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '13.0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: rspec
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '3.6'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '3.6'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rubocop
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '1.26'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: '1.26'
98
+ - !ruby/object:Gem::Dependency
99
+ name: rubocop-performance
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: '1.13'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '1.13'
112
+ - !ruby/object:Gem::Dependency
113
+ name: rubocop-rspec
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - "~>"
117
+ - !ruby/object:Gem::Version
118
+ version: '2.9'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: '2.9'
126
+ description: Use Bunny for SaaS subscription management, quoting, billing and CRM
127
+ email:
128
+ - support@bunny.com
129
+ executables: []
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - CHANGELOG.md
134
+ - Gemfile
135
+ - LICENSE
136
+ - README.md
137
+ - Rakefile
138
+ - bunny_app.gemspec
139
+ - lib/bunny_app.rb
140
+ - lib/bunny_app/client.rb
141
+ - lib/bunny_app/errors.rb
142
+ - lib/bunny_app/platform.rb
143
+ - lib/bunny_app/subscription.rb
144
+ - lib/bunny_app/tenant.rb
145
+ - lib/bunny_app/usage.rb
146
+ - lib/bunny_app/version.rb
147
+ - lib/bunny_app/webhook.rb
148
+ - lib/generators/bunny_app/install_generator.rb
149
+ homepage: https://github.com/bunny/bunny-ruby
150
+ licenses:
151
+ - MIT
152
+ metadata:
153
+ allowed_push_host: https://rubygems.org
154
+ rubygems_mfa_required: 'true'
155
+ post_install_message:
156
+ rdoc_options: []
157
+ require_paths:
158
+ - lib
159
+ required_ruby_version: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - ">="
162
+ - !ruby/object:Gem::Version
163
+ version: 3.1.0
164
+ required_rubygems_version: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - ">="
167
+ - !ruby/object:Gem::Version
168
+ version: '0'
169
+ requirements: []
170
+ rubygems_version: 3.3.3
171
+ signing_key:
172
+ specification_version: 4
173
+ summary: Ruby SDK for Bunny App
174
+ test_files: []