cryptum 0.0.398 → 0.0.400

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: bf83992e0e95b37febd02252408c8737787b96c391c29c8ba884a576e78930d3
4
- data.tar.gz: 919eb5b669e93ce91ccded4adc5dfd73e8821be72b73c66b2bfe8f846034cd28
3
+ metadata.gz: 8d4ccaed7aa5df46e13b97e435ddbf04e77ceedc9e2f385057cd096ec2f8c8b0
4
+ data.tar.gz: d1466bb66ac26757deb64c453df732496467a9a5dd5192d9aeb2df5b6d6d56a9
5
5
  SHA512:
6
- metadata.gz: 2b6c1423945dd56b5dd1138be8d59ab41fa2296d936d5811537c86ac92f694c1c63d3683fe09ca630e2d0bb67b3bf48cad2d39b425f811c310a9a4fd3496b542
7
- data.tar.gz: 60f3a01446ed7a1cc973f1c99776af09c61b18b026fbf5c30b357af2e3359737a0e2acdb024266b0105a143cd6ead9235e6eeadd23674113ee34904ac4f1f3ff
6
+ metadata.gz: 7dd733c6bb7b6a9800a7041ddc2ab0e90944903b4567d5beab5188a0a81eec6706441406e352e4c208e5479976f230fcd12b6f16ca66a7638235ea56df3cc328
7
+ data.tar.gz: 286bd79d23e28162b3cc43a385cf2601ff63e8bf3d2f9b18e22cb3b7c8347199b90368e3f1e3d22427c7296a7f631d130561d091c43d25616b228a0f1c16c8e5
data/Gemfile CHANGED
@@ -11,7 +11,7 @@ gemspec
11
11
  # In some circumstances custom flags are passed to gems in order
12
12
  # to build appropriately. Defer to ./reinstall_coinbot_gemset.sh
13
13
  # to review these custom flags
14
- gem 'addressable', '2.8.2'
14
+ gem 'addressable', '2.8.3'
15
15
  gem 'bundler', '>=2.4.10'
16
16
  gem 'bundler-audit', '0.9.1'
17
17
  gem 'curses', '1.4.4'
@@ -159,7 +159,7 @@ module Cryptum
159
159
  crypto_smallest_decimal = base_increment.to_s.split('.')[-1].length
160
160
  fiat_smallest_decimal = quote_increment.to_s.split('.')[-1].length
161
161
 
162
- # TODO: Calculate / Price / Size
162
+ # Calculate / Price / Size
163
163
  last_three_prices_arr = []
164
164
  last_ticker_price = event_history.order_book[:ticker_price].to_f
165
165
  second_to_last_ticker_price = event_history.order_book[:ticker_price_second_to_last].to_f
@@ -37,12 +37,18 @@ module Cryptum
37
37
 
38
38
  if event_history.order_plan_win_active
39
39
  unless event_history.red_pill
40
- event_history.order_plan_details_win_active = true
41
- event_history.order_plan_details_win_active = false if event_history.order_plan_details_win_active
40
+ event_history.order_plan_details_win_active = if event_history.order_plan_details_win_active
41
+ false
42
+ else
43
+ true
44
+ end
42
45
  end
43
46
  elsif event_history.order_execute_win_active
44
- event_history.order_execute_details_win_active = true
45
- event_history.order_execute_details_win_active = false if event_history.order_execute_details_win_active
47
+ event_history.order_execute_details_win_active = if event_history.order_execute_details_win_active
48
+ false
49
+ else
50
+ true
51
+ end
46
52
  end
47
53
  rescue Interrupt, StandardError => e
48
54
  Cryptum::Log.append(level: :error, msg: e, which_self: self, event_history: event_history)
data/lib/cryptum/log.rb CHANGED
@@ -33,11 +33,10 @@ module Cryptum
33
33
  exit_gracefully = true
34
34
  logger.level = Logger::ERROR
35
35
  when :fatal
36
- # This is reserved for:
37
- # Cryptum::UI::Exit
38
- # module(s) if StandardError is triggered.
39
- # This ensures we're not infintely attempting
40
- # to log to file and exit.
36
+ # This is reserved for the Cryptum::UI::Exit module
37
+ # if the Interrupt or StandardError exceptions are
38
+ # triggered. This prevents infintely attempting to
39
+ # exit if something in the module fails.
41
40
  logger.level = Logger::FATAL
42
41
  when :unknown
43
42
  logger.level = Logger::UNKNOWN
@@ -46,7 +45,9 @@ module Cryptum
46
45
  when :info
47
46
  logger.level = Logger::INFO
48
47
  else
49
- raise "ERROR: Invalid log level. Valid options are:\n:info\n:warn\n:unknown\n:fatal\n:error\n:debug"
48
+ level_error = "ERROR: Invalid log level. Valid options are:\n"
49
+ level_error += ":info\n:warn\n:unknown\n:fatal\n:error\n:debug"
50
+ raise level_error
50
51
  end
51
52
 
52
53
  logger.datetime_format = '%Y-%m-%d %H:%M:%S.%N'
@@ -61,7 +62,7 @@ module Cryptum
61
62
  logger.level = Logger::WARN
62
63
  exit_gracefully = true
63
64
  else
64
- log_event += "=> #{msg}"
65
+ log_event += " => #{msg}"
65
66
  end
66
67
 
67
68
  logger.add(logger.level, log_event, which_self)
@@ -16,101 +16,101 @@ module Cryptum
16
16
  cols = opts[:cols].to_i
17
17
 
18
18
  matrix_arr = [
19
- 0x30a0.chr('UTF-8'),
20
- 0x30a1.chr('UTF-8'),
21
- 0x30a2.chr('UTF-8'),
22
- 0x30a3.chr('UTF-8'),
23
- 0x30a4.chr('UTF-8'),
24
- 0x30a5.chr('UTF-8'),
25
- 0x30a6.chr('UTF-8'),
26
- 0x30a7.chr('UTF-8'),
27
- 0x30a8.chr('UTF-8'),
28
- 0x30a9.chr('UTF-8'),
29
- 0x30aa.chr('UTF-8'),
30
- 0x30ab.chr('UTF-8'),
31
- 0x30ac.chr('UTF-8'),
32
- 0x30ad.chr('UTF-8'),
33
- 0x30ae.chr('UTF-8'),
34
- 0x30af.chr('UTF-8'),
35
- 0x30b0.chr('UTF-8'),
36
- 0x30b1.chr('UTF-8'),
37
- 0x30b2.chr('UTF-8'),
38
- 0x30b3.chr('UTF-8'),
39
- 0x30b4.chr('UTF-8'),
40
- 0x30b5.chr('UTF-8'),
41
- 0x30b6.chr('UTF-8'),
42
- 0x30b7.chr('UTF-8'),
43
- 0x30b8.chr('UTF-8'),
44
- 0x30b9.chr('UTF-8'),
45
- 0x30ba.chr('UTF-8'),
46
- 0x30bb.chr('UTF-8'),
47
- 0x30bc.chr('UTF-8'),
48
- 0x30bd.chr('UTF-8'),
49
- 0x30be.chr('UTF-8'),
50
- 0x30bf.chr('UTF-8'),
51
- 0x30c0.chr('UTF-8'),
52
- 0x30c1.chr('UTF-8'),
53
- 0x30c2.chr('UTF-8'),
54
- 0x30c3.chr('UTF-8'),
55
- 0x30c4.chr('UTF-8'),
56
- 0x30c5.chr('UTF-8'),
57
- 0x30c6.chr('UTF-8'),
58
- 0x30c7.chr('UTF-8'),
59
- 0x30c8.chr('UTF-8'),
60
- 0x30c9.chr('UTF-8'),
61
- 0x30ca.chr('UTF-8'),
62
- 0x30cb.chr('UTF-8'),
63
- 0x30cc.chr('UTF-8'),
64
- 0x30cd.chr('UTF-8'),
65
- 0x30ce.chr('UTF-8'),
66
- 0x30cf.chr('UTF-8'),
67
- 0x30d0.chr('UTF-8'),
68
- 0x30d1.chr('UTF-8'),
69
- 0x30d2.chr('UTF-8'),
70
- 0x30d3.chr('UTF-8'),
71
- 0x30d4.chr('UTF-8'),
72
- 0x30d5.chr('UTF-8'),
73
- 0x30d6.chr('UTF-8'),
74
- 0x30d7.chr('UTF-8'),
75
- 0x30d8.chr('UTF-8'),
76
- 0x30d9.chr('UTF-8'),
77
- 0x30da.chr('UTF-8'),
78
- 0x30db.chr('UTF-8'),
79
- 0x30dc.chr('UTF-8'),
80
- 0x30dd.chr('UTF-8'),
81
- 0x30de.chr('UTF-8'),
82
- 0x30df.chr('UTF-8'),
83
- 0x30e0.chr('UTF-8'),
84
- 0x30e1.chr('UTF-8'),
85
- 0x30e2.chr('UTF-8'),
86
- 0x30e3.chr('UTF-8'),
87
- 0x30e4.chr('UTF-8'),
88
- 0x30e5.chr('UTF-8'),
89
- 0x30e6.chr('UTF-8'),
90
- 0x30e7.chr('UTF-8'),
91
- 0x30e8.chr('UTF-8'),
92
- 0x30e9.chr('UTF-8'),
93
- 0x30ea.chr('UTF-8'),
94
- 0x30eb.chr('UTF-8'),
95
- 0x30ec.chr('UTF-8'),
96
- 0x30ed.chr('UTF-8'),
97
- 0x30ee.chr('UTF-8'),
98
- 0x30ef.chr('UTF-8'),
99
- 0x30f0.chr('UTF-8'),
100
- 0x30f1.chr('UTF-8'),
101
- 0x30f2.chr('UTF-8'),
102
- 0x30f3.chr('UTF-8'),
103
- 0x30f4.chr('UTF-8'),
104
- 0x30f5.chr('UTF-8'),
105
- 0x30f6.chr('UTF-8'),
106
- 0x30f7.chr('UTF-8'),
107
- 0x30f8.chr('UTF-8'),
108
- 0x30f9.chr('UTF-8'),
109
- 0x30fa.chr('UTF-8'),
110
- 0x30fb.chr('UTF-8'),
111
- 0x30fc.chr('UTF-8'),
112
- 0x30fd.chr('UTF-8'),
113
- 0x30fe.chr('UTF-8'),
19
+ "\u30a0",
20
+ "\u30a1",
21
+ "\u30a2",
22
+ "\u30a3",
23
+ "\u30a4",
24
+ "\u30a5",
25
+ "\u30a6",
26
+ "\u30a7",
27
+ "\u30a8",
28
+ "\u30a9",
29
+ "\u30aa",
30
+ "\u30ab",
31
+ "\u30ac",
32
+ "\u30ad",
33
+ "\u30ae",
34
+ "\u30af",
35
+ "\u30b0",
36
+ "\u30b1",
37
+ "\u30b2",
38
+ "\u30b3",
39
+ "\u30b4",
40
+ "\u30b5",
41
+ "\u30b6",
42
+ "\u30b7",
43
+ "\u30b8",
44
+ "\u30b9",
45
+ "\u30ba",
46
+ "\u30bb",
47
+ "\u30bc",
48
+ "\u30bd",
49
+ "\u30be",
50
+ "\u30bf",
51
+ "\u30c0",
52
+ "\u30c1",
53
+ "\u30c2",
54
+ "\u30c3",
55
+ "\u30c4",
56
+ "\u30c5",
57
+ "\u30c6",
58
+ "\u30c7",
59
+ "\u30c8",
60
+ "\u30c9",
61
+ "\u30ca",
62
+ "\u30cb",
63
+ "\u30cc",
64
+ "\u30cd",
65
+ "\u30ce",
66
+ "\u30cf",
67
+ "\u30d0",
68
+ "\u30d1",
69
+ "\u30d2",
70
+ "\u30d3",
71
+ "\u30d4",
72
+ "\u30d5",
73
+ "\u30d6",
74
+ "\u30d7",
75
+ "\u30d8",
76
+ "\u30d9",
77
+ "\u30da",
78
+ "\u30db",
79
+ "\u30dc",
80
+ "\u30dd",
81
+ "\u30de",
82
+ "\u30df",
83
+ "\u30e0",
84
+ "\u30e1",
85
+ "\u30e2",
86
+ "\u30e3",
87
+ "\u30e4",
88
+ "\u30e5",
89
+ "\u30e6",
90
+ "\u30e7",
91
+ "\u30e8",
92
+ "\u30e9",
93
+ "\u30ea",
94
+ "\u30eb",
95
+ "\u30ec",
96
+ "\u30ed",
97
+ "\u30ee",
98
+ "\u30ef",
99
+ "\u30f0",
100
+ "\u30f1",
101
+ "\u30f2",
102
+ "\u30f3",
103
+ "\u30f4",
104
+ "\u30f5",
105
+ "\u30f6",
106
+ "\u30f7",
107
+ "\u30f8",
108
+ "\u30f9",
109
+ "\u30fa",
110
+ "\u30fb",
111
+ "\u30fc",
112
+ "\u30fd",
113
+ "\u30fe",
114
114
  '0 ',
115
115
  '1 ',
116
116
  '2 ',
@@ -159,15 +159,11 @@ module Cryptum
159
159
  ', '
160
160
  ]
161
161
 
162
- # last_index = matrix_arr.length - 1
163
-
164
162
  matrix_row = ''
165
163
  most_cols = cols - 1
166
164
  most_cols.times.each do
167
- # matrix_row += "#{matrix_arr[Random.rand(0..last_index)]} "
168
165
  matrix_row += "#{matrix_arr.sample} "
169
166
  end
170
- # matrix_row += matrix_arr[Random.rand(0..last_index)]
171
167
  matrix_row += matrix_arr.sample
172
168
  rescue Interrupt, StandardError => e
173
169
  Cryptum::Log.append(level: :error, msg: e, which_self: self)
@@ -225,8 +225,6 @@ module Cryptum
225
225
 
226
226
  meta[:done_at] = Time.now.strftime('%Y-%m-%d %H:%M:%S.%N%z')
227
227
 
228
- # TODO: Retry sell order if the original sell order expires.
229
-
230
228
  # Reinitiate GTFO if the previous GTFO Order Expires.
231
229
  terminal_win.key_press_event.key_g = true if meta[:color] == :magenta
232
230
  meta[:color] = :white
@@ -332,8 +330,7 @@ module Cryptum
332
330
  # TODO: Everything Above this Line Needs to be Indicators ^
333
331
 
334
332
  # UI
335
- col_just1 = (Curses.cols - Cryptum::UI.col_first) - 1
336
- col_just4 = Curses.cols - Cryptum::UI.col_fourth
333
+ col_just1 = Curses.cols - Cryptum::UI.col_first
337
334
 
338
335
  # ROW 1
339
336
  out_line_no = 0
@@ -377,15 +374,6 @@ module Cryptum
377
374
  string: header_str
378
375
  )
379
376
 
380
- order_execute_win.setpos(out_line_no, Cryptum::UI.col_fourth)
381
- order_execute_win.clrtoeol
382
- Cryptum::UI.colorize(
383
- ui_win: order_execute_win,
384
- color: header_color,
385
- style: header_style,
386
- string: ''.ljust(col_just4, ' ')
387
- )
388
-
389
377
  # ROWS 3-10
390
378
  remaining_blank_rows = 0
391
379
  remaining_blank_rows = max_rows_to_display if order_history_meta.empty?
@@ -455,13 +443,6 @@ module Cryptum
455
443
  style: style,
456
444
  string: order_exec_ln.ljust(col_just1, '.')
457
445
  )
458
-
459
- Cryptum::UI.colorize(
460
- ui_win: order_execute_win,
461
- color: meta[:color],
462
- style: style,
463
- string: ''.ljust(col_just4, ' ')
464
- )
465
446
  end
466
447
  event_history.order_execute_selected_data = selected_order
467
448
  end
@@ -512,15 +493,6 @@ module Cryptum
512
493
  string: header_str
513
494
  )
514
495
 
515
- # order_execute_win.setpos(out_line_no, Cryptum::UI.col_fourth)
516
- # order_execute_win.clrtoeol
517
- # Cryptum::UI.colorize(
518
- # ui_win: order_execute_win,
519
- # color: header_color,
520
- # style: header_style,
521
- # string: ''.ljust(col_just4, ' ')
522
- # )
523
-
524
496
  # ROW 11
525
497
  out_line_no += 1
526
498
  Cryptum::UI.line(
@@ -104,7 +104,6 @@ module Cryptum
104
104
  risk_target = fiat_budget * autotrade_cast_as_decimal
105
105
  risk_alloc = risk_target
106
106
 
107
- # TODO: Order Plan <= event_history.max_open_sell_orders
108
107
  previous_slice_fiat_investing = 0.00
109
108
  last_slice_detected = false
110
109
  loop do
@@ -190,7 +189,6 @@ module Cryptum
190
189
 
191
190
  if event_history.red_pill
192
191
  order_plan_prefix = '--'
193
- # max_order_plan_slices = '0'
194
192
  order_plan_volume_out = '0.00'
195
193
  order_plan_profit_sum_out = '0.00'
196
194
  order_plan_exec_percent = '0.00'
@@ -225,8 +223,7 @@ module Cryptum
225
223
  # TODO: Everything Above this Line Needs to be Indicators ^
226
224
 
227
225
  # UI
228
- col_just1 = (Curses.cols - Cryptum::UI.col_first) - 1
229
- col_just4 = Curses.cols - Cryptum::UI.col_fourth
226
+ col_just1 = Curses.cols - Cryptum::UI.col_first
230
227
 
231
228
  # ROW 1
232
229
  out_line_no = 0
@@ -271,14 +268,6 @@ module Cryptum
271
268
  string: header_str
272
269
  )
273
270
 
274
- order_plan_win.setpos(out_line_no, Cryptum::UI.col_fourth)
275
- Cryptum::UI.colorize(
276
- ui_win: order_plan_win,
277
- color: header_color,
278
- style: header_style,
279
- string: ''.ljust(col_just4, ' ')
280
- )
281
-
282
271
  # ROWS 3-10
283
272
  remaining_blank_rows = 0
284
273
  max_rows_to_display = event_history.order_plan_max_rows_to_display
@@ -306,14 +295,6 @@ module Cryptum
306
295
  string: red_pill_alert
307
296
  )
308
297
 
309
- order_plan_win.setpos(out_line_no, Cryptum::UI.col_fourth)
310
- Cryptum::UI.colorize(
311
- ui_win: order_plan_win,
312
- color: :red,
313
- style: :highlight,
314
- string: ''.ljust(col_just4, ' ')
315
- )
316
-
317
298
  out_line_no += 1
318
299
  order_plan_win.setpos(out_line_no, Cryptum::UI.col_first)
319
300
  order_plan_win.clrtoeol
@@ -335,13 +316,6 @@ module Cryptum
335
316
  string: red_pill_msg
336
317
  )
337
318
 
338
- order_plan_win.setpos(out_line_no, Cryptum::UI.col_fourth)
339
- Cryptum::UI.colorize(
340
- ui_win: order_plan_win,
341
- color: :yellow,
342
- string: ''.ljust(col_just4, ' ')
343
- )
344
-
345
319
  max_rows_to_display.times.each do
346
320
  out_line_no += 1
347
321
  this_matrix_row = Cryptum::UI::Matrix.generate(cols: Curses.cols)
@@ -426,13 +400,6 @@ module Cryptum
426
400
  style: style,
427
401
  string: "#{order_plan_invest}#{order_plan_return}".ljust(col_just1, '.')
428
402
  )
429
-
430
- Cryptum::UI.colorize(
431
- ui_win: order_plan_win,
432
- color: plan_color,
433
- style: style,
434
- string: ''.ljust(col_just4, ' ')
435
- )
436
403
  end
437
404
  event_history.order_plan_selected_data = selected_order
438
405
 
@@ -480,15 +447,6 @@ module Cryptum
480
447
  style: header_style,
481
448
  string: header_str
482
449
  )
483
-
484
- # order_plan_win.setpos(out_line_no, Cryptum::UI.col_fourth)
485
- # order_plan_win.clrtoeol
486
- # Cryptum::UI.colorize(
487
- # ui_win: order_plan_win,
488
- # color: header_color,
489
- # style: header_style,
490
- # string: ''.ljust(col_just4, ' ')
491
- # )
492
450
  end
493
451
 
494
452
  # ROW 11
@@ -64,9 +64,6 @@ module Cryptum
64
64
  color = indicator_status.market_trend[:color] if indicator_status.market_trend
65
65
  case color
66
66
  when :green
67
- # TODO: add condition to check if open sell orders exist.
68
- # If so intent should be something like, "- SEE ORDER HISTORY -"
69
- # Otherwise, intent should be something like, "- WAIT FOR MARKET TREND SHIFT -"
70
67
  intent = "- #{Cryptum.down_arrow} SEE ORDER HISTORY #{Cryptum.down_arrow} -"
71
68
  else
72
69
  speed = 'FAST'
@@ -40,8 +40,7 @@ module Cryptum
40
40
  # TODO: Everything Above this Line Needs to be Indicators ^
41
41
 
42
42
  # UI
43
- col_just1 = (Curses.cols - Cryptum::UI.col_first) - 1
44
- col_just4 = Curses.cols - Cryptum::UI.col_fourth
43
+ col_just1 = Curses.cols - Cryptum::UI.col_first
45
44
 
46
45
  # ROW 1
47
46
  out_line_no = 0
@@ -74,14 +73,6 @@ module Cryptum
74
73
  string: action_signal_out
75
74
  )
76
75
 
77
- signal_engine_win.setpos(out_line_no, Cryptum::UI.col_fourth)
78
- Cryptum::UI.colorize(
79
- ui_win: signal_engine_win,
80
- color: signal_color,
81
- style: :reverse,
82
- string: ''.ljust(col_just4, ' ')
83
- )
84
-
85
76
  signal_engine_win.refresh
86
77
 
87
78
  indicator_status.action_signal = action_signal
@@ -83,9 +83,6 @@ module Cryptum
83
83
  value: volume_30d
84
84
  )
85
85
 
86
- # TODO: Potential for RACE CONDITIONS - MIGRATE TO
87
- # Cryptum::Event.parse
88
- # Indicate if 24 Hour High is Reached During Sesssion
89
86
  high_24h = format(
90
87
  "%0.#{fiat_smallest_decimal}f",
91
88
  event[:high_24h]
data/lib/cryptum/ui.rb CHANGED
@@ -249,12 +249,9 @@ module Cryptum
249
249
  key_press = ui_win.get_char
250
250
 
251
251
  # Useful for detecting and logging actual key presses to file
252
- # unless key_press.nil?
253
- # File.open('/tmp/detect_key_press_in_ui-cryptum.txt', 'a') do |f|
254
- # f.puts key_press.class
255
- # f.print key_press.inspect
256
- # f.puts "\n\n\n"
257
- # end
252
+ # if key_press
253
+ # debug_keys = "#{key_press.class} => key_press.inspect\n\n\n"
254
+ # Cryptum::Log.append(level: :debug, msg: debug_keys, which_self: self)
258
255
  # end
259
256
 
260
257
  case key_press
@@ -278,6 +275,7 @@ module Cryptum
278
275
  key_press_event.key_tab = true
279
276
  end
280
277
 
278
+ # TODO: Fix this - sometimes this results in unintended behavior.
281
279
  # What a hack to detect special keys (-.-)
282
280
  if key_press_event.key_esc
283
281
  key_press_event.key_ansi = true if key_press == '['
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cryptum
4
- VERSION = '0.0.398'
4
+ VERSION = '0.0.400'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cryptum
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.398
4
+ version: 0.0.400
5
5
  platform: ruby
6
6
  authors:
7
7
  - 0day Inc.
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 2.8.2
19
+ version: 2.8.3
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: 2.8.2
26
+ version: 2.8.3
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement