docscribe 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +11 -0
- data/.rubocop_todo.yml +73 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +73 -0
- data/LICENSE.txt +21 -0
- data/README.md +451 -0
- data/Rakefile +12 -0
- data/exe/docscribe +77 -0
- data/lib/docscribe/config.rb +245 -0
- data/lib/docscribe/infer.rb +302 -0
- data/lib/docscribe/inline_rewriter.rb +534 -0
- data/lib/docscribe/version.rb +5 -0
- data/lib/docscribe.rb +10 -0
- data/rakelib/docs.rake +73 -0
- data/stingray_docs_internal.gemspec +41 -0
- metadata +144 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'yaml'
|
|
4
|
+
|
|
5
|
+
module Docscribe
|
|
6
|
+
class Config
|
|
7
|
+
DEFAULT = {
|
|
8
|
+
'emit' => {
|
|
9
|
+
'header' => true,
|
|
10
|
+
'param_tags' => true,
|
|
11
|
+
'return_tag' => true,
|
|
12
|
+
'visibility_tags' => true,
|
|
13
|
+
'raise_tags' => true,
|
|
14
|
+
'rescue_conditional_returns' => true
|
|
15
|
+
},
|
|
16
|
+
'doc' => {
|
|
17
|
+
'default_message' => 'Method documentation.'
|
|
18
|
+
},
|
|
19
|
+
'methods' => {
|
|
20
|
+
'instance' => {
|
|
21
|
+
'public' => {},
|
|
22
|
+
'protected' => {},
|
|
23
|
+
'private' => {}
|
|
24
|
+
},
|
|
25
|
+
'class' => {
|
|
26
|
+
'public' => {},
|
|
27
|
+
'protected' => {},
|
|
28
|
+
'private' => {}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
'inference' => {
|
|
32
|
+
'fallback_type' => 'Object',
|
|
33
|
+
'nil_as_optional' => true,
|
|
34
|
+
'treat_options_keyword_as_hash' => true
|
|
35
|
+
},
|
|
36
|
+
'filter' => {
|
|
37
|
+
'visibilities' => %w[public protected private],
|
|
38
|
+
'scopes' => %w[instance class],
|
|
39
|
+
'include' => [],
|
|
40
|
+
'exclude' => []
|
|
41
|
+
}
|
|
42
|
+
}.freeze
|
|
43
|
+
|
|
44
|
+
attr_reader :raw
|
|
45
|
+
|
|
46
|
+
# +Docscribe::Config#initialize+ -> Object
|
|
47
|
+
#
|
|
48
|
+
# Method documentation.
|
|
49
|
+
#
|
|
50
|
+
# @param [Hash] raw Param documentation.
|
|
51
|
+
# @return [Object]
|
|
52
|
+
def initialize(raw = {})
|
|
53
|
+
@raw = deep_merge(DEFAULT, raw || {})
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# +Docscribe::Config.load+ -> Object
|
|
57
|
+
#
|
|
58
|
+
# Method documentation.
|
|
59
|
+
#
|
|
60
|
+
# @param [nil] path Param documentation.
|
|
61
|
+
# @return [Object]
|
|
62
|
+
def self.load(path = nil)
|
|
63
|
+
raw = {}
|
|
64
|
+
if path && File.file?(path)
|
|
65
|
+
raw = YAML.safe_load_file(path, permitted_classes: [], aliases: true) || {}
|
|
66
|
+
elsif File.file?('docscribe.yml')
|
|
67
|
+
raw = YAML.safe_load_file('docscribe.yml', permitted_classes: [], aliases: true) || {}
|
|
68
|
+
end
|
|
69
|
+
new(raw)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# +Docscribe::Config#emit_header?+ -> Object
|
|
73
|
+
#
|
|
74
|
+
# Method documentation.
|
|
75
|
+
#
|
|
76
|
+
# @return [Object]
|
|
77
|
+
def emit_header?
|
|
78
|
+
fetch_bool(%w[emit header], true)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# +Docscribe::Config#emit_param_tags?+ -> Object
|
|
82
|
+
#
|
|
83
|
+
# Method documentation.
|
|
84
|
+
#
|
|
85
|
+
# @return [Object]
|
|
86
|
+
def emit_param_tags?
|
|
87
|
+
fetch_bool(%w[emit param_tags], true)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# +Docscribe::Config#emit_visibility_tags?+ -> Object
|
|
91
|
+
#
|
|
92
|
+
# Method documentation.
|
|
93
|
+
#
|
|
94
|
+
# @return [Object]
|
|
95
|
+
def emit_visibility_tags?
|
|
96
|
+
fetch_bool(%w[emit visibility_tags], true)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# +Docscribe::Config#emit_raise_tags?+ -> Object
|
|
100
|
+
#
|
|
101
|
+
# Method documentation.
|
|
102
|
+
#
|
|
103
|
+
# @return [Object]
|
|
104
|
+
def emit_raise_tags?
|
|
105
|
+
fetch_bool(%w[emit raise_tags], true)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# +Docscribe::Config#emit_rescue_conditional_returns?+ -> Object
|
|
109
|
+
#
|
|
110
|
+
# Method documentation.
|
|
111
|
+
#
|
|
112
|
+
# @return [Object]
|
|
113
|
+
def emit_rescue_conditional_returns?
|
|
114
|
+
fetch_bool(%w[emit rescue_conditional_returns], true)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# +Docscribe::Config#emit_return_tag?+ -> Object
|
|
118
|
+
#
|
|
119
|
+
# Method documentation.
|
|
120
|
+
#
|
|
121
|
+
# @param [Object] scope Param documentation.
|
|
122
|
+
# @param [Object] visibility Param documentation.
|
|
123
|
+
# @return [Object]
|
|
124
|
+
def emit_return_tag?(scope, visibility)
|
|
125
|
+
method_override_bool(scope, visibility, 'return_tag',
|
|
126
|
+
default: fetch_bool(%w[emit return_tag], true))
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# +Docscribe::Config#default_message+ -> Object
|
|
130
|
+
#
|
|
131
|
+
# Method documentation.
|
|
132
|
+
#
|
|
133
|
+
# @param [Object] scope Param documentation.
|
|
134
|
+
# @param [Object] visibility Param documentation.
|
|
135
|
+
# @return [Object]
|
|
136
|
+
def default_message(scope, visibility)
|
|
137
|
+
method_override_str(scope, visibility, 'default_message',
|
|
138
|
+
default: raw.dig('doc', 'default_message') || 'Method documentation.')
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# +Docscribe::Config#fallback_type+ -> Object
|
|
142
|
+
#
|
|
143
|
+
# Method documentation.
|
|
144
|
+
#
|
|
145
|
+
# @return [Object]
|
|
146
|
+
def fallback_type
|
|
147
|
+
raw.dig('inference', 'fallback_type') || 'Object'
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# +Docscribe::Config#nil_as_optional?+ -> Object
|
|
151
|
+
#
|
|
152
|
+
# Method documentation.
|
|
153
|
+
#
|
|
154
|
+
# @return [Object]
|
|
155
|
+
def nil_as_optional?
|
|
156
|
+
fetch_bool(%w[inference nil_as_optional], true)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# +Docscribe::Config#treat_options_keyword_as_hash?+ -> Object
|
|
160
|
+
#
|
|
161
|
+
# Method documentation.
|
|
162
|
+
#
|
|
163
|
+
# @return [Object]
|
|
164
|
+
def treat_options_keyword_as_hash?
|
|
165
|
+
fetch_bool(%w[inference treat_options_keyword_as_hash], true)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
private
|
|
169
|
+
|
|
170
|
+
# +Docscribe::Config#method_override_bool+ -> Object
|
|
171
|
+
#
|
|
172
|
+
# Method documentation.
|
|
173
|
+
#
|
|
174
|
+
# @private
|
|
175
|
+
# @param [Object] scope Param documentation.
|
|
176
|
+
# @param [Object] vis Param documentation.
|
|
177
|
+
# @param [Object] key Param documentation.
|
|
178
|
+
# @param [Object] default Param documentation.
|
|
179
|
+
# @return [Object]
|
|
180
|
+
def method_override_bool(scope, vis, key, default:)
|
|
181
|
+
node = raw.dig('methods', scope_to_key(scope), vis.to_s, key)
|
|
182
|
+
node.nil? ? default : !!node
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# +Docscribe::Config#fetch_bool+ -> Object
|
|
186
|
+
#
|
|
187
|
+
# Method documentation.
|
|
188
|
+
#
|
|
189
|
+
# @private
|
|
190
|
+
# @param [Object] path Param documentation.
|
|
191
|
+
# @param [Object] default Param documentation.
|
|
192
|
+
# @return [Object]
|
|
193
|
+
def fetch_bool(path, default)
|
|
194
|
+
node = raw
|
|
195
|
+
path.each { |k| node = node[k] if node }
|
|
196
|
+
node.nil? ? default : !!node
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# +Docscribe::Config#method_override_str+ -> Object
|
|
200
|
+
#
|
|
201
|
+
# Method documentation.
|
|
202
|
+
#
|
|
203
|
+
# @private
|
|
204
|
+
# @param [Object] scope Param documentation.
|
|
205
|
+
# @param [Object] vis Param documentation.
|
|
206
|
+
# @param [Object] key Param documentation.
|
|
207
|
+
# @param [Object] default Param documentation.
|
|
208
|
+
# @return [Object]
|
|
209
|
+
def method_override_str(scope, vis, key, default:)
|
|
210
|
+
node = raw.dig('methods', scope_to_key(scope), vis.to_s, key)
|
|
211
|
+
node.nil? ? default : node.to_s
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# +Docscribe::Config#scope_to_key+ -> String
|
|
215
|
+
#
|
|
216
|
+
# Method documentation.
|
|
217
|
+
#
|
|
218
|
+
# @private
|
|
219
|
+
# @param [Object] scope Param documentation.
|
|
220
|
+
# @return [String]
|
|
221
|
+
def scope_to_key(scope)
|
|
222
|
+
scope == :class ? 'class' : 'instance'
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# +Docscribe::Config#deep_merge+ -> Object
|
|
226
|
+
#
|
|
227
|
+
# Method documentation.
|
|
228
|
+
#
|
|
229
|
+
# @private
|
|
230
|
+
# @param [Object] hash1 Param documentation.
|
|
231
|
+
# @param [Object] hash2 Param documentation.
|
|
232
|
+
# @return [Object]
|
|
233
|
+
def deep_merge(hash1, hash2)
|
|
234
|
+
return hash1 unless hash2
|
|
235
|
+
|
|
236
|
+
hash1.merge(hash2) do |_, v1, v2|
|
|
237
|
+
if v1.is_a?(Hash) && v2.is_a?(Hash)
|
|
238
|
+
deep_merge(v1, v2)
|
|
239
|
+
else
|
|
240
|
+
v2
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'parser/current'
|
|
4
|
+
|
|
5
|
+
module Docscribe
|
|
6
|
+
module Infer
|
|
7
|
+
class << self
|
|
8
|
+
# +Docscribe::Infer.infer_raises_from_node+ -> Object
|
|
9
|
+
#
|
|
10
|
+
# Method documentation.
|
|
11
|
+
#
|
|
12
|
+
# @param [Object] node Param documentation.
|
|
13
|
+
# @return [Object]
|
|
14
|
+
def infer_raises_from_node(node)
|
|
15
|
+
raises = []
|
|
16
|
+
walk = lambda do |n|
|
|
17
|
+
return unless n.is_a?(Parser::AST::Node)
|
|
18
|
+
|
|
19
|
+
case n.type
|
|
20
|
+
when :rescue
|
|
21
|
+
n.children.each { |ch| walk.call(ch) }
|
|
22
|
+
when :resbody
|
|
23
|
+
exc_list = n.children[0]
|
|
24
|
+
if exc_list.nil?
|
|
25
|
+
raises << 'StandardError'
|
|
26
|
+
elsif exc_list.type == :array
|
|
27
|
+
exc_list.children.each { |e| (c = const_full_name(e)) && (raises << c) }
|
|
28
|
+
else
|
|
29
|
+
(c = const_full_name(exc_list)) && (raises << c)
|
|
30
|
+
end
|
|
31
|
+
n.children.each { |ch| walk.call(ch) if ch.is_a?(Parser::AST::Node) }
|
|
32
|
+
when :send
|
|
33
|
+
recv, meth, *args = *n
|
|
34
|
+
if recv.nil? && %i[raise fail].include?(meth)
|
|
35
|
+
if args.empty?
|
|
36
|
+
raises << 'StandardError'
|
|
37
|
+
else
|
|
38
|
+
c = const_full_name(args[0])
|
|
39
|
+
raises << (c || 'StandardError')
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
n.children.each { |ch| walk.call(ch) if ch.is_a?(Parser::AST::Node) }
|
|
43
|
+
else
|
|
44
|
+
n.children.each { |ch| walk.call(ch) if ch.is_a?(Parser::AST::Node) }
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
walk.call(node)
|
|
48
|
+
raises.uniq
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# +Docscribe::Infer.infer_param_type+ -> Object
|
|
52
|
+
#
|
|
53
|
+
# Method documentation.
|
|
54
|
+
#
|
|
55
|
+
# @param [Object] name Param documentation.
|
|
56
|
+
# @param [Object] default_str Param documentation.
|
|
57
|
+
# @return [Object]
|
|
58
|
+
def infer_param_type(name, default_str)
|
|
59
|
+
# splats and kwargs are driven by name shape
|
|
60
|
+
return 'Array' if name.start_with?('*') && !name.start_with?('**')
|
|
61
|
+
return 'Hash' if name.start_with?('**')
|
|
62
|
+
return 'Proc' if name.start_with?('&')
|
|
63
|
+
|
|
64
|
+
# keyword arg e.g. "verbose:" — default_str might be nil or something
|
|
65
|
+
is_kw = name.end_with?(':')
|
|
66
|
+
|
|
67
|
+
node = parse_expr(default_str)
|
|
68
|
+
ty = type_from_literal(node)
|
|
69
|
+
|
|
70
|
+
# If kw with no default, still show Object (or Hash for options:)
|
|
71
|
+
if is_kw && default_str.nil?
|
|
72
|
+
return (name == 'options:' ? 'Hash' : 'Object')
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# If param named options and default is {}, call it Hash
|
|
76
|
+
return 'Hash' if name == 'options:' && (default_str == '{}' || ty == 'Hash')
|
|
77
|
+
|
|
78
|
+
ty
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# +Docscribe::Infer.parse_expr+ -> Object
|
|
82
|
+
#
|
|
83
|
+
# Method documentation.
|
|
84
|
+
#
|
|
85
|
+
# @param [Object] src Param documentation.
|
|
86
|
+
# @raise [Parser::SyntaxError]
|
|
87
|
+
# @return [Object]
|
|
88
|
+
# @return [nil] if Parser::SyntaxError
|
|
89
|
+
def parse_expr(src)
|
|
90
|
+
return nil if src.nil? || src.strip.empty?
|
|
91
|
+
|
|
92
|
+
buffer = Parser::Source::Buffer.new('(param)')
|
|
93
|
+
buffer.source = src
|
|
94
|
+
Parser::CurrentRuby.new.parse(buffer)
|
|
95
|
+
rescue Parser::SyntaxError
|
|
96
|
+
nil
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# +Docscribe::Infer.infer_return_type+ -> Object
|
|
100
|
+
#
|
|
101
|
+
# Method documentation.
|
|
102
|
+
#
|
|
103
|
+
# @param [Object] method_source Param documentation.
|
|
104
|
+
# @raise [Parser::SyntaxError]
|
|
105
|
+
# @return [Object]
|
|
106
|
+
# @return [String] if Parser::SyntaxError
|
|
107
|
+
def infer_return_type(method_source)
|
|
108
|
+
return 'Object' if method_source.nil? || method_source.strip.empty?
|
|
109
|
+
|
|
110
|
+
buffer = Parser::Source::Buffer.new('(method)')
|
|
111
|
+
buffer.source = method_source
|
|
112
|
+
root = Parser::CurrentRuby.new.parse(buffer)
|
|
113
|
+
return 'Object' unless root && %i[def defs].include?(root.type)
|
|
114
|
+
|
|
115
|
+
body = root.children.last # method body node
|
|
116
|
+
ty = last_expr_type(body)
|
|
117
|
+
ty || 'Object'
|
|
118
|
+
rescue Parser::SyntaxError
|
|
119
|
+
'Object'
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# +Docscribe::Infer.infer_return_type_from_node+ -> Object
|
|
123
|
+
#
|
|
124
|
+
# Method documentation.
|
|
125
|
+
#
|
|
126
|
+
# @param [Object] node Param documentation.
|
|
127
|
+
# @return [Object]
|
|
128
|
+
def infer_return_type_from_node(node)
|
|
129
|
+
body =
|
|
130
|
+
case node.type
|
|
131
|
+
when :def then node.children[2] # [name, args, body]
|
|
132
|
+
when :defs then node.children[3] # [recv, name, args, body]
|
|
133
|
+
end
|
|
134
|
+
return 'Object' unless body
|
|
135
|
+
|
|
136
|
+
ty = last_expr_type(body)
|
|
137
|
+
ty || 'Object'
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# +Docscribe::Infer.returns_spec_from_node+ -> Object
|
|
141
|
+
#
|
|
142
|
+
# Method documentation.
|
|
143
|
+
#
|
|
144
|
+
# @param [Object] node Param documentation.
|
|
145
|
+
# @return [Object]
|
|
146
|
+
def returns_spec_from_node(node)
|
|
147
|
+
# Returns a Hash like: { normal: 'Type', rescues: [[['Foo','Bar'], 'Type'], ...] }
|
|
148
|
+
body =
|
|
149
|
+
case node.type
|
|
150
|
+
when :def then node.children[2] # [name, args, body]
|
|
151
|
+
when :defs then node.children[3] # [recv, name, args, body]
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
spec = { normal: 'Object', rescues: [] }
|
|
155
|
+
return spec unless body
|
|
156
|
+
|
|
157
|
+
if body.type == :rescue
|
|
158
|
+
# child[0] is the main body (before rescue)
|
|
159
|
+
main_body = body.children[0]
|
|
160
|
+
spec[:normal] = last_expr_type(main_body) || 'Object'
|
|
161
|
+
|
|
162
|
+
# :resbody nodes hold exception list, optional var, and rescue body
|
|
163
|
+
body.children.each do |ch|
|
|
164
|
+
next unless ch.is_a?(Parser::AST::Node) && ch.type == :resbody
|
|
165
|
+
|
|
166
|
+
exc_list, _asgn, rescue_body = *ch
|
|
167
|
+
|
|
168
|
+
exc_names = []
|
|
169
|
+
if exc_list.nil?
|
|
170
|
+
exc_names << 'StandardError'
|
|
171
|
+
elsif exc_list.type == :array
|
|
172
|
+
exc_list.children.each do |e|
|
|
173
|
+
name = const_full_name(e)
|
|
174
|
+
exc_names << (name || 'StandardError')
|
|
175
|
+
end
|
|
176
|
+
else
|
|
177
|
+
name = const_full_name(exc_list)
|
|
178
|
+
exc_names << (name || 'StandardError')
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
rtype = last_expr_type(rescue_body) || 'Object'
|
|
182
|
+
spec[:rescues] << [exc_names, rtype]
|
|
183
|
+
end
|
|
184
|
+
else
|
|
185
|
+
spec[:normal] = last_expr_type(body) || 'Object'
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
spec
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# +Docscribe::Infer.last_expr_type+ -> Object
|
|
192
|
+
#
|
|
193
|
+
# Method documentation.
|
|
194
|
+
#
|
|
195
|
+
# @param [Object] node Param documentation.
|
|
196
|
+
# @return [Object]
|
|
197
|
+
def last_expr_type(node)
|
|
198
|
+
return nil unless node
|
|
199
|
+
|
|
200
|
+
case node.type
|
|
201
|
+
when :begin
|
|
202
|
+
last = node.children.last
|
|
203
|
+
last_expr_type(last)
|
|
204
|
+
when :if
|
|
205
|
+
t = last_expr_type(node.children[1])
|
|
206
|
+
e = last_expr_type(node.children[2])
|
|
207
|
+
unify_types(t, e)
|
|
208
|
+
when :case
|
|
209
|
+
# check whens and else
|
|
210
|
+
branches = node.children[1..].compact.flat_map do |child|
|
|
211
|
+
if child && child.type == :when
|
|
212
|
+
last_expr_type(child.children.last)
|
|
213
|
+
else
|
|
214
|
+
last_expr_type(child)
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
branches.compact!
|
|
218
|
+
branches.empty? ? 'Object' : branches.reduce { |a, b| unify_types(a, b) }
|
|
219
|
+
when :return
|
|
220
|
+
type_from_literal(node.children.first)
|
|
221
|
+
else
|
|
222
|
+
type_from_literal(node)
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# +Docscribe::Infer.const_full_name+ -> Object
|
|
227
|
+
#
|
|
228
|
+
# Method documentation.
|
|
229
|
+
#
|
|
230
|
+
# @param [Object] n Param documentation.
|
|
231
|
+
# @return [Object]
|
|
232
|
+
def const_full_name(n)
|
|
233
|
+
return nil unless n.is_a?(Parser::AST::Node)
|
|
234
|
+
|
|
235
|
+
case n.type
|
|
236
|
+
when :const
|
|
237
|
+
scope, name = *n
|
|
238
|
+
scope_name = const_full_name(scope)
|
|
239
|
+
if scope_name && !scope_name.empty?
|
|
240
|
+
"#{scope_name}::#{name}"
|
|
241
|
+
elsif scope_name == '' # leading ::
|
|
242
|
+
"::#{name}"
|
|
243
|
+
else
|
|
244
|
+
name.to_s
|
|
245
|
+
end
|
|
246
|
+
when :cbase
|
|
247
|
+
'' # represents leading :: scope
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# +Docscribe::Infer.type_from_literal+ -> Object
|
|
252
|
+
#
|
|
253
|
+
# Method documentation.
|
|
254
|
+
#
|
|
255
|
+
# @param [Object] node Param documentation.
|
|
256
|
+
# @return [Object]
|
|
257
|
+
def type_from_literal(node)
|
|
258
|
+
return 'Object' unless node
|
|
259
|
+
|
|
260
|
+
case node.type
|
|
261
|
+
when :int then 'Integer'
|
|
262
|
+
when :float then 'Float'
|
|
263
|
+
when :str, :dstr then 'String'
|
|
264
|
+
when :sym then 'Symbol'
|
|
265
|
+
when :true, :false then 'Boolean' # rubocop:disable Lint/BooleanSymbol
|
|
266
|
+
when :nil then 'nil'
|
|
267
|
+
when :array then 'Array'
|
|
268
|
+
when :hash then 'Hash'
|
|
269
|
+
when :regexp then 'Regexp'
|
|
270
|
+
when :const
|
|
271
|
+
node.children.last.to_s
|
|
272
|
+
when :send
|
|
273
|
+
recv, meth, = node.children
|
|
274
|
+
if meth == :new && recv && recv.type == :const
|
|
275
|
+
recv.children.last.to_s
|
|
276
|
+
else
|
|
277
|
+
'Object'
|
|
278
|
+
end
|
|
279
|
+
else
|
|
280
|
+
'Object'
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# +Docscribe::Infer.unify_types+ -> String
|
|
285
|
+
#
|
|
286
|
+
# Method documentation.
|
|
287
|
+
#
|
|
288
|
+
# @param [Object] a Param documentation.
|
|
289
|
+
# @param [Object] b Param documentation.
|
|
290
|
+
# @return [String]
|
|
291
|
+
def unify_types(a, b)
|
|
292
|
+
a ||= 'Object'
|
|
293
|
+
b ||= 'Object'
|
|
294
|
+
return a if a == b
|
|
295
|
+
# nil-union => Optional
|
|
296
|
+
return "#{a == 'nil' ? b : a}?" if a == 'nil' || b == 'nil'
|
|
297
|
+
|
|
298
|
+
'Object'
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
end
|