ctfc 0.4.2 → 1.0.0.alpha

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 409d75b59775b440b646f56056d957339253c550befff121d954373b4e26634f
4
- data.tar.gz: 5c11ef13d7da7fb6dcfac08b0985620d9104100db0851a3760066d08b261d84b
3
+ metadata.gz: f2aa46b7e28383d2845d81ddeed7173ac7423e6e960dea6ffb4f37ba5e536969
4
+ data.tar.gz: 86ecfff9bb989a17054570ce600ea70e35c71fb1b01ce34e32265c010efa6e44
5
5
  SHA512:
6
- metadata.gz: 2a6011b38fb81898fae7a59d54e512104b7e8bee9f15d38d5f716d6680a62bf07e6beb6d67615c4486bb971f2ac8db8c9652ceb7f0328145f484e36e6ee362ea
7
- data.tar.gz: c2cecff14b934c6cfb467933528329be3ad79ed5e5a5205a4448e587d7d2f1a185e6c10e24d858dc6f76b2e019a9242f8d7d6e13a516d71535f0819b6ce540e6
6
+ metadata.gz: cacd0718b90b741a18ddf4199b9ceb23a49fcf63505e741c2c55c40183b0ae40979192b2e875046424db9a0dccee2df04ce8e9973a0be6b90236d395297fd2b3
7
+ data.tar.gz: 12c0ae246495fde8927693ee626d198268d1686483d4ed2e02494c35230511537b3e41030b92eae25278d6b709a12e2ba3e80fe38ab7f2322342850d93635441
data/README.md CHANGED
@@ -1,177 +1 @@
1
- [**NOTE:**](https://www.github.com/alx3dev/ctfc/LICENSE_DEPENDENCIES.md)
2
- >Removed gem `colorize` to allow **MIT** license.
3
- >All comits from `v-0.4.0` must be signed and tagged **verified**.
4
-
5
-
6
- # About
7
- Convert any crypto to fiat currency, gather all data and/or save in `.csv` table.
8
- For now only prices are printed/saved, while all data remain easily accessible from variable (for developers).
9
-
10
-
11
- # How to install
12
- Make sure you have ruby and git installed
13
-
14
- Install from source:
15
- ```bash
16
- git clone https://github.com/alx3dev/ctfc.git
17
- cd ctfc && bundle install
18
- ```
19
-
20
- Install from rubygems:
21
-
22
- ```bash
23
- gem install ctfc
24
- ```
25
- # How to run
26
- - **Read documentation on:** https://rubydoc.info/gems/ctfc/CTFC/Data
27
-
28
- ```bash
29
- ruby bin/ctfc fiat_1 fiat_2 fiat_3
30
- ```
31
-
32
- This command also accept multiple arguments:
33
-
34
- - `--no-save` - do not save `.csv.` output
35
- - `--no-print` - do not print terminal output
36
- - `--coins` - coins to scrap (default: BTC, LTC, XMR, ETH, BCH, ZEC )
37
- - `--loop` - repeat script N times (default 1)
38
- - `--wait` - wait N seconds between loops (default 0)
39
- - `--help` - help menu
40
-
41
-
42
- # Script Examples
43
- 1 - Run script without arguments (default options)
44
-
45
- ```ruby
46
- ruby bin/ctfc
47
-
48
- => return:
49
- print EUR rates for default coins (BTC, LTC, XMR, ETH, BCH, ZEC)
50
- do not save '.csv' table
51
- ```
52
-
53
-
54
- 2 - Add fiat currencies as arguments
55
-
56
- ```ruby
57
- ruby bin/ctfc eur usd rsd
58
-
59
- => return:
60
- print EUR, USD, RSD rates for default coins
61
- save data in '.csv' table with pattern: 'crypto_#{CURRENCY}.csv'
62
- -> './crypto_eur.csv', './crypto_usd.csv', './crypto_rsd.csv'
63
- ```
64
-
65
- 3 - Use `--no-save`, `--no-print`, `--loop`, `--wait`
66
-
67
- ```ruby
68
- ruby bin/ctfc eur --no-print --coins btc xmr ltc
69
-
70
- => return:
71
- save EUR rates for BTC, XMR and LTC
72
- do not print output
73
-
74
-
75
- ruby bin/ctfc rsd --no-save --coins btc xmr
76
-
77
- => return:
78
- print RSD rates for BTC and XMR
79
-
80
-
81
- # added in version 0.4.0
82
- ruby bin/ctfc rsd --no-print --loop 1440 --wait 60
83
-
84
- => return:
85
- save RSD rates without print, run each minute for 24 hours
86
- ```
87
-
88
-
89
- # Developer Examples
90
- ```ruby
91
- # define coins to scrap
92
- COINS = %w[ BTC XMR LTC ETH ]
93
-
94
- # initialize Data class
95
- @data = Ctfc.new :eur, save: false, print: false, coins: COINS
96
- => return Ctfc object to work with
97
- -> #<Ctfc:0x000055b5c8b61a38 @coins=["BTC", "LTC", "XMR", "ETH", "BCH", "ZEC"], @fiat="EUR", @print=true, @save=true>
98
-
99
- # execute request
100
- @data.get
101
- => return Hash with upcase string coins as keys, and float prices
102
- -> {"BTC"=>36760.11, "XMR"=>169.55, "LTC"=>114.4, "ETH"=>2746.22}
103
-
104
- # now you can use ::Data instance methods
105
- @data.response
106
- => return RestClient response to cryptocomare API
107
- -> <RestClient::Response 200 "{\"RAW\":{\"BT...">
108
-
109
- # check request url
110
- @data.url
111
- => return Cryptocompare API url
112
- -> "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=BTC&fsyms=LTC&fsyms=XMR&fsyms=ETH&fsyms=BCH&fsyms=ZEC&tsyms=EUR"
113
-
114
- # name of csv table (saved in working directory)
115
- @data.table
116
- => return '.csv' table name
117
- -> 'ctfc_eur.csv'
118
-
119
- # array of coins to work with
120
- @data.coins
121
- => return coins for scrap, also allow setter method @data.coins = [...]
122
- -> ['BTC', 'XMR', 'LTC', 'ETH']
123
-
124
- # get all data about all coins (json api response)
125
- @data.data
126
- => return all data returned by cryptocompare API
127
- -> {"RAW"=>
128
- {"BTC"=>
129
- {"EUR"=>
130
- {"TYPE"=>"5",
131
- "MARKET"=>"CCCAGG",
132
- "FROMSYMBOL"=>"BTC",
133
- "TOSYMBOL"=>"EUR",
134
- "FLAGS"=>"2049",
135
- "PRICE"=>33851.17,
136
- "LASTUPDATE"=>1642773847,
137
- "MEDIAN"=>33853.8,
138
- "LASTVOLUME"=>0.1,
139
- "LASTVOLUMETO"=>3384.3676,
140
- "LASTTRADEID"=>"2024043",
141
- ... ... ... ... ... ... ...
142
-
143
-
144
- TO BE CONTINIUED ...
145
- ```
146
-
147
- **Class methods as shortcuts:**
148
-
149
- ```ruby
150
- # get default coins in EUR, save output without printing
151
- prices = Ctfc.to :eur, print: false
152
-
153
- # get default coins in RSD, print output, don't save
154
- Ctfc.to :rsd, save: false
155
-
156
- # For those who don't like name `Ctfc`, you can use `Crypto` too:
157
- prices = Crypto.to :eur, coins: %w[BTC XMR]
158
- ```
159
-
160
- # Tests
161
- To run tests use `./check-syntax.sh`.
162
- This command will run rubocop for code inspection, but with some errors hidden by `.rubocop_todo.yml`. Using check-syntax script, all test should pass.
163
-
164
-
165
- # Contribution
166
- Any contribution is highly appreciated, as long as you follow Code of Conduct.
167
-
168
- - Fork repository
169
- - Make your changes
170
- - Write tests
171
- - Submit pull request
172
-
173
- # License
174
- Don't be a dick - it's MIT.
175
-
176
- # To-Do:
177
- See **Projects**
1
+ This is development branch, testing code before merge.
data/bin/ctfc CHANGED
@@ -1,12 +1,14 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require_relative '../lib/ctfc'
5
4
  require 'optimist'
5
+ require_relative '../lib/ctfc'
6
+ require_relative '../lib/ctfc/helpers/cli'
7
+
8
+ COINS = %w[BTC XMR ETH LTC].freeze
6
9
 
7
10
  opts = Optimist.options do
8
- version "Crypto To Fiat Currency\n".cyan.bold \
9
- + "Gem Version: #{CTFC::VERSION}"
11
+ version "Crypto To Fiat Currency\nGem Version: #{CTFC::VERSION}"
10
12
 
11
13
  banner ''
12
14
  banner ' Enter fiat currencies with/out additional arguments:'
@@ -15,42 +17,38 @@ opts = Optimist.options do
15
17
  banner ' ruby bin/ctfc eur usd --no-save --coins btc xmr ltc'
16
18
  banner ''
17
19
 
18
- opt :coins, 'Set crypto coins', default: CTFC::CONFIG::COINS
19
- opt :no_save, "Do not save '.csv' output"
20
- opt :no_print, 'Do not print terminal output'
21
- opt :loop, 'Run script N times', default: 1, type: :integer
22
- opt :wait, 'Wait N seconds between loop', default: 0, type: :integer
20
+ opt :coins, 'Set crypto coins', default: COINS
21
+ opt :save, "Save prices in '.csv' table", default: false
22
+ opt :export, "Export all data in '.json' file", default: false
23
+ opt :no_print, 'Do not print terminal output', default: false
24
+ opt :source, 'Set source to extract data', default: 'cryptocompare'
25
+ opt :loop, 'Run script N times', default: 1, type: :integer
26
+ opt :wait, 'Wait N seconds between loop', default: 0, type: :integer
23
27
  end
24
28
 
25
- save = opts[:no_save] ? false : true
26
- print = opts[:no_print] ? false : true
27
-
28
- @crypto = Ctfc.new
29
+ coins = opts[:coins]
30
+ source = opts[:source]
31
+ save = opts[:save]
32
+ export = opts[:export]
33
+ print = true unless opts[:no_print]
29
34
 
30
35
  if ARGV.empty?
31
-
32
- @crypto.get(:eur, save: false)
33
-
36
+ prices = Crypto.to :usd, coins, source.to_sym, save: save, export: export
37
+ Cli.print_output :USD, prices if print
34
38
  else
35
-
36
39
  opts[:loop].times do
37
40
  ARGV.each do |fiat|
38
41
  next if opts.include?(fiat.downcase)
39
42
 
40
- @crypto.get(fiat,
41
- save: save,
42
- print: print,
43
- coins: opts.coins)
44
- sleep 1 # wait between requests
43
+ prices = Crypto.to fiat, coins, source.to_sym, save: save, export: export
44
+ next unless print
45
+
46
+ system 'clear' or system 'cls'
47
+ Cli.print_output fiat, prices
45
48
  end
46
49
 
47
- # end if no `--loop` arg
48
50
  next unless opts[:loop] > 1
49
51
 
50
- # pause between loops
51
52
  sleep opts[:wait]
52
-
53
- # clear screan - depending on OS
54
- system 'clear' or system 'cls'
55
53
  end
56
54
  end
data/ctfc.gemspec CHANGED
@@ -1,14 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative './lib/ctfc/version'
4
+ require_relative './lib/ctfc/helpers/list'
4
5
 
5
6
  Gem::Specification.new do |s|
6
7
  s.name = 'ctfc'
7
8
  s.version = CTFC::VERSION
8
- s.summary = 'Cryptocurrency to Fiat values, get data and save prices.'
9
+ s.summary = 'Cryptocurrency data gathering gem. Scrap and save as CSV and/or JSON.'
9
10
  s.description = <<~DESCRIPTION
10
- Convert any cryptocurrency to any fiat value, export data to csv table.
11
- Print colorized terminal output.
11
+ == DEVELOPMENT VERSION==
12
+ Cryptocurrency data gathering gem. Get data from multiple APIs, print and
13
+ save output as you wish. Run script from terminal, or use in another app.
14
+ Class-template based, easy to extend to add more sources. MIT License.
12
15
  DESCRIPTION
13
16
 
14
17
  s.license = 'MIT'
@@ -22,27 +25,34 @@ Gem::Specification.new do |s|
22
25
  s.metadata['homepage_uri'] = 'https://github.com/alx3dev/ctfc'
23
26
  s.metadata['source_code_uri'] = 'https://github.com/alx3dev/ctfc'
24
27
  s.metadata['bug_tracker_uri'] = 'https://github.com/alx3dev/ctfc/issues'
25
- s.metadata['documentation_uri'] = "https://rubydoc.info/gems/#{s.name}"
28
+ s.metadata['changelog_uri'] = 'https://github.com/alx3dev/ctfc/CHANGELOG.md'
29
+ s.metadata['documentation_uri'] = "https://rubydoc.info/gems/#{s.name}/#{s.version}"
30
+ s.metadata['license_uri'] = 'https://github.com/alx3dev/ctfc/LICENSE'
26
31
  s.metadata['rubygems_mfa_required'] = 'true'
27
32
 
28
- s.files = %w[ bin/ctfc
29
- bin/console
30
- lib/ctfc.rb
33
+ s.files = %w[ lib/ctfc.rb
34
+ lib/ctfc/client.rb
35
+ lib/ctfc/export.rb
31
36
  lib/ctfc/version.rb
32
- lib/ctfc/base.rb
33
- lib/ctfc/config.rb
37
+ lib/ctfc/api.rb
38
+ lib/ctfc/api/apitemplate.rb
34
39
  LICENSE
35
40
  README.md
36
41
  ctfc.gemspec]
37
42
 
38
- s.required_ruby_version = '>= 3.0.1'
43
+ # auto-add sources in api dir
44
+ List.source_files.select do |source|
45
+ file = "lib/ctfc/api/#{source}"
46
+ s.files += [file]
47
+ end
39
48
 
49
+ s.required_ruby_version = '> 2.7', '< 3.2'
50
+
51
+ s.add_runtime_dependency 'kolorit', '~> 0.2'
40
52
  s.add_runtime_dependency 'optimist', '~> 3.0.1'
41
53
  s.add_runtime_dependency 'rest-client', '~> 2.1.0'
42
- s.add_runtime_dependency 'kolorit', '~> 0.1.3'
43
54
 
44
- s.add_development_dependency 'bundler', '~> 2.2.9'
45
- s.add_development_dependency 'pry', '~> 0.14.1'
46
- s.add_development_dependency 'rake', '~> 13.0.3'
47
- s.add_development_dependency 'rspec', '~> 3.10.0'
55
+ s.add_development_dependency 'bundler', '~> 2.3'
56
+ s.add_development_dependency 'pry', '~> 0.14'
57
+ s.add_development_dependency 'rake', '~> 13.0'
48
58
  end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rest-client'
4
+ require 'json'
5
+
6
+ module CTFC
7
+ module API
8
+ # Template for other sources. Every file in api dir should extend this class.
9
+ # Automatically call method #process to send api request after initialization.
10
+ # This mean every source should include method #process, that will be executed
11
+ # after initialization.
12
+ #
13
+ # @see CTFC::API
14
+ # @see CTFC::API::Cryptocompare
15
+ #
16
+ class ApiTemplate
17
+ attr_reader :response
18
+
19
+ # max number of requests to send
20
+ MAX_RETRY = 3
21
+
22
+ # Construct response hash from given arguments, and start counting requests.
23
+ # Call private method #process to extract data from web.
24
+ #
25
+ # @example Send request to cryptocompare
26
+ # crypto = Cryptocompare.new :eur, %w[BTC XMR]
27
+ #
28
+ # @param [Symbol] fiat **Required**. Fiat currency to use for conversion.
29
+ # @param [Array] coins **Required**. Array of coins to extract data.
30
+ #
31
+ # @return [Object] Source instance.
32
+ #
33
+ def initialize(fiat, coins)
34
+ @response = { fiat: fiat, coins: coins, success: false }
35
+ @counter = 0
36
+ process
37
+ end
38
+
39
+ # Initialize new instance, send request and return response hash.
40
+ # @example
41
+ # Cryptocompare[:eur, %w[BTC XMR]]
42
+ #
43
+ # @param [Symbol] fiat **Required**. Fiat currency.
44
+ # @param [Array] coins **Required**. Cryptocurrency coins.
45
+ #
46
+ # @return [Hash] Response hash object.
47
+ #
48
+ def self.[](fiat, coins)
49
+ new(fiat, coins).response
50
+ end
51
+
52
+ private
53
+
54
+ def process
55
+ return false unless response[:fiat] && response[:coins]
56
+ end
57
+
58
+ def success!(set: true)
59
+ @counter = 0 if set == true
60
+ @response[:success] = set
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'apitemplate' unless defined? CTFC::API::ApiTemplate
4
+
5
+ module CTFC
6
+ module API
7
+ # Source file for cryptocompare api.
8
+ # Initialize will automatically call #process,
9
+ # to send request after all attributes and variables are configured.
10
+ #
11
+ # @see CTFC::API::ApiTemplate
12
+ #
13
+ class Cryptocompare < ApiTemplate
14
+ # Cryptocompare API base url, where we add coins and fiat currency.
15
+ BASE_URL = 'https://min-api.cryptocompare.com/data/pricemultifull?'
16
+
17
+ private
18
+
19
+ def process
20
+ super
21
+ uri = ''
22
+ response[:coins].collect do |coin|
23
+ uri += "fsyms=#{coin}&" unless uri.include? coin
24
+ end
25
+ uri += "tsyms=#{response[:fiat]}"
26
+ @response[:uri] = BASE_URL + uri
27
+ do_rest_request
28
+ end
29
+
30
+ def do_rest_request(time = Time.now)
31
+ rest = RestClient.get(response[:uri])
32
+ success! if rest.code == 200
33
+ process_json_data JSON.parse(rest), time
34
+ rescue StandardError => e
35
+ success! set: false
36
+ if (@counter += 1) > MAX_RETRY
37
+ puts e.message
38
+ else
39
+ retry
40
+ end
41
+ end
42
+
43
+ def process_json_data(data, time)
44
+ fiat = response[:fiat]
45
+ prices = {}
46
+ response[:coins].each do |coin|
47
+ value = data['RAW'][coin.upcase][fiat.to_s.upcase]['PRICE'].round(2)
48
+ prices[coin] = value
49
+ end
50
+ @response.merge!(time: time.to_s, prices: prices, data: data)
51
+ end
52
+ end
53
+ end
54
+ end
data/lib/ctfc/api.rb ADDED
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Benchmark say it's faster to use **unless defined?** if we require file
4
+ # on multiple locations
5
+
6
+ require_relative 'api/apitemplate' unless defined? CTFC::API::ApiTemplate
7
+ require_relative 'helpers/list' unless defined? List
8
+
9
+ # automatically require new apis
10
+ List.sources.select { |source| require_relative "api/#{source}" }
11
+
12
+ module CTFC
13
+ #
14
+ # Keep sources to extract data. Each source has to be a class,
15
+ # named as API domain, extending ApiTemplate. This will automatically
16
+ # make it available in Client, but also added to .gemspec.
17
+ #
18
+ # @see CTFC::API::ApiTemplate
19
+ # @see CTFC::API::Cryptocompare
20
+ #
21
+ # @example Add a new source to extract data:
22
+ # # make file new_source.rb
23
+ # class NewSource < ApiTemplate
24
+ #
25
+ # private
26
+ #
27
+ # def process
28
+ # # check response hash for persistence of fiat and coins
29
+ # super
30
+ # # write method to scrap data from NewSource
31
+ # end
32
+ # end
33
+ #
34
+ module API
35
+ end
36
+ end
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'api'
4
+ require_relative 'export'
5
+
6
+ module CTFC
7
+ #
8
+ # Client allow us to get data from our sources, and to
9
+ # manipulate with that data. While other classes are mostly
10
+ # used by each-other, Client is mostly used directly by user.
11
+ #
12
+ class Client
13
+ attr_reader :config, :response, :prices
14
+
15
+ #
16
+ # Choose fiat currency, coins and source for new client.
17
+ # @example Initialize new **EUR** client
18
+ # client = CTFC::Client.new :eur, %w[BTC XMR LTC ETH]
19
+ #
20
+ # @param [Symbol] currency **Required**. Set fiat currency.
21
+ # @param [Array] coins **Required**. Set crypto coins.
22
+ # @param [Symbol] source Optional. Source for data extraction.
23
+ # @param [Hash] opts Options hash for additional configuration.
24
+ #
25
+ # @option opts [Symbol] source Set source to extract data.
26
+ # @option opts [Boolean] save Set option to save prices in csv table.
27
+ # @option opts [Boolean] export Set option to export all data in json file.
28
+ #
29
+ # @return [Client] Client instance.
30
+ #
31
+ def initialize(fiat, coins, source = nil, opts = {})
32
+ @config = {
33
+ fiat: fiat,
34
+ coins: coins,
35
+ source: source || opts[:source],
36
+ save: [nil, true].include?(opts[:save]),
37
+ export: opts[:export].is_a?(TrueClass)
38
+ }
39
+ end
40
+
41
+ # Scrap data from source.
42
+ # @example
43
+ # client.get :cryptocompare
44
+ #
45
+ # @param [Symbol] source Source to send api request
46
+ # @return [Hash] Hash of fiat values for scrapped coins
47
+ #
48
+ def get(source = nil)
49
+ source ||= config[:source]
50
+ send_api_request(source)
51
+ if success?
52
+ Export.to_csv(source, response) if save?
53
+ Export.to_json(source, response) if export?
54
+ end
55
+ @prices = response[:prices]
56
+ end
57
+
58
+ # Source for data extraction.
59
+ # @return [Symbol]
60
+ #
61
+ def source
62
+ config[:source]
63
+ end
64
+
65
+ # Set source for data extraction.
66
+ # @return [Symbol]
67
+ #
68
+ def source=(param)
69
+ @config[:source] = param
70
+ end
71
+
72
+ # Check if csv output will be saved after request.
73
+ # @return [Boolean]
74
+ #
75
+ def save?
76
+ config[:save].is_a?(TrueClass)
77
+ end
78
+
79
+ # Change option to save prices in csv table after request.
80
+ # @return [Boolean]
81
+ #
82
+ def save=(opt)
83
+ @config[:save] = opt.is_a?(TrueClass)
84
+ end
85
+
86
+ # Check if json output will be exported after request.
87
+ # @return [Boolean]
88
+ #
89
+ def export?
90
+ config[:export].is_a?(TrueClass)
91
+ end
92
+
93
+ # Change option to export all data in json file after request.
94
+ # @return [Boolean]
95
+ #
96
+ def export=(opt)
97
+ @config[:export] = opt.is_a?(TrueClass)
98
+ end
99
+
100
+ # Get fiat value from response hash with crypto prices
101
+ # @example
102
+ # client.price(:btc)
103
+ #
104
+ # @param [Symbol] coin **Required**. Coin name as symbol.
105
+ # @return [Float]
106
+ #
107
+ def price(coin)
108
+ prices[coin.to_s.upcase]
109
+ end
110
+
111
+ # Check if request was successful.
112
+ #
113
+ def success?
114
+ return false if response.nil?
115
+
116
+ response[:success].is_a?(TrueClass)
117
+ end
118
+
119
+ private
120
+
121
+ def send_api_request(source)
122
+ # automatically add new sources to the client, but be careful with eval.
123
+ if List.sources.include? source
124
+ klass = check_source_name source
125
+
126
+ @response =
127
+ instance_eval "CTFC::API::#{klass}[ config[:fiat], config[:coins] ]"\
128
+ '# CTFC::API::Cryptocompare[fiat, coins]', __FILE__, __LINE__ - 1
129
+ else
130
+ message = 'Add source to extract data' if source.nil?
131
+ message = "#{source} not included in API list" if source
132
+ raise ArgumentError, message
133
+ end
134
+ end
135
+
136
+ # Check for underscore and capitalize each word.
137
+ #
138
+ def check_source_name(source)
139
+ if source.to_s.include? '_'
140
+ source.split('_').select(&:capitalize!).join
141
+ else
142
+ source.to_s.capitalize
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'csv'
4
+
5
+ # Keep methods to export data as csv or json.
6
+ # JSON extract all data, while CSV only prices.
7
+ #
8
+ module Export
9
+ class << self
10
+ #
11
+ # Save crypto prices in csv table.
12
+ #
13
+ def to_csv(source, response = {})
14
+ table = "ctfc_#{response[:fiat]}_#{source}.csv"
15
+ coins = response[:coins]
16
+ data_row = price_array_from response
17
+ create_csv_headers(table, coins) unless File.exist?(table)
18
+ CSV.open(table, 'ab') { |column| column << data_row }
19
+ end
20
+
21
+ # Extract all data in json file.
22
+ #
23
+ def to_json(source, response = {})
24
+ table = "ctfc_#{response[:fiat]}_#{source}.json"
25
+ File.open(table, 'ab') do |append|
26
+ append.puts JSON.pretty_generate response
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def create_csv_headers(table, coins)
33
+ header_array = ['TIME']
34
+ coins.each { |coin| header_array << coin }
35
+ CSV.open(table, 'w') { |header| header << header_array }
36
+ end
37
+
38
+ def price_array_from(response = {})
39
+ price_array = [response[:time]]
40
+ response[:prices].each do |_coin, price|
41
+ price_array << price
42
+ end
43
+ price_array
44
+ end
45
+ end
46
+ end
data/lib/ctfc/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  module CTFC
4
4
  # gem version
5
- VERSION = '0.4.2'
5
+ VERSION = '1.0.0.alpha'
6
6
  end
data/lib/ctfc.rb CHANGED
@@ -1,49 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'ctfc/base'
3
+ require_relative 'ctfc/client'
4
+ require_relative 'ctfc/version'
4
5
 
5
- ##
6
- # For easier job use Ctfc, instead of typing CTFC::Data.
7
- # You can define default coins with Ctfc::COINS=
8
- #
9
- # @note For instance methods look at CTFC::Data.
10
- #
11
- class Ctfc < CTFC::Data
12
- ##
13
- # @todo Allow Ctfc to use proxy and/or tor
14
- #
15
- def initialize(currency = :eur, opts = {})
16
- opts[:coins] ||= COINS
17
- super(currency, opts)
18
- end
19
-
20
- ##
21
- # @example Get EUR data for BTC, XMR, LTC, ETH, print but don't save output
22
- #
23
- # Ctfc.to :eur, save: false, coins: %w[BTC XMR LTC ETH]
24
- #
25
- # @param [Symbol] currency **Required**. Define fiat currency.
26
- # @param [Hash] opts **Optional**. Additional options hash.
27
- #
28
- # @option opts [Boolean] print **Optional**. Print terminal output.
29
- # @option opts [Boolean] save **Optional**. Save `.csv` output.
30
- # @option opts [Array] coins **Optional**. Define coins to scrap.
31
- #
32
- # @return [Hash] CTFC::Data#prices || CTFC::Data#response
33
- #
34
- def self.to(currency, opts = {})
35
- new(currency.to_sym, opts).get
36
- end
6
+ # Ctfc is shortcut for CTFC::Client.
7
+ # @see CTFC::Client
8
+ class Ctfc < CTFC::Client
37
9
  end
38
10
 
39
- ##
40
- # Same as Ctfc
41
- # @see Ctfc
42
- # @see CTFC::Data
11
+ # Shortcut to initialize new client,
12
+ # and get prices hash.
13
+ #
14
+ # @example Get EUR prices for coins:
15
+ # coins = %w[BTC XMR LTC ETH]
16
+ # Crypto.to :eur, coins, :cryptocompare, save: true
43
17
  #
44
- class Crypto < Ctfc
45
- def initialize(currency = :eur, opts = {})
46
- opts[:coins] ||= COINS
47
- super(currency, opts)
18
+ class Crypto
19
+ # @return [Hash]
20
+ # @see CTFC::Client
21
+ def self.to(*args)
22
+ CTFC::Client.new(*args).get
48
23
  end
49
24
  end
metadata CHANGED
@@ -1,116 +1,104 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ctfc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 1.0.0.alpha
5
5
  platform: ruby
6
6
  authors:
7
7
  - alx3dev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-25 00:00:00.000000000 Z
11
+ date: 2022-02-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: optimist
14
+ name: kolorit
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 3.0.1
19
+ version: '0.2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 3.0.1
26
+ version: '0.2'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rest-client
28
+ name: optimist
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 2.1.0
33
+ version: 3.0.1
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 2.1.0
40
+ version: 3.0.1
41
41
  - !ruby/object:Gem::Dependency
42
- name: kolorit
42
+ name: rest-client
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 0.1.3
47
+ version: 2.1.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.1.3
54
+ version: 2.1.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 2.2.9
61
+ version: '2.3'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 2.2.9
68
+ version: '2.3'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: pry
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 0.14.1
75
+ version: '0.14'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 0.14.1
82
+ version: '0.14'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rake
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 13.0.3
89
+ version: '13.0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 13.0.3
97
- - !ruby/object:Gem::Dependency
98
- name: rspec
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: 3.10.0
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: 3.10.0
96
+ version: '13.0'
111
97
  description: |
112
- Convert any cryptocurrency to any fiat value, export data to csv table.
113
- Print colorized terminal output.
98
+ == DEVELOPMENT VERSION==
99
+ Cryptocurrency data gathering gem. Get data from multiple APIs, print and
100
+ save output as you wish. Run script from terminal, or use in another app.
101
+ Class-template based, easy to extend to add more sources. MIT License.
114
102
  email:
115
103
  executables:
116
104
  - ctfc
@@ -119,12 +107,14 @@ extra_rdoc_files: []
119
107
  files:
120
108
  - LICENSE
121
109
  - README.md
122
- - bin/console
123
110
  - bin/ctfc
124
111
  - ctfc.gemspec
125
112
  - lib/ctfc.rb
126
- - lib/ctfc/base.rb
127
- - lib/ctfc/config.rb
113
+ - lib/ctfc/api.rb
114
+ - lib/ctfc/api/apitemplate.rb
115
+ - lib/ctfc/api/cryptocompare.rb
116
+ - lib/ctfc/client.rb
117
+ - lib/ctfc/export.rb
128
118
  - lib/ctfc/version.rb
129
119
  homepage: https://github.com/alx3dev/ctfc
130
120
  licenses:
@@ -133,7 +123,9 @@ metadata:
133
123
  homepage_uri: https://github.com/alx3dev/ctfc
134
124
  source_code_uri: https://github.com/alx3dev/ctfc
135
125
  bug_tracker_uri: https://github.com/alx3dev/ctfc/issues
136
- documentation_uri: https://rubydoc.info/gems/ctfc
126
+ changelog_uri: https://github.com/alx3dev/ctfc/CHANGELOG.md
127
+ documentation_uri: https://rubydoc.info/gems/ctfc/1.0.0.alpha
128
+ license_uri: https://github.com/alx3dev/ctfc/LICENSE
137
129
  rubygems_mfa_required: 'true'
138
130
  post_install_message:
139
131
  rdoc_options: []
@@ -141,17 +133,20 @@ require_paths:
141
133
  - lib
142
134
  required_ruby_version: !ruby/object:Gem::Requirement
143
135
  requirements:
144
- - - ">="
136
+ - - ">"
137
+ - !ruby/object:Gem::Version
138
+ version: '2.7'
139
+ - - "<"
145
140
  - !ruby/object:Gem::Version
146
- version: 3.0.1
141
+ version: '3.2'
147
142
  required_rubygems_version: !ruby/object:Gem::Requirement
148
143
  requirements:
149
- - - ">="
144
+ - - ">"
150
145
  - !ruby/object:Gem::Version
151
- version: '0'
146
+ version: 1.3.1
152
147
  requirements: []
153
- rubygems_version: 3.2.32
148
+ rubygems_version: 3.3.6
154
149
  signing_key:
155
150
  specification_version: 4
156
- summary: Cryptocurrency to Fiat values, get data and save prices.
151
+ summary: Cryptocurrency data gathering gem. Scrap and save as CSV and/or JSON.
157
152
  test_files: []
data/bin/console DELETED
@@ -1,9 +0,0 @@
1
- #/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require 'pry'
5
- require 'bundler/setup'
6
-
7
- require_relative '../lib/ctfc'
8
-
9
- Pry.start
data/lib/ctfc/base.rb DELETED
@@ -1,204 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'config'
4
- require_relative 'version'
5
-
6
- require 'json'
7
- require 'csv'
8
- require 'kolorit'
9
- require 'rest-client'
10
-
11
- ##
12
- # Module **CTFC** keep everything together. **CTFC::CONFIG** module for default setup,
13
- # and **CTFC::Data** class for actual request execution. For instance methods look
14
- # at **CTFC::Data**, for class methods look at **Ctfc**.
15
- #
16
- # @see CTFC::Data
17
- # @see Ctfc
18
- #
19
- module CTFC
20
- ##
21
- # Data class keep all the logic to send request, receive response,
22
- # and everything between. Class Ctfc extend CTFC::Data, for easier work.
23
- #
24
- # @note Instead of using CTFC::Data.new, you can also call Ctfc.new
25
- #
26
- class Data
27
- include CONFIG
28
-
29
- attr_reader :response, :data, :url, :table, :count, :prices
30
- attr_accessor :fiat, :coins
31
-
32
- alias currency fiat
33
-
34
- ##
35
- # @example Initialization example
36
- # @data = CTFC::Data.new :eur, save: true
37
- #
38
- # @param [Symbol] currency **Optional**. Define fiat currency.
39
- # @param [Hash] opts **Optional**. Additional options hash.
40
- #
41
- # @option opts [Boolean] print **Optional**. Print terminal output.
42
- # @option opts [Boolean] save **Optional**. Save `.csv` output.
43
- # @option opts [Array] coins **Optional**. Define coins to scrap.
44
- #
45
- # @return [Data] Data object to work with
46
- #
47
- def initialize(currency = :eur, opts = {})
48
- @fiat = currency.to_s.upcase
49
- @save = opts[:save].nil? ? true : opts[:save]
50
- @print = opts[:print].nil? ? true : opts[:print]
51
- @coins = opts[:coins].nil? ? COINS : Array(opts[:coins])
52
- end
53
-
54
- ##
55
- # @example Get fiat prices for initialized config
56
- #
57
- # @data.get
58
- #
59
- # @example Get prices and change initialized config "on-the-fly"
60
- #
61
- # @data.get :usd, save: false, coins: %w[BTC XMR ETH]
62
- #
63
- # @param [Symbol || String] currency **Optional**. Change fiat currency and execute request.
64
- # @param [Hash] opts **Optional**. Options hash to change config 'on-the-fly' - see #initialize.
65
- #
66
- # @return [Hash || false] Hash of coins and fiat values, or false if all requests fail
67
- #
68
- def get(currency = nil, opts = {})
69
- @fiat = currency.to_s.upcase unless currency.nil?
70
- @coins = opts[:coins] unless opts[:coins].nil?
71
- @save = opts[:save] unless opts[:save].nil?
72
- @print = opts[:print] unless opts[:print].nil?
73
- @count = 0
74
- @table = "ctfc_#{@fiat}.csv".downcase
75
- do_rest_request
76
- end
77
-
78
- ##
79
- # Get fiat value from response hash with crypto prices
80
- #
81
- # @example
82
- #
83
- # @data.price(:btc)
84
- #
85
- # @param [Symbol || String] coin **Required**. Coin name as symbol or string.
86
- # @return [Float]
87
- #
88
- def price(coin)
89
- @prices[coin.to_s.upcase]
90
- end
91
-
92
- ##
93
- # Check if crypto prices will be saved in `.csv` table
94
- #
95
- # @return [true || false]
96
- #
97
- def save?
98
- @save == true
99
- end
100
-
101
- ##
102
- # Check if crypto prices will be printed in terminal
103
- #
104
- # @return [true || false]
105
- #
106
- def print?
107
- @print == true
108
- end
109
-
110
- ##
111
- # Change option to save '.csv' table with prices
112
- #
113
- # @return [true || false]
114
- #
115
- def save=(opt)
116
- @save = opt.is_a?(TrueClass)
117
- end
118
-
119
- ##
120
- # Change option to print prices in terminal
121
- #
122
- # @return [true || false]
123
- #
124
- def print=(opt)
125
- @print = opt.is_a?(TrueClass)
126
- end
127
-
128
- ##
129
- # Check if request was successful or not.
130
- #
131
- # @return [true || false]
132
- #
133
- def success?
134
- return false if @response.nil?
135
-
136
- @response.code == 200
137
- end
138
-
139
- private
140
-
141
- def do_rest_request
142
- prepare_uri
143
- process_data
144
- @prices
145
- rescue StandardError
146
- if (@count += 1) >= MAX_RETRY
147
- puts @response.to_s.split(',')
148
- false
149
- else
150
- do_rest_request
151
- end
152
- end
153
-
154
- def process_data
155
- @response = RestClient.get @url
156
- @data = JSON.parse @response
157
-
158
- @data_array << Time.now.to_s
159
- @coins.each do |coin|
160
- value = @data['RAW'][coin.to_s.upcase][@fiat.to_s.upcase]['PRICE'].round(2)
161
- @prices[coin] = value
162
- @data_array << value
163
- end
164
-
165
- print_fiat_values
166
- save_csv_data
167
- end
168
-
169
- def prepare_uri
170
- @prices = {}
171
- @data_array = []
172
- coin_uri = String.new ''
173
- @coins.collect { |coin| coin_uri << "fsyms=#{coin}&" }
174
- @url = URL + "#{coin_uri}tsyms=#{@fiat}"
175
- end
176
-
177
- def print_fiat_values
178
- return unless print?
179
-
180
- 30.times { print '='.cyan }
181
- puts ''
182
- puts "#{'['.cyan.bold}#{@fiat.to_s.upcase.yellow.bold}#{']'.cyan.bold} conversion rate"
183
- 30.times { print '='.cyan }
184
- puts ''
185
- @prices.each do |name, value|
186
- print '['.yellow.bold + name.to_s.cyan.bold + ']'.yellow.bold
187
- puts ": #{value}".bold
188
- end
189
- end
190
-
191
- def save_csv_data
192
- return unless save?
193
-
194
- create_csv_headers unless File.exist?(@table)
195
- CSV.open(@table, 'ab') { |column| column << @data_array }
196
- end
197
-
198
- def create_csv_headers
199
- header_array = ['TIME']
200
- @coins.each { |coin| header_array << coin }
201
- CSV.open(@table, 'w') { |header| header << header_array }
202
- end
203
- end
204
- end
data/lib/ctfc/config.rb DELETED
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CTFC
4
- ##
5
- # Keep default configuration data, like coins to scrap, max number
6
- # of retries and cryptocompare API url.
7
- #
8
- module CONFIG
9
- # default coins to use
10
- COINS = %w[BTC LTC XMR ETH BCH ZEC].freeze
11
-
12
- # max number of retries if request fail
13
- MAX_RETRY = 3
14
-
15
- # Cryptocompare API - base url for requests
16
- URL = 'https://min-api.cryptocompare.com/data/pricemultifull?'
17
- end
18
- end