yard 0.9.28 → 0.9.43
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 +139 -1
- data/LEGAL +29 -1
- data/README.md +29 -25
- data/docs/GettingStarted.md +41 -15
- data/docs/Parser.md +17 -42
- data/docs/Tags.md +6 -6
- data/docs/Templates.md +5 -4
- data/docs/WhatsNew.md +61 -9
- data/docs/templates/default/yard_tags/html/setup.rb +1 -1
- data/lib/yard/autoload.rb +20 -1
- data/lib/yard/cli/command.rb +1 -1
- data/lib/yard/cli/diff.rb +7 -2
- data/lib/yard/cli/yardoc.rb +1 -1
- data/lib/yard/code_objects/base.rb +6 -2
- data/lib/yard/code_objects/extra_file_object.rb +1 -0
- data/lib/yard/code_objects/macro_object.rb +0 -1
- data/lib/yard/code_objects/proxy.rb +1 -1
- data/lib/yard/docstring_parser.rb +1 -2
- data/lib/yard/handlers/base.rb +23 -1
- data/lib/yard/handlers/processor.rb +1 -1
- data/lib/yard/handlers/rbs/attribute_handler.rb +79 -0
- data/lib/yard/handlers/rbs/base.rb +38 -0
- data/lib/yard/handlers/rbs/constant_handler.rb +18 -0
- data/lib/yard/handlers/rbs/method_handler.rb +327 -0
- data/lib/yard/handlers/rbs/mixin_handler.rb +20 -0
- data/lib/yard/handlers/rbs/namespace_handler.rb +26 -0
- data/lib/yard/handlers/ruby/attribute_handler.rb +7 -4
- data/lib/yard/handlers/ruby/constant_handler.rb +24 -6
- data/lib/yard/handlers/ruby/legacy/attribute_handler.rb +1 -1
- data/lib/yard/handlers/ruby/legacy/visibility_handler.rb +2 -1
- data/lib/yard/handlers/ruby/mixin_handler.rb +13 -6
- data/lib/yard/handlers/ruby/visibility_handler.rb +14 -1
- data/lib/yard/i18n/locale.rb +2 -2
- data/lib/yard/i18n/message.rb +2 -2
- data/lib/yard/i18n/messages.rb +1 -1
- data/lib/yard/i18n/pot_generator.rb +2 -2
- data/lib/yard/logging.rb +116 -61
- data/lib/yard/open_struct.rb +67 -0
- data/lib/yard/options.rb +1 -1
- data/lib/yard/parser/rbs/rbs_parser.rb +325 -0
- data/lib/yard/parser/rbs/statement.rb +75 -0
- data/lib/yard/parser/ruby/ast_node.rb +5 -4
- data/lib/yard/parser/ruby/legacy/irb/slex.rb +19 -1
- data/lib/yard/parser/ruby/legacy/ruby_lex.rb +20 -5
- data/lib/yard/parser/ruby/ruby_parser.rb +117 -26
- data/lib/yard/parser/source_parser.rb +7 -7
- data/lib/yard/registry_resolver.rb +9 -1
- data/lib/yard/rubygems/specification.rb +1 -1
- data/lib/yard/server/commands/base.rb +2 -2
- data/lib/yard/server/commands/library_command.rb +8 -8
- data/lib/yard/server/commands/static_file_helpers.rb +1 -2
- data/lib/yard/server/http_utils.rb +512 -0
- data/lib/yard/server/library_version.rb +1 -1
- data/lib/yard/server/rack_adapter.rb +13 -5
- data/lib/yard/server/templates/default/fulldoc/html/css/custom.css +168 -88
- data/lib/yard/server/templates/default/fulldoc/html/js/autocomplete.js +203 -12
- data/lib/yard/server/templates/default/layout/html/breadcrumb.erb +1 -17
- data/lib/yard/server/templates/default/method_details/html/permalink.erb +4 -2
- data/lib/yard/server/templates/doc_server/library_list/html/headers.erb +3 -3
- data/lib/yard/server/templates/doc_server/library_list/html/library_list.erb +2 -3
- data/lib/yard/server/templates/doc_server/processing/html/processing.erb +22 -16
- data/lib/yard/tags/default_factory.rb +1 -0
- data/lib/yard/tags/directives.rb +7 -1
- data/lib/yard/tags/library.rb +3 -3
- data/lib/yard/tags/overload_tag.rb +2 -1
- data/lib/yard/tags/tag.rb +4 -3
- data/lib/yard/tags/types_explainer.rb +6 -5
- data/lib/yard/templates/engine.rb +0 -1
- data/lib/yard/templates/helpers/base_helper.rb +1 -1
- data/lib/yard/templates/helpers/html_helper.rb +21 -6
- data/lib/yard/templates/helpers/html_syntax_highlight_helper.rb +6 -1
- data/lib/yard/templates/helpers/markup/hybrid_markdown.rb +2147 -0
- data/lib/yard/templates/helpers/markup/rdoc_markup.rb +2 -0
- data/lib/yard/templates/helpers/markup_helper.rb +4 -2
- data/lib/yard/templates/template_options.rb +0 -1
- data/lib/yard/version.rb +1 -1
- data/po/ja.po +101 -101
- data/templates/default/fulldoc/html/css/common.css +1 -1
- data/templates/default/fulldoc/html/css/full_list.css +201 -53
- data/templates/default/fulldoc/html/css/style.css +991 -399
- data/templates/default/fulldoc/html/frames.erb +9 -4
- data/templates/default/fulldoc/html/full_list.erb +8 -5
- data/templates/default/fulldoc/html/js/app.js +799 -312
- data/templates/default/fulldoc/html/js/full_list.js +332 -214
- data/templates/default/fulldoc/html/setup.rb +10 -2
- data/templates/default/layout/html/headers.erb +1 -1
- data/templates/default/layout/html/layout.erb +3 -1
- data/templates/default/method/html/header.erb +3 -3
- data/templates/default/module/html/defines.erb +3 -3
- data/templates/default/module/html/inherited_methods.erb +1 -0
- data/templates/default/module/html/method_summary.erb +8 -0
- data/templates/default/module/setup.rb +20 -0
- data/templates/default/onefile/html/headers.erb +2 -0
- data/templates/default/onefile/html/layout.erb +3 -4
- data/templates/default/tags/html/example.erb +2 -2
- data/templates/default/tags/html/option.erb +1 -1
- data/templates/guide/fulldoc/html/css/style.css +347 -97
- data/templates/guide/fulldoc/html/js/app.js +61 -33
- data/templates/guide/layout/html/layout.erb +69 -72
- metadata +21 -60
- data/.dockerignore +0 -2
- data/.gitattributes +0 -4
- data/.github/FUNDING.yml +0 -3
- data/.github/ISSUE_TEMPLATE.md +0 -33
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -12
- data/.github/workflows/ci.yml +0 -30
- data/.github/workflows/gem.yml +0 -19
- data/.gitignore +0 -14
- data/.rspec +0 -2
- data/.rubocop.yml +0 -112
- data/CODE_OF_CONDUCT.md +0 -15
- data/CONTRIBUTING.md +0 -140
- data/Dockerfile.samus +0 -28
- data/Gemfile +0 -34
- data/Rakefile +0 -36
- data/SECURITY.md +0 -26
- data/benchmarks/builtins_vs_eval.rb +0 -24
- data/benchmarks/concat_vs_join.rb +0 -13
- data/benchmarks/erb_vs_erubis.rb +0 -54
- data/benchmarks/format_args.rb +0 -47
- data/benchmarks/generation.rb +0 -38
- data/benchmarks/marshal_vs_dbm.rb +0 -64
- data/benchmarks/parsing.rb +0 -46
- data/benchmarks/pathname_vs_string.rb +0 -51
- data/benchmarks/rdoc_vs_yardoc.rb +0 -11
- data/benchmarks/registry_store_types.rb +0 -49
- data/benchmarks/ri_vs_yri.rb +0 -19
- data/benchmarks/ripper_parser.rb +0 -13
- data/benchmarks/splat_vs_flatten.rb +0 -13
- data/benchmarks/template_erb.rb +0 -23
- data/benchmarks/template_format.rb +0 -7
- data/benchmarks/template_profile.rb +0 -18
- data/benchmarks/yri_cache.rb +0 -20
- data/samus.json +0 -49
- data/tasks/prepare_tag.rake +0 -45
- data/tasks/update_error_map.rake +0 -53
- data/yard.gemspec +0 -25
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Handles RBS method definitions (def name: signature).
|
|
3
|
+
#
|
|
4
|
+
# Creates a {YARD::CodeObjects::MethodObject} for each declaration
|
|
5
|
+
# and infers @param, @return, @yield, and @yieldparam tags from the
|
|
6
|
+
# RBS type signature when those tags are absent from the docstring.
|
|
7
|
+
class YARD::Handlers::RBS::MethodHandler < YARD::Handlers::RBS::Base
|
|
8
|
+
handles :method_def
|
|
9
|
+
|
|
10
|
+
process do
|
|
11
|
+
meth_scope = statement.visibility == :class ? :class : :instance
|
|
12
|
+
obj = register MethodObject.new(namespace, statement.name, meth_scope)
|
|
13
|
+
apply_signature_tags(obj, statement.signatures)
|
|
14
|
+
|
|
15
|
+
# For initialize, ensure the return type is the class, not void.
|
|
16
|
+
if statement.name == 'initialize'
|
|
17
|
+
ret_tags = obj.tags(:return)
|
|
18
|
+
if ret_tags.none? || (ret_tags.length == 1 && ret_tags.first.types == ['void'])
|
|
19
|
+
obj.docstring.delete_tags(:return)
|
|
20
|
+
obj.add_tag YARD::Tags::Tag.new(:return, "a new instance of #{namespace.name}",
|
|
21
|
+
[namespace.name.to_s])
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Convert an RBS type string to an array of YARD type strings.
|
|
27
|
+
#
|
|
28
|
+
# @param rbs [String] e.g. "String | Integer", "Array[String]", "bool"
|
|
29
|
+
# @return [Array<String>]
|
|
30
|
+
def self.rbs_type_to_yard_types(rbs)
|
|
31
|
+
rbs = rbs.strip
|
|
32
|
+
return ['void'] if rbs == 'void'
|
|
33
|
+
return ['Boolean'] if rbs == 'bool'
|
|
34
|
+
return ['Object'] if rbs == 'untyped'
|
|
35
|
+
return ['nil'] if rbs == 'nil'
|
|
36
|
+
|
|
37
|
+
# Strip outer parentheses: `(String | Integer)` → recurse on inner.
|
|
38
|
+
if rbs.start_with?('(') && rbs.end_with?(')') && bracket_depth(rbs[1..-2]) == 0
|
|
39
|
+
return rbs_type_to_yard_types(rbs[1..-2])
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# `Type?` is shorthand for `Type | nil` when the ? is outermost.
|
|
43
|
+
if rbs =~ /\A(.+)\?\z/ && bracket_depth($1) == 0
|
|
44
|
+
return rbs_type_to_yard_types($1) + ['nil']
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
split_on_pipe(rbs).map { |t| t.strip }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
# Apply tags from all overload signatures to the method object.
|
|
53
|
+
def apply_signature_tags(obj, sigs)
|
|
54
|
+
return if sigs.nil? || sigs.empty?
|
|
55
|
+
|
|
56
|
+
if sigs.length == 1
|
|
57
|
+
# Single signature: add @param and @return directly.
|
|
58
|
+
add_param_return_tags(obj, sigs.first)
|
|
59
|
+
else
|
|
60
|
+
# Multiple signatures: add @overload tags.
|
|
61
|
+
sigs.each { |sig| add_overload_tag(obj, statement.name, sig) }
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Add @param / @return / @yield / @yieldparam from a single overload sig.
|
|
66
|
+
def add_param_return_tags(obj, sig)
|
|
67
|
+
parsed = parse_function_type(sig)
|
|
68
|
+
|
|
69
|
+
parsed[:params].each do |p|
|
|
70
|
+
next if p[:block] # block param handled via @yield below
|
|
71
|
+
tag_name = p[:name] ? p[:name].to_s : nil
|
|
72
|
+
next if tag_name && obj.tags(:param).any? { |t| t.name == tag_name }
|
|
73
|
+
obj.add_tag YARD::Tags::Tag.new(:param, '', p[:types], tag_name)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
if (blk = parsed[:block_param])
|
|
77
|
+
add_yield_tags(obj, blk)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
unless obj.has_tag?(:return)
|
|
81
|
+
obj.add_tag YARD::Tags::Tag.new(:return, '', parsed[:return_types])
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Add an @overload tag for one signature overload.
|
|
86
|
+
def add_overload_tag(obj, meth_name, sig)
|
|
87
|
+
parsed = parse_function_type(sig)
|
|
88
|
+
param_sigs = parsed[:params].reject { |p| p[:block] }.map.with_index do |p, idx|
|
|
89
|
+
p[:name] || "arg#{idx}"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Build the overload tag text: signature line + nested @param/@return lines.
|
|
93
|
+
lines = ["#{meth_name}(#{param_sigs.join(', ')})"]
|
|
94
|
+
parsed[:params].reject { |p| p[:block] }.each_with_index do |p, idx|
|
|
95
|
+
pname = p[:name] || "arg#{idx}"
|
|
96
|
+
lines << " @param #{pname} [#{p[:types].join(', ')}]"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
if (blk = parsed[:block_param])
|
|
100
|
+
add_yield_tags(obj, blk)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
lines << " @return [#{parsed[:return_types].join(', ')}]"
|
|
104
|
+
obj.add_tag YARD::Tags::OverloadTag.new(:overload, lines.join("\n"))
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Add @yield and @yieldparam tags from a parsed block type.
|
|
108
|
+
def add_yield_tags(obj, blk)
|
|
109
|
+
return if obj.has_tag?(:yield) && obj.has_tag?(:yieldparam)
|
|
110
|
+
obj.add_tag YARD::Tags::Tag.new(:yield, '') unless obj.has_tag?(:yield)
|
|
111
|
+
blk[:params].each_with_index do |p, idx|
|
|
112
|
+
pname = p[:name] || "arg#{idx}"
|
|
113
|
+
next if obj.tags(:yieldparam).any? { |t| t.name == pname }
|
|
114
|
+
obj.add_tag YARD::Tags::Tag.new(:yieldparam, '', p[:types], pname)
|
|
115
|
+
end
|
|
116
|
+
unless obj.has_tag?(:yieldreturn)
|
|
117
|
+
obj.add_tag YARD::Tags::Tag.new(:yieldreturn, '', self.class.rbs_type_to_yard_types(blk[:return_type] || 'void'))
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Parse a single RBS function type string (one overload) into its components.
|
|
122
|
+
#
|
|
123
|
+
# @param sig [String] e.g. "(String name, Integer age) -> String"
|
|
124
|
+
# @return [Hash] { :params => [...], :block_param => Hash|nil, :return_types => [...] }
|
|
125
|
+
def parse_function_type(sig)
|
|
126
|
+
sig = sig.strip
|
|
127
|
+
return { :params => [], :block_param => nil, :return_types => ['void'] } if sig.empty?
|
|
128
|
+
|
|
129
|
+
remaining = sig
|
|
130
|
+
params = []
|
|
131
|
+
block_param = nil
|
|
132
|
+
|
|
133
|
+
# 1. Extract positional/keyword params: leading `(...)`.
|
|
134
|
+
if remaining.start_with?('(')
|
|
135
|
+
close = find_matching(remaining, 0, '(', ')')
|
|
136
|
+
raise YARD::Parser::UndocumentableError, "malformed signature (unclosed '('): #{sig}" if close.nil?
|
|
137
|
+
params_str = remaining[1...close]
|
|
138
|
+
remaining = remaining[close + 1..-1].lstrip
|
|
139
|
+
params = parse_params_list(params_str)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# 2. Extract block type: `{ ... }`.
|
|
143
|
+
if remaining.start_with?('{')
|
|
144
|
+
close = find_matching(remaining, 0, '{', '}')
|
|
145
|
+
raise YARD::Parser::UndocumentableError, "malformed signature (unclosed '{'): #{sig}" if close.nil?
|
|
146
|
+
block_inner = remaining[1...close]
|
|
147
|
+
remaining = remaining[close + 1..-1].lstrip
|
|
148
|
+
block_param = parse_block_type(block_inner)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# 3. Return type after `->`.
|
|
152
|
+
return_types = if remaining =~ /\A->\s*(.*)\z/
|
|
153
|
+
self.class.rbs_type_to_yard_types($1.strip)
|
|
154
|
+
else
|
|
155
|
+
['void']
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
{ :params => params, :block_param => block_param, :return_types => return_types }
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Parse a comma-separated parameter list (content inside outer parens).
|
|
162
|
+
def parse_params_list(str)
|
|
163
|
+
str = str.strip
|
|
164
|
+
return [] if str.empty?
|
|
165
|
+
|
|
166
|
+
split_by_comma(str).map { |p| parse_single_param(p.strip) }.compact
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Parse one parameter from an RBS param list.
|
|
170
|
+
def parse_single_param(param)
|
|
171
|
+
return nil if param.empty?
|
|
172
|
+
|
|
173
|
+
optional = false
|
|
174
|
+
rest = false
|
|
175
|
+
|
|
176
|
+
# Optional marker `?`.
|
|
177
|
+
if param.start_with?('?') && !param.start_with?('?(')
|
|
178
|
+
optional = true
|
|
179
|
+
param = param[1..-1].lstrip
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Double-splat `**` (rest keyword).
|
|
183
|
+
if param.start_with?('**')
|
|
184
|
+
rest = true
|
|
185
|
+
param = param[2..-1].lstrip
|
|
186
|
+
# Single-splat `*` (rest positional).
|
|
187
|
+
elsif param.start_with?('*') && !param.start_with?('*)')
|
|
188
|
+
rest = true
|
|
189
|
+
param = param[1..-1].lstrip
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Block-type proc: `^(...)`.
|
|
193
|
+
if param.start_with?('^')
|
|
194
|
+
return { :name => nil, :types => [param], :optional => false, :rest => false, :block => true }
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Keyword parameter: `name: Type` or `?name: Type`.
|
|
198
|
+
if param =~ /\A([a-z_]\w*)\s*:\s*(.*)\z/ && !rest
|
|
199
|
+
kw_name = $1
|
|
200
|
+
kw_type = $2.strip
|
|
201
|
+
return { :name => "#{kw_name}:", :types => self.class.rbs_type_to_yard_types(kw_type),
|
|
202
|
+
:optional => optional, :rest => false }
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Positional: `Type [param_name]`.
|
|
206
|
+
type_str, param_name = extract_type_and_name(param)
|
|
207
|
+
{ :name => param_name, :types => self.class.rbs_type_to_yard_types(type_str),
|
|
208
|
+
:optional => optional, :rest => rest }
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Split a type+name string like "Array[String] names" into ["Array[String]", "names"].
|
|
212
|
+
# The name is the trailing lowercase identifier (if any).
|
|
213
|
+
def extract_type_and_name(str)
|
|
214
|
+
str = str.strip
|
|
215
|
+
if str =~ /\A(.*\S)\s+([a-z_]\w*)\z/m
|
|
216
|
+
type_part = $1.strip
|
|
217
|
+
name_part = $2
|
|
218
|
+
# Exclude RBS type keywords from being mistaken for names.
|
|
219
|
+
unless %w[void untyped nil bool top bottom self instance class].include?(name_part)
|
|
220
|
+
return [type_part, name_part] unless type_part.empty?
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
[str, nil]
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# Parse the inside of a `{ ... }` block type, e.g. "(Integer) -> String".
|
|
227
|
+
def parse_block_type(inner)
|
|
228
|
+
inner = inner.strip
|
|
229
|
+
params = []
|
|
230
|
+
ret = nil
|
|
231
|
+
|
|
232
|
+
if inner.start_with?('(')
|
|
233
|
+
close = find_matching(inner, 0, '(', ')')
|
|
234
|
+
raise YARD::Parser::UndocumentableError, "malformed block type (unclosed '('): #{inner}" if close.nil?
|
|
235
|
+
params = parse_params_list(inner[1...close])
|
|
236
|
+
rest = inner[close + 1..-1].lstrip
|
|
237
|
+
else
|
|
238
|
+
rest = inner
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
ret = $1.strip if rest =~ /\A->\s*(.*)\z/
|
|
242
|
+
{ :params => params, :return_type => ret }
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# Find the index of the matching close bracket starting from +start+.
|
|
246
|
+
# @return [nil] if no matching bracket is found (malformed input).
|
|
247
|
+
def find_matching(str, start, open, close)
|
|
248
|
+
depth = 0
|
|
249
|
+
(start...str.length).each do |i|
|
|
250
|
+
case str[i]
|
|
251
|
+
when open then depth += 1
|
|
252
|
+
when close
|
|
253
|
+
depth -= 1
|
|
254
|
+
return i if depth == 0
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
nil
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# Split +str+ on commas that are not inside brackets.
|
|
261
|
+
def split_by_comma(str)
|
|
262
|
+
depth = 0
|
|
263
|
+
parts = []
|
|
264
|
+
cur = String.new('')
|
|
265
|
+
str.each_char do |c|
|
|
266
|
+
case c
|
|
267
|
+
when '(', '[', '{'
|
|
268
|
+
depth += 1
|
|
269
|
+
cur << c
|
|
270
|
+
when ')', ']', '}'
|
|
271
|
+
depth -= 1
|
|
272
|
+
cur << c
|
|
273
|
+
when ','
|
|
274
|
+
if depth == 0
|
|
275
|
+
parts << cur.strip
|
|
276
|
+
cur = String.new('')
|
|
277
|
+
else
|
|
278
|
+
cur << c
|
|
279
|
+
end
|
|
280
|
+
else
|
|
281
|
+
cur << c
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
parts << cur.strip unless cur.strip.empty?
|
|
285
|
+
parts
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
# Split +str+ on `|` that are not inside brackets.
|
|
289
|
+
def self.split_on_pipe(str)
|
|
290
|
+
depth = 0
|
|
291
|
+
parts = []
|
|
292
|
+
cur = String.new('')
|
|
293
|
+
str.each_char do |c|
|
|
294
|
+
case c
|
|
295
|
+
when '(', '[', '{'
|
|
296
|
+
depth += 1
|
|
297
|
+
cur << c
|
|
298
|
+
when ')', ']', '}'
|
|
299
|
+
depth -= 1
|
|
300
|
+
cur << c
|
|
301
|
+
when '|'
|
|
302
|
+
if depth == 0
|
|
303
|
+
parts << cur.strip
|
|
304
|
+
cur = String.new('')
|
|
305
|
+
else
|
|
306
|
+
cur << c
|
|
307
|
+
end
|
|
308
|
+
else
|
|
309
|
+
cur << c
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
parts << cur.strip unless cur.strip.empty?
|
|
313
|
+
parts
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
# Return the bracket depth of the full string (should be 0 for well-formed types).
|
|
317
|
+
def self.bracket_depth(str)
|
|
318
|
+
depth = 0
|
|
319
|
+
str.each_char do |c|
|
|
320
|
+
case c
|
|
321
|
+
when '(', '[', '{' then depth += 1
|
|
322
|
+
when ')', ']', '}' then depth -= 1
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
depth
|
|
326
|
+
end
|
|
327
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Handles RBS include, extend, and prepend declarations.
|
|
3
|
+
class YARD::Handlers::RBS::MixinHandler < YARD::Handlers::RBS::Base
|
|
4
|
+
handles :include, :extend, :prepend
|
|
5
|
+
|
|
6
|
+
process do
|
|
7
|
+
mixin = P(namespace, statement.mixin_name)
|
|
8
|
+
case statement.type
|
|
9
|
+
when :include
|
|
10
|
+
mixins = namespace.mixins(:instance)
|
|
11
|
+
mixins << mixin unless mixins.include?(mixin)
|
|
12
|
+
when :extend
|
|
13
|
+
mixins = namespace.mixins(:class)
|
|
14
|
+
mixins << mixin unless mixins.include?(mixin)
|
|
15
|
+
when :prepend
|
|
16
|
+
mixins = namespace.mixins(:instance)
|
|
17
|
+
mixins.unshift(mixin) unless mixins.include?(mixin)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# Handles RBS class, module, and interface declarations by registering
|
|
3
|
+
# the corresponding namespace code objects and recursing into their bodies.
|
|
4
|
+
class YARD::Handlers::RBS::NamespaceHandler < YARD::Handlers::RBS::Base
|
|
5
|
+
handles :class, :module, :interface
|
|
6
|
+
namespace_only
|
|
7
|
+
|
|
8
|
+
process do
|
|
9
|
+
name = statement.name
|
|
10
|
+
type = statement.type
|
|
11
|
+
|
|
12
|
+
obj = case type
|
|
13
|
+
when :class
|
|
14
|
+
klass = register ClassObject.new(namespace, name)
|
|
15
|
+
if (sc = statement.superclass) && !sc.strip.empty?
|
|
16
|
+
klass.superclass = P(namespace, sc)
|
|
17
|
+
klass.superclass.type = :class if klass.superclass.is_a?(Proxy)
|
|
18
|
+
end
|
|
19
|
+
klass
|
|
20
|
+
when :module, :interface
|
|
21
|
+
register ModuleObject.new(namespace, name)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
parse_block(:namespace => obj)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -31,8 +31,6 @@ class YARD::Handlers::Ruby::AttributeHandler < YARD::Handlers::Ruby::Base
|
|
|
31
31
|
|
|
32
32
|
# Add all attributes
|
|
33
33
|
validated_attribute_names(params).each do |name|
|
|
34
|
-
namespace.attributes[scope][name] ||= SymbolHash[:read => nil, :write => nil]
|
|
35
|
-
|
|
36
34
|
# Show their methods as well
|
|
37
35
|
{:read => name, :write => "#{name}="}.each do |type, meth|
|
|
38
36
|
if type == :read ? read : write
|
|
@@ -52,12 +50,17 @@ class YARD::Handlers::Ruby::AttributeHandler < YARD::Handlers::Ruby::Base
|
|
|
52
50
|
register(o)
|
|
53
51
|
o.docstring = doc if o.docstring.blank?(false)
|
|
54
52
|
|
|
55
|
-
#
|
|
56
|
-
|
|
53
|
+
# Register the object explicitly.
|
|
54
|
+
# Use o.scope rather than scope: register() may have changed o.scope
|
|
55
|
+
# via a @!scope directive, so the attribute must be stored under the
|
|
56
|
+
# method's final scope to keep attr_info's lookup consistent.
|
|
57
|
+
namespace.attributes[o.scope][name] ||= SymbolHash[:read => nil, :write => nil]
|
|
58
|
+
namespace.attributes[o.scope][name][type] = o
|
|
57
59
|
else
|
|
58
60
|
obj = namespace.children.find {|other| other.name == meth.to_sym && other.scope == scope }
|
|
59
61
|
|
|
60
62
|
# register an existing method as attribute
|
|
63
|
+
namespace.attributes[scope][name] ||= SymbolHash[:read => nil, :write => nil]
|
|
61
64
|
namespace.attributes[scope][name][type] = obj if obj
|
|
62
65
|
end
|
|
63
66
|
end
|
|
@@ -9,6 +9,9 @@ class YARD::Handlers::Ruby::ConstantHandler < YARD::Handlers::Ruby::Base
|
|
|
9
9
|
if statement[1].call? && statement[1][0][0] == s(:const, "Struct") &&
|
|
10
10
|
statement[1][2] == s(:ident, "new")
|
|
11
11
|
process_structclass(statement)
|
|
12
|
+
elsif statement[1].call? && statement[1][0][0] == s(:const, "Data") &&
|
|
13
|
+
statement[1][2] == s(:ident, "define")
|
|
14
|
+
process_dataclass(statement)
|
|
12
15
|
elsif statement[0].type == :var_field && statement[0][0].type == :const
|
|
13
16
|
process_constant(statement)
|
|
14
17
|
elsif statement[0].type == :const_path_field
|
|
@@ -31,20 +34,35 @@ class YARD::Handlers::Ruby::ConstantHandler < YARD::Handlers::Ruby::Base
|
|
|
31
34
|
end
|
|
32
35
|
|
|
33
36
|
def process_structclass(statement)
|
|
34
|
-
lhs = statement[0]
|
|
35
|
-
if lhs.type == :const
|
|
36
|
-
klass = create_class(lhs
|
|
37
|
+
lhs = statement[0]
|
|
38
|
+
if (lhs.type == :var_field && lhs[0].type == :const) || lhs.type == :const_path_field
|
|
39
|
+
klass = create_class(lhs.source, P(:Struct))
|
|
37
40
|
create_attributes(klass, extract_parameters(statement[1]))
|
|
38
41
|
parse_block(statement[1].block[1], :namespace => klass) unless statement[1].block.nil?
|
|
39
42
|
else
|
|
40
|
-
raise YARD::Parser::UndocumentableError, "Struct assignment to #{
|
|
43
|
+
raise YARD::Parser::UndocumentableError, "Struct assignment to #{lhs.source}"
|
|
41
44
|
end
|
|
42
45
|
end
|
|
43
46
|
|
|
44
|
-
|
|
47
|
+
def process_dataclass(statement)
|
|
48
|
+
lhs = statement[0]
|
|
49
|
+
if (lhs.type == :var_field && lhs[0].type == :const) || lhs.type == :const_path_field
|
|
50
|
+
klass = create_class(lhs.source, P(:Data))
|
|
51
|
+
extract_parameters(statement[1]).each do |member|
|
|
52
|
+
next if klass.attributes[:instance][member]
|
|
53
|
+
klass.attributes[:instance][member] = SymbolHash[:read => nil, :write => nil]
|
|
54
|
+
create_reader(klass, member)
|
|
55
|
+
end
|
|
56
|
+
parse_block(statement[1].block[1], :namespace => klass) unless statement[1].block.nil?
|
|
57
|
+
else
|
|
58
|
+
raise YARD::Parser::UndocumentableError, "Data assignment to #{lhs.source}"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Extract the parameters from the Struct.new or Data.define AST node, returning them as a list
|
|
45
63
|
# of strings
|
|
46
64
|
#
|
|
47
|
-
# @param [MethodCallNode] superclass the AST node for the Struct.new call
|
|
65
|
+
# @param [MethodCallNode] superclass the AST node for the Struct.new or Data.define call
|
|
48
66
|
# @return [Array<String>] the member names to generate methods for
|
|
49
67
|
def extract_parameters(superclass)
|
|
50
68
|
return [] unless superclass.parameters
|
|
@@ -51,7 +51,7 @@ class YARD::Handlers::Ruby::Legacy::AttributeHandler < YARD::Handlers::Ruby::Leg
|
|
|
51
51
|
register(o)
|
|
52
52
|
o.docstring = doc if o.docstring.blank?(false)
|
|
53
53
|
|
|
54
|
-
#
|
|
54
|
+
# Register the object explicitly
|
|
55
55
|
namespace.attributes[scope][name][type] = o
|
|
56
56
|
else
|
|
57
57
|
obj = namespace.children.find {|other| other.name == meth.to_sym && other.scope == scope }
|
|
@@ -8,9 +8,10 @@ class YARD::Handlers::Ruby::Legacy::VisibilityHandler < YARD::Handlers::Ruby::Le
|
|
|
8
8
|
vis = statement.tokens.first.text
|
|
9
9
|
if statement.tokens.size == 1
|
|
10
10
|
self.visibility = vis
|
|
11
|
+
globals.visibility_origin = :keyword
|
|
11
12
|
else
|
|
12
13
|
tokval_list(statement.tokens[2..-1], :attr).each do |name|
|
|
13
|
-
MethodObject.new(namespace, name, scope) {|o| o.visibility = vis }
|
|
14
|
+
MethodObject.new(namespace, name, scope) { |o| o.visibility = vis }
|
|
14
15
|
end
|
|
15
16
|
end
|
|
16
17
|
end
|
|
@@ -26,22 +26,29 @@ class YARD::Handlers::Ruby::MixinHandler < YARD::Handlers::Ruby::Base
|
|
|
26
26
|
raise YARD::Parser::UndocumentableError unless mixin.ref?
|
|
27
27
|
raise YARD::Parser::UndocumentableError if mixin.first.type == :ident
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
obj = Proxy.new(namespace, obj.value, :module)
|
|
29
|
+
if mixin.type == :var_ref && mixin[0] == s(:kw, "self")
|
|
30
|
+
obj = namespace
|
|
32
31
|
else
|
|
33
|
-
obj = Proxy.new(namespace, mixin.source
|
|
32
|
+
case obj = Proxy.new(namespace, mixin.source)
|
|
33
|
+
when ConstantObject # If a constant is included, use its value as the real object
|
|
34
|
+
obj = Proxy.new(namespace, obj.value, :module)
|
|
35
|
+
else
|
|
36
|
+
obj = Proxy.new(namespace, mixin.source, :module)
|
|
37
|
+
end
|
|
34
38
|
end
|
|
35
39
|
|
|
36
40
|
rec = recipient(mixin)
|
|
37
|
-
return if rec.nil?
|
|
41
|
+
return if rec.nil?
|
|
42
|
+
|
|
43
|
+
ensure_loaded!(rec)
|
|
44
|
+
return if rec.mixins(scope).include?(obj)
|
|
38
45
|
|
|
39
46
|
shift = statement.method_name(true) == :include ? :unshift : :push
|
|
40
47
|
rec.mixins(scope).send(shift, obj)
|
|
41
48
|
end
|
|
42
49
|
|
|
43
50
|
def recipient(mixin)
|
|
44
|
-
if statement[0].type == :const_path_ref
|
|
51
|
+
if statement[0].type == :const_path_ref || statement[0].type == :top_const_ref
|
|
45
52
|
Proxy.new(namespace, statement[0].source)
|
|
46
53
|
elsif statement[0].type == :var_ref && statement[0][0] != s(:kw, "self")
|
|
47
54
|
statement[0][0].type == :const ?
|
|
@@ -13,10 +13,23 @@ class YARD::Handlers::Ruby::VisibilityHandler < YARD::Handlers::Ruby::Base
|
|
|
13
13
|
case statement.type
|
|
14
14
|
when :var_ref, :vcall
|
|
15
15
|
self.visibility = ident.first.to_sym
|
|
16
|
-
|
|
16
|
+
globals.visibility_origin = :keyword
|
|
17
|
+
when :command
|
|
18
|
+
if RUBY_VERSION >= '3.' && is_attribute_method?(statement.parameters.first)
|
|
19
|
+
parse_block(statement.parameters.first, visibility: ident.first.to_sym)
|
|
20
|
+
return
|
|
21
|
+
end
|
|
22
|
+
process_decorator do |method|
|
|
23
|
+
method.visibility = ident.first if method.respond_to? :visibility=
|
|
24
|
+
end
|
|
25
|
+
when :fcall
|
|
17
26
|
process_decorator do |method|
|
|
18
27
|
method.visibility = ident.first if method.respond_to? :visibility=
|
|
19
28
|
end
|
|
20
29
|
end
|
|
21
30
|
end
|
|
31
|
+
|
|
32
|
+
def is_attribute_method?(node)
|
|
33
|
+
node.type == :command && node.jump(:ident).first.to_s =~ /^attr_(accessor|writer|reader)$/
|
|
34
|
+
end
|
|
22
35
|
end
|
data/lib/yard/i18n/locale.rb
CHANGED
|
@@ -24,7 +24,7 @@ module YARD
|
|
|
24
24
|
|
|
25
25
|
# @return [String] the name of the locale. It used IETF language
|
|
26
26
|
# tag format +[language[_territory][.codeset][@modifier]]+.
|
|
27
|
-
# @see
|
|
27
|
+
# @see https://tools.ietf.org/rfc/bcp/bcp47.txt
|
|
28
28
|
# BCP 47 - Tags for Identifying Languages
|
|
29
29
|
attr_reader :name
|
|
30
30
|
|
|
@@ -57,7 +57,7 @@ module YARD
|
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
# @param [String] message the translation target message.
|
|
60
|
-
# @return [String] translated message. If
|
|
60
|
+
# @return [String] translated message. If translation isn't
|
|
61
61
|
# registered, the +message+ is returned.
|
|
62
62
|
def translate(message)
|
|
63
63
|
@messages[message] || message
|
data/lib/yard/i18n/message.rb
CHANGED
|
@@ -8,7 +8,7 @@ module YARD
|
|
|
8
8
|
#
|
|
9
9
|
# @since 0.8.1
|
|
10
10
|
class Message
|
|
11
|
-
# @return [String] the message ID of the
|
|
11
|
+
# @return [String] the message ID of the translation target message.
|
|
12
12
|
attr_reader :id
|
|
13
13
|
|
|
14
14
|
# @return [Set] the set of locations. Location is an array of
|
|
@@ -18,7 +18,7 @@ module YARD
|
|
|
18
18
|
# @return [Set] the set of comments for the messages.
|
|
19
19
|
attr_reader :comments
|
|
20
20
|
|
|
21
|
-
# Creates a
|
|
21
|
+
# Creates a translate target message for message ID +id+.
|
|
22
22
|
#
|
|
23
23
|
# @param [String] id the message ID of the translate target message.
|
|
24
24
|
def initialize(id)
|
data/lib/yard/i18n/messages.rb
CHANGED
|
@@ -28,7 +28,7 @@ module YARD
|
|
|
28
28
|
@messages[id]
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
# Registers a {Message}, the
|
|
31
|
+
# Registers a {Message}, the message ID of which is +id+. If
|
|
32
32
|
# corresponding +Message+ is already registered, the previously
|
|
33
33
|
# registered object is returned.
|
|
34
34
|
#
|
|
@@ -60,7 +60,7 @@ module YARD
|
|
|
60
60
|
# File.open(po_file_path, "w") do |pot_file|
|
|
61
61
|
# pot_file.print(pot)
|
|
62
62
|
# end
|
|
63
|
-
# @see
|
|
63
|
+
# @see https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html
|
|
64
64
|
# GNU gettext manual about details of PO file
|
|
65
65
|
class PotGenerator
|
|
66
66
|
# Extracted messages.
|
|
@@ -113,7 +113,7 @@ module YARD
|
|
|
113
113
|
#
|
|
114
114
|
# Locations of the +Message+ are used to generate the reference
|
|
115
115
|
# line that is started with "#: ". +relative_base_path+ passed
|
|
116
|
-
# when the
|
|
116
|
+
# when the generator is created is prepended to each path in location.
|
|
117
117
|
#
|
|
118
118
|
# Comments of the +Message+ are used to generate the
|
|
119
119
|
# translator-comment line that is started with "# ".
|