dodgeball-trust-sdk-ruby 0.0.1

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: abfd89964ce453124544cf58b89603d36c7ae5286aa52998a53e55d2755d67a5
4
+ data.tar.gz: 9e04f8b5b691b617d1e1e65df1e613e780023fc75ffe62a0d9b20a28a0450ad3
5
+ SHA512:
6
+ metadata.gz: 5eed501cfcf9f9d47eaa5f4d1469b2e14ff876212abd012941c2a22634c34986f25a1de91963dfcba8b923ede71752d9923bf6a6c0bfe668e3b597207832e55f
7
+ data.tar.gz: ded1407e1a0bdb6c530d1650fb8f394ec6f44219b90eaa4a43613d6a05eac2ed01e1610c0e8e23a1a3fca746e88ea8a9215ee06bf67485deb0cb131733320027
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dodgeball/client/defaults'
4
+
5
+ module Dodgeball
6
+ class Client
7
+ class BackoffPolicy
8
+ include Dodgeball::Client::Defaults::BackoffPolicy
9
+
10
+ # @param [Hash] opts
11
+ # @option opts [Numeric] :min_timeout_ms The minimum backoff timeout
12
+ # @option opts [Numeric] :max_timeout_ms The maximum backoff timeout
13
+ # @option opts [Numeric] :multiplier The value to multiply the current
14
+ # interval with for each retry attempt
15
+ # @option opts [Numeric] :randomization_factor The randomization factor
16
+ # to use to create a range around the retry interval
17
+ def initialize(opts = {})
18
+ @min_timeout_ms = opts[:min_timeout_ms] || MIN_TIMEOUT_MS
19
+ @max_timeout_ms = opts[:max_timeout_ms] || MAX_TIMEOUT_MS
20
+ @multiplier = opts[:multiplier] || MULTIPLIER
21
+ @randomization_factor = opts[:randomization_factor] || RANDOMIZATION_FACTOR
22
+
23
+ @attempts = 0
24
+ end
25
+
26
+ # @return [Numeric] the next backoff interval, in milliseconds.
27
+ def next_interval
28
+ interval = @min_timeout_ms * (@multiplier**@attempts)
29
+ interval = add_jitter(interval, @randomization_factor)
30
+
31
+ @attempts += 1
32
+
33
+ [interval, @max_timeout_ms].min
34
+ end
35
+
36
+ private
37
+
38
+ def add_jitter(base, randomization_factor)
39
+ random_number = rand
40
+ max_deviation = base * randomization_factor
41
+ deviation = random_number * max_deviation
42
+
43
+ if random_number < 0.5
44
+ base - deviation
45
+ else
46
+ base + deviation
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dodgeball
4
+ class Client
5
+ module Defaults
6
+ module Request
7
+ # HOST/PORT Used for testing
8
+ HOST = 'localhost'.freeze
9
+ PORT = 3000.freeze
10
+ PATH_ROOT = '/v1/'.freeze
11
+ DODGEBALL_API_URL = 'http://localhost:3000'.freeze
12
+
13
+ DEFAULT_READ_TIMEOUT = 8.freeze
14
+ DEFAULT_OPEN_TIMEOUT = 4.freeze
15
+ SSL = true.freeze
16
+ HEADERS = { 'Accept' => 'application/json',
17
+ 'Content-Type' => 'application/json',
18
+ 'User-Agent' => "dodgeball-ruby/#{Client::VERSION}" }.freeze
19
+ RETRIES = 10.freeze
20
+
21
+ SECRET_KEY_HEADER = 'Dodgeball-Secret-Key'.freeze
22
+ SOURCE_ID_HEADER = 'Dodgeball-Source-Id'.freeze
23
+ VERIFICATION_ID_HEADER = 'Dodgeball-Verification-Id'.freeze
24
+ end
25
+
26
+ module BackoffPolicy
27
+ MIN_TIMEOUT_MS = 100.freeze
28
+ MAX_TIMEOUT_MS = 10000.freeze
29
+ MULTIPLIER = 1.5.freeze
30
+ RANDOMIZATION_FACTOR = 0.5.freeze
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+
5
+ module Dodgeball
6
+ class Client
7
+ # Wraps an existing logger and adds a prefix to all messages
8
+ class PrefixedLogger
9
+ def initialize(logger, prefix)
10
+ @logger = logger
11
+ @prefix = prefix
12
+ end
13
+
14
+ def debug(msg)
15
+ @logger.debug("#{@prefix} #{msg}")
16
+ end
17
+
18
+ def info(msg)
19
+ @logger.info("#{@prefix} #{msg}")
20
+ end
21
+
22
+ def warn(msg)
23
+ @logger.warn("#{@prefix} #{msg}")
24
+ end
25
+
26
+ def error(msg)
27
+ @logger.error("#{@prefix} #{msg}")
28
+ end
29
+ end
30
+
31
+ module Logging
32
+ class << self
33
+ def logger
34
+ return @logger if @logger
35
+
36
+ base_logger = if defined?(Rails)
37
+ Rails.logger
38
+ else
39
+ logger = Logger.new STDOUT
40
+ logger.progname = 'Dodgeball::Client'
41
+ logger
42
+ end
43
+ @logger = PrefixedLogger.new(base_logger, '[dodgeball-ruby]')
44
+ end
45
+
46
+ attr_writer :logger
47
+ end
48
+
49
+ def self.included(base)
50
+ class << base
51
+ def logger
52
+ Logging.logger
53
+ end
54
+ end
55
+ end
56
+
57
+ def logger
58
+ Logging.logger
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dodgeball/client/defaults'
4
+ require 'dodgeball/client/utils'
5
+ require 'dodgeball/client/response'
6
+ require 'dodgeball/client/logging'
7
+ require 'dodgeball/client/backoff_policy'
8
+ require 'net/http'
9
+ require 'net/https'
10
+ require 'json'
11
+ require 'pry'
12
+ require 'uri'
13
+
14
+ module Dodgeball
15
+ class Client
16
+ class Request
17
+ include Dodgeball::Client::Defaults::Request
18
+ include Dodgeball::Client::Utils
19
+ include Dodgeball::Client::Logging
20
+
21
+
22
+ # public: Creates a new request object to send dodgeball api request
23
+ #
24
+ def initialize(options = {})
25
+ options[:host] ||= HOST
26
+ options[:port] ||= PORT
27
+
28
+ options[:ssl] ||= SSL
29
+
30
+ @headers = options[:headers] || HEADERS
31
+ @retries = options[:retries] || RETRIES
32
+ @backoff_policy =
33
+ options[:backoff_policy] || Dodgeball::Client::BackoffPolicy.new
34
+
35
+ uri = URI(options[:dodgeball_api_url] || DODGEBALL_API_URL)
36
+
37
+ http = Net::HTTP.new(uri.host, uri.port)
38
+ http.use_ssl = options[:ssl]
39
+ http.read_timeout = DEFAULT_READ_TIMEOUT
40
+ http.open_timeout = DEFAULT_OPEN_TIMEOUT
41
+
42
+ @http = http
43
+ end
44
+
45
+
46
+ # public: Posts the write key and path to the API.
47
+ #
48
+ # returns - Response of the status and error if it exists
49
+ def post(write_key, path, request_body, request_specific_headers=nil)
50
+
51
+ last_response, exception = retry_with_backoff(@retries) do
52
+ status_code, response_body = send_request(write_key, path, request_body, request_specific_headers)
53
+ should_retry = should_retry_request?(status_code, response_body)
54
+ logger.debug("Response status code: #{status_code}")
55
+ logger.debug("Response response body: #{response_body}") if response_body
56
+
57
+ [Response.new(status_code, response_body), should_retry]
58
+ end
59
+
60
+ if exception
61
+ logger.error(exception.message)
62
+ puts "E #{exception.message}"
63
+ exception.backtrace.each { |line| logger.error(line) }
64
+ Response.new(-1, exception.to_s)
65
+ else
66
+ last_response
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ def should_retry_request?(status_code, body)
73
+ if status_code >= 500
74
+ true # Server error
75
+ elsif status_code == 429
76
+ true # Rate limited
77
+ elsif status_code >= 400
78
+ logger.error(body)
79
+ false # Client error. Do not retry, but log
80
+ else
81
+ false
82
+ end
83
+ end
84
+
85
+ # Takes a block that returns [result, should_retry].
86
+ #
87
+ # Retries upto `retries_remaining` times, if `should_retry` is false or
88
+ # an exception is raised. `@backoff_policy` is used to determine the
89
+ # duration to sleep between attempts
90
+ #
91
+ # Returns [last_result, raised_exception]
92
+ def retry_with_backoff(retries_remaining, &block)
93
+ result, caught_exception = nil
94
+ should_retry = false
95
+
96
+ begin
97
+ result, should_retry = yield
98
+ return [result, nil] unless should_retry
99
+ rescue StandardError => e
100
+ should_retry = true
101
+ caught_exception = e
102
+ end
103
+
104
+ if should_retry && (retries_remaining > 1)
105
+ logger.debug("Retrying request, #{retries_remaining} retries left")
106
+ sleep(@backoff_policy.next_interval.to_f / 1000)
107
+ retry_with_backoff(retries_remaining - 1, &block)
108
+ else
109
+ [result, caught_exception]
110
+ end
111
+ end
112
+
113
+ # Sends a request to the path, returns [status_code, body]
114
+ def send_request(write_key, path, body, request_specific_headers)
115
+
116
+ payload = JSON.generate(body) if body
117
+
118
+ request_headers =(@headers || {}).merge(request_specific_headers || {})
119
+ request_headers[SECRET_KEY_HEADER] = write_key
120
+ request = Net::HTTP::Post.new(path, request_headers)
121
+
122
+ if self.class.stub
123
+ logger.debug "stubbed request to #{path}: " \
124
+ "write key = #{write_key}, payload = #{payload}"
125
+
126
+ [200, '{}']
127
+ else
128
+ puts payload
129
+ response = @http.request(request, payload)
130
+ [response.code.to_i, response.body]
131
+ end
132
+ end
133
+
134
+ class << self
135
+ attr_writer :stub
136
+
137
+ def stub
138
+ @stub || ENV['STUB']
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dodgeball
4
+ class Client
5
+ class Response
6
+ attr_reader :status, :response_body
7
+
8
+ # public: Simple class to wrap responses from the API
9
+ #
10
+ #
11
+ def initialize(status = 200, response_body = nil)
12
+ @status = status
13
+ @response_body = response_body
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module Dodgeball
6
+ class Client
7
+ module Utils
8
+ extend self
9
+
10
+ # public: Return a new hash with keys converted from strings to symbols
11
+ #
12
+ def symbolize_keys(hash)
13
+ hash.each_with_object({}) do |(k, v), memo|
14
+ memo[k.to_sym] = v
15
+ end
16
+ end
17
+
18
+ # public: Convert hash keys from strings to symbols in place
19
+ #
20
+ def symbolize_keys!(hash)
21
+ hash.replace symbolize_keys hash
22
+ end
23
+
24
+ # public: Return a new hash with keys as strings
25
+ #
26
+ def stringify_keys(hash)
27
+ hash.each_with_object({}) do |(k, v), memo|
28
+ memo[k.to_s] = v
29
+ end
30
+ end
31
+
32
+ # public: Returns a new hash with all the date values in the into iso8601
33
+ # strings
34
+ #
35
+ def isoify_dates(hash)
36
+ hash.each_with_object({}) do |(k, v), memo|
37
+ memo[k] = datetime_in_iso8601(v)
38
+ end
39
+ end
40
+
41
+ # public: Converts all the date values in the into iso8601 strings in place
42
+ #
43
+ def isoify_dates!(hash)
44
+ hash.replace isoify_dates hash
45
+ end
46
+
47
+ # public: Returns a uid string
48
+ #
49
+ def uid
50
+ arr = SecureRandom.random_bytes(16).unpack('NnnnnN')
51
+ arr[2] = (arr[2] & 0x0fff) | 0x4000
52
+ arr[3] = (arr[3] & 0x3fff) | 0x8000
53
+ '%08x-%04x-%04x-%04x-%04x%08x' % arr
54
+ end
55
+
56
+ def datetime_in_iso8601(datetime)
57
+ case datetime
58
+ when Time
59
+ time_in_iso8601 datetime
60
+ when DateTime
61
+ time_in_iso8601 datetime.to_time
62
+ when Date
63
+ date_in_iso8601 datetime
64
+ else
65
+ datetime
66
+ end
67
+ end
68
+
69
+ def time_in_iso8601(time, fraction_digits = 3)
70
+ fraction = (('.%06i' % time.usec)[0, fraction_digits + 1] if fraction_digits > 0)
71
+
72
+ "#{time.strftime('%Y-%m-%dT%H:%M:%S')}#{fraction}#{formatted_offset(time, true, 'Z')}"
73
+ end
74
+
75
+ def date_in_iso8601(date)
76
+ date.strftime('%F')
77
+ end
78
+
79
+ def formatted_offset(time, colon = true, alternate_utc_string = nil)
80
+ time.utc? && alternate_utc_string || seconds_to_utc_offset(time.utc_offset, colon)
81
+ end
82
+
83
+ def seconds_to_utc_offset(seconds, colon = true)
84
+ (colon ? UTC_OFFSET_WITH_COLON : UTC_OFFSET_WITHOUT_COLON) % [(seconds < 0 ? '-' : '+'), (seconds.abs / 3600), ((seconds.abs % 3600) / 60)]
85
+ end
86
+
87
+ UTC_OFFSET_WITH_COLON = '%s%02d:%02d'
88
+ UTC_OFFSET_WITHOUT_COLON = UTC_OFFSET_WITH_COLON.sub(':', '')
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dodgeball
4
+ class Client
5
+ VERSION = '0.0.1'
6
+ end
7
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'time'
4
+ require 'uri'
5
+
6
+ require 'dodgeball/client/version'
7
+ require 'dodgeball/client/defaults'
8
+ require 'dodgeball/client/utils'
9
+ require 'dodgeball/client/request'
10
+ require 'dodgeball/client/response'
11
+ require 'dodgeball/client/logging'
12
+ require 'net/http'
13
+
14
+ module Dodgeball
15
+ class Client
16
+ include Dodgeball::Client::Utils
17
+ include Dodgeball::Client::Logging
18
+
19
+ # @param [Hash] opts
20
+ # @option opts [String] :write_key Your project's write_key
21
+ # @option opts [String] :dodgeball_api_url Your Dodgeball API URL
22
+ # @option opts [Proc] :on_error Handles error calls from the API.
23
+ # @option opts [Boolean] :ssl Whether to send the call via SSL
24
+ # @option opts [Boolean] :stub Whether to cause all requests to be stubbed, making it easier to test
25
+ def initialize(opts = {})
26
+ symbolize_keys!(opts)
27
+ Request.stub = opts[:stub] if opts.has_key?(:stub)
28
+
29
+ @write_key = opts[:write_key]
30
+ @dodgeball_api_url = opts[:dodgeball_api_url] || Defaults::Request::DODGEBALL_API_URL
31
+ uri = URI(opts[:dodgeball_api_url])
32
+ @host = uri.host
33
+ @port = uri.port
34
+ @on_error = opts[:on_error] || proc { |status, error| }
35
+ @ssl = opts[:ssl] || Defaults::Request::SSL
36
+
37
+ check_write_key!
38
+ end
39
+
40
+
41
+ # Verifies an event and executes a workflow
42
+ #
43
+ # @param [Hash] attrs
44
+ #
45
+ # @option attrs [Hash] :event Any input to pass to the workflow (required)
46
+ # @option attrs [String] :source_id Id of the user from the client(required)
47
+ # @option attrs [Boolean] :sync Direction to the API to return immediately or wait until the workflow returns its first resolution.
48
+ # @option attrs [String] :verification_id if there was a previous verification executed in the client (optional)
49
+ def verify(event,source_id,verification_id=nil, sync=true)
50
+ raise ArgumentError.new('No event provided') unless event
51
+ raise ArgumentError.new('No source_id provided') unless source_id
52
+ request_headers={}
53
+ request_headers[Defaults::Request::SOURCE_ID_HEADER] = source_id
54
+ request_headers[Defaults::Request::VERIFICATION_ID_HEADER] = verification_id if verification_id
55
+ body = {event: event, options: {sync: sync}}
56
+ res=execute_request('verify', body, request_headers)
57
+ res
58
+ end
59
+
60
+
61
+ private
62
+
63
+ # private: Executes a request with common code to handle results.
64
+ #
65
+ def execute_request(request_function, body, request_specific_headers)
66
+ path=generate_path(request_function)
67
+ res = Request.new(:dodgeball_api_url => @dodgeball_api_url, :ssl => @ssl).post(@write_key, path, body, request_specific_headers)
68
+ @on_error.call(res.status, res.response_body) unless res.status == 200
69
+ res
70
+ end
71
+
72
+ # private: Adds the correct path root
73
+ #
74
+ # @param [String] Function name to build into a path
75
+ def generate_path(request_function)
76
+ Defaults::Request::PATH_ROOT + request_function
77
+ end
78
+
79
+ # private: Checks that the write_key is properly initialized
80
+ def check_write_key!
81
+ raise ArgumentError, 'Write key must be initialized' if @write_key.nil?
82
+ end
83
+
84
+ include Logging
85
+ end
86
+ end
data/lib/dodgeball.rb ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dodgeball/client'
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dodgeball'
metadata ADDED
@@ -0,0 +1,179 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dodgeball-trust-sdk-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Dodgeball
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-02-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: commander
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.4'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.4'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 12.3.3
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 12.3.3
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: tzinfo
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 1.2.1
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 1.2.1
69
+ - !ruby/object:Gem::Dependency
70
+ name: activesupport
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 6.0.2
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 6.0.2
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.9.12.2
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.9.12.2
97
+ - !ruby/object:Gem::Dependency
98
+ name: oj
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 3.6.2
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 3.6.2
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 0.78.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 0.78.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: codecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 0.1.4
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 0.1.4
139
+ description: This library provides functionality for Ruby-based server applications
140
+ to execute no-code workflows from the Dodgeball platform
141
+ email: hello@dodgeballhq.com
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - lib/dodgeball.rb
147
+ - lib/dodgeball/client.rb
148
+ - lib/dodgeball/client/backoff_policy.rb
149
+ - lib/dodgeball/client/defaults.rb
150
+ - lib/dodgeball/client/logging.rb
151
+ - lib/dodgeball/client/request.rb
152
+ - lib/dodgeball/client/response.rb
153
+ - lib/dodgeball/client/utils.rb
154
+ - lib/dodgeball/client/version.rb
155
+ - lib/trust-sdk-ruby.rb
156
+ homepage: https://github.com/dodgeballhq/dodgeball-trust-sdk-ruby
157
+ licenses:
158
+ - MIT
159
+ metadata: {}
160
+ post_install_message:
161
+ rdoc_options: []
162
+ require_paths:
163
+ - lib
164
+ required_ruby_version: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - ">="
167
+ - !ruby/object:Gem::Version
168
+ version: '2.0'
169
+ required_rubygems_version: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ requirements: []
175
+ rubygems_version: 3.0.3.1
176
+ signing_key:
177
+ specification_version: 4
178
+ summary: The Dodgeball Ruby Server Library
179
+ test_files: []