yardcheck 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +3 -0
- data/.rubocop.yml +214 -0
- data/.rubocop_todo.yml +69 -0
- data/.ruby-version +1 -0
- data/Gemfile +22 -0
- data/Guardfile +5 -0
- data/README.md +83 -0
- data/bin/yardcheck +6 -0
- data/lib/yardcheck.rb +26 -0
- data/lib/yardcheck/color.rb +27 -0
- data/lib/yardcheck/const.rb +39 -0
- data/lib/yardcheck/documentation.rb +29 -0
- data/lib/yardcheck/documentation/method_object.rb +111 -0
- data/lib/yardcheck/method_call.rb +38 -0
- data/lib/yardcheck/method_tracer.rb +86 -0
- data/lib/yardcheck/observation.rb +72 -0
- data/lib/yardcheck/proxy.rb +33 -0
- data/lib/yardcheck/runner.rb +93 -0
- data/lib/yardcheck/source_lines.rb +29 -0
- data/lib/yardcheck/spec_observer.rb +28 -0
- data/lib/yardcheck/test_runner.rb +27 -0
- data/lib/yardcheck/test_value.rb +82 -0
- data/lib/yardcheck/typedef.rb +122 -0
- data/lib/yardcheck/typedef/parser.rb +82 -0
- data/lib/yardcheck/version.rb +5 -0
- data/lib/yardcheck/violation.rb +156 -0
- data/lib/yardcheck/warning.rb +14 -0
- data/spec/integration/yardcheck_spec.rb +57 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/unit/yardcheck/const_spec.rb +48 -0
- data/spec/unit/yardcheck/documentation_spec.rb +148 -0
- data/spec/unit/yardcheck/method_tracer_spec.rb +59 -0
- data/spec/unit/yardcheck/runner_spec.rb +183 -0
- data/spec/unit/yardcheck/test_value_spec.rb +25 -0
- data/spec/unit/yardcheck/typedef/parser_spec.rb +37 -0
- data/spec/unit/yardcheck/typedef_spec.rb +32 -0
- data/test_app/.rspec +1 -0
- data/test_app/Gemfile +7 -0
- data/test_app/Gemfile.lock +66 -0
- data/test_app/lib/test_app.rb +119 -0
- data/test_app/spec/test_app_spec.rb +49 -0
- data/yardcheck.gemspec +24 -0
- metadata +158 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 88750f901e803de9b757d1699df2284e811e1b46
|
4
|
+
data.tar.gz: 47016f5393d602d75bbaf3a736735b9d93680eb9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 688559a7d4caebc0218a1193ed67add77977e4c191e1f58767fa85e0120503a333d4146fe148d9f205c6940972f4d2451883e91fc21d244f3cc7575a3ac49b85
|
7
|
+
data.tar.gz: 3ae9fe9623004ec459faf4a1cfb475c7f60e7e4f2f47a177ae160360d92a5ef6c44a24fe3acd00c067fb09e0d9eb072be1dcae284dc7949fcb117731b760cdc6
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,214 @@
|
|
1
|
+
---
|
2
|
+
inherit_from: .rubocop_todo.yml
|
3
|
+
require:
|
4
|
+
- rubocop-rspec
|
5
|
+
- rubocop/devtools
|
6
|
+
AllCops:
|
7
|
+
Exclude:
|
8
|
+
- 'test_app/**/*'
|
9
|
+
- 'tmp/**/*'
|
10
|
+
- vendor/**/*
|
11
|
+
DisplayCopNames: true
|
12
|
+
TargetRubyVersion: 2.3
|
13
|
+
# This ends up being too spammy
|
14
|
+
Style/Documentation:
|
15
|
+
Enabled: false
|
16
|
+
Style/ExtraSpacing:
|
17
|
+
AllowForAlignment: true
|
18
|
+
Metrics/LineLength:
|
19
|
+
Max: 100
|
20
|
+
Metrics/BlockLength:
|
21
|
+
Exclude:
|
22
|
+
# Ignore RSpec DSL
|
23
|
+
- spec/**/*
|
24
|
+
# Ignore Rake task DSL
|
25
|
+
- Rakefile
|
26
|
+
Style/IfUnlessModifier:
|
27
|
+
MaxLineLength: 100
|
28
|
+
Style/Next:
|
29
|
+
EnforcedStyle: always
|
30
|
+
Style/PercentLiteralDelimiters:
|
31
|
+
PreferredDelimiters:
|
32
|
+
'%i': '[]'
|
33
|
+
'%I': '[]'
|
34
|
+
'%q': '{}'
|
35
|
+
'%Q': '{}'
|
36
|
+
'%r': '{}'
|
37
|
+
'%s': ()
|
38
|
+
'%w': '[]'
|
39
|
+
'%W': '[]'
|
40
|
+
'%x': ()
|
41
|
+
Style/TrivialAccessors:
|
42
|
+
ExactNameMatch: false
|
43
|
+
Style/SymbolArray:
|
44
|
+
Enabled: true
|
45
|
+
Style/BarePercentLiterals:
|
46
|
+
EnforcedStyle: percent_q
|
47
|
+
Style/CollectionMethods:
|
48
|
+
Enabled: true
|
49
|
+
Style/Send:
|
50
|
+
Enabled: true
|
51
|
+
Style/AutoResourceCleanup:
|
52
|
+
Enabled: true
|
53
|
+
Style/FirstArrayElementLineBreak:
|
54
|
+
Enabled: true
|
55
|
+
Style/FirstHashElementLineBreak:
|
56
|
+
Enabled: true
|
57
|
+
Style/FirstMethodArgumentLineBreak:
|
58
|
+
Enabled: true
|
59
|
+
Style/FirstMethodParameterLineBreak:
|
60
|
+
Enabled: true
|
61
|
+
Style/MultilineArrayBraceLayout:
|
62
|
+
Enabled: true
|
63
|
+
Style/MultilineAssignmentLayout:
|
64
|
+
EnforcedStyle: new_line
|
65
|
+
Enabled: true
|
66
|
+
Style/MultilineHashBraceLayout:
|
67
|
+
Enabled: true
|
68
|
+
Style/MultilineMethodCallBraceLayout:
|
69
|
+
Enabled: true
|
70
|
+
Style/MultilineMethodDefinitionBraceLayout:
|
71
|
+
Enabled: true
|
72
|
+
Style/OptionHash:
|
73
|
+
Enabled: true
|
74
|
+
Style/StringMethods:
|
75
|
+
Enabled: true
|
76
|
+
Style/IndentArray:
|
77
|
+
EnforcedStyle: consistent
|
78
|
+
Style/IndentHash:
|
79
|
+
EnforcedStyle: consistent
|
80
|
+
MultilineMethodCallIndentation:
|
81
|
+
EnforcedStyle: indented
|
82
|
+
Style/Alias:
|
83
|
+
EnforcedStyle: prefer_alias_method
|
84
|
+
Style/AlignHash:
|
85
|
+
EnforcedColonStyle: table
|
86
|
+
Style/SignalException:
|
87
|
+
EnforcedStyle: semantic
|
88
|
+
Style/SingleLineBlockParams:
|
89
|
+
Enabled: false
|
90
|
+
# We prefer being able to write
|
91
|
+
#
|
92
|
+
# foo(*%w[bar baz qux norf hello goodbye])
|
93
|
+
#
|
94
|
+
# over
|
95
|
+
#
|
96
|
+
# foo('bar', 'baz', 'qux', 'norf', 'hello', 'goodbye')
|
97
|
+
#
|
98
|
+
# because
|
99
|
+
#
|
100
|
+
# 1. the `%w` signals that all elements are strings without interpolation
|
101
|
+
# 2. the `%w` case is more compact
|
102
|
+
#
|
103
|
+
# The only exception is method invocations with a single argument. These
|
104
|
+
# cases should be `foo('bar')` and never `foo(*%w[bar])`
|
105
|
+
#
|
106
|
+
Lint/UnneededSplatExpansion:
|
107
|
+
Enabled: false
|
108
|
+
# We only use guard clauses when it guards two or more statements:
|
109
|
+
#
|
110
|
+
# # bad
|
111
|
+
# def foo
|
112
|
+
# return if bar
|
113
|
+
#
|
114
|
+
# baz
|
115
|
+
# end
|
116
|
+
#
|
117
|
+
# # good
|
118
|
+
# def foo
|
119
|
+
# baz if bar
|
120
|
+
# end
|
121
|
+
#
|
122
|
+
# This includes conditionals with an `else` branch:
|
123
|
+
#
|
124
|
+
# # bad
|
125
|
+
# def foo
|
126
|
+
# return qux if bar
|
127
|
+
#
|
128
|
+
# baz
|
129
|
+
# end
|
130
|
+
#
|
131
|
+
# # good
|
132
|
+
# def foo
|
133
|
+
# if bar
|
134
|
+
# qux
|
135
|
+
# else
|
136
|
+
# baz
|
137
|
+
# end
|
138
|
+
# end
|
139
|
+
#
|
140
|
+
# It is up to the author of the code in question if the condition concerns
|
141
|
+
# exactly two statements
|
142
|
+
#
|
143
|
+
# # ok
|
144
|
+
# def foo
|
145
|
+
# return if bar
|
146
|
+
#
|
147
|
+
# baz
|
148
|
+
# qux
|
149
|
+
# end
|
150
|
+
#
|
151
|
+
# # also ok
|
152
|
+
# def foo
|
153
|
+
# if bar
|
154
|
+
# baz
|
155
|
+
# qux
|
156
|
+
# end
|
157
|
+
# end
|
158
|
+
#
|
159
|
+
# Use a guard clause if more than two statements are being guarded by the conditional
|
160
|
+
#
|
161
|
+
# # bad
|
162
|
+
# def foo
|
163
|
+
# if bar
|
164
|
+
# baz
|
165
|
+
# qux
|
166
|
+
# norf
|
167
|
+
# end
|
168
|
+
# end
|
169
|
+
#
|
170
|
+
# # good
|
171
|
+
# def foo
|
172
|
+
# return if bar
|
173
|
+
#
|
174
|
+
# baz
|
175
|
+
# qux
|
176
|
+
# norf
|
177
|
+
# end
|
178
|
+
Style/GuardClause:
|
179
|
+
Enabled: false
|
180
|
+
# Prefer writing an empty method on two lines
|
181
|
+
#
|
182
|
+
# # good
|
183
|
+
# def foo
|
184
|
+
# end
|
185
|
+
#
|
186
|
+
# # bar
|
187
|
+
# def foo; end
|
188
|
+
#
|
189
|
+
Style/EmptyMethod:
|
190
|
+
EnforcedStyle: expanded
|
191
|
+
# RuboCop disables end alignment by default. Explanation:
|
192
|
+
#
|
193
|
+
# The end alignment cops are in the Lint category because the bad
|
194
|
+
# indentation could be something more serious than just a style issue.
|
195
|
+
# It could be a mistake in which keyword you think you're matching with the end.
|
196
|
+
# (ruby -w warns for these too, by the way.) So for this reason I don't think
|
197
|
+
# we can add auto-correct for these cops.
|
198
|
+
#
|
199
|
+
# From https://github.com/bbatsov/rubocop/pull/1789#issuecomment-92308357
|
200
|
+
#
|
201
|
+
# I think we have more than enough tools that sound the alarms if we have
|
202
|
+
# such an obvious mistake like mismatched tokens.
|
203
|
+
#
|
204
|
+
# - Our specs are likely to fail
|
205
|
+
# - RuboCop will flag it regardless, it just doesn't autocorrect it by default
|
206
|
+
# - Ruby will emit a warning which we configure to fail our specs
|
207
|
+
#
|
208
|
+
# So I think it is safe to enable autocorrect for end alignment cops because it
|
209
|
+
# does not seem unsafe and it improves workflow to be able to autocorrect alignment
|
210
|
+
Lint/DefEndAlignment:
|
211
|
+
AutoCorrect: true
|
212
|
+
# See explanation for `Lint/DefEndAlignment`
|
213
|
+
Lint/EndAlignment:
|
214
|
+
AutoCorrect: true
|
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2017-03-22 20:59:41 -0700 using RuboCop version 0.47.1.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 1
|
10
|
+
Lint/HandleExceptions:
|
11
|
+
Exclude:
|
12
|
+
- 'spec/spec_helper.rb'
|
13
|
+
|
14
|
+
# Offense count: 4
|
15
|
+
Metrics/AbcSize:
|
16
|
+
Max: 22
|
17
|
+
|
18
|
+
# Offense count: 1
|
19
|
+
Metrics/CyclomaticComplexity:
|
20
|
+
Max: 8
|
21
|
+
|
22
|
+
# Offense count: 5
|
23
|
+
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
|
24
|
+
# URISchemes: http, https
|
25
|
+
Metrics/LineLength:
|
26
|
+
Max: 138
|
27
|
+
|
28
|
+
# Offense count: 3
|
29
|
+
# Configuration parameters: CountComments.
|
30
|
+
Metrics/MethodLength:
|
31
|
+
Max: 27
|
32
|
+
|
33
|
+
# Offense count: 1
|
34
|
+
RSpec/DescribeClass:
|
35
|
+
Exclude:
|
36
|
+
- 'spec/integration/yardcheck_spec.rb'
|
37
|
+
|
38
|
+
# Offense count: 6
|
39
|
+
# Configuration parameters: Max.
|
40
|
+
RSpec/ExampleLength:
|
41
|
+
Exclude:
|
42
|
+
- 'spec/integration/yardcheck_spec.rb'
|
43
|
+
- 'spec/unit/yardcheck/documentation_spec.rb'
|
44
|
+
- 'spec/unit/yardcheck/method_tracer_spec.rb'
|
45
|
+
- 'spec/unit/yardcheck/typedef/parser_spec.rb'
|
46
|
+
- 'spec/unit/yardcheck/typedef_spec.rb'
|
47
|
+
|
48
|
+
# Offense count: 1
|
49
|
+
# Configuration parameters: IgnoreSymbolicNames.
|
50
|
+
RSpec/VerifiedDoubles:
|
51
|
+
Exclude:
|
52
|
+
- 'spec/unit/yardcheck/test_value_spec.rb'
|
53
|
+
|
54
|
+
# Offense count: 1
|
55
|
+
Style/MethodMissing:
|
56
|
+
Exclude:
|
57
|
+
- 'lib/yardcheck/proxy.rb'
|
58
|
+
|
59
|
+
# Offense count: 6
|
60
|
+
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
61
|
+
# SupportedStyles: separated, grouped
|
62
|
+
Style/MixinGrouping:
|
63
|
+
Exclude:
|
64
|
+
- 'lib/yardcheck/documentation.rb'
|
65
|
+
- 'lib/yardcheck/documentation/method_object.rb'
|
66
|
+
- 'lib/yardcheck/method_tracer.rb'
|
67
|
+
- 'lib/yardcheck/runner.rb'
|
68
|
+
- 'lib/yardcheck/spec_observer.rb'
|
69
|
+
- 'lib/yardcheck/typedef/parser.rb'
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.3.3
|
data/Gemfile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source 'https://rubygems.org'
|
4
|
+
|
5
|
+
ruby File.read('.ruby-version').chomp
|
6
|
+
|
7
|
+
gemspec
|
8
|
+
|
9
|
+
group :test do
|
10
|
+
gem 'rspec', '~> 3.5'
|
11
|
+
end
|
12
|
+
|
13
|
+
group :lint do
|
14
|
+
gem 'rubocop', git: 'https://github.com/bbatsov/rubocop.git'
|
15
|
+
gem 'rubocop-devtools', git: 'https://github.com/backus/rubocop-devtools.git'
|
16
|
+
gem 'rubocop-rspec', git: 'https://github.com/backus/rubocop-rspec.git'
|
17
|
+
end
|
18
|
+
|
19
|
+
gem 'guard'
|
20
|
+
gem 'guard-rspec'
|
21
|
+
gem 'mutest', '0.0.6'
|
22
|
+
gem 'mutest-rspec'
|
data/Guardfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# Yardcheck
|
2
|
+
|
3
|
+
Check whether your YARD types are correct by running your test suite. Take a look!
|
4
|
+
|
5
|
+
![yardcheck](https://cloud.githubusercontent.com/assets/2085622/24262402/211ecfbe-0fb7-11e7-86f7-1b287298339f.gif)
|
6
|
+
|
7
|
+
## What is this?
|
8
|
+
|
9
|
+
When you write documentation like this
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
# Validates the user
|
13
|
+
#
|
14
|
+
# @param user [User]
|
15
|
+
#
|
16
|
+
# @return [true,false]
|
17
|
+
# def valid?(user)
|
18
|
+
# ...
|
19
|
+
# end
|
20
|
+
```
|
21
|
+
|
22
|
+
You are saying that you are always going to be passing in a `User` instance and the method will always returns `true` or `false`.
|
23
|
+
|
24
|
+
`yardcheck` traces method invocations to observe the parameters and return values in your application while running your test suite. When your test suite finishes running we compare the observed types found while running your tests against the types in your documentation.
|
25
|
+
|
26
|
+
For example, here is part of the output from the demo gif at the top of the README:
|
27
|
+
|
28
|
+
> Expected `Dry::Types::Array::Member#try` to receive `an object responding to #call` for `block` but observed `NilClass`
|
29
|
+
>
|
30
|
+
> ```
|
31
|
+
> source: lib/dry/types/array/member.rb:35
|
32
|
+
> tests:
|
33
|
+
> - ./spec/dry/types/compiler_spec.rb:184
|
34
|
+
> - ./spec/dry/types/sum_spec.rb:47
|
35
|
+
> - ./spec/dry/types/sum_spec.rb:60
|
36
|
+
> - ./spec/dry/types/types/form_spec.rb:235
|
37
|
+
> - ./spec/dry/types/types/form_spec.rb:240
|
38
|
+
> - ./spec/dry/types/types/form_spec.rb:245
|
39
|
+
> - ./spec/dry/types/types/form_spec.rb:250
|
40
|
+
> - ./spec/dry/types/types/json_spec.rb:69
|
41
|
+
> ```
|
42
|
+
>
|
43
|
+
>
|
44
|
+
> ```ruby
|
45
|
+
> # @param [Array, Object] input
|
46
|
+
> # @param [#call] block
|
47
|
+
> # @yieldparam [Failure] failure
|
48
|
+
> # @yieldreturn [Result]
|
49
|
+
> # @return [Result]
|
50
|
+
> def try(input, &block)
|
51
|
+
> if input.is_a?(::Array)
|
52
|
+
> result = call(input, :try)
|
53
|
+
> output = result.map(&:input)
|
54
|
+
>
|
55
|
+
> if result.all?(&:success?)
|
56
|
+
> success(output)
|
57
|
+
> else
|
58
|
+
> failure = failure(output, result.select(&:failure?))
|
59
|
+
> block ? yield(failure) : failure
|
60
|
+
> end
|
61
|
+
> else
|
62
|
+
> failure = failure(input, "#{input} is not an array")
|
63
|
+
> block ? yield(failure) : failure
|
64
|
+
> end
|
65
|
+
> end
|
66
|
+
> ```
|
67
|
+
|
68
|
+
Yardcheck is doing some cool things here:
|
69
|
+
|
70
|
+
1. It outputs the offending method and documentation to give you immediate context. It also gives you the path and line number if you want to open up that file.
|
71
|
+
2. It understands that the YARD documentation `@param [#call]` means a duck typed object that responds to the method `#call`.
|
72
|
+
3. It tells you that it actually observed cases where the param was `nil` which does not respond to `#call`.
|
73
|
+
4. It lists all of the tests that observed a `nil` block param.
|
74
|
+
|
75
|
+
In this case I would update the documentation to be `@param [#call, nil] block`
|
76
|
+
|
77
|
+
# Is this ready?
|
78
|
+
|
79
|
+
Kind of.
|
80
|
+
|
81
|
+
It is not ready to be run in CI to check your documentation and it may never be since tracing method calls is fairly slow. We also sometimes mess up. For example, if another method raises an error then all of the methods that bubble up that error without rescuing it will be marked as returning `nil`. This seems like a limitation of ruby's `TracePoint` right now.
|
82
|
+
|
83
|
+
It is very helpful though. It will find a lot of cases where your documentation isn't quite right and the output is clear. Install it and give it a try.
|
data/bin/yardcheck
ADDED
data/lib/yardcheck.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'anima'
|
4
|
+
require 'concord'
|
5
|
+
require 'yard'
|
6
|
+
require 'rspec'
|
7
|
+
require 'coderay'
|
8
|
+
|
9
|
+
require 'yardcheck/version'
|
10
|
+
require 'yardcheck/runner'
|
11
|
+
require 'yardcheck/method_tracer'
|
12
|
+
require 'yardcheck/method_call'
|
13
|
+
require 'yardcheck/proxy'
|
14
|
+
require 'yardcheck/test_value'
|
15
|
+
require 'yardcheck/test_runner'
|
16
|
+
require 'yardcheck/const'
|
17
|
+
require 'yardcheck/documentation'
|
18
|
+
require 'yardcheck/documentation/method_object'
|
19
|
+
require 'yardcheck/typedef'
|
20
|
+
require 'yardcheck/typedef/parser'
|
21
|
+
require 'yardcheck/observation'
|
22
|
+
require 'yardcheck/spec_observer'
|
23
|
+
require 'yardcheck/color'
|
24
|
+
require 'yardcheck/violation'
|
25
|
+
require 'yardcheck/warning'
|
26
|
+
require 'yardcheck/source_lines'
|