coinpare 0.2.0 → 0.3.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 +4 -4
- data/CHANGELOG.md +12 -0
- data/exe/coinpare +4 -4
- data/lib/coinpare/cli.rb +73 -64
- data/lib/coinpare/command.rb +20 -17
- data/lib/coinpare/commands/coins.rb +44 -40
- data/lib/coinpare/commands/holdings.rb +94 -95
- data/lib/coinpare/commands/markets.rb +27 -27
- data/lib/coinpare/fetcher.rb +11 -9
- data/lib/coinpare/version.rb +1 -1
- metadata +47 -57
- data/Rakefile +0 -9
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/coinpare.gemspec +0 -45
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 95d8580cc429e071a026b03263fb52cb17560486c3627867e432772285211c8a
|
4
|
+
data.tar.gz: b2aba6a81e5827730fe124326f7cc3ca9e5b75dd6223d884f4aa22a217175173
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b9a4a0dd8ff044e345d6f4cd103a19f6ce24ab73ed7bfd478e081cd3440eef5d2d276ced28851edba6e299ce2583cb6a287d252544ca27a88cc72d9ee86be25
|
7
|
+
data.tar.gz: b66f298dcaa9d28f9d9597b13c60c2fab42a66afd839b47ddb498d535bcf34a68b501e8b28690c7756d1d4d324b2fe0d2d6728f0978dcfb0c16da77a380910bc
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## [v0.3.0] - 2020-11-09
|
4
|
+
|
5
|
+
### Changed
|
6
|
+
* Change gemspec to only package lib files and include metadata
|
7
|
+
* Update all the tty and thor runtime dependencies
|
8
|
+
* Remove tty-color as a dependency
|
9
|
+
* Change to make tty-screen an explicit runtime dependency
|
10
|
+
|
11
|
+
### Fixed
|
12
|
+
* Fix Ruby 2.7 keyword conversion errors
|
13
|
+
|
3
14
|
## [v0.2.0] - 2019-01-12
|
4
15
|
|
5
16
|
### Added
|
@@ -15,5 +26,6 @@
|
|
15
26
|
|
16
27
|
* Initial implementation and release
|
17
28
|
|
29
|
+
[v0.3.0]: https://github.com/piotrmurach/coinpare/compare/v0.2.0...v0.3.0
|
18
30
|
[v0.2.0]: https://github.com/piotrmurach/coinpare/compare/v0.1.0...v0.2.0
|
19
31
|
[v0.1.0]: https://github.com/piotrmurach/coinpare/compare/v0.1.0
|
data/exe/coinpare
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
lib_path = File.expand_path(
|
5
|
-
|
6
|
-
require
|
4
|
+
lib_path = File.expand_path("../lib", __dir__)
|
5
|
+
$LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path)
|
6
|
+
require "coinpare/cli"
|
7
7
|
|
8
|
-
Signal.trap(
|
8
|
+
Signal.trap("INT") do
|
9
9
|
warn("\n#{caller.join("\n")}: interrupted")
|
10
10
|
exit(1)
|
11
11
|
end
|
data/lib/coinpare/cli.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require "thor"
|
4
|
+
require "pastel"
|
5
|
+
require "tty-font"
|
6
6
|
|
7
7
|
module Coinpare
|
8
8
|
# Handle the application command line parsing
|
@@ -14,16 +14,17 @@ module Coinpare
|
|
14
14
|
Error = Class.new(StandardError)
|
15
15
|
|
16
16
|
def help(*args)
|
17
|
-
font =
|
18
|
-
pastel = Pastel.new(enabled: !options[
|
17
|
+
font = TTY::Font.new(:standard)
|
18
|
+
pastel = Pastel.new(enabled: !options["no-color"])
|
19
19
|
puts pastel.yellow(font.write("Coinpare"))
|
20
20
|
super
|
21
21
|
end
|
22
22
|
|
23
23
|
class_option :"no-color", type: :boolean, default: false,
|
24
|
-
desc:
|
24
|
+
desc: "Disable colorization in output"
|
25
25
|
|
26
|
-
desc
|
26
|
+
desc "coins NAMES...", "Get all the current trading data for the " \
|
27
|
+
"coin names..."
|
27
28
|
long_desc <<-DESC
|
28
29
|
Get all the current trading info (price, vol, open, high, low etc)
|
29
30
|
of any list of cryptocurrencies in any other currency that you need.
|
@@ -39,31 +40,33 @@ module Coinpare
|
|
39
40
|
|
40
41
|
> $ coinpare coins BTC ETH --exchange coinbase
|
41
42
|
DESC
|
42
|
-
method_option :base, aliases:
|
43
|
-
desc:
|
44
|
-
banner:
|
45
|
-
method_option :columns, aliases:
|
46
|
-
desc:
|
47
|
-
banner:
|
48
|
-
method_option :exchange, aliases:
|
49
|
-
desc:
|
50
|
-
banner:
|
51
|
-
method_option :help, aliases:
|
52
|
-
desc:
|
53
|
-
method_option :top, aliases:
|
54
|
-
desc: "The number of top coins by total volume
|
55
|
-
|
56
|
-
|
43
|
+
method_option :base, aliases: "-b", type: :string, default: "USD",
|
44
|
+
desc: "The currency symbol to convert into",
|
45
|
+
banner: "CURRENCY"
|
46
|
+
method_option :columns, aliases: "-c", type: :array,
|
47
|
+
desc: "Specify columns to display",
|
48
|
+
banner: "0 1 2"
|
49
|
+
method_option :exchange, aliases: "-e", type: :string, default: "CCCAGG",
|
50
|
+
desc: "Name of exchange",
|
51
|
+
banner: "name"
|
52
|
+
method_option :help, aliases: "-h", type: :boolean,
|
53
|
+
desc: "Display usage information"
|
54
|
+
method_option :top, aliases: "-t", type: :numeric, default: 10, banner: "N",
|
55
|
+
desc: "The number of top coins by total volume " \
|
56
|
+
"accross all markets in 24 hours"
|
57
|
+
method_option :watch, aliases: "-w", banner: "N",
|
58
|
+
desc: "Automatically refresh data every n seconds," \
|
59
|
+
" default 5 sec"
|
57
60
|
def coins(*names)
|
58
61
|
if options[:help]
|
59
|
-
invoke :help, [
|
62
|
+
invoke :help, ["coins"]
|
60
63
|
else
|
61
|
-
require_relative
|
64
|
+
require_relative "commands/coins"
|
62
65
|
Coinpare::Commands::Coins.new(names, options).execute
|
63
66
|
end
|
64
67
|
end
|
65
68
|
|
66
|
-
desc
|
69
|
+
desc "holdings", "Keep track of all your cryptocurrency investments"
|
67
70
|
long_desc <<-DESC
|
68
71
|
Get the current trading prices and their change in value and percentage
|
69
72
|
for all your cryptocurrency investments.
|
@@ -76,36 +79,40 @@ module Coinpare
|
|
76
79
|
|
77
80
|
> $ coinpare holdings --exchange coinbase --base USD
|
78
81
|
DESC
|
79
|
-
method_option :add, aliases:
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
82
|
+
method_option :add, aliases: "-a", type: :boolean,
|
83
|
+
desc: "Add a new coin without altering any " \
|
84
|
+
"existhing holdings"
|
85
|
+
method_option :base, aliases: "-b", type: :string,
|
86
|
+
desc: "The currency symbol to convert into",
|
87
|
+
banner: "CURRENCY"
|
84
88
|
method_option :clear, type: :boolean, default: false,
|
85
|
-
desc:
|
86
|
-
method_option :edit, type: :string, banner:
|
87
|
-
desc:
|
88
|
-
|
89
|
-
|
90
|
-
method_option :
|
91
|
-
|
92
|
-
method_option :
|
93
|
-
|
94
|
-
|
89
|
+
desc: "Remove all coins from your existing holdings"
|
90
|
+
method_option :edit, type: :string, banner: "editor",
|
91
|
+
desc: "Open the holdings configuration file for " \
|
92
|
+
"editing in EDITOR, or the default editor " \
|
93
|
+
"if not specified."
|
94
|
+
method_option :exchange, aliases: "-e", type: :string,
|
95
|
+
desc: "Name of exchange", banner: "NAME"
|
96
|
+
method_option :help, aliases: "-h", type: :boolean,
|
97
|
+
desc: "Display usage information"
|
98
|
+
method_option :pie, aliases: "-p", type: :string,
|
99
|
+
desc: "Display data in a pie chart format",
|
100
|
+
banner: "RADIUS"
|
95
101
|
method_option :remove, type: :boolean,
|
96
|
-
|
97
|
-
method_option :watch, aliases:
|
98
|
-
desc:
|
102
|
+
desc: "Remove the given coin(s) from holdings"
|
103
|
+
method_option :watch, aliases: "-w", banner: "N",
|
104
|
+
desc: "Automatically refresh data every n seconds," \
|
105
|
+
" default 5 sec"
|
99
106
|
def holdings(*)
|
100
107
|
if options[:help]
|
101
|
-
invoke :help, [
|
108
|
+
invoke :help, ["holdings"]
|
102
109
|
else
|
103
|
-
require_relative
|
110
|
+
require_relative "commands/holdings"
|
104
111
|
Coinpare::Commands::Holdings.new(options).execute
|
105
112
|
end
|
106
113
|
end
|
107
114
|
|
108
|
-
desc
|
115
|
+
desc "markets [NAME]", "Get top markets by volume for a currency pair"
|
109
116
|
long_desc <<-DESC
|
110
117
|
Get top markets by volume for a currency pair.
|
111
118
|
|
@@ -120,32 +127,34 @@ module Coinpare
|
|
120
127
|
|
121
128
|
> $ coinpare markets ETH -b BTC
|
122
129
|
DESC
|
123
|
-
method_option :base, aliases:
|
124
|
-
desc:
|
125
|
-
banner:
|
126
|
-
method_option :columns, aliases:
|
127
|
-
desc:
|
128
|
-
banner:
|
129
|
-
method_option :help, aliases:
|
130
|
-
desc:
|
131
|
-
method_option :top, aliases:
|
132
|
-
desc: "The number of top exchanges by total volume
|
133
|
-
|
134
|
-
|
135
|
-
|
130
|
+
method_option :base, aliases: "-b", type: :string, default: "USD",
|
131
|
+
desc: "The currency symbol to convert into",
|
132
|
+
banner: "CURRENCY"
|
133
|
+
method_option :columns, aliases: "-c", type: :array,
|
134
|
+
desc: "Specify columns to display",
|
135
|
+
banner: "0 1 2"
|
136
|
+
method_option :help, aliases: "-h", type: :boolean,
|
137
|
+
desc: "Display usage information"
|
138
|
+
method_option :top, aliases: "-t", type: :numeric, default: 10,
|
139
|
+
desc: "The number of top exchanges by total volume " \
|
140
|
+
"in 24 hours"
|
141
|
+
method_option :watch, aliases: "-w", banner: "N",
|
142
|
+
desc: "Automatically refresh data every n seconds," \
|
143
|
+
" default 5 sec"
|
144
|
+
def markets(name = "BTC")
|
136
145
|
if options[:help]
|
137
|
-
invoke :help, [
|
146
|
+
invoke :help, ["markets"]
|
138
147
|
else
|
139
|
-
require_relative
|
148
|
+
require_relative "commands/markets"
|
140
149
|
Coinpare::Commands::Markets.new(name, options).execute
|
141
150
|
end
|
142
151
|
end
|
143
152
|
|
144
|
-
desc
|
153
|
+
desc "version", "coinpare version"
|
145
154
|
def version
|
146
|
-
require_relative
|
155
|
+
require_relative "version"
|
147
156
|
puts "v#{Coinpare::VERSION}"
|
148
157
|
end
|
149
|
-
map %w
|
158
|
+
map %w[--version -v] => :version
|
150
159
|
end
|
151
160
|
end
|
data/lib/coinpare/command.rb
CHANGED
@@ -3,22 +3,22 @@
|
|
3
3
|
module Coinpare
|
4
4
|
class Command
|
5
5
|
SYMBOLS = {
|
6
|
-
down_arrow:
|
7
|
-
up_arrow:
|
6
|
+
down_arrow: "▼",
|
7
|
+
up_arrow: "▲"
|
8
8
|
}.freeze
|
9
9
|
|
10
10
|
# The default interval for auto updating data
|
11
11
|
DEFAULT_INTERVAL = 5
|
12
12
|
|
13
|
-
trap(
|
13
|
+
trap("SIGINT") { exit }
|
14
14
|
|
15
15
|
# Main configuration
|
16
16
|
# @api public
|
17
17
|
def config
|
18
18
|
@config ||= begin
|
19
19
|
config = TTY::Config.new
|
20
|
-
config.filename =
|
21
|
-
config.extname =
|
20
|
+
config.filename = "coinpare"
|
21
|
+
config.extname = ".toml"
|
22
22
|
config.append_path Dir.pwd
|
23
23
|
config.append_path Dir.home
|
24
24
|
config
|
@@ -28,7 +28,7 @@ module Coinpare
|
|
28
28
|
# Time for when the data was fetched
|
29
29
|
# @api public
|
30
30
|
def timestamp
|
31
|
-
"#{Time.now.strftime(
|
31
|
+
"#{Time.now.strftime('%d %B %Y')} at #{Time.now.strftime('%I:%M:%S %p %Z')}"
|
32
32
|
end
|
33
33
|
|
34
34
|
# The exchange, currency & time banner
|
@@ -43,6 +43,7 @@ module Coinpare
|
|
43
43
|
# @api public
|
44
44
|
def pick_arrow(change)
|
45
45
|
return if change.zero?
|
46
|
+
|
46
47
|
change > 0 ? SYMBOLS[:up_arrow] : SYMBOLS[:down_arrow]
|
47
48
|
end
|
48
49
|
|
@@ -52,6 +53,7 @@ module Coinpare
|
|
52
53
|
|
53
54
|
def pick_color(change)
|
54
55
|
return :none if change.zero?
|
56
|
+
|
55
57
|
change > 0 ? :green : :red
|
56
58
|
end
|
57
59
|
|
@@ -64,29 +66,30 @@ module Coinpare
|
|
64
66
|
end
|
65
67
|
|
66
68
|
def shorten_currency(value)
|
67
|
-
if value > 10
|
68
|
-
|
69
|
-
elsif value > 10
|
70
|
-
(value / 10
|
69
|
+
if value > 10**9
|
70
|
+
"#{(value / 10**9).to_f.round(2)} B"
|
71
|
+
elsif value > 10**6
|
72
|
+
"#{(value / 10**6).to_f.round(2)} M"
|
71
73
|
else
|
72
74
|
value
|
73
75
|
end
|
74
76
|
end
|
75
77
|
|
76
78
|
def precision(value, decimals = 2)
|
77
|
-
part = value.to_s.split(
|
79
|
+
part = value.to_s.split(".")[1]
|
78
80
|
return 0 if part.nil?
|
81
|
+
|
79
82
|
value.between?(0, 1) ? (part.index(/[^0]/) + decimals) : decimals
|
80
83
|
end
|
81
84
|
|
82
85
|
def round_to(value, prec = nil)
|
83
86
|
prec = precision(value) if prec.nil?
|
84
|
-
"%.#{prec}f"
|
87
|
+
format("%.#{prec}f", value)
|
85
88
|
end
|
86
89
|
|
87
90
|
def number_to_currency(value)
|
88
|
-
whole, part = value.to_s.split(
|
89
|
-
part =
|
91
|
+
whole, part = value.to_s.split(".")
|
92
|
+
part = "." + part unless part.nil?
|
90
93
|
"#{whole.gsub(/(\d)(?=(\d{3})+(?!\d))/, '\\1,')}#{part}"
|
91
94
|
end
|
92
95
|
|
@@ -106,7 +109,7 @@ module Coinpare
|
|
106
109
|
#
|
107
110
|
# @api public
|
108
111
|
def cursor
|
109
|
-
require
|
112
|
+
require "tty-cursor"
|
110
113
|
TTY::Cursor
|
111
114
|
end
|
112
115
|
|
@@ -116,7 +119,7 @@ module Coinpare
|
|
116
119
|
#
|
117
120
|
# @api public
|
118
121
|
def editor
|
119
|
-
require
|
122
|
+
require "tty-editor"
|
120
123
|
TTY::Editor
|
121
124
|
end
|
122
125
|
|
@@ -126,7 +129,7 @@ module Coinpare
|
|
126
129
|
#
|
127
130
|
# @api public
|
128
131
|
def screen
|
129
|
-
require
|
132
|
+
require "tty-screen"
|
130
133
|
TTY::Screen
|
131
134
|
end
|
132
135
|
end # Command
|
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
3
|
+
require "pastel"
|
4
|
+
require "tty-pager"
|
5
|
+
require "tty-spinner"
|
6
|
+
require "tty-table"
|
7
|
+
require "timers"
|
8
8
|
|
9
|
-
require_relative
|
10
|
-
require_relative
|
9
|
+
require_relative "../command"
|
10
|
+
require_relative "../fetcher"
|
11
11
|
|
12
12
|
module Coinpare
|
13
13
|
module Commands
|
@@ -17,7 +17,7 @@ module Coinpare
|
|
17
17
|
@options = options
|
18
18
|
@pastel = Pastel.new
|
19
19
|
@timers = Timers::Group.new
|
20
|
-
@spinner = TTY::Spinner.new(
|
20
|
+
@spinner = TTY::Spinner.new(":spinner Fetching data...",
|
21
21
|
format: :dots, clear: true)
|
22
22
|
end
|
23
23
|
|
@@ -25,9 +25,9 @@ module Coinpare
|
|
25
25
|
pager = TTY::Pager.new(output: output)
|
26
26
|
@spinner.auto_spin
|
27
27
|
|
28
|
-
if @options[
|
28
|
+
if @options["watch"]
|
29
29
|
output.print cursor.hide
|
30
|
-
interval = @options[
|
30
|
+
interval = @options["watch"].to_f > 0 ? @options["watch"].to_f : DEFAULT_INTERVAL
|
31
31
|
@timers.now_and_every(interval) { display_coins(output, pager) }
|
32
32
|
loop { @timers.wait }
|
33
33
|
else
|
@@ -35,7 +35,7 @@ module Coinpare
|
|
35
35
|
end
|
36
36
|
ensure
|
37
37
|
@spinner.stop
|
38
|
-
if @options[
|
38
|
+
if @options["watch"]
|
39
39
|
@timers.cancel
|
40
40
|
output.print cursor.clear_screen_down
|
41
41
|
output.print cursor.show
|
@@ -48,10 +48,11 @@ module Coinpare
|
|
48
48
|
if @names.empty? # no coins provided
|
49
49
|
@names = setup_top_coins
|
50
50
|
end
|
51
|
-
response = Fetcher.fetch_prices(@names.map(&:upcase).join(
|
52
|
-
@options[
|
51
|
+
response = Fetcher.fetch_prices(@names.map(&:upcase).join(","),
|
52
|
+
@options["base"].upcase, @options)
|
53
53
|
return unless response
|
54
|
-
|
54
|
+
|
55
|
+
table = setup_table(response["RAW"], response["DISPLAY"])
|
55
56
|
@spinner.stop
|
56
57
|
|
57
58
|
lines = banner(@options).lines.size + 1 + table.rows_size + 3
|
@@ -59,9 +60,9 @@ module Coinpare
|
|
59
60
|
end
|
60
61
|
|
61
62
|
def clear_output(output, lines)
|
62
|
-
output.print cursor.clear_screen_down if @options[
|
63
|
+
output.print cursor.clear_screen_down if @options["watch"]
|
63
64
|
yield if block_given?
|
64
|
-
output.print cursor.up(lines) if @options[
|
65
|
+
output.print cursor.up(lines) if @options["watch"]
|
65
66
|
end
|
66
67
|
|
67
68
|
def print_results(table, output, pager)
|
@@ -77,41 +78,44 @@ module Coinpare
|
|
77
78
|
end
|
78
79
|
|
79
80
|
def setup_top_coins
|
80
|
-
response = Fetcher.fetch_top_coins_by_volume(@options[
|
81
|
+
response = Fetcher.fetch_top_coins_by_volume(@options["base"].upcase,
|
81
82
|
@options)
|
82
83
|
return unless response
|
83
|
-
|
84
|
+
|
85
|
+
response["Data"].map { |coin| coin["CoinInfo"]["Name"] }[0...@options["top"]]
|
84
86
|
end
|
85
87
|
|
86
88
|
def setup_table(raw_data, display_data)
|
87
89
|
table = TTY::Table.new(header: [
|
88
|
-
{ value:
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
90
|
+
{ value: "Coin", alignment: :left },
|
91
|
+
"Price",
|
92
|
+
"Chg. 24H",
|
93
|
+
"Chg.% 24H",
|
94
|
+
"Open 24H",
|
95
|
+
"High 24H",
|
96
|
+
"Low 24H",
|
97
|
+
"Direct Vol. 24H",
|
98
|
+
"Total Vol. 24H",
|
99
|
+
"Market Cap"
|
98
100
|
])
|
99
101
|
|
100
102
|
@names.each do |name|
|
101
|
-
coin_data = display_data[name.upcase][@options[
|
102
|
-
coin_raw_data = raw_data[name.upcase][@options[
|
103
|
-
change24h = coin_raw_data[
|
103
|
+
coin_data = display_data[name.upcase][@options["base"].upcase]
|
104
|
+
coin_raw_data = raw_data[name.upcase][@options["base"].upcase]
|
105
|
+
change24h = coin_raw_data["CHANGE24HOUR"]
|
104
106
|
coin_details = [
|
105
107
|
{ value: add_color(name.upcase, :yellow), alignment: :left },
|
106
|
-
add_color(coin_data[
|
107
|
-
add_color("#{pick_arrow(change24h)} #{coin_data['CHANGE24HOUR']}",
|
108
|
-
|
109
|
-
coin_data['
|
110
|
-
|
111
|
-
coin_data[
|
112
|
-
coin_data[
|
113
|
-
coin_data[
|
114
|
-
coin_data[
|
108
|
+
add_color(coin_data["PRICE"], pick_color(change24h)),
|
109
|
+
add_color("#{pick_arrow(change24h)} #{coin_data['CHANGE24HOUR']}",
|
110
|
+
pick_color(change24h)),
|
111
|
+
add_color("#{pick_arrow(change24h)} #{coin_data['CHANGEPCT24HOUR']}%",
|
112
|
+
pick_color(change24h)),
|
113
|
+
coin_data["OPEN24HOUR"],
|
114
|
+
coin_data["HIGH24HOUR"],
|
115
|
+
coin_data["LOW24HOUR"],
|
116
|
+
coin_data["VOLUME24HOURTO"],
|
117
|
+
coin_data["TOTALVOLUME24HTO"],
|
118
|
+
coin_data["MKTCAP"]
|
115
119
|
]
|
116
120
|
table << coin_details
|
117
121
|
end
|