rubycritic 0.0.5 → 1.4.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/.rubocop.yml +593 -0
- data/.travis.yml +11 -0
- data/CHANGELOG.md +45 -0
- data/CONTRIBUTING.md +67 -15
- data/README.md +105 -14
- data/Rakefile +9 -6
- data/bin/rubycritic +3 -1
- data/lib/rubycritic/analysers/attributes.rb +21 -0
- data/lib/rubycritic/analysers/churn.rb +21 -0
- data/lib/rubycritic/analysers/complexity.rb +22 -0
- data/lib/rubycritic/analysers/helpers/ast_node.rb +69 -0
- data/lib/rubycritic/analysers/{config.reek → helpers/config.reek} +8 -0
- data/lib/rubycritic/analysers/helpers/flay.rb +13 -0
- data/lib/rubycritic/analysers/helpers/flog.rb +17 -0
- data/lib/rubycritic/analysers/helpers/methods_counter.rb +25 -0
- data/lib/rubycritic/analysers/helpers/modules_locator.rb +43 -0
- data/lib/rubycritic/analysers/helpers/parser.rb +12 -0
- data/lib/rubycritic/analysers/helpers/reek.rb +17 -0
- data/lib/rubycritic/analysers/smells/flay.rb +68 -0
- data/lib/rubycritic/analysers/smells/flog.rb +62 -0
- data/lib/rubycritic/analysers/smells/reek.rb +44 -0
- data/lib/rubycritic/analysers_runner.rb +21 -10
- data/lib/rubycritic/cli/application.rb +24 -0
- data/lib/rubycritic/cli/options.rb +79 -0
- data/lib/rubycritic/commands/ci.rb +26 -0
- data/lib/rubycritic/commands/default.rb +28 -0
- data/lib/rubycritic/commands/help.rb +13 -0
- data/lib/rubycritic/commands/version.rb +11 -0
- data/lib/rubycritic/configuration.rb +33 -0
- data/lib/rubycritic/core/analysed_module.rb +66 -0
- data/lib/rubycritic/{location.rb → core/location.rb} +17 -2
- data/lib/rubycritic/core/rating.rb +30 -0
- data/lib/rubycritic/{smell.rb → core/smell.rb} +22 -13
- data/lib/rubycritic/generators/html/assets/javascripts/application.js +104 -0
- data/lib/rubycritic/generators/html/assets/javascripts/highcharts.src-4.0.1.js +17672 -0
- data/lib/rubycritic/generators/html/assets/javascripts/jquery.floatThead-v1.2.7.js +754 -0
- data/lib/rubycritic/generators/html/assets/javascripts/jquery.scrollTo-1.4.11.js +186 -0
- data/lib/rubycritic/generators/html/assets/javascripts/jquery.tablesorter.js +2089 -0
- data/lib/rubycritic/generators/html/assets/javascripts/jquery.timeago-v1.4.1.js +214 -0
- data/lib/rubycritic/generators/html/assets/stylesheets/application.css +303 -0
- data/lib/rubycritic/{report_generators → generators/html}/assets/stylesheets/prettify.custom_theme.css +1 -4
- data/lib/rubycritic/generators/html/base.rb +52 -0
- data/lib/rubycritic/generators/html/code_file.rb +40 -0
- data/lib/rubycritic/generators/html/code_index.rb +26 -0
- data/lib/rubycritic/generators/html/line.rb +37 -0
- data/lib/rubycritic/generators/html/overview.rb +27 -0
- data/lib/rubycritic/generators/html/smells_index.rb +38 -0
- data/lib/rubycritic/generators/html/templates/code_file.html.erb +38 -0
- data/lib/rubycritic/generators/html/templates/code_index.html.erb +30 -0
- data/lib/rubycritic/generators/html/templates/layouts/application.html.erb +34 -0
- data/lib/rubycritic/generators/html/templates/overview.html.erb +5 -0
- data/lib/rubycritic/generators/html/templates/smells_index.html.erb +26 -0
- data/lib/rubycritic/{report_generators → generators/html}/templates/smelly_line.html.erb +1 -1
- data/lib/rubycritic/generators/html/turbulence.rb +17 -0
- data/lib/rubycritic/generators/html/view_helpers.rb +43 -0
- data/lib/rubycritic/generators/html_report.rb +66 -0
- data/lib/rubycritic/generators/json/simple.rb +30 -0
- data/lib/rubycritic/generators/json_report.rb +23 -0
- data/lib/rubycritic/reporter.rb +20 -0
- data/lib/rubycritic/revision_comparator.rb +27 -29
- data/lib/rubycritic/serializer.rb +32 -0
- data/lib/rubycritic/smells_status_setter.rb +7 -16
- data/lib/rubycritic/source_control_systems/base.rb +37 -0
- data/lib/rubycritic/source_control_systems/double.rb +18 -0
- data/lib/rubycritic/source_control_systems/git.rb +41 -37
- data/lib/rubycritic/source_control_systems/mercurial.rb +29 -0
- data/lib/rubycritic/source_locator.rb +25 -13
- data/lib/rubycritic/version.rb +1 -1
- data/lib/rubycritic.rb +17 -22
- data/rubycritic.gemspec +10 -7
- data/test/analysers_test_helper.rb +3 -0
- data/test/lib/rubycritic/analysers/churn_test.rb +33 -0
- data/test/lib/rubycritic/analysers/complexity_test.rb +16 -0
- data/test/lib/rubycritic/analysers/helpers/methods_counter_test.rb +29 -0
- data/test/lib/rubycritic/analysers/helpers/modules_locator_test.rb +53 -0
- data/test/lib/rubycritic/analysers/smells/flay_test.rb +39 -0
- data/test/lib/rubycritic/analysers/smells/flog_test.rb +26 -0
- data/test/lib/rubycritic/analysers/smells/reek_test.rb +33 -0
- data/test/lib/rubycritic/configuration_test.rb +29 -0
- data/test/lib/rubycritic/core/analysed_module_test.rb +88 -0
- data/test/lib/rubycritic/{location_test.rb → core/location_test.rb} +8 -4
- data/test/lib/rubycritic/core/smell_test.rb +72 -0
- data/test/lib/rubycritic/{smells_array_test.rb → core/smells_array_test.rb} +1 -1
- data/test/lib/rubycritic/report_generators/turbulence_test.rb +17 -0
- data/test/lib/rubycritic/report_generators/view_helpers_test.rb +83 -0
- data/test/lib/rubycritic/smells_status_setter_test.rb +5 -5
- data/test/lib/rubycritic/source_control_systems/base_test.rb +29 -0
- data/test/lib/rubycritic/source_control_systems/double_test.rb +11 -0
- data/test/lib/rubycritic/source_control_systems/git_test.rb +13 -0
- data/test/lib/rubycritic/source_control_systems/interfaces/basic.rb +7 -0
- data/test/lib/rubycritic/source_control_systems/interfaces/time_travel.rb +7 -0
- data/test/lib/rubycritic/source_control_systems/mercurial_test.rb +11 -0
- data/test/lib/rubycritic/source_locator_test.rb +42 -18
- data/test/lib/rubycritic/version_test.rb +1 -0
- data/test/samples/empty.rb +0 -0
- data/test/samples/flay/smelly.rb +8 -0
- data/test/samples/flay/smelly2.rb +8 -0
- data/test/samples/flog/complex.rb +11 -0
- data/test/samples/flog/smelly.rb +7 -2
- data/test/samples/location/file0_symlink.rb +0 -0
- data/test/samples/methods_count.rb +7 -0
- data/test/samples/module_names.rb +18 -0
- data/test/samples/reek/not_smelly.rb +31 -3
- data/test/samples/unparsable.rb +1 -0
- data/test/test_helper.rb +39 -0
- metadata +178 -53
- data/SPEC.md +0 -58
- data/lib/rubycritic/analysers/flog.rb +0 -20
- data/lib/rubycritic/analysers/reek.rb +0 -15
- data/lib/rubycritic/cli.rb +0 -25
- data/lib/rubycritic/report_generators/assets/javascripts/application.js +0 -25
- data/lib/rubycritic/report_generators/assets/stylesheets/application.css +0 -26
- data/lib/rubycritic/report_generators/base_generator.rb +0 -42
- data/lib/rubycritic/report_generators/file_generator.rb +0 -42
- data/lib/rubycritic/report_generators/index_generator.rb +0 -28
- data/lib/rubycritic/report_generators/line_generator.rb +0 -27
- data/lib/rubycritic/report_generators/reporter.rb +0 -45
- data/lib/rubycritic/report_generators/templates/file.html.erb +0 -3
- data/lib/rubycritic/report_generators/templates/index.html.erb +0 -14
- data/lib/rubycritic/report_generators/templates/layouts/application.html.erb +0 -19
- data/lib/rubycritic/report_generators/view_helpers.rb +0 -26
- data/lib/rubycritic/smell_adapters/flog.rb +0 -41
- data/lib/rubycritic/smell_adapters/reek.rb +0 -35
- data/lib/rubycritic/smells_aggregator.rb +0 -29
- data/lib/rubycritic/smelly_pathnames_serializer.rb +0 -34
- data/lib/rubycritic/source_control_systems/source_control_system.rb +0 -42
- data/test/lib/rubycritic/metric_adapters/flog_adapter_test.rb +0 -25
- data/test/lib/rubycritic/metric_adapters/reek_adapter_test.rb +0 -34
- data/test/lib/rubycritic/smell_test.rb +0 -71
- data/test/lib/rubycritic/smells_aggregator_test.rb +0 -47
- data/test/lib/rubycritic/source_control_systems/source_control_system_test.rb +0 -26
- /data/lib/rubycritic/{report_generators → generators/html}/assets/javascripts/jquery-2.1.0.js +0 -0
- /data/lib/rubycritic/{report_generators/assets/javascripts/prettify.js → generators/html/assets/javascripts/prettify-4-Mar-2013.js} +0 -0
- /data/lib/rubycritic/{report_generators → generators/html}/templates/line.html.erb +0 -0
data/CONTRIBUTING.md
CHANGED
|
@@ -1,19 +1,71 @@
|
|
|
1
1
|
Contributing
|
|
2
2
|
============
|
|
3
3
|
|
|
4
|
+
RubyCritic is open source and contributions from the community are encouraged! No contribution is too small. Please consider:
|
|
5
|
+
|
|
6
|
+
* [Writing some Code](#writing-some-code)
|
|
7
|
+
* [Improving the Documentation](#improving-the-documentation)
|
|
8
|
+
* [Reporting a Bug](#reporting-a-bug)
|
|
9
|
+
|
|
10
|
+
Writing some Code
|
|
11
|
+
-----------------
|
|
12
|
+
|
|
13
|
+
If you want to squash a bug or add a new feature, please:
|
|
14
|
+
|
|
4
15
|
1. Fork the project.
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
5.
|
|
13
|
-
|
|
14
|
-
6.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
[
|
|
19
|
-
|
|
16
|
+
|
|
17
|
+
2. Create a feature branch (`git checkout -b my-new-feature`).
|
|
18
|
+
|
|
19
|
+
3. Make your changes. Include tests for your changes, otherwise I may accidentally break them in the future.
|
|
20
|
+
|
|
21
|
+
4. Run the tests with the `rake` command. Make sure that they are still passing.
|
|
22
|
+
|
|
23
|
+
5. Stage partial-file changesets (`git -p`).
|
|
24
|
+
|
|
25
|
+
6. Commit your changes (`git commit`).
|
|
26
|
+
Make exactly as many commits as you need.
|
|
27
|
+
Each commit should do one thing and one thing only. For example, all whitespace fixes should be relegated to a single commit.
|
|
28
|
+
|
|
29
|
+
7. Write [descriptive commit messages].
|
|
30
|
+
|
|
31
|
+
8. Push the branch to GitHub (`git push origin my-new-feature`).
|
|
32
|
+
|
|
33
|
+
9. [Create a Pull Request] and send it to be merged with the master branch.
|
|
34
|
+
|
|
35
|
+
10. After your code is reviewed, [hide the sausage making]. Squash, split and reorder commits if necessary (`git rebase -i`).
|
|
36
|
+
For a more in-depth look at interactive rebasing, be sure to check [how to rewrite history].
|
|
37
|
+
|
|
38
|
+
Improving the Documentation
|
|
39
|
+
---------------------------
|
|
40
|
+
|
|
41
|
+
You are welcome to clarify how something works or simply fix a typo. Please include `[ci skip]` on a new line in each of your commit messages. This will signal [Travis] that running the test suite is not necessary for these changes.
|
|
42
|
+
|
|
43
|
+
Reporting a Bug
|
|
44
|
+
---------------
|
|
45
|
+
|
|
46
|
+
If you are experiencing unexpected behavior and, after having read the documentation, you are convinced this behavior is a bug, please:
|
|
47
|
+
|
|
48
|
+
1. Search the [issues tracker] to see if it was already reported / fixed.
|
|
49
|
+
|
|
50
|
+
2. [Create a new issue].
|
|
51
|
+
|
|
52
|
+
3. Include the Ruby and RubyCritic versions in your report. Here's a little table to help you out:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
| | Version |
|
|
56
|
+
|------------|---------|
|
|
57
|
+
| Ruby | 2.1.2 |
|
|
58
|
+
| RubyCritic | 1.0.0 |
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The more information you provide, the easier it will be to track down the issue and fix it.
|
|
62
|
+
If you have never written a bug report before, or if you want to brush up on your bug reporting skills, read Simon Tatham's essay [How to Report Bugs Effectively].
|
|
63
|
+
|
|
64
|
+
[descriptive commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
|
|
65
|
+
[Create a pull request]: https://help.github.com/articles/creating-a-pull-request
|
|
66
|
+
[hide the sausage making]: http://sethrobertson.github.io/GitBestPractices/#sausage
|
|
67
|
+
[how to rewrite history]: http://git-scm.com/book/en/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages
|
|
68
|
+
[Travis]: https://travis-ci.org
|
|
69
|
+
[issues tracker]: https://github.com/whitesmith/rubycritic/issues
|
|
70
|
+
[Create a new issue]: https://github.com/whitesmith/rubycritic/issues/new
|
|
71
|
+
[How to Report Bugs Effectively]: http://www.chiark.greenend.org.uk/~sgtatham/bugs.html
|
data/README.md
CHANGED
|
@@ -1,33 +1,73 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
RubyCritic
|
|
2
|
+
==========
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
[](http://badge.fury.io/rb/rubycritic)
|
|
5
|
+
[](https://travis-ci.org/whitesmith/rubycritic)
|
|
6
|
+
[](https://codeclimate.com/github/whitesmith/rubycritic)
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
<img src="http://i.imgur.com/66HACCD.png" alt="RubyCritic Icon" align="right" />
|
|
9
|
+
RubyCritic is a gem that wraps around static analysis gems such as [Reek][1], [Flay][2] and [Flog][3] to provide a quality report of your Ruby code.
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
This gem provides features such as:
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
gem "rubycritic"
|
|
13
|
-
```
|
|
13
|
+
1. An overview of your project:
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
2. An index of the project files with their respective number of smells:
|
|
18
|
+
|
|
19
|
+

|
|
20
|
+
|
|
21
|
+
3. An index of the smells detected:
|
|
22
|
+
|
|
23
|
+

|
|
24
|
+
|
|
25
|
+
4. Finally, when analysing code like the following:
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
class Dirty
|
|
29
|
+
def awful(x, y)
|
|
30
|
+
if y
|
|
31
|
+
@screen = widgets.map {|w| w.each {|key| key += 3}}
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
It basically turns something like this:
|
|
38
|
+
|
|
39
|
+

|
|
40
|
+
|
|
41
|
+
Into something like this:
|
|
42
|
+
|
|
43
|
+

|
|
44
|
+
|
|
45
|
+
Getting Started
|
|
46
|
+
---------------
|
|
47
|
+
|
|
48
|
+
RubyCritic can be installed with the following command:
|
|
16
49
|
|
|
17
50
|
```bash
|
|
18
|
-
$
|
|
51
|
+
$ gem install rubycritic
|
|
19
52
|
```
|
|
20
53
|
|
|
21
|
-
|
|
54
|
+
If you'd rather install RubyCritic using Bundler, add this line to your
|
|
55
|
+
application's Gemfile:
|
|
56
|
+
|
|
57
|
+
```ruby
|
|
58
|
+
gem "rubycritic", :require => false
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
And then execute:
|
|
22
62
|
|
|
23
63
|
```bash
|
|
24
|
-
$
|
|
64
|
+
$ bundle
|
|
25
65
|
```
|
|
26
66
|
|
|
27
67
|
Usage
|
|
28
68
|
-----
|
|
29
69
|
|
|
30
|
-
Running `rubycritic` with no arguments will
|
|
70
|
+
Running `rubycritic` with no arguments will analyse all the Ruby files in the
|
|
31
71
|
current directory:
|
|
32
72
|
|
|
33
73
|
```bash
|
|
@@ -39,3 +79,54 @@ Alternatively you can pass `rubycritic` a list of files and directories to check
|
|
|
39
79
|
```bash
|
|
40
80
|
$ rubycritic app lib/foo.rb
|
|
41
81
|
```
|
|
82
|
+
|
|
83
|
+
For a full list of the command-line options run:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
$ rubycritic --help
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
| Command flag | Description |
|
|
90
|
+
|--------------------------|-------------------------------------------------------|
|
|
91
|
+
| `-v/--version` | Displays the current version and exits |
|
|
92
|
+
| `-p/--path` | Sets the output directory (tmp/rubycritic by default) |
|
|
93
|
+
| `-m/--mode-ci` | Uses CI mode (faster, but only analyses last commit) |
|
|
94
|
+
| `--deduplicate-symlinks` | De-duplicate symlinks based on their final target |
|
|
95
|
+
| `--suppress-ratings` | Suppress letter ratings |
|
|
96
|
+
|
|
97
|
+
Alternative Usage Methods
|
|
98
|
+
-------------------------
|
|
99
|
+
|
|
100
|
+
If you're fond of Guard you might like [guard-rubycritic][4]. It automatically analyses your Ruby files as they are modified.
|
|
101
|
+
|
|
102
|
+
For continuous integration, you can give [Jenkins CI][5] a spin. With it, you can [easily build your own (poor-man's) Code Climate][6]!
|
|
103
|
+
|
|
104
|
+
Improving RubyCritic
|
|
105
|
+
--------------------
|
|
106
|
+
|
|
107
|
+
RubyCritic doesn't have to remain a second choice to other code quality analysis services. Together, we can improve it and continue to build on the great code metric tools that are available in the Ruby ecosystem.
|
|
108
|
+
|
|
109
|
+
Arguably, the [better_errors gem][7] only got popular after receiving a [(pretty awesome) Pull Request][8] that changed its page design.
|
|
110
|
+
|
|
111
|
+
Similarly, Pull Requests that improve the look and feel of the gem, that tweak the calculation of ratings or that fix existing issues will be most welcome. This is my first gem, so just commenting on an issue and giving some insight into how something should work will be appreciated. No contribution is too small.
|
|
112
|
+
|
|
113
|
+
See RubyCritic's [contributing guidelines](CONTRIBUTING.md) about how to proceed.
|
|
114
|
+
|
|
115
|
+
Credits
|
|
116
|
+
-------
|
|
117
|
+
|
|
118
|
+

|
|
119
|
+
|
|
120
|
+
RubyCritic is maintained and funded by [Whitesmith][9]. Tweet your questions or suggestions to [@glitchdout][10] or [@Whitesmithco][11].
|
|
121
|
+
|
|
122
|
+
[1]: https://github.com/troessner/reek
|
|
123
|
+
[2]: https://github.com/seattlerb/flay
|
|
124
|
+
[3]: https://github.com/seattlerb/flog
|
|
125
|
+
[4]: https://github.com/whitesmith/guard-rubycritic
|
|
126
|
+
[5]: http://jenkins-ci.org/
|
|
127
|
+
[6]: https://github.com/whitesmith/rubycritic/wiki/Building-your-own-Code-Climate
|
|
128
|
+
[7]: https://github.com/charliesome/better_errors
|
|
129
|
+
[8]: https://github.com/charliesome/better_errors/pull/22
|
|
130
|
+
[9]: http://www.whitesmith.co/
|
|
131
|
+
[10]: https://twitter.com/glitchdout
|
|
132
|
+
[11]: https://twitter.com/Whitesmithco
|
data/Rakefile
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
require "bundler/gem_tasks"
|
|
2
2
|
require "rake/testtask"
|
|
3
|
+
require "rubocop/rake_task"
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
t.libs.push "test"
|
|
9
|
-
t.pattern = "test/**/*_test.rb"
|
|
5
|
+
Rake::TestTask.new do |task|
|
|
6
|
+
task.libs.push "lib"
|
|
7
|
+
task.libs.push "test"
|
|
8
|
+
task.pattern = "test/**/*_test.rb"
|
|
10
9
|
end
|
|
10
|
+
|
|
11
|
+
RuboCop::RakeTask.new
|
|
12
|
+
|
|
13
|
+
task :default => [:test, :rubocop]
|
data/bin/rubycritic
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require "rubycritic/analysers/helpers/methods_counter"
|
|
2
|
+
require "rubycritic/analysers/helpers/modules_locator"
|
|
3
|
+
|
|
4
|
+
module Rubycritic
|
|
5
|
+
module Analyser
|
|
6
|
+
|
|
7
|
+
class Attributes
|
|
8
|
+
def initialize(analysed_modules)
|
|
9
|
+
@analysed_modules = analysed_modules
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def run
|
|
13
|
+
@analysed_modules.each do |analysed_module|
|
|
14
|
+
analysed_module.methods_count = MethodsCounter.new(analysed_module).count
|
|
15
|
+
analysed_module.name = ModulesLocator.new(analysed_module).first_name
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Rubycritic
|
|
2
|
+
module Analyser
|
|
3
|
+
|
|
4
|
+
class Churn
|
|
5
|
+
attr_writer :source_control_system
|
|
6
|
+
|
|
7
|
+
def initialize(analysed_modules)
|
|
8
|
+
@analysed_modules = analysed_modules
|
|
9
|
+
@source_control_system = Config.source_control_system
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def run
|
|
13
|
+
@analysed_modules.each do |analysed_module|
|
|
14
|
+
analysed_module.churn = @source_control_system.revisions_count(analysed_module.path)
|
|
15
|
+
analysed_module.committed_at = @source_control_system.date_of_last_commit(analysed_module.path)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require "rubycritic/analysers/helpers/flog"
|
|
2
|
+
|
|
3
|
+
module Rubycritic
|
|
4
|
+
module Analyser
|
|
5
|
+
|
|
6
|
+
class Complexity
|
|
7
|
+
def initialize(analysed_modules)
|
|
8
|
+
@flog = Flog.new
|
|
9
|
+
@analysed_modules = analysed_modules
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def run
|
|
13
|
+
@analysed_modules.each do |analysed_module|
|
|
14
|
+
@flog.reset
|
|
15
|
+
@flog.flog(analysed_module.path)
|
|
16
|
+
analysed_module.complexity = @flog.total_score.round
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
module Parser
|
|
2
|
+
module AST
|
|
3
|
+
|
|
4
|
+
class Node
|
|
5
|
+
MODULE_TYPES = [:module, :class]
|
|
6
|
+
|
|
7
|
+
def count_nodes_of_type(*types)
|
|
8
|
+
count = 0
|
|
9
|
+
recursive_children do |child|
|
|
10
|
+
count += 1 if types.include?(child.type)
|
|
11
|
+
end
|
|
12
|
+
count
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def recursive_children
|
|
16
|
+
children.each do |child|
|
|
17
|
+
next unless child.is_a?(Parser::AST::Node)
|
|
18
|
+
yield child
|
|
19
|
+
child.recursive_children { |grand_child| yield grand_child }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def get_module_names
|
|
24
|
+
children_modules = children
|
|
25
|
+
.select { |child| child.is_a?(Parser::AST::Node) }
|
|
26
|
+
.flat_map(&:get_module_names)
|
|
27
|
+
|
|
28
|
+
if MODULE_TYPES.include?(type)
|
|
29
|
+
if children_modules.empty?
|
|
30
|
+
[module_name]
|
|
31
|
+
else
|
|
32
|
+
children_modules.map do |children_module|
|
|
33
|
+
"#{module_name}::#{children_module}"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
else
|
|
37
|
+
children_modules
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def module_name
|
|
44
|
+
name_segments = []
|
|
45
|
+
current_node = children[0]
|
|
46
|
+
while current_node
|
|
47
|
+
name_segments.unshift(current_node.children[1])
|
|
48
|
+
current_node = current_node.children[0]
|
|
49
|
+
end
|
|
50
|
+
name_segments.join("::")
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
module Rubycritic
|
|
57
|
+
module AST
|
|
58
|
+
class EmptyNode
|
|
59
|
+
def count_nodes_of_type(*)
|
|
60
|
+
0
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def get_module_names
|
|
64
|
+
[]
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
Attribute:
|
|
3
3
|
enabled: false
|
|
4
|
+
DuplicateMethodCall:
|
|
5
|
+
max_calls: 2
|
|
4
6
|
IrresponsibleModule:
|
|
5
7
|
enabled: false
|
|
8
|
+
NestedIterators:
|
|
9
|
+
max_allowed_nesting: 2
|
|
10
|
+
TooManyStatements:
|
|
11
|
+
enabled: false
|
|
6
12
|
UncommunicativeMethodName:
|
|
7
13
|
reject:
|
|
8
14
|
- !ruby/regexp /^[a-z]$/
|
|
@@ -16,3 +22,5 @@ UncommunicativeVariableName:
|
|
|
16
22
|
reject:
|
|
17
23
|
- !ruby/regexp /^.$/
|
|
18
24
|
- !ruby/regexp /[0-9]$/
|
|
25
|
+
UtilityFunction:
|
|
26
|
+
enabled: false
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require "rubycritic/analysers/helpers/parser"
|
|
2
|
+
|
|
3
|
+
module Rubycritic
|
|
4
|
+
|
|
5
|
+
class MethodsCounter
|
|
6
|
+
def initialize(analysed_module)
|
|
7
|
+
@analysed_module = analysed_module
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def count
|
|
11
|
+
node.count_nodes_of_type(:def, :defs)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def node
|
|
17
|
+
Parser.parse(content)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def content
|
|
21
|
+
File.read(@analysed_module.path)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
require "rubycritic/analysers/helpers/parser"
|
|
2
|
+
|
|
3
|
+
module Rubycritic
|
|
4
|
+
|
|
5
|
+
class ModulesLocator
|
|
6
|
+
def initialize(analysed_module)
|
|
7
|
+
@analysed_module = analysed_module
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def first_name
|
|
11
|
+
names.first
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def names
|
|
15
|
+
return name_from_path if @analysed_module.methods_count == 0
|
|
16
|
+
names = node.get_module_names
|
|
17
|
+
if names.empty?
|
|
18
|
+
name_from_path
|
|
19
|
+
else
|
|
20
|
+
names
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def node
|
|
27
|
+
Parser.parse(content)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def content
|
|
31
|
+
File.read(@analysed_module.path)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def name_from_path
|
|
35
|
+
[file_name.split("_").map(&:capitalize).join]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def file_name
|
|
39
|
+
@analysed_module.pathname.basename.sub_ext("").to_s
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
require "parser/current"
|
|
2
|
+
require "rubycritic/analysers/helpers/ast_node"
|
|
3
|
+
|
|
4
|
+
module Rubycritic
|
|
5
|
+
module Parser
|
|
6
|
+
def self.parse(content)
|
|
7
|
+
::Parser::CurrentRuby.parse(content) || AST::EmptyNode.new
|
|
8
|
+
rescue ::Parser::SyntaxError
|
|
9
|
+
AST::EmptyNode.new
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require "reek"
|
|
2
|
+
require "reek/configuration/app_configuration"
|
|
3
|
+
require "ostruct"
|
|
4
|
+
|
|
5
|
+
module Rubycritic
|
|
6
|
+
|
|
7
|
+
class Reek < ::Reek::Examiner
|
|
8
|
+
DEFAULT_CONFIG_FILE = File.expand_path("../config.reek", __FILE__)
|
|
9
|
+
|
|
10
|
+
def initialize(paths)
|
|
11
|
+
config = OpenStruct.new(:options => OpenStruct.new(:config_file => DEFAULT_CONFIG_FILE))
|
|
12
|
+
::Reek::Configuration::AppConfiguration.initialize_with(config)
|
|
13
|
+
super(Array(paths))
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
require "rubycritic/analysers/helpers/flay"
|
|
2
|
+
require "rubycritic/core/smell"
|
|
3
|
+
|
|
4
|
+
module Rubycritic
|
|
5
|
+
module Analyser
|
|
6
|
+
|
|
7
|
+
class FlaySmells
|
|
8
|
+
def initialize(analysed_modules)
|
|
9
|
+
@analysed_modules = paths_to_analysed_modules(analysed_modules)
|
|
10
|
+
@flay = Flay.new(@analysed_modules.keys)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def run
|
|
14
|
+
@flay.hashes.each do |structural_hash, nodes|
|
|
15
|
+
smell = create_smell(structural_hash, nodes)
|
|
16
|
+
nodes.map(&:file).uniq.each do |file|
|
|
17
|
+
@analysed_modules[file].smells << smell
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
nodes.each do |node|
|
|
21
|
+
@analysed_modules[node.file].duplication += node.mass
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def paths_to_analysed_modules(analysed_modules)
|
|
29
|
+
paths = {}
|
|
30
|
+
analysed_modules.each do |analysed_module|
|
|
31
|
+
paths[analysed_module.path] = analysed_module
|
|
32
|
+
end
|
|
33
|
+
paths
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def create_smell(structural_hash, nodes)
|
|
37
|
+
mass = @flay.masses[structural_hash]
|
|
38
|
+
Smell.new(
|
|
39
|
+
:locations => smell_locations(nodes),
|
|
40
|
+
:context => similarity(structural_hash),
|
|
41
|
+
:message => "found in #{nodes.size} nodes",
|
|
42
|
+
:score => mass,
|
|
43
|
+
:type => "DuplicateCode",
|
|
44
|
+
:cost => cost(mass)
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def smell_locations(nodes)
|
|
49
|
+
nodes.map do |node|
|
|
50
|
+
Location.new(node.file, node.line)
|
|
51
|
+
end.sort
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def similarity(structural_hash)
|
|
55
|
+
if @flay.identical[structural_hash]
|
|
56
|
+
"Identical code"
|
|
57
|
+
else
|
|
58
|
+
"Similar code"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def cost(mass)
|
|
63
|
+
mass / 25
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
require "rubycritic/analysers/helpers/flog"
|
|
2
|
+
require "rubycritic/core/smell"
|
|
3
|
+
|
|
4
|
+
module Rubycritic
|
|
5
|
+
module Analyser
|
|
6
|
+
|
|
7
|
+
class FlogSmells
|
|
8
|
+
HIGH_COMPLEXITY_SCORE_THRESHOLD = 25
|
|
9
|
+
VERY_HIGH_COMPLEXITY_SCORE_THRESHOLD = 60
|
|
10
|
+
|
|
11
|
+
def initialize(analysed_modules)
|
|
12
|
+
@flog = Flog.new
|
|
13
|
+
@analysed_modules = analysed_modules
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def run
|
|
17
|
+
@analysed_modules.each do |analysed_module|
|
|
18
|
+
add_smells_to(analysed_module)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def add_smells_to(analysed_module)
|
|
25
|
+
@flog.reset
|
|
26
|
+
@flog.flog(analysed_module.path)
|
|
27
|
+
@flog.each_by_score do |class_method, original_score|
|
|
28
|
+
score = original_score.round
|
|
29
|
+
if score >= HIGH_COMPLEXITY_SCORE_THRESHOLD
|
|
30
|
+
analysed_module.smells << create_smell(class_method, score)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def create_smell(context, score)
|
|
36
|
+
Smell.new(
|
|
37
|
+
:locations => smell_locations(context),
|
|
38
|
+
:context => context,
|
|
39
|
+
:message => "has a flog score of #{score}",
|
|
40
|
+
:score => score,
|
|
41
|
+
:type => type(score),
|
|
42
|
+
:cost => 0
|
|
43
|
+
)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def smell_locations(context)
|
|
47
|
+
line = @flog.method_locations[context]
|
|
48
|
+
file_path, file_line = line.split(":")
|
|
49
|
+
[Location.new(file_path, file_line)]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def type(score)
|
|
53
|
+
if score >= VERY_HIGH_COMPLEXITY_SCORE_THRESHOLD
|
|
54
|
+
"VeryHighComplexity"
|
|
55
|
+
else
|
|
56
|
+
"HighComplexity"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
62
|
+
end
|