coinmarketcap.rb 0.3.1
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 +7 -0
- data/Gemfile +9 -0
- data/README.md +104 -0
- data/coinmarketcap.rb.gemspec +28 -0
- data/lib/CoinMarketCap/Client.rb +92 -0
- data/lib/CoinMarketCap/Common.rb +61 -0
- data/lib/CoinMarketCap/V1/Client.rb +84 -0
- data/lib/CoinMarketCap/V2/Client.rb +67 -0
- data/lib/CoinMarketCap/VERSION.rb +6 -0
- data/lib/CoinMarketCap.rb +4 -0
- data/test/V1/client_test.rb +141 -0
- data/test/V2/client_test.rb +111 -0
- data/test/client_test.rb +213 -0
- data/test/helper.rb +18 -0
- metadata +66 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9418640a33531147099044276f4ae89f219e52f97def35df2581d85eb61f59b7
|
4
|
+
data.tar.gz: 565de31e863b431b9d772e7ded94cfffd0d607fa5829018600947b7cf7837ca1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5315e3dd994ef654670772cdff4efecc7d8a992489720497b17f18223fdb7008de1127315d1f4c405d0fd656b7bd08aa593ba2a56029e98e463180a81c5e4758
|
7
|
+
data.tar.gz: 4e575c130f2aa09d041a0ae5183a02a617958064841d87016e028960179df70af07455859d6c1f8840e8b5960ec4f32df41fccc48e804d016daf7b391817c7aa
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
# coinmarketcap.rb
|
2
|
+
|
3
|
+
## Description
|
4
|
+
|
5
|
+
Access the coinmarketcap.com API with Ruby.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
```ruby
|
11
|
+
gem 'coinmarketcap.rb'
|
12
|
+
```
|
13
|
+
And then execute:
|
14
|
+
```bash
|
15
|
+
$ bundle
|
16
|
+
```
|
17
|
+
Or install it yourself as:
|
18
|
+
```bash
|
19
|
+
$ gem install coinmarketcap.rb
|
20
|
+
```
|
21
|
+
|
22
|
+
## Notes
|
23
|
+
|
24
|
+
This gem attempts to make sense of a CoinMarketCap's somewhat confused APIs and so far only partially covers off V1 and V2 APIs. It makes sense of the V1 and V2 APIs by creating a mezzanine, API version agnostic client which will use V1 or V2 endpoints/sub-clients selectively depending on which retrieves the requested information whilst giving a cleaner and more consistent overall interface. It is likely that further abstraction/simplification of the APIs is possible, further improving the usability.
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
### Setup
|
29
|
+
```ruby
|
30
|
+
api_key = 'api_key0'
|
31
|
+
coinmarketcap_client ||= CoinMarketCap::Client.new(api_key: api_key)
|
32
|
+
```
|
33
|
+
|
34
|
+
### Airdrops
|
35
|
+
```ruby
|
36
|
+
coinmarketcap_client.airdrops
|
37
|
+
coinmarketcap_client.airdrops(id: 123)
|
38
|
+
```
|
39
|
+
|
40
|
+
### Categories
|
41
|
+
```ruby
|
42
|
+
coinmarketcap_client.categories
|
43
|
+
coinmarketcap_client.categories(id: 123)
|
44
|
+
```
|
45
|
+
|
46
|
+
### Gainers and Losers
|
47
|
+
```ruby
|
48
|
+
coinmarketcap_client.gainers_and_losers
|
49
|
+
```
|
50
|
+
|
51
|
+
### Historical Price Data (OHLCV)
|
52
|
+
```ruby
|
53
|
+
coinmarketcap_client.historical_price_data(id: 123)
|
54
|
+
```
|
55
|
+
|
56
|
+
### Historical Quotes
|
57
|
+
```ruby
|
58
|
+
coinmarketcap_client.historical_quotes
|
59
|
+
coinmarketcap_client.historical_quotes(id: 123)
|
60
|
+
```
|
61
|
+
|
62
|
+
### Info for a Specific Coin
|
63
|
+
```ruby
|
64
|
+
coinmarketcap_client.info(id: 123)
|
65
|
+
```
|
66
|
+
|
67
|
+
### Latest Coin Pairs Listed
|
68
|
+
```ruby
|
69
|
+
coinmarketcap_client.latest_listings
|
70
|
+
```
|
71
|
+
|
72
|
+
### Latest OHLCV Price Data
|
73
|
+
```ruby
|
74
|
+
coinmarketcap_client.latest_price_data
|
75
|
+
```
|
76
|
+
|
77
|
+
### Latest Performance Stats
|
78
|
+
```ruby
|
79
|
+
coinmarketcap_client.latest_price_performance_stats
|
80
|
+
```
|
81
|
+
|
82
|
+
### Latest Quotes
|
83
|
+
```ruby
|
84
|
+
coinmarketcap_client.latest_quotes
|
85
|
+
coinmarketcap_client.latest_quotes(id: 123)
|
86
|
+
```
|
87
|
+
|
88
|
+
### Most Visited Coins
|
89
|
+
```ruby
|
90
|
+
coinmarketcap_client.most_visited
|
91
|
+
```
|
92
|
+
|
93
|
+
### Trending Coins
|
94
|
+
```ruby
|
95
|
+
coinmarketcap_client.trending
|
96
|
+
```
|
97
|
+
|
98
|
+
## Contributing
|
99
|
+
|
100
|
+
1. Fork it ( https://github.com/thoran/eodhd.rb/fork )
|
101
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
102
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
103
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
104
|
+
5. Create a new pull request
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative './lib/CoinMarketCap/VERSION'
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = 'coinmarketcap.rb'
|
5
|
+
|
6
|
+
spec.version = CoinMarketCap::VERSION
|
7
|
+
spec.date = '2025-03-30'
|
8
|
+
|
9
|
+
spec.summary = "Access the coinmarketcap.com API with Ruby."
|
10
|
+
spec.description = "Access the coinmarketcap.com API with Ruby."
|
11
|
+
|
12
|
+
spec.author = 'thoran'
|
13
|
+
spec.email = 'code@thoran.com'
|
14
|
+
spec.homepage = 'http://github.com/thoran/coinmarketcap.rb'
|
15
|
+
spec.license = 'Ruby'
|
16
|
+
|
17
|
+
spec.required_ruby_version = '>= 2.7'
|
18
|
+
|
19
|
+
spec.add_dependency('http.rb')
|
20
|
+
spec.files = [
|
21
|
+
'coinmarketcap.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,92 @@
|
|
1
|
+
# CoinMarketCap/Client.rb
|
2
|
+
# CoinMarketCap::Client
|
3
|
+
|
4
|
+
require_relative './V1/Client'
|
5
|
+
require_relative './V2/Client'
|
6
|
+
|
7
|
+
module CoinMarketCap
|
8
|
+
class Client
|
9
|
+
def airdrops(id: nil)
|
10
|
+
if id
|
11
|
+
v1_client.airdrop(id: id)
|
12
|
+
else
|
13
|
+
v1_client.airdrops
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def categories(id: nil)
|
18
|
+
if id
|
19
|
+
v1_client.category(id: id)
|
20
|
+
else
|
21
|
+
v1_client.categories
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def gainers_and_losers
|
26
|
+
v1_client.trending_gainers_losers
|
27
|
+
end
|
28
|
+
|
29
|
+
def historical_price_data(id:)
|
30
|
+
v2_client.ohlcv_historical(id: id)
|
31
|
+
end
|
32
|
+
|
33
|
+
# I don't see the point of these endpoints at all. (Ha ha!) Either you want current prices or you want historical OHLCV. I don't see why having historical quotes is of any value.
|
34
|
+
def historical_quotes(id: nil)
|
35
|
+
if id
|
36
|
+
v2_client.quotes_historical(id: id)
|
37
|
+
else
|
38
|
+
v1_client.listings_historical
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def info(id:)
|
43
|
+
v2_client.info(id: id)
|
44
|
+
end
|
45
|
+
|
46
|
+
def map
|
47
|
+
v1_client.map
|
48
|
+
end
|
49
|
+
|
50
|
+
def latest_listings
|
51
|
+
v2_client.market_pairs_latest
|
52
|
+
end
|
53
|
+
|
54
|
+
def latest_price_data
|
55
|
+
v2_client.ohlcv_latest
|
56
|
+
end
|
57
|
+
|
58
|
+
def most_visited
|
59
|
+
v1_client.trending_most_visited
|
60
|
+
end
|
61
|
+
|
62
|
+
def latest_price_performance_stats
|
63
|
+
v2_client.price_performance_stats_latest
|
64
|
+
end
|
65
|
+
|
66
|
+
def latest_quotes(id: nil)
|
67
|
+
if id
|
68
|
+
v2_client.quotes_latest(id: id)
|
69
|
+
else
|
70
|
+
v1_client.listings_latest
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def trending
|
75
|
+
v1_client.trending_latest
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def initialize(api_key:)
|
81
|
+
@api_key = api_key
|
82
|
+
end
|
83
|
+
|
84
|
+
def v1_client
|
85
|
+
@v1_client ||= CoinMarketCap::V1::Client.new(api_key: @api_key)
|
86
|
+
end
|
87
|
+
|
88
|
+
def v2_client
|
89
|
+
@v2_client ||= CoinMarketCap::V2::Client.new(api_key: @api_key)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# CoinMarketCap/Common.rb
|
2
|
+
# CoinMarketCap::Common
|
3
|
+
|
4
|
+
module CoinMarketCap
|
5
|
+
class Error < RuntimeError
|
6
|
+
attr_reader :code, :message, :body
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def initialize(code:, message:, body:)
|
11
|
+
@code = code
|
12
|
+
@message = message
|
13
|
+
@body = body
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module Common
|
18
|
+
API_HOST = 'pro-api.coinmarketcap.com'
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def initialize(api_key:)
|
23
|
+
@api_key = api_key
|
24
|
+
end
|
25
|
+
|
26
|
+
def request_string(path)
|
27
|
+
"https://#{API_HOST}#{self.class.path_prefix}#{path}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def headers
|
31
|
+
{
|
32
|
+
'Accept' => 'application/json',
|
33
|
+
'X-CMC_PRO_API_KEY' => @api_key,
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def do_request(verb:, path:, args: {})
|
38
|
+
HTTP.send(verb.to_s.downcase, request_string(path), args, headers)
|
39
|
+
end
|
40
|
+
|
41
|
+
def get(path:, args: {})
|
42
|
+
do_request(verb: 'GET', path: path, args: args)
|
43
|
+
end
|
44
|
+
|
45
|
+
def post(path:, args: {})
|
46
|
+
do_request(verb: 'POST', path: path, args: args)
|
47
|
+
end
|
48
|
+
|
49
|
+
def handle_response(response)
|
50
|
+
if response.success?
|
51
|
+
JSON.parse(response.body)
|
52
|
+
else
|
53
|
+
raise CoinMarketCap::Error.new(
|
54
|
+
code: response.code,
|
55
|
+
message: response.message,
|
56
|
+
body: response.body,
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# CoinMarketCap/V1/Client.rb
|
2
|
+
# CoinMarketCap::V1::Client
|
3
|
+
|
4
|
+
# Notes:
|
5
|
+
# 1. From https://coinmarketcap.com/api/documentation/v1/#tag/cryptocurrency
|
6
|
+
# /v1/cryptocurrency/airdrop - Airdrop
|
7
|
+
# /v1/cryptocurrency/airdrops - Airdrops
|
8
|
+
# /v1/cryptocurrency/categories - Categories
|
9
|
+
# /v1/cryptocurrency/category - Category
|
10
|
+
# /v1/cryptocurrency/listings/historical - Historical listings
|
11
|
+
# /v1/cryptocurrency/listings/latest - Latest listings
|
12
|
+
# /v1/cryptocurrency/map - CoinMarketCap ID map
|
13
|
+
# /v1/cryptocurrency/trending/gainers-losers - Trending Gainers & Losers
|
14
|
+
# /v1/cryptocurrency/trending/latest - Trending Latest
|
15
|
+
# /v1/cryptocurrency/trending/most-visited - Trending Most Visited
|
16
|
+
|
17
|
+
gem 'http.rb'
|
18
|
+
require 'http.rb'
|
19
|
+
require 'json'
|
20
|
+
require_relative '../Common'
|
21
|
+
|
22
|
+
module CoinMarketCap
|
23
|
+
module V1
|
24
|
+
class Client
|
25
|
+
include Common
|
26
|
+
|
27
|
+
class << self
|
28
|
+
def path_prefix
|
29
|
+
'/v1/cryptocurrency'
|
30
|
+
end
|
31
|
+
end # class << self
|
32
|
+
|
33
|
+
def airdrop(id:)
|
34
|
+
response = get(path: '/airdrop', args: {id: id})
|
35
|
+
handle_response(response)
|
36
|
+
end
|
37
|
+
|
38
|
+
def airdrops
|
39
|
+
response = get(path: '/airdrops')
|
40
|
+
handle_response(response)
|
41
|
+
end
|
42
|
+
|
43
|
+
def categories
|
44
|
+
response = get(path: '/categories')
|
45
|
+
handle_response(response)
|
46
|
+
end
|
47
|
+
|
48
|
+
def category(id:)
|
49
|
+
response = get(path: '/category', args: {id: id})
|
50
|
+
handle_response(response)
|
51
|
+
end
|
52
|
+
|
53
|
+
def listings_historical
|
54
|
+
response = get(path: '/listings/historical')
|
55
|
+
handle_response(response)
|
56
|
+
end
|
57
|
+
|
58
|
+
def listings_latest
|
59
|
+
response = get(path: '/listings/latest')
|
60
|
+
handle_response(response)
|
61
|
+
end
|
62
|
+
|
63
|
+
def map
|
64
|
+
response = get(path: '/map')
|
65
|
+
handle_response(response)
|
66
|
+
end
|
67
|
+
|
68
|
+
def trending_gainers_losers
|
69
|
+
response = get(path: '/trending/gainers-losers')
|
70
|
+
handle_response(response)
|
71
|
+
end
|
72
|
+
|
73
|
+
def trending_latest
|
74
|
+
response = get(path: '/trending/latest')
|
75
|
+
handle_response(response)
|
76
|
+
end
|
77
|
+
|
78
|
+
def trending_most_visited
|
79
|
+
response = get(path: '/trending/most-visited')
|
80
|
+
handle_response(response)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# CoinMarketCap/V2/Client.rb
|
2
|
+
# CoinMarketCap::V2::Client
|
3
|
+
|
4
|
+
# Notes:
|
5
|
+
# 1. From https://coinmarketcap.com/api/documentation/v1/#tag/cryptocurrency
|
6
|
+
# /v2/cryptocurrency/info - Metadata
|
7
|
+
# /v2/cryptocurrency/market-pairs/latest - Latest market pairs
|
8
|
+
# /v2/cryptocurrency/ohlcv/historical - Historical OHLCV
|
9
|
+
# /v2/cryptocurrency/ohlcv/latest - Latest OHLCV
|
10
|
+
# /v2/cryptocurrency/price-performance-stats/latest - Price performance Stats
|
11
|
+
# /v2/cryptocurrency/quotes/historical - Historical quotes
|
12
|
+
# /v2/cryptocurrency/quotes/latest - Latest quotes
|
13
|
+
|
14
|
+
gem 'http.rb'
|
15
|
+
require 'http.rb'
|
16
|
+
require 'json'
|
17
|
+
require_relative '../Common'
|
18
|
+
|
19
|
+
module CoinMarketCap
|
20
|
+
module V2
|
21
|
+
class Client
|
22
|
+
include Common
|
23
|
+
|
24
|
+
class << self
|
25
|
+
def path_prefix
|
26
|
+
'/v2/cryptocurrency'
|
27
|
+
end
|
28
|
+
end # class << self
|
29
|
+
|
30
|
+
def info(id:)
|
31
|
+
response = get(path: '/info', args: {id: id})
|
32
|
+
handle_response(response)
|
33
|
+
end
|
34
|
+
|
35
|
+
def market_pairs_latest
|
36
|
+
response = get(path: '/market-pairs/latest')
|
37
|
+
handle_response(response)
|
38
|
+
end
|
39
|
+
|
40
|
+
def ohlcv_historical(id:)
|
41
|
+
response = get(path: '/ohlcv/historical', args: {id: id})
|
42
|
+
handle_response(response)
|
43
|
+
end
|
44
|
+
|
45
|
+
def ohlcv_latest
|
46
|
+
response = get(path: '/ohlcv/latest')
|
47
|
+
handle_response(response)
|
48
|
+
end
|
49
|
+
|
50
|
+
def price_performance_stats_latest
|
51
|
+
response = get(path: '/price-performance-stats/latest')
|
52
|
+
handle_response(response)
|
53
|
+
end
|
54
|
+
|
55
|
+
def quotes_historical(id:)
|
56
|
+
response = get(path: '/quotes/historical', args: {id: id})
|
57
|
+
handle_response(response)
|
58
|
+
end
|
59
|
+
|
60
|
+
def quotes_latest(id:)
|
61
|
+
id = [id].compact.join(',')
|
62
|
+
response = get(path: '/quotes/latest', args: {id: id})
|
63
|
+
handle_response(response)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require_relative '../helper'
|
2
|
+
require_relative '../../lib/CoinMarketCap/V1/Client'
|
3
|
+
|
4
|
+
describe CoinMarketCap::V1::Client do
|
5
|
+
let(:client) {CoinMarketCap::V1::Client.new(api_key: api_key)}
|
6
|
+
|
7
|
+
describe "#airdrop" do
|
8
|
+
it "returns AN airdrop" do
|
9
|
+
VCR.use_cassette('v1/cryptocurrency/airdrop') do
|
10
|
+
assert_raises CoinMarketCap::Error do
|
11
|
+
response = client.airdrop(id: 1)
|
12
|
+
# Too poor to subscribe...
|
13
|
+
# _(response).must_include('data')
|
14
|
+
_(JSON.parse(response.body).dig('status', 'error_message')).must_equal "Your API Key subscription plan doesn't support this endpoint."
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#airdrops" do
|
21
|
+
it "returns ALL airdrops" do
|
22
|
+
VCR.use_cassette('v1/cryptocurrency/airdrops') do
|
23
|
+
assert_raises CoinMarketCap::Error do
|
24
|
+
response = client.airdrops
|
25
|
+
# Still too poor to subscribe...
|
26
|
+
# _(response).must_include('data')
|
27
|
+
_(JSON.parse(response.body).dig('status', 'error_message')).must_equal "Your API Key subscription plan doesn't support this endpoint."
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#categories" do
|
34
|
+
it "returns ALL categories" do
|
35
|
+
VCR.use_cassette('v1/cryptocurrency/categories') do
|
36
|
+
assert_raises CoinMarketCap::Error do
|
37
|
+
response = client.categories
|
38
|
+
# _(response).must_include('data')
|
39
|
+
_(JSON.parse(response.body).dig('status', 'error_message')).must_equal "Your API Key subscription plan doesn't support this endpoint."
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#category" do
|
46
|
+
it "returns a specific category" do
|
47
|
+
VCR.use_cassette('v1/cryptocurrency/category') do
|
48
|
+
assert_raises CoinMarketCap::Error do
|
49
|
+
response = client.category(id: 1)
|
50
|
+
# _(response).must_include('data')
|
51
|
+
_(JSON.parse(response.body).dig('status', 'error_message')).must_equal "Your API Key subscription plan doesn't support this endpoint."
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#listings_historical" do
|
58
|
+
it "returns historical listings for all cryptos" do
|
59
|
+
VCR.use_cassette('v1/cryptocurrency/listings/historical') do
|
60
|
+
assert_raises CoinMarketCap::Error do
|
61
|
+
response = client.listings_historical
|
62
|
+
_(response).must_include('data')
|
63
|
+
_(JSON.parse(response.body).dig('status', 'error_message')).must_equal "Your API Key subscription plan doesn't support this endpoint."
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "#listings_latest" do
|
70
|
+
it "returns an array of latest prices" do
|
71
|
+
VCR.use_cassette('v1/cryptocurrency/listings/latest') do
|
72
|
+
response = client.listings_latest
|
73
|
+
_(response).must_include('data')
|
74
|
+
_(response['data']).must_be_kind_of(Array)
|
75
|
+
_(response['data'][0]).must_be_kind_of(Hash)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "#map" do
|
81
|
+
it "returns a map of crypto IDs to symbols" do
|
82
|
+
VCR.use_cassette('v1/cryptocurrency/map') do
|
83
|
+
response = client.map
|
84
|
+
_(response).must_include('data')
|
85
|
+
_(response['data'].first['symbol']).must_equal 'BTC'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "#trending_gainers_losers" do
|
91
|
+
it "returns trending gainers and losers" do
|
92
|
+
VCR.use_cassette('v1/cryptocurrency/trending/gainers-losers') do
|
93
|
+
assert_raises CoinMarketCap::Error do
|
94
|
+
response = client.trending_gainers_losers
|
95
|
+
# _(response).must_include('data')
|
96
|
+
_(JSON.parse(response.body).dig('status', 'error_message')).must_equal "Your API Key subscription plan doesn't support this endpoint."
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "#trending_latest" do
|
103
|
+
it "returns trending latest" do
|
104
|
+
VCR.use_cassette('v1/cryptocurrency/trending/latest') do
|
105
|
+
assert_raises CoinMarketCap::Error do
|
106
|
+
response = client.trending_latest
|
107
|
+
# _(response).must_include('data')
|
108
|
+
_(JSON.parse(response.body).dig('status', 'error_message')).must_equal "Your API Key subscription plan doesn't support this endpoint."
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "#trending_most_visited" do
|
115
|
+
it "returns trending most visited" do
|
116
|
+
VCR.use_cassette('v1/cryptocurrency/trending/most-visited') do
|
117
|
+
assert_raises CoinMarketCap::Error do
|
118
|
+
response = client.trending_most_visited
|
119
|
+
# _(response).must_include('data')
|
120
|
+
_(JSON.parse(response.body).dig('status', 'error_message')).must_equal "Your API Key subscription plan doesn't support this endpoint."
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "#handle_response" do
|
127
|
+
it "handles a successful response" do
|
128
|
+
raw_response = OpenStruct.new(success?: true, body: '{"data": {}}')
|
129
|
+
response = client.send(:handle_response, raw_response)
|
130
|
+
_(response).must_include('data')
|
131
|
+
_(response).must_be_kind_of(Hash)
|
132
|
+
end
|
133
|
+
|
134
|
+
it "raises an error for a failed response" do
|
135
|
+
raw_response = OpenStruct.new(success?: false, code: 404, message: 'Not Found')
|
136
|
+
assert_raises RuntimeError do
|
137
|
+
client.send(:handle_response, raw_response)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require_relative '../helper'
|
2
|
+
require_relative '../../lib/CoinMarketCap/V2/Client'
|
3
|
+
|
4
|
+
describe CoinMarketCap::V2::Client do
|
5
|
+
let(:client) {CoinMarketCap::V2::Client.new(api_key: api_key)}
|
6
|
+
|
7
|
+
describe "#info" do
|
8
|
+
it "retrieves metadata for a specific cryptocurrency" do
|
9
|
+
VCR.use_cassette('v2/cryptocurrency/info') do
|
10
|
+
response = client.info(id: 1)
|
11
|
+
_(response).must_include('data')
|
12
|
+
_(response.dig('data', '1', 'symbol')).must_equal 'BTC'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#market_pairs_latest" do
|
18
|
+
it "retrieves the latest market pairs" do
|
19
|
+
VCR.use_cassette('v2/cryptocurrency/market-pairs/latest') do
|
20
|
+
assert_raises CoinMarketCap::Error do
|
21
|
+
response = client.market_pairs_latest
|
22
|
+
# _(response).must_include('data')
|
23
|
+
_(JSON.parse(response.body).dig('status', 'error_message')).must_equal "Your API Key subscription plan doesn't support this endpoint."
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#ohlcv_historical" do
|
30
|
+
it "retrieves historical OHLCV data" do
|
31
|
+
VCR.use_cassette('v2/cryptocurrency/ohlcv/historical') do
|
32
|
+
assert_raises CoinMarketCap::Error do
|
33
|
+
response = client.ohlcv_historical(id: 1)
|
34
|
+
# _(response).must_include('data')
|
35
|
+
_(JSON.parse(response.body).dig('status', 'error_message')).must_equal "Your API Key subscription plan doesn't support this endpoint."
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#ohlcv_latest" do
|
42
|
+
it "returns the latest OHLCV data" do
|
43
|
+
VCR.use_cassette('v2/cryptocurrency/ohlcv/latest') do
|
44
|
+
assert_raises CoinMarketCap::Error do
|
45
|
+
response = client.ohlcv_latest
|
46
|
+
# _(response).must_include('data')
|
47
|
+
_(JSON.parse(response.body).dig('status', 'error_message')).must_equal "Your API Key subscription plan doesn't support this endpoint."
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#price_performance_stats_latest" do
|
54
|
+
it "retrieves the latest price performance statistics" do
|
55
|
+
VCR.use_cassette('v2/cryptocurrency/price-performance-stats/latest') do
|
56
|
+
assert_raises CoinMarketCap::Error do
|
57
|
+
response = client.price_performance_stats_latest
|
58
|
+
# _(response).must_include('data')
|
59
|
+
_(JSON.parse(response.body).dig('status', 'error_message')).must_equal "Your API Key subscription plan doesn't support this endpoint."
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#quotes_historical" do
|
66
|
+
it "returns historical quotes" do
|
67
|
+
VCR.use_cassette('v2/cryptocurrency/quotes/historical') do
|
68
|
+
assert_raises CoinMarketCap::Error do
|
69
|
+
response = client.quotes_historical(id: 1)
|
70
|
+
# _(response).must_include('data')
|
71
|
+
_(JSON.parse(response.body).dig('status', 'error_message')).must_equal "Your API Key subscription plan doesn't support this endpoint."
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#quotes_latest" do
|
78
|
+
it "retrieves the latest quotes for a specific cryptocurrency" do
|
79
|
+
VCR.use_cassette('v2/cryptocurrency/quotes/latest') do
|
80
|
+
response = client.quotes_latest(id: 1)
|
81
|
+
_(response).must_include('data')
|
82
|
+
_(response['data']).must_be_kind_of(Hash)
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
it "retrieves quotes for multiple IDs" do
|
88
|
+
VCR.use_cassette('v2/cryptocurrency/quotes/latest_with_multiple_ids') do
|
89
|
+
response = client.quotes_latest(id: [1, 2])
|
90
|
+
_(response).must_include("data")
|
91
|
+
_(response["data"]).must_be_kind_of(Hash)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "#handle_response" do
|
97
|
+
it "handles a successful response" do
|
98
|
+
raw_response = OpenStruct.new(success?: true, body: '{"data": {}}')
|
99
|
+
response = client.send(:handle_response, raw_response)
|
100
|
+
_(response).must_include('data')
|
101
|
+
_(response).must_be_kind_of(Hash)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "raises an error for a failed response" do
|
105
|
+
response = OpenStruct.new(success?: false, code: 404, message: 'Not Found')
|
106
|
+
assert_raises RuntimeError do
|
107
|
+
client.send(:handle_response, response)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
data/test/client_test.rb
ADDED
@@ -0,0 +1,213 @@
|
|
1
|
+
require_relative './helper'
|
2
|
+
require_relative '../lib/CoinMarketCap/Client'
|
3
|
+
|
4
|
+
describe CoinMarketCap::Client do
|
5
|
+
let(:client){CoinMarketCap::Client.new(api_key: api_key)}
|
6
|
+
|
7
|
+
describe "#airdrops" do
|
8
|
+
context "when an id IS provided" do
|
9
|
+
it "calls the V1 client" do
|
10
|
+
mocked_client = Minitest::Mock.new
|
11
|
+
mocked_client.expect(:airdrop, {'data' => []}) do |kwargs|
|
12
|
+
kwargs[:id] == 1
|
13
|
+
end
|
14
|
+
client.stub :v1_client, mocked_client do
|
15
|
+
client.airdrops(id: 1)
|
16
|
+
end
|
17
|
+
mocked_client.verify
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "when an id is NOT provided" do
|
22
|
+
it "calls the V1 client" do
|
23
|
+
mocked_client = Minitest::Mock.new
|
24
|
+
mocked_client.expect :airdrops, true, []
|
25
|
+
client.stub :v1_client, mocked_client do
|
26
|
+
client.airdrops
|
27
|
+
end
|
28
|
+
mocked_client.verify
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#categories" do
|
34
|
+
context "when an id IS provided" do
|
35
|
+
it "calls the V1 client" do
|
36
|
+
mocked_client = Minitest::Mock.new
|
37
|
+
mocked_client.expect(:category, {'data' => []}) do |kwargs|
|
38
|
+
kwargs[:id] == 1
|
39
|
+
end
|
40
|
+
client.stub :v1_client, mocked_client do
|
41
|
+
client.categories(id: 1)
|
42
|
+
end
|
43
|
+
mocked_client.verify
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "when an id is NOT provided" do
|
48
|
+
it "calls the V1 client" do
|
49
|
+
mocked_client = Minitest::Mock.new
|
50
|
+
mocked_client.expect :categories, true, []
|
51
|
+
client.stub :v1_client, mocked_client do
|
52
|
+
client.categories
|
53
|
+
end
|
54
|
+
mocked_client.verify
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#gainers_and_losers" do
|
60
|
+
it "calls the V1 client trending_gainers_losers method" do
|
61
|
+
mocked_client = Minitest::Mock.new
|
62
|
+
mocked_client.expect :trending_gainers_losers, true, []
|
63
|
+
client.stub :v1_client, mocked_client do
|
64
|
+
client.gainers_and_losers
|
65
|
+
end
|
66
|
+
mocked_client.verify
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#historical_price_data" do
|
71
|
+
it "calls the V2 client" do
|
72
|
+
mocked_client = Minitest::Mock.new
|
73
|
+
mocked_client.expect(:ohlcv_historical, {'data' => []}) do |kwargs|
|
74
|
+
kwargs[:id] == 1
|
75
|
+
end
|
76
|
+
client.stub :v2_client, mocked_client do
|
77
|
+
client.historical_price_data(id: 1)
|
78
|
+
end
|
79
|
+
mocked_client.verify
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "#historical_quotes" do
|
84
|
+
context "when an ID IS provided" do
|
85
|
+
it "calls the V2 client" do
|
86
|
+
mocked_client = Minitest::Mock.new
|
87
|
+
mocked_client.expect(:quotes_historical, {'data' => []}) do |kwargs|
|
88
|
+
kwargs[:id] == 1
|
89
|
+
end
|
90
|
+
client.stub :v2_client, mocked_client do
|
91
|
+
client.historical_quotes(id: 1)
|
92
|
+
end
|
93
|
+
mocked_client.verify
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context "when no ID is provided" do
|
98
|
+
it "calls the V1 client" do
|
99
|
+
mocked_client = Minitest::Mock.new
|
100
|
+
mocked_client.expect :listings_historical, {"data" => {}}, []
|
101
|
+
client.stub :v1_client, mocked_client do
|
102
|
+
client.historical_quotes
|
103
|
+
end
|
104
|
+
mocked_client.verify
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe "#info" do
|
110
|
+
it "calls the V2 client" do
|
111
|
+
mocked_client = Minitest::Mock.new
|
112
|
+
mocked_client.expect(:info, {'data' => []}) do |kwargs|
|
113
|
+
kwargs[:id] == 1
|
114
|
+
end
|
115
|
+
client.stub :v2_client, mocked_client do
|
116
|
+
client.info(id: 1)
|
117
|
+
end
|
118
|
+
mocked_client.verify
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe "#map" do
|
123
|
+
it "calls the V1 client" do
|
124
|
+
mocked_client = Minitest::Mock.new
|
125
|
+
mocked_client.expect(:map, {'data' => []})
|
126
|
+
client.stub :v1_client, mocked_client do
|
127
|
+
client.map
|
128
|
+
end
|
129
|
+
mocked_client.verify
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe "#latest_listings" do
|
134
|
+
it "calls the V2 client" do
|
135
|
+
mocked_client = Minitest::Mock.new
|
136
|
+
mocked_client.expect(:market_pairs_latest, true, [])
|
137
|
+
client.stub :v2_client, mocked_client do
|
138
|
+
client.latest_listings
|
139
|
+
end
|
140
|
+
mocked_client.verify
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe "#latest_price_data" do
|
145
|
+
it "calls the V2 client" do
|
146
|
+
mocked_client = Minitest::Mock.new
|
147
|
+
mocked_client.expect(:ohlcv_latest, true, [])
|
148
|
+
client.stub :v2_client, mocked_client do
|
149
|
+
client.latest_price_data
|
150
|
+
end
|
151
|
+
mocked_client.verify
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
describe "#latest_price_performance_stats" do
|
156
|
+
it "calls the V2 client" do
|
157
|
+
mocked_client = Minitest::Mock.new
|
158
|
+
mocked_client.expect(:price_performance_stats_latest, true, [])
|
159
|
+
client.stub :v2_client, mocked_client do
|
160
|
+
client.latest_price_performance_stats
|
161
|
+
end
|
162
|
+
mocked_client.verify
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
describe "#latest_quotes" do
|
167
|
+
context "when an ID IS provided" do
|
168
|
+
it "calls the V2 client" do
|
169
|
+
mocked_client = Minitest::Mock.new
|
170
|
+
mocked_client.expect(:quotes_latest, {'data' => []}) do |kwargs|
|
171
|
+
kwargs[:id] == 1
|
172
|
+
end
|
173
|
+
client.stub :v2_client, mocked_client do
|
174
|
+
client.latest_quotes(id: 1)
|
175
|
+
end
|
176
|
+
mocked_client.verify
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context "when an ID is NOT provided" do
|
181
|
+
it "calls the V1 client" do
|
182
|
+
mocked_client = Minitest::Mock.new
|
183
|
+
mocked_client.expect(:listings_latest, true, [])
|
184
|
+
client.stub :v1_client, mocked_client do
|
185
|
+
client.latest_quotes
|
186
|
+
end
|
187
|
+
mocked_client.verify
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
describe "#most_visited" do
|
193
|
+
it "calls the V1 client trending_most_visited method" do
|
194
|
+
mocked_client = Minitest::Mock.new
|
195
|
+
mocked_client.expect :trending_most_visited, true, []
|
196
|
+
client.stub :v1_client, mocked_client do
|
197
|
+
client.most_visited
|
198
|
+
end
|
199
|
+
mocked_client.verify
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
describe "#trending" do
|
204
|
+
it "calls the V1 client trending_latest method" do
|
205
|
+
mocked_client = Minitest::Mock.new
|
206
|
+
mocked_client.expect :trending_latest, true, []
|
207
|
+
client.stub :v1_client, mocked_client do
|
208
|
+
client.trending
|
209
|
+
end
|
210
|
+
mocked_client.verify
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'minitest-spec-context'
|
3
|
+
require 'minitest/spec'
|
4
|
+
require 'ostruct'
|
5
|
+
require 'vcr'
|
6
|
+
|
7
|
+
VCR.configure do |config|
|
8
|
+
config.cassette_library_dir = File.expand_path('../fixtures/vcr_cassettes', __FILE__)
|
9
|
+
config.hook_into :webmock
|
10
|
+
end
|
11
|
+
|
12
|
+
def api_key
|
13
|
+
if ENV['COINMARKETCAP_API_KEY']
|
14
|
+
ENV['COINMARKETCAP_API_KEY']
|
15
|
+
else
|
16
|
+
'api_key0'
|
17
|
+
end
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: coinmarketcap.rb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- thoran
|
8
|
+
bindir: bin
|
9
|
+
cert_chain: []
|
10
|
+
date: 2025-03-30 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 coinmarketcap.com API with Ruby.
|
27
|
+
email: code@thoran.com
|
28
|
+
executables: []
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- Gemfile
|
33
|
+
- README.md
|
34
|
+
- coinmarketcap.rb.gemspec
|
35
|
+
- lib/CoinMarketCap.rb
|
36
|
+
- lib/CoinMarketCap/Client.rb
|
37
|
+
- lib/CoinMarketCap/Common.rb
|
38
|
+
- lib/CoinMarketCap/V1/Client.rb
|
39
|
+
- lib/CoinMarketCap/V2/Client.rb
|
40
|
+
- lib/CoinMarketCap/VERSION.rb
|
41
|
+
- test/V1/client_test.rb
|
42
|
+
- test/V2/client_test.rb
|
43
|
+
- test/client_test.rb
|
44
|
+
- test/helper.rb
|
45
|
+
homepage: http://github.com/thoran/coinmarketcap.rb
|
46
|
+
licenses:
|
47
|
+
- Ruby
|
48
|
+
metadata: {}
|
49
|
+
rdoc_options: []
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '2.7'
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
requirements: []
|
63
|
+
rubygems_version: 3.6.6
|
64
|
+
specification_version: 4
|
65
|
+
summary: Access the coinmarketcap.com API with Ruby.
|
66
|
+
test_files: []
|