nice_http 1.6.5 → 1.7.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/README.md +191 -0
- data/lib/nice_http.rb +22 -3
- data/lib/nice_http/manage_request.rb +6 -2
- data/lib/nice_http/manage_response.rb +98 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 74ab2804913e2aaa1677a20d5819d9e8a30f4689ffc3f2cc9805ec1f1bd5a9f6
|
4
|
+
data.tar.gz: 24d575ea5251c1e9a39d9af68ca794c07d0f858e95d30c72dfccdcbefa40633e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 69591afdbafca487154dd816af0eaff06edb3bfd09f877204124b9aa0978cf37f8b84a6f76d9c7f2baa5e19058d32277806226ff63b6603622065039bf7805b8
|
7
|
+
data.tar.gz: 3e0f852310ae7ecc1a47d4bed3b45df81ddd28cbde1c516c06da867562dcfb315530b508899742850aaae360477d68096117f61507b51ba1525ebfa1b5a514fa
|
data/README.md
CHANGED
@@ -351,6 +351,197 @@ Example posting a csv file:
|
|
351
351
|
|
352
352
|
```
|
353
353
|
|
354
|
+
## Http logs
|
355
|
+
|
356
|
+
You can set where the http logs will be stored by using the log attribute of the NiceHttp.
|
357
|
+
By default they will be stored in your root directory with the name nice_http.log.
|
358
|
+
```ruby
|
359
|
+
# you can specify the default for all connections
|
360
|
+
NiceHttp.log = :file_run
|
361
|
+
|
362
|
+
# also you can specify for a concrete connection
|
363
|
+
http = NiceHttp.new({host: 'www.example.com', log: './example.log'})
|
364
|
+
```
|
365
|
+
|
366
|
+
Other values you can supply:
|
367
|
+
* :fix_file, will log the communication on nice_http.log. (default).
|
368
|
+
* :no, won't generate any logs.
|
369
|
+
* :screen, will print the logs on the screen.
|
370
|
+
* :file, will be generated a log file with name: nice_http_YY-mm-dd-HHMMSS.log.
|
371
|
+
* :file_run, will generate a log file with the name where the object was created and extension .log, fex: myfile.rb.log
|
372
|
+
* String, the path and file name where the logs will be stored.
|
373
|
+
|
374
|
+
Example of logs:
|
375
|
+
```
|
376
|
+
I, [2019-03-22T18:38:58.518964 #29412] INFO -- : (47266856647720): Http connection created. host:www.reqres.in, port:443, ssl:true, mode:, proxy_host: , proxy_port:
|
377
|
+
I, [2019-03-22T18:38:58.537106 #29412] INFO -- : (47266856647720): Http connection: https://www.reqres.in:443
|
378
|
+
|
379
|
+
|
380
|
+
- - - - - - - - - - - - - - - - - - - - - - - - -
|
381
|
+
POST Request: Doom.example
|
382
|
+
path: /api/users
|
383
|
+
headers: {Loop:44, Cookie:, Boom:33, Content-Type:application/json, }
|
384
|
+
data: {
|
385
|
+
"name": "peter",
|
386
|
+
"job": "leader",
|
387
|
+
"products": [
|
388
|
+
{
|
389
|
+
"one": "uno",
|
390
|
+
"two": 2
|
391
|
+
},
|
392
|
+
{
|
393
|
+
"one": "uno",
|
394
|
+
"two": 22
|
395
|
+
}
|
396
|
+
]
|
397
|
+
}
|
398
|
+
|
399
|
+
I, [2019-03-22T18:38:58.873935 #29412] INFO -- :
|
400
|
+
RESPONSE:
|
401
|
+
201:Created
|
402
|
+
time_elapsed_total: '0.335720719'
|
403
|
+
time_elapsed: '0.335728095'
|
404
|
+
date: 'Fri, 22 Mar 2019 18:38:58 GMT'
|
405
|
+
content-type: 'application/json; charset=utf-8'
|
406
|
+
content-length: '172'
|
407
|
+
connection: 'keep-alive'
|
408
|
+
set-cookie: '__cfduid=dfb962e62cd8386ce4ab9bad601611553272738; expires=Sat, 21-Mar-20 18:38:58 GMT; path=/; domain=.reqres.in; HttpOnly'
|
409
|
+
x-powered-by: 'Express'
|
410
|
+
access-control-allow-origin: '*'
|
411
|
+
etag: 'W/"ac-EMh4XBmK5vry/OeKaGWILGtmHU0"'
|
412
|
+
expect-ct: 'max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"'
|
413
|
+
server: 'cloudflare'
|
414
|
+
cf-ray: '4bb99958090dbf89-AMS'
|
415
|
+
data: '{
|
416
|
+
"name": "peter",
|
417
|
+
"job": "leader",
|
418
|
+
"products": [
|
419
|
+
{
|
420
|
+
"one": "uno",
|
421
|
+
"two": 2
|
422
|
+
},
|
423
|
+
{
|
424
|
+
"one": "uno",
|
425
|
+
"two": 22
|
426
|
+
}
|
427
|
+
],
|
428
|
+
"id": "628",
|
429
|
+
"createdAt": "2019-03-22T18:43:33.619Z"
|
430
|
+
}'
|
431
|
+
|
432
|
+
I, [2019-03-22T18:38:58.874190 #29412] INFO -- : set-cookie added to Cookie header as required
|
433
|
+
I, [2019-03-22T18:38:59.075293 #29412] INFO -- :
|
434
|
+
|
435
|
+
- - - - - - - - - - - - - - - - - - - - - - - - -
|
436
|
+
GET Request: Doom.example
|
437
|
+
path: /api/users
|
438
|
+
Same headers and data as in the previous request.
|
439
|
+
I, [2019-03-22T18:38:59.403459 #29412] INFO -- :
|
440
|
+
RESPONSE:
|
441
|
+
200:OK
|
442
|
+
time_elapsed_total: '0.327002338'
|
443
|
+
time_elapsed: '0.327004766'
|
444
|
+
date: 'Fri, 22 Mar 2019 18:38:59 GMT'
|
445
|
+
content-type: 'application/json; charset=utf-8'
|
446
|
+
transfer-encoding: 'chunked'
|
447
|
+
connection: 'keep-alive'
|
448
|
+
x-powered-by: 'Express'
|
449
|
+
access-control-allow-origin: '*'
|
450
|
+
etag: 'W/"1bb-D+c3sZ5g5u/nmLPQRl1uVo2heAo"'
|
451
|
+
expect-ct: 'max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"'
|
452
|
+
server: 'cloudflare'
|
453
|
+
cf-ray: '4bb9995b5c20bf89-AMS'
|
454
|
+
data: '{
|
455
|
+
"page": 1,
|
456
|
+
"per_page": 3,
|
457
|
+
"total": 12,
|
458
|
+
"total_pages": 4,
|
459
|
+
"data": [
|
460
|
+
{
|
461
|
+
"id": 1,
|
462
|
+
"first_name": "George",
|
463
|
+
"last_name": "Bluth",
|
464
|
+
"avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/calebogden/128.jpg"
|
465
|
+
},
|
466
|
+
{
|
467
|
+
"id": 2,
|
468
|
+
"first_name": "Janet",
|
469
|
+
"last_name": "Weaver",
|
470
|
+
"avatar": "https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128.jpg"
|
471
|
+
},
|
472
|
+
]
|
473
|
+
}'
|
474
|
+
|
475
|
+
```
|
476
|
+
|
477
|
+
## Http stats
|
478
|
+
|
479
|
+
If you want to get a summarize stats of your http communication you need to set `NiceHttp.create_stats = true`
|
480
|
+
|
481
|
+
Then whenever you want to access the stats: `NiceHttp.stats`
|
482
|
+
|
483
|
+
Also it is very convenient to store the stats on a file, for example on YAML format. You can use the at_exit method to be run at the end of the run:
|
484
|
+
|
485
|
+
```ruby
|
486
|
+
at_exit do
|
487
|
+
require 'yaml'
|
488
|
+
NiceHttp.stats.keys.each do |key|
|
489
|
+
File.open("./nice_http_stats_#{key}.yaml", "w") { |file| file.write(NiceHttp.stats[key].to_yaml) }
|
490
|
+
end
|
491
|
+
end
|
492
|
+
```
|
493
|
+
|
494
|
+
This is an example of the output:
|
495
|
+
|
496
|
+
```yaml
|
497
|
+
---
|
498
|
+
www.reqres.in:443:
|
499
|
+
:num_requests: 11
|
500
|
+
:time_elapsed:
|
501
|
+
:total: 2.947269038
|
502
|
+
:maximum: 0.357101109
|
503
|
+
:minimum: 0.198707111
|
504
|
+
:average: 0.2679335489090909
|
505
|
+
"/api/users":
|
506
|
+
:num_requests: 11
|
507
|
+
:time_elapsed:
|
508
|
+
:total: 2.947269038
|
509
|
+
:maximum: 0.357101109
|
510
|
+
:minimum: 0.198707111
|
511
|
+
:average: 0.2679335489090909
|
512
|
+
:method:
|
513
|
+
POST:
|
514
|
+
:num_requests: 8
|
515
|
+
:time_elapsed:
|
516
|
+
:total: 2.3342455970000002
|
517
|
+
:maximum: 0.357101109
|
518
|
+
:minimum: 0.198707111
|
519
|
+
:average: 0.29178069962500003
|
520
|
+
:response:
|
521
|
+
'201':
|
522
|
+
:num_requests: 8
|
523
|
+
:time_elapsed:
|
524
|
+
:total: 2.3342455970000002
|
525
|
+
:maximum: 0.357101109
|
526
|
+
:minimum: 0.198707111
|
527
|
+
:average: 0.29178069962500003
|
528
|
+
GET:
|
529
|
+
:num_requests: 3
|
530
|
+
:time_elapsed:
|
531
|
+
:total: 0.613023441
|
532
|
+
:maximum: 0.210662528
|
533
|
+
:minimum: 0.200197583
|
534
|
+
:average: 0.20434114699999997
|
535
|
+
:response:
|
536
|
+
'200':
|
537
|
+
:num_requests: 3
|
538
|
+
:time_elapsed:
|
539
|
+
:total: 0.613023441
|
540
|
+
:maximum: 0.210662528
|
541
|
+
:minimum: 0.200197583
|
542
|
+
:average: 0.20434114699999997
|
543
|
+
```
|
544
|
+
|
354
545
|
## Contributing
|
355
546
|
|
356
547
|
Bug reports are very welcome on GitHub at https://github.com/marioruiz/nice_http.
|
data/lib/nice_http.rb
CHANGED
@@ -9,7 +9,7 @@ require_relative "nice_http/http_methods"
|
|
9
9
|
# Attributes you can access using NiceHttp.the_attribute:
|
10
10
|
# :host, :port, :ssl, :headers, :debug, :log, :proxy_host, :proxy_port,
|
11
11
|
# :last_request, :last_response, :request_id, :use_mocks, :connections,
|
12
|
-
# :active, :auto_redirect, :values_for
|
12
|
+
# :active, :auto_redirect, :values_for, :create_stats, :stats
|
13
13
|
#
|
14
14
|
# @attr [String] host The host to be accessed
|
15
15
|
# @attr [Integer] port The port number
|
@@ -41,6 +41,8 @@ require_relative "nice_http/http_methods"
|
|
41
41
|
# my_http.logger.info "add this to the log file"
|
42
42
|
# @see https://ruby-doc.org/stdlib-2.5.0/libdoc/logger/rdoc/Logger.html
|
43
43
|
# @attr [Hash] values_for The default values to set on the data in case not specified others
|
44
|
+
# @attr [Boolean] create_stats If true, NiceHttp will create stats of the http communication and store them on NiceHttp.stats hash
|
45
|
+
# @attr [Hash] stats It contains detailed stats of the http communication
|
44
46
|
######################################################
|
45
47
|
class NiceHttp
|
46
48
|
include NiceHttpManageRequest
|
@@ -64,7 +66,7 @@ class NiceHttp
|
|
64
66
|
class << self
|
65
67
|
attr_accessor :host, :port, :ssl, :headers, :debug, :log, :proxy_host, :proxy_port,
|
66
68
|
:last_request, :last_response, :request_id, :use_mocks, :connections,
|
67
|
-
:active, :auto_redirect, :log_files, :values_for
|
69
|
+
:active, :auto_redirect, :log_files, :values_for, :create_stats, :stats
|
68
70
|
end
|
69
71
|
|
70
72
|
######################################################
|
@@ -88,6 +90,21 @@ class NiceHttp
|
|
88
90
|
@active = 0
|
89
91
|
@auto_redirect = true
|
90
92
|
@log_files = {}
|
93
|
+
@create_stats = false
|
94
|
+
@stats = {
|
95
|
+
all: {
|
96
|
+
num_requests: 0,
|
97
|
+
time_elapsed: {
|
98
|
+
total: 0,
|
99
|
+
maximum: 0,
|
100
|
+
minimum: 100000,
|
101
|
+
average: 0,
|
102
|
+
},
|
103
|
+
method: {},
|
104
|
+
},
|
105
|
+
path: {},
|
106
|
+
name: {},
|
107
|
+
}
|
91
108
|
end
|
92
109
|
reset!
|
93
110
|
|
@@ -104,7 +121,7 @@ class NiceHttp
|
|
104
121
|
######################################################
|
105
122
|
# Change the default values for NiceHttp supplying a Hash
|
106
123
|
#
|
107
|
-
# @param par [Hash] keys: :host, :port, :ssl, :headers, :debug, :log, :proxy_host, :proxy_port, :use_mocks, :auto_redirect, :values_for
|
124
|
+
# @param par [Hash] keys: :host, :port, :ssl, :headers, :debug, :log, :proxy_host, :proxy_port, :use_mocks, :auto_redirect, :values_for, :create_stats
|
108
125
|
######################################################
|
109
126
|
def self.defaults=(par = {})
|
110
127
|
@host = par[:host] if par.key?(:host)
|
@@ -118,6 +135,7 @@ class NiceHttp
|
|
118
135
|
@proxy_port = par[:proxy_port] if par.key?(:proxy_port)
|
119
136
|
@use_mocks = par[:use_mocks] if par.key?(:use_mocks)
|
120
137
|
@auto_redirect = par[:auto_redirect] if par.key?(:auto_redirect)
|
138
|
+
@create_stats = par[:create_stats] if par.key?(:create_stats)
|
121
139
|
end
|
122
140
|
|
123
141
|
######################################################
|
@@ -184,6 +202,7 @@ class NiceHttp
|
|
184
202
|
@auto_redirect = false #set it up at the end of initialize
|
185
203
|
auto_redirect = self.class.auto_redirect
|
186
204
|
@num_redirects = 0
|
205
|
+
@create_stats = self.class.create_stats
|
187
206
|
|
188
207
|
#todo: set only the cookies for the current domain
|
189
208
|
#key: path, value: hash with key is the name of the cookie and value the value
|
@@ -191,7 +191,7 @@ module NiceHttpManageRequest
|
|
191
191
|
|
192
192
|
headers_ts = ""
|
193
193
|
headers_t.each { |key, val| headers_ts += key.to_s + ":" + val.to_s() + ", " }
|
194
|
-
message = "#{"- " * 25}\n"
|
194
|
+
message = "\n\n#{"- " * 25}\n"
|
195
195
|
if arguments.size == 1 and arguments[0].kind_of?(Hash) and arguments[0].key?(:name)
|
196
196
|
message += "#{method_s.upcase} Request: #{arguments[0][:name]}"
|
197
197
|
else
|
@@ -203,7 +203,7 @@ module NiceHttpManageRequest
|
|
203
203
|
message += " data: " + data_s.to_s() + "\n"
|
204
204
|
message = @message_server + "\n" + message
|
205
205
|
else
|
206
|
-
message += " Same as the
|
206
|
+
message += " Same#{" headers" if headers_t != {}}#{" and" if headers_t != {} and data.to_s != ""}#{" data" if data.to_s != ""} as in the previous request."
|
207
207
|
end
|
208
208
|
if path.to_s().scan(/^https?:\/\//).size > 0 and path.to_s().scan(/^https?:\/\/#{@host}/).size == 0
|
209
209
|
# the path is for another server than the current
|
@@ -219,6 +219,10 @@ module NiceHttpManageRequest
|
|
219
219
|
@prev_request[:path] = path
|
220
220
|
@prev_request[:data] = data
|
221
221
|
@prev_request[:headers] = headers_t
|
222
|
+
@prev_request[:method] = method_s.upcase
|
223
|
+
if arguments.size == 1 and arguments[0].kind_of?(Hash) and arguments[0].key?(:name)
|
224
|
+
@prev_request[:name] = arguments[0][:name]
|
225
|
+
end
|
222
226
|
return path, data, headers_t
|
223
227
|
rescue Exception => stack
|
224
228
|
@logger.fatal(stack)
|
@@ -24,6 +24,9 @@ module NiceHttpManageResponse
|
|
24
24
|
else
|
25
25
|
@response[:time_elapsed] = nil
|
26
26
|
end
|
27
|
+
|
28
|
+
create_stats(resp) if @create_stats
|
29
|
+
|
27
30
|
begin
|
28
31
|
# this is to be able to access all keys as symbols
|
29
32
|
new_resp = Hash.new()
|
@@ -90,8 +93,8 @@ module NiceHttpManageResponse
|
|
90
93
|
|
91
94
|
@response[:code] = resp.code
|
92
95
|
message = "\nRESPONSE: \n " + @response[:code].to_s() + ":" + @response[:message].to_s()
|
93
|
-
if @debug or @prev_response[:'content-type']
|
94
|
-
|
96
|
+
if @debug or @prev_response[:'content-type'] != @response[:'content-type'] or @prev_response[:'content-length'] != @response[:'content-length'] or
|
97
|
+
@prev_response[:data] != @response[:data] or @prev_response[:code] != @response[:code] or @prev_response[:message] != @response[:message]
|
95
98
|
self.class.last_response = message if @debug
|
96
99
|
@response.each { |key, value|
|
97
100
|
if value.to_s() != ""
|
@@ -180,4 +183,97 @@ module NiceHttpManageResponse
|
|
180
183
|
@logger.fatal "manage_response Error on method #{method_s} "
|
181
184
|
end
|
182
185
|
end
|
186
|
+
|
187
|
+
private
|
188
|
+
|
189
|
+
def set_stats(hash)
|
190
|
+
unless hash.key?(:num_requests)
|
191
|
+
# to add to the end the previous keys so num_requests and time_elapsed come first
|
192
|
+
keys = hash.keys
|
193
|
+
hash.keys.each do |k|
|
194
|
+
hash.delete(k)
|
195
|
+
end
|
196
|
+
|
197
|
+
hash[:num_requests] = 0
|
198
|
+
hash[:time_elapsed] = {
|
199
|
+
total: 0,
|
200
|
+
maximum: 0,
|
201
|
+
minimum: 100000,
|
202
|
+
average: 0,
|
203
|
+
}
|
204
|
+
|
205
|
+
# to add to the end the previous keys so num_requests and time_elapsed come first
|
206
|
+
keys.each do |k|
|
207
|
+
hash[k] = {}
|
208
|
+
end
|
209
|
+
end
|
210
|
+
hash[:num_requests] += 1
|
211
|
+
hash[:time_elapsed][:total] += @response[:time_elapsed]
|
212
|
+
hash[:time_elapsed][:maximum] = @response[:time_elapsed] if @response[:time_elapsed] > hash[:time_elapsed][:maximum]
|
213
|
+
hash[:time_elapsed][:minimum] = @response[:time_elapsed] if @response[:time_elapsed] < hash[:time_elapsed][:minimum]
|
214
|
+
hash[:time_elapsed][:average] = hash[:time_elapsed][:total] / hash[:num_requests]
|
215
|
+
end
|
216
|
+
|
217
|
+
private
|
218
|
+
|
219
|
+
def create_stats(resp)
|
220
|
+
# all
|
221
|
+
set_stats(self.class.stats[:all])
|
222
|
+
# all method
|
223
|
+
unless self.class.stats[:all][:method].key?(@prev_request[:method])
|
224
|
+
self.class.stats[:all][:method][@prev_request[:method]] = {
|
225
|
+
response: {},
|
226
|
+
}
|
227
|
+
end
|
228
|
+
set_stats(self.class.stats[:all][:method][@prev_request[:method]])
|
229
|
+
# all method response
|
230
|
+
unless self.class.stats[:all][:method][@prev_request[:method]][:response].key?(resp.code)
|
231
|
+
self.class.stats[:all][:method][@prev_request[:method]][:response][resp.code] = {}
|
232
|
+
end
|
233
|
+
set_stats(self.class.stats[:all][:method][@prev_request[:method]][:response][resp.code])
|
234
|
+
|
235
|
+
# server
|
236
|
+
server = "#{@host}:#{@port}"
|
237
|
+
unless self.class.stats[:path].key?(server)
|
238
|
+
self.class.stats[:path][server] = {}
|
239
|
+
end
|
240
|
+
set_stats(self.class.stats[:path][server])
|
241
|
+
# server path
|
242
|
+
unless self.class.stats[:path][server].key?(@prev_request[:path])
|
243
|
+
self.class.stats[:path][server][@prev_request[:path]] = {method: {}}
|
244
|
+
end
|
245
|
+
set_stats(self.class.stats[:path][server][@prev_request[:path]])
|
246
|
+
# server path method
|
247
|
+
unless self.class.stats[:path][server][@prev_request[:path]][:method].key?(@prev_request[:method])
|
248
|
+
self.class.stats[:path][server][@prev_request[:path]][:method][@prev_request[:method]] = {
|
249
|
+
response: {},
|
250
|
+
}
|
251
|
+
end
|
252
|
+
set_stats(self.class.stats[:path][server][@prev_request[:path]][:method][@prev_request[:method]])
|
253
|
+
# server path method response
|
254
|
+
unless self.class.stats[:path][server][@prev_request[:path]][:method][@prev_request[:method]][:response].key?(resp.code)
|
255
|
+
self.class.stats[:path][server][@prev_request[:path]][:method][@prev_request[:method]][:response][resp.code] = {}
|
256
|
+
end
|
257
|
+
set_stats(self.class.stats[:path][server][@prev_request[:path]][:method][@prev_request[:method]][:response][resp.code])
|
258
|
+
|
259
|
+
if @prev_request.key?(:name)
|
260
|
+
# name
|
261
|
+
unless self.class.stats[:name].key?(@prev_request[:name])
|
262
|
+
self.class.stats[:name][@prev_request[:name]] = {method: {}}
|
263
|
+
end
|
264
|
+
set_stats(self.class.stats[:name][@prev_request[:name]])
|
265
|
+
# name method
|
266
|
+
unless self.class.stats[:name][@prev_request[:name]][:method].key?(@prev_request[:method])
|
267
|
+
self.class.stats[:name][@prev_request[:name]][:method][@prev_request[:method]] = {
|
268
|
+
response: {},
|
269
|
+
}
|
270
|
+
end
|
271
|
+
set_stats(self.class.stats[:name][@prev_request[:name]][:method][@prev_request[:method]])
|
272
|
+
# name method response
|
273
|
+
unless self.class.stats[:name][@prev_request[:name]][:method][@prev_request[:method]][:response].key?(resp.code)
|
274
|
+
self.class.stats[:name][@prev_request[:name]][:method][@prev_request[:method]][:response][resp.code] = {}
|
275
|
+
end
|
276
|
+
set_stats(self.class.stats[:name][@prev_request[:name]][:method][@prev_request[:method]][:response][resp.code])
|
277
|
+
end
|
278
|
+
end
|
183
279
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nice_http
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mario Ruiz
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-03-
|
11
|
+
date: 2019-03-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nice_hash
|