coinpare 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,16 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'toml'
4
- require 'pastel'
5
- require 'tty-config'
6
- require 'tty-prompt'
7
- require 'tty-spinner'
8
- require 'tty-table'
9
- require 'tty-pie'
10
- require 'timers'
11
-
12
- require_relative '../command'
13
- require_relative '../fetcher'
3
+ require "toml"
4
+ require "pastel"
5
+ require "tty-config"
6
+ require "tty-prompt"
7
+ require "tty-spinner"
8
+ require "tty-table"
9
+ require "tty-pie"
10
+ require "timers"
11
+
12
+ require_relative "../command"
13
+ require_relative "../fetcher"
14
14
 
15
15
  module Coinpare
16
16
  module Commands
@@ -23,16 +23,16 @@ module Coinpare
23
23
  @timers = Timers::Group.new
24
24
  @spinner = TTY::Spinner.new(":spinner Fetching data...",
25
25
  format: :dots, clear: true)
26
- @interval = @options.fetch('watch', DEFAULT_INTERVAL).to_f
27
- config.set('settings', 'color', value: !@options['no-color'])
26
+ @interval = @options.fetch("watch", DEFAULT_INTERVAL).to_f
27
+ config.set("settings", "color", value: !@options["no-color"])
28
28
  end
29
29
 
30
30
  def execute(input: $stdin, output: $stdout)
31
31
  config_saved = config.exist?
32
- if config_saved && @options['edit']
32
+ if config_saved && @options["edit"]
33
33
  editor.open(config.source_file)
34
34
  return
35
- elsif @options['edit']
35
+ elsif @options["edit"]
36
36
  output.puts "Sorry, no holdings configuration found."
37
37
  output.print "Run \""
38
38
  output.print "$ #{add_color('coinpare holdings', :yellow)}\" "
@@ -42,29 +42,29 @@ module Coinpare
42
42
 
43
43
  config.read if config_saved
44
44
 
45
- holdings = config.fetch('holdings')
45
+ holdings = config.fetch("holdings")
46
46
  if holdings.nil? || (holdings && holdings.empty?)
47
47
  info = setup_portfolio(input, output)
48
48
  config.merge(info)
49
- elsif @options['add']
49
+ elsif @options["add"]
50
50
  coin_info = add_coin(input, output)
51
- config.append(coin_info, to: ['holdings'])
52
- elsif @options['remove']
51
+ config.append(coin_info, to: ["holdings"])
52
+ elsif @options["remove"]
53
53
  coin_info = remove_coin(input, output)
54
- config.remove(*coin_info, from: ['holdings'])
55
- elsif @options['clear']
54
+ config.remove(*coin_info, from: ["holdings"])
55
+ elsif @options["clear"]
56
56
  prompt = create_prompt(input, output)
57
- answer = prompt.yes?('Do you want to remove all holdings?')
57
+ answer = prompt.yes?("Do you want to remove all holdings?")
58
58
  if answer
59
- config.delete('holdings')
59
+ config.delete("holdings")
60
60
  output.puts add_color("All holdings removed", :red)
61
61
  end
62
62
  end
63
63
 
64
- holdings = config.fetch('holdings')
64
+ holdings = config.fetch("holdings")
65
65
  no_holdings_left = holdings.nil? || (holdings && holdings.empty?)
66
66
  if no_holdings_left
67
- config.delete('holdings')
67
+ config.delete("holdings")
68
68
  end
69
69
 
70
70
  # Persist current configuration
@@ -77,15 +77,15 @@ module Coinpare
77
77
  end
78
78
 
79
79
  @spinner.auto_spin
80
- settings = config.fetch('settings')
80
+ settings = config.fetch("settings")
81
81
  # command options take precedence over config settings
82
82
  overridden_settings = {}
83
- overridden_settings['exchange'] = @options.fetch('exchange', settings.fetch('exchange'))
84
- overridden_settings['base'] = @options.fetch('base', settings.fetch('base'))
85
- holdings = config.fetch('holdings') { [] }
86
- names = holdings.map { |c| c['name'] }
83
+ overridden_settings["exchange"] = @options.fetch("exchange", settings.fetch("exchange"))
84
+ overridden_settings["base"] = @options.fetch("base", settings.fetch("base"))
85
+ holdings = config.fetch("holdings") { [] }
86
+ names = holdings.map { |c| c["name"] }
87
87
 
88
- if @options['watch']
88
+ if @options["watch"]
89
89
  output.print cursor.hide
90
90
  @timers.now_and_every(@interval) do
91
91
  display_coins(output, names, overridden_settings)
@@ -96,7 +96,7 @@ module Coinpare
96
96
  end
97
97
  ensure
98
98
  @spinner.stop
99
- if @options['watch']
99
+ if @options["watch"]
100
100
  @timers.cancel
101
101
  output.print cursor.clear_screen_down
102
102
  output.print cursor.show
@@ -104,14 +104,14 @@ module Coinpare
104
104
  end
105
105
 
106
106
  def display_coins(output, names, overridden_settings)
107
- response = Fetcher.fetch_prices(names.join(','),
108
- overridden_settings['base'].upcase,
107
+ response = Fetcher.fetch_prices(names.join(","),
108
+ overridden_settings["base"].upcase,
109
109
  overridden_settings)
110
110
  return unless response
111
- table = if @options['pie']
112
- setup_table_with_pies(response['RAW'], response['DISPLAY'])
111
+ table = if @options["pie"]
112
+ setup_table_with_pies(response["RAW"], response["DISPLAY"])
113
113
  else
114
- setup_table(response['RAW'], response['DISPLAY'])
114
+ setup_table(response["RAW"], response["DISPLAY"])
115
115
  end
116
116
 
117
117
  @spinner.stop
@@ -119,7 +119,7 @@ module Coinpare
119
119
  lines = banner(overridden_settings).lines.size + 1 + (table.rows_size + 3)
120
120
  clear_output(output, lines) do
121
121
  output.puts banner(overridden_settings)
122
- if @options['pie']
122
+ if @options["pie"]
123
123
  output.puts table.render(:unicode, padding: [0, 2])
124
124
  else
125
125
  output.puts table.render(:unicode, padding: [0, 1], alignment: :right)
@@ -128,9 +128,9 @@ module Coinpare
128
128
  end
129
129
 
130
130
  def clear_output(output, lines)
131
- output.print cursor.clear_screen_down if @options['watch']
131
+ output.print cursor.clear_screen_down if @options["watch"]
132
132
  yield if block_given?
133
- output.print cursor.up(lines) if @options['watch']
133
+ output.print cursor.up(lines) if @options["watch"]
134
134
  end
135
135
 
136
136
  def create_prompt(input, output)
@@ -138,32 +138,31 @@ module Coinpare
138
138
  prefix: "[#{add_color('c', :yellow)}] ",
139
139
  input: input, output: output,
140
140
  interrupt: -> { puts; exit 1 },
141
- enable_color: !@options['no-color'],
142
- clear: true
141
+ enable_color: !@options["no-color"]
143
142
  )
144
143
  prompt.on(:keypress) { |event|
145
- prompt.trigger(:keydown) if event.value == 'j'
146
- prompt.trigger(:keyup) if event.value == 'k'
144
+ prompt.trigger(:keydown) if event.value == "j"
145
+ prompt.trigger(:keyup) if event.value == "k"
147
146
  }
148
147
  prompt
149
148
  end
150
149
 
151
150
  def ask_coin
152
151
  -> (prompt) do
153
- key('name').ask('What coin do you own?') do |q|
154
- q.default 'BTC'
155
- q.required(true, 'You need to provide a coin')
156
- q.validate(/\w{2,}/, 'Currency can only be chars.')
152
+ key("name").ask("What coin do you own?") do |q|
153
+ q.default "BTC"
154
+ q.required(true, "You need to provide a coin")
155
+ q.validate(/\w{2,}/, "Currency can only be chars.")
157
156
  q.convert ->(coin) { coin.upcase }
158
157
  end
159
- key('amount').ask('What amount?') do |q|
160
- q.required(true, 'You need to provide an amount')
161
- q.validate(/[\d.]+/, 'Invalid amount provided')
158
+ key("amount").ask("What amount?") do |q|
159
+ q.required(true, "You need to provide an amount")
160
+ q.validate(/[\d.]+/, "Invalid amount provided")
162
161
  q.convert ->(am) { am.to_f }
163
162
  end
164
- key('price').ask('At what price per coin?') do |q|
165
- q.required(true, 'You need to provide a price')
166
- q.validate(/[\d.]+/, 'Invalid prince provided')
163
+ key("price").ask("At what price per coin?") do |q|
164
+ q.required(true, "You need to provide a price")
165
+ q.validate(/[\d.]+/, "Invalid prince provided")
167
166
  q.convert ->(p) { p.to_f }
168
167
  end
169
168
  end
@@ -180,8 +179,8 @@ module Coinpare
180
179
 
181
180
  def remove_coin(input, output)
182
181
  prompt = create_prompt(input, output)
183
- holdings = config.fetch('holdings')
184
- data = prompt.multi_select('Which hodlings to remove?') do |menu|
182
+ holdings = config.fetch("holdings")
183
+ data = prompt.multi_select("Which hodlings to remove?") do |menu|
185
184
  holdings.each do |holding|
186
185
  menu.choice "#{holding['name']} (#{holding['amount']})", holding
187
186
  end
@@ -198,26 +197,26 @@ module Coinpare
198
197
  prompt = create_prompt(input, output)
199
198
  context = self
200
199
  data = prompt.collect do
201
- key('settings') do
202
- key('base').ask('What base currency to convert holdings to?') do |q|
200
+ key("settings") do
201
+ key("base").ask("What base currency to convert holdings to?") do |q|
203
202
  q.default "USD"
204
203
  q.convert ->(b) { b.upcase }
205
- q.validate(/\w{3}/, 'Currency code needs to be 3 chars long')
204
+ q.validate(/\w{3}/, "Currency code needs to be 3 chars long")
206
205
  end
207
- key('exchange').ask('What exchange would you like to use?') do |q|
206
+ key("exchange").ask("What exchange would you like to use?") do |q|
208
207
  q.default "CCCAGG"
209
208
  q.required true
210
209
  end
211
210
  end
212
211
 
213
212
  while prompt.yes?("Do you want to add coin to your altfolio?")
214
- key('holdings').values(&context.ask_coin)
213
+ key("holdings").values(&context.ask_coin)
215
214
  end
216
215
  end
217
216
 
218
217
  lines = 4 + # intro
219
218
  2 + # base + exchange
220
- data['holdings'].size * 4 + 1
219
+ data["holdings"].size * 4 + 1
221
220
  output.print cursor.up(lines)
222
221
  output.print cursor.clear_screen_down
223
222
 
@@ -226,24 +225,24 @@ module Coinpare
226
225
 
227
226
  def create_pie_charts(raw_data, display_data)
228
227
  colors = %i[yellow blue green cyan magenta red]
229
- radius = @options['pie'].to_i > 0 ? @options['pie'].to_i : DEFAULT_PIE_RADIUS
230
- base = @options.fetch('base', config.fetch('settings', 'base')).upcase
228
+ radius = @options["pie"].to_i > 0 ? @options["pie"].to_i : DEFAULT_PIE_RADIUS
229
+ base = @options.fetch("base", config.fetch("settings", "base")).upcase
231
230
  to_symbol = nil
232
231
  past_data = []
233
232
  curr_data = []
234
233
 
235
- config.fetch('holdings').each do |coin|
236
- coin_data = raw_data[coin['name']][base]
237
- to_symbol = display_data[coin['name']][base]['TOSYMBOL']
238
- past_price = coin['amount'] * coin['price']
239
- curr_price = coin['amount'] * coin_data['PRICE']
234
+ config.fetch("holdings").each do |coin|
235
+ coin_data = raw_data[coin["name"]][base]
236
+ to_symbol = display_data[coin["name"]][base]["TOSYMBOL"]
237
+ past_price = coin["amount"] * coin["price"]
238
+ curr_price = coin["amount"] * coin_data["PRICE"]
240
239
 
241
- past_data << { name: coin['name'], value: past_price }
242
- curr_data << { name: coin['name'], value: curr_price }
240
+ past_data << { name: coin["name"], value: past_price }
241
+ curr_data << { name: coin["name"], value: curr_price }
243
242
  end
244
243
 
245
244
  options = {
246
- colors: !@options['no-color'] && colors,
245
+ colors: !@options["no-color"] && colors,
247
246
  radius: radius,
248
247
  legend: {
249
248
  left: 2,
@@ -253,8 +252,8 @@ module Coinpare
253
252
  }
254
253
 
255
254
  [
256
- TTY::Pie.new(options.merge(data: past_data)),
257
- TTY::Pie.new(options.merge(data: curr_data)),
255
+ TTY::Pie.new(**options.merge(data: past_data)),
256
+ TTY::Pie.new(**options.merge(data: curr_data)),
258
257
  to_symbol
259
258
  ]
260
259
  end
@@ -273,8 +272,8 @@ module Coinpare
273
272
 
274
273
  table = TTY::Table.new(
275
274
  header: [
276
- {value: header_past, alignment: :center},
277
- {value: header_curr, alignment: :center}
275
+ { value: header_past, alignment: :center },
276
+ { value: header_curr, alignment: :center }
278
277
  ]
279
278
  )
280
279
  past_pie.to_s.split("\n").zip(curr_pie.to_s.split("\n")).each do |past_part, curr_part|
@@ -284,36 +283,36 @@ module Coinpare
284
283
  end
285
284
 
286
285
  def setup_table(raw_data, display_data)
287
- base = @options.fetch('base', config.fetch('settings', 'base')).upcase
286
+ base = @options.fetch("base", config.fetch("settings", "base")).upcase
288
287
  total_buy = 0
289
288
  total = 0
290
289
  to_symbol = nil
291
290
 
292
291
  table = TTY::Table.new(header: [
293
- { value: 'Coin', alignment: :left },
294
- 'Amount',
295
- 'Price',
296
- 'Total Price',
297
- 'Cur. Price',
298
- 'Total Cur. Price',
299
- 'Change',
300
- 'Change%'
292
+ { value: "Coin", alignment: :left },
293
+ "Amount",
294
+ "Price",
295
+ "Total Price",
296
+ "Cur. Price",
297
+ "Total Cur. Price",
298
+ "Change",
299
+ "Change%"
301
300
  ])
302
301
 
303
- config.fetch('holdings').each do |coin|
304
- coin_data = raw_data[coin['name']][base]
305
- coin_display_data = display_data[coin['name']][base]
306
- past_price = coin['amount'] * coin['price']
307
- curr_price = coin['amount'] * coin_data['PRICE']
308
- to_symbol = coin_display_data['TOSYMBOL']
302
+ config.fetch("holdings").each do |coin|
303
+ coin_data = raw_data[coin["name"]][base]
304
+ coin_display_data = display_data[coin["name"]][base]
305
+ past_price = coin["amount"] * coin["price"]
306
+ curr_price = coin["amount"] * coin_data["PRICE"]
307
+ to_symbol = coin_display_data["TOSYMBOL"]
309
308
  change = curr_price - past_price
310
309
  arrow = pick_arrow(change)
311
310
  total_buy += past_price
312
311
  total += curr_price
313
312
 
314
313
  coin_details = [
315
- { value: add_color(coin['name'], :yellow), alignment: :left },
316
- coin['amount'],
314
+ { value: add_color(coin["name"], :yellow), alignment: :left },
315
+ coin["amount"],
317
316
  "#{to_symbol} #{number_to_currency(round_to(coin['price']))}",
318
317
  "#{to_symbol} #{number_to_currency(round_to(past_price))}",
319
318
  add_color("#{to_symbol} #{number_to_currency(round_to(coin_data['PRICE']))}", pick_color(change)),
@@ -328,8 +327,8 @@ module Coinpare
328
327
  arrow = pick_arrow(total_change)
329
328
 
330
329
  table << [
331
- { value: add_color('ALL', :cyan), alignment: :left }, '-', '-',
332
- "#{to_symbol} #{number_to_currency(round_to(total_buy))}", '-',
330
+ { value: add_color("ALL", :cyan), alignment: :left }, "-", "-",
331
+ "#{to_symbol} #{number_to_currency(round_to(total_buy))}", "-",
333
332
  add_color("#{to_symbol} #{number_to_currency(round_to(total))}", pick_color(total_change)),
334
333
  add_color("#{arrow} #{to_symbol} #{number_to_currency(round_to(total_change))}", pick_color(total_change)),
335
334
  add_color("#{arrow} #{round_to(percent_change(total_buy, total))}%", pick_color(total_change))
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pastel'
4
- require 'tty-pager'
5
- require 'tty-spinner'
6
- require 'tty-table'
7
- require 'timers'
3
+ require "pastel"
4
+ require "tty-pager"
5
+ require "tty-spinner"
6
+ require "tty-table"
7
+ require "timers"
8
8
 
9
- require_relative '../command'
10
- require_relative '../fetcher'
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(':spinner Fetching data...',
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['watch']
28
+ if @options["watch"]
29
29
  output.print cursor.hide
30
- interval = @options['watch'].to_f > 0 ? @options['watch'].to_f : DEFAULT_INTERVAL
30
+ interval = @options["watch"].to_f > 0 ? @options["watch"].to_f : DEFAULT_INTERVAL
31
31
  @timers.now_and_every(interval) { display_markets(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['watch']
38
+ if @options["watch"]
39
39
  @timers.cancel
40
40
  output.print cursor.clear_screen_down
41
41
  output.print cursor.show
@@ -45,7 +45,7 @@ module Coinpare
45
45
  def display_markets(output, pager)
46
46
  to_symbol = fetch_symbol
47
47
  response = Fetcher.fetch_top_exchanges_by_pair(
48
- @name.upcase, @options['base'].upcase, @options)
48
+ @name.upcase, @options["base"].upcase, @options)
49
49
  return unless response
50
50
  table = setup_table(response["Data"]["Exchanges"], to_symbol)
51
51
 
@@ -55,9 +55,9 @@ module Coinpare
55
55
  end
56
56
 
57
57
  def clear_output(output, lines)
58
- output.print cursor.clear_screen_down if @options['watch']
58
+ output.print cursor.clear_screen_down if @options["watch"]
59
59
  yield if block_given?
60
- output.print cursor.up(lines) if @options['watch']
60
+ output.print cursor.up(lines) if @options["watch"]
61
61
  end
62
62
 
63
63
  def print_results(table, output, pager)
@@ -73,10 +73,10 @@ module Coinpare
73
73
  end
74
74
 
75
75
  def fetch_symbol
76
- prices = Fetcher.fetch_prices(
77
- @name.upcase, @options['base'].upcase, @options)
76
+ prices = Fetcher.fetch_prices(@name.upcase, @options["base"].upcase, @options)
78
77
  return unless prices
79
- prices['DISPLAY'][@name.upcase][@options['base'].upcase]['TOSYMBOL']
78
+
79
+ prices["DISPLAY"][@name.upcase][@options["base"].upcase]["TOSYMBOL"]
80
80
  end
81
81
 
82
82
  def banner
@@ -87,20 +87,20 @@ module Coinpare
87
87
 
88
88
  def setup_table(data, to_symbol)
89
89
  table = TTY::Table.new(header: [
90
- { value: 'Market', alignment: :left },
91
- 'Price',
92
- 'Chg. 24H',
93
- 'Chg.% 24H',
94
- 'Open 24H',
95
- 'High 24H',
96
- 'Low 24H',
97
- 'Direct Vol. 24H',
90
+ { value: "Market", alignment: :left },
91
+ "Price",
92
+ "Chg. 24H",
93
+ "Chg.% 24H",
94
+ "Open 24H",
95
+ "High 24H",
96
+ "Low 24H",
97
+ "Direct Vol. 24H"
98
98
  ])
99
99
 
100
100
  data.each do |market|
101
- change24h = market['CHANGE24HOUR']
101
+ change24h = market["CHANGE24HOUR"]
102
102
  market_details = [
103
- { value: add_color(market['MARKET'], :yellow), alignment: :left },
103
+ { value: add_color(market["MARKET"], :yellow), alignment: :left },
104
104
  add_color("#{to_symbol} #{number_to_currency(round_to(market['PRICE']))}", pick_color(change24h)),
105
105
  add_color("#{pick_arrow(change24h)} #{to_symbol} #{number_to_currency(round_to(change24h))}", pick_color(change24h)),
106
106
  add_color("#{pick_arrow(change24h)} #{round_to(market['CHANGEPCT24HOUR'] * 100)}%", pick_color(change24h)),