solid_score 0.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.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +427 -0
  4. data/config/default.yml +36 -0
  5. data/exe/solid-score +6 -0
  6. data/lib/rubocop/cop/solid_score/dependency_inversion.rb +22 -0
  7. data/lib/rubocop/cop/solid_score/helpers.rb +74 -0
  8. data/lib/rubocop/cop/solid_score/interface_segregation.rb +22 -0
  9. data/lib/rubocop/cop/solid_score/liskov_substitution.rb +22 -0
  10. data/lib/rubocop/cop/solid_score/open_closed.rb +22 -0
  11. data/lib/rubocop/cop/solid_score/principle_base.rb +47 -0
  12. data/lib/rubocop/cop/solid_score/single_responsibility.rb +22 -0
  13. data/lib/rubocop/cop/solid_score/total_score.rb +54 -0
  14. data/lib/rubocop/solid_score/inject.rb +17 -0
  15. data/lib/rubocop-solid_score.rb +16 -0
  16. data/lib/solid_score/analyzers/base_analyzer.rb +17 -0
  17. data/lib/solid_score/analyzers/dip_analyzer.rb +173 -0
  18. data/lib/solid_score/analyzers/isp_analyzer.rb +131 -0
  19. data/lib/solid_score/analyzers/lsp_analyzer.rb +54 -0
  20. data/lib/solid_score/analyzers/mitigations.rb +19 -0
  21. data/lib/solid_score/analyzers/ocp_analyzer.rb +104 -0
  22. data/lib/solid_score/analyzers/srp_analyzer.rb +177 -0
  23. data/lib/solid_score/cli.rb +83 -0
  24. data/lib/solid_score/configuration.rb +159 -0
  25. data/lib/solid_score/diff_analyzer.rb +58 -0
  26. data/lib/solid_score/diff_classifier.rb +49 -0
  27. data/lib/solid_score/formatters/base_formatter.rb +11 -0
  28. data/lib/solid_score/formatters/html_formatter.rb +223 -0
  29. data/lib/solid_score/formatters/json_formatter.rb +45 -0
  30. data/lib/solid_score/formatters/text_formatter.rb +54 -0
  31. data/lib/solid_score/models/class_info.rb +150 -0
  32. data/lib/solid_score/models/method_info.rb +82 -0
  33. data/lib/solid_score/models/score_result.rb +95 -0
  34. data/lib/solid_score/parser/ruby_parser.rb +451 -0
  35. data/lib/solid_score/presets.rb +64 -0
  36. data/lib/solid_score/runner.rb +82 -0
  37. data/lib/solid_score/scorer.rb +35 -0
  38. data/lib/solid_score/version.rb +5 -0
  39. data/lib/solid_score.rb +28 -0
  40. metadata +114 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 465bf41b4b60ca3d4f6c9eecc7de89bb6bcf6dae598a0fa8052bca0e34a16dbf
4
+ data.tar.gz: 235fd46777ef84ab2fd31620a0171f269c1f56ff9347bdac4e98731f7a76c5c0
5
+ SHA512:
6
+ metadata.gz: 5522bbc639d6d4b88a89973f10dda2f58d59266d378361441c0bec332b355a0134255297e8d9a4888b486d1566c78b3791ab35aab8e3ef303dd88a6016d718c8
7
+ data.tar.gz: a81c10321ab5f6e75ca1d134caa1b8111112c98e9a0d3108b9f1313a338491be83c1fbad17f4b1fc55d6eaefc143692e0054fb9d39c47557837ce78903c3040a
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 harachan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,427 @@
1
+ # solid-score
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/solid_score.svg)](https://badge.fury.io/rb/solid_score)
4
+ [![Ruby](https://img.shields.io/badge/ruby-%3E%3D%203.2.0-ruby.svg)](https://www.ruby-lang.org/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ A static analysis tool that scores Ruby classes and modules against SOLID principles using AST analysis.
8
+
9
+ ## Features
10
+
11
+ - **SOLID Principles Analysis**: Scores each class/module on all five SOLID principles (SRP, OCP, LSP, ISP, DIP)
12
+ - **Multiple Output Formats**: Text (table), JSON, and HTML report output
13
+ - **Git Diff Mode**: Analyze only changed files to prevent score regression
14
+ - **Configurable Thresholds**: Set minimum scores for CI quality gates
15
+ - **Customizable Weights**: Adjust the importance of each principle in the total score
16
+ - **RuboCop Integration**: Use as RuboCop cops for seamless linting workflow
17
+
18
+ ## Installation
19
+
20
+ Add this line to your application's Gemfile:
21
+
22
+ ```ruby
23
+ gem 'solid_score'
24
+ ```
25
+
26
+ And then execute:
27
+
28
+ ```bash
29
+ bundle install
30
+ ```
31
+
32
+ Or install it yourself as:
33
+
34
+ ```bash
35
+ gem install solid_score
36
+ ```
37
+
38
+ ## Quick Start
39
+
40
+ ```bash
41
+ # Analyze current directory
42
+ solid-score .
43
+
44
+ # Analyze specific directory
45
+ solid-score app/models
46
+
47
+ # Output as JSON
48
+ solid-score app/ --format json
49
+
50
+ # Generate HTML report
51
+ solid-score app/ --format html > report.html
52
+
53
+ # Analyze only changed files (git diff)
54
+ solid-score . --diff origin/main
55
+
56
+ # Use configuration file
57
+ solid-score . --config .solid-score.yml
58
+ ```
59
+
60
+ ## Usage
61
+
62
+ ### Command Line Options
63
+
64
+ ```
65
+ Usage: solid-score [path] [options]
66
+
67
+ Options:
68
+ --format FORMAT Output format: text (default), json, html
69
+ --config FILE Path to configuration file
70
+ --min-score SCORE Minimum total score (exit 1 if below)
71
+ --min-srp SCORE Minimum SRP score
72
+ --min-ocp SCORE Minimum OCP score
73
+ --min-lsp SCORE Minimum LSP score
74
+ --min-isp SCORE Minimum ISP score
75
+ --min-dip SCORE Minimum DIP score
76
+ --diff REF Analyze only files changed since REF (git ref)
77
+ --max-decrease SCORE Maximum allowed score decrease per class
78
+ --exclude PATTERN Exclude patterns (comma-separated)
79
+ --version Show version
80
+ -h, --help Show help
81
+ ```
82
+
83
+ ### Output Examples
84
+
85
+ #### Text Format (default)
86
+
87
+ ```
88
+ solid-score v0.1.0
89
+
90
+ Analyzed 5 class(es)
91
+
92
+ Class SRP OCP LSP ISP DIP Total
93
+ -------------------------------------------------------------------------------
94
+ OrderService 100.0 100.0 100.0 100.0 100.0 100.0
95
+ UserRepository 80.0 90.0 100.0 95.0 85.0 88.0
96
+ PaymentProcessor 60.0 70.0 100.0 80.0 50.0 68.5
97
+ ShapeCalculator 60.0 35.0 100.0 100.0 100.0 78.2
98
+ GodClass 30.0 100.0 100.0 65.0 100.0 72.0
99
+ -------------------------------------------------------------------------------
100
+ Average 66.0 79.0 100.0 88.0 87.0 81.3
101
+ ```
102
+
103
+ #### JSON Format
104
+
105
+ ```json
106
+ {
107
+ "version": "0.1.0",
108
+ "classes": [
109
+ {
110
+ "class_name": "OrderService",
111
+ "file_path": "app/services/order_service.rb",
112
+ "srp": 100,
113
+ "ocp": 100.0,
114
+ "lsp": 100,
115
+ "isp": 100,
116
+ "dip": 100.0,
117
+ "total": 100.0,
118
+ "confidence": {
119
+ "srp": "high",
120
+ "ocp": "low",
121
+ "lsp": "low_medium",
122
+ "isp": "medium_high",
123
+ "dip": "high"
124
+ }
125
+ }
126
+ ],
127
+ "summary": {
128
+ "total_classes": 1,
129
+ "average_score": 100.0
130
+ }
131
+ }
132
+ ```
133
+
134
+ ## Configuration
135
+
136
+ Create a `.solid-score.yml` file in your project root:
137
+
138
+ ```yaml
139
+ # Target paths to analyze
140
+ paths:
141
+ - app/models
142
+ - app/services
143
+ - lib
144
+
145
+ # Patterns to exclude (glob format)
146
+ exclude:
147
+ - spec/**
148
+ - test/**
149
+ - tmp/**
150
+ - vendor/**
151
+
152
+ # Preset (loads predefined configuration)
153
+ # preset: rails
154
+
155
+ # Output format
156
+ format: text # or json or html
157
+
158
+ # Score thresholds (CI will fail if below)
159
+ thresholds:
160
+ total: 70
161
+ srp: 60
162
+ ocp: 50
163
+ lsp: 50
164
+ isp: 50
165
+ dip: 60
166
+
167
+ # Weight of each principle in total score (must sum to 1.0)
168
+ weights:
169
+ srp: 0.30 # 30%
170
+ ocp: 0.15 # 15%
171
+ lsp: 0.10 # 10%
172
+ isp: 0.20 # 20%
173
+ dip: 0.25 # 25%
174
+
175
+ # Git diff analysis settings
176
+ diff:
177
+ max_decrease: 5 # Max allowed score decrease per class
178
+ new_class_min: 70 # Minimum score for new classes
179
+ ```
180
+
181
+ ## SOLID Principles Scoring
182
+
183
+ ### SRP (Single Responsibility Principle)
184
+
185
+ **Metric**: LCOM4 (Lack of Cohesion of Methods 4)
186
+
187
+ Measures class cohesion using graph connectivity analysis. A class with high cohesion (methods working with shared instance variables) scores higher.
188
+
189
+ - **Score 100**: All methods are connected (single responsibility)
190
+ - **Score 0**: Methods are completely disconnected (multiple responsibilities)
191
+ - **Confidence**: High
192
+
193
+ ### OCP (Open/Closed Principle)
194
+
195
+ **Metric**: Conditional complexity + type checking patterns
196
+
197
+ Detects patterns that suggest a class needs modification for extension:
198
+ - `if/else` chains with type checking (`is_a?`, `kind_of?`, `instance_of?`)
199
+ - `case/when` statements with multiple branches
200
+ - Conditional density in methods
201
+
202
+ - **Confidence**: Low-Medium (heuristic-based)
203
+
204
+ ### LSP (Liskov Substitution Principle)
205
+
206
+ **Metric**: Inheritance contract compliance
207
+
208
+ Detects potential violations:
209
+ - Method signature changes (different parameters than parent)
210
+ - Missing `super` calls in overridden methods
211
+ - Return type inconsistencies
212
+
213
+ - **Confidence**: Low-Medium (requires runtime analysis for full accuracy)
214
+
215
+ ### ISP (Interface Segregation Principle)
216
+
217
+ **Metric**: Interface bloat detection
218
+
219
+ Measures:
220
+ - Number of public methods
221
+ - Method parameter count
222
+ - Unused method dependencies
223
+
224
+ - **Confidence**: Medium-High
225
+
226
+ ### DIP (Dependency Inversion Principle)
227
+
228
+ **Metric**: Concrete dependency ratio
229
+
230
+ Calculates the ratio of concrete class instantiations to total dependencies:
231
+ - Direct `ClassName.new` calls penalize the score
232
+ - Standard library classes (Array, Hash, String, etc.) are whitelisted
233
+ - Dependency injection patterns score higher
234
+
235
+ - **Confidence**: High
236
+
237
+ ## Rails Preset
238
+
239
+ For Rails projects, use the built-in preset to get sensible defaults:
240
+
241
+ ```yaml
242
+ # .solid-score.yml
243
+ preset: rails
244
+ thresholds:
245
+ total: 60
246
+ ```
247
+
248
+ The Rails preset configures:
249
+ - **Paths**: `app/models`, `app/controllers`, `app/services`, `app/jobs`, `app/mailers`, `lib`, etc.
250
+ - **Excludes**: `spec/**`, `test/**`, `vendor/**`, `db/**`, `tmp/**`
251
+ - **Weights**: DIP weighted higher (0.30), SRP slightly lower (0.25)
252
+ - **DIP Whitelist**: Rails, Logger, Net::HTTP, ActionMailer, ActiveJob, etc.
253
+
254
+ Explicit YAML values override the preset.
255
+
256
+ ## CI/CD Integration
257
+
258
+ ### GitHub Actions (Official Action)
259
+
260
+ ```yaml
261
+ name: SOLID Score Check
262
+
263
+ on:
264
+ pull_request:
265
+ branches: [main]
266
+
267
+ jobs:
268
+ solid-score:
269
+ runs-on: ubuntu-latest
270
+ steps:
271
+ - uses: actions/checkout@v4
272
+ with:
273
+ fetch-depth: 0
274
+
275
+ - uses: harakeishi/solid-score@main
276
+ with:
277
+ min-score: "70"
278
+ pr-comment: "true"
279
+ ```
280
+
281
+ The action supports these inputs:
282
+
283
+ | Input | Default | Description |
284
+ |-------|---------|-------------|
285
+ | `ruby-version` | `3.2` | Ruby version |
286
+ | `min-score` | `0` | Minimum total score threshold |
287
+ | `format` | `text` | Output format (text/json/html) |
288
+ | `paths` | `.` | Paths to analyze |
289
+ | `config` | `.solid-score.yml` | Config file path |
290
+ | `pr-comment` | `false` | Post score report as PR comment |
291
+ | `diff-ref` | `origin/main` | Base ref for diff comparison |
292
+
293
+ Outputs: `score-json`, `passing`, `average-score`.
294
+
295
+ ### Manual Setup
296
+
297
+ ```yaml
298
+ jobs:
299
+ solid-score:
300
+ runs-on: ubuntu-latest
301
+ steps:
302
+ - uses: actions/checkout@v4
303
+ with:
304
+ fetch-depth: 0
305
+
306
+ - uses: ruby/setup-ruby@v1
307
+ with:
308
+ ruby-version: '3.3'
309
+ bundler-cache: true
310
+
311
+ - name: Install solid-score
312
+ run: gem install solid_score
313
+
314
+ - name: Check SOLID scores
315
+ run: solid-score app/ lib/ --min-score 70
316
+
317
+ - name: Check score regression (diff mode)
318
+ run: solid-score . --diff origin/main --max-decrease 5
319
+ ```
320
+
321
+ ### RuboCop Integration
322
+
323
+ Add `rubocop-solid_score` to your `.rubocop.yml` to run SOLID score checks as part of your existing RuboCop workflow:
324
+
325
+ ```yaml
326
+ # .rubocop.yml
327
+ require:
328
+ - rubocop-solid_score
329
+ ```
330
+
331
+ #### Available Cops
332
+
333
+ | Cop | Default | Description |
334
+ |-----|---------|-------------|
335
+ | `SolidScore/TotalScore` | Enabled (70) | Checks weighted total score |
336
+ | `SolidScore/SingleResponsibility` | Disabled (60) | Checks SRP score |
337
+ | `SolidScore/OpenClosed` | Disabled (50) | Checks OCP score |
338
+ | `SolidScore/LiskovSubstitution` | Disabled (60) | Checks LSP score |
339
+ | `SolidScore/InterfaceSegregation` | Disabled (70) | Checks ISP score |
340
+ | `SolidScore/DependencyInversion` | Disabled (65) | Checks DIP score |
341
+
342
+ #### Configuration
343
+
344
+ ```yaml
345
+ # .rubocop.yml
346
+ SolidScore/TotalScore:
347
+ Enabled: true
348
+ MinScore: 70
349
+ Weights:
350
+ srp: 0.30
351
+ ocp: 0.15
352
+ lsp: 0.10
353
+ isp: 0.20
354
+ dip: 0.25
355
+ DipWhitelist:
356
+ - Rails
357
+ - Logger
358
+
359
+ # Enable individual principle checks
360
+ SolidScore/SingleResponsibility:
361
+ Enabled: true
362
+ MinScore: 60
363
+
364
+ SolidScore/DependencyInversion:
365
+ Enabled: true
366
+ MinScore: 65
367
+ ```
368
+
369
+ ### Exit Codes
370
+
371
+ | Code | Description |
372
+ |------|-------------|
373
+ | 0 | All checks passed |
374
+ | 1 | Score below threshold or regression detected |
375
+ | 2 | Invalid arguments or configuration error |
376
+
377
+ ## Development
378
+
379
+ After checking out the repo, run:
380
+
381
+ ```bash
382
+ # Install dependencies
383
+ bundle install
384
+
385
+ # Run tests
386
+ bundle exec rspec
387
+
388
+ # Run tests with coverage
389
+ COVERAGE=true bundle exec rspec
390
+
391
+ # Run linter
392
+ bundle exec rubocop
393
+
394
+ # Run the tool locally
395
+ bundle exec solid-score spec/fixtures
396
+ ```
397
+
398
+ ## Limitations
399
+
400
+ - **Static Analysis Only**: Cannot detect runtime behavior or duck typing patterns
401
+ - **OCP/LSP Accuracy**: These principles are difficult to measure statically; scores are heuristic-based
402
+ - **Module Support**: Module analysis is less accurate than class analysis
403
+ - **Metaprogramming**: Heavy use of `define_method`, `method_missing`, etc. may affect accuracy
404
+
405
+ ## Requirements
406
+
407
+ - Ruby >= 3.2.0
408
+
409
+ ## Contributing
410
+
411
+ Bug reports and pull requests are welcome on GitHub at https://github.com/harakeishi/solid-score.
412
+
413
+ 1. Fork the repository
414
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
415
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
416
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
417
+ 5. Open a Pull Request
418
+
419
+ ## License
420
+
421
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
422
+
423
+ ## References
424
+
425
+ - [SOLID Principles](https://en.wikipedia.org/wiki/SOLID) - Wikipedia
426
+ - [LCOM4 Metric](https://www.aivosto.com/project/help/pm-oo-cohesion.html) - Lack of Cohesion of Methods
427
+ - [Robert C. Martin - Clean Architecture](https://www.amazon.com/Clean-Architecture-Craftsmans-Software-Structure/dp/0134494164)
@@ -0,0 +1,36 @@
1
+ SolidScore/TotalScore:
2
+ Description: "Checks that each class/module meets a minimum SOLID total score."
3
+ Enabled: true
4
+ MinScore: 70
5
+ Weights:
6
+ srp: 0.30
7
+ ocp: 0.15
8
+ lsp: 0.10
9
+ isp: 0.20
10
+ dip: 0.25
11
+ DipWhitelist: []
12
+
13
+ SolidScore/SingleResponsibility:
14
+ Description: "Checks that each class/module meets a minimum SRP score."
15
+ Enabled: false
16
+ MinScore: 60
17
+
18
+ SolidScore/OpenClosed:
19
+ Description: "Checks that each class/module meets a minimum OCP score."
20
+ Enabled: false
21
+ MinScore: 50
22
+
23
+ SolidScore/LiskovSubstitution:
24
+ Description: "Checks that each class/module meets a minimum LSP score."
25
+ Enabled: false
26
+ MinScore: 60
27
+
28
+ SolidScore/InterfaceSegregation:
29
+ Description: "Checks that each class/module meets a minimum ISP score."
30
+ Enabled: false
31
+ MinScore: 70
32
+
33
+ SolidScore/DependencyInversion:
34
+ Description: "Checks that each class/module meets a minimum DIP score."
35
+ Enabled: false
36
+ MinScore: 65
data/exe/solid-score ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "solid_score"
5
+
6
+ SolidScore::CLI.new.run(ARGV)
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module SolidScore
6
+ # Checks that each class/module meets a minimum DIP (Dependency Inversion Principle) score.
7
+ #
8
+ # @example MinScore: 65 (default)
9
+ # SolidScore/DependencyInversion:
10
+ # Enabled: true
11
+ # MinScore: 65
12
+ class DependencyInversion < PrincipleBase
13
+ MSG = "DIP score %.1f is below minimum %g"
14
+
15
+ private
16
+
17
+ def principle_key = :dip
18
+ def principle_name = "DIP"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module SolidScore
6
+ # Shared helper for all SolidScore cops.
7
+ # Parses the file once per cop run and caches scored results.
8
+ module Helpers
9
+ private
10
+
11
+ def score_results_for
12
+ @solid_score_results ||= compute_scores(processed_source.file_path)
13
+ end
14
+
15
+ def compute_scores(file_path)
16
+ parser = ::SolidScore::Parser::RubyParser.new
17
+ scorer = ::SolidScore::Scorer.new(
18
+ weights: cop_config_weights,
19
+ dip_whitelist: cop_config_dip_whitelist
20
+ )
21
+
22
+ class_infos = parser.parse_file(file_path)
23
+ scorer.score_all(class_infos)
24
+ rescue ::Parser::SyntaxError
25
+ []
26
+ end
27
+
28
+ def cop_config_weights
29
+ weights = ::SolidScore::Models::ScoreResult::DEFAULT_WEIGHTS.dup
30
+ config_weights = cop_config["Weights"]
31
+ return weights unless config_weights
32
+
33
+ config_weights.each { |k, v| weights[k.to_sym] = v.to_f }
34
+ weights
35
+ end
36
+
37
+ def cop_config_dip_whitelist
38
+ cop_config["DipWhitelist"] || []
39
+ end
40
+
41
+ def score_threshold
42
+ cop_config["MinScore"]&.to_f || 70.0
43
+ end
44
+
45
+ def find_class_node_for(result)
46
+ find_node_at_line(processed_source.ast, result.class_info&.line_start)
47
+ end
48
+
49
+ def find_node_at_line(ast, target_line)
50
+ return nil unless ast && target_line
51
+
52
+ if %i[class module].include?(ast.type) && ast.loc.keyword.line == target_line
53
+ return ast
54
+ end
55
+
56
+ return nil unless ast.respond_to?(:children)
57
+
58
+ ast.children.each do |child|
59
+ next unless child.is_a?(::RuboCop::AST::Node)
60
+
61
+ found = find_node_at_line(child, target_line)
62
+ return found if found
63
+ end
64
+
65
+ nil
66
+ end
67
+
68
+ def same_node?(target, current)
69
+ target.loc.keyword.line == current.loc.keyword.line
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module SolidScore
6
+ # Checks that each class/module meets a minimum ISP (Interface Segregation Principle) score.
7
+ #
8
+ # @example MinScore: 70 (default)
9
+ # SolidScore/InterfaceSegregation:
10
+ # Enabled: true
11
+ # MinScore: 70
12
+ class InterfaceSegregation < PrincipleBase
13
+ MSG = "ISP score %.1f is below minimum %g"
14
+
15
+ private
16
+
17
+ def principle_key = :isp
18
+ def principle_name = "ISP"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module SolidScore
6
+ # Checks that each class/module meets a minimum LSP (Liskov Substitution Principle) score.
7
+ #
8
+ # @example MinScore: 60 (default)
9
+ # SolidScore/LiskovSubstitution:
10
+ # Enabled: true
11
+ # MinScore: 60
12
+ class LiskovSubstitution < PrincipleBase
13
+ MSG = "LSP score %.1f is below minimum %g"
14
+
15
+ private
16
+
17
+ def principle_key = :lsp
18
+ def principle_name = "LSP"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module SolidScore
6
+ # Checks that each class/module meets a minimum OCP (Open/Closed Principle) score.
7
+ #
8
+ # @example MinScore: 50 (default)
9
+ # SolidScore/OpenClosed:
10
+ # Enabled: true
11
+ # MinScore: 50
12
+ class OpenClosed < PrincipleBase
13
+ MSG = "OCP score %.1f is below minimum %g"
14
+
15
+ private
16
+
17
+ def principle_key = :ocp
18
+ def principle_name = "OCP"
19
+ end
20
+ end
21
+ end
22
+ end