rubocop-platanus 0.1.0 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a03dfa4de53bd8b6ecc894167346f22ae13d475c5388990d014b8cf910a36aa7
4
- data.tar.gz: aa8b77d809a7c927feb85fbc2611bca678025243e2997a98aea81bc25fa25d68
3
+ metadata.gz: 1c7bdbf20cbe6ebdb80fc221e98427c0aaf6ce306e0f916eea5d41ddf15a1d61
4
+ data.tar.gz: 1d8b17010d0875bc096c683444d1d7221b080f07c10d19749db25c8b6db60ebc
5
5
  SHA512:
6
- metadata.gz: 1f8e068755dca01d916faa1e80696d4a7e169d805829a0c62f3fba93f30ca76e55208ba70116d844d12c0c84d71ebf02d0cedc70f90658a0fc49624471ebcdeb
7
- data.tar.gz: 80a86b5d5706bb9306c14a10b030f6500fce2b7f66e26c30247419f2b16527ab7e7e891b235c251f2554fd4583798267af01438d225045f9b1dd679644aa321c
6
+ metadata.gz: afa1eee563a4fb84a2ab075c47c21d0b9a42b92b4ab3f6588e3cb1cd951bc7b39a08c6cf01a2bc2eaf2e56dededd368c4ae78b1f0a56a671cddbc37bbeff2ec1
7
+ data.tar.gz: ac478f3cd0a18ee955c6c2d03c0d7ca8bfbc18c855393911482dc17d8ceb219e3e01efef45fa3ed22c9e987d0aed8638c68d0b4c5565be441413557e498de9f8
data/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
2
2
  All notable changes to this project will be documented in this file.
3
3
  This project adheres to [Semantic Versioning](http://semver.org/).
4
4
 
5
+ ### v0.2.0
6
+
7
+ Features
8
+
9
+ * Add cop Platanus/NoFlashInApi
10
+ * Add cop Platanus/NoEnumerize
11
+ * Add cop Platanus/NoRenderJson
12
+ * Add cop Platanus/PunditInApplicationController
13
+
5
14
  ### v0.1.0
6
15
 
7
16
  * Initial release.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rubocop-platanus (0.1.0)
4
+ rubocop-platanus (0.2.0)
5
5
  rubocop (>= 0.89.0)
6
6
 
7
7
  GEM
@@ -98,6 +98,7 @@ GEM
98
98
  unicode-display_width (2.1.0)
99
99
 
100
100
  PLATFORMS
101
+ x86_64-darwin-20
101
102
  x86_64-linux
102
103
 
103
104
  DEPENDENCIES
@@ -112,4 +113,4 @@ DEPENDENCIES
112
113
  rubocop-platanus!
113
114
 
114
115
  BUNDLED WITH
115
- 2.3.11
116
+ 2.3.14
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Test Gem
1
+ # Rubocop Platanus
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/rubocop-platanus.svg)](https://badge.fury.io/rb/rubocop-platanus)
4
4
  [![CircleCI](https://circleci.com/gh/platanus/rubocop-platanus.svg?style=shield)](https://app.circleci.com/pipelines/github/platanus/rubocop-platanus)
data/config/default.yml CHANGED
@@ -3,4 +3,36 @@
3
3
  Platanus/NoCommand:
4
4
  Description: "Prefer usage of `ActiveJob` instead of `PowerTypes::Command`"
5
5
  Enabled: true
6
+ Include:
7
+ - "app/commands/**/*.rb"
6
8
  VersionAdded: "<<next>>"
9
+
10
+ Platanus/NoFlashInApi:
11
+ Description: "Don't use `flash` in api controllers."
12
+ Enabled: true
13
+ SafeAutoCorrect: false
14
+ Include:
15
+ - "app/controllers/api/**/*.rb"
16
+ VersionAdded: "<<next>>"
17
+
18
+ Platanus/NoEnumerize:
19
+ Description: "Prefer usage of Rails `enum` instead of `Enumerize`"
20
+ Enabled: true
21
+ SafeAutoCorrect: false
22
+ Include:
23
+ - "app/models/**/*.rb"
24
+ VersionAdded: "<<next>>"
25
+
26
+ Platanus/NoRenderJson:
27
+ Description: "Prefer usage of `respond_with` instead of `render json:` to take advantage of `ApiResponder` and `serializers`"
28
+ Enabled: true
29
+ Include:
30
+ - "app/controllers/**/*.rb"
31
+ VersionAdded: "<<next>>"
32
+
33
+ Platanus/PunditInApplicationController:
34
+ Description: "`Pundit` should be included only in the `Application Controller`"
35
+ Enabled: true
36
+ Include:
37
+ - "app/controllers/**/*.rb"
38
+ VersionAdded: "0.1.0"
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Platanus
6
+ # Prefer usage of Rails `enum` instead of `Enumerize`
7
+ #
8
+ # @safety
9
+ # This cop's autocorrection will remove any lines using `extend Enumerize`
10
+ # and `enumerize :foo, in: [:bar, :baz]` within a file in app/models.
11
+ # There might be a case where using `enumerize` might be the intended behavior.
12
+ #
13
+ # @example
14
+ # # bad
15
+ # class Foo
16
+ # extend Enumerize
17
+ # enumerize :bar, in: [:foo, :bar]
18
+ # end
19
+ #
20
+ # # good
21
+ # class Foo
22
+ # enum bar: { foo: 0, bar: 1 }
23
+ # end
24
+ #
25
+ class NoEnumerize < Base
26
+ extend AutoCorrector
27
+ MSG = 'Use Rails `enum` instead of `enumerize`.'
28
+
29
+ # Detect if class extends `Enumerize`
30
+ def_node_matcher :extend_enumerize?, <<~PATTERN
31
+ (send nil? :extend (const nil? :Enumerize) ...)
32
+ PATTERN
33
+
34
+ # Returns the name and `in:` arguments of the enumerize call
35
+ def_node_matcher :get_enumerize_args, <<~PATTERN
36
+ (send nil? :enumerize (sym $_) (
37
+ hash
38
+ <
39
+ (pair (sym :in) (array $...))
40
+ ...
41
+ >
42
+ ))
43
+ PATTERN
44
+
45
+ def on_send(node)
46
+ on_extend_enumerize(node)
47
+ on_enumerize(node)
48
+ end
49
+
50
+ private
51
+
52
+ # Detects if class extends `Enumerize`
53
+ def on_extend_enumerize(node)
54
+ return unless extend_enumerize?(node)
55
+
56
+ add_offense(node) do |corrector|
57
+ corrector.remove(node)
58
+ end
59
+ end
60
+
61
+ # Detects if class uses `enumerize`. If so, it corrects the code.
62
+ def on_enumerize(node)
63
+ enumerize_args = get_enumerize_args(node)
64
+ return unless enumerize_args
65
+
66
+ name, args = enumerize_args
67
+ args = args.map(&:value)
68
+
69
+ add_offense(node) do |corrector|
70
+ corrector.replace(node, enumerize_correction(name, args))
71
+ end
72
+ end
73
+
74
+ # Returns the corrected code for `enumerize`
75
+ def enumerize_correction(name, args)
76
+ args_string = args.map.with_index do |arg, i|
77
+ "#{arg}: #{i}"
78
+ end.join(', ')
79
+
80
+ "enum #{name}: { #{args_string} }"
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Platanus
6
+ # Flash shouldn't be used in API controllers.
7
+ #
8
+ # @safety
9
+ # Auto correction will delete any lines using `flash[:type] = 'foo'`. There might be cases
10
+ # where using flash might be the intended behavior.
11
+ #
12
+ # @example
13
+ #
14
+ # # bad
15
+ # class Api::Internal::ResourcesController < Api::Internal::BaseController
16
+ # def show
17
+ # flash[:notice] = 'Foo'
18
+ # ...
19
+ # end
20
+ # end
21
+ #
22
+ # # good
23
+ # class Api::Internal::ResourcesController < Api::Internal::BaseController
24
+ # def show
25
+ # ...
26
+ # end
27
+ # end
28
+ #
29
+ class NoFlashInApi < Base
30
+ extend AutoCorrector
31
+
32
+ MSG = "Don't use `flash` in API controllers."
33
+
34
+ def_node_matcher :flash?, <<~PATTERN
35
+ (send (send nil? :flash) :[]= ...)
36
+ PATTERN
37
+
38
+ def on_send(node)
39
+ return unless flash?(node)
40
+
41
+ add_offense(node) do |corrector|
42
+ corrector.remove(node)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Platanus
6
+ # `render json:` shouldn't be used in controllers because it'll skip
7
+ # the use of ApiResponder and serializers. Use `respond_with` instead.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # render json: { data: @foo }
13
+ #
14
+ # # bad
15
+ # class Api::Internal::ResourcesController < Api::Internal::BaseController
16
+ # def show
17
+ # authorization_url = google_srv.generate_authorization_url
18
+ # respond_with({ authorization_url: authorization_url })
19
+ # end
20
+ # end
21
+ #
22
+ # # bad
23
+ # class Api::Internal::ResourcesController < Api::Internal::BaseController
24
+ # def show
25
+ # hash_response = { data: @foo }
26
+ # respond_with hash_response
27
+ # end
28
+ # end
29
+ #
30
+ # # good
31
+ # respond_with @foo
32
+ #
33
+ # # good
34
+ # # values/resource.rb
35
+ # class Resource
36
+ # include ActiveModel::Serialization
37
+ #
38
+ # attr_accessor :id, :name
39
+ #
40
+ # def initialize(id, name)
41
+ # @id = id
42
+ # @name = name
43
+ # end
44
+ # end
45
+ #
46
+ # # serializers/resource_serializer.rb
47
+ # class Api::Internal::ResourceSerializer < ActiveModel::Serializer
48
+ # type :resource
49
+ # attributes(
50
+ # :id,
51
+ # :name
52
+ # )
53
+ # end
54
+ #
55
+ # # controllers/api/internal_resources/resources_controller.rb
56
+ # class Api::Internal::ResourcesController < Api::Internal::BaseController
57
+ # def show
58
+ # respond_with(Resource.new(blog.id, blog.title))
59
+ # end
60
+ # end
61
+ #
62
+ class NoRenderJson < Base
63
+ RENDER_JSON_MSG = 'Use `respond_with` instead of `render json:`.'
64
+ RENDER_HASH_MSG =
65
+ 'Don\'t use `respond_with` with a hash. Use a value and serializer instead.'
66
+
67
+ RESTRICT_ON_SEND = %i[render respond_with].freeze
68
+
69
+ # Matches if render is called with json
70
+ def_node_matcher :render_json?, <<~PATTERN
71
+ (send nil? :render (hash (pair (sym :json) ...) ...))
72
+ PATTERN
73
+
74
+ # Captures the argument of respond_with
75
+ def_node_matcher :respond_with, <<~PATTERN
76
+ (send nil? :respond_with $_)
77
+ PATTERN
78
+
79
+ # Matches if node is hash
80
+ def_node_matcher :is_hash?, '(hash ...)'
81
+
82
+ # Captures the variable named of a used variable
83
+ def_node_matcher :var_name, '(lvar $_)'
84
+
85
+ def on_send(node)
86
+ if render_json?(node)
87
+ add_offense(node, message: RENDER_JSON_MSG)
88
+ elsif respond_with_hash?(node)
89
+ add_offense(node, message: RENDER_HASH_MSG)
90
+ end
91
+ end
92
+
93
+ # Determines if the node corresponds to a call of respond_with
94
+ # with a hash as it's argument.
95
+ def respond_with_hash?(node)
96
+ hash_node = respond_with(node)
97
+ return true if is_hash?(hash_node)
98
+
99
+ var_name = var_name(hash_node)
100
+ return false if var_name.nil?
101
+
102
+ var_is_hash?(node, var_name)
103
+ end
104
+
105
+ # Determines if a variable name corresponds to a hash within it's
106
+ # most immediate scope.
107
+ def var_is_hash?(node, var_name)
108
+ scope = node.parent
109
+ return false unless scope
110
+
111
+ pattern = "`(lvasgn :#{var_name} (hash ...))"
112
+ matcher = RuboCop::AST::NodePattern.new(pattern)
113
+
114
+ matcher.match(scope)
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Platanus
6
+ # Pundit should not be included in specific controllers. Prefer
7
+ # including it in the ApplicationController instead.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # class ApplicationController < ActionController::Base
12
+ # end
13
+ #
14
+ # class FooController < ApplicationController
15
+ # include Pundit
16
+ # end
17
+ #
18
+ # # bad
19
+ # class ApplicationController < ActionController::Base
20
+ # end
21
+ #
22
+ # class FooController < ApplicationController
23
+ # include Pundit::Authorization
24
+ # end
25
+ #
26
+ # # good
27
+ # class ApplicationController < ActionController::Base
28
+ # include Pundit
29
+ # end
30
+ #
31
+ # class FooController < ApplicationController
32
+ # end
33
+ #
34
+ # # good
35
+ # class ApplicationController < ActionController::Base
36
+ # include Pundit::Authorization
37
+ # end
38
+ #
39
+ # class FooController < ApplicationController
40
+ # end
41
+ #
42
+ class PunditInApplicationController < Base
43
+ MSG = '`Pundit` should be included only in the `ApplicationController`.'
44
+
45
+ def_node_matcher :get_include_pundit_node, <<~PATTERN
46
+ (class _ _ `$(
47
+ send
48
+ nil?
49
+ :include
50
+ (const {nil? | (const _ :Pundit)} {:Pundit | :Authorization})
51
+ ))
52
+ PATTERN
53
+
54
+ def_node_matcher :application_controller?, <<~PATTERN
55
+ (class (const nil? :ApplicationController) `(const (const nil? :ActionController) :Base) ...)
56
+ PATTERN
57
+
58
+ def on_class(node)
59
+ pundit_include_node = get_include_pundit_node(node)
60
+ return unless pundit_include_node && !application_controller?(node)
61
+
62
+ add_offense(pundit_include_node)
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -1,3 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'platanus/no_command'
4
+ require_relative 'platanus/no_flash_in_api'
5
+ require_relative 'platanus/no_enumerize'
6
+ require_relative 'platanus/no_render_json'
7
+ require_relative 'platanus/pundit_in_application_controller'
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  module Platanus
5
- VERSION = "0.1.0"
5
+ VERSION = "0.2.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-platanus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Platanus
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-22 00:00:00.000000000 Z
11
+ date: 2022-05-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -158,6 +158,10 @@ files:
158
158
  - config/default.yml
159
159
  - lib/rubocop-platanus.rb
160
160
  - lib/rubocop/cop/platanus/no_command.rb
161
+ - lib/rubocop/cop/platanus/no_enumerize.rb
162
+ - lib/rubocop/cop/platanus/no_flash_in_api.rb
163
+ - lib/rubocop/cop/platanus/no_render_json.rb
164
+ - lib/rubocop/cop/platanus/pundit_in_application_controller.rb
161
165
  - lib/rubocop/cop/platanus_cops.rb
162
166
  - lib/rubocop/platanus.rb
163
167
  - lib/rubocop/platanus/inject.rb