ducalis 0.5.14 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +8 -10
  3. data/README.md +2 -4
  4. data/Rakefile +0 -5
  5. data/bin/ducalis +8 -3
  6. data/config/.ducalis.yml +20 -1
  7. data/ducalis.gemspec +0 -1
  8. data/lib/ducalis.rb +7 -0
  9. data/lib/ducalis/cli.rb +80 -19
  10. data/lib/ducalis/commentators/console.rb +1 -1
  11. data/lib/ducalis/cops/black_list_suffix.rb +3 -0
  12. data/lib/ducalis/cops/callbacks_activerecord.rb +7 -16
  13. data/lib/ducalis/cops/case_mapping.rb +8 -3
  14. data/lib/ducalis/cops/controllers_except.rb +0 -8
  15. data/lib/ducalis/cops/data_access_objects.rb +28 -0
  16. data/lib/ducalis/cops/enforce_namespace.rb +28 -0
  17. data/lib/ducalis/cops/evlis_overusing.rb +30 -0
  18. data/lib/ducalis/cops/extensions/type_resolving.rb +52 -0
  19. data/lib/ducalis/cops/fetch_expression.rb +80 -0
  20. data/lib/ducalis/cops/module_like_class.rb +1 -0
  21. data/lib/ducalis/cops/multiple_times.rb +50 -0
  22. data/lib/ducalis/cops/options_argument.rb +5 -22
  23. data/lib/ducalis/cops/possible_tap.rb +4 -0
  24. data/lib/ducalis/cops/preferable_methods.rb +3 -1
  25. data/lib/ducalis/cops/private_instance_assign.rb +4 -9
  26. data/lib/ducalis/cops/protected_scope_cop.rb +4 -0
  27. data/lib/ducalis/cops/public_send.rb +18 -0
  28. data/lib/ducalis/cops/regex_cop.rb +36 -6
  29. data/lib/ducalis/cops/rest_only_cop.rb +4 -11
  30. data/lib/ducalis/cops/too_long_workers.rb +3 -8
  31. data/lib/ducalis/cops/uncommented_gem.rb +13 -1
  32. data/lib/ducalis/cops/useless_only.rb +6 -8
  33. data/lib/ducalis/documentation.rb +28 -18
  34. data/lib/ducalis/passed_args.rb +2 -2
  35. data/lib/ducalis/version.rb +1 -1
  36. metadata +9 -17
  37. data/DOCUMENTATION.md +0 -1185
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dee09942e0904fe18f8abf7a345305cbdfd8989c
4
- data.tar.gz: f93046f6e097760d0a5768dc3f2212b9d2cfe834
3
+ metadata.gz: c318246f914585d93588a49a31dfb31c7598b5f5
4
+ data.tar.gz: 8a4d1be3c918559feffab7275779250d76c60dfb
5
5
  SHA512:
6
- metadata.gz: b039f3df86b92eb0ccda9d61c8eaa3ac32995d9de8cc60f9f372b5c6a50b524d7dfb37385de66d3d63dd4ae4a4d97f88950a26388a225057d533da62f98e5cf7
7
- data.tar.gz: 1278017d4fafa60ff80a176e3c2d1a4fea13a76bf279c29a3879100c46a479b33a8691992e16ed96d520b4562d59d638120657a66ce540ce8498d4f3a2c137b5
6
+ metadata.gz: 319fb773559268eec362ae2a8f561d6f92a2f77d9d9b44825d4eb0fa70548173af97cdf266346677231ca152da5e9d416478b60a1b322845c1f576e55035b032
7
+ data.tar.gz: 4c81501488830a22fb562b31c32f4104f0d47d9dda9ab5102c2a0c9b149a328c30ead9a774f1368869af7cc128d8a86d3f2631be9f3783994fc993e0a2e0b732
@@ -1,19 +1,18 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ducalis (0.5.14)
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.3.0)
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.13.1)
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.12.2)
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.4.0.2)
42
- ast (~> 2.3)
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.1)
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.1)
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)
@@ -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.start(ARGV)
19
- RuboCop::CLI.new.run
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.start(ARGV - %w(--ci))
29
+ Ducalis::CLI.new(ARGV - %w(--ci)).start
25
30
  else
26
31
  Ducalis::PassedArgs.process_args!
27
32
 
@@ -1,6 +1,6 @@
1
1
  AllCops:
2
2
  DisabledByDefault: true
3
- TargetRubyVersion: 2.3
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
 
@@ -32,5 +32,4 @@ Gem::Specification.new do |spec|
32
32
  spec.add_dependency 'policial', '0.0.4'
33
33
  spec.add_dependency 'regexp-examples', '~> 1.3', '>= 1.3.2'
34
34
  spec.add_dependency 'rubocop', '>= 0.45.0', '~> 0.46.0'
35
- spec.add_dependency 'thor', '~> 0.20.0'
36
35
  end
@@ -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'
@@ -1,35 +1,96 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'thor'
3
+ require 'optparse'
4
4
 
5
5
  module Ducalis
6
- class CLI < Thor
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
- default_task :start
13
-
14
- desc '--ci', ''
15
- option :adapter, required: true, default: DEFAULT_ADAPTER,
16
- desc: 'Describes how Ducalis will receive PR information'
17
- option :id, type: :numeric, desc: 'PR id, ex: 2347'
18
- option :repo, type: :string, desc: 'PR repository, ex: author/repo'
19
- option :sha, type: :string, desc: 'Starting commit, can be skipped'
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
- adapter = ADAPTERS.fetch(options[:adapter].to_sym) do
24
- raise "Unsupported adapter #{options[:adapter]}"
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
- desc '--ci help', 'Describe available commands'
30
- def help(command = nil, subcommand = false)
31
- command ||= :start
32
- super
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.com/ignat-zakrevsky/ducalis/blob/master/DOCUMENTATION.md'
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
- MODELS_CLASS_NAMES = [
13
- 'ApplicationRecord',
14
- 'ActiveRecord::Base'
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 @triggered
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