rubocop-lts-ruby 0.1.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 +7 -0
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +119 -0
- data/LICENSE.md +10 -0
- data/README.md +533 -0
- data/Rakefile +188 -0
- data/config/base.yml +12 -0
- data/lib/rubocop/lts/ruby/catalog.rb +383 -0
- data/lib/rubocop/lts/ruby/cop/lint_lts_ruby/unavailable_method.rb +71 -0
- data/lib/rubocop/lts/ruby/plugin.rb +35 -0
- data/lib/rubocop/lts/ruby/version.rb +15 -0
- data/lib/rubocop/lts/ruby.rb +11 -0
- data/lib/rubocop-lts-ruby.rb +9 -0
- data/rubocop-lts-ruby.gemspec +151 -0
- data/sig/rubocop/lts/ruby.rbs +10 -0
- data.tar.gz.sig +0 -0
- metadata +360 -0
- metadata.gz.sig +0 -0
data/Rakefile
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# kettle-jem:freeze
|
|
4
|
+
# To retain chunks of comments & code during kettle-jem templating:
|
|
5
|
+
# Wrap custom sections with freeze markers (e.g., as above and below this comment chunk).
|
|
6
|
+
# kettle-jem will then preserve content between those markers across template runs.
|
|
7
|
+
# kettle-jem:unfreeze
|
|
8
|
+
|
|
9
|
+
# rubocop-lts-ruby Rakefile v7.1.1 - 2026-08-09
|
|
10
|
+
# Ruby 2.3 (Safe Navigation) or higher required
|
|
11
|
+
#
|
|
12
|
+
# See LICENSE.md for license information.
|
|
13
|
+
#
|
|
14
|
+
# Copyright (c) 2026 Peter H. Boling (galtzo.com)
|
|
15
|
+
#
|
|
16
|
+
# Expected to work in any project that uses Bundler.
|
|
17
|
+
#
|
|
18
|
+
# Sets up tasks for appraisal2, floss_funding, kettle-jem, kettle-dev, rspec, minitest, rubocop_gradual, reek, yard, and stone_checksums.
|
|
19
|
+
#
|
|
20
|
+
# rake appraisal:install # Install Appraisal gemfiles (initial setup...
|
|
21
|
+
# rake appraisal:reset # Delete Appraisal lockfiles (gemfiles/*.gemfile.lock)
|
|
22
|
+
# rake appraisal:generate # Generate Appraisal gemfiles without resolving...
|
|
23
|
+
# rake appraisal:update # Generate and update Appraisal gemfiles
|
|
24
|
+
# rake bench # Run all benchmarks (alias for bench:run)
|
|
25
|
+
# rake bench:list # List available benchmark scripts
|
|
26
|
+
# rake bench:run # Run all benchmark scripts (skips on CI)
|
|
27
|
+
# rake build:generate_checksums # Generate both SHA256 & SHA512 checksums i...
|
|
28
|
+
# rake bundle:audit:check # Checks the Gemfile.lock for insecure depe...
|
|
29
|
+
# rake bundle:audit:update # Updates the bundler-audit vulnerability d...
|
|
30
|
+
# rake ci:act[opt] # Run 'act' with a selected workflow
|
|
31
|
+
# rake coverage # Run specs w/ coverage and open results in...
|
|
32
|
+
# rake default # Default tasks aggregator
|
|
33
|
+
# rake install # Build and install rubocop-lts-ruby-1.0.0.gem in...
|
|
34
|
+
# rake install:local # Build and install rubocop-lts-ruby-1.0.0.gem in...
|
|
35
|
+
# rake kettle:jem:install # Internal target used by `kettle-jem install`
|
|
36
|
+
# rake kettle:jem:selftest # Self-test: template rubocop-lts-ruby against itse...
|
|
37
|
+
# rake kettle:jem:template # Internal target used by scoped `kettle-jem template --only`
|
|
38
|
+
# rake reek # Check for code smells
|
|
39
|
+
# rake reek:update # Run reek and store the output into the RE...
|
|
40
|
+
# rake release[remote] # Create tag v1.0.0 and build and push kett...
|
|
41
|
+
# rake rubocop_gradual # Run RuboCop Gradual
|
|
42
|
+
# rake rubocop_gradual:autocorrect # Run RuboCop Gradual with autocorrect (onl...
|
|
43
|
+
# rake rubocop_gradual:autocorrect_all # Run RuboCop Gradual with autocorrect (saf...
|
|
44
|
+
# rake rubocop_gradual:check # Run RuboCop Gradual to check the lock file
|
|
45
|
+
# rake rubocop_gradual:force_update # Run RuboCop Gradual to force update the l...
|
|
46
|
+
# rake rubocop_gradual_debug # Run RuboCop Gradual
|
|
47
|
+
# rake rubocop_gradual_debug:autocorrect # Run RuboCop Gradual with autocorrect (onl...
|
|
48
|
+
# rake rubocop_gradual_debug:autocorrect_all # Run RuboCop Gradual with autocorrect (saf...
|
|
49
|
+
# rake rubocop_gradual_debug:check # Run RuboCop Gradual to check the lock file
|
|
50
|
+
# rake rubocop_gradual_debug:force_update # Run RuboCop Gradual to force update the l...
|
|
51
|
+
# rake spec # Run RSpec code examples
|
|
52
|
+
# rake test # Run tests
|
|
53
|
+
# rake yard # Generate YARD Documentation
|
|
54
|
+
# rake yard:lint # Lint YARD Documentation
|
|
55
|
+
#
|
|
56
|
+
|
|
57
|
+
# simplecov:disable
|
|
58
|
+
require "bundler/gem_tasks" if !Dir[File.join(__dir__, "*.gemspec")].empty?
|
|
59
|
+
# simplecov:enable
|
|
60
|
+
|
|
61
|
+
# Define a base default task early so other files can enhance it.
|
|
62
|
+
desc "Default tasks aggregator"
|
|
63
|
+
task :default do
|
|
64
|
+
puts "Default task complete."
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# simplecov:disable
|
|
68
|
+
### MONOREPO FAMILY TASKS
|
|
69
|
+
if Dir.exist?(File.join(__dir__, "gems"))
|
|
70
|
+
def family_gem_dirs
|
|
71
|
+
Dir.glob(File.join(__dir__, "gems", "*", "*.gemspec"))
|
|
72
|
+
.map { |path| File.dirname(path) }
|
|
73
|
+
.uniq
|
|
74
|
+
.sort_by { |path| File.basename(path) }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def run_kettle_family(*args)
|
|
78
|
+
sh("bundle", "exec", "kettle-family", *args)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
namespace :family do
|
|
82
|
+
desc "List released Ruby subgems"
|
|
83
|
+
task :list do
|
|
84
|
+
family_gem_dirs.each { |path| puts File.basename(path) }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
desc "Run release readiness checks for the Ruby gem family"
|
|
88
|
+
task :readiness do
|
|
89
|
+
run_kettle_family("check")
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
desc "Run tests for the Ruby gem family"
|
|
93
|
+
task :test do
|
|
94
|
+
run_kettle_family("test", "--execute")
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
desc "Run lint for the Ruby gem family"
|
|
98
|
+
task :lint do
|
|
99
|
+
run_kettle_family("lint", "--execute")
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
desc "Generate YARD docs for the Ruby gem family"
|
|
103
|
+
task :docs do
|
|
104
|
+
run_kettle_family("docs", "--execute")
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
desc "Report release state for the Ruby gem family"
|
|
108
|
+
task :release_state do
|
|
109
|
+
run_kettle_family("release-state")
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
desc "Run the Ruby gem family release planner"
|
|
113
|
+
task :release do
|
|
114
|
+
run_kettle_family("release")
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
desc "Execute the Ruby gem family release"
|
|
118
|
+
task :release_execute do
|
|
119
|
+
run_kettle_family("release", "--execute")
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
# simplecov:enable
|
|
124
|
+
|
|
125
|
+
# External gems that define tasks - add here!
|
|
126
|
+
begin
|
|
127
|
+
require "kettle/dev"
|
|
128
|
+
Kettle::Dev.install_tasks unless Kettle::Dev::RUNNING_AS == "rake"
|
|
129
|
+
rescue LoadError
|
|
130
|
+
warn("NOTE: kettle-dev isn't installed, or is disabled for #{RUBY_VERSION} in the current environment")
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
### DUPLICATE DRIFT TASKS
|
|
134
|
+
begin
|
|
135
|
+
require "kettle/drift"
|
|
136
|
+
Kettle::Drift.install_tasks
|
|
137
|
+
rescue LoadError
|
|
138
|
+
desc("(stub) kettle:drift:check is unavailable")
|
|
139
|
+
task("kettle:drift:check") do
|
|
140
|
+
warn("NOTE: kettle-drift isn't installed, or is disabled for #{RUBY_VERSION} in the current environment")
|
|
141
|
+
end
|
|
142
|
+
desc("(stub) kettle:drift:update is unavailable")
|
|
143
|
+
task("kettle:drift:update") do
|
|
144
|
+
warn("NOTE: kettle-drift isn't installed, or is disabled for #{RUBY_VERSION} in the current environment")
|
|
145
|
+
end
|
|
146
|
+
desc("(stub) kettle:drift:force_update is unavailable")
|
|
147
|
+
task("kettle:drift:force_update") do
|
|
148
|
+
warn("NOTE: kettle-drift isn't installed, or is disabled for #{RUBY_VERSION} in the current environment")
|
|
149
|
+
end
|
|
150
|
+
desc("(stub) kettle:drift is unavailable")
|
|
151
|
+
task("kettle:drift" => "kettle:drift:update")
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
### TEMPLATING TASKS
|
|
155
|
+
# These tasks are installed for the `kettle-jem` executable. Run full templating
|
|
156
|
+
# through `kettle-jem install`; use `kettle-jem template --only PATH` only for
|
|
157
|
+
# scoped file updates. The executable prepares the environment and then
|
|
158
|
+
# delegates here when rake orchestration is needed.
|
|
159
|
+
kettle_jem_selftest_unavailable_note = nil
|
|
160
|
+
begin
|
|
161
|
+
require "kettle/jem"
|
|
162
|
+
if Kettle::Jem.respond_to?(:install_tasks)
|
|
163
|
+
Kettle::Jem.install_tasks
|
|
164
|
+
else
|
|
165
|
+
kettle_jem_selftest_unavailable_note = "NOTE: kettle-jem #{Kettle::Jem::Version::VERSION} does not provide rake tasks in this environment"
|
|
166
|
+
end
|
|
167
|
+
rescue LoadError
|
|
168
|
+
kettle_jem_selftest_unavailable_note = "NOTE: kettle-jem isn't installed, or is disabled for #{RUBY_VERSION} in the current environment"
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
if kettle_jem_selftest_unavailable_note
|
|
172
|
+
desc("(stub) kettle:jem:selftest is unavailable")
|
|
173
|
+
task("kettle:jem:selftest") do
|
|
174
|
+
warn(kettle_jem_selftest_unavailable_note)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
### RELEASE TASKS
|
|
179
|
+
# Setup stone_checksums
|
|
180
|
+
begin
|
|
181
|
+
require "stone_checksums"
|
|
182
|
+
rescue LoadError
|
|
183
|
+
desc("(stub) build:generate_checksums is unavailable")
|
|
184
|
+
task("build:generate_checksums") do
|
|
185
|
+
warn("NOTE: stone_checksums isn't installed, or is disabled for #{RUBY_VERSION} in the current environment")
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
# frozen_string_literal: true
|
data/config/base.yml
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# This plugin owns its API-gating rules only. The consuming RuboCop
|
|
2
|
+
# configuration remains the sole owner of AllCops: TargetRubyVersion.
|
|
3
|
+
require:
|
|
4
|
+
- rubocop/lts/ruby/cop/lint_lts_ruby/unavailable_method
|
|
5
|
+
|
|
6
|
+
Lint/LtsRuby/UnavailableMethod:
|
|
7
|
+
Description: >-
|
|
8
|
+
Detect explicit calls to Ruby APIs that were introduced after the configured
|
|
9
|
+
TargetRubyVersion.
|
|
10
|
+
Enabled: true
|
|
11
|
+
VersionAdded: '0.1'
|
|
12
|
+
AllowedMethods: []
|
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rubygems/version"
|
|
4
|
+
|
|
5
|
+
module RuboCop
|
|
6
|
+
module Lts
|
|
7
|
+
module Ruby
|
|
8
|
+
# Runtime APIs whose availability is tied to the Ruby release that added them.
|
|
9
|
+
# Keep entries explicit until a versioned API source can be made authoritative.
|
|
10
|
+
module Catalog
|
|
11
|
+
Entry = Data.define(:owner, :method_name, :introduced_in, :receiver_type)
|
|
12
|
+
|
|
13
|
+
def self.entry(owner, method_name, introduced_in, receiver_type: :instance)
|
|
14
|
+
Entry.new(owner, method_name, Gem::Version.new(introduced_in), receiver_type)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
ENTRIES = [
|
|
18
|
+
entry("ARGF", :codepoints, "2.0"),
|
|
19
|
+
entry("ARGF", :each_codepoint, "2.0"),
|
|
20
|
+
entry("Array", :append, "2.5"),
|
|
21
|
+
entry("Array", :bsearch, "2.0"),
|
|
22
|
+
entry("Array", :bsearch_index, "2.3"),
|
|
23
|
+
entry("Array", :fetch_values, "3.4"),
|
|
24
|
+
entry("Array", :prepend, "2.5"),
|
|
25
|
+
entry("Array", :dig, "2.3"),
|
|
26
|
+
entry("Array", :difference, "2.6"),
|
|
27
|
+
entry("Array", :filter, "2.6"),
|
|
28
|
+
entry("Array", :filter!, "2.6"),
|
|
29
|
+
entry("Array", :intersection, "2.7"),
|
|
30
|
+
entry("Array", :intersect?, "3.1"),
|
|
31
|
+
entry("Array", :minmax, "2.7"),
|
|
32
|
+
entry("Array", :sum, "2.4"),
|
|
33
|
+
entry("Array", :to_h, "2.1"),
|
|
34
|
+
entry("Array", :union, "2.6"),
|
|
35
|
+
entry("Binding", :local_variable_defined?, "2.1"),
|
|
36
|
+
entry("Binding", :local_variable_get, "2.1"),
|
|
37
|
+
entry("Binding", :local_variable_set, "2.1"),
|
|
38
|
+
entry("Binding", :local_variables, "2.2"),
|
|
39
|
+
entry("Binding", :receiver, "2.2"),
|
|
40
|
+
entry("Binding", :source_location, "2.6"),
|
|
41
|
+
entry("Class", :attached_object, "3.2"),
|
|
42
|
+
entry("Class", :subclasses, "3.1"),
|
|
43
|
+
entry("Comparable", :clamp, "2.4"),
|
|
44
|
+
entry("Complex", :<=>, "2.7"),
|
|
45
|
+
entry("Coverage", :peek_result, "2.3", receiver_type: :constant),
|
|
46
|
+
entry("Coverage", :line_stub, "2.6", receiver_type: :constant),
|
|
47
|
+
entry("Coverage", :supported?, "3.2", receiver_type: :constant),
|
|
48
|
+
entry("Date", :jisx0301, "2.7"),
|
|
49
|
+
entry("Date", :jisx0301, "2.7", receiver_type: :constant),
|
|
50
|
+
entry("Dir", :children, "2.5", receiver_type: :constant),
|
|
51
|
+
entry("Dir", :chdir, "3.3"),
|
|
52
|
+
entry("Dir", :each_child, "2.5", receiver_type: :constant),
|
|
53
|
+
entry("Dir", :empty?, "2.4", receiver_type: :constant),
|
|
54
|
+
entry("Dir", :fchdir, "3.3", receiver_type: :constant),
|
|
55
|
+
entry("Dir", :fileno, "2.2"),
|
|
56
|
+
entry("Dir", :for_fd, "3.3", receiver_type: :constant),
|
|
57
|
+
entry("Enumerable", :chain, "2.6"),
|
|
58
|
+
entry("Enumerable", :chunk_while, "2.3"),
|
|
59
|
+
entry("Enumerable", :compact, "3.1"),
|
|
60
|
+
entry("Enumerable", :filter, "2.6"),
|
|
61
|
+
entry("Enumerable", :filter_map, "2.7"),
|
|
62
|
+
entry("Enumerable", :grep_v, "2.3"),
|
|
63
|
+
entry("Enumerable", :lazy, "2.0"),
|
|
64
|
+
entry("Enumerable", :slice_after, "2.2"),
|
|
65
|
+
entry("Enumerable", :slice_when, "2.2"),
|
|
66
|
+
entry("Enumerable", :sum, "2.4"),
|
|
67
|
+
entry("Enumerable", :tally, "2.7"),
|
|
68
|
+
entry("Enumerable", :to_h, "2.1"),
|
|
69
|
+
entry("Enumerable", :uniq, "2.4"),
|
|
70
|
+
entry("Enumerator", :size, "2.0"),
|
|
71
|
+
entry("Enumerator", :+, "2.6"),
|
|
72
|
+
entry("Enumerator", :produce, "2.7", receiver_type: :constant),
|
|
73
|
+
entry("Enumerator", :product, "3.2", receiver_type: :constant),
|
|
74
|
+
entry("Enumerator::Lazy", :chunk_while, "2.4"),
|
|
75
|
+
entry("Enumerator::Lazy", :compact, "3.1"),
|
|
76
|
+
entry("Enumerator::Lazy", :eager, "2.7"),
|
|
77
|
+
entry("Enumerator::Lazy", :filter, "2.6"),
|
|
78
|
+
entry("Enumerator::Lazy", :grep_v, "2.3"),
|
|
79
|
+
entry("Enumerator::Lazy", :uniq, "2.4"),
|
|
80
|
+
entry("Enumerator::Yielder", :to_proc, "2.7"),
|
|
81
|
+
entry("Exception", :cause, "2.1"),
|
|
82
|
+
entry("Exception", :detailed_message, "3.2"),
|
|
83
|
+
entry("Exception", :full_message, "2.5"),
|
|
84
|
+
entry("ENV", :except, "3.0", receiver_type: :constant),
|
|
85
|
+
entry("ERB::Escape", :html_escape, "3.2", receiver_type: :constant),
|
|
86
|
+
entry("Etc", :confstr, "2.2", receiver_type: :constant),
|
|
87
|
+
entry("Etc", :nprocessors, "2.2", receiver_type: :constant),
|
|
88
|
+
entry("Etc", :sysconf, "2.2", receiver_type: :constant),
|
|
89
|
+
entry("Etc", :uname, "2.2", receiver_type: :constant),
|
|
90
|
+
entry("Date", :deconstruct_keys, "3.2"),
|
|
91
|
+
entry("DateTime", :deconstruct_keys, "3.2"),
|
|
92
|
+
entry("Fiber", :[], "3.2", receiver_type: :constant),
|
|
93
|
+
entry("Fiber", :[]=, "3.2", receiver_type: :constant),
|
|
94
|
+
entry("Fiber", :backtrace, "3.0"),
|
|
95
|
+
entry("Fiber", :backtrace_locations, "3.0"),
|
|
96
|
+
entry("Fiber", :blocking?, "3.0"),
|
|
97
|
+
entry("Fiber", :blocking?, "3.0", receiver_type: :constant),
|
|
98
|
+
entry("Fiber", :kill, "3.3"),
|
|
99
|
+
entry("Fiber", :raise, "2.7"),
|
|
100
|
+
entry("Fiber", :scheduler, "3.0", receiver_type: :constant),
|
|
101
|
+
entry("Fiber", :set_scheduler, "3.0", receiver_type: :constant),
|
|
102
|
+
entry("Fiber", :storage, "3.2"),
|
|
103
|
+
entry("Fiber", :"storage=", "3.2"),
|
|
104
|
+
entry("Fiber::Scheduler", :blocking_operation_wait, "3.4"),
|
|
105
|
+
entry("Fiber::Scheduler", :io_select, "3.2"),
|
|
106
|
+
entry("File", :absolute_path?, "2.7", receiver_type: :constant),
|
|
107
|
+
entry("File", :birthtime, "2.2"),
|
|
108
|
+
entry("File", :birthtime, "2.2", receiver_type: :constant),
|
|
109
|
+
entry("File", :empty?, "2.4", receiver_type: :constant),
|
|
110
|
+
entry("File", :lutime, "2.5", receiver_type: :constant),
|
|
111
|
+
entry("File", :mkfifo, "2.3", receiver_type: :constant),
|
|
112
|
+
entry("File::Stat", :birthtime, "2.2"),
|
|
113
|
+
entry("FileUtils", :cp_lr, "2.6"),
|
|
114
|
+
entry("FileUtils", :cp_lr, "2.6", receiver_type: :constant),
|
|
115
|
+
entry("FileUtils", :ln_sr, "3.2"),
|
|
116
|
+
entry("FileUtils", :ln_sr, "3.2", receiver_type: :constant),
|
|
117
|
+
entry("Float", :next_float, "2.2"),
|
|
118
|
+
entry("Float", :prev_float, "2.2"),
|
|
119
|
+
entry("FrozenError", :receiver, "2.7"),
|
|
120
|
+
entry("GC", :auto_compact, "3.0", receiver_type: :constant),
|
|
121
|
+
entry("GC", :"auto_compact=", "3.0", receiver_type: :constant),
|
|
122
|
+
entry("GC", :compact, "2.7", receiver_type: :constant),
|
|
123
|
+
entry("GC", :latest_gc_info, "2.2", receiver_type: :constant),
|
|
124
|
+
entry("GC", :config, "3.4", receiver_type: :constant),
|
|
125
|
+
entry("GC", :measure_total_time, "3.1", receiver_type: :constant),
|
|
126
|
+
entry("GC", :"measure_total_time=", "3.1", receiver_type: :constant),
|
|
127
|
+
entry("GC", :total_time, "3.1", receiver_type: :constant),
|
|
128
|
+
entry("GC::Profiler", :raw_data, "2.0", receiver_type: :constant),
|
|
129
|
+
entry("Hash", :compact, "2.4"),
|
|
130
|
+
entry("Hash", :compact!, "2.4"),
|
|
131
|
+
entry("Hash", :dig, "2.3"),
|
|
132
|
+
entry("Hash", :except, "3.0"),
|
|
133
|
+
entry("Hash", :fetch_values, "2.3"),
|
|
134
|
+
entry("Hash", :filter, "2.6"),
|
|
135
|
+
entry("Hash", :filter!, "2.6"),
|
|
136
|
+
entry("Hash", :slice, "2.5"),
|
|
137
|
+
entry("Hash", :to_h, "2.0"),
|
|
138
|
+
entry("Hash", :to_proc, "2.3"),
|
|
139
|
+
entry("Hash", :transform_keys, "2.5"),
|
|
140
|
+
entry("Hash", :transform_keys!, "2.5"),
|
|
141
|
+
entry("Hash", :transform_values, "2.4"),
|
|
142
|
+
entry("Hash", :transform_values!, "2.4"),
|
|
143
|
+
entry("IO", :path, "3.2"),
|
|
144
|
+
entry("IO", :cooked, "2.0"),
|
|
145
|
+
entry("IO", :cooked!, "2.0"),
|
|
146
|
+
entry("IO", :pathconf, "2.2"),
|
|
147
|
+
entry("IO", :pread, "2.5"),
|
|
148
|
+
entry("IO", :pwrite, "2.5"),
|
|
149
|
+
entry("IO", :set_encoding_by_bom, "2.7"),
|
|
150
|
+
entry("IO", :timeout, "3.2"),
|
|
151
|
+
entry("IO", :"timeout=", "3.2"),
|
|
152
|
+
entry("IO", :wait_readable, "2.0"),
|
|
153
|
+
entry("IO", :wait_writable, "2.0"),
|
|
154
|
+
entry("Integer", :allbits?, "2.5"),
|
|
155
|
+
entry("Integer", :anybits?, "2.5"),
|
|
156
|
+
entry("Integer", :bit_length, "2.1"),
|
|
157
|
+
entry("Integer", :ceildiv, "3.2"),
|
|
158
|
+
entry("Integer", :digits, "2.4"),
|
|
159
|
+
entry("Integer", :nobits?, "2.5"),
|
|
160
|
+
entry("Integer", :sqrt, "2.5", receiver_type: :constant),
|
|
161
|
+
entry("Integer", :try_convert, "3.1", receiver_type: :constant),
|
|
162
|
+
entry("KeyError", :key, "2.5"),
|
|
163
|
+
entry("KeyError", :receiver, "2.5"),
|
|
164
|
+
entry("Logger", :reopen, "2.3"),
|
|
165
|
+
entry("LoadError", :path, "2.0"),
|
|
166
|
+
entry("Kernel", :__dir__, "2.0"),
|
|
167
|
+
entry("Kernel", :Hash, "2.0"),
|
|
168
|
+
entry("Kernel", :caller_locations, "2.0"),
|
|
169
|
+
entry("Kernel", :itself, "2.2"),
|
|
170
|
+
entry("Kernel", :singleton_method, "2.1"),
|
|
171
|
+
entry("MatchData", :byteoffset, "3.2"),
|
|
172
|
+
entry("MatchData", :deconstruct, "3.2"),
|
|
173
|
+
entry("MatchData", :deconstruct_keys, "3.2"),
|
|
174
|
+
entry("MatchData", :match, "3.1"),
|
|
175
|
+
entry("MatchData", :match_length, "3.1"),
|
|
176
|
+
entry("MatchData", :named_captures, "2.4"),
|
|
177
|
+
entry("Matrix", :[]=, "2.6"),
|
|
178
|
+
entry("Matrix", :adjugate, "2.2"),
|
|
179
|
+
entry("Matrix", :antisymmetric?, "2.6"),
|
|
180
|
+
entry("Matrix", :cofactor, "2.2"),
|
|
181
|
+
entry("Matrix", :first_minor, "2.2"),
|
|
182
|
+
entry("Matrix", :hstack, "2.2"),
|
|
183
|
+
entry("Matrix", :independent?, "2.2"),
|
|
184
|
+
entry("Matrix", :laplace_expansion, "2.2"),
|
|
185
|
+
entry("Matrix", :map!, "2.6"),
|
|
186
|
+
entry("Matrix", :collect!, "2.6"),
|
|
187
|
+
entry("Matrix", :skew_symmetric?, "2.6"),
|
|
188
|
+
entry("Matrix", :vstack, "2.2"),
|
|
189
|
+
entry("Matrix", :hstack, "2.2", receiver_type: :constant),
|
|
190
|
+
entry("Matrix", :independent?, "2.2", receiver_type: :constant),
|
|
191
|
+
entry("Matrix", :vstack, "2.2", receiver_type: :constant),
|
|
192
|
+
entry("Method", :===, "2.5"),
|
|
193
|
+
entry("Method", :<<, "2.6"),
|
|
194
|
+
entry("Method", :curry, "2.2"),
|
|
195
|
+
entry("Method", :private?, "3.1"),
|
|
196
|
+
entry("Method", :protected?, "3.1"),
|
|
197
|
+
entry("Method", :public?, "3.1"),
|
|
198
|
+
entry("Method", :super_method, "2.2"),
|
|
199
|
+
entry("Method", :>>, "2.6"),
|
|
200
|
+
entry("Module", :const_added, "3.2"),
|
|
201
|
+
entry("Module", :const_source_location, "2.7"),
|
|
202
|
+
entry("Module", :deprecate_constant, "2.3"),
|
|
203
|
+
entry("Module", :prepend, "2.0"),
|
|
204
|
+
entry("Module", :prepend_features, "2.0"),
|
|
205
|
+
entry("Module", :prepended, "2.0"),
|
|
206
|
+
entry("Module", :refine, "2.0"),
|
|
207
|
+
entry("Module", :refinements, "3.2"),
|
|
208
|
+
entry("Module", :ruby2_keywords, "2.7"),
|
|
209
|
+
entry("Module", :set_temporary_name, "3.3"),
|
|
210
|
+
entry("Module", :singleton_class?, "2.1"),
|
|
211
|
+
entry("Module", :undefined_instance_methods, "3.2"),
|
|
212
|
+
entry("Module", :using, "2.1"),
|
|
213
|
+
entry("Module", :used_modules, "2.4"),
|
|
214
|
+
entry("Module", :used_refinements, "3.2", receiver_type: :constant),
|
|
215
|
+
entry("Mutex", :owned?, "2.0"),
|
|
216
|
+
entry("NameError", :receiver, "2.3"),
|
|
217
|
+
entry("Net::FTP", :features, "2.7"),
|
|
218
|
+
entry("Net::FTP", :mlsd, "2.3"),
|
|
219
|
+
entry("Net::FTP", :mlst, "2.3"),
|
|
220
|
+
entry("Net::FTP", :option, "2.7"),
|
|
221
|
+
entry("Net::HTTP", :local_host, "2.0"),
|
|
222
|
+
entry("Net::HTTP", :local_port, "2.0"),
|
|
223
|
+
entry("Net::HTTP", :post, "2.4", receiver_type: :constant),
|
|
224
|
+
entry("Net::HTTP", :verify_hostname, "3.0"),
|
|
225
|
+
entry("Net::HTTP", :"verify_hostname=", "3.0"),
|
|
226
|
+
entry("Net::IMAP", :default_port, "2.0", receiver_type: :constant),
|
|
227
|
+
entry("Net::IMAP", :default_imap_port, "2.0", receiver_type: :constant),
|
|
228
|
+
entry("Net::IMAP", :default_tls_port, "2.0", receiver_type: :constant),
|
|
229
|
+
entry("Net::IMAP", :default_ssl_port, "2.0", receiver_type: :constant),
|
|
230
|
+
entry("Net::IMAP", :default_imaps_port, "2.0", receiver_type: :constant),
|
|
231
|
+
entry("Net::SMTP", :rset, "2.1"),
|
|
232
|
+
entry("NilClass", :to_h, "2.0"),
|
|
233
|
+
entry("Numeric", :finite?, "2.4"),
|
|
234
|
+
entry("Numeric", :infinite?, "2.4"),
|
|
235
|
+
entry("Numeric", :negative?, "2.3"),
|
|
236
|
+
entry("Numeric", :positive?, "2.3"),
|
|
237
|
+
entry("Object", :then, "2.6"),
|
|
238
|
+
entry("Object", :yield_self, "2.5"),
|
|
239
|
+
entry("ObjectSpace", :reachable_objects_from, "2.0", receiver_type: :constant),
|
|
240
|
+
entry("ObjectSpace::WeakMap", :delete, "3.3"),
|
|
241
|
+
entry("OpenStruct", :[], "2.0"),
|
|
242
|
+
entry("OpenStruct", :[]=, "2.0"),
|
|
243
|
+
entry("OpenStruct", :each_pair, "2.0"),
|
|
244
|
+
entry("OpenStruct", :eql?, "2.0"),
|
|
245
|
+
entry("OpenStruct", :hash, "2.0"),
|
|
246
|
+
entry("OpenStruct", :to_h, "2.0"),
|
|
247
|
+
entry("Pathname", :empty?, "2.4"),
|
|
248
|
+
entry("Pathname", :birthtime, "2.2"),
|
|
249
|
+
entry("Pathname", :binwrite, "2.1"),
|
|
250
|
+
entry("Pathname", :lutime, "3.2"),
|
|
251
|
+
entry("Pathname", :write, "2.1"),
|
|
252
|
+
entry("Process", :argv0, "2.1", receiver_type: :constant),
|
|
253
|
+
entry("Process", :clock_getres, "2.1", receiver_type: :constant),
|
|
254
|
+
entry("Process", :clock_gettime, "2.1", receiver_type: :constant),
|
|
255
|
+
entry("Process", :getsid, "2.0", receiver_type: :constant),
|
|
256
|
+
entry("Process", :last_status, "2.5", receiver_type: :constant),
|
|
257
|
+
entry("Process", :setproctitle, "2.1", receiver_type: :constant),
|
|
258
|
+
entry("Process", :warmup, "3.3", receiver_type: :constant),
|
|
259
|
+
entry("Random", :bytes, "2.6", receiver_type: :constant),
|
|
260
|
+
entry("Readline", :quoting_detection_proc, "2.4", receiver_type: :constant),
|
|
261
|
+
entry("Readline", :quoting_detection_proc=, "2.4", receiver_type: :constant),
|
|
262
|
+
entry("Resolv::DNS", :timeouts=, "2.0"),
|
|
263
|
+
entry("Ripper", :state, "2.5"),
|
|
264
|
+
entry("Proc", :<<, "2.6"),
|
|
265
|
+
entry("Proc", :>>, "2.6"),
|
|
266
|
+
entry("Proc", :ruby2_keywords, "2.7"),
|
|
267
|
+
entry("Range", :bsearch, "2.0"),
|
|
268
|
+
entry("Range", :%, "2.6"),
|
|
269
|
+
entry("Range", :minmax, "2.7"),
|
|
270
|
+
entry("Range", :overlap?, "3.3"),
|
|
271
|
+
entry("Range", :size, "2.0"),
|
|
272
|
+
entry("Regexp", :linear_time?, "3.2", receiver_type: :constant),
|
|
273
|
+
entry("Regexp", :match?, "2.4"),
|
|
274
|
+
entry("Regexp", :timeout, "3.2", receiver_type: :constant),
|
|
275
|
+
entry("Regexp", :"timeout=", "3.2", receiver_type: :constant),
|
|
276
|
+
entry("Refinement", :refined_class, "3.2"),
|
|
277
|
+
entry("Refinement", :target, "3.3"),
|
|
278
|
+
entry("Signal", :signame, "2.0", receiver_type: :constant),
|
|
279
|
+
entry("Set", :<=>, "3.0"),
|
|
280
|
+
entry("Set", :compare_by_identity, "2.4"),
|
|
281
|
+
entry("Set", :compare_by_identity?, "2.4"),
|
|
282
|
+
entry("Set", :join, "3.0"),
|
|
283
|
+
entry("Set", :===, "2.5"),
|
|
284
|
+
entry("Set", :reset, "2.5"),
|
|
285
|
+
entry("Set", :to_s, "2.5"),
|
|
286
|
+
entry("SecureRandom", :alphanumeric, "2.5", receiver_type: :constant),
|
|
287
|
+
entry("String", :+@, "2.3"),
|
|
288
|
+
entry("String", :-@, "2.3"),
|
|
289
|
+
entry("String", :b, "2.0"),
|
|
290
|
+
entry("String", :byteindex, "3.2"),
|
|
291
|
+
entry("String", :byterindex, "3.2"),
|
|
292
|
+
entry("String", :bytesplice, "3.2"),
|
|
293
|
+
entry("String", :append_as_bytes, "3.4"),
|
|
294
|
+
entry("String", :casecmp?, "2.4"),
|
|
295
|
+
entry("String", :concat, "2.4"),
|
|
296
|
+
entry("String", :delete_prefix, "2.5"),
|
|
297
|
+
entry("String", :delete_prefix!, "2.5"),
|
|
298
|
+
entry("String", :delete_suffix, "2.5"),
|
|
299
|
+
entry("String", :delete_suffix!, "2.5"),
|
|
300
|
+
entry("String", :dedup, "3.2"),
|
|
301
|
+
entry("String", :each_grapheme_cluster, "2.5"),
|
|
302
|
+
entry("String", :grapheme_clusters, "2.5"),
|
|
303
|
+
entry("String", :match?, "2.4"),
|
|
304
|
+
entry("String", :prepend, "2.4"),
|
|
305
|
+
entry("String", :scrub, "2.1"),
|
|
306
|
+
entry("String", :scrub!, "2.1"),
|
|
307
|
+
entry("String", :unicode_normalize, "2.2"),
|
|
308
|
+
entry("String", :unicode_normalize!, "2.2"),
|
|
309
|
+
entry("String", :unicode_normalized?, "2.2"),
|
|
310
|
+
entry("String", :undump, "2.5"),
|
|
311
|
+
entry("String", :unpack1, "2.4"),
|
|
312
|
+
entry("Struct", :dig, "2.3"),
|
|
313
|
+
entry("Struct", :to_h, "2.0"),
|
|
314
|
+
entry("StringScanner", :captures, "2.5"),
|
|
315
|
+
entry("StringScanner", :size, "2.5"),
|
|
316
|
+
entry("StringScanner", :values_at, "2.5"),
|
|
317
|
+
entry("Symbol", :casecmp?, "2.4"),
|
|
318
|
+
entry("Symbol", :match, "2.4"),
|
|
319
|
+
entry("Symbol", :match?, "2.4"),
|
|
320
|
+
entry("Symbol", :name, "3.0"),
|
|
321
|
+
entry("Symbol", :start_with?, "2.7"),
|
|
322
|
+
entry("Symbol", :end_with?, "2.7"),
|
|
323
|
+
entry("Thread", :backtrace_locations, "2.0"),
|
|
324
|
+
entry("Thread", :each_caller_location, "3.2", receiver_type: :constant),
|
|
325
|
+
entry("Thread", :fetch, "2.5"),
|
|
326
|
+
entry("Thread", :ignore_deadlock, "3.0", receiver_type: :constant),
|
|
327
|
+
entry("Thread", :name, "2.3"),
|
|
328
|
+
entry("Thread", :"name=", "2.3"),
|
|
329
|
+
entry("Thread", :native_thread_id, "3.1"),
|
|
330
|
+
entry("Thread", :pending_interrupt?, "2.0"),
|
|
331
|
+
entry("Thread", :pending_interrupt?, "2.0", receiver_type: :constant),
|
|
332
|
+
entry("Thread", :report_on_exception, "2.4"),
|
|
333
|
+
entry("Thread", :"report_on_exception=", "2.4"),
|
|
334
|
+
entry("Thread", :report_on_exception, "2.4", receiver_type: :constant),
|
|
335
|
+
entry("Thread", :"report_on_exception=", "2.4", receiver_type: :constant),
|
|
336
|
+
entry("Thread", :thread_variable?, "2.0"),
|
|
337
|
+
entry("Thread", :thread_variable_get, "2.0"),
|
|
338
|
+
entry("Thread", :thread_variable_set, "2.0"),
|
|
339
|
+
entry("Thread", :thread_variables, "2.0"),
|
|
340
|
+
entry("Thread", :handle_interrupt, "2.0", receiver_type: :constant),
|
|
341
|
+
entry("Thread::Backtrace", :limit, "3.1", receiver_type: :constant),
|
|
342
|
+
entry("Socket::ResolutionError", :error_code, "3.4"),
|
|
343
|
+
entry("Time", :deconstruct_keys, "3.2"),
|
|
344
|
+
entry("Time", :ceil, "2.7"),
|
|
345
|
+
entry("Time", :floor, "2.7"),
|
|
346
|
+
entry("UnboundMethod", :private?, "3.1"),
|
|
347
|
+
entry("UnboundMethod", :protected?, "3.1"),
|
|
348
|
+
entry("UnboundMethod", :public?, "3.1"),
|
|
349
|
+
entry("UnboundMethod", :bind_call, "2.7"),
|
|
350
|
+
entry("Vector", :[]=, "2.6"),
|
|
351
|
+
entry("Vector", :angle_with, "2.2"),
|
|
352
|
+
entry("Vector", :collect!, "2.6"),
|
|
353
|
+
entry("Vector", :cross, "2.2"),
|
|
354
|
+
entry("Vector", :cross_product, "2.1"),
|
|
355
|
+
entry("Vector", :dot, "2.2"),
|
|
356
|
+
entry("Vector", :map!, "2.6"),
|
|
357
|
+
entry("Vector", :round, "2.3"),
|
|
358
|
+
entry("Vector", :basis, "2.2", receiver_type: :constant),
|
|
359
|
+
entry("Warning", :[], "2.7", receiver_type: :constant),
|
|
360
|
+
entry("Warning", :[]=, "2.7", receiver_type: :constant),
|
|
361
|
+
entry("Warning", :categories, "3.4", receiver_type: :constant),
|
|
362
|
+
entry("SyntaxError", :path, "3.2"),
|
|
363
|
+
entry("TracePoint", :allow_reentry, "3.1", receiver_type: :constant),
|
|
364
|
+
entry("TracePoint", :eval_script, "2.6"),
|
|
365
|
+
entry("TracePoint", :instruction_sequence, "2.6"),
|
|
366
|
+
entry("TracePoint", :parameters, "2.6"),
|
|
367
|
+
entry("Thread::Queue", :close, "2.3"),
|
|
368
|
+
entry("Data", :define, "3.2", receiver_type: :constant),
|
|
369
|
+
entry("Zlib", :gzip, "2.4", receiver_type: :constant),
|
|
370
|
+
entry("Zlib", :gunzip, "2.4", receiver_type: :constant)
|
|
371
|
+
].freeze
|
|
372
|
+
|
|
373
|
+
BY_METHOD = ENTRIES.group_by(&:method_name).transform_values(&:freeze).freeze
|
|
374
|
+
|
|
375
|
+
module_function
|
|
376
|
+
|
|
377
|
+
def lookup(method_name)
|
|
378
|
+
BY_METHOD[method_name]
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rubocop"
|
|
4
|
+
require "rubocop/lts/ruby/catalog"
|
|
5
|
+
|
|
6
|
+
module RuboCop
|
|
7
|
+
module Cop
|
|
8
|
+
module Lint
|
|
9
|
+
module LtsRuby
|
|
10
|
+
# Reports known Ruby APIs that were introduced after the configured target.
|
|
11
|
+
#
|
|
12
|
+
# RuboCop's TargetRubyVersion handles syntax and version-aware style rules,
|
|
13
|
+
# but it does not provide a complete runtime API compatibility database.
|
|
14
|
+
# This cop fills that gap for explicit receiver calls in the catalog.
|
|
15
|
+
class UnavailableMethod < Base
|
|
16
|
+
MSG = "%<owner>s#%<method>s is unavailable before Ruby %<version>s."
|
|
17
|
+
|
|
18
|
+
RESTRICT_ON_SEND = RuboCop::Lts::Ruby::Catalog::BY_METHOD.keys.freeze
|
|
19
|
+
|
|
20
|
+
def on_send(node)
|
|
21
|
+
return unless node.receiver
|
|
22
|
+
|
|
23
|
+
entries = RuboCop::Lts::Ruby::Catalog.lookup(node.method_name)
|
|
24
|
+
return unless entries
|
|
25
|
+
|
|
26
|
+
applicable_entries = entries.select { |entry| entry_applies?(node, entry) }
|
|
27
|
+
applicable_entries.group_by(&:introduced_in).each_value do |same_version_entries|
|
|
28
|
+
report_unavailable(node, same_version_entries)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def target_ruby_version
|
|
35
|
+
@target_ruby_version ||= Gem::Version.new(super.to_s)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def allowed_methods
|
|
39
|
+
Array(cop_config.fetch("AllowedMethods", [])).map(&:to_s)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def method_keys(entries)
|
|
43
|
+
entries.map { |entry| "#{entry.owner}##{entry.method_name}" }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def entry_applies?(node, entry)
|
|
47
|
+
if entry.receiver_type == :instance
|
|
48
|
+
return false if node.receiver.const_type?
|
|
49
|
+
|
|
50
|
+
return true
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
node.receiver.const_type? && node.receiver.const_name == entry.owner
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def report_unavailable(node, entries)
|
|
57
|
+
return unless target_ruby_version < entries.first.introduced_in
|
|
58
|
+
return if method_keys(entries).any? { |key| allowed_methods.include?(key) }
|
|
59
|
+
|
|
60
|
+
add_offense(node.selector, message: offense_message(entries))
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def offense_message(entries)
|
|
64
|
+
owners = entries.map(&:owner).uniq.join("/")
|
|
65
|
+
format(MSG, owner: owners, method: entries.first.method_name, version: entries.first.introduced_in)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|