rubocop-rhino-project 0.20.0.alpha.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 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: []