terminal-shop 1.1.0 → 1.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 751da463435546aa646463c23f281021151b8416d6d96abd3fcb607cb4f1d2dd
4
- data.tar.gz: 9b4b300351f7f8752b18fe11098c91b6c77fd805859f9d91aa90d85e04e4a5fe
3
+ metadata.gz: 974257e90aeb93cf152e34de6ea7351f727f6e6ee95e04415b290b90f648a251
4
+ data.tar.gz: 7de2c3d22ad41f81fe735d5fb3018b99a9a15350c4faa35b4f316f4ab0ae822a
5
5
  SHA512:
6
- metadata.gz: 200d08ede71db6dc925f78727b3e15474e825400e8ef73da2affa1ad6991b4f2832cdfe363c3b3348d308ccd5a6127288d9beea6263f819c232cbbbb82c28a6a
7
- data.tar.gz: 433ff5cef723e81a8fef27c0d48a8e6a7cf30a3f051b1ad454cc2fc9d1e7b05e0bf70f7a995254ec265c0f2c48a980ab0a809122b885cba976de93bcf0066d7f
6
+ metadata.gz: 8f6a23136217de3ea26e0bed3db6f7ca39ced5bd099b681fd3f61cc50fdc8b4eb8d3c48591049a7d19e21c107cf7abc576a1bc714bf012ec35a4fa7eda2a46cb
7
+ data.tar.gz: e8145d5a065574cf2f972f33978247fc21a1a9f9c935ced9d30aaae9d346aed51bc52f6e71b1555cbc089628dfb97c5d740aa2b2a8c2a43752c21253cd2afdd7
@@ -457,8 +457,10 @@ module TerminalShop
457
457
  # @return [String]
458
458
  #
459
459
  def inspect
460
+ # rubocop:disable Layout/LineLength
460
461
  base_url = TerminalShop::Util.unparse_uri(@base_url)
461
462
  "#<#{self.class.name}:0x#{object_id.to_s(16)} base_url=#{base_url} max_retries=#{@max_retries} timeout=#{@timeout}>"
463
+ # rubocop:enable Layout/LineLength
462
464
  end
463
465
  end
464
466
  end
@@ -55,11 +55,11 @@ module TerminalShop
55
55
  type_info(spec.slice(:const, :enum, :union).first&.last)
56
56
  in Proc
57
57
  spec
58
- in TerminalShop::Converter | Class
58
+ in TerminalShop::Converter | Class | Symbol
59
59
  -> { spec }
60
60
  in true | false
61
61
  -> { TerminalShop::BooleanModel }
62
- in NilClass | true | false | Symbol | Integer | Float
62
+ in NilClass | Integer | Float
63
63
  -> { spec.class }
64
64
  end
65
65
  end
@@ -82,6 +82,13 @@ module TerminalShop
82
82
  case target
83
83
  in TerminalShop::Converter
84
84
  target.coerce(value)
85
+ in Symbol
86
+ case value
87
+ in Symbol | String if (val = value.to_sym) == target
88
+ val
89
+ else
90
+ value
91
+ end
85
92
  in Class
86
93
  case target
87
94
  in -> { _1 <= NilClass }
@@ -140,6 +147,13 @@ module TerminalShop
140
147
  case target
141
148
  in TerminalShop::Converter
142
149
  target.try_strict_coerce(value)
150
+ in Symbol
151
+ case value
152
+ in Symbol | String if (val = value.to_sym) == target
153
+ [true, val, 1]
154
+ else
155
+ [false, false, 0]
156
+ end
143
157
  in Class
144
158
  case [target, value]
145
159
  in [-> { _1 <= NilClass }, _]
@@ -338,7 +352,14 @@ module TerminalShop
338
352
  #
339
353
  # @return [Symbol, Object]
340
354
  #
341
- def coerce(value) = (value.is_a?(String) ? value.to_sym : value)
355
+ def coerce(value)
356
+ case value
357
+ in Symbol | String if values.include?(val = value.to_sym)
358
+ val
359
+ else
360
+ value
361
+ end
362
+ end
342
363
 
343
364
  # @!parse
344
365
  # # @private
@@ -359,7 +380,7 @@ module TerminalShop
359
380
  return [true, value, 1] if values.include?(value)
360
381
 
361
382
  case value
362
- in String if values.include?(val = value.to_sym)
383
+ in Symbol | String if values.include?(val = value.to_sym)
363
384
  [true, val, 1]
364
385
  else
365
386
  case [value, values.first]
@@ -5,6 +5,26 @@ module TerminalShop
5
5
  #
6
6
  # @abstract
7
7
  #
8
+ # @example
9
+ # ```ruby
10
+ # if page.has_next?
11
+ # page = page.next_page
12
+ # end
13
+ # ```
14
+ #
15
+ # @example
16
+ # ```ruby
17
+ # page.auto_paging_each do |product|
18
+ # puts(product)
19
+ # end
20
+ # ```
21
+ #
22
+ # @example
23
+ # ```ruby
24
+ # products = page.to_enum.take(2)
25
+ #
26
+ # products => Array
27
+ # ```
8
28
  module BasePage
9
29
  # @return [Boolean]
10
30
  #
@@ -48,9 +48,11 @@ module TerminalShop
48
48
  #
49
49
  # @option request [Hash{String=>String}] :headers
50
50
  #
51
+ # @param blk [Proc]
52
+ #
51
53
  # @return [Net::HTTPGenericRequest]
52
54
  #
53
- def build_request(request)
55
+ def build_request(request, &)
54
56
  method, url, headers, body = request.fetch_values(:method, :url, :headers, :body)
55
57
  req = Net::HTTPGenericRequest.new(
56
58
  method.to_s.upcase,
@@ -64,12 +66,14 @@ module TerminalShop
64
66
  case body
65
67
  in nil
66
68
  in String
67
- req.body = body
69
+ req["content-length"] ||= body.bytesize.to_s unless req["transfer-encoding"]
70
+ req.body_stream = TerminalShop::Util::ReadIOAdapter.new(body, &)
68
71
  in StringIO
69
- req.body = body.string
70
- in IO
71
- body.rewind
72
- req.body_stream = body
72
+ req["content-length"] ||= body.size.to_s unless req["transfer-encoding"]
73
+ req.body_stream = TerminalShop::Util::ReadIOAdapter.new(body, &)
74
+ in IO | Enumerator
75
+ req["transfer-encoding"] ||= "chunked" unless req["content-length"]
76
+ req.body_stream = TerminalShop::Util::ReadIOAdapter.new(body, &)
73
77
  end
74
78
 
75
79
  req
@@ -97,7 +101,7 @@ module TerminalShop
97
101
 
98
102
  pool =
99
103
  @mutex.synchronize do
100
- @pools[origin] ||= ConnectionPool.new(size: Etc.nprocessors) do
104
+ @pools[origin] ||= ConnectionPool.new(size: @size) do
101
105
  self.class.connect(url)
102
106
  end
103
107
  end
@@ -128,7 +132,6 @@ module TerminalShop
128
132
  #
129
133
  def execute(request)
130
134
  url, deadline = request.fetch_values(:url, :deadline)
131
- req = self.class.build_request(request)
132
135
 
133
136
  eof = false
134
137
  finished = false
@@ -136,6 +139,10 @@ module TerminalShop
136
139
  with_pool(url) do |conn|
137
140
  next if finished
138
141
 
142
+ req = self.class.build_request(request) do
143
+ self.class.calibrate_socket_timeout(conn, deadline)
144
+ end
145
+
139
146
  self.class.calibrate_socket_timeout(conn, deadline)
140
147
  conn.start unless conn.started?
141
148
 
@@ -156,19 +163,25 @@ module TerminalShop
156
163
  end
157
164
 
158
165
  conn, response = enum.next
159
- body = TerminalShop::Util.fused_enum(enum) do
166
+ body = TerminalShop::Util.fused_enum(enum, external: true) do
160
167
  finished = true
161
168
  tap do
162
169
  enum.next
163
170
  rescue StopIteration
171
+ nil
164
172
  end
165
173
  conn.finish if !eof && conn&.started?
166
174
  end
167
175
  [response, (response.body = body)]
168
176
  end
169
177
 
170
- def initialize
178
+ # @private
179
+ #
180
+ # @param size [Integer]
181
+ #
182
+ def initialize(size: Etc.nprocessors)
171
183
  @mutex = Mutex.new
184
+ @size = size
172
185
  @pools = {}
173
186
  end
174
187
  end
@@ -399,41 +399,152 @@ module TerminalShop
399
399
  end
400
400
  end
401
401
 
402
+ # @private
403
+ #
404
+ # An adapter that satisfies the IO interface required by `::IO.copy_stream`
405
+ class ReadIOAdapter
406
+ # @private
407
+ #
408
+ # @param max_len [Integer, nil]
409
+ #
410
+ # @return [String]
411
+ #
412
+ private def read_enum(max_len)
413
+ case max_len
414
+ in nil
415
+ @stream.to_a.join
416
+ in Integer
417
+ @buf << @stream.next while @buf.length < max_len
418
+ @buf.slice!(..max_len)
419
+ end
420
+ rescue StopIteration
421
+ @stream = nil
422
+ @buf.slice!(0..)
423
+ end
424
+
425
+ # @private
426
+ #
427
+ # @param max_len [Integer, nil]
428
+ # @param out_string [String, nil]
429
+ #
430
+ # @return [String, nil]
431
+ #
432
+ def read(max_len = nil, out_string = nil)
433
+ case @stream
434
+ in nil
435
+ nil
436
+ in IO | StringIO
437
+ @stream.read(max_len, out_string)
438
+ in Enumerator
439
+ read = read_enum(max_len)
440
+ case out_string
441
+ in String
442
+ out_string.replace(read)
443
+ in nil
444
+ read
445
+ end
446
+ end
447
+ .tap(&@blk)
448
+ end
449
+
450
+ # @private
451
+ #
452
+ # @param stream [String, IO, StringIO, Enumerable]
453
+ # @param blk [Proc]
454
+ #
455
+ def initialize(stream, &blk)
456
+ @stream = stream.is_a?(String) ? StringIO.new(stream) : stream
457
+ @buf = String.new.b
458
+ @blk = blk
459
+ end
460
+ end
461
+
462
+ class << self
463
+ # @param blk [Proc]
464
+ #
465
+ # @return [Enumerable]
466
+ #
467
+ def string_io(&blk)
468
+ Enumerator.new do |y|
469
+ y.define_singleton_method(:write) do
470
+ self << _1.clone
471
+ _1.bytesize
472
+ end
473
+
474
+ blk.call(y)
475
+ end
476
+ end
477
+ end
478
+
402
479
  class << self
403
480
  # @private
404
481
  #
405
- # @param io [StringIO]
482
+ # @param y [Enumerator::Yielder]
406
483
  # @param boundary [String]
407
484
  # @param key [Symbol, String]
408
485
  # @param val [Object]
409
486
  #
410
- private def encode_multipart_formdata(io, boundary:, key:, val:)
411
- io << "--#{boundary}\r\n"
412
- io << "Content-Disposition: form-data"
487
+ private def encode_multipart_formdata(y, boundary:, key:, val:)
488
+ y << "--#{boundary}\r\n"
489
+ y << "Content-Disposition: form-data"
413
490
  unless key.nil?
414
491
  name = ERB::Util.url_encode(key.to_s)
415
- io << "; name=\"#{name}\""
492
+ y << "; name=\"#{name}\""
416
493
  end
417
494
  if val.is_a?(IO)
418
495
  filename = ERB::Util.url_encode(File.basename(val.to_path))
419
- io << "; filename=\"#{filename}\""
496
+ y << "; filename=\"#{filename}\""
420
497
  end
421
- io << "\r\n"
498
+ y << "\r\n"
422
499
  case val
423
- in IO | StringIO
424
- io << "Content-Type: application/octet-stream\r\n\r\n"
425
- IO.copy_stream(val, io)
500
+ in IO
501
+ y << "Content-Type: application/octet-stream\r\n\r\n"
502
+ IO.copy_stream(val, y)
503
+ in StringIO
504
+ y << "Content-Type: application/octet-stream\r\n\r\n"
505
+ y << val.string
426
506
  in String
427
- io << "Content-Type: application/octet-stream\r\n\r\n"
428
- io << val.to_s
507
+ y << "Content-Type: application/octet-stream\r\n\r\n"
508
+ y << val.to_s
429
509
  in true | false | Integer | Float | Symbol
430
- io << "Content-Type: text/plain\r\n\r\n"
431
- io << val.to_s
510
+ y << "Content-Type: text/plain\r\n\r\n"
511
+ y << val.to_s
432
512
  else
433
- io << "Content-Type: application/json\r\n\r\n"
434
- io << JSON.fast_generate(val)
513
+ y << "Content-Type: application/json\r\n\r\n"
514
+ y << JSON.fast_generate(val)
515
+ end
516
+ y << "\r\n"
517
+ end
518
+
519
+ # @private
520
+ #
521
+ # @param body [Object]
522
+ #
523
+ # @return [Array(String, Enumerable)]
524
+ #
525
+ private def encode_multipart_streaming(body)
526
+ boundary = SecureRandom.urlsafe_base64(60)
527
+
528
+ strio = string_io do |y|
529
+ case body
530
+ in Hash
531
+ body.each do |key, val|
532
+ case val
533
+ in Array if val.all? { primitive?(_1) }
534
+ val.each do |v|
535
+ encode_multipart_formdata(y, boundary: boundary, key: key, val: v)
536
+ end
537
+ else
538
+ encode_multipart_formdata(y, boundary: boundary, key: key, val: val)
539
+ end
540
+ end
541
+ else
542
+ encode_multipart_formdata(y, boundary: boundary, key: nil, val: body)
543
+ end
544
+ y << "--#{boundary}--\r\n"
435
545
  end
436
- io << "\r\n"
546
+
547
+ [boundary, strio]
437
548
  end
438
549
 
439
550
  # @private
@@ -449,37 +560,11 @@ module TerminalShop
449
560
  in ["application/json", Hash | Array]
450
561
  [headers, JSON.fast_generate(body)]
451
562
  in [%r{^multipart/form-data}, Hash | IO | StringIO]
452
- boundary = SecureRandom.urlsafe_base64(60)
453
- strio = StringIO.new.tap do |io|
454
- case body
455
- in Hash
456
- body.each do |key, val|
457
- case val
458
- in Array if val.all? { primitive?(_1) }
459
- val.each do |v|
460
- encode_multipart_formdata(io, boundary: boundary, key: key, val: v)
461
- end
462
- else
463
- encode_multipart_formdata(io, boundary: boundary, key: key, val: val)
464
- end
465
- end
466
- else
467
- encode_multipart_formdata(io, boundary: boundary, key: nil, val: body)
468
- end
469
- io << "--#{boundary}--\r\n"
470
- io.rewind
471
- end
472
- headers = {
473
- **headers,
474
- "content-type" => "#{content_type}; boundary=#{boundary}",
475
- "transfer-encoding" => "chunked"
476
- }
563
+ boundary, strio = encode_multipart_streaming(body)
564
+ headers = {**headers, "content-type" => "#{content_type}; boundary=#{boundary}"}
477
565
  [headers, strio]
478
566
  in [_, StringIO]
479
567
  [headers, body.string]
480
- in [_, IO]
481
- headers = {**headers, "transfer-encoding" => "chunked"}
482
- [headers, body]
483
568
  else
484
569
  [headers, body]
485
570
  end
@@ -524,17 +609,22 @@ module TerminalShop
524
609
  # https://doc.rust-lang.org/std/iter/trait.FusedIterator.html
525
610
  #
526
611
  # @param enum [Enumerable]
612
+ # @param external [Boolean]
527
613
  # @param close [Proc]
528
614
  #
529
615
  # @return [Enumerable]
530
616
  #
531
- def fused_enum(enum, &close)
617
+ def fused_enum(enum, external: false, &close)
532
618
  fused = false
533
619
  iter = Enumerator.new do |y|
534
620
  next if fused
535
621
 
536
622
  fused = true
537
- loop { y << enum.next }
623
+ if external
624
+ loop { y << enum.next }
625
+ else
626
+ enum.each(&y)
627
+ end
538
628
  ensure
539
629
  close&.call
540
630
  close = nil
@@ -584,8 +674,9 @@ module TerminalShop
584
674
 
585
675
  chain_fused(enum) do |y|
586
676
  enum.each do |row|
677
+ offset = buffer.bytesize
587
678
  buffer << row
588
- while (match = re.match(buffer, cr_seen.to_i))
679
+ while (match = re.match(buffer, cr_seen&.to_i || offset))
589
680
  case [match.captures.first, cr_seen]
590
681
  in ["\r", nil]
591
682
  cr_seen = match.end(1)
@@ -595,6 +686,7 @@ module TerminalShop
595
686
  else
596
687
  y << buffer.slice!(..(match.end(1).pred))
597
688
  end
689
+ offset = 0
598
690
  cr_seen = nil
599
691
  end
600
692
  end
@@ -613,6 +705,7 @@ module TerminalShop
613
705
  # @return [Hash{Symbol=>Object}]
614
706
  #
615
707
  def decode_sse(lines)
708
+ # rubocop:disable Metrics/BlockLength
616
709
  chain_fused(lines) do |y|
617
710
  blank = {event: nil, data: nil, id: nil, retry: nil}
618
711
  current = {}
@@ -631,7 +724,7 @@ module TerminalShop
631
724
  in "event"
632
725
  current.merge!(event: value)
633
726
  in "data"
634
- (current[:data] ||= String.new.b) << value << "\n"
727
+ (current[:data] ||= String.new.b) << (value << "\n")
635
728
  in "id" unless value.include?("\0")
636
729
  current.merge!(id: value)
637
730
  in "retry" if /^\d+$/ =~ value
@@ -641,6 +734,7 @@ module TerminalShop
641
734
  else
642
735
  end
643
736
  end
737
+ # rubocop:enable Metrics/BlockLength
644
738
 
645
739
  y << {**blank, **current} unless current.empty?
646
740
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TerminalShop
4
- VERSION = "1.1.0"
4
+ VERSION = "1.2.0"
5
5
  end
@@ -15,8 +15,11 @@ module TerminalShop
15
15
  def calibrate_socket_timeout(conn, deadline)
16
16
  end
17
17
 
18
- sig { params(request: TerminalShop::PooledNetRequester::RequestShape).returns(Net::HTTPGenericRequest) }
19
- def build_request(request)
18
+ sig do
19
+ params(request: TerminalShop::PooledNetRequester::RequestShape, blk: T.proc.params(arg0: String).void)
20
+ .returns(Net::HTTPGenericRequest)
21
+ end
22
+ def build_request(request, &blk)
20
23
  end
21
24
  end
22
25
 
@@ -31,8 +34,8 @@ module TerminalShop
31
34
  def execute(request)
32
35
  end
33
36
 
34
- sig { returns(T.attached_class) }
35
- def self.new
37
+ sig { params(size: Integer).returns(T.attached_class) }
38
+ def self.new(size: Etc.nprocessors)
36
39
  end
37
40
  end
38
41
  end
@@ -131,9 +131,41 @@ module TerminalShop
131
131
  end
132
132
  end
133
133
 
134
+ class ReadIOAdapter
135
+ sig { params(max_len: T.nilable(Integer)).returns(String) }
136
+ private def read_enum(max_len)
137
+ end
138
+
139
+ sig { params(max_len: T.nilable(Integer), out_string: T.nilable(String)).returns(T.nilable(String)) }
140
+ def read(max_len = nil, out_string = nil)
141
+ end
142
+
143
+ sig do
144
+ params(
145
+ stream: T.any(String, IO, StringIO, T::Enumerable[String]),
146
+ blk: T.proc.params(arg0: String).void
147
+ )
148
+ .returns(T.attached_class)
149
+ end
150
+ def self.new(stream, &blk)
151
+ end
152
+ end
153
+
134
154
  class << self
135
- sig { params(io: StringIO, boundary: String, key: T.any(Symbol, String), val: T.anything).void }
136
- private def encode_multipart_formdata(io, boundary:, key:, val:)
155
+ sig { params(blk: T.proc.params(y: Enumerator::Yielder).void).returns(T::Enumerable[String]) }
156
+ def string_io(&blk)
157
+ end
158
+ end
159
+
160
+ class << self
161
+ sig do
162
+ params(y: Enumerator::Yielder, boundary: String, key: T.any(Symbol, String), val: T.anything).void
163
+ end
164
+ private def encode_multipart_formdata(y, boundary:, key:, val:)
165
+ end
166
+
167
+ sig { params(body: T.anything).returns([String, T::Enumerable[String]]) }
168
+ private def encode_multipart_streaming(body)
137
169
  end
138
170
 
139
171
  sig { params(headers: T::Hash[String, String], body: T.anything).returns(T.anything) }
@@ -153,8 +185,11 @@ module TerminalShop
153
185
  end
154
186
 
155
187
  class << self
156
- sig { params(enum: T::Enumerable[T.anything], close: T.proc.void).returns(T::Enumerable[T.anything]) }
157
- def fused_enum(enum, &close)
188
+ sig do
189
+ params(enum: T::Enumerable[T.anything], external: T::Boolean, close: T.proc.void)
190
+ .returns(T::Enumerable[T.anything])
191
+ end
192
+ def fused_enum(enum, external: false, &close)
158
193
  end
159
194
 
160
195
  sig { params(enum: T.nilable(T::Enumerable[T.anything])).void }
@@ -1,5 +1,5 @@
1
1
  # typed: strong
2
2
 
3
3
  module TerminalShop
4
- VERSION = "1.1.0"
4
+ VERSION = "1.2.0"
5
5
  end
@@ -15,7 +15,9 @@ module TerminalShop
15
15
 
16
16
  def self.build_request: (
17
17
  TerminalShop::PooledNetRequester::request request
18
- ) -> top
18
+ ) {
19
+ (String arg0) -> void
20
+ } -> top
19
21
 
20
22
  private def with_pool: (URI::Generic url) { (top arg0) -> void } -> void
21
23
 
@@ -23,6 +25,6 @@ module TerminalShop
23
25
  TerminalShop::PooledNetRequester::request request
24
26
  ) -> [top, Enumerable[String]]
25
27
 
26
- def initialize: -> void
28
+ def initialize: (size: Integer) -> void
27
29
  end
28
30
  end
@@ -74,13 +74,33 @@ module TerminalShop
74
74
  | ::Array[(String | Integer)?])?] headers
75
75
  ) -> ::Hash[String, String]
76
76
 
77
+ class ReadIOAdapter
78
+ private def read_enum: (Integer? max_len) -> String
79
+
80
+ def read: (?Integer? max_len, ?String? out_string) -> String?
81
+
82
+ def initialize: (
83
+ String | IO | StringIO | Enumerable[String] stream
84
+ ) {
85
+ (String arg0) -> void
86
+ } -> void
87
+ end
88
+
89
+ def self?.string_io: {
90
+ (Enumerator::Yielder y) -> void
91
+ } -> Enumerable[String]
92
+
77
93
  def self?.encode_multipart_formdata: (
78
- StringIO io,
94
+ Enumerator::Yielder y,
79
95
  boundary: String,
80
96
  key: Symbol | String,
81
97
  val: top
82
98
  ) -> void
83
99
 
100
+ def self?.encode_multipart_streaming: (
101
+ top body
102
+ ) -> [String, Enumerable[String]]
103
+
84
104
  def self?.encode_content: (::Hash[String, String] headers, top body) -> top
85
105
 
86
106
  def self?.decode_content: (
@@ -89,7 +109,12 @@ module TerminalShop
89
109
  suppress_error: bool
90
110
  ) -> top
91
111
 
92
- def self?.fused_enum: (Enumerable[top] enum) { -> void } -> Enumerable[top]
112
+ def self?.fused_enum: (
113
+ Enumerable[top] enum,
114
+ external: bool
115
+ ) {
116
+ -> void
117
+ } -> Enumerable[top]
93
118
 
94
119
  def self?.close_fused!: (Enumerable[top]? enum) -> void
95
120
 
@@ -1,3 +1,3 @@
1
1
  module TerminalShop
2
- VERSION: "1.0.0"
2
+ VERSION: "1.1.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: terminal-shop
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Terminal
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-03-11 00:00:00.000000000 Z
11
+ date: 2025-03-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: connection_pool