rubocop-rhino-project 0.20.0.alpha.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8d1e3753b313df9f9f1890d4af12074b96c0f7fe843e52d71e252f351e5ede79
4
+ data.tar.gz: 55693f13ed9852996e5fd026d76fe4d5bbdfcf24e9d551d3691d41ca8b33fcb8
5
+ SHA512:
6
+ metadata.gz: fb134e396dd3ff56d92c27e6e2212f991abb34b9fa3abaa583b25b4d1722ba9d8662da8f633619526422872dfb85e9fe53be208a7c71621e3cdf81bd4234ebca
7
+ data.tar.gz: 22a5209ac3c8171e456574d02476a0e4be7b3f1377816bf5ec42ec554e6fe5c9dcd403ea1352e8295131d10715d045dfda9979aef35f387614d273d07f1e10e0
@@ -0,0 +1,21 @@
1
+ # Common configuration.
2
+
3
+ inherit_mode:
4
+ merge:
5
+ - Exclude
6
+
7
+ AllCops:
8
+ Exclude:
9
+ - app/assets/**/*
10
+ - bin/*
11
+ # Exclude db/schema.rb and db/[CONFIGURATION_NAMESPACE]_schema.rb by default.
12
+ # See: https://guides.rubyonrails.org/active_record_multiple_databases.html#setting-up-your-application
13
+ - db/*schema.rb
14
+ - log/**/*
15
+ - public/**/*
16
+ - storage/**/*
17
+
18
+ RhinoProject/DuplicateRhinoReferences:
19
+ Description: ''
20
+ Enabled: true
21
+ SafeAutoCorrect: false
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module RhinoProject
6
+ # Don't call `rhino_references` method more than once in the same class.
7
+ #
8
+ #
9
+ # @example
10
+ # # bad
11
+ # class Blog < ApplicationRecord
12
+ # belongs_to :user
13
+ # belongs_to :category
14
+ #
15
+ # rhino_references %i[user]
16
+ # rhino_references %i[user category]
17
+ # end
18
+ #
19
+ # # good
20
+ # class Blog < ApplicationRecord
21
+ # belongs_to :user
22
+ # belongs_to :category
23
+ #
24
+ # rhino_references %i[user category]
25
+ # end
26
+ #
27
+ class DuplicateRhinoReferences < Base
28
+ MSG = "Avoid calling `rhino_references` method more than once in the same class."
29
+
30
+ def_node_search :rhino_references_call, "(send nil? :rhino_references (array ...))"
31
+
32
+ def on_class(node)
33
+ check_for_multiple_calls(node)
34
+ end
35
+
36
+ private
37
+ def check_for_multiple_calls(node)
38
+ rhino_references_calls = rhino_references_call(node)
39
+
40
+ return if rhino_references_calls.count <= 1
41
+
42
+ rhino_references_calls.each do |offending_call|
43
+ add_offense(offending_call, message: MSG)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "rhino_project/duplicate_rhino_references"
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module RhinoProject
5
+ # Because RuboCop doesn't yet support plugins, we have to monkey patch in a
6
+ # bit of our configuration.
7
+ module Inject
8
+ def self.defaults!
9
+ path = CONFIG_DEFAULT.to_s
10
+ hash = ConfigLoader.send(:load_yaml_configuration, path)
11
+ config = Config.new(hash, path).tap(&:make_excludes_absolute)
12
+ puts "configuration from #{path}" if ConfigLoader.debug?
13
+ config = ConfigLoader.merge_with_default(config, path, unset_nil: false)
14
+ ConfigLoader.instance_variable_set(:@default_configuration, config)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,188 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module RhinoProject
5
+ module SchemaLoader
6
+ # Represent db/schema.rb
7
+ class Schema
8
+ attr_reader :tables, :add_indices
9
+
10
+ def initialize(ast)
11
+ @tables = []
12
+ @add_indices = []
13
+
14
+ build!(ast)
15
+ end
16
+
17
+ def table_by(name:)
18
+ tables.find do |table|
19
+ table.name == name
20
+ end
21
+ end
22
+
23
+ def add_indices_by(table_name:)
24
+ add_indices.select do |add_index|
25
+ add_index.table_name == table_name
26
+ end
27
+ end
28
+
29
+ private
30
+ def build!(ast)
31
+ raise "Unexpected type: #{ast.type}" unless ast.block_type?
32
+ return unless ast.body
33
+
34
+ each_table(ast) do |table_def|
35
+ next unless table_def.method?(:create_table)
36
+
37
+ @tables << Table.new(table_def)
38
+ end
39
+
40
+ # Compatibility for Rails 4.2.
41
+ each_add_index(ast) do |add_index_def|
42
+ @add_indices << AddIndex.new(add_index_def)
43
+ end
44
+ end
45
+
46
+ def each_table(ast)
47
+ case ast.body.type
48
+ when :begin
49
+ ast.body.children.each do |node|
50
+ next unless node.block_type? && node.method?(:create_table)
51
+
52
+ yield(node)
53
+ end
54
+ else
55
+ yield ast.body
56
+ end
57
+ end
58
+
59
+ def each_add_index(ast)
60
+ ast.body.children.each do |node|
61
+ next unless node.respond_to?(:send_type?)
62
+ next if !node&.send_type? || !node.method?(:add_index)
63
+
64
+ yield(node)
65
+ end
66
+ end
67
+ end
68
+
69
+ # Represent a table
70
+ class Table
71
+ attr_reader :name, :columns, :indices
72
+
73
+ def initialize(node)
74
+ @name = node.send_node.first_argument.value
75
+ @columns = build_columns(node)
76
+ @indices = build_indices(node)
77
+ end
78
+
79
+ def with_column?(name:)
80
+ @columns.any? { |c| c.name == name }
81
+ end
82
+
83
+ private
84
+ def build_columns(node)
85
+ each_content(node).filter_map do |child|
86
+ next unless child&.send_type?
87
+ next if child.method?(:index)
88
+
89
+ Column.new(child)
90
+ end
91
+ end
92
+
93
+ def build_indices(node)
94
+ each_content(node).filter_map do |child|
95
+ next unless child&.send_type?
96
+ next unless child.method?(:index)
97
+
98
+ Index.new(child)
99
+ end
100
+ end
101
+
102
+ def each_content(node, &block)
103
+ return enum_for(__method__, node) unless block
104
+
105
+ case node.body&.type
106
+ when :begin
107
+ node.body.children.each(&block)
108
+ else
109
+ yield(node.body)
110
+ end
111
+ end
112
+ end
113
+
114
+ # Represent a column
115
+ class Column
116
+ attr_reader :name, :type, :not_null
117
+
118
+ def initialize(node)
119
+ @name = node.first_argument.str_content
120
+ @type = node.method_name
121
+ @not_null = nil
122
+
123
+ analyze_keywords!(node)
124
+ end
125
+
126
+ private
127
+ def analyze_keywords!(node)
128
+ pairs = node.last_argument
129
+ return unless pairs.hash_type?
130
+
131
+ pairs.each_pair do |k, v|
132
+ @not_null = !v.true_type? if k.value == :null
133
+ end
134
+ end
135
+ end
136
+
137
+ # Represent an index
138
+ class Index
139
+ attr_reader :name, :columns, :expression, :unique
140
+
141
+ def initialize(node)
142
+ @columns, @expression = build_columns_or_expr(node.first_argument)
143
+ @unique = nil
144
+
145
+ analyze_keywords!(node)
146
+ end
147
+
148
+ private
149
+ def build_columns_or_expr(columns)
150
+ if columns.array_type?
151
+ [columns.values.map(&:value), nil]
152
+ else
153
+ [[], columns.value]
154
+ end
155
+ end
156
+
157
+ def analyze_keywords!(node)
158
+ pairs = node.last_argument
159
+ return unless pairs.hash_type?
160
+
161
+ pairs.each_pair do |k, v|
162
+ case k.value
163
+ when :name
164
+ @name = v.value
165
+ when :unique
166
+ @unique = true
167
+ end
168
+ end
169
+ end
170
+ end
171
+
172
+ # Represent an `add_index`
173
+ class AddIndex < Index
174
+ attr_reader :table_name
175
+
176
+ def initialize(node)
177
+ super(node)
178
+
179
+ @table_name = node.first_argument.value
180
+ @columns, @expression = build_columns_or_expr(node.arguments[1])
181
+ @unique = nil
182
+
183
+ analyze_keywords!(node)
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module RhinoProject
5
+ # It loads db/schema.rb and return Schema object.
6
+ # Cops refers database schema information with this module.
7
+ module SchemaLoader
8
+ extend self
9
+
10
+ # It parses `db/schema.rb` and return it.
11
+ # It returns `nil` if it can't find `db/schema.rb`.
12
+ # So a cop that uses the loader should handle `nil` properly.
13
+ #
14
+ # @return [Schema, nil]
15
+ def load(target_ruby_version, parser_engine)
16
+ return @load if defined?(@load)
17
+
18
+ @load = load!(target_ruby_version, parser_engine)
19
+ end
20
+
21
+ def reset!
22
+ return unless instance_variable_defined?(:@load)
23
+
24
+ remove_instance_variable(:@load)
25
+ end
26
+
27
+ def db_schema_path
28
+ path = Pathname.pwd
29
+ until path.root?
30
+ schema_path = path.join("db/schema.rb")
31
+ return schema_path if schema_path.exist?
32
+
33
+ path = path.join("../").cleanpath
34
+ end
35
+
36
+ nil
37
+ end
38
+
39
+ private
40
+ def load!(target_ruby_version, parser_engine)
41
+ path = db_schema_path
42
+ return unless path
43
+
44
+ ast = RuboCop::ProcessedSource.new(File.read(path), target_ruby_version, path, parser_engine:).ast
45
+
46
+ Schema.new(ast) if ast
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubocopRhinoProject
4
+ # Returns the currently loaded version of Rhino core as a +Gem::Version+.
5
+ def self.gem_version
6
+ Gem::Version.new VERSION::STRING
7
+ end
8
+
9
+ module VERSION
10
+ MAJOR = 0
11
+ MINOR = 20
12
+ TINY = 0
13
+ PRE = "alpha.0"
14
+
15
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ # RuboCop Rails project namespace
5
+ module RhinoProject
6
+ PROJECT_ROOT = Pathname.new(__dir__).parent.parent.expand_path.freeze
7
+ CONFIG_DEFAULT = PROJECT_ROOT.join("config", "default.yml").freeze
8
+ CONFIG = YAML.safe_load(CONFIG_DEFAULT.read, permitted_classes: [Regexp, Symbol]).freeze
9
+
10
+ private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT)
11
+ end
12
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubocop"
4
+ require "rack/utils"
5
+ require "active_support/inflector"
6
+ require "active_support/core_ext/object/blank"
7
+
8
+ require_relative "rubocop/rhino_project"
9
+ require_relative "rubocop/rhino_project/version"
10
+ require_relative "rubocop/rhino_project/inject"
11
+ require_relative "rubocop/rhino_project/schema_loader"
12
+ require_relative "rubocop/rhino_project/schema_loader/schema"
13
+
14
+ RuboCop::RhinoProject::Inject.defaults!
15
+
16
+ require_relative "rubocop/cop/rhino_project_cops"
17
+
18
+ RuboCop::Cop::Style::HashExcept.minimum_target_ruby_version(2.0)
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubocop-rhino-project
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.20.0.alpha.0
5
+ platform: ruby
6
+ authors:
7
+ - JP Rosevear
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-08-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 4.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 4.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rack
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '1.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '1.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 1.24.1
48
+ - - "<"
49
+ - !ruby/object:Gem::Version
50
+ version: '2.0'
51
+ type: :runtime
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: 1.24.1
58
+ - - "<"
59
+ - !ruby/object:Gem::Version
60
+ version: '2.0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: rubocop-ast
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: 1.21.0
68
+ - - "<"
69
+ - !ruby/object:Gem::Version
70
+ version: '2.0'
71
+ type: :runtime
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: 1.21.0
78
+ - - "<"
79
+ - !ruby/object:Gem::Version
80
+ version: '2.0'
81
+ description: ''
82
+ email:
83
+ - jp@codalio.com
84
+ executables: []
85
+ extensions: []
86
+ extra_rdoc_files: []
87
+ files:
88
+ - config/default.yml
89
+ - lib/rubocop-rhino-project.rb
90
+ - lib/rubocop/cop/rhino_project/duplicate_rhino_references.rb
91
+ - lib/rubocop/cop/rhino_project_cops.rb
92
+ - lib/rubocop/rhino_project.rb
93
+ - lib/rubocop/rhino_project/inject.rb
94
+ - lib/rubocop/rhino_project/schema_loader.rb
95
+ - lib/rubocop/rhino_project/schema_loader/schema.rb
96
+ - lib/rubocop/rhino_project/version.rb
97
+ homepage: ''
98
+ licenses:
99
+ - MIT
100
+ metadata: {}
101
+ post_install_message:
102
+ rdoc_options: []
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubygems_version: 3.5.11
117
+ signing_key:
118
+ specification_version: 4
119
+ summary: ''
120
+ test_files: []