crap4ruby 0.1.1 → 0.2.1
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 +25 -1
- data/CONTRIBUTING.md +12 -2
- data/README.md +42 -18
- data/lib/crap4ruby/analyzer.rb +177 -29
- data/lib/crap4ruby/cli.rb +44 -23
- data/lib/crap4ruby/coverage.rb +13 -9
- data/lib/crap4ruby/discovery.rb +22 -5
- data/lib/crap4ruby/report.rb +14 -4
- data/lib/crap4ruby/score.rb +5 -2
- data/lib/crap4ruby/version.rb +1 -1
- data/lib/crap4ruby.rb +4 -4
- data/oss-audit-report.before.md +159 -0
- data/oss-audit-report.md +110 -0
- data/scoring-audit.md +251 -0
- data/sig/crap4ruby.rbs +31 -15
- metadata +4 -1
data/scoring-audit.md
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# Scoring correctness audit
|
|
2
|
+
|
|
3
|
+
Audited 2026-10-28 at commit `0f88ceef5a6e9530487428392e9d698635a1b37f`.
|
|
4
|
+
|
|
5
|
+
## Follow-up implementation
|
|
6
|
+
|
|
7
|
+
The working tree now implements the selected O1 and O6 policies. The original findings below describe the audited commit, before these changes.
|
|
8
|
+
|
|
9
|
+
1. F1: Fixed heredoc descendant ranges, including exclusion of nested method heredocs from enclosing coverage.
|
|
10
|
+
2. F2: Shared declaration lines and body lines with trailing code after the definition now produce unknown coverage. Unknown scores pass a threshold only when `CC^2 + CC` fits it. Otherwise, the check exits 1; measured violations retain exit 2.
|
|
11
|
+
3. F3: Coverage fractions, scores, and decimal threshold comparisons retain exact rational arithmetic. Display rounding does not affect the result.
|
|
12
|
+
4. F4: Explicit definitions inside parameter defaults and superclass expressions are discovered.
|
|
13
|
+
5. F5: Complexity follows RuboCop 1.92.1, and literal bare `define_method` blocks are discovered. The remaining documented limits, including line coverage, runtime metaprogramming, and `.rb` source selection, still apply.
|
|
14
|
+
|
|
15
|
+
The complete repository gate passes on CRuby 3.3.11 and 4.0.9: 54 tests, 260 assertions, full static call typing, and all library CRAP scores at or below 10. An independent comparison matched 649 method results against the actual RuboCop 1.92.1 CLI. Eighteen additional deliberate scoring and output mutations were caught by regression assertions.
|
|
16
|
+
|
|
17
|
+
Independent CLI QA found and verified repairs for implicit block parameter locations, trailing-line coverage contamination, control characters in method names, and misleading rounded threshold diagnostics. The final tested source hashes match the working tree. Ruby 3.4 remains untested in this session.
|
|
18
|
+
|
|
19
|
+
These public scoring and threshold changes require a minor release. No version change or commit was made. The result remains CRAP with a documented line-coverage proxy, not original basis path measurement or an exhaustive runtime Ruby inventory.
|
|
20
|
+
|
|
21
|
+
## Result
|
|
22
|
+
|
|
23
|
+
The algebra matches the CRAP formula. The implementation cannot claim complete Ruby coverage or universally correct scores.
|
|
24
|
+
|
|
25
|
+
This audit reproduced incorrect coverage attribution, omitted explicit definitions, and a false threshold failure. Some broader limits are already documented design choices.
|
|
26
|
+
|
|
27
|
+
The relevant distinction is between formula correctness, input measurement, and source selection. Correct algebra does not correct missing methods or inaccurate coverage.
|
|
28
|
+
|
|
29
|
+
## Reproduced findings
|
|
30
|
+
|
|
31
|
+
### F1: Final heredocs can lose executable coverage lines
|
|
32
|
+
|
|
33
|
+
Severity: high. This is an implementation defect in method-body line selection.
|
|
34
|
+
|
|
35
|
+
[Analyzer#body_lines](lib/crap4ruby/analyzer.rb#L118) uses the outer node's location range. A final heredoc's outer location can end at its introducer.
|
|
36
|
+
|
|
37
|
+
The interpolation contains executable descendants outside that range:
|
|
38
|
+
|
|
39
|
+
```ruby
|
|
40
|
+
class Sample
|
|
41
|
+
def sample(flag)
|
|
42
|
+
<<~TEXT
|
|
43
|
+
#{if flag
|
|
44
|
+
:yes
|
|
45
|
+
else
|
|
46
|
+
:no
|
|
47
|
+
end}
|
|
48
|
+
TEXT
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
After `Sample.new.sample(true)`, fresh SimpleCov data reports executable lines 4, 5, and 7 with hits `1, 1, 0`.
|
|
54
|
+
|
|
55
|
+
The analyzer selects only line 3, whose hit count is `nil`. Reported complexity is 2, but coverage and CRAP are N/A.
|
|
56
|
+
|
|
57
|
+
With the documented line-coverage policy, coverage should be `2/3` and CRAP should be approximately `2.148148`.
|
|
58
|
+
|
|
59
|
+
The real CLI exits 0 with `--threshold 1`, because [threshold_status](lib/crap4ruby/cli.rb#L111) ignores unknown scores.
|
|
60
|
+
|
|
61
|
+
Correction: include executable heredoc descendants when selecting body locations. Preserve exclusions for nested definitions. Add a real SimpleCov regression fixture.
|
|
62
|
+
|
|
63
|
+
### F2: Uncalled inline and endless methods can receive full coverage
|
|
64
|
+
|
|
65
|
+
Severity: high for score reliability. This is a documented measurement limitation with a demonstrated false pass.
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
class Sample
|
|
69
|
+
def sample(flag) = flag ? :yes : :no
|
|
70
|
+
end
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Loading this file without calling `sample` gives its definition line a positive hit count.
|
|
74
|
+
|
|
75
|
+
[Coverage#fraction](lib/crap4ruby/coverage.rb#L40) interprets that line as covered method code. The report shows CC 2, coverage 100%, and CRAP 2.
|
|
76
|
+
|
|
77
|
+
The uncalled method should have coverage 0% and CRAP 6. The CLI exits 0 with `--threshold 3`.
|
|
78
|
+
|
|
79
|
+
The same issue affects `def sample; :yes; end`. Distinct methods or expressions sharing a line also cannot be separated reliably.
|
|
80
|
+
|
|
81
|
+
The [README limitation](README.md#L170) acknowledges shared lines. Documentation does not make the resulting 100% value proof of method execution.
|
|
82
|
+
|
|
83
|
+
Correction: require independent invocation evidence for ambiguous definition lines, or report their coverage as unknown. Define how unknown scores affect threshold enforcement.
|
|
84
|
+
|
|
85
|
+
### F3: Floating-point error can fail a mathematically equal threshold
|
|
86
|
+
|
|
87
|
+
Severity: medium. This is a numeric boundary defect.
|
|
88
|
+
|
|
89
|
+
With CC 2 and three covered lines out of five:
|
|
90
|
+
|
|
91
|
+
```text
|
|
92
|
+
Exact CRAP = 2^2 * (1 - 3/5)^3 + 2 = 2.256
|
|
93
|
+
Computed Float = 2.2560000000000002
|
|
94
|
+
Threshold = 2.256
|
|
95
|
+
CLI exit = 2
|
|
96
|
+
Snapshot CRAP = 2.256
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
This was reproduced through the real CLI using fresh SimpleCov data from this method, called with `true`:
|
|
100
|
+
|
|
101
|
+
```ruby
|
|
102
|
+
def sample(flag)
|
|
103
|
+
value = 1
|
|
104
|
+
if flag
|
|
105
|
+
value + 1
|
|
106
|
+
else
|
|
107
|
+
value - 1
|
|
108
|
+
value - 2
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
[Coverage#fraction](lib/crap4ruby/coverage.rb#L50) converts the ratio to Float. [Score.call](lib/crap4ruby/score.rb#L14) propagates rounding, and [threshold_status](lib/crap4ruby/cli.rb#L112) compares it strictly.
|
|
114
|
+
|
|
115
|
+
Correction: define exact decimal threshold semantics and preserve sufficient numeric precision through comparison. Do not compare rounded display values.
|
|
116
|
+
|
|
117
|
+
### F4: Some explicit method definitions are omitted
|
|
118
|
+
|
|
119
|
+
Severity: medium. This contradicts the stated coverage of explicit and nested definitions.
|
|
120
|
+
|
|
121
|
+
```ruby
|
|
122
|
+
def outer(value = (def inner(flag)
|
|
123
|
+
flag ? :yes : :no
|
|
124
|
+
end))
|
|
125
|
+
value
|
|
126
|
+
end
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Ruby installs `inner` when the default expression executes. The analyzer returns only `outer`, so `inner` never receives a score.
|
|
130
|
+
|
|
131
|
+
[Analyzer#discover_method](lib/crap4ruby/analyzer.rb#L64) discovers nested definitions only in the body. It does not traverse parameter expressions for definitions.
|
|
132
|
+
|
|
133
|
+
The complexity counter does inspect parameters, but it deliberately stops at nested definitions. Therefore, the omitted method's decisions are not counted elsewhere.
|
|
134
|
+
|
|
135
|
+
A second parsed example, `class Sample < (def outer; true; end; Object); end`, returns no methods.
|
|
136
|
+
|
|
137
|
+
[Analyzer#discover](lib/crap4ruby/analyzer.rb#L38) visits a class body without visiting its superclass expression.
|
|
138
|
+
|
|
139
|
+
Correction: separate definition discovery from complexity ownership. Visit executable parameter and superclass expressions while preserving each nested method's independent score.
|
|
140
|
+
|
|
141
|
+
### F5: The metric has explicit scope and policy gaps
|
|
142
|
+
|
|
143
|
+
Severity: a contract limitation, not one isolated implementation defect.
|
|
144
|
+
|
|
145
|
+
| Area | Observed behavior | Consequence |
|
|
146
|
+
| --- | --- | --- |
|
|
147
|
+
| Iteration | `items.each { ... }` adds no point; equivalent `for` adds one. | Ruby spelling changes the score. |
|
|
148
|
+
| Safe navigation | Every operation adds one, including repeated operations on the same local variable. | Differs from RuboCop's repeated-receiver discount. |
|
|
149
|
+
| Parameter defaults | Explicit decisions count toward CC; default-expression lines do not enter coverage. | Untested defaults can accompany reported 100% coverage. |
|
|
150
|
+
| Method creation | Literal `define_method`, aliases, and generated accessors are excluded. | The report does not enumerate all runtime methods. |
|
|
151
|
+
| Dynamic ownership | Dynamic receivers and some namespace expressions are skipped. `Class.new { def sample; ...; end }` is attributed lexically to `Object`. | Ownership is not a runtime method inventory. |
|
|
152
|
+
| Source selection | Only `.rb` files survive [Discovery.call](lib/crap4ruby/discovery.rb#L34), even when another filename is explicit. | `.rake`, `.gemspec`, `Rakefile`, `Gemfile`, `config.ru`, and extensionless scripts are excluded. |
|
|
153
|
+
| Non-method code | Top-level and class/module initialization decisions receive no independent score. | Whole-program Ruby coverage is outside the metric's scope. |
|
|
154
|
+
| Coverage freshness | Supplied suites merge without an age cutoff or source-content identity check. | Old results can describe different source text. |
|
|
155
|
+
| Coverage granularity | Positive line hits define coverage; branch records are ignored. | Untested branches on executed lines can appear fully covered. |
|
|
156
|
+
|
|
157
|
+
These policies are mostly documented in the [complexity rules and limits](README.md#L116). They prevent an unrestricted claim about every Ruby construct.
|
|
158
|
+
|
|
159
|
+
Additional probes found CC 1 for a standalone `value in [Integer]` predicate and no extra point for a pattern alternative or flip-flop.
|
|
160
|
+
|
|
161
|
+
Those constructs need explicit policy decisions before calling their counts wrong. Neither the CRAP formula nor the cited ports supplies a complete Ruby specification.
|
|
162
|
+
|
|
163
|
+
## What passed
|
|
164
|
+
|
|
165
|
+
The [scoring expression](lib/crap4ruby/score.rb#L14) matches:
|
|
166
|
+
|
|
167
|
+
```text
|
|
168
|
+
CRAP = CC^2 * (1 - coverage_fraction)^3 + CC
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
At zero coverage it produces `CC^2 + CC`. At full coverage it produces `CC`. Percentage conversion happens after calculation.
|
|
172
|
+
|
|
173
|
+
The existing suite passed: `bundle exec rake test`, 33 tests, zero failures.
|
|
174
|
+
|
|
175
|
+
A separate 49-case parser matrix matched the README's documented counts. It covered conditionals, loops, cases, guards, rescues, boolean operators, assignments, safe navigation, blocks, lambdas, and nested boundaries.
|
|
176
|
+
|
|
177
|
+
A 49,500-case numeric grid compared scores with exact rational results. No difference exceeded `1e-8`; exact threshold equality still fails as F3 demonstrates.
|
|
178
|
+
|
|
179
|
+
Existing tests also cover suite unions, null-line exclusion, absent files, malformed reports, and separating loaded definitions from called multiline methods.
|
|
180
|
+
|
|
181
|
+
Taking the maximum hit count across suites is sufficient for covered-line union because scoring only asks whether each count is positive.
|
|
182
|
+
|
|
183
|
+
## Upstream interpretation
|
|
184
|
+
|
|
185
|
+
### Original CRAP definition
|
|
186
|
+
|
|
187
|
+
Alberto Savoia's original definition uses the same algebra, with coverage expressed as a percentage before division by 100.
|
|
188
|
+
|
|
189
|
+
It specifies basis path coverage, not line coverage. His 2011 retrospective repeats that requirement. [Original definition](https://www.artima.com/weblogs/viewpost.jsp?thread=210575), [author's retrospective](https://testing.googleblog.com/2011/02/this-code-is-crap.html).
|
|
190
|
+
|
|
191
|
+
Inference: line or branch totals do not establish which combinations of decisions were executed. Branch coverage alone would not establish original basis path coverage.
|
|
192
|
+
|
|
193
|
+
### Implementations cited by the README
|
|
194
|
+
|
|
195
|
+
The three cited ports share the formula but use different coverage proxies and counting policies:
|
|
196
|
+
|
|
197
|
+
| Implementation | Inspected commit | Coverage input |
|
|
198
|
+
| --- | --- | --- |
|
|
199
|
+
| `unclebob/crap4java` | `69b561209f130ece728f19b0001e90df5a117c3a` | JaCoCo method instruction counters. |
|
|
200
|
+
| `unclebob/crap4clj` | `e90be2e7aa02c2ec5d6544e9cecddc6b73ad3e4d` | Weighted Cloverage forms, with LCOV line fallback. |
|
|
201
|
+
| `unclebob/crap4go` | `bee16dbdadb4af927a7792083f3cba2ae58841ed` | Weighted covered statements from Go coverage segments. |
|
|
202
|
+
|
|
203
|
+
Coverage sources: [Java](https://github.com/unclebob/crap4java/blob/69b561209f130ece728f19b0001e90df5a117c3a/src/crap4java/JacocoCoverageParser.java), [Clojure](https://github.com/unclebob/crap4clj/blob/e90be2e7aa02c2ec5d6544e9cecddc6b73ad3e4d/src/crap4clj/coverage.cljc), [Go](https://github.com/unclebob/crap4go/blob/bee16dbdadb4af927a7792083f3cba2ae58841ed/internal/coverage/coverage.go).
|
|
204
|
+
|
|
205
|
+
Formula sources: [Java](https://github.com/unclebob/crap4java/blob/69b561209f130ece728f19b0001e90df5a117c3a/src/crap4java/CrapScore.java), [Clojure](https://github.com/unclebob/crap4clj/blob/e90be2e7aa02c2ec5d6544e9cecddc6b73ad3e4d/src/crap4clj/crap.cljc), [Go](https://github.com/unclebob/crap4go/blob/bee16dbdadb4af927a7792083f3cba2ae58841ed/internal/crap/crap.go).
|
|
206
|
+
|
|
207
|
+
The ports also differ in extracted units and handling absent coverage. Their implementations cannot define a single complete Ruby contract.
|
|
208
|
+
|
|
209
|
+
Some upstream README examples contain arithmetic errors. Both Go and Clojure show CC 12, coverage 45%, and CRAP 130.2; the formula gives 35.958.
|
|
210
|
+
|
|
211
|
+
Clojure also shows CC 8, coverage 82%, and CRAP 3.4. The formula gives 8.373248, and a score below CC is impossible.
|
|
212
|
+
|
|
213
|
+
Example sources: [Go README](https://github.com/unclebob/crap4go/blob/bee16dbdadb4af927a7792083f3cba2ae58841ed/README.md), [Clojure README](https://github.com/unclebob/crap4clj/blob/e90be2e7aa02c2ec5d6544e9cecddc6b73ad3e4d/README.md).
|
|
214
|
+
|
|
215
|
+
### Ruby reference policy
|
|
216
|
+
|
|
217
|
+
RuboCop `v1.92.1`, commit `aa228eb03094d66aca26664839ca14b10d76f702`, provides an established Ruby convention. CRAP does not require that convention.
|
|
218
|
+
|
|
219
|
+
Its complexity calculation counts known iteration blocks and block arguments, discounts repeated safe navigation on a local receiver, and excludes parameter-default decisions.
|
|
220
|
+
|
|
221
|
+
It counts each `when` clause once, matching this project. Its method detector also recognizes bare `define_method` calls with literal names.
|
|
222
|
+
|
|
223
|
+
Sources: [complexity counter](https://github.com/rubocop/rubocop/blob/aa228eb03094d66aca26664839ca14b10d76f702/lib/rubocop/cop/metrics/cyclomatic_complexity.rb), [iteration rules](https://github.com/rubocop/rubocop/blob/aa228eb03094d66aca26664839ca14b10d76f702/lib/rubocop/cop/metrics/utils/iterating_block.rb), [safe-navigation rules](https://github.com/rubocop/rubocop/blob/aa228eb03094d66aca26664839ca14b10d76f702/lib/rubocop/cop/metrics/utils/repeated_csend_discount.rb), [method detection](https://github.com/rubocop/rubocop/blob/aa228eb03094d66aca26664839ca14b10d76f702/lib/rubocop/cop/mixin/method_complexity.rb).
|
|
224
|
+
|
|
225
|
+
Ruby documents separate line, branch, and method coverage modes. Its documented modes do not include basis path coverage. [Ruby Coverage API](https://docs.ruby-lang.org/en/master/Coverage.html).
|
|
226
|
+
|
|
227
|
+
## Evidence scope
|
|
228
|
+
|
|
229
|
+
F1 through F4 were reproduced using CRuby 3.3.11 and 4.0.9, Prism 1.9.0, and SimpleCov 1.3.2.
|
|
230
|
+
|
|
231
|
+
F1 through F3 include actual subprocess CLI runs with freshly generated SimpleCov reports. The nested-default example also executed successfully and installed its omitted method.
|
|
232
|
+
|
|
233
|
+
The parser matrix, numeric grid, and existing suite ran on CRuby 4.0.9. Ruby 3.4 execution was not attempted after dependency checking found missing `lefthook`.
|
|
234
|
+
|
|
235
|
+
Runtime coverage instrumentation can differ between Ruby versions. The audit observed different executable-line treatment for a pattern-matching `case` header between 3.3 and 4.0.
|
|
236
|
+
|
|
237
|
+
Upstream evidence came from primary publications, documentation, and fixed GitHub revisions. Upstream programs were inspected but not executed.
|
|
238
|
+
|
|
239
|
+
Prism 1.0.0 source contains the checked call/index node classes and generates their `safe_navigation?` predicates. This was a source check, not minimum-version execution.
|
|
240
|
+
|
|
241
|
+
Sources: [Prism node schema](https://github.com/ruby/prism/blob/163a2659260c6c74d8e7e02c5431fc61d17315c1/config.yml), [Ruby node generator](https://github.com/ruby/prism/blob/163a2659260c6c74d8e7e02c5431fc61d17315c1/templates/lib/prism/node.rb.erb).
|
|
242
|
+
|
|
243
|
+
No production code, dependencies, or existing tests were changed. Temporary probe scripts were removed after recording their source examples and results here.
|
|
244
|
+
|
|
245
|
+
## Recommended sequence
|
|
246
|
+
|
|
247
|
+
1. Fix heredoc location selection and discovery of explicit definitions in executable expressions, with real coverage regressions.
|
|
248
|
+
2. Define ambiguous and unknown coverage behavior, including threshold enforcement, before reporting full coverage for shared definition lines.
|
|
249
|
+
3. Make exact threshold equality reliable with a documented numeric comparison policy.
|
|
250
|
+
4. Adopt and document one Ruby complexity convention, with explicit decisions for iterators, defaults, patterns, and safe navigation.
|
|
251
|
+
5. Describe the result as CRAP using that convention and its coverage proxy. Avoid claims of complete Ruby analysis or original basis path measurement.
|
data/sig/crap4ruby.rbs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
module Crap4Ruby
|
|
2
2
|
VERSION: String
|
|
3
|
+
type score = Float | Rational
|
|
3
4
|
|
|
4
5
|
class Error < StandardError
|
|
5
6
|
end
|
|
@@ -8,12 +9,12 @@ module Crap4Ruby
|
|
|
8
9
|
attr_reader name: String
|
|
9
10
|
attr_reader namespace: String
|
|
10
11
|
attr_reader complexity: Integer
|
|
11
|
-
attr_reader lines: Array[Integer]
|
|
12
|
+
attr_reader lines: Array[Integer]?
|
|
12
13
|
attr_reader path: String
|
|
13
|
-
def self.new: (String name, String namespace, Integer complexity, Array[Integer] lines, String path) -> instance
|
|
14
|
-
| (name: String, namespace: String, complexity: Integer, lines: Array[Integer]
|
|
14
|
+
def self.new: (String name, String namespace, Integer complexity, Array[Integer]? lines, String path) -> instance
|
|
15
|
+
| (name: String, namespace: String, complexity: Integer, lines: Array[Integer]?, path: String) -> instance
|
|
15
16
|
alias self.[] self.new
|
|
16
|
-
def with: (?name: String, ?namespace: String, ?complexity: Integer, ?lines: Array[Integer]
|
|
17
|
+
def with: (?name: String, ?namespace: String, ?complexity: Integer, ?lines: Array[Integer]?, ?path: String) -> instance
|
|
17
18
|
end
|
|
18
19
|
|
|
19
20
|
class Entry < Data
|
|
@@ -21,24 +22,36 @@ module Crap4Ruby
|
|
|
21
22
|
attr_reader namespace: String
|
|
22
23
|
attr_reader complexity: Integer
|
|
23
24
|
attr_reader coverage: Float?
|
|
24
|
-
attr_reader crap:
|
|
25
|
+
attr_reader crap: score?
|
|
25
26
|
attr_reader path: String
|
|
26
|
-
def self.new: (String name, String namespace, Integer complexity, Float? coverage,
|
|
27
|
-
| (name: String, namespace: String, complexity: Integer, coverage: Float?, crap:
|
|
27
|
+
def self.new: (String name, String namespace, Integer complexity, Float? coverage, score? crap, String path) -> instance
|
|
28
|
+
| (name: String, namespace: String, complexity: Integer, coverage: Float?, crap: score?, path: String) -> instance
|
|
28
29
|
alias self.[] self.new
|
|
29
|
-
def with: (?name: String, ?namespace: String, ?complexity: Integer, ?coverage: Float?, ?crap:
|
|
30
|
+
def with: (?name: String, ?namespace: String, ?complexity: Integer, ?coverage: Float?, ?crap: score?, ?path: String) -> instance
|
|
30
31
|
end
|
|
31
32
|
|
|
32
33
|
class Analyzer
|
|
34
|
+
ITERATING_METHODS: Array[Symbol]
|
|
33
35
|
def call: (String source, path: String) -> Array[MethodInfo]
|
|
34
36
|
private
|
|
35
37
|
def discover: (Prism::Node? node, Array[String] scope, bool singleton, String path) -> Array[MethodInfo]
|
|
38
|
+
def discover_class: (Prism::ClassNode | Prism::ModuleNode node, Array[String] scope, bool singleton, String path) -> Array[MethodInfo]
|
|
39
|
+
def discover_call: (Prism::CallNode node, Array[String] scope, bool singleton, String path) -> Array[MethodInfo]
|
|
36
40
|
def discover_method: (Prism::DefNode node, Array[String] scope, bool singleton, String path) -> Array[MethodInfo]
|
|
41
|
+
def discover_block: (Prism::BlockNode block, String name, Array[String] scope, bool singleton, String path) -> Array[MethodInfo]
|
|
42
|
+
def defined_name: (Prism::Node node) -> String?
|
|
43
|
+
def method_owner: (Prism::DefNode node, Array[String] scope) -> Array[String]?
|
|
37
44
|
def qualify: (Prism::Node? node, Array[String] scope, ?declaration: bool) -> Array[String]?
|
|
38
|
-
def decisions: (Prism::Node? node) -> Integer
|
|
45
|
+
def decisions: (Prism::Node? node, ?Hash[Symbol, bool] seen, ?target: bool) -> Integer
|
|
46
|
+
def child_decisions: (Prism::Node node, Hash[Symbol, bool] seen, bool target) -> Integer
|
|
47
|
+
def assignment_target?: (Prism::Node node, Prism::Node child, bool target) -> bool
|
|
48
|
+
def decision?: (Prism::Node node) -> bool
|
|
49
|
+
def safe_navigation?: (Prism::Node node, Hash[Symbol, bool] seen) -> bool
|
|
50
|
+
def iteration?: (Prism::Node node) -> bool
|
|
39
51
|
def boundary?: (Prism::Node node) -> bool
|
|
40
|
-
def body_lines: (Prism::Node? node) -> Array[Integer]
|
|
41
|
-
def
|
|
52
|
+
def body_lines: (Prism::Node? node, after: Integer, ending: Prism::Location) -> Array[Integer]?
|
|
53
|
+
def trailing_code?: (Prism::Location location) -> bool
|
|
54
|
+
def body_end_line: (Prism::Node node, Array[Integer] excluded) -> Integer
|
|
42
55
|
end
|
|
43
56
|
|
|
44
57
|
type json = nil | bool | Integer | Float | String | Array[json] | Hash[String, json]
|
|
@@ -47,7 +60,7 @@ module Crap4Ruby
|
|
|
47
60
|
@files: Hash[String, Array[Integer?]]
|
|
48
61
|
def self.load: (String path, root: String) -> Coverage
|
|
49
62
|
def initialize: (json suites, root: String) -> void
|
|
50
|
-
def fraction: (MethodInfo method) ->
|
|
63
|
+
def fraction: (MethodInfo method) -> Rational?
|
|
51
64
|
private
|
|
52
65
|
def add_suite: (json suite, String root) -> void
|
|
53
66
|
def add_file: (String path, json data, String root) -> void
|
|
@@ -56,6 +69,7 @@ module Crap4Ruby
|
|
|
56
69
|
module Discovery
|
|
57
70
|
EXCLUDED: Array[String]
|
|
58
71
|
def self.call: (root: String, source_roots: Array[String], paths: Array[String], changed: bool) -> Array[String]
|
|
72
|
+
def self.selection_roots: (String root, Array[String] source_roots, Array[String] existing) -> Array[String]
|
|
59
73
|
def self.walk: (String root) -> Array[String]
|
|
60
74
|
def self.git: (String root, *String arguments) -> String
|
|
61
75
|
def self.changed_files: (String root) -> Array[String]
|
|
@@ -68,8 +82,9 @@ module Crap4Ruby
|
|
|
68
82
|
module Report
|
|
69
83
|
def self.sorted: (Array[Entry] entries) -> Array[Entry]
|
|
70
84
|
def self.table: (Array[Entry] entries) -> String
|
|
85
|
+
def self.label: (String value) -> String
|
|
71
86
|
def self.edn: (Array[Entry] entries) -> String
|
|
72
|
-
def self.number: (
|
|
87
|
+
def self.number: (score? value) -> String
|
|
73
88
|
def self.write: (Array[Entry] entries, root: String) -> String
|
|
74
89
|
end
|
|
75
90
|
|
|
@@ -80,15 +95,16 @@ module Crap4Ruby
|
|
|
80
95
|
|
|
81
96
|
class CLI
|
|
82
97
|
type options = { root: String, source_roots: Array[String], changed: bool, coverage: String,
|
|
83
|
-
?help: bool, ?version: bool, ?no_coverage: bool, ?existing: bool, ?command: String, ?threshold:
|
|
98
|
+
?help: bool, ?version: bool, ?no_coverage: bool, ?no_save: bool, ?existing: bool, ?command: String, ?threshold: Rational }
|
|
84
99
|
@stdout: _Output
|
|
85
100
|
@stderr: _Output
|
|
86
101
|
def initialize: (?stdout: _Output, ?stderr: _Output) -> void
|
|
87
102
|
def run: (Array[String] arguments) -> Integer
|
|
88
103
|
private
|
|
104
|
+
def analyze: (Array[String] files, Coverage? coverage) -> Array[Entry]
|
|
89
105
|
def parse_options: (Array[String] arguments) -> [options, OptionParser, Array[String]]
|
|
90
106
|
def validate_options: (options options) -> void
|
|
91
|
-
def threshold_status: (Array[Entry] entries,
|
|
107
|
+
def threshold_status: (Array[Entry] entries, Rational? threshold) -> Integer
|
|
92
108
|
def load_coverage: (options options, String root) -> Coverage
|
|
93
109
|
def run_coverage: (String command, String root, String report) -> void
|
|
94
110
|
def report_stamp: (String path) -> [Integer, Time, Time, Integer]?
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: crap4ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Leonid Svyatov
|
|
@@ -52,6 +52,9 @@ files:
|
|
|
52
52
|
- lib/crap4ruby/report.rb
|
|
53
53
|
- lib/crap4ruby/score.rb
|
|
54
54
|
- lib/crap4ruby/version.rb
|
|
55
|
+
- oss-audit-report.before.md
|
|
56
|
+
- oss-audit-report.md
|
|
57
|
+
- scoring-audit.md
|
|
55
58
|
- sig/crap4ruby.rbs
|
|
56
59
|
- sig/manifest.yaml
|
|
57
60
|
- sig/stdlib.rbs
|