steep 0.13.0 → 0.14.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 +4 -4
- data/CHANGELOG.md +8 -0
- data/lib/steep.rb +16 -0
- data/lib/steep/ast/types/factory.rb +72 -37
- data/lib/steep/drivers/init.rb +5 -5
- data/lib/steep/drivers/langserver.rb +176 -6
- data/lib/steep/project/completion_provider.rb +302 -0
- data/lib/steep/project/file.rb +45 -35
- data/lib/steep/type_construction.rb +15 -8
- data/lib/steep/typing.rb +13 -2
- data/lib/steep/version.rb +1 -1
- data/smoke/alias/a.rb +1 -1
- data/smoke/regexp/b.rb +4 -4
- data/vendor/ruby-signature/Rakefile +5 -4
- data/vendor/ruby-signature/docs/CONTRIBUTING.md +3 -3
- data/vendor/ruby-signature/lib/ruby/signature/cli.rb +23 -2
- data/vendor/ruby-signature/lib/ruby/signature/parser.y +2 -1
- data/vendor/ruby-signature/lib/ruby/signature/prototype/rb.rb +3 -0
- data/vendor/ruby-signature/lib/ruby/signature/test/spy.rb +3 -0
- data/vendor/ruby-signature/stdlib/builtin/match_data.rbs +233 -103
- data/vendor/ruby-signature/stdlib/builtin/regexp.rbs +1024 -72
- data/vendor/ruby-signature/stdlib/builtin/string.rbs +1773 -649
- metadata +4 -3
data/lib/steep/project/file.rb
CHANGED
@@ -44,45 +44,55 @@ module Steep
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
+
def self.parse(source_code, path:, factory:)
|
48
|
+
Source.parse(source_code, path: path.to_s, factory: factory, labeling: ASTUtils::Labeling.new)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.type_check(source, subtyping:)
|
52
|
+
typing = Typing.new
|
53
|
+
|
54
|
+
if source
|
55
|
+
annotations = source.annotations(block: source.node, factory: subtyping.factory, current_module: AST::Namespace.root)
|
56
|
+
const_env = TypeInference::ConstantEnv.new(factory: subtyping.factory, context: nil)
|
57
|
+
type_env = TypeInference::TypeEnv.build(annotations: annotations,
|
58
|
+
subtyping: subtyping,
|
59
|
+
const_env: const_env,
|
60
|
+
signatures: subtyping.factory.env)
|
61
|
+
|
62
|
+
construction = TypeConstruction.new(
|
63
|
+
checker: subtyping,
|
64
|
+
annotations: annotations,
|
65
|
+
source: source,
|
66
|
+
context: TypeInference::Context.new(
|
67
|
+
block_context: nil,
|
68
|
+
module_context: TypeInference::Context::ModuleContext.new(
|
69
|
+
instance_type: nil,
|
70
|
+
module_type: nil,
|
71
|
+
implement_name: nil,
|
72
|
+
current_namespace: AST::Namespace.root,
|
73
|
+
const_env: const_env,
|
74
|
+
class_name: nil
|
75
|
+
),
|
76
|
+
method_context: nil,
|
77
|
+
break_context: nil,
|
78
|
+
self_type: AST::Builtin::Object.instance_type,
|
79
|
+
type_env: type_env
|
80
|
+
),
|
81
|
+
typing: typing
|
82
|
+
)
|
83
|
+
|
84
|
+
construction.synthesize(source.node)
|
85
|
+
end
|
86
|
+
|
87
|
+
typing
|
88
|
+
end
|
89
|
+
|
47
90
|
def type_check(subtyping, env_updated_at)
|
48
91
|
# skip type check
|
49
92
|
return false if status.is_a?(TypeCheckStatus) && env_updated_at <= status.timestamp
|
50
93
|
|
51
94
|
parse(subtyping.factory) do |source|
|
52
|
-
typing =
|
53
|
-
|
54
|
-
if source
|
55
|
-
annotations = source.annotations(block: source.node, factory: subtyping.factory, current_module: AST::Namespace.root)
|
56
|
-
const_env = TypeInference::ConstantEnv.new(factory: subtyping.factory, context: nil)
|
57
|
-
type_env = TypeInference::TypeEnv.build(annotations: annotations,
|
58
|
-
subtyping: subtyping,
|
59
|
-
const_env: const_env,
|
60
|
-
signatures: subtyping.factory.env)
|
61
|
-
|
62
|
-
construction = TypeConstruction.new(
|
63
|
-
checker: subtyping,
|
64
|
-
annotations: annotations,
|
65
|
-
source: source,
|
66
|
-
context: TypeInference::Context.new(
|
67
|
-
block_context: nil,
|
68
|
-
module_context: TypeInference::Context::ModuleContext.new(
|
69
|
-
instance_type: nil,
|
70
|
-
module_type: nil,
|
71
|
-
implement_name: nil,
|
72
|
-
current_namespace: AST::Namespace.root,
|
73
|
-
const_env: const_env,
|
74
|
-
class_name: nil
|
75
|
-
),
|
76
|
-
method_context: nil,
|
77
|
-
break_context: nil,
|
78
|
-
self_type: AST::Builtin::Object.instance_type,
|
79
|
-
type_env: type_env
|
80
|
-
),
|
81
|
-
typing: typing
|
82
|
-
)
|
83
|
-
|
84
|
-
construction.synthesize(source.node)
|
85
|
-
end
|
95
|
+
typing = self.class.type_check(source, subtyping: subtyping)
|
86
96
|
|
87
97
|
@status = TypeCheckStatus.new(
|
88
98
|
typing: typing,
|
@@ -100,7 +110,7 @@ module Steep
|
|
100
110
|
if status.is_a?(TypeCheckStatus)
|
101
111
|
yield status.source
|
102
112
|
else
|
103
|
-
yield
|
113
|
+
yield self.class.parse(content, path: path, factory: factory)
|
104
114
|
end
|
105
115
|
rescue AnnotationParser::SyntaxError => exn
|
106
116
|
Steep.logger.warn { "Annotation syntax error on #{path}: #{exn.inspect}" }
|
@@ -708,8 +708,15 @@ module Steep
|
|
708
708
|
when :return
|
709
709
|
yield_self do
|
710
710
|
if node.children.size > 0
|
711
|
+
method_return_type = expand_alias(method_context&.return_type)
|
712
|
+
|
711
713
|
return_types = node.children.map do |value|
|
712
|
-
synthesize(value
|
714
|
+
synthesize(value,
|
715
|
+
hint: if method_return_type.is_a?(AST::Types::Void)
|
716
|
+
nil
|
717
|
+
else
|
718
|
+
method_return_type
|
719
|
+
end)
|
713
720
|
end
|
714
721
|
|
715
722
|
value_type = if return_types.size == 1
|
@@ -718,9 +725,9 @@ module Steep
|
|
718
725
|
AST::Builtin::Array.instance_type(union_type(*return_types))
|
719
726
|
end
|
720
727
|
|
721
|
-
if
|
722
|
-
unless
|
723
|
-
result = check_relation(sub_type: value_type, super_type:
|
728
|
+
if method_return_type
|
729
|
+
unless method_return_type.is_a?(AST::Types::Void)
|
730
|
+
result = check_relation(sub_type: value_type, super_type: method_return_type)
|
724
731
|
|
725
732
|
if result.failure?
|
726
733
|
typing.add_error(Errors::ReturnTypeMismatch.new(node: node,
|
@@ -941,9 +948,9 @@ module Steep
|
|
941
948
|
if constructor.module_context&.implement_name && !namespace_module?(node)
|
942
949
|
constructor.validate_method_definitions(node, constructor.module_context.implement_name)
|
943
950
|
end
|
944
|
-
end
|
945
951
|
|
946
|
-
|
952
|
+
typing.add_typing(node, AST::Builtin.nil_type, constructor.context)
|
953
|
+
end
|
947
954
|
end
|
948
955
|
|
949
956
|
when :module
|
@@ -954,9 +961,9 @@ module Steep
|
|
954
961
|
if constructor.module_context&.implement_name && !namespace_module?(node)
|
955
962
|
constructor.validate_method_definitions(node, constructor.module_context.implement_name)
|
956
963
|
end
|
957
|
-
end
|
958
964
|
|
959
|
-
|
965
|
+
typing.add_typing(node, AST::Builtin.nil_type, constructor.context)
|
966
|
+
end
|
960
967
|
end
|
961
968
|
|
962
969
|
when :self
|
data/lib/steep/typing.rb
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
module Steep
|
2
2
|
class Typing
|
3
|
+
class UnknownNodeError < StandardError
|
4
|
+
attr_reader :op
|
5
|
+
attr_reader :node
|
6
|
+
|
7
|
+
def initialize(op, node:)
|
8
|
+
@op = op
|
9
|
+
@node = node
|
10
|
+
super "Unknown node for #{op}: #{node.inspect}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
3
14
|
attr_reader :errors
|
4
15
|
attr_reader :typing
|
5
16
|
attr_reader :parent
|
@@ -48,7 +59,7 @@ module Steep
|
|
48
59
|
if parent
|
49
60
|
parent.type_of(node: node)
|
50
61
|
else
|
51
|
-
raise
|
62
|
+
raise UnknownNodeError.new(:type, node: node)
|
52
63
|
end
|
53
64
|
end
|
54
65
|
end
|
@@ -62,7 +73,7 @@ module Steep
|
|
62
73
|
if parent
|
63
74
|
parent.context_of(node: node)
|
64
75
|
else
|
65
|
-
raise
|
76
|
+
raise UnknownNodeError.new(:context, node: node)
|
66
77
|
end
|
67
78
|
end
|
68
79
|
end
|
data/lib/steep/version.rb
CHANGED
data/smoke/alias/a.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# @type var x: foo
|
2
2
|
x = ""
|
3
3
|
|
4
|
-
# !expects ArgumentTypeMismatch: receiver=(::Integer | ::String), expected=::
|
4
|
+
# !expects ArgumentTypeMismatch: receiver=(::Integer | ::String), expected=::string, actual=::Integer
|
5
5
|
x + 123
|
6
6
|
|
7
7
|
# @type var y: bar
|
data/smoke/regexp/b.rb
CHANGED
@@ -12,11 +12,11 @@
|
|
12
12
|
match_ref_3.foo
|
13
13
|
|
14
14
|
match_ref_4 = match[0, 1]
|
15
|
-
# !expects NoMethodError: type=::Array[::String], method=foo
|
15
|
+
# !expects NoMethodError: type=::Array[(::String | nil)], method=foo
|
16
16
|
match_ref_4.foo
|
17
17
|
|
18
18
|
match_ref_5 = match[0..1]
|
19
|
-
# !expects NoMethodError: type=::Array[::String], method=foo
|
19
|
+
# !expects NoMethodError: type=::Array[(::String | nil)], method=foo
|
20
20
|
match_ref_5.foo
|
21
21
|
|
22
22
|
begin_1 = match.begin(0)
|
@@ -32,7 +32,7 @@
|
|
32
32
|
begin_3.foo
|
33
33
|
|
34
34
|
captures_1 = match.captures
|
35
|
-
# !expects NoMethodError: type=::Array[::String], method=foo
|
35
|
+
# !expects NoMethodError: type=::Array[(::String | nil)], method=foo
|
36
36
|
captures_1.foo
|
37
37
|
|
38
38
|
end_1 = match.end(0)
|
@@ -92,7 +92,7 @@
|
|
92
92
|
string_1.foo
|
93
93
|
|
94
94
|
to_a_1 = match.to_a
|
95
|
-
# !expects NoMethodError: type=::Array[::String], method=foo
|
95
|
+
# !expects NoMethodError: type=::Array[(::String | nil)], method=foo
|
96
96
|
to_a_1.foo
|
97
97
|
|
98
98
|
values_at_1 = match.values_at
|
@@ -9,16 +9,17 @@ Rake::TestTask.new(:test) do |t|
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
|
12
|
+
multitask :default => [:test, :stdlib_test, :rubocop, :validate]
|
13
13
|
|
14
|
-
task :validate do
|
14
|
+
task :validate => :parser do
|
15
15
|
sh "rbs validate"
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
|
-
|
18
|
+
FileList["test/stdlib/*_test.rb"].each do |test|
|
19
|
+
multitask test => :parser do
|
20
20
|
sh "ruby bin/test_runner.rb #{test}"
|
21
21
|
end
|
22
|
+
multitask stdlib_test: test
|
22
23
|
end
|
23
24
|
|
24
25
|
task :rubocop do
|
@@ -20,8 +20,8 @@
|
|
20
20
|
- Use `bin/annotate-with-rdoc stdlib/path/to/signature.rbs` to annotate the RBS files.
|
21
21
|
- Committing the generated annotations is recommended.
|
22
22
|
6. Fix method types and comments.
|
23
|
-
- The auto generated RDoc comments include `
|
24
|
-
- Delete the `
|
23
|
+
- The auto generated RDoc comments include `arglists` section, which we don't expect to be included the RBS files.
|
24
|
+
- Delete the `arglists` sections.
|
25
25
|
- Give methods correct types.
|
26
26
|
- Write tests, if possible. (If it is too difficult to write test, skip it.)
|
27
27
|
|
@@ -50,7 +50,7 @@ You may find the *Good for first contributor* column where you can find some cla
|
|
50
50
|
* You can use --method-owner if you want to print method of other classes too, for documentation purpose.
|
51
51
|
* `bin/annotate-with-rdoc stdlib/builtin/string.rbs`
|
52
52
|
* Write comments using RDoc.
|
53
|
-
* It contains
|
53
|
+
* It contains arglists section, but I don't think we should have it in RBS files.
|
54
54
|
* `bin/query-rdoc String#initialize`
|
55
55
|
* Print RDoc documents in the format you can copy-and-paste to RBS.
|
56
56
|
* `bin/sort stdlib/builtin/string.rbs`
|
@@ -23,7 +23,7 @@ module Ruby
|
|
23
23
|
loader.add(path: Pathname(dir))
|
24
24
|
end
|
25
25
|
|
26
|
-
loader.no_builtin!
|
26
|
+
loader.no_builtin! if no_stdlib
|
27
27
|
|
28
28
|
loader
|
29
29
|
end
|
@@ -37,7 +37,7 @@ module Ruby
|
|
37
37
|
@stderr = stderr
|
38
38
|
end
|
39
39
|
|
40
|
-
COMMANDS = [:ast, :list, :ancestors, :methods, :method, :validate, :constant, :paths, :prototype, :vendor, :version]
|
40
|
+
COMMANDS = [:ast, :list, :ancestors, :methods, :method, :validate, :constant, :paths, :prototype, :vendor, :version, :parse]
|
41
41
|
|
42
42
|
def library_parse(opts, options:)
|
43
43
|
opts.on("-r LIBRARY") do |lib|
|
@@ -523,6 +523,27 @@ module Ruby
|
|
523
523
|
end
|
524
524
|
end
|
525
525
|
|
526
|
+
def run_parse(args, options)
|
527
|
+
loader = EnvironmentLoader.new()
|
528
|
+
|
529
|
+
syntax_error = false
|
530
|
+
args.each do |path|
|
531
|
+
path = Pathname(path)
|
532
|
+
loader.each_signature(path) do |sig_path|
|
533
|
+
Parser.parse_signature(sig_path.read)
|
534
|
+
rescue Ruby::Signature::Parser::SyntaxError => ex
|
535
|
+
loc = ex.error_value.location
|
536
|
+
stdout.puts "#{sig_path}:#{loc.start_line}:#{loc.start_column}: parse error on value: (#{ex.token_str})"
|
537
|
+
syntax_error = true
|
538
|
+
rescue Ruby::Signature::Parser::SemanticsError => ex
|
539
|
+
loc = ex.location
|
540
|
+
stdout.puts "#{sig_path}:#{loc.start_line}:#{loc.start_column}: #{ex.original_message}"
|
541
|
+
syntax_error = true
|
542
|
+
end
|
543
|
+
end
|
544
|
+
exit 1 if syntax_error
|
545
|
+
end
|
546
|
+
|
526
547
|
def parse_type_name(string)
|
527
548
|
Namespace.parse(string).yield_self do |namespace|
|
528
549
|
last = namespace.path.last
|
@@ -1330,11 +1330,12 @@ class SyntaxError < StandardError
|
|
1330
1330
|
end
|
1331
1331
|
|
1332
1332
|
class SemanticsError < StandardError
|
1333
|
-
attr_reader :subject
|
1333
|
+
attr_reader :subject, :location, :original_message
|
1334
1334
|
|
1335
1335
|
def initialize(message, subject:, location:)
|
1336
1336
|
@subject = subject
|
1337
1337
|
@location = location
|
1338
|
+
@original_message = message
|
1338
1339
|
|
1339
1340
|
super "parse error on #{location}: #{message}"
|
1340
1341
|
end
|
@@ -59,6 +59,7 @@ module Ruby
|
|
59
59
|
spy = self
|
60
60
|
|
61
61
|
object.singleton_class.class_eval do
|
62
|
+
remove_method spy.method_name
|
62
63
|
define_method spy.method_name, spy.spy()
|
63
64
|
end
|
64
65
|
end
|
@@ -154,6 +155,7 @@ module Ruby
|
|
154
155
|
spy = self
|
155
156
|
|
156
157
|
mod.class_eval do
|
158
|
+
remove_method spy.method_name
|
157
159
|
define_method spy.method_name, spy.spy()
|
158
160
|
end
|
159
161
|
end
|
@@ -162,6 +164,7 @@ module Ruby
|
|
162
164
|
spy = self
|
163
165
|
|
164
166
|
mod.class_eval do
|
167
|
+
remove_method spy.method_name
|
165
168
|
define_method spy.method_name, spy.original_method
|
166
169
|
end
|
167
170
|
end
|
@@ -1,141 +1,271 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# MatchData encapsulates the result of matching a Regexp against string. It is
|
2
|
+
# returned by Regexp#match and String#match, and also stored in a global
|
3
|
+
# variable returned by Regexp.last_match.
|
4
|
+
#
|
5
|
+
# Usage:
|
6
|
+
#
|
7
|
+
# url = 'https://docs.ruby-lang.org/en/2.5.0/MatchData.html'
|
8
|
+
# m = url.match(/(\d\.?)+/) # => #<MatchData "2.5.0" 1:"0">
|
9
|
+
# m.string # => "https://docs.ruby-lang.org/en/2.5.0/MatchData.html"
|
10
|
+
# m.regexp # => /(\d\.?)+/
|
11
|
+
# # entire matched substring:
|
12
|
+
# m[0] # => "2.5.0"
|
13
|
+
#
|
14
|
+
# # Working with unnamed captures
|
15
|
+
# m = url.match(%r{([^/]+)/([^/]+)\.html$})
|
16
|
+
# m.captures # => ["2.5.0", "MatchData"]
|
17
|
+
# m[1] # => "2.5.0"
|
18
|
+
# m.values_at(1, 2) # => ["2.5.0", "MatchData"]
|
19
|
+
#
|
20
|
+
# # Working with named captures
|
21
|
+
# m = url.match(%r{(?<version>[^/]+)/(?<module>[^/]+)\.html$})
|
22
|
+
# m.captures # => ["2.5.0", "MatchData"]
|
23
|
+
# m.named_captures # => {"version"=>"2.5.0", "module"=>"MatchData"}
|
24
|
+
# m[:version] # => "2.5.0"
|
25
|
+
# m.values_at(:version, :module)
|
26
|
+
# # => ["2.5.0", "MatchData"]
|
27
|
+
# # Numerical indexes are working, too
|
28
|
+
# m[1] # => "2.5.0"
|
29
|
+
# m.values_at(1, 2) # => ["2.5.0", "MatchData"]
|
30
|
+
#
|
31
|
+
# ## Global variables equivalence
|
32
|
+
#
|
33
|
+
# Parts of last MatchData (returned by Regexp.last_match) are also aliased as
|
34
|
+
# global variables:
|
35
|
+
#
|
36
|
+
# * `$~` is Regexp.last_match;
|
37
|
+
# * `$&` is [Regexp.last_match](0);
|
38
|
+
# * `$1`, `$2`, and so on are [Regexp.last_match](i) (captures by number);
|
39
|
+
# * `$`` is Regexp.last_match`.pre_match`;
|
40
|
+
# * `$'` is Regexp.last_match`.post_match`;
|
41
|
+
# * `$+` is [Regexp.last_match](-1) (the last capture).
|
42
|
+
#
|
43
|
+
#
|
44
|
+
# See also "Special global variables" section in Regexp documentation.
|
45
|
+
#
|
46
|
+
class MatchData
|
47
|
+
public
|
3
48
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
49
|
+
# Equality---Two matchdata are equal if their target strings, patterns, and
|
50
|
+
# matched positions are identical.
|
51
|
+
#
|
52
|
+
def ==: (untyped other) -> bool
|
8
53
|
|
9
|
-
|
54
|
+
# Match Reference -- MatchData acts as an array, and may be accessed using the
|
55
|
+
# normal array indexing techniques. `mtch[0]` is equivalent to the special
|
56
|
+
# variable `$&`, and returns the entire matched string. `mtch[1]`, `mtch[2]`,
|
57
|
+
# and so on return the values of the matched backreferences (portions of the
|
58
|
+
# pattern between parentheses).
|
59
|
+
#
|
60
|
+
# m = /(.)(.)(\d+)(\d)/.match("THX1138.")
|
61
|
+
# m #=> #<MatchData "HX1138" 1:"H" 2:"X" 3:"113" 4:"8">
|
62
|
+
# m[0] #=> "HX1138"
|
63
|
+
# m[1, 2] #=> ["H", "X"]
|
64
|
+
# m[1..3] #=> ["H", "X", "113"]
|
65
|
+
# m[-3, 2] #=> ["X", "113"]
|
66
|
+
#
|
67
|
+
# m = /(?<foo>a+)b/.match("ccaaab")
|
68
|
+
# m #=> #<MatchData "aaab" foo:"aaa">
|
69
|
+
# m["foo"] #=> "aaa"
|
70
|
+
# m[:foo] #=> "aaa"
|
71
|
+
#
|
72
|
+
def []: (Integer idx) -> String?
|
73
|
+
| (Integer start, Integer length) -> ::Array[String?]
|
74
|
+
| (::Range[Integer] range) -> ::Array[String?]
|
75
|
+
| (String | Symbol name) -> String?
|
10
76
|
|
11
|
-
# Returns the
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
|
77
|
+
# Returns the offset of the start of the *n*th element of the match array in the
|
78
|
+
# string. *n* can be a string or symbol to reference a named capture.
|
79
|
+
#
|
80
|
+
# m = /(.)(.)(\d+)(\d)/.match("THX1138.")
|
81
|
+
# m.begin(0) #=> 1
|
82
|
+
# m.begin(2) #=> 2
|
83
|
+
#
|
84
|
+
# m = /(?<foo>.)(.)(?<bar>.)/.match("hoge")
|
85
|
+
# p m.begin(:foo) #=> 0
|
86
|
+
# p m.begin(:bar) #=> 2
|
87
|
+
#
|
88
|
+
def begin: (Integer | String | Symbol n_or_name) -> Integer?
|
21
89
|
|
22
|
-
|
90
|
+
# Returns the array of captures; equivalent to `mtch.to_a[1..-1]`.
|
91
|
+
#
|
92
|
+
# f1,f2,f3,f4 = /(.)(.)(\d+)(\d)/.match("THX1138.").captures
|
93
|
+
# f1 #=> "H"
|
94
|
+
# f2 #=> "X"
|
95
|
+
# f3 #=> "113"
|
96
|
+
# f4 #=> "8"
|
97
|
+
#
|
98
|
+
def captures: () -> ::Array[String?]
|
23
99
|
|
100
|
+
# Returns the offset of the character immediately following the end of the *n*th
|
101
|
+
# element of the match array in the string. *n* can be a string or symbol to
|
102
|
+
# reference a named capture.
|
103
|
+
#
|
104
|
+
# m = /(.)(.)(\d+)(\d)/.match("THX1138.")
|
105
|
+
# m.end(0) #=> 7
|
106
|
+
# m.end(2) #=> 3
|
107
|
+
#
|
108
|
+
# m = /(?<foo>.)(.)(?<bar>.)/.match("hoge")
|
109
|
+
# p m.end(:foo) #=> 1
|
110
|
+
# p m.end(:bar) #=> 3
|
111
|
+
#
|
112
|
+
def `end`: (Integer | String | Symbol n_or_name) -> Integer?
|
113
|
+
|
114
|
+
# Equality---Two matchdata are equal if their target strings, patterns, and
|
115
|
+
# matched positions are identical.
|
116
|
+
#
|
24
117
|
def eql?: (untyped other) -> bool
|
25
118
|
|
26
|
-
# Produce a hash based on the target string, regexp and matched positions
|
27
|
-
#
|
28
|
-
#
|
29
|
-
# See also Object
|
119
|
+
# Produce a hash based on the target string, regexp and matched positions of
|
120
|
+
# this matchdata.
|
121
|
+
#
|
122
|
+
# See also Object#hash.
|
123
|
+
#
|
30
124
|
def hash: () -> Integer
|
31
125
|
|
126
|
+
# Returns a printable version of *mtch*.
|
127
|
+
#
|
128
|
+
# puts /.$/.match("foo").inspect
|
129
|
+
# #=> #<MatchData "o">
|
130
|
+
#
|
131
|
+
# puts /(.)(.)(.)/.match("foo").inspect
|
132
|
+
# #=> #<MatchData "foo" 1:"f" 2:"o" 3:"o">
|
133
|
+
#
|
134
|
+
# puts /(.)(.)?(.)/.match("fo").inspect
|
135
|
+
# #=> #<MatchData "fo" 1:"f" 2:nil 3:"o">
|
136
|
+
#
|
137
|
+
# puts /(?<foo>.)(?<bar>.)(?<baz>.)/.match("hoge").inspect
|
138
|
+
# #=> #<MatchData "hog" foo:"h" bar:"o" baz:"g">
|
139
|
+
#
|
32
140
|
def inspect: () -> String
|
33
141
|
|
34
142
|
# Returns the number of elements in the match array.
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
# ```
|
143
|
+
#
|
144
|
+
# m = /(.)(.)(\d+)(\d)/.match("THX1138.")
|
145
|
+
# m.length #=> 5
|
146
|
+
# m.size #=> 5
|
147
|
+
#
|
41
148
|
def length: () -> Integer
|
42
149
|
|
43
|
-
# Returns a
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
# m.named_captures #=> {"a" => "x"}
|
61
|
-
# ```
|
150
|
+
# Returns a Hash using named capture.
|
151
|
+
#
|
152
|
+
# A key of the hash is a name of the named captures. A value of the hash is a
|
153
|
+
# string of last successful capture of corresponding group.
|
154
|
+
#
|
155
|
+
# m = /(?<a>.)(?<b>.)/.match("01")
|
156
|
+
# m.named_captures #=> {"a" => "0", "b" => "1"}
|
157
|
+
#
|
158
|
+
# m = /(?<a>.)(?<b>.)?/.match("0")
|
159
|
+
# m.named_captures #=> {"a" => "0", "b" => nil}
|
160
|
+
#
|
161
|
+
# m = /(?<a>.)(?<a>.)/.match("01")
|
162
|
+
# m.named_captures #=> {"a" => "1"}
|
163
|
+
#
|
164
|
+
# m = /(?<a>x)|(?<a>y)/.match("x")
|
165
|
+
# m.named_captures #=> {"a" => "x"}
|
166
|
+
#
|
62
167
|
def named_captures: () -> ::Hash[String, String?]
|
63
168
|
|
169
|
+
# Returns a list of names of captures as an array of strings. It is same as
|
170
|
+
# mtch.regexp.names.
|
171
|
+
#
|
172
|
+
# /(?<foo>.)(?<bar>.)(?<baz>.)/.match("hoge").names
|
173
|
+
# #=> ["foo", "bar", "baz"]
|
174
|
+
#
|
175
|
+
# m = /(?<x>.)(?<y>.)?/.match("a") #=> #<MatchData "a" x:"a" y:nil>
|
176
|
+
# m.names #=> ["x", "y"]
|
177
|
+
#
|
64
178
|
def names: () -> ::Array[String]
|
65
179
|
|
66
|
-
|
180
|
+
# Returns a two-element array containing the beginning and ending offsets of the
|
181
|
+
# *n*th match. *n* can be a string or symbol to reference a named capture.
|
182
|
+
#
|
183
|
+
# m = /(.)(.)(\d+)(\d)/.match("THX1138.")
|
184
|
+
# m.offset(0) #=> [1, 7]
|
185
|
+
# m.offset(4) #=> [6, 7]
|
186
|
+
#
|
187
|
+
# m = /(?<foo>.)(.)(?<bar>.)/.match("hoge")
|
188
|
+
# p m.offset(:foo) #=> [0, 1]
|
189
|
+
# p m.offset(:bar) #=> [2, 3]
|
190
|
+
#
|
191
|
+
def offset: (Integer | Symbol | String n_or_name) -> ([ Integer, Integer ] | [ nil, nil ])
|
67
192
|
|
68
|
-
# Returns the portion of the original string after the current match.
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
# ```
|
193
|
+
# Returns the portion of the original string after the current match. Equivalent
|
194
|
+
# to the special variable `$'`.
|
195
|
+
#
|
196
|
+
# m = /(.)(.)(\d+)(\d)/.match("THX1138: The Movie")
|
197
|
+
# m.post_match #=> ": The Movie"
|
198
|
+
#
|
75
199
|
def post_match: () -> String
|
76
200
|
|
77
201
|
# Returns the portion of the original string before the current match.
|
78
|
-
# Equivalent to the special variable
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
# ```
|
202
|
+
# Equivalent to the special variable `$``.
|
203
|
+
#
|
204
|
+
# m = /(.)(.)(\d+)(\d)/.match("THX1138.")
|
205
|
+
# m.pre_match #=> "T"
|
206
|
+
#
|
84
207
|
def pre_match: () -> String
|
85
208
|
|
86
209
|
# Returns the regexp.
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
# ```
|
210
|
+
#
|
211
|
+
# m = /a.*b/.match("abc")
|
212
|
+
# m.regexp #=> /a.*b/
|
213
|
+
#
|
92
214
|
def regexp: () -> Regexp
|
93
215
|
|
94
216
|
# Returns the number of elements in the match array.
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
98
|
-
#
|
99
|
-
#
|
100
|
-
# ```
|
217
|
+
#
|
218
|
+
# m = /(.)(.)(\d+)(\d)/.match("THX1138.")
|
219
|
+
# m.length #=> 5
|
220
|
+
# m.size #=> 5
|
221
|
+
#
|
101
222
|
def size: () -> Integer
|
102
223
|
|
103
|
-
# Returns a frozen copy of the string passed in to `match
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
# ```
|
224
|
+
# Returns a frozen copy of the string passed in to `match`.
|
225
|
+
#
|
226
|
+
# m = /(.)(.)(\d+)(\d)/.match("THX1138.")
|
227
|
+
# m.string #=> "THX1138."
|
228
|
+
#
|
109
229
|
def string: () -> String
|
110
230
|
|
111
231
|
# Returns the array of matches.
|
112
|
-
#
|
113
|
-
#
|
114
|
-
#
|
115
|
-
#
|
116
|
-
#
|
117
|
-
#
|
118
|
-
#
|
119
|
-
#
|
120
|
-
#
|
121
|
-
#
|
122
|
-
#
|
123
|
-
#
|
124
|
-
#
|
125
|
-
#
|
126
|
-
|
127
|
-
# f2 #=> "X"
|
128
|
-
# f3 #=> "113"
|
129
|
-
# ```
|
130
|
-
def to_a: () -> ::Array[String]
|
232
|
+
#
|
233
|
+
# m = /(.)(.)(\d+)(\d)/.match("THX1138.")
|
234
|
+
# m.to_a #=> ["HX1138", "H", "X", "113", "8"]
|
235
|
+
#
|
236
|
+
# Because `to_a` is called when expanding `*`*variable*, there's a useful
|
237
|
+
# assignment shortcut for extracting matched fields. This is slightly slower
|
238
|
+
# than accessing the fields directly (as an intermediate array is generated).
|
239
|
+
#
|
240
|
+
# all,f1,f2,f3 = * /(.)(.)(\d+)(\d)/.match("THX1138.")
|
241
|
+
# all #=> "HX1138"
|
242
|
+
# f1 #=> "H"
|
243
|
+
# f2 #=> "X"
|
244
|
+
# f3 #=> "113"
|
245
|
+
#
|
246
|
+
def to_a: () -> ::Array[String?]
|
131
247
|
|
132
248
|
# Returns the entire matched string.
|
133
|
-
#
|
134
|
-
#
|
135
|
-
#
|
136
|
-
#
|
137
|
-
# ```
|
249
|
+
#
|
250
|
+
# m = /(.)(.)(\d+)(\d)/.match("THX1138.")
|
251
|
+
# m.to_s #=> "HX1138"
|
252
|
+
#
|
138
253
|
def to_s: () -> String
|
139
254
|
|
140
|
-
|
255
|
+
# Uses each *index* to access the matching values, returning an array of the
|
256
|
+
# corresponding matches.
|
257
|
+
#
|
258
|
+
# m = /(.)(.)(\d+)(\d)/.match("THX1138: The Movie")
|
259
|
+
# m.to_a #=> ["HX1138", "H", "X", "113", "8"]
|
260
|
+
# m.values_at(0, 2, -2) #=> ["HX1138", "X", "113"]
|
261
|
+
#
|
262
|
+
# m = /(?<a>\d+) *(?<op>[+\-*\/]) *(?<b>\d+)/.match("1 + 2")
|
263
|
+
# m.to_a #=> ["1 + 2", "1", "+", "2"]
|
264
|
+
# m.values_at(:a, :b, :op) #=> ["1", "2", "+"]
|
265
|
+
#
|
266
|
+
def values_at: (*Integer | Symbol | String n_or_name) -> ::Array[String?]
|
267
|
+
|
268
|
+
private
|
269
|
+
|
270
|
+
def initialize_copy: (self object) -> void
|
141
271
|
end
|