ducalis 0.5.14 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +8 -10
- data/README.md +2 -4
- data/Rakefile +0 -5
- data/bin/ducalis +8 -3
- data/config/.ducalis.yml +20 -1
- data/ducalis.gemspec +0 -1
- data/lib/ducalis.rb +7 -0
- data/lib/ducalis/cli.rb +80 -19
- data/lib/ducalis/commentators/console.rb +1 -1
- data/lib/ducalis/cops/black_list_suffix.rb +3 -0
- data/lib/ducalis/cops/callbacks_activerecord.rb +7 -16
- data/lib/ducalis/cops/case_mapping.rb +8 -3
- data/lib/ducalis/cops/controllers_except.rb +0 -8
- data/lib/ducalis/cops/data_access_objects.rb +28 -0
- data/lib/ducalis/cops/enforce_namespace.rb +28 -0
- data/lib/ducalis/cops/evlis_overusing.rb +30 -0
- data/lib/ducalis/cops/extensions/type_resolving.rb +52 -0
- data/lib/ducalis/cops/fetch_expression.rb +80 -0
- data/lib/ducalis/cops/module_like_class.rb +1 -0
- data/lib/ducalis/cops/multiple_times.rb +50 -0
- data/lib/ducalis/cops/options_argument.rb +5 -22
- data/lib/ducalis/cops/possible_tap.rb +4 -0
- data/lib/ducalis/cops/preferable_methods.rb +3 -1
- data/lib/ducalis/cops/private_instance_assign.rb +4 -9
- data/lib/ducalis/cops/protected_scope_cop.rb +4 -0
- data/lib/ducalis/cops/public_send.rb +18 -0
- data/lib/ducalis/cops/regex_cop.rb +36 -6
- data/lib/ducalis/cops/rest_only_cop.rb +4 -11
- data/lib/ducalis/cops/too_long_workers.rb +3 -8
- data/lib/ducalis/cops/uncommented_gem.rb +13 -1
- data/lib/ducalis/cops/useless_only.rb +6 -8
- data/lib/ducalis/documentation.rb +28 -18
- data/lib/ducalis/passed_args.rb +2 -2
- data/lib/ducalis/version.rb +1 -1
- metadata +9 -17
- data/DOCUMENTATION.md +0 -1185
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c318246f914585d93588a49a31dfb31c7598b5f5
|
4
|
+
data.tar.gz: 8a4d1be3c918559feffab7275779250d76c60dfb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 319fb773559268eec362ae2a8f561d6f92a2f77d9d9b44825d4eb0fa70548173af97cdf266346677231ca152da5e9d416478b60a1b322845c1f576e55035b032
|
7
|
+
data.tar.gz: 4c81501488830a22fb562b31c32f4104f0d47d9dda9ab5102c2a0c9b149a328c30ead9a774f1368869af7cc128d8a86d3f2631be9f3783994fc993e0a2e0b732
|
data/Gemfile.lock
CHANGED
@@ -1,19 +1,18 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
ducalis (0.
|
4
|
+
ducalis (0.6.0)
|
5
5
|
git (~> 1.3, >= 1.3.0)
|
6
6
|
policial (= 0.0.4)
|
7
7
|
regexp-examples (~> 1.3, >= 1.3.2)
|
8
8
|
rubocop (~> 0.46.0, >= 0.45.0)
|
9
|
-
thor (~> 0.20.0)
|
10
9
|
|
11
10
|
GEM
|
12
11
|
remote: https://rubygems.org/
|
13
12
|
specs:
|
14
13
|
addressable (2.5.2)
|
15
14
|
public_suffix (>= 2.0.2, < 4.0)
|
16
|
-
ast (2.
|
15
|
+
ast (2.4.0)
|
17
16
|
coderay (1.1.2)
|
18
17
|
coffee-script (2.4.1)
|
19
18
|
coffee-script-source
|
@@ -29,17 +28,17 @@ GEM
|
|
29
28
|
multi_json (>= 1.3)
|
30
29
|
rake
|
31
30
|
execjs (2.7.0)
|
32
|
-
faraday (0.
|
31
|
+
faraday (0.14.0)
|
33
32
|
multipart-post (>= 1.2, < 3)
|
34
33
|
git (1.3.0)
|
35
34
|
json (2.1.0)
|
36
35
|
method_source (0.9.0)
|
37
|
-
multi_json (1.
|
36
|
+
multi_json (1.13.1)
|
38
37
|
multipart-post (2.0.0)
|
39
38
|
octokit (4.8.0)
|
40
39
|
sawyer (~> 0.8.0, >= 0.5.3)
|
41
|
-
parser (2.
|
42
|
-
ast (~> 2.
|
40
|
+
parser (2.5.0.0)
|
41
|
+
ast (~> 2.4.0)
|
43
42
|
policial (0.0.4)
|
44
43
|
coffeelint (~> 1.14)
|
45
44
|
eslintrb (~> 2.0)
|
@@ -49,11 +48,11 @@ GEM
|
|
49
48
|
pry (0.11.2)
|
50
49
|
coderay (~> 1.1.0)
|
51
50
|
method_source (~> 0.9.0)
|
52
|
-
public_suffix (3.0.
|
51
|
+
public_suffix (3.0.2)
|
53
52
|
rainbow (2.2.2)
|
54
53
|
rake
|
55
54
|
rake (12.1.0)
|
56
|
-
regexp-examples (1.4.
|
55
|
+
regexp-examples (1.4.2)
|
57
56
|
rspec (3.7.0)
|
58
57
|
rspec-core (~> 3.7.0)
|
59
58
|
rspec-expectations (~> 3.7.0)
|
@@ -77,7 +76,6 @@ GEM
|
|
77
76
|
sawyer (0.8.1)
|
78
77
|
addressable (>= 2.3.5, < 2.6)
|
79
78
|
faraday (~> 0.8, < 1.0)
|
80
|
-
thor (0.20.0)
|
81
79
|
unicode-display_width (1.3.0)
|
82
80
|
|
83
81
|
PLATFORMS
|
data/README.md
CHANGED
@@ -9,6 +9,8 @@ As __Ducalis__ isn't style checker and could sometimes be false-positive it's no
|
|
9
9
|
necessary to follow all it rules, the main purpose of __Ducalis__ is help to find
|
10
10
|
possible weak code parts.
|
11
11
|
|
12
|
+
[Documentation](<https://ducalis-rb.github.io/>)
|
13
|
+
|
12
14
|
## Installation
|
13
15
|
|
14
16
|
Add this line to your application's Gemfile:
|
@@ -77,7 +79,3 @@ To pass your code through the all checks you simply need to run:
|
|
77
79
|
```
|
78
80
|
bundle exec rake
|
79
81
|
```
|
80
|
-
|
81
|
-
Please, do not edit
|
82
|
-
[DOCUMENTATION.md](<https://github.com/ignat-z/ducalis/blob/master/DOCUMENTATION.md>),
|
83
|
-
this file is generating by `bundle exec rake documentation` command.
|
data/Rakefile
CHANGED
@@ -8,10 +8,5 @@ RuboCop::RakeTask.new do |task|
|
|
8
8
|
task.options = %w(--auto-correct)
|
9
9
|
end
|
10
10
|
|
11
|
-
task :documentation do
|
12
|
-
require './lib/ducalis/documentation'
|
13
|
-
File.write('DOCUMENTATION.md', Documentation.new.call)
|
14
|
-
end
|
15
|
-
|
16
11
|
RSpec::Core::RakeTask.new(:spec)
|
17
12
|
task default: %i(rubocop spec)
|
data/bin/ducalis
CHANGED
@@ -15,13 +15,18 @@ Env `GITHUB_TOKEN` should be available to receive PRs files."
|
|
15
15
|
puts ' --all [default] check all files in RuboCop style.'
|
16
16
|
puts ''
|
17
17
|
|
18
|
-
Ducalis::CLI.
|
19
|
-
|
18
|
+
Ducalis::CLI.new(ARGV).start
|
19
|
+
exit 0
|
20
|
+
end
|
21
|
+
|
22
|
+
if ARGV.any? { |arg| arg == '--docs' }
|
23
|
+
require 'ducalis/documentation'
|
24
|
+
File.write(ARGV[1] || 'DOCUMENTATION.md', Documentation.new.call)
|
20
25
|
exit 0
|
21
26
|
end
|
22
27
|
|
23
28
|
if Ducalis::PassedArgs.ci_mode?
|
24
|
-
Ducalis::CLI.
|
29
|
+
Ducalis::CLI.new(ARGV - %w(--ci)).start
|
25
30
|
else
|
26
31
|
Ducalis::PassedArgs.process_args!
|
27
32
|
|
data/config/.ducalis.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
AllCops:
|
2
2
|
DisabledByDefault: true
|
3
|
-
TargetRubyVersion:
|
3
|
+
TargetRubyVersion: ~
|
4
4
|
Exclude:
|
5
5
|
- 'db/**/*'
|
6
6
|
- 'node_modules/**/*'
|
@@ -20,6 +20,10 @@ Ducalis/BlackListSuffix:
|
|
20
20
|
- Renderer
|
21
21
|
- Loader
|
22
22
|
|
23
|
+
Ducalis/EnforceNamespace:
|
24
|
+
Enabled: true
|
25
|
+
ServicePath: 'app/services'
|
26
|
+
|
23
27
|
Ducalis/PreferableMethods:
|
24
28
|
Enabled: true
|
25
29
|
|
@@ -29,9 +33,18 @@ Ducalis/CaseMapping:
|
|
29
33
|
Ducalis/CallbacksActiverecord:
|
30
34
|
Enabled: true
|
31
35
|
|
36
|
+
Ducalis/DataAccessObjects:
|
37
|
+
Enabled: true
|
38
|
+
|
32
39
|
Ducalis/PossibleTap:
|
33
40
|
Enabled: false
|
34
41
|
|
42
|
+
Ducalis/PublicSend:
|
43
|
+
Enabled: false
|
44
|
+
|
45
|
+
Ducalis/FetchExpression:
|
46
|
+
Enabled: true
|
47
|
+
|
35
48
|
Ducalis/ProtectedScopeCop:
|
36
49
|
Enabled: true
|
37
50
|
Exclude:
|
@@ -63,6 +76,9 @@ Ducalis/RestOnlyCop:
|
|
63
76
|
Ducalis/KeywordDefaults:
|
64
77
|
Enabled: true
|
65
78
|
|
79
|
+
Ducalis/MultipleTimes:
|
80
|
+
Enabled: true
|
81
|
+
|
66
82
|
Ducalis/OptionsArgument:
|
67
83
|
Enabled: true
|
68
84
|
|
@@ -86,6 +102,9 @@ Ducalis/ControllersExcept:
|
|
86
102
|
Ducalis/PrivateInstanceAssign:
|
87
103
|
Enabled: true
|
88
104
|
|
105
|
+
Ducalis/EvlisOverusing:
|
106
|
+
Enabled: true
|
107
|
+
|
89
108
|
Ducalis/StandardMethods:
|
90
109
|
Enabled: true
|
91
110
|
|
data/ducalis.gemspec
CHANGED
data/lib/ducalis.rb
CHANGED
@@ -31,19 +31,26 @@ require 'ducalis/patched_rubocop/git_runner'
|
|
31
31
|
require 'ducalis/patched_rubocop/git_turget_finder'
|
32
32
|
require 'ducalis/patched_rubocop/rubo_cop'
|
33
33
|
|
34
|
+
require 'ducalis/cops/extensions/type_resolving'
|
34
35
|
require 'ducalis/cops/black_list_suffix'
|
35
36
|
require 'ducalis/cops/callbacks_activerecord'
|
36
37
|
require 'ducalis/cops/case_mapping'
|
37
38
|
require 'ducalis/cops/controllers_except'
|
39
|
+
require 'ducalis/cops/data_access_objects'
|
40
|
+
require 'ducalis/cops/fetch_expression'
|
38
41
|
require 'ducalis/cops/only_defs'
|
39
42
|
require 'ducalis/cops/keyword_defaults'
|
40
43
|
require 'ducalis/cops/module_like_class'
|
44
|
+
require 'ducalis/cops/multiple_times'
|
45
|
+
require 'ducalis/cops/evlis_overusing'
|
46
|
+
require 'ducalis/cops/enforce_namespace'
|
41
47
|
require 'ducalis/cops/options_argument'
|
42
48
|
require 'ducalis/cops/params_passing'
|
43
49
|
require 'ducalis/cops/possible_tap'
|
44
50
|
require 'ducalis/cops/preferable_methods'
|
45
51
|
require 'ducalis/cops/private_instance_assign'
|
46
52
|
require 'ducalis/cops/protected_scope_cop'
|
53
|
+
require 'ducalis/cops/public_send'
|
47
54
|
require 'ducalis/cops/raise_without_error_class'
|
48
55
|
require 'ducalis/cops/regex_cop'
|
49
56
|
require 'ducalis/cops/rest_only_cop'
|
data/lib/ducalis/cli.rb
CHANGED
@@ -1,35 +1,96 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'optparse'
|
4
4
|
|
5
5
|
module Ducalis
|
6
|
-
class CLI
|
6
|
+
class CLI
|
7
7
|
ADAPTERS = {
|
8
8
|
circle: Adapters::CircleCi,
|
9
9
|
custom: Adapters::Custom
|
10
10
|
}.freeze
|
11
11
|
DEFAULT_ADAPTER = ADAPTERS.keys.last
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
option :dry, type: :boolean, default: false,
|
21
|
-
desc: 'Allows user run dry mode, default: false'
|
12
|
+
|
13
|
+
def initialize(arguments)
|
14
|
+
@arguments = arguments
|
15
|
+
@options = {}
|
16
|
+
@parser = OptionParser.new
|
17
|
+
configure_parser!
|
18
|
+
end
|
19
|
+
|
22
20
|
def start
|
23
|
-
|
24
|
-
|
21
|
+
@parser.parse(@arguments)
|
22
|
+
Runner.new(adapter.new(@options)).call
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def adapter
|
28
|
+
ADAPTERS.fetch(@options.fetch(:adapter, DEFAULT_ADAPTER)) do
|
29
|
+
raise "Unsupported adapter #{@options[:adapter]}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def configure_parser!
|
34
|
+
@parser.banner = 'Usage: ducalis --ci --adapter=ADAPTER'
|
35
|
+
adapter_option_parsing
|
36
|
+
id_option_parsing
|
37
|
+
repo_option_parsing
|
38
|
+
sha_option_parsing
|
39
|
+
dry_option_parsing
|
40
|
+
help_command
|
41
|
+
end
|
42
|
+
|
43
|
+
def help_command
|
44
|
+
@parser.on_tail('--help', 'Show this message') do
|
45
|
+
puts @parser
|
46
|
+
RuboCop::CLI.new.run(@arguments)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def adapter_option_parsing
|
51
|
+
@parser.on(
|
52
|
+
'--adapter=ADAPTER',
|
53
|
+
'Describes how Ducalis will receive PR information. Default: custom'
|
54
|
+
) do |adapter|
|
55
|
+
@options[:adapter] = adapter.to_sym
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def id_option_parsing
|
60
|
+
@parser.on(
|
61
|
+
'--id=N',
|
62
|
+
'PR id, ex: 2347'
|
63
|
+
) do |id|
|
64
|
+
@options[:id] = id
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def repo_option_parsing
|
69
|
+
@parser.on(
|
70
|
+
'--repo=REPO',
|
71
|
+
'PR repository, ex: author/repo'
|
72
|
+
) do |repo|
|
73
|
+
@options[:repo] = repo
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def sha_option_parsing
|
78
|
+
@parser.on(
|
79
|
+
'--sha=SHA',
|
80
|
+
'Starting commit, can be omitted'
|
81
|
+
) do |sha|
|
82
|
+
@options[:sha] = sha
|
25
83
|
end
|
26
|
-
Runner.new(adapter.new(options)).call
|
27
84
|
end
|
28
85
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
86
|
+
def dry_option_parsing
|
87
|
+
@options[:dry] = false # default
|
88
|
+
@parser.on(
|
89
|
+
'--dry',
|
90
|
+
'Allows user to run dry mode, default: false'
|
91
|
+
) do |_dry|
|
92
|
+
@options[:dry] = true
|
93
|
+
end
|
33
94
|
end
|
34
95
|
end
|
35
96
|
end
|
@@ -5,7 +5,7 @@ require 'logger'
|
|
5
5
|
module Ducalis
|
6
6
|
module Commentators
|
7
7
|
class Console
|
8
|
-
DOCUMENTATION_PATH = 'https://github.
|
8
|
+
DOCUMENTATION_PATH = 'https://ducalis-rb.github.io/'
|
9
9
|
|
10
10
|
def initialize(config)
|
11
11
|
@config = config
|
@@ -8,6 +8,9 @@ module Ducalis
|
|
8
8
|
| Please, avoid using of class suffixes like `Meneger`, `Client` and so on. If it has no parts, change the name of the class to what each object is managing.
|
9
9
|
|
10
10
|
| It's ok to use Manager as subclass of Person, which is there to refine a type of personal that has management behavior to it.
|
11
|
+
MESSAGE
|
12
|
+
|
13
|
+
DETAILS = <<-MESSAGE.gsub(/^ +\|\s/, '').strip
|
11
14
|
| Related [article](<http://www.carlopescio.com/2011/04/your-coding-conventions-are-hurting-you.html>)
|
12
15
|
MESSAGE
|
13
16
|
|
@@ -1,18 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'rubocop'
|
4
|
+
require 'ducalis/cops/extensions/type_resolving'
|
4
5
|
|
5
6
|
module Ducalis
|
6
7
|
class CallbacksActiverecord < RuboCop::Cop::Cop
|
8
|
+
prepend TypeResolving
|
9
|
+
|
7
10
|
OFFENSE = <<-MESSAGE.gsub(/^ +\|\s/, '').strip
|
8
11
|
| Please, avoid using of callbacks for models. It's better to keep models small ("dumb") and instead use "builder" classes/services: to construct new objects.
|
9
|
-
| You can read more [here](https://medium.com/planet-arkency/a61fd75ab2d3).
|
10
12
|
MESSAGE
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
].freeze
|
14
|
+
DETAILS = <<-MESSAGE.gsub(/^ +\|\s/, '').strip
|
15
|
+
| You can read more [here](https://medium.com/planet-arkency/a61fd75ab2d3).
|
16
|
+
MESSAGE
|
16
17
|
|
17
18
|
METHODS_BLACK_LIST = %i(
|
18
19
|
after_commit
|
@@ -36,20 +37,10 @@ module Ducalis
|
|
36
37
|
before_validation
|
37
38
|
).freeze
|
38
39
|
|
39
|
-
def on_class(node)
|
40
|
-
_classdef_node, superclass, _body = *node
|
41
|
-
@triggered = superclass &&
|
42
|
-
MODELS_CLASS_NAMES.include?(superclass.loc.expression.source)
|
43
|
-
end
|
44
|
-
|
45
40
|
def on_send(node)
|
46
|
-
return unless
|
41
|
+
return unless in_model?
|
47
42
|
return unless METHODS_BLACK_LIST.include?(node.method_name)
|
48
43
|
add_offense(node, :selector, OFFENSE)
|
49
44
|
end
|
50
|
-
|
51
|
-
private
|
52
|
-
|
53
|
-
attr_reader :triggered
|
54
45
|
end
|
55
46
|
end
|
@@ -13,7 +13,7 @@ module Ducalis
|
|
13
13
|
| Usually `case when` statements are using for the next reasons:
|
14
14
|
|
15
15
|
| I. Mapping between different values.
|
16
|
-
| ("A" => 1, "B" => 2, ...)
|
16
|
+
| `("A" => 1, "B" => 2, ...)`
|
17
17
|
|
18
18
|
| This case is all about data representing. If you do not need to execute any code it's better to use data structure which represents it. This way you are separating concepts: code returns corresponding value and you have config-like data structure which describes your data.
|
19
19
|
|
@@ -25,12 +25,13 @@ module Ducalis
|
|
25
25
|
|
26
26
|
| II. Code execution depending of parameter or type:
|
27
27
|
|
28
|
-
| - a. (:attack => attack, :defend => defend)
|
29
|
-
| - b. (Feet => value * 0.348, Meters => `value`)
|
28
|
+
| - a. `(:attack => attack, :defend => defend)`
|
29
|
+
| - b. `(Feet => value * 0.348, Meters => `value`)`
|
30
30
|
|
31
31
|
| In this case code violates OOP and S[O]LID principle. Code shouldn't know about object type and classes should be open for extension, but closed for modification (but you can't do it with case-statements). This is a signal that you have some problems with architecture.
|
32
32
|
|
33
33
|
| a.
|
34
|
+
|
34
35
|
| ```ruby
|
35
36
|
| attack: -> { execute_attack }, defend: -> { execute_defend }
|
36
37
|
| #{(action = '#{' + 'action' + '}') && '# or'}
|
@@ -38,13 +39,17 @@ module Ducalis
|
|
38
39
|
| ```
|
39
40
|
|
40
41
|
| b.
|
42
|
+
|
41
43
|
| ```ruby
|
42
44
|
| class Meters; def to_metters; value; end
|
43
45
|
| class Feet; def to_metters; value * 0.348; end
|
44
46
|
| ```
|
45
47
|
|
46
48
|
| III. Code execution depending on some statement.
|
49
|
+
|
50
|
+
| ```ruby
|
47
51
|
| (`a > 0` => 1, `a == 0` => 0, `a < 0` => -1)
|
52
|
+
| ```
|
48
53
|
|
49
54
|
| This case is combination of I and II -- high code complexity and unit-tests complexity. There are variants how to solve it:
|
50
55
|
|
@@ -11,12 +11,6 @@ module Ducalis
|
|
11
11
|
FILTERS = %i(before_filter after_filter around_filter
|
12
12
|
before_action after_action around_action).freeze
|
13
13
|
|
14
|
-
def on_class(node)
|
15
|
-
_classdef_node, superclass, _body = *node
|
16
|
-
return if superclass.nil?
|
17
|
-
@triggered = superclass.loc.expression.source =~ /Controller/
|
18
|
-
end
|
19
|
-
|
20
14
|
def on_send(node)
|
21
15
|
_, method_name, *args = *node
|
22
16
|
hash_node = args.find { |subnode| subnode.type == :hash }
|
@@ -31,7 +25,5 @@ module Ducalis
|
|
31
25
|
def decomposite_hash(args)
|
32
26
|
args.to_a.first.children.to_a
|
33
27
|
end
|
34
|
-
|
35
|
-
attr_reader :triggered
|
36
28
|
end
|
37
29
|
end
|