with_clues 1.0.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +98 -35
- data/.tool-versions +1 -0
- data/CHANGELOG.md +1 -0
- data/README.md +6 -1
- data/bin/mk_circle_config +84 -0
- data/lib/with_clues/browser_logs.rb +25 -14
- data/lib/with_clues/html.rb +7 -5
- data/lib/with_clues/method.rb +15 -7
- data/lib/with_clues/private/custom_clue_method_analysis.rb +139 -0
- data/lib/with_clues/version.rb +1 -1
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 270e2b6f2af29d8d7871cba1103db16ec84efd97380acb4592b094729adfb994
|
4
|
+
data.tar.gz: 22de0039993571e0a491cbe9ec5d1b53021d184793d99bfc47ffb34d64ca833a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f019bd0a5354f762b4a7304d88509054fe53078528c188e8186aa8af134ff40d99042b0c3556ea2c2497317e0d899e764a6649e78f22ed1aea53e5301ee83c6f
|
7
|
+
data.tar.gz: d106562538a1cd625d422e1e500aa34564c5f1c97bfeea30fa6083c7e7f1b99d4addf59f7046c29575122f0b43a15c61b7efefc6fba16ef8a0aeec0107b15148
|
data/.circleci/config.yml
CHANGED
@@ -1,35 +1,98 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
1
|
+
# THIS IS GENERATED - DO NOT EDIT
|
2
|
+
# regenerate with bin/mk_circle_config
|
3
|
+
# You are very welcome
|
4
|
+
---
|
5
|
+
version: '2.1'
|
6
|
+
jobs:
|
7
|
+
ruby__2_6:
|
8
|
+
docker:
|
9
|
+
- image: cimg/ruby:2.6
|
10
|
+
steps:
|
11
|
+
- checkout
|
12
|
+
- run:
|
13
|
+
name: Setup for build
|
14
|
+
command: bin/setup
|
15
|
+
- run:
|
16
|
+
name: Ensure bin/setup is idempotent
|
17
|
+
command: bin/setup
|
18
|
+
- run:
|
19
|
+
name: Create the test results dir
|
20
|
+
command: mkdir -p /tmp/test-results/2.6
|
21
|
+
- run:
|
22
|
+
name: Run all tests
|
23
|
+
command: bin/ci /tmp/test-results/2.6/rspec_results.xml
|
24
|
+
- store_test_results:
|
25
|
+
path: "/tmp/test-results/2.6"
|
26
|
+
- store_artifacts:
|
27
|
+
path: "/tmp/test-results/2.6"
|
28
|
+
ruby__2_7:
|
29
|
+
docker:
|
30
|
+
- image: cimg/ruby:2.7
|
31
|
+
steps:
|
32
|
+
- checkout
|
33
|
+
- run:
|
34
|
+
name: Setup for build
|
35
|
+
command: bin/setup
|
36
|
+
- run:
|
37
|
+
name: Ensure bin/setup is idempotent
|
38
|
+
command: bin/setup
|
39
|
+
- run:
|
40
|
+
name: Create the test results dir
|
41
|
+
command: mkdir -p /tmp/test-results/2.7
|
42
|
+
- run:
|
43
|
+
name: Run all tests
|
44
|
+
command: bin/ci /tmp/test-results/2.7/rspec_results.xml
|
45
|
+
- store_test_results:
|
46
|
+
path: "/tmp/test-results/2.7"
|
47
|
+
- store_artifacts:
|
48
|
+
path: "/tmp/test-results/2.7"
|
49
|
+
ruby__3_0:
|
50
|
+
docker:
|
51
|
+
- image: cimg/ruby:3.0
|
52
|
+
steps:
|
53
|
+
- checkout
|
54
|
+
- run:
|
55
|
+
name: Setup for build
|
56
|
+
command: bin/setup
|
57
|
+
- run:
|
58
|
+
name: Ensure bin/setup is idempotent
|
59
|
+
command: bin/setup
|
60
|
+
- run:
|
61
|
+
name: Create the test results dir
|
62
|
+
command: mkdir -p /tmp/test-results/3.0
|
63
|
+
- run:
|
64
|
+
name: Run all tests
|
65
|
+
command: bin/ci /tmp/test-results/3.0/rspec_results.xml
|
66
|
+
- store_test_results:
|
67
|
+
path: "/tmp/test-results/3.0"
|
68
|
+
- store_artifacts:
|
69
|
+
path: "/tmp/test-results/3.0"
|
70
|
+
ruby__3_1:
|
71
|
+
docker:
|
72
|
+
- image: cimg/ruby:3.1
|
73
|
+
steps:
|
74
|
+
- checkout
|
75
|
+
- run:
|
76
|
+
name: Setup for build
|
77
|
+
command: bin/setup
|
78
|
+
- run:
|
79
|
+
name: Ensure bin/setup is idempotent
|
80
|
+
command: bin/setup
|
81
|
+
- run:
|
82
|
+
name: Create the test results dir
|
83
|
+
command: mkdir -p /tmp/test-results/3.1
|
84
|
+
- run:
|
85
|
+
name: Run all tests
|
86
|
+
command: bin/ci /tmp/test-results/3.1/rspec_results.xml
|
87
|
+
- store_test_results:
|
88
|
+
path: "/tmp/test-results/3.1"
|
89
|
+
- store_artifacts:
|
90
|
+
path: "/tmp/test-results/3.1"
|
91
|
+
workflows:
|
92
|
+
version: 2
|
93
|
+
all_rubies:
|
94
|
+
jobs:
|
95
|
+
- ruby__2_6
|
96
|
+
- ruby__2_7
|
97
|
+
- ruby__3_0
|
98
|
+
- ruby__3_1
|
data/.tool-versions
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby 3.1.0
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
See [https://github.com/sustainable-rails/with\_clues/releases](https://github.com/sustainable-rails/with_clues/releases)
|
data/README.md
CHANGED
@@ -107,13 +107,15 @@ There are three clues included:
|
|
107
107
|
`with_clues` is intended as a diagnostic tool you can develop and enhance over time. As your team writes more code or develops
|
108
108
|
more conventions, you can develop diagnostics as well.
|
109
109
|
|
110
|
-
To add one, create a class that implements `dump(notifier, context:)`:
|
110
|
+
To add one, create a class that implements `dump(notifier, context:)` or `dump(notifier, context:, page:)`:
|
111
111
|
|
112
112
|
* `notifier` is a `WithClues::Notifier` that you should use to produce output:
|
113
113
|
* `notify` - output text, preceded with `[ with_clues ]` (this is so you can tell output from your code vs from `with_clues`)
|
114
114
|
* `blank_line` - a blank line (no prefix)
|
115
115
|
* `notify_raw` - output text without a prefix, useful for removing ambiguity about what is being output
|
116
116
|
* `context:` the context passed into `with_clues` (nil if it was omitted)
|
117
|
+
* `page:` If `dump` requires this keyword, your clue will only be used in a browser context when the Capybara `page` object is available.
|
118
|
+
In that case, that is what is passed in.
|
117
119
|
|
118
120
|
For example, suppose you want to output information about an Active Record like so:
|
119
121
|
|
@@ -153,6 +155,9 @@ WithClues::Method.use_custom_clue ActiveRecordClues
|
|
153
155
|
|
154
156
|
You can use multiple clues by repeatedly calling `use_custom_clue`
|
155
157
|
|
158
|
+
Note that if your clue implements the three-arg version of `dump` ( `dump(notifier, context:, page:)` ), it will *only* be used when in
|
159
|
+
a context where Capybara's `page` element in in play.
|
160
|
+
|
156
161
|
## Developing
|
157
162
|
|
158
163
|
* Get set up with `bin/setup`
|
@@ -0,0 +1,84 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "yaml"
|
4
|
+
require "pathname"
|
5
|
+
|
6
|
+
circle_config = {
|
7
|
+
"version" => "2.1",
|
8
|
+
"jobs" => {},
|
9
|
+
"workflows" => {
|
10
|
+
"version" => 2,
|
11
|
+
"all_rubies" => {
|
12
|
+
"jobs" => [
|
13
|
+
],
|
14
|
+
},
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
supported_rubies = [
|
19
|
+
"2.6",
|
20
|
+
"2.7",
|
21
|
+
"3.0",
|
22
|
+
"3.1",
|
23
|
+
]
|
24
|
+
|
25
|
+
supported_rubies.each do |ruby_verison|
|
26
|
+
|
27
|
+
test_results_dir = "/tmp/test-results/#{ruby_verison}"
|
28
|
+
job_name = "ruby__#{ruby_verison.gsub(/\./,"_")}"
|
29
|
+
|
30
|
+
job = {
|
31
|
+
"docker" => [
|
32
|
+
{
|
33
|
+
"image" => "cimg/ruby:#{ruby_verison}",
|
34
|
+
}
|
35
|
+
],
|
36
|
+
"steps" => [
|
37
|
+
"checkout",
|
38
|
+
{
|
39
|
+
"run" => {
|
40
|
+
"name" => "Setup for build",
|
41
|
+
"command" => "bin/setup",
|
42
|
+
}
|
43
|
+
},
|
44
|
+
{
|
45
|
+
"run" => {
|
46
|
+
"name" => "Ensure bin/setup is idempotent",
|
47
|
+
"command" => "bin/setup",
|
48
|
+
}
|
49
|
+
},
|
50
|
+
{
|
51
|
+
"run" => {
|
52
|
+
"name" => "Create the test results dir",
|
53
|
+
"command" => "mkdir -p #{test_results_dir}",
|
54
|
+
}
|
55
|
+
},
|
56
|
+
{
|
57
|
+
"run" => {
|
58
|
+
"name" => "Run all tests",
|
59
|
+
"command" => "bin/ci #{test_results_dir}/rspec_results.xml",
|
60
|
+
}
|
61
|
+
},
|
62
|
+
{
|
63
|
+
"store_test_results" => {
|
64
|
+
"path" => test_results_dir,
|
65
|
+
}
|
66
|
+
},
|
67
|
+
{
|
68
|
+
"store_artifacts" => {
|
69
|
+
"path" => test_results_dir,
|
70
|
+
}
|
71
|
+
},
|
72
|
+
]
|
73
|
+
}
|
74
|
+
circle_config["jobs"][job_name] = job
|
75
|
+
circle_config["workflows"]["all_rubies"]["jobs"] << job_name
|
76
|
+
end
|
77
|
+
|
78
|
+
circle_config_file = (Pathname(__FILE__).dirname / ".." / ".circleci" / "config.yml").expand_path
|
79
|
+
File.open(circle_config_file,"w") do |file|
|
80
|
+
file.puts "# THIS IS GENERATED - DO NOT EDIT"
|
81
|
+
file.puts "# regenerate with bin/mk_circle_config"
|
82
|
+
file.puts "# You are very welcome"
|
83
|
+
file.puts circle_config.to_yaml
|
84
|
+
end
|
@@ -6,24 +6,35 @@ module WithClues
|
|
6
6
|
return
|
7
7
|
end
|
8
8
|
if page.driver.respond_to?(:browser)
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
notifier.notify_raw log.message
|
16
|
-
end
|
17
|
-
notifier.notify "} END BROWSER LOGS"
|
18
|
-
else
|
19
|
-
notifier.notify "NO BROWSER LOGS: page.driver.browser.manage #{page.driver.browser.manage.class} does not respond to #logs"
|
9
|
+
logs = locate_logs(page.driver.browser, notifier: notifier)
|
10
|
+
if !logs.nil?
|
11
|
+
browser_logs = logs.get(:browser)
|
12
|
+
notifier.notify "BROWSER LOGS {"
|
13
|
+
browser_logs.each do |log|
|
14
|
+
notifier.notify_raw log.message
|
20
15
|
end
|
21
|
-
|
22
|
-
notifier.notify "NO BROWSER LOGS: page.driver.browser #{page.driver.browser.class} does not respond to #manage"
|
16
|
+
notifier.notify "} END BROWSER LOGS"
|
23
17
|
end
|
24
18
|
else
|
25
|
-
notifier.notify "NO BROWSER LOGS: page.driver #{page.driver.class} does not respond to #browser"
|
19
|
+
notifier.notify "[with_clues: #{self.class}] NO BROWSER LOGS: page.driver #{page.driver.class} does not respond to #browser"
|
26
20
|
end
|
27
21
|
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def locate_logs(browser, notifier:)
|
26
|
+
if browser.respond_to?(:logs)
|
27
|
+
return browser.logs
|
28
|
+
elsif browser.respond_to?(:manage)
|
29
|
+
if browser.manage.respond_to?(:logs)
|
30
|
+
return browser.manage.logs
|
31
|
+
end
|
32
|
+
notifier.notify "[with_clues: #{self.class}] NO BROWSER LOGS: page.driver.browser.manage #{browser.manage.class} does not respond to #logs"
|
33
|
+
else
|
34
|
+
notifier.notify "[with_clues: #{self.class}] NO BROWSER LOGS: page.driver.browser #{browser.class} does not respond to #manage or #logs"
|
35
|
+
end
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
28
39
|
end
|
29
40
|
end
|
data/lib/with_clues/html.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
1
|
module WithClues
|
2
2
|
class Html
|
3
3
|
def dump(notifier, page:, context:)
|
4
|
-
if !page.respond_to?(:html)
|
5
|
-
notifier.notify "Something may be wrong. page (#{page.class}) does not respond to #html"
|
6
|
-
return
|
7
|
-
end
|
8
4
|
notifier.blank_line
|
9
5
|
notifier.notify "HTML {"
|
10
6
|
notifier.blank_line
|
11
|
-
|
7
|
+
if page.respond_to?(:html)
|
8
|
+
notifier.notify_raw page.html
|
9
|
+
elsif page.respond_to?(:native)
|
10
|
+
notifier.notify_raw page.native
|
11
|
+
else
|
12
|
+
notifier.notify "[!] Something may be wrong. page (#{page.class}) does not respond to #html or #native"
|
13
|
+
end
|
12
14
|
notifier.blank_line
|
13
15
|
notifier.notify "} END HTML"
|
14
16
|
end
|
data/lib/with_clues/method.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require_relative "html"
|
2
2
|
require_relative "browser_logs"
|
3
3
|
require_relative "notifier"
|
4
|
+
require_relative "private/custom_clue_method_analysis"
|
4
5
|
|
5
6
|
module WithClues
|
6
7
|
module Method
|
@@ -23,18 +24,25 @@ module WithClues
|
|
23
24
|
@@clue_classes[:custom].each do |klass|
|
24
25
|
klass.new.dump(notifier, context: context)
|
25
26
|
end
|
26
|
-
if
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
klass.new.dump(notifier, context: context, page: page)
|
27
|
+
if defined?(page)
|
28
|
+
notifier.notify "Test failed: #{ex.message}"
|
29
|
+
@@clue_classes[:require_page].each do |klass|
|
30
|
+
klass.new.dump(notifier, context: context, page: page)
|
31
|
+
end
|
32
32
|
end
|
33
33
|
raise ex
|
34
34
|
end
|
35
35
|
|
36
36
|
def self.use_custom_clue(klass)
|
37
|
-
|
37
|
+
dump_method = klass.instance_method(:dump)
|
38
|
+
analysis = WithClues::Private::CustomClueMethodAnalysis.from_method(dump_method)
|
39
|
+
if analysis.standard_implementation?
|
40
|
+
@@clue_classes[:custom] << klass
|
41
|
+
elsif analysis.requires_page_object?
|
42
|
+
@@clue_classes[:require_page] << klass
|
43
|
+
else
|
44
|
+
analysis.raise_exception!
|
45
|
+
end
|
38
46
|
end
|
39
47
|
end
|
40
48
|
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
module WithClues
|
2
|
+
module Private
|
3
|
+
class CustomClueMethodAnalysis
|
4
|
+
|
5
|
+
def self.from_method(unbound_method)
|
6
|
+
|
7
|
+
params = unbound_method.parameters.map { |param_array| Param.new(param_array) }
|
8
|
+
|
9
|
+
if params.size == 2
|
10
|
+
two_arg_method = TwoArgMethod.new(params)
|
11
|
+
if two_arg_method.valid?
|
12
|
+
return StandardImplementation.new
|
13
|
+
end
|
14
|
+
|
15
|
+
return BadParams.new(two_arg_method.errors)
|
16
|
+
|
17
|
+
elsif params.size == 3
|
18
|
+
three_arg_method = ThreeArgMethod.new(params)
|
19
|
+
if three_arg_method.valid?
|
20
|
+
return RequiresPageObject.new
|
21
|
+
end
|
22
|
+
return BadParams.new(three_arg_method.errors)
|
23
|
+
end
|
24
|
+
|
25
|
+
BadParams.new([])
|
26
|
+
end
|
27
|
+
|
28
|
+
def standard_implementation?
|
29
|
+
false
|
30
|
+
end
|
31
|
+
|
32
|
+
def requires_page_object?
|
33
|
+
false
|
34
|
+
end
|
35
|
+
|
36
|
+
def raise_exception!
|
37
|
+
raise StandardError.new("Unimplemented condition found inside #from_method")
|
38
|
+
end
|
39
|
+
|
40
|
+
class Param
|
41
|
+
|
42
|
+
def initialize(method_param_array)
|
43
|
+
@type = method_param_array[0]
|
44
|
+
@name = method_param_array[1]
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
def required?
|
49
|
+
@type == :req
|
50
|
+
end
|
51
|
+
def keyword_required?
|
52
|
+
@type == :keyreq
|
53
|
+
end
|
54
|
+
|
55
|
+
def named?(*allowed_names)
|
56
|
+
allowed_names.include?(@name)
|
57
|
+
end
|
58
|
+
def name
|
59
|
+
if self.keyword_required?
|
60
|
+
"#{@name}:"
|
61
|
+
else
|
62
|
+
@name
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class TwoArgMethod
|
68
|
+
attr_reader :errors
|
69
|
+
def initialize(params)
|
70
|
+
@errors = []
|
71
|
+
if !params[0].required?
|
72
|
+
@errors << "Param 1, #{params[0].name}, is not required"
|
73
|
+
end
|
74
|
+
require_keyword(2,params[1])
|
75
|
+
end
|
76
|
+
|
77
|
+
def valid?
|
78
|
+
@errors.empty?
|
79
|
+
end
|
80
|
+
private
|
81
|
+
|
82
|
+
def require_keyword(param_number, param)
|
83
|
+
if !param.keyword_required?
|
84
|
+
@errors << "Param #{param_number}, #{param.name}, is not a required keyword param"
|
85
|
+
end
|
86
|
+
if !param.named?(*allowed_names)
|
87
|
+
@errors << "Param #{param_number}, #{param.name}, should be named context:"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def allowed_names
|
92
|
+
[ :context ]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class ThreeArgMethod < TwoArgMethod
|
97
|
+
def initialize(params)
|
98
|
+
super(params)
|
99
|
+
require_keyword(3,params[2])
|
100
|
+
end
|
101
|
+
private
|
102
|
+
def allowed_names
|
103
|
+
[ :context, :page ]
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
class GoodParams < CustomClueMethodAnalysis
|
110
|
+
def raise_exception!
|
111
|
+
raise StandardError.new("You should not have called .exception on a #{self.class.name}")
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
class RequiresPageObject < CustomClueMethodAnalysis
|
116
|
+
def requires_page_object?
|
117
|
+
true
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
class StandardImplementation < CustomClueMethodAnalysis
|
122
|
+
def standard_implementation?
|
123
|
+
true
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
class BadParams < CustomClueMethodAnalysis
|
128
|
+
def initialize(errors)
|
129
|
+
@message = errors.empty? ? DEFAULT_ERROR : errors.join(", ")
|
130
|
+
end
|
131
|
+
|
132
|
+
DEFAULT_ERROR = "dump must take one required param, one keyword param named context: and an optional keyword param named page:"
|
133
|
+
|
134
|
+
def raise_exception!
|
135
|
+
raise NameError.new(@message)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
data/lib/with_clues/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: with_clues
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dave Copeland
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-12-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -76,6 +76,8 @@ files:
|
|
76
76
|
- ".circleci/config.yml"
|
77
77
|
- ".gitignore"
|
78
78
|
- ".rspec"
|
79
|
+
- ".tool-versions"
|
80
|
+
- CHANGELOG.md
|
79
81
|
- CODE_OF_CONDUCT.md
|
80
82
|
- CONTRIBUTING.md
|
81
83
|
- Gemfile
|
@@ -84,6 +86,7 @@ files:
|
|
84
86
|
- Rakefile
|
85
87
|
- bin/ci
|
86
88
|
- bin/console
|
89
|
+
- bin/mk_circle_config
|
87
90
|
- bin/mk_gem
|
88
91
|
- bin/rake
|
89
92
|
- bin/rspec
|
@@ -93,6 +96,7 @@ files:
|
|
93
96
|
- lib/with_clues/html.rb
|
94
97
|
- lib/with_clues/method.rb
|
95
98
|
- lib/with_clues/notifier.rb
|
99
|
+
- lib/with_clues/private/custom_clue_method_analysis.rb
|
96
100
|
- lib/with_clues/version.rb
|
97
101
|
- with_clues.gemspec
|
98
102
|
homepage: https://sustainable-rails.com
|
@@ -117,7 +121,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
117
121
|
- !ruby/object:Gem::Version
|
118
122
|
version: '0'
|
119
123
|
requirements: []
|
120
|
-
rubygems_version: 3.
|
124
|
+
rubygems_version: 3.3.3
|
121
125
|
signing_key:
|
122
126
|
specification_version: 4
|
123
127
|
summary: WTF does this do?
|