prop_check 0.13.0 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/CHANGELOG.md +1 -0
- data/lib/prop_check/generators.rb +85 -26
- data/lib/prop_check/hooks.rb +20 -13
- data/lib/prop_check/property.rb +56 -28
- data/lib/prop_check/property/configuration.rb +1 -1
- data/lib/prop_check/version.rb +1 -1
- 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: 013ca5101f31799feb0c86533c4100a781c451f937d6d8497a30476073e27e4b
|
4
|
+
data.tar.gz: f592ec086ca3018cfca1016baa1690619a5783274f02c910eb2ad03e5861a53d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f49b2514fe4e179013bd8c4a4683c1210b65d6852901156c6c5373f26305343fa4cae40860f13386a8f1fda33406927bf20a357f88cd5b99936318410837ba00
|
7
|
+
data.tar.gz: 261b980fb68c2d1af8baccb09919a838f91c1f6ae33f8c8a79923b2cb50490e4406e848ffbf6a75361d13d33719907a3342b4a7eed88ebdf37d1bdd8cd981ee4
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
- 0.14.0 - Adds `uniq: true` option to `Generators.array`. Makes `PropCheck::Property` an immutable object that returns copies that have changes whenever reconfiguring, allowing re-usable configuration.
|
1
2
|
- 0.13.0 - Adds Generator#resize
|
2
3
|
- 0.12.1 - Fixes shrinking when filtering bug.
|
3
4
|
- 0.12.0 - `PropCheck::Generators#instance`
|
@@ -9,7 +9,7 @@ module PropCheck
|
|
9
9
|
# Use this module by including it in the class (e.g. in your test suite)
|
10
10
|
# where you want to use them.
|
11
11
|
module Generators
|
12
|
-
|
12
|
+
module_function
|
13
13
|
|
14
14
|
##
|
15
15
|
# Always returns the same value, regardless of `size` or `rng` (random number generator state)
|
@@ -146,7 +146,7 @@ module PropCheck
|
|
146
146
|
end
|
147
147
|
end
|
148
148
|
|
149
|
-
|
149
|
+
@@special_floats = [Float::NAN, Float::INFINITY, -Float::INFINITY, Float::MAX, Float::MIN, 0.0.next_float, 0.0.prev_float]
|
150
150
|
##
|
151
151
|
# Generates floating-point numbers
|
152
152
|
# Will generate NaN, Infinity, -Infinity,
|
@@ -159,7 +159,7 @@ module PropCheck
|
|
159
159
|
# >> Generators.float().sample(10, size: 10, rng: Random.new(42))
|
160
160
|
# => [4.0, 9.555555555555555, 0.0, -Float::INFINITY, 5.5, -5.818181818181818, 1.1428571428571428, 0.0, 8.0, 7.857142857142858]
|
161
161
|
def float
|
162
|
-
frequency(99 => real_float, 1 => one_of(
|
162
|
+
frequency(99 => real_float, 1 => one_of(*@@special_floats.map(&method(:constant))))
|
163
163
|
end
|
164
164
|
|
165
165
|
##
|
@@ -241,6 +241,12 @@ module PropCheck
|
|
241
241
|
# `empty:` When false, behaves the same as `min: 1`
|
242
242
|
# `min:` Ensures at least this many elements are generated. (default: 0)
|
243
243
|
# `max:` Ensures at most this many elements are generated. When nil, an arbitrary count is used instead. (default: nil)
|
244
|
+
# `uniq:` When `true`, ensures that all elements in the array are unique.
|
245
|
+
# When given a proc, uses the result of this proc to check for uniqueness.
|
246
|
+
# (matching the behaviour of `Array#uniq`)
|
247
|
+
# If it is not possible to generate another unique value after the configured `max_consecutive_attempts`
|
248
|
+
# an `PropCheck::Errors::GeneratorExhaustedError` will be raised.
|
249
|
+
# (default: `false`)
|
244
250
|
#
|
245
251
|
#
|
246
252
|
# >> Generators.array(Generators.positive_integer).sample(5, size: 1, rng: Random.new(42))
|
@@ -252,25 +258,68 @@ module PropCheck
|
|
252
258
|
# => [[], [2], [], [], [2]]
|
253
259
|
# >> Generators.array(Generators.positive_integer, empty: false).sample(5, size: 1, rng: Random.new(1))
|
254
260
|
# => [[2], [1], [2], [1], [1]]
|
261
|
+
#
|
262
|
+
# >> Generators.array(Generators.boolean, uniq: true).sample(5, rng: Random.new(1))
|
263
|
+
# => [[true, false], [false, true], [true, false], [false, true], [false, true]]
|
255
264
|
|
256
|
-
|
257
|
-
def array(element_generator, min: 0, max: nil, empty: true)
|
265
|
+
def array(element_generator, min: 0, max: nil, empty: true, uniq: false)
|
258
266
|
min = 1 if min.zero? && !empty
|
267
|
+
uniq = proc { |x| x } if uniq == true
|
259
268
|
|
260
|
-
|
261
|
-
count
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
269
|
+
if max.nil?
|
270
|
+
nonnegative_integer.bind { |count| make_array(element_generator, min, count, uniq) }
|
271
|
+
else
|
272
|
+
make_array(element_generator, min, max, uniq)
|
273
|
+
end
|
274
|
+
end
|
266
275
|
|
267
|
-
|
276
|
+
private def make_array(element_generator, min, count, uniq)
|
277
|
+
amount = min if count < min
|
278
|
+
amount = min if count == min && min != 0
|
279
|
+
amount ||= (count - min)
|
280
|
+
|
281
|
+
# Simple, optimized implementation:
|
282
|
+
return make_array_simple(element_generator, amount) unless uniq
|
283
|
+
|
284
|
+
# More complex implementation that filters duplicates
|
285
|
+
make_array_uniq(element_generator, min, amount, uniq)
|
286
|
+
end
|
287
|
+
|
288
|
+
private def make_array_simple(element_generator, amount)
|
289
|
+
generators = amount.times.map do
|
290
|
+
element_generator.clone
|
268
291
|
end
|
269
292
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
293
|
+
tuple(*generators)
|
294
|
+
end
|
295
|
+
|
296
|
+
private def make_array_uniq(element_generator, min, amount, uniq_fun)
|
297
|
+
Generator.new do |**kwargs|
|
298
|
+
arr = []
|
299
|
+
uniques = Set.new
|
300
|
+
count = 0
|
301
|
+
(0..).lazy.map do
|
302
|
+
elem = element_generator.clone.generate(**kwargs)
|
303
|
+
if uniques.add?(uniq_fun.call(elem.root))
|
304
|
+
arr.push(elem)
|
305
|
+
count = 0
|
306
|
+
else
|
307
|
+
count += 1
|
308
|
+
end
|
309
|
+
|
310
|
+
if count > kwargs[:max_consecutive_attempts]
|
311
|
+
if arr.size >= min
|
312
|
+
# Give up and return shorter array in this case
|
313
|
+
amount = min
|
314
|
+
else
|
315
|
+
raise Errors::GeneratorExhaustedError, "Too many consecutive elements filtered by 'uniq:'."
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
.take_while { arr.size < amount }
|
320
|
+
.force
|
321
|
+
|
322
|
+
LazyTree.zip(arr).map { |array| array.uniq(&uniq_fun) }
|
274
323
|
end
|
275
324
|
end
|
276
325
|
|
@@ -300,7 +349,7 @@ module PropCheck
|
|
300
349
|
.map(&:to_h)
|
301
350
|
end
|
302
351
|
|
303
|
-
|
352
|
+
@@alphanumeric_chars = [('a'..'z'), ('A'..'Z'), ('0'..'9')].flat_map(&:to_a).freeze
|
304
353
|
##
|
305
354
|
# Generates a single-character string
|
306
355
|
# containing one of a..z, A..Z, 0..9
|
@@ -310,7 +359,7 @@ module PropCheck
|
|
310
359
|
# >> Generators.alphanumeric_char.sample(5, size: 10, rng: Random.new(42))
|
311
360
|
# => ["M", "Z", "C", "o", "Q"]
|
312
361
|
def alphanumeric_char
|
313
|
-
one_of(
|
362
|
+
one_of(*@@alphanumeric_chars.map(&method(:constant)))
|
314
363
|
end
|
315
364
|
|
316
365
|
##
|
@@ -321,11 +370,13 @@ module PropCheck
|
|
321
370
|
#
|
322
371
|
# >> Generators.alphanumeric_string.sample(5, size: 10, rng: Random.new(42))
|
323
372
|
# => ["ZCoQ", "8uM", "wkkx0JNx", "v0bxRDLb", "Gl5v8RyWA6"]
|
373
|
+
#
|
374
|
+
# Accepts the same options as `array`
|
324
375
|
def alphanumeric_string(**kwargs)
|
325
376
|
array(alphanumeric_char, **kwargs).map(&:join)
|
326
377
|
end
|
327
378
|
|
328
|
-
|
379
|
+
@@printable_ascii_chars = (' '..'~').to_a.freeze
|
329
380
|
|
330
381
|
##
|
331
382
|
# Generates a single-character string
|
@@ -336,7 +387,7 @@ module PropCheck
|
|
336
387
|
# >> Generators.printable_ascii_char.sample(size: 10, rng: Random.new(42))
|
337
388
|
# => ["S", "|", ".", "g", "\\", "4", "r", "v", "j", "j"]
|
338
389
|
def printable_ascii_char
|
339
|
-
one_of(
|
390
|
+
one_of(*@@printable_ascii_chars.map(&method(:constant)))
|
340
391
|
end
|
341
392
|
|
342
393
|
##
|
@@ -347,12 +398,14 @@ module PropCheck
|
|
347
398
|
#
|
348
399
|
# >> Generators.printable_ascii_string.sample(5, size: 10, rng: Random.new(42))
|
349
400
|
# => ["S|.g", "rvjjw7\"5T!", "=", "!_[4@", "Y"]
|
401
|
+
#
|
402
|
+
# Accepts the same options as `array`
|
350
403
|
def printable_ascii_string(**kwargs)
|
351
404
|
array(printable_ascii_char, **kwargs).map(&:join)
|
352
405
|
end
|
353
406
|
|
354
|
-
|
355
|
-
|
407
|
+
@@ascii_chars = [
|
408
|
+
@@printable_ascii_chars,
|
356
409
|
[
|
357
410
|
"\n",
|
358
411
|
"\r",
|
@@ -375,7 +428,7 @@ module PropCheck
|
|
375
428
|
# >> Generators.ascii_char.sample(size: 10, rng: Random.new(42))
|
376
429
|
# => ["d", "S", "|", ".", "g", "\\", "4", "d", "r", "v"]
|
377
430
|
def ascii_char
|
378
|
-
one_of(
|
431
|
+
one_of(*@@ascii_chars.map(&method(:constant)))
|
379
432
|
end
|
380
433
|
|
381
434
|
##
|
@@ -386,12 +439,14 @@ module PropCheck
|
|
386
439
|
#
|
387
440
|
# >> Generators.ascii_string.sample(5, size: 10, rng: Random.new(42))
|
388
441
|
# => ["S|.g", "drvjjw\b\a7\"", "!w=E!_[4@k", "x", "zZI{[o"]
|
442
|
+
#
|
443
|
+
# Accepts the same options as `array`
|
389
444
|
def ascii_string(**kwargs)
|
390
445
|
array(ascii_char, **kwargs).map(&:join)
|
391
446
|
end
|
392
447
|
|
393
|
-
|
394
|
-
|
448
|
+
@@printable_chars = [
|
449
|
+
@@ascii_chars,
|
395
450
|
"\u{A0}".."\u{D7FF}",
|
396
451
|
"\u{E000}".."\u{FFFD}",
|
397
452
|
"\u{10000}".."\u{10FFFF}"
|
@@ -406,7 +461,7 @@ module PropCheck
|
|
406
461
|
# >> Generators.printable_char.sample(size: 10, rng: Random.new(42))
|
407
462
|
# => ["吏", "", "", "", "", "", "", "", "", "Ȍ"]
|
408
463
|
def printable_char
|
409
|
-
one_of(
|
464
|
+
one_of(*@@printable_chars.map(&method(:constant)))
|
410
465
|
end
|
411
466
|
|
412
467
|
##
|
@@ -417,6 +472,8 @@ module PropCheck
|
|
417
472
|
#
|
418
473
|
# >> Generators.printable_string.sample(5, size: 10, rng: Random.new(42))
|
419
474
|
# => ["", "Ȍ", "𐁂", "Ȕ", ""]
|
475
|
+
#
|
476
|
+
# Accepts the same options as `array`
|
420
477
|
def printable_string(**kwargs)
|
421
478
|
array(printable_char, **kwargs).map(&:join)
|
422
479
|
end
|
@@ -443,6 +500,8 @@ module PropCheck
|
|
443
500
|
#
|
444
501
|
# >> Generators.string.sample(5, size: 10, rng: Random.new(42))
|
445
502
|
# => ["\u{A3DB3}𠍜\u{3F46A}\u{1AEBC}", "𡡹\u{DED74}𪱣\u{43E97}ꂂ\u{50695}\u{C0301}", "\u{4FD9D}", "\u{C14BF}\u{193BB}𭇋\u{76B58}", "𦐺\u{9FDDB}\u{80ABB}\u{9E3CF}𐂽\u{14AAE}"]
|
503
|
+
#
|
504
|
+
# Accepts the same options as `array`
|
446
505
|
def string(**kwargs)
|
447
506
|
array(char, **kwargs).map(&:join)
|
448
507
|
end
|
data/lib/prop_check/hooks.rb
CHANGED
@@ -19,10 +19,11 @@
|
|
19
19
|
# wrapping the elements of an enumerable with hooks.
|
20
20
|
class PropCheck::Hooks
|
21
21
|
# attr_reader :before, :after, :around
|
22
|
-
def initialize()
|
23
|
-
@before =
|
24
|
-
@after =
|
25
|
-
@around =
|
22
|
+
def initialize(before: proc {}, after: proc {}, around: proc { |*args, &block| block.call(*args) })
|
23
|
+
@before = before
|
24
|
+
@after = after
|
25
|
+
@around = around
|
26
|
+
freeze
|
26
27
|
end
|
27
28
|
|
28
29
|
def wrap_enum(enumerable)
|
@@ -59,34 +60,40 @@ class PropCheck::Hooks
|
|
59
60
|
# Adds `hook` to the `before` proc.
|
60
61
|
# It is called after earlier-added `before` procs.
|
61
62
|
def add_before(&hook)
|
62
|
-
old_before = @before
|
63
|
-
|
64
|
-
|
63
|
+
# old_before = @before
|
64
|
+
new_before = proc {
|
65
|
+
@before.call
|
65
66
|
hook.call
|
66
67
|
}
|
68
|
+
# self
|
69
|
+
self.class.new(before: new_before, after: @after, around: @around)
|
67
70
|
end
|
68
71
|
|
69
72
|
##
|
70
73
|
# Adds `hook` to the `after` proc.
|
71
74
|
# It is called before earlier-added `after` procs.
|
72
75
|
def add_after(&hook)
|
73
|
-
old_after = @after
|
74
|
-
|
76
|
+
# old_after = @after
|
77
|
+
new_after = proc {
|
75
78
|
hook.call
|
76
|
-
|
79
|
+
@after.call
|
77
80
|
}
|
81
|
+
# self
|
82
|
+
self.class.new(before: @before, after: new_after, around: @around)
|
78
83
|
end
|
79
84
|
|
80
85
|
##
|
81
86
|
# Adds `hook` to the `around` proc.
|
82
87
|
# It is called _inside_ earlier-added `around` procs.
|
83
88
|
def add_around(&hook)
|
84
|
-
old_around = @around
|
85
|
-
|
86
|
-
|
89
|
+
# old_around = @around
|
90
|
+
new_around = proc do |&block|
|
91
|
+
@around.call do |*args|
|
87
92
|
hook.call(*args, &block)
|
88
93
|
end
|
89
94
|
end
|
95
|
+
# self
|
96
|
+
self.class.new(before: @before, after: @after, around: new_around)
|
90
97
|
end
|
91
98
|
|
92
99
|
##
|
data/lib/prop_check/property.rb
CHANGED
@@ -7,9 +7,15 @@ require 'prop_check/property/shrinker'
|
|
7
7
|
require 'prop_check/hooks'
|
8
8
|
module PropCheck
|
9
9
|
##
|
10
|
-
#
|
10
|
+
# Create and run property-checks.
|
11
|
+
#
|
12
|
+
# For simple usage, see `.forall`.
|
13
|
+
#
|
14
|
+
# For advanced usage, call `PropCheck::Property.new(...)` and then configure it to your liking
|
15
|
+
# using e.g. `#with_config`, `#before`, `#after`, `#around` etc.
|
16
|
+
# Each of these methods will return a new `Property`, so earlier properties are not mutated.
|
17
|
+
# This allows you to re-use configuration and hooks between multiple tests.
|
11
18
|
class Property
|
12
|
-
|
13
19
|
##
|
14
20
|
# Main entry-point to create (and possibly immediately run) a property-test.
|
15
21
|
#
|
@@ -36,7 +42,6 @@ module PropCheck
|
|
36
42
|
# of this class on before finally passing a block to it using `#check`.
|
37
43
|
# (so `forall(Generators.integer) do |val| ... end` and forall(Generators.integer).check do |val| ... end` are the same)
|
38
44
|
def self.forall(*bindings, **kwbindings, &block)
|
39
|
-
|
40
45
|
property = new(*bindings, **kwbindings)
|
41
46
|
|
42
47
|
return property.check(&block) if block_given?
|
@@ -61,19 +66,25 @@ module PropCheck
|
|
61
66
|
yield(configuration)
|
62
67
|
end
|
63
68
|
|
64
|
-
attr_reader :bindings, :condition
|
65
|
-
|
66
69
|
def initialize(*bindings, **kwbindings)
|
67
|
-
raise ArgumentError, 'No bindings specified!' if bindings.empty? && kwbindings.empty?
|
68
|
-
|
69
|
-
# @bindings = bindings
|
70
|
-
# @kwbindings = kwbindings
|
71
|
-
@gen = gen_from_bindings(bindings, kwbindings)
|
72
|
-
@condition = proc { true }
|
73
70
|
@config = self.class.configuration
|
74
71
|
@hooks = PropCheck::Hooks.new
|
72
|
+
|
73
|
+
@gen = gen_from_bindings(bindings, kwbindings) unless bindings.empty? && kwbindings.empty?
|
74
|
+
freeze
|
75
75
|
end
|
76
76
|
|
77
|
+
# [:condition, :config, :hooks, :gen].each do |symbol|
|
78
|
+
# define_method(symbol) do
|
79
|
+
# self.instance_variable_get("@#{symbol}")
|
80
|
+
# end
|
81
|
+
|
82
|
+
# protected define_method("#{symbol}=") do |value|
|
83
|
+
# duplicate = self.dup
|
84
|
+
# duplicate.instance_variable_set("@#{symbol}", value)
|
85
|
+
# duplicate
|
86
|
+
# end
|
87
|
+
|
77
88
|
##
|
78
89
|
# Returns the configuration of this property
|
79
90
|
# for introspection.
|
@@ -91,11 +102,22 @@ module PropCheck
|
|
91
102
|
# you can immediately pass a block to this method.
|
92
103
|
# (so `forall(a: Generators.integer).with_config(verbose: true) do ... end` is the same as `forall(a: Generators.integer).with_config(verbose: true).check do ... end`)
|
93
104
|
def with_config(**config, &block)
|
94
|
-
|
105
|
+
duplicate = self.dup
|
106
|
+
duplicate.instance_variable_set(:@config, @config.merge(config))
|
107
|
+
duplicate.freeze
|
95
108
|
|
96
|
-
return
|
109
|
+
return duplicate.check(&block) if block_given?
|
97
110
|
|
98
|
-
|
111
|
+
duplicate
|
112
|
+
end
|
113
|
+
|
114
|
+
def with_bindings(*bindings, **kwbindings)
|
115
|
+
raise ArgumentError, 'No bindings specified!' if bindings.empty? && kwbindings.empty?
|
116
|
+
|
117
|
+
duplicate = self.dup
|
118
|
+
duplicate.instance_variable_set(:@gen, gen_from_bindings(bindings, kwbindings))
|
119
|
+
duplicate.freeze
|
120
|
+
duplicate
|
99
121
|
end
|
100
122
|
|
101
123
|
##
|
@@ -107,14 +129,12 @@ module PropCheck
|
|
107
129
|
# you might encounter a GeneratorExhaustedError.
|
108
130
|
# Only filter if you have few inputs to reject. Otherwise, improve your generators.
|
109
131
|
def where(&condition)
|
110
|
-
#
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
self
|
132
|
+
raise ArgumentError, 'No generator bindings specified! #where should be called after `#forall` or `#with_bindings`.' unless @gen
|
133
|
+
|
134
|
+
duplicate = self.dup
|
135
|
+
duplicate.instance_variable_set(:@gen, @gen.where(&condition))
|
136
|
+
duplicate.freeze
|
137
|
+
duplicate
|
118
138
|
end
|
119
139
|
|
120
140
|
|
@@ -124,8 +144,10 @@ module PropCheck
|
|
124
144
|
# This is useful to add setup logic
|
125
145
|
# When called multiple times, earlier-added hooks will be called _before_ `hook` is called.
|
126
146
|
def before(&hook)
|
127
|
-
|
128
|
-
|
147
|
+
duplicate = self.dup
|
148
|
+
duplicate.instance_variable_set(:@hooks, @hooks.add_before(&hook))
|
149
|
+
duplicate.freeze
|
150
|
+
duplicate
|
129
151
|
end
|
130
152
|
|
131
153
|
##
|
@@ -134,8 +156,10 @@ module PropCheck
|
|
134
156
|
# This is useful to add teardown logic
|
135
157
|
# When called multiple times, earlier-added hooks will be called _after_ `hook` is called.
|
136
158
|
def after(&hook)
|
137
|
-
|
138
|
-
|
159
|
+
duplicate = self.dup
|
160
|
+
duplicate.instance_variable_set(:@hooks, @hooks.add_after(&hook))
|
161
|
+
duplicate.freeze
|
162
|
+
duplicate
|
139
163
|
end
|
140
164
|
|
141
165
|
##
|
@@ -152,8 +176,10 @@ module PropCheck
|
|
152
176
|
# it is possible for the code after `yield` not to be called.
|
153
177
|
# So make sure that cleanup logic is wrapped with the `ensure` keyword.
|
154
178
|
def around(&hook)
|
155
|
-
|
156
|
-
|
179
|
+
duplicate = self.dup
|
180
|
+
duplicate.instance_variable_set(:@hooks, @hooks.add_around(&hook))
|
181
|
+
duplicate.freeze
|
182
|
+
duplicate
|
157
183
|
end
|
158
184
|
|
159
185
|
##
|
@@ -238,6 +264,8 @@ c.f. https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-k
|
|
238
264
|
end
|
239
265
|
|
240
266
|
private def attempts_enum(binding_generator)
|
267
|
+
ap @hooks
|
268
|
+
|
241
269
|
@hooks
|
242
270
|
.wrap_enum(raw_attempts_enum(binding_generator))
|
243
271
|
.lazy
|
data/lib/prop_check/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prop_check
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Qqwy/Wiebe-Marten Wijnja
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-08-
|
11
|
+
date: 2020-08-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: awesome_print
|