with_clues 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 +4 -4
- data/CHANGELOG.md +1 -0
- data/README.md +6 -1
- data/lib/with_clues/browser_logs.rb +25 -14
- 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 +4 -2
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/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`
|
@@ -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/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: 2022-
|
11
|
+
date: 2022-12-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -77,6 +77,7 @@ files:
|
|
77
77
|
- ".gitignore"
|
78
78
|
- ".rspec"
|
79
79
|
- ".tool-versions"
|
80
|
+
- CHANGELOG.md
|
80
81
|
- CODE_OF_CONDUCT.md
|
81
82
|
- CONTRIBUTING.md
|
82
83
|
- Gemfile
|
@@ -95,6 +96,7 @@ files:
|
|
95
96
|
- lib/with_clues/html.rb
|
96
97
|
- lib/with_clues/method.rb
|
97
98
|
- lib/with_clues/notifier.rb
|
99
|
+
- lib/with_clues/private/custom_clue_method_analysis.rb
|
98
100
|
- lib/with_clues/version.rb
|
99
101
|
- with_clues.gemspec
|
100
102
|
homepage: https://sustainable-rails.com
|