gate.rb 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 97a150ad280b246d59dce0e7e011ae8faeaf9f3c743b726ae931a7353457e5b3
4
+ data.tar.gz: a530909743923390245e633b04703c81fe9d78d10387118c959cea4d59a94e41
5
+ SHA512:
6
+ metadata.gz: e05641f6589dd90c24b86779b8845309da739e3fc662712c43b9ac49c00abd0097a45b17f77378ef94d943566da09b03519792e5b9d965d9e7ac953bdc6bd252
7
+ data.tar.gz: a40ba066ccc2aeeea27067601a0d91bd5f41ac5c5843c599efa58c69bd5b71bde598fec6979efdab6582d8ff634d1c02aa815d0de91050425ff90ef685e35cf4
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'http.rb'
4
+
5
+ group :development, :test do
6
+ gem 'rake'
7
+ gem 'minitest'
8
+ gem 'minitest-spec-context'
9
+ gem 'vcr'
10
+ gem 'webmock'
11
+ end
data/README.md ADDED
@@ -0,0 +1,88 @@
1
+ # gate.rb
2
+
3
+ Access the Gate API with Ruby.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'gate.rb'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```
16
+ $ bundle install
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```
22
+ $ gem install gate.rb
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ ```ruby
28
+ client = Gate::Client.new(
29
+ api_key: 'your_api_key',
30
+ api_secret: 'your_api_secret',
31
+ )
32
+ ```
33
+
34
+ ### Public API Methods
35
+
36
+ ```ruby
37
+ # Get all currencies
38
+ client.spot_currencies
39
+
40
+ # Get specific currency
41
+ client.spot_currencies('BTC')
42
+
43
+ # Get all symbol/currency pairs
44
+ client.currency_pairs
45
+
46
+ # Get one symbol/currency pair
47
+ client.currency_pairs('BTC_USDT')
48
+
49
+ # Get all ticker
50
+ client.spot_tickers
51
+
52
+ # Get ticker for one symbol/currency pair
53
+ client.spot_tickers(currency_pair: 'BTC_USDT')
54
+
55
+ # Get order book for a symbol/currency pair
56
+ client.spot_order_book(currency_pair: 'BTC_USDT')
57
+
58
+ # Get order book for a symbol/currency pair
59
+ client.spot_trades(currency_pair: 'BTC_USDT')
60
+
61
+ # Get OHLC for a symbol/currency pair
62
+ client.spot_candlesticks(currency_pair: 'BTC_USDT')
63
+
64
+ # Get OHLC for a symbol for specific period
65
+ client.spot_candlesticks('BTC_USDT', interval: '1d', start_time: 1648995780000, end_time: 1649082180000)
66
+
67
+ # Get server time
68
+ client.spot_time
69
+ ```
70
+
71
+ ### A Private API Method
72
+
73
+ ```ruby
74
+ # Get the authenticated user's trades for specific symbol/currency pair
75
+ client.spot_orders(currency_pair: 'BTC_USDT')
76
+ ```
77
+
78
+ ## Contributing
79
+
80
+ 1. Fork it (https://github.com/thoran/gate.rb/fork)
81
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
82
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
83
+ 4. Push to the branch (`git push origin my-new-feature`)
84
+ 5. Create a new pull request
85
+
86
+ ## License
87
+
88
+ The gem is available as open source under the terms of the [Ruby License](https://opensource.org/licenses/MIT).
data/gate.rb.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ require_relative './lib/Gate/VERSION'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'gate.rb'
5
+
6
+ spec.version = Gate::VERSION
7
+ spec.date = '2025-07-14'
8
+
9
+ spec.summary = "Access the Gate API with Ruby."
10
+ spec.description = "Access the Gate API with Ruby."
11
+
12
+ spec.author = 'thoran'
13
+ spec.email = 'code@thoran.com'
14
+ spec.homepage = 'http://github.com/thoran/gate.rb'
15
+ spec.license = 'Ruby'
16
+
17
+ spec.required_ruby_version = '>= 2.7'
18
+
19
+ spec.add_dependency('http.rb')
20
+ spec.files = [
21
+ 'gate.rb.gemspec',
22
+ 'Gemfile',
23
+ Dir['lib/**/*.rb'],
24
+ 'README.md',
25
+ Dir['test/**/*.rb']
26
+ ].flatten
27
+ spec.require_paths = ['lib']
28
+ end
@@ -0,0 +1,8 @@
1
+ # Gate/Client.rb
2
+ # Gate::Client
3
+
4
+ require_relative './V4/Client'
5
+
6
+ module Gate
7
+ class Client < Gate::V4::Client; end
8
+ end
data/lib/Gate/Error.rb ADDED
@@ -0,0 +1,30 @@
1
+ # Gate/Error.rb
2
+ # Gate::Error
3
+
4
+ module Gate
5
+ class Error < RuntimeError
6
+ attr_reader\
7
+ :code,
8
+ :message,
9
+ :body
10
+
11
+ def to_s
12
+ "#{self.class} (#{@code}): #{@message}"
13
+ end
14
+
15
+ private
16
+
17
+ def initialize(code:, message:, body:)
18
+ @code = code
19
+ @message = message
20
+ @body = body
21
+ super(message)
22
+ end
23
+ end
24
+
25
+ class APIError < Error; end
26
+ class AuthenticationError < Error; end
27
+ class InvalidRequestError < Error; end
28
+ class NetworkError < Error; end
29
+ class RateLimitError < Error; end
30
+ end
@@ -0,0 +1,254 @@
1
+ # Gate/V4/Client.rb
2
+ # Gate::V4::Client
3
+
4
+ # 20250714
5
+ # 0.1.0
6
+
7
+ # Notes:
8
+ # 1. API methods appear in the order in which they appear in the documentation.
9
+
10
+ gem 'http.rb'; require 'http.rb'
11
+ require 'json'
12
+ require 'openssl'
13
+
14
+ require 'Gate/Error'
15
+ require 'Hash/stringify_values'
16
+ require 'Hash/x_www_form_urlencode'
17
+
18
+ module Gate
19
+ module V4
20
+ class Client
21
+
22
+ API_HOST = 'api.gateio.ws'
23
+
24
+ class << self
25
+ def path_prefix
26
+ '/api/v4'
27
+ end
28
+ end # class << self
29
+
30
+ # Public endpoints
31
+
32
+ def spot_currencies(currency = nil)
33
+ response = get(
34
+ path: "/spot/currencies/#{currency}"
35
+ )
36
+ handle_response(response)
37
+ end
38
+
39
+ def spot_currency_pairs(currency_pair = nil)
40
+ response = get(
41
+ path: "/spot/currency_pairs/#{currency_pair}"
42
+ )
43
+ handle_response(response)
44
+ end
45
+
46
+ def spot_tickers(currency_pair: nil, timezone: nil)
47
+ response = get(
48
+ path: '/spot/tickers',
49
+ args: {currency_pair: currency_pair, timezone: timezone}
50
+ )
51
+ handle_response(response)
52
+ end
53
+
54
+ def spot_order_book(
55
+ currency_pair:,
56
+ interval: nil,
57
+ limit: nil,
58
+ with_id: nil
59
+ )
60
+ response = get(
61
+ path: '/spot/order_book',
62
+ args: {
63
+ currency_pair: currency_pair,
64
+ interval: interval,
65
+ limit: limit,
66
+ with_id: with_id
67
+ }
68
+ )
69
+ handle_response(response)
70
+ end
71
+
72
+ def spot_trades(
73
+ currency_pair:,
74
+ limit: nil,
75
+ last_id: nil,
76
+ reverse: nil,
77
+ from: nil,
78
+ to: nil,
79
+ page: nil
80
+ )
81
+ response = get(
82
+ path: '/spot/trades',
83
+ args: {
84
+ currency_pair: currency_pair,
85
+ limit: limit,
86
+ last_id: last_id,
87
+ reverse: reverse,
88
+ from: from,
89
+ to: to,
90
+ page: page
91
+ }
92
+ )
93
+ handle_response(response)
94
+ end
95
+
96
+ def spot_candlesticks(
97
+ currency_pair:,
98
+ limit: nil,
99
+ from: nil,
100
+ to: nil,
101
+ interval: nil
102
+ )
103
+ response = get(
104
+ path: '/spot/candlesticks',
105
+ args: {
106
+ currency_pair: currency_pair,
107
+ limit: limit,
108
+ from: from,
109
+ to: to,
110
+ interval: interval
111
+ }
112
+ )
113
+ handle_response(response)
114
+ end
115
+
116
+ def spot_time
117
+ response = get(
118
+ path: '/spot/time'
119
+ )
120
+ handle_response(response)
121
+ end
122
+
123
+ def spot_orders(
124
+ text: nil,
125
+ currency_pair:,
126
+ type: nil,
127
+ account: nil,
128
+ side:,
129
+ amount:,
130
+ price: nil,
131
+ time_in_force: nil,
132
+ iceberg: nil
133
+ )
134
+ args = {
135
+ text: text,
136
+ currency_pair: currency_pair,
137
+ type: type,
138
+ account: account,
139
+ side: side,
140
+ amount: amount,
141
+ price: price,
142
+ time_in_force: time_in_force,
143
+ iceberg: iceberg
144
+ }.reject{|k,v| v.nil?}.stringify_values
145
+ response = post(
146
+ path: '/spot/orders',
147
+ args: args
148
+ )
149
+ handle_response(response)
150
+ end
151
+
152
+ private
153
+
154
+ def initialize(api_key:, api_secret:)
155
+ @api_key = api_key.encode('UTF-8')
156
+ @api_secret = api_secret.encode('UTF-8')
157
+ end
158
+
159
+ def full_path(path)
160
+ self.class.path_prefix + path
161
+ end
162
+
163
+ def encoded_payload(args)
164
+ args.reject!{|k,v| v.nil?}
165
+ OpenSSL::Digest::SHA512.hexdigest(JSON.dump(args))
166
+ end
167
+
168
+ def timestamp
169
+ @timestamp ||= Time.now.to_i.to_s
170
+ end
171
+
172
+ def message(verb:, path:, args:)
173
+ query_string = (
174
+ case verb
175
+ when 'GET'
176
+ args.x_www_form_urlencode
177
+ when 'POST'
178
+ nil
179
+ else
180
+ raise "The verb, #{verb}, is not acceptable."
181
+ end
182
+ )
183
+ [verb, full_path(path), query_string, encoded_payload(args), timestamp].join("\n")
184
+ end
185
+
186
+ def signature(message)
187
+ OpenSSL::HMAC.hexdigest('SHA512', @api_secret, message)
188
+ end
189
+
190
+ def request_string(path)
191
+ "https://#{API_HOST}#{self.class.path_prefix}#{path}"
192
+ end
193
+
194
+ def headers(signature)
195
+ {
196
+ 'Accept' => 'application/json',
197
+ 'Content-Type' => 'application/json',
198
+ 'KEY' => @api_key,
199
+ 'SIGN' => signature,
200
+ 'Timestamp' => timestamp,
201
+ }
202
+ end
203
+
204
+ def do_request(verb:, path:, args: {})
205
+ message = message(verb: verb, path: path, args: args)
206
+ signature = signature(message)
207
+ response = HTTP.send(verb.to_s.downcase, request_string(path), args, headers(signature))
208
+ @timestamp = nil
209
+ response
210
+ end
211
+
212
+ def get(path:, args: {})
213
+ do_request(verb: 'GET', path: path, args: args)
214
+ end
215
+
216
+ def post(path:, args: {})
217
+ do_request(verb: 'POST', path: path, args: args)
218
+ end
219
+
220
+ def handle_response(response)
221
+ if response.success?
222
+ JSON.parse(response.body)
223
+ else
224
+ case response.code.to_i
225
+ when 400
226
+ raise Gate::InvalidRequestError.new(
227
+ code: response.code,
228
+ message: response.message,
229
+ body: response.body
230
+ )
231
+ when 401
232
+ raise Gate::AuthenticationError.new(
233
+ code: response.code,
234
+ message: response.message,
235
+ body: response.body
236
+ )
237
+ when 429
238
+ raise Gate::RateLimitError.new(
239
+ code: response.code,
240
+ message: response.message,
241
+ body: response.body
242
+ )
243
+ else
244
+ raise Gate::APIError.new(
245
+ code: response.code,
246
+ message: response.message,
247
+ body: response.body
248
+ )
249
+ end
250
+ end
251
+ end
252
+ end
253
+ end
254
+ end
@@ -0,0 +1,6 @@
1
+ # Gate/VERSION.rb
2
+ # Gate::VERSION
3
+
4
+ module Gate
5
+ VERSION = '0.1.0'
6
+ end
@@ -0,0 +1,14 @@
1
+ # Hash/stringify_values.rb
2
+ # Hash#stringify_values
3
+
4
+ # 20250425
5
+ # 0.0.0
6
+
7
+ class Hash
8
+ def stringify_values
9
+ self.inject({}) do |a,e|
10
+ a[e.first] = e.last.to_s
11
+ a
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,7 @@
1
+ # Hash/x_www_form_urlencode.rb
2
+ # Hash#x_www_form_urlencode
3
+
4
+ # 20241009
5
+ # 0.1.0
6
+
7
+ require 'Thoran/Hash/XWwwFormUrlencode/x_www_form_urlencode'
@@ -0,0 +1,26 @@
1
+ # Thoran/Hash/XWwwFormUrlEncode/x_www_form_urlencode.rb
2
+ # Thoran::Hash::XWwwFormUrlEncode#x_www_form_urlencode
3
+
4
+ # 20241009
5
+ # 0.2.0
6
+
7
+ # Changes since 0.1:
8
+ # -/0: (The class name and the snake case name are consistent now.)
9
+ # 1. /XWWWFormUrlEncode/XWwwFormUrlEncode/
10
+
11
+ require 'Thoran/String/UrlEncode/url_encode'
12
+
13
+ module Thoran
14
+ module Hash
15
+ module XWwwFormUrlEncode
16
+
17
+ def x_www_form_url_encode(joiner = '&')
18
+ inject([]){|a,e| a << "#{e.first.to_s.url_encode}=#{e.last.to_s.url_encode}" unless e.last.nil?; a}.join(joiner)
19
+ end
20
+ alias_method :x_www_form_urlencode, :x_www_form_url_encode
21
+
22
+ end
23
+ end
24
+ end
25
+
26
+ Hash.send(:include, Thoran::Hash::XWwwFormUrlEncode)
@@ -0,0 +1,26 @@
1
+ # Thoran/String/UrlEncode/url_encode.rb
2
+ # Thoran::String::UrlEncode#url_encode
3
+
4
+ # 20160505
5
+ # 0.3.0
6
+
7
+ # Acknowledgements: I've simply ripped off and refashioned the code from the CGI module!...
8
+
9
+ # Changes since 0.2:
10
+ # 1. + Thoran namespace.
11
+
12
+ module Thoran
13
+ module String
14
+ module UrlEncode
15
+
16
+ def url_encode
17
+ self.gsub(/([^ a-zA-Z0-9_.-]+)/n) do
18
+ '%' + $1.unpack('H2' * $1.size).join('%').upcase
19
+ end.tr(' ', '+')
20
+ end
21
+
22
+ end
23
+ end
24
+ end
25
+
26
+ String.send(:include, Thoran::String::UrlEncode)
data/lib/gate.rb ADDED
@@ -0,0 +1,9 @@
1
+ # gate.rb
2
+
3
+ lib_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+ $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
5
+
6
+ module Gate; end
7
+
8
+ require 'Gate/Client'
9
+ require 'Gate/VERSION'
@@ -0,0 +1,43 @@
1
+ require_relative '../../../helper'
2
+
3
+ describe Gate::V4::Client do
4
+ let(:api_key){ENV.fetch('GATE_API_KEY', '<API_KEY>')}
5
+ let(:api_secret){ENV.fetch('GATE_API_SECRET', '<API_SECRET>')}
6
+
7
+ subject do
8
+ Gate::V4::Client.new(
9
+ api_key: api_key,
10
+ api_secret: api_secret
11
+ )
12
+ end
13
+
14
+ describe "#spot_orders" do
15
+ let(:amount){0.0001}
16
+ let(:price){100_000}
17
+ let(:side){'buy'}
18
+
19
+ context "success" do
20
+ it "fetches my orders for a specific market" do
21
+ VCR.use_cassette('v4/spot/orders') do
22
+ response = subject.spot_orders(currency_pair: 'BTC_USDT', side: side, amount: amount, time_in_force: 'gtc', price: price)
23
+ _(response).must_be_kind_of(Hash)
24
+ assert(response['id'])
25
+ assert(response['create_time'])
26
+ _(response['amount']).must_equal(amount.to_s)
27
+ _(response['price']).must_equal(price.to_s)
28
+ _(response['side']).must_equal(side)
29
+ end
30
+ end
31
+ end
32
+
33
+ context "invalid key" do
34
+ it "fetches my orders for a specific market" do
35
+ VCR.use_cassette('v4/spot/orders_with_an_invalid_key') do
36
+ assert_raises do
37
+ subject.spot_orders(currency_pair: 'BTC_USDT', side: side, amount: amount, time_in_force: 'gtc', price: price)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,147 @@
1
+ require_relative '../../../helper'
2
+
3
+ describe Gate::V4::Client do
4
+ let(:api_key){ENV.fetch('GATE_API_KEY', '<API_KEY>')}
5
+ let(:api_secret){ENV.fetch('GATE_API_SECRET', '<API_SECRET>')}
6
+
7
+ subject do
8
+ Gate::V4::Client.new(
9
+ api_key: api_key,
10
+ api_secret: api_secret
11
+ )
12
+ end
13
+
14
+ describe "#spot_currencies" do
15
+ context "no currency specified" do
16
+ it "fetches all currencies" do
17
+ VCR.use_cassette('v4/spot/currencies') do
18
+ response = subject.spot_currencies
19
+ _(response).must_be_kind_of(Array)
20
+ assert(response.size > 4000)
21
+ _(response[0]['currency']).must_equal('BBC')
22
+ end
23
+ end
24
+ end
25
+
26
+ context "currency specified" do
27
+ it "fetches one currency" do
28
+ VCR.use_cassette('v4/spot/currencies_btc') do
29
+ response = subject.spot_currencies('BTC')
30
+ _(response).must_be_kind_of(Hash)
31
+ _(response.size).must_equal(10)
32
+ _(response['currency']).must_equal('BTC')
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ describe "#spot_currency_pairs" do
39
+ context "no pair specified" do
40
+ it "fetches data for all markets" do
41
+ VCR.use_cassette('v4/spot/currency_pairs') do
42
+ response = subject.spot_currency_pairs
43
+ _(response).must_be_kind_of(Array)
44
+ assert(response.size > 2000)
45
+ _(response[0]['id']).must_equal('ALEPH_USDT')
46
+ _(response[0]['base']).must_equal('ALEPH')
47
+ _(response[0]['quote']).must_equal('USDT')
48
+ end
49
+ end
50
+ end
51
+
52
+ context "pair specified" do
53
+ it "fetches data for one market" do
54
+ VCR.use_cassette('v4/spot/currency_pairs_btc') do
55
+ response = subject.spot_currency_pairs('BTC_USDT')
56
+ _(response).must_be_kind_of(Hash)
57
+ _(response.size).must_equal(18)
58
+ _(response['id']).must_equal('BTC_USDT')
59
+ _(response['base']).must_equal('BTC')
60
+ _(response['quote']).must_equal('USDT')
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ describe "#spot_tickers" do
67
+ context "no ticker specified" do
68
+ it "fetches tickers for all markets" do
69
+ VCR.use_cassette('v4/spot/tickers') do
70
+ response = subject.spot_tickers
71
+ _(response).must_be_kind_of(Array)
72
+ assert(response.size > 2000)
73
+ _(response[0]['currency_pair']).must_equal('BAND_USDT')
74
+ assert(response[0]['last'].match(/\d+\.\d*/))
75
+ assert(response[0]['change_percentage'].match(/\d+\.\d*/))
76
+ end
77
+ end
78
+ end
79
+
80
+ context "ticker specified" do
81
+ it "fetches ticker for a specific market" do
82
+ VCR.use_cassette('v4/spot/tickers_btc') do
83
+ response = subject.spot_tickers(currency_pair: 'BTC_USDT')
84
+ _(response).must_be_kind_of(Array)
85
+ _(response[0]['currency_pair']).must_equal('BTC_USDT')
86
+ assert(response[0]['last'].match(/\d+\.\d*/))
87
+ assert(response[0]['change_percentage'].match(/\d+\.\d*/))
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ describe "#spot_order_book" do
94
+ it "retrieves order book for a specific market" do
95
+ VCR.use_cassette('v4/spot/order_book') do
96
+ response = subject.spot_order_book(currency_pair:'BTC_USDT', limit: 10)
97
+ _(response).must_be_kind_of(Hash)
98
+ _(response['asks'].size).must_equal(10)
99
+ _(response['bids'].size).must_equal(10)
100
+ _(response['asks']).must_be_kind_of(Array)
101
+ _(response['bids']).must_be_kind_of(Array)
102
+ assert(response['asks'].first.first.match(/\d+\.*\d*/))
103
+ assert(response['asks'].first.last.match(/\d+\.*\d*/))
104
+ assert(response['bids'].first.first.match(/\d+\.*\d*/))
105
+ assert(response['bids'].first.last.match(/\d+\.*\d*/))
106
+ end
107
+ end
108
+ end
109
+
110
+ describe "#spot_trades" do
111
+ it "fetches recent trades for a given market" do
112
+ VCR.use_cassette('v4/spot/trades') do
113
+ response = subject.spot_trades(currency_pair: 'BTC_USDT', limit: 10)
114
+ _(response).must_be_kind_of(Array)
115
+ _(response.size).must_equal(10)
116
+ assert(response[0]['id'].match(/\d+\.*\d*/))
117
+ assert(response[0]['side'] == 'buy' || response[0]['side'] == 'sell')
118
+ assert(response[0]['amount'].match(/\d+\.*\d*/))
119
+ assert(response[0]['price'].match(/\d+\.*\d*/))
120
+ end
121
+ end
122
+ end
123
+
124
+ describe "#spot_candlesticks" do
125
+ it "fetches candlestick data for a specific market" do
126
+ VCR.use_cassette('v4/spot/candlesticks') do
127
+ response = subject.spot_candlesticks(currency_pair: 'BTC_USDT', interval: '1h', limit: 10)
128
+ _(response).must_be_kind_of(Array)
129
+ _(response.size).must_equal(10)
130
+ _(response[0].size).must_equal(8)
131
+ assert(response[0][0].match(/\d+\.*\d*/))
132
+ assert(response[0][1].match(/\d+\.*\d*/)) # open
133
+ assert(response[0][4].match(/\d+\.*\d*/)) # close
134
+ end
135
+ end
136
+ end
137
+
138
+ describe "#spot_time" do
139
+ it "fetches candlestick data for a specific market" do
140
+ VCR.use_cassette('v4/spot/time') do
141
+ response = subject.spot_time
142
+ _(response).must_be_kind_of(Hash)
143
+ assert(response['server_time'].to_s.match(/\d+\.*\d*/))
144
+ end
145
+ end
146
+ end
147
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,32 @@
1
+ require 'minitest/autorun'
2
+ require 'minitest/spec'
3
+ require 'minitest-spec-context'
4
+ require 'vcr'
5
+ require 'webmock'
6
+
7
+ $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
8
+ require 'gate'
9
+
10
+ VCR.configure do |config|
11
+ config.cassette_library_dir = 'test/fixtures/vcr_cassettes'
12
+
13
+ config.hook_into :webmock
14
+
15
+ config.filter_sensitive_data('<API_KEY>'){ENV['GATE_API_KEY']}
16
+ config.filter_sensitive_data('<API_SECRET>'){ENV['GATE_API_SECRET'] }
17
+
18
+ # Allow localhost connections for debugging
19
+ config.ignore_localhost = true
20
+
21
+ config.default_cassette_options = {
22
+ record: :new_episodes,
23
+ match_requests_on: [:method, :uri]
24
+ }
25
+ end
26
+
27
+ class Minitest::Test
28
+ def before_setup
29
+ super
30
+ Gate.reset_configuration!
31
+ end
32
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gate.rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - thoran
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2025-07-14 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: http.rb
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
26
+ description: Access the Gate API with Ruby.
27
+ email: code@thoran.com
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - Gemfile
33
+ - README.md
34
+ - gate.rb.gemspec
35
+ - lib/Gate/Client.rb
36
+ - lib/Gate/Error.rb
37
+ - lib/Gate/V4/Client.rb
38
+ - lib/Gate/VERSION.rb
39
+ - lib/Hash/stringify_values.rb
40
+ - lib/Hash/x_www_form_urlencode.rb
41
+ - lib/Thoran/Hash/XWwwFormUrlencode/x_www_form_urlencode.rb
42
+ - lib/Thoran/String/UrlEncode/url_encode.rb
43
+ - lib/gate.rb
44
+ - test/Gate/V4/Client/test_private_endpoints.rb
45
+ - test/Gate/V4/Client/test_public_endpoints.rb
46
+ - test/helper.rb
47
+ homepage: http://github.com/thoran/gate.rb
48
+ licenses:
49
+ - Ruby
50
+ metadata: {}
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '2.7'
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubygems_version: 3.6.9
66
+ specification_version: 4
67
+ summary: Access the Gate API with Ruby.
68
+ test_files: []