ruby-lsp-i18n 0.3.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.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +13 -0
  3. data/.ruby-version +1 -0
  4. data/.vscode/settings.json +12 -0
  5. data/CHANGELOG.md +36 -0
  6. data/CODE_OF_CONDUCT.md +84 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +73 -0
  9. data/Rakefile +16 -0
  10. data/es.yml +4 -0
  11. data/example/app/example.rb +14 -0
  12. data/example/config/locales/a/es.yml +4 -0
  13. data/example/config/locales/es.yml +6 -0
  14. data/lib/ruby_lsp/ruby_lsp_i18n/addon.rb +138 -0
  15. data/lib/ruby_lsp/ruby_lsp_i18n/i18n_index.rb +130 -0
  16. data/lib/ruby_lsp/ruby_lsp_i18n/listeners/completion.rb +65 -0
  17. data/lib/ruby_lsp/ruby_lsp_i18n/listeners/inlay_hints.rb +118 -0
  18. data/lib/ruby_lsp/ruby_lsp_i18n/prefix_tree.rb +158 -0
  19. data/lib/ruby_lsp/ruby_lsp_i18n/requests/inlay_hints.rb +36 -0
  20. data/lib/ruby_lsp_i18n/version.rb +7 -0
  21. data/lib/ruby_lsp_i18n.rb +9 -0
  22. data/media/demo.gif +0 -0
  23. data/ruby-lsp-i18n.gemspec +35 -0
  24. data/sorbet/config +4 -0
  25. data/sorbet/rbi/annotations/.gitattributes +1 -0
  26. data/sorbet/rbi/annotations/minitest.rbi +119 -0
  27. data/sorbet/rbi/annotations/rainbow.rbi +269 -0
  28. data/sorbet/rbi/dsl/.gitattributes +1 -0
  29. data/sorbet/rbi/gems/.gitattributes +1 -0
  30. data/sorbet/rbi/gems/ast@2.4.2.rbi +585 -0
  31. data/sorbet/rbi/gems/bump@0.10.0.rbi +9 -0
  32. data/sorbet/rbi/gems/concurrent-ruby@1.3.4.rbi +406 -0
  33. data/sorbet/rbi/gems/erubi@1.13.0.rbi +150 -0
  34. data/sorbet/rbi/gems/i18n@1.14.5.rbi +2208 -0
  35. data/sorbet/rbi/gems/json@2.7.2.rbi +1562 -0
  36. data/sorbet/rbi/gems/language_server-protocol@3.17.0.3.rbi +14238 -0
  37. data/sorbet/rbi/gems/logger@1.7.0.rbi +963 -0
  38. data/sorbet/rbi/gems/minitest@5.25.1.rbi +1546 -0
  39. data/sorbet/rbi/gems/netrc@0.11.0.rbi +159 -0
  40. data/sorbet/rbi/gems/parallel@1.26.3.rbi +291 -0
  41. data/sorbet/rbi/gems/parser@3.3.4.2.rbi +5519 -0
  42. data/sorbet/rbi/gems/prism@1.2.0.rbi +39085 -0
  43. data/sorbet/rbi/gems/racc@1.8.1.rbi +162 -0
  44. data/sorbet/rbi/gems/rainbow@3.1.1.rbi +403 -0
  45. data/sorbet/rbi/gems/rake@13.2.1.rbi +3028 -0
  46. data/sorbet/rbi/gems/rbi@0.2.0.rbi +9 -0
  47. data/sorbet/rbi/gems/rbs@3.9.4.rbi +6976 -0
  48. data/sorbet/rbi/gems/regexp_parser@2.9.2.rbi +3772 -0
  49. data/sorbet/rbi/gems/rexml@3.3.6.rbi +4813 -0
  50. data/sorbet/rbi/gems/rubocop-ast@1.32.1.rbi +7079 -0
  51. data/sorbet/rbi/gems/rubocop-minitest@0.35.1.rbi +2613 -0
  52. data/sorbet/rbi/gems/rubocop-rake@0.6.0.rbi +329 -0
  53. data/sorbet/rbi/gems/rubocop-shopify@2.15.1.rbi +9 -0
  54. data/sorbet/rbi/gems/rubocop-sorbet@0.8.5.rbi +1665 -0
  55. data/sorbet/rbi/gems/rubocop@1.65.1.rbi +58100 -0
  56. data/sorbet/rbi/gems/ruby-lsp@0.24.1.rbi +7508 -0
  57. data/sorbet/rbi/gems/ruby-progressbar@1.13.0.rbi +1318 -0
  58. data/sorbet/rbi/gems/spoom@1.4.2.rbi +4932 -0
  59. data/sorbet/rbi/gems/strscan@3.1.0.rbi +9 -0
  60. data/sorbet/rbi/gems/tapioca@0.16.2.rbi +16 -0
  61. data/sorbet/rbi/gems/thor@1.3.2.rbi +4378 -0
  62. data/sorbet/rbi/gems/unicode-display_width@2.5.0.rbi +66 -0
  63. data/sorbet/rbi/gems/yard-sorbet@0.9.0.rbi +435 -0
  64. data/sorbet/rbi/gems/yard@0.9.36.rbi +18221 -0
  65. data/sorbet/rbi/shims/gems/fast_trie@0.5.1.rbi +18 -0
  66. data/sorbet/tapioca/config.yml +13 -0
  67. data/sorbet/tapioca/require.rb +6 -0
  68. metadata +113 -0
@@ -0,0 +1,118 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RubyLsp
5
+ module RubyLspI18n
6
+ class InlayHints
7
+ extend T::Sig
8
+ include Requests::Support::Common
9
+
10
+ sig do
11
+ params(
12
+ i18n_index: I18nIndex,
13
+ response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::InlayHint],
14
+ dispatcher: Prism::Dispatcher,
15
+ document: T.any(RubyDocument, ERBDocument),
16
+ ).void
17
+ end
18
+ def initialize(i18n_index, response_builder, dispatcher, document)
19
+ absolute_path = T.must(document.uri.path)
20
+ @absolute_path = T.let(absolute_path, String)
21
+ @path = T.let(Pathname(absolute_path).relative_path_from(Dir.pwd), Pathname)
22
+ @i18n_index = i18n_index
23
+ @response_builder = response_builder
24
+
25
+ dispatcher.register(
26
+ self,
27
+ :on_call_node_enter,
28
+ )
29
+ end
30
+
31
+ sig { params(node: Prism::CallNode).void }
32
+ def on_call_node_enter(node)
33
+ return unless node.name == :t
34
+
35
+ receiver = node.receiver
36
+ return unless receiver.is_a?(Prism::ConstantReadNode)
37
+
38
+ return unless receiver.name == :I18n
39
+
40
+ arguments = node.arguments
41
+ return unless arguments
42
+ return if arguments.arguments.empty?
43
+
44
+ return if i18n_arguments_has_scope_argument(arguments)
45
+
46
+ key_node = arguments.arguments.first
47
+ return unless key_node.is_a?(Prism::StringNode)
48
+
49
+ key = key_node.unescaped
50
+
51
+ matches = @i18n_index.find(key)
52
+
53
+ tooltip_content = <<~MARKDOWN
54
+ **Translations (es)**
55
+ #{matches.map { |match| "- [#{match.file}](#{create_file_uri(match.file)}): #{match.value}" }.join("\n")}
56
+ MARKDOWN
57
+
58
+ suggested_path = @path.to_s.gsub("app", "config/locales").gsub(@path.basename.to_s, "es.yml")
59
+ suggested_path_link = create_file_uri(suggested_path)
60
+ if matches.empty?
61
+ tooltip_content += <<~MARKDOWN
62
+ ⚠️ Translation missing\n
63
+ suggested file: [#{suggested_path}](#{suggested_path_link})
64
+ MARKDOWN
65
+ end
66
+
67
+ if matches.size > 1
68
+ tooltip_content += <<~MARKDOWN
69
+ \n ⚠️ There are more than one translation for this key
70
+ MARKDOWN
71
+ end
72
+
73
+ tooltip = Interface::MarkupContent.new(
74
+ kind: "markdown",
75
+ value: tooltip_content,
76
+ )
77
+
78
+ value = matches.first&.value || "⚠️ Translation missing"
79
+
80
+ @response_builder << Interface::InlayHint.new(
81
+ position: { line: node.location.start_line - 1, character: node.location.end_column },
82
+ label: value,
83
+ padding_left: true,
84
+ tooltip: tooltip,
85
+ )
86
+ end
87
+
88
+ private
89
+
90
+ sig { params(path: String).returns(String) }
91
+ def create_file_uri(path)
92
+ base_uri = "file://#{Dir.pwd}/"
93
+ URI.join(base_uri, path).to_s
94
+ end
95
+
96
+ sig { params(arguments: Prism::ArgumentsNode).returns(T::Boolean) }
97
+ def i18n_arguments_has_scope_argument(arguments)
98
+ arguments = arguments.arguments
99
+ return false if arguments.size <= 1
100
+
101
+ # Check if the key is scoped, and if it is, ignore it
102
+ keyword_arguments = arguments[1]
103
+ if keyword_arguments.is_a?(Prism::KeywordHashNode)
104
+ keyword_argument_nodes = keyword_arguments.elements.grep(Prism::AssocNode)
105
+ keyword_argument_nodes.each do |arg|
106
+ key = arg.key
107
+ next unless key.is_a?(Prism::SymbolNode)
108
+
109
+ if key.value == "scope"
110
+ return true
111
+ end
112
+ end
113
+ end
114
+ false
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,158 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module RubyLsp
5
+ module RubyLspI18n
6
+ # Copy from: https://github.com/Shopify/ruby-lsp/blob/main/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb
7
+ # A PrefixTree is a data structure that allows searching for partial strings fast. The tree is similar to a nested
8
+ # hash structure, where the keys are the characters of the inserted strings.
9
+ #
10
+ # ## Example
11
+ # ```ruby
12
+ # tree = PrefixTree[String].new
13
+ # # Insert entries using the same key and value
14
+ # tree.insert("bar", "bar")
15
+ # tree.insert("baz", "baz")
16
+ # # Internally, the structure is analogous to this, but using nodes:
17
+ # # {
18
+ # # "b" => {
19
+ # # "a" => {
20
+ # # "r" => "bar",
21
+ # # "z" => "baz"
22
+ # # }
23
+ # # }
24
+ # # }
25
+ # # When we search it, it finds all possible values based on partial (or complete matches):
26
+ # tree.search("") # => ["bar", "baz"]
27
+ # tree.search("b") # => ["bar", "baz"]
28
+ # tree.search("ba") # => ["bar", "baz"]
29
+ # tree.search("bar") # => ["bar"]
30
+ # ```
31
+ #
32
+ # A PrefixTree is useful for autocomplete, since we always want to find all alternatives while the developer hasn't
33
+ # finished typing yet. This PrefixTree implementation allows for string keys and any arbitrary value using the
34
+ # generic
35
+ # `Value` type.
36
+ #
37
+ # See https://en.wikipedia.org/wiki/Trie for more information
38
+ class PrefixTree
39
+ extend T::Sig
40
+ extend T::Generic
41
+
42
+ Value = type_member
43
+
44
+ sig { void }
45
+ def initialize
46
+ @root = T.let(Node.new("", ""), Node[Value])
47
+ end
48
+
49
+ # Search the PrefixTree based on a given `prefix`. If `foo` is an entry in the tree, then searching for `fo` will
50
+ # return it as a result. The result is always an array of the type of value attribute to the generic `Value` type.
51
+ # Notice that if the `Value` is an array, this method will return an array of arrays, where each entry is
52
+ # the array
53
+ # of values for a given match
54
+ sig { params(prefix: String).returns(T::Array[Value]) }
55
+ def search(prefix)
56
+ node = find_node(prefix)
57
+ return [] unless node
58
+
59
+ node.collect
60
+ end
61
+
62
+ # Inserts a `value` using the given `key`
63
+ sig { params(key: String, value: Value).void }
64
+ def insert(key, value)
65
+ node = @root
66
+
67
+ key.each_char do |char|
68
+ node = node.children[char] ||= Node.new(char, value, node)
69
+ end
70
+
71
+ # This line is to allow a value to be overridden. When we are indexing files, we want to be able to update
72
+ # entries for a given fully qualified name if we find more occurrences of it. Without being able to override,
73
+ # that would not be possible
74
+ node.value = value
75
+ node.leaf = true
76
+ end
77
+
78
+ # Deletes the entry identified by `key` from the tree. Notice that a partial match will still delete all entries
79
+ # that match it. For example, if the tree contains `foo` and we ask to delete `fo`, then `foo` will be deleted
80
+ sig { params(key: String).void }
81
+ def delete(key)
82
+ node = find_node(key)
83
+ return unless node
84
+
85
+ # Remove the node from the tree and then go up the parents to remove any of them with empty children
86
+ parent = T.let(T.must(node.parent), T.nilable(Node[Value]))
87
+
88
+ while parent
89
+ parent.children.delete(node.key)
90
+ return if parent.children.any? || parent.leaf
91
+
92
+ node = parent
93
+ parent = parent.parent
94
+ end
95
+ end
96
+
97
+ private
98
+
99
+ # Find a node that matches the given `key`
100
+ sig { params(key: String).returns(T.nilable(Node[Value])) }
101
+ def find_node(key)
102
+ node = @root
103
+
104
+ key.each_char do |char|
105
+ snode = node.children[char]
106
+ return nil unless snode
107
+
108
+ node = snode
109
+ end
110
+
111
+ node
112
+ end
113
+
114
+ class Node
115
+ extend T::Sig
116
+ extend T::Generic
117
+
118
+ Value = type_member
119
+
120
+ sig { returns(T::Hash[String, Node[Value]]) }
121
+ attr_reader :children
122
+
123
+ sig { returns(String) }
124
+ attr_reader :key
125
+
126
+ sig { returns(Value) }
127
+ attr_accessor :value
128
+
129
+ sig { returns(T::Boolean) }
130
+ attr_accessor :leaf
131
+
132
+ sig { returns(T.nilable(Node[Value])) }
133
+ attr_reader :parent
134
+
135
+ sig { params(key: String, value: Value, parent: T.nilable(Node[Value])).void }
136
+ def initialize(key, value, parent = nil)
137
+ @key = key
138
+ @value = value
139
+ @parent = parent
140
+ @children = {}
141
+ @leaf = false
142
+ end
143
+
144
+ sig { returns(T::Array[Value]) }
145
+ def collect
146
+ result = []
147
+ result << @value if @leaf
148
+
149
+ @children.each_value do |node|
150
+ result.concat(node.collect)
151
+ end
152
+
153
+ result
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,36 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ # Moneky patch overrifing the InlayHints Initializer
5
+ # to support addons for InlayHints in the ruby lsp.
6
+ module RubyLsp
7
+ module Requests
8
+ module InlayHintsPatch
9
+ extend T::Sig
10
+ extend T::Helpers
11
+
12
+ requires_ancestor { InlayHints }
13
+
14
+ sig do
15
+ params(
16
+ document: T.any(RubyDocument, ERBDocument),
17
+ hints_configuration: RequestConfig,
18
+ dispatcher: Prism::Dispatcher,
19
+ ).void
20
+ end
21
+ def initialize(document, hints_configuration, dispatcher)
22
+ super
23
+
24
+ Addon.addons.each do |addon|
25
+ next unless addon.respond_to?(:create_inlay_hints_listener)
26
+
27
+ addon.create_inlay_hints_listener(@response_builder, dispatcher, document)
28
+ end
29
+ end
30
+ end
31
+
32
+ class InlayHints
33
+ prepend InlayHintsPatch
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLsp
4
+ module RubyLspI18n
5
+ VERSION = "0.3.0"
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "ruby_lsp_i18n/version"
5
+
6
+ module RubyLsp
7
+ module RubyLspI18n
8
+ end
9
+ end
data/media/demo.gif ADDED
Binary file
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/ruby_lsp_i18n/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "ruby-lsp-i18n"
7
+ spec.version = RubyLsp::RubyLspI18n::VERSION
8
+ spec.authors = ["domingo2000"]
9
+ spec.email = ["dedwards@buk.cl"]
10
+
11
+ spec.summary = "Gives support for i18n in Ruby LSP"
12
+ spec.description = "Gives support for i18n in Ruby LSP"
13
+ spec.homepage = "https://github.com/bukhr/ruby-lsp-i18n"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = ">= 3.0.0"
16
+
17
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
18
+
19
+ spec.metadata["homepage_uri"] = spec.homepage
20
+ spec.metadata["source_code_uri"] = "https://github.com/bukhr/ruby-lsp-i18n"
21
+ spec.metadata["changelog_uri"] = "https://github.com/bukhr/ruby-lsp-i18n/blob/main/CHANGELOG.md"
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
+ spec.files = Dir.chdir(__dir__) do
26
+ %x(git ls-files -z).split("\x0").reject do |f|
27
+ (File.expand_path(f) == __FILE__) ||
28
+ f.start_with?("bin/", "test/", "spec/", "features/", ".git", ".github", "appveyor", "Gemfile")
29
+ end
30
+ end
31
+
32
+ spec.bindir = "exe"
33
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
34
+ spec.require_paths = ["lib"]
35
+ end
data/sorbet/config ADDED
@@ -0,0 +1,4 @@
1
+ --dir
2
+ .
3
+ --ignore=tmp/
4
+ --ignore=vendor/
@@ -0,0 +1 @@
1
+ **/*.rbi linguist-vendored=true
@@ -0,0 +1,119 @@
1
+ # typed: true
2
+
3
+ # DO NOT EDIT MANUALLY
4
+ # This file was pulled from a central RBI files repository.
5
+ # Please run `bin/tapioca annotations` to update it.
6
+
7
+ module Minitest::Assertions
8
+ sig { params(test: T.anything, msg: T.anything).returns(TrueClass) }
9
+ def assert(test, msg = nil); end
10
+
11
+ sig { params(obj: T.anything, msg: T.anything).returns(TrueClass) }
12
+ def assert_empty(obj, msg = nil); end
13
+
14
+ sig { params(exp: T.anything, act: T.anything, msg: T.anything).returns(TrueClass) }
15
+ def assert_equal(exp, act, msg = nil); end
16
+
17
+ sig { params(exp: T.anything, act: T.anything, delta: Numeric, msg: T.anything).returns(TrueClass) }
18
+ def assert_in_delta(exp, act, delta = T.unsafe(nil), msg = nil); end
19
+
20
+ sig { params(a: T.anything, b: T.anything, epsilon: Numeric, msg: T.anything).returns(TrueClass) }
21
+ def assert_in_epsilon(a, b, epsilon = T.unsafe(nil), msg = nil); end
22
+
23
+ sig { params(collection: T.anything, obj: T.anything, msg: T.anything).returns(TrueClass) }
24
+ def assert_includes(collection, obj, msg = nil); end
25
+
26
+ sig { params(cls: T.anything, obj: T.anything, msg: T.anything).returns(TrueClass) }
27
+ def assert_instance_of(cls, obj, msg = nil); end
28
+
29
+ sig { params(cls: T.anything, obj: T.anything, msg: T.anything).returns(TrueClass) }
30
+ def assert_kind_of(cls, obj, msg = nil); end
31
+
32
+ sig { params(matcher: T.any(String, Regexp), obj: T.anything, msg: T.anything).returns(MatchData) }
33
+ def assert_match(matcher, obj, msg = nil); end
34
+
35
+ sig { params(obj: T.anything, msg: T.anything).returns(TrueClass) }
36
+ def assert_nil(obj, msg = nil); end
37
+
38
+ sig { params(o1: T.anything, op: T.any(Symbol, String), o2: T.anything, msg: T.anything).returns(TrueClass) }
39
+ def assert_operator(o1, op, o2 = T.unsafe(nil), msg = nil); end
40
+
41
+ sig { params(stdout: T.nilable(T.any(String, Regexp)), stderr: T.nilable(T.any(String, Regexp)), block: T.proc.void).returns(T::Boolean) }
42
+ def assert_output(stdout = nil, stderr = nil, &block); end
43
+
44
+ sig { params(path: T.any(String, Pathname), msg: T.anything).returns(TrueClass) }
45
+ def assert_path_exists(path, msg = nil); end
46
+
47
+ sig { params(block: T.proc.void).returns(TrueClass) }
48
+ def assert_pattern(&block); end
49
+
50
+ sig { params(o1: T.anything, op: T.any(String, Symbol), msg: T.anything).returns(TrueClass) }
51
+ def assert_predicate(o1, op, msg = nil); end
52
+
53
+ sig { params(exp: NilClass, block: T.proc.void).returns(StandardError) }
54
+ sig { type_parameters(:T).params(exp: T.any(T::Class[T.type_parameter(:T)], Regexp, String), block: T.proc.void).returns(T.type_parameter(:T)) }
55
+ def assert_raises(*exp, &block); end
56
+
57
+ sig { params(obj: T.anything, meth: T.any(String, Symbol), msg: T.anything, include_all: T::Boolean).returns(TrueClass) }
58
+ def assert_respond_to(obj, meth, msg = nil, include_all: false); end
59
+
60
+ sig { params(exp: T.anything, act: T.anything, msg: T.anything).returns(TrueClass) }
61
+ def assert_same(exp, act, msg = nil); end
62
+
63
+ sig { params(send_ary: T::Array[T.anything], m: T.anything).returns(T::Boolean) }
64
+ def assert_send(send_ary, m = nil); end
65
+
66
+ sig { params(block: T.proc.void).returns(T::Boolean) }
67
+ def assert_silent(&block); end
68
+
69
+ sig { params(sym: Symbol, msg: T.anything, block: T.proc.void).returns(T.anything) }
70
+ def assert_throws(sym, msg = nil, &block); end
71
+
72
+ sig { params(test: T.anything, msg: T.anything).returns(TrueClass) }
73
+ def refute(test, msg = nil); end
74
+
75
+ sig { params(obj: T.anything, msg: T.anything).returns(TrueClass) }
76
+ def refute_empty(obj, msg = nil); end
77
+
78
+ sig { params(exp: T.anything, act: T.anything, msg: T.anything).returns(TrueClass) }
79
+ def refute_equal(exp, act, msg = nil); end
80
+
81
+ sig { params(exp: T.anything, act: T.anything, delta: Numeric, msg: T.anything).returns(TrueClass) }
82
+ def refute_in_delta(exp, act, delta = T.unsafe(nil), msg = nil); end
83
+
84
+ sig { params(a: T.anything, b: T.anything, epsilon: Numeric, msg: T.anything).returns(TrueClass) }
85
+ def refute_in_epsilon(a, b, epsilon = T.unsafe(nil), msg = nil); end
86
+
87
+ sig { params(collection: T.anything, obj: T.anything, msg: T.anything).returns(TrueClass) }
88
+ def refute_includes(collection, obj, msg = nil); end
89
+
90
+ sig { params(cls: T.anything, obj: T.anything, msg: T.anything).returns(TrueClass) }
91
+ def refute_instance_of(cls, obj, msg = nil); end
92
+
93
+ sig { params(cls: T.anything, obj: T.anything, msg: T.anything).returns(TrueClass) }
94
+ def refute_kind_of(cls, obj, msg = nil); end
95
+
96
+ sig { params(matcher: T.any(String, Regexp), obj: T.anything, msg: T.anything).returns(TrueClass) }
97
+ def refute_match(matcher, obj, msg = nil); end
98
+
99
+ sig { params(obj: T.anything, msg: T.anything).returns(TrueClass) }
100
+ def refute_nil(obj, msg = nil); end
101
+
102
+ sig { params(block: T.proc.void).returns(TrueClass) }
103
+ def refute_pattern(&block); end
104
+
105
+ sig { params(o1: T.anything, op: T.any(Symbol, String), o2: T.anything, msg: T.anything).returns(TrueClass) }
106
+ def refute_operator(o1, op, o2 = T.unsafe(nil), msg = nil); end
107
+
108
+ sig { params(path: T.any(String, Pathname), msg: T.anything).returns(TrueClass) }
109
+ def refute_path_exists(path, msg = nil); end
110
+
111
+ sig { params(o1: T.anything, op: T.any(String, Symbol), msg: T.anything).returns(TrueClass) }
112
+ def refute_predicate(o1, op, msg = nil); end
113
+
114
+ sig { params(obj: T.anything, meth: T.any(String, Symbol), msg: T.anything, include_all: T::Boolean).returns(TrueClass) }
115
+ def refute_respond_to(obj, meth, msg = nil, include_all: false); end
116
+
117
+ sig { params(exp: T.anything, act: T.anything, msg: T.anything).returns(TrueClass) }
118
+ def refute_same(exp, act, msg = nil); end
119
+ end