steep 0.13.0 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|