ducalis 0.5.5 → 0.5.6

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.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ducalis (0.5.5)
4
+ ducalis (0.5.6)
5
5
  git (~> 1.3, >= 1.3.0)
6
6
  policial (= 0.0.4)
7
7
  regexp-examples (~> 1.3, >= 1.3.2)
@@ -38,8 +38,8 @@ GEM
38
38
  multipart-post (2.0.0)
39
39
  octokit (4.7.0)
40
40
  sawyer (~> 0.8.0, >= 0.5.3)
41
- parser (2.4.0.0)
42
- ast (~> 2.2)
41
+ parser (2.4.0.2)
42
+ ast (~> 2.3)
43
43
  policial (0.0.4)
44
44
  coffeelint (~> 1.14)
45
45
  eslintrb (~> 2.0)
@@ -49,11 +49,11 @@ GEM
49
49
  pry (0.11.2)
50
50
  coderay (~> 1.1.0)
51
51
  method_source (~> 0.9.0)
52
- public_suffix (3.0.0)
52
+ public_suffix (3.0.1)
53
53
  rainbow (2.2.2)
54
54
  rake
55
55
  rake (12.1.0)
56
- regexp-examples (1.4.0)
56
+ regexp-examples (1.4.1)
57
57
  rspec (3.7.0)
58
58
  rspec-core (~> 3.7.0)
59
59
  rspec-expectations (~> 3.7.0)
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/ducalis.svg)](https://badge.fury.io/rb/ducalis)
4
4
  [![Build Status](https://travis-ci.org/ignat-z/ducalis.svg?branch=master)](https://travis-ci.org/ignat-z/ducalis)
5
- [![Code Climate](https://codeclimate.com/github/ignat-z/ducalis/badges/gpa.svg)](https://codeclimate.com/github/ignat-z/ducalis)
5
+ [![Maintainability](https://api.codeclimate.com/v1/badges/d03d4e567e8728d2c58b/maintainability)](https://codeclimate.com/github/ignat-z/ducalis/maintainability)
6
6
 
7
7
  __Ducalis__ is RuboCop-based static code analyzer for enterprise Rails applications.
8
8
  As __Ducalis__ isn't style checker and could sometimes be false-positive it's not
@@ -58,3 +58,15 @@ rack application. All related files are located in the `client/` directory.
58
58
  In CLI modes you can provide yours `.ducalis.yml` file based on
59
59
  [default](https://github.com/ignat-z/ducalis/blob/master/config/.ducalis.yml) by
60
60
  `-c` flag or simply putting it in your project directory.
61
+
62
+ ## Contribution
63
+
64
+ To pass your code through the all checks you simply need to run:
65
+
66
+ ```
67
+ bundle exec rake
68
+ ```
69
+
70
+ Please, do not edit
71
+ [DOCUMENTATION.md](<https://github.com/ignat-z/ducalis/blob/master/DOCUMENTATION.md>),
72
+ this file is generating by `bundle exec rake documentation` command.
@@ -4,11 +4,18 @@ require 'rubocop'
4
4
 
5
5
  module Ducalis
6
6
  class CallbacksActiverecord < RuboCop::Cop::Cop
7
- OFFENSE = "Please, avoid using of callbacks for models. It's better to "\
8
- 'keep models small ("dumb") and instead use "builder" classes'\
9
- '/services: to construct new objects. You can read more [here]'\
10
- '(https://medium.com/planet-arkency/a61fd75ab2d3).'
11
- MODELS_CLASS_NAMES = ['ApplicationRecord', 'ActiveRecord::Base'].freeze
7
+ OFFENSE = <<-MESSAGE.gsub(/^ +\|/, '').strip
8
+ | Please, avoid using of callbacks for models. It's better to
9
+ | keep models small ("dumb") and instead use "builder" classes
10
+ | / services: to construct new objects. You can read more
11
+ | [here](https://medium.com/planet-arkency/a61fd75ab2d3).
12
+ MESSAGE
13
+
14
+ MODELS_CLASS_NAMES = [
15
+ 'ApplicationRecord',
16
+ 'ActiveRecord::Base'
17
+ ].freeze
18
+
12
19
  METHODS_BLACK_LIST = %i(
13
20
  after_commit
14
21
  after_create
@@ -4,14 +4,15 @@ require 'rubocop'
4
4
 
5
5
  module Ducalis
6
6
  class CaseMapping < RuboCop::Cop::Cop
7
- OFFENSE = %(
8
- Try to avoid `case when` statements. You can replace it with a sequence of
9
- `if... elsif... elsif... else`. For cases where you need to choose from a
10
- large number of possibilities, you can create a dictionary mapping case values
11
- to functions to call by `call`. It's nice to have prefix for the method
12
- names, i.e.: `visit_`.
13
-
14
- <details>
7
+ OFFENSE = <<-MESSAGE.gsub(/^ +\|/, '').strip
8
+ | Try to avoid `case when` statements. You can replace it with a sequence
9
+ | of `if... elsif... elsif... else`. For cases where you need to choose
10
+ | from a large number of possibilities, you can create a dictionary
11
+ | mapping case values to functions to call by `call`. It's nice to have
12
+ | prefix for the method names, i.e.: `visit_`.
13
+ MESSAGE
14
+
15
+ DETAILS = %(
15
16
  Usually `case when` statements are using for the next reasons:
16
17
 
17
18
  I. Mapping between different values.
@@ -3,14 +3,14 @@
3
3
  require 'rubocop'
4
4
 
5
5
  module Ducalis
6
- class ControllersExcept < ::RuboCop::Cop::Cop
7
- include RuboCop::Cop::DefNode
6
+ class ControllersExcept < RuboCop::Cop::Cop
7
+ OFFENSE = <<-MESSAGE.gsub(/^ +\|/, '').strip
8
+ | Prefer to use `:only` over `:except` in controllers because it's more
9
+ | explicit and will be easier to maintain for new developers.
10
+ MESSAGE
11
+
8
12
  FILTERS = %i(before_filter after_filter around_filter
9
13
  before_action after_action around_action).freeze
10
- OFFENSE = %(
11
- Prefer to use `:only` over `:except` in controllers because it's more explicit \
12
- and will be easier to maintain for new developers.
13
- ).strip
14
14
 
15
15
  def on_class(node)
16
16
  _classdef_node, superclass, _body = *node
@@ -4,11 +4,10 @@ require 'rubocop'
4
4
 
5
5
  module Ducalis
6
6
  class KeywordDefaults < RuboCop::Cop::Cop
7
- include RuboCop::Cop::DefNode
8
- OFFENSE = %(
9
- Prefer to use keyword arguments for defaults. \
10
- It increases readability and reduces ambiguities.
11
- ).strip
7
+ OFFENSE = <<-MESSAGE.gsub(/^ +\|/, '').strip
8
+ | Prefer to use keyword arguments for defaults. It increases readability
9
+ | and reduces ambiguities.
10
+ MESSAGE
12
11
 
13
12
  def on_def(node)
14
13
  args = node.type == :defs ? node.to_a[2] : node.to_a[1]
@@ -5,11 +5,10 @@ require 'rubocop'
5
5
  module Ducalis
6
6
  class ModuleLikeClass < RuboCop::Cop::Cop
7
7
  include RuboCop::Cop::DefNode
8
-
9
- OFFENSE = %(
10
- Seems like it will be better to define initialize and pass %<args>s there \
11
- instead of each method.
12
- ).strip
8
+ OFFENSE = <<-MESSAGE.gsub(/^ +\|/, '').strip
9
+ | Seems like it will be better to define initialize and pass %<args>s
10
+ | there instead of each method.
11
+ MESSAGE
13
12
 
14
13
  def on_class(node)
15
14
  _name, inheritance, body = *node
@@ -4,12 +4,12 @@ require 'rubocop'
4
4
 
5
5
  module Ducalis
6
6
  class ParamsPassing < RuboCop::Cop::Cop
7
- include RuboCop::Cop::DefNode
7
+ OFFENSE = <<-MESSAGE.gsub(/^ +\|/, '').strip
8
+ | It's better to pass already preprocessed params hash to services. Or
9
+ | you can use `arcane` gem.
10
+ MESSAGE
11
+
8
12
  PARAMS_CALL = s(:send, nil, :params)
9
- OFFENSE = %(
10
- It's better to pass already preprocessed params hash to services. Or you can use
11
- `arcane` gem
12
- ).strip
13
13
 
14
14
  def on_send(node)
15
15
  _who, _what, *args = *node
@@ -4,20 +4,19 @@ require 'rubocop'
4
4
 
5
5
  module Ducalis
6
6
  class PossibleTap < RuboCop::Cop::Cop
7
- include RuboCop::Cop::DefNode
8
-
9
- OFFENSE = %(
10
- Consider of using `.tap`, default ruby \
11
- [method](<https://apidock.com/ruby/Object/tap>) which allows to replace \
12
- intermediate variables with block, by this you are limiting scope pollution \
13
- and make scope more clear. \
14
- [Related article](<http://seejohncode.com/2012/01/02/ruby-tap-that/>).
15
- ).strip
7
+ OFFENSE = <<-MESSAGE.gsub(/^ +\|/, '').strip
8
+ | Consider of using `.tap`, default ruby
9
+ | [method](<https://apidock.com/ruby/Object/tap>)
10
+ | which allows to replace intermediate variables with block, by this you
11
+ | are limiting scope pollution and make scope more clear.
12
+ | [Related article](<http://seejohncode.com/2012/01/02/ruby-tap-that/>).
13
+ MESSAGE
16
14
 
17
15
  PAIRS = {
18
16
  lvar: :lvasgn,
19
17
  ivar: :ivasgn
20
18
  }.freeze
19
+
21
20
  ASSIGNS = PAIRS.keys
22
21
 
23
22
  def on_def(node)
@@ -49,11 +48,13 @@ and make scope more clear. \
49
48
 
50
49
  def return_var_call?(body)
51
50
  return unless body.children.last.respond_to?(:children)
52
- subnodes(body.children.last).find { |node| ASSIGNS.include?(node.type) }
51
+ subnodes(body.children.last.to_a.first).find do |node|
52
+ ASSIGNS.include?(node.type)
53
+ end
53
54
  end
54
55
 
55
56
  def subnodes(node)
56
- node.children.select { |child| child.respond_to?(:type) }
57
+ ([node] + node.children).select { |child| child.respond_to?(:type) }
57
58
  end
58
59
  end
59
60
  end
@@ -3,21 +3,27 @@ require 'rubocop'
3
3
 
4
4
  module Ducalis
5
5
  class PreferableMethods < RuboCop::Cop::Cop
6
- OFFENSE = %(
7
- Prefer to use %<alternative>s method instead of %<original>s because of
8
- %<reason>s.
9
- ).strip
6
+ OFFENSE = <<-MESSAGE.gsub(/^ +\|/, '').strip
7
+ | Prefer to use %<alternative>s method instead of %<original>s because of
8
+ | %<reason>s.
9
+ MESSAGE
10
+
10
11
  ALWAYS_TRUE = ->(_who, _what, _args) { true }
12
+
11
13
  DELETE_CHECK = lambda do |who, _what, args|
12
- !%i(sym str).include?(args.first&.type) &&
14
+ !%i(sym str).include?(args.first && args.first.type) &&
13
15
  args.count <= 1 && who.to_s !~ /file/
14
16
  end
17
+
15
18
  DESCRIPTION = {
16
19
  # Method => [Alternative, Reason, Callable condition]
17
20
  delete_all: [:destroy_all, 'it is not invoking callbacks', ALWAYS_TRUE],
18
21
  delete: [:destroy, 'it is not invoking callbacks', DELETE_CHECK]
19
22
  }.freeze
20
23
 
24
+ DETAILS = "Dangerous methods are:
25
+ #{DESCRIPTION.keys.map { |name| "`#{name}`" }.join(', ')}."
26
+
21
27
  def on_send(node)
22
28
  who, what, *args = *node
23
29
  return unless DESCRIPTION.keys.include?(what)
@@ -5,15 +5,22 @@ require 'rubocop'
5
5
  module Ducalis
6
6
  class PrivateInstanceAssign < RuboCop::Cop::Cop
7
7
  include RuboCop::Cop::DefNode
8
+ OFFENSE = <<-MESSAGE.gsub(/^ +\|/, '').strip
9
+ | Don't use filters for setting instance variables, use them only for
10
+ | changing application flow, such as redirecting if a user is not
11
+ | authenticated. Controller instance variables are forming contract
12
+ | between controller and view. Keeping instance variables defined in one
13
+ | place makes it easier to: reason, refactor and remove old views, test
14
+ | controllers and views, extract actions to new controllers, etc.
15
+ MESSAGE
8
16
 
9
- OFFENSE = %(
10
- Please, don't assign instance variables in controller's private methods. It's \
11
- make hard to understand what variables are available in views.
12
- ).strip
13
17
  ADD_OFFENSE = %(
14
18
  If you want to memoize variable, please, add underscore to the variable name \
15
19
  start: `@_name`.
16
20
  ).strip
21
+
22
+ DETAILS = ADD_OFFENSE
23
+
17
24
  def on_class(node)
18
25
  _classdef_node, superclass, _body = *node
19
26
  return if superclass.nil?
@@ -4,17 +4,17 @@ require 'rubocop'
4
4
 
5
5
  module Ducalis
6
6
  class ProtectedScopeCop < RuboCop::Cop::Cop
7
- OFFENSE = %{
8
- Seems like you are using `find` on non-protected scope. Potentially it could
9
- lead to unauthorized access. It's better to call `find` on authorized resources
10
- scopes. Example:
11
-
12
- ```ruby
13
- current_group.employees.find(params[:id])
14
- # better then
15
- Employee.find(params[:id])
16
- ```
17
- }.strip
7
+ OFFENSE = <<-MESSAGE.gsub(/^ +\|/, '').strip
8
+ | Seems like you are using `find` on non-protected scope. Potentially it
9
+ | could lead to unauthorized access. It's better to call `find` on
10
+ | authorized resources scopes. Example:
11
+ |
12
+ | ```ruby
13
+ | current_group.employees.find(params[:id])
14
+ | # better then
15
+ | Employee.find(params[:id])
16
+ | ```
17
+ MESSAGE
18
18
 
19
19
  def on_send(node)
20
20
  _, method_name, *args = *node
@@ -4,11 +4,10 @@ require 'rubocop'
4
4
 
5
5
  module Ducalis
6
6
  class RaiseWithourErrorClass < RuboCop::Cop::Cop
7
- include RuboCop::Cop::DefNode
8
- OFFENSE = %(
9
- It's better to add exception class as raise argument. It will make easier to \
10
- catch and process it later.
11
- ).strip
7
+ OFFENSE = <<-MESSAGE.gsub(/^ +\|/, '').strip
8
+ | It's better to add exception class as raise argument. It will make
9
+ | easier to catch and process it later.
10
+ MESSAGE
12
11
 
13
12
  def on_send(node)
14
13
  _who, what, *args = *node
@@ -5,15 +5,17 @@ require 'regexp-examples'
5
5
 
6
6
  module Ducalis
7
7
  class RegexCop < RuboCop::Cop::Cop
8
- OFFENSE = %(
9
- It's better to move regex to constants with example instead of direct using it.
10
- It will allow you to reuse this regex and provide instructions for others.
8
+ OFFENSE = <<-MESSAGE.gsub(/^ +\|/, '').strip
9
+ | It's better to move regex to constants with example instead of direct
10
+ | using it. It will allow you to reuse this regex and provide instructions
11
+ | for others.
12
+ |
13
+ |```ruby
14
+ |CONST_NAME = %<constant>s # "%<example>s"
15
+ |%<fixed_string>s
16
+ |```
17
+ MESSAGE
11
18
 
12
- ```ruby
13
- CONST_NAME = %<constant>s # "%<example>s"
14
- %<fixed_string>s
15
- ```
16
- ).strip
17
19
  SELF_DESCRIPTIVE = %w(
18
20
  /[[:alnum:]]/
19
21
  /[[:alpha:]]/
@@ -31,6 +33,9 @@ CONST_NAME = %<constant>s # "%<example>s"
31
33
  /[[:ascii:]]/
32
34
  ).freeze
33
35
 
36
+ DETAILS = "Available regexes are:
37
+ #{SELF_DESCRIPTIVE.map { |name| "`#{name}`" }.join(', ')}"
38
+
34
39
  def on_regexp(node)
35
40
  return if node.parent.type == :casgn
36
41
  return if SELF_DESCRIPTIVE.include?(node.source)
@@ -5,11 +5,12 @@ require 'rubocop'
5
5
  module Ducalis
6
6
  class RestOnlyCop < RuboCop::Cop::Cop
7
7
  include RuboCop::Cop::DefNode
8
+ OFFENSE = <<-MESSAGE.gsub(/^ +\|/, '').strip
9
+ | It's better for controllers to stay adherent to REST:
10
+ | http://jeromedalbert.com/how-dhh-organizes-his-rails-controllers/
11
+ MESSAGE
12
+
8
13
  WHITELIST = %i(index show new edit create update destroy).freeze
9
- OFFENSE = %(
10
- It's better for controllers to stay adherent to REST:
11
- http://jeromedalbert.com/how-dhh-organizes-his-rails-controllers/
12
- ).strip
13
14
 
14
15
  def on_class(node)
15
16
  _classdef_node, superclass, _body = *node
@@ -4,10 +4,11 @@ require 'rubocop'
4
4
 
5
5
  module Ducalis
6
6
  class RubocopDisable < RuboCop::Cop::Cop
7
- OFFENSE = %(
8
- Please, do not suppress RuboCop metrics, may be you can introduce some \
9
- refactoring or another concept.
10
- )
7
+ OFFENSE = <<-MESSAGE.gsub(/^ +\|/, '').strip
8
+ | Please, do not suppress RuboCop metrics, may be you can introduce some
9
+ | refactoring or another concept.
10
+ MESSAGE
11
+
11
12
  def investigate(processed_source)
12
13
  return unless processed_source.ast
13
14
  processed_source.comments.each do |comment_node|
@@ -4,12 +4,13 @@ require 'rubocop'
4
4
  require_relative './callbacks_activerecord'
5
5
 
6
6
  module Ducalis
7
- class StringsInActiverecords < ::RuboCop::Cop::Cop
8
- OFFENSE = %(
9
- Please, do not use strings as arguments for %<method_name>s argument.
10
- It's hard to test, grep sources, code highlighting and so on.
11
- Consider using of symbols or lambdas for complex expressions.
12
- ).strip
7
+ class StringsInActiverecords < RuboCop::Cop::Cop
8
+ OFFENSE = <<-MESSAGE.gsub(/^ +\|/, '').strip
9
+ | Please, do not use strings as arguments for %<method_name>s argument.
10
+ | It's hard to test, grep sources, code highlighting and so on.
11
+ | Consider using of symbols or lambdas for complex expressions.
12
+ MESSAGE
13
+
13
14
  VALIDATEBLE_METHODS =
14
15
  ::Ducalis::CallbacksActiverecord::METHODS_BLACK_LIST + %i(
15
16
  validates
@@ -3,11 +3,12 @@
3
3
  require 'rubocop'
4
4
 
5
5
  module Ducalis
6
- class UncommentedGem < ::RuboCop::Cop::Cop
7
- OFFENSE = %(
8
- Please, add comment why are you including non-realized gem version for %<gem>s.
9
- It will increase [bus-factor](<https://en.wikipedia.org/wiki/Bus_factor>).
10
- ).strip
6
+ class UncommentedGem < RuboCop::Cop::Cop
7
+ OFFENSE = <<-MESSAGE.gsub(/^ +\|/, '').strip
8
+ | Please, add comment why are you including non-realized gem version for
9
+ | %<gem>s. It will increase
10
+ | [bus-factor](<https://en.wikipedia.org/wiki/Bus_factor>).
11
+ MESSAGE
11
12
 
12
13
  def investigate(processed_source)
13
14
  return unless processed_source.ast