yard-sketchup 1.3.0 → 1.4.1
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/Gemfile +15 -15
- data/lib/yard-sketchup/patches/c_base_handler.rb +52 -52
- data/lib/yard-sketchup/stubs/autoload.rb +134 -134
- data/lib/yard-sketchup/templates/changelog/fulldoc/text/setup.rb +44 -44
- data/lib/yard-sketchup/templates/coverage/fulldoc/text/setup.rb +41 -41
- data/lib/yard-sketchup/templates/default/fulldoc/html/css/rubyapi.css +10 -10
- data/lib/yard-sketchup/templates/default/fulldoc/html/css/sketchup.css +141 -141
- data/lib/yard-sketchup/templates/default/fulldoc/html/favicon.ico +0 -0
- data/lib/yard-sketchup/templates/default/fulldoc/html/full_list_object_types.erb +1 -1
- data/lib/yard-sketchup/templates/default/fulldoc/html/images/Ruby.svg +1 -1
- data/lib/yard-sketchup/templates/default/fulldoc/html/images/sketchup-logo.svg +19 -19
- data/lib/yard-sketchup/templates/default/fulldoc/html/images/trimble-logo-white.svg +29 -29
- data/lib/yard-sketchup/templates/default/fulldoc/html/js/sketchup.js +37 -37
- data/lib/yard-sketchup/templates/default/fulldoc/html/setup.rb +75 -67
- data/lib/yard-sketchup/templates/default/layout/html/embed_meta.erb +78 -78
- data/lib/yard-sketchup/templates/default/layout/html/footer.erb +4 -4
- data/lib/yard-sketchup/templates/default/layout/html/headers.erb +15 -15
- data/lib/yard-sketchup/templates/default/layout/html/layout.erb +56 -55
- data/lib/yard-sketchup/templates/default/layout/html/navbar.erb +36 -36
- data/lib/yard-sketchup/templates/default/layout/html/setup.rb +25 -25
- data/lib/yard-sketchup/templates/default/method_details/html/method_signature.erb +25 -25
- data/lib/yard-sketchup/templates/default/method_details/setup.rb +11 -11
- data/lib/yard-sketchup/templates/default/module/html/box_info.erb +37 -37
- data/lib/yard-sketchup/templates/default/module/html/constant_summary.erb +17 -17
- data/lib/yard-sketchup/templates/default/module/html/method_summary.erb +18 -18
- data/lib/yard-sketchup/templates/inheritance/fulldoc/text/setup.rb +54 -54
- data/lib/yard-sketchup/templates/stubs/fulldoc/text/setup.rb +372 -361
- data/lib/yard-sketchup/templates/versions/fulldoc/text/setup.rb +25 -25
- data/lib/yard-sketchup/version.rb +3 -3
- data/lib/yard-sketchup/yard/html_helper.rb +16 -0
- data/lib/yard-sketchup.rb +37 -36
- data/yard-sketchup.gemspec +26 -25
- metadata +22 -7
@@ -1,361 +1,372 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
require 'pathname'
|
3
|
-
require 'set'
|
4
|
-
require 'stringio'
|
5
|
-
|
6
|
-
include Helpers::ModuleHelper
|
7
|
-
|
8
|
-
def init
|
9
|
-
generate_stubs
|
10
|
-
end
|
11
|
-
|
12
|
-
|
13
|
-
# NOTE: Remember to run objects outputted through `run_verifier` first in order
|
14
|
-
# to filter out items that should be excluded by command line arguments.
|
15
|
-
|
16
|
-
def namespace_objects
|
17
|
-
run_verifier(Registry.all(:class, :module))
|
18
|
-
end
|
19
|
-
|
20
|
-
def generate_stubs
|
21
|
-
puts "Generating stubs..."
|
22
|
-
generate_module_stubs(Registry.root)
|
23
|
-
namespace_objects.each do |object|
|
24
|
-
generate_module_stubs(object)
|
25
|
-
end
|
26
|
-
generate_autoloader(namespace_objects)
|
27
|
-
end
|
28
|
-
|
29
|
-
def generate_autoloader(namespace_objects)
|
30
|
-
generator = SketchUpYARD::Stubs::AutoLoadGenerator.new
|
31
|
-
autoload_file = File.join(stubs_gem_path, 'sketchup.rb')
|
32
|
-
File.open(autoload_file, 'w') do |file|
|
33
|
-
generator.generate(namespace_objects, file)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def print_section(io, title, content)
|
38
|
-
return if content.strip.empty?
|
39
|
-
io.puts
|
40
|
-
io.puts " # #{title}"
|
41
|
-
io.puts
|
42
|
-
io.puts content
|
43
|
-
end
|
44
|
-
|
45
|
-
def generate_module_stubs(object)
|
46
|
-
filename = stub_filename(object)
|
47
|
-
ensure_exist(File.dirname(filename))
|
48
|
-
StubFile.open(filename, 'w') { |file|
|
49
|
-
file.puts file_header(object)
|
50
|
-
file.puts
|
51
|
-
file.puts namespace_definition(object)
|
52
|
-
print_section(file, 'Extends', generate_mixins(object, :class))
|
53
|
-
print_section(file, 'Includes', generate_mixins(object, :instance))
|
54
|
-
print_section(file, 'Constants', generate_constants_grouped(object))
|
55
|
-
print_section(file, 'Class Methods', generate_class_methods(object))
|
56
|
-
print_section(file, 'Instance Methods', generate_instance_methods(object))
|
57
|
-
file.puts
|
58
|
-
file.puts file_footer(object)
|
59
|
-
}
|
60
|
-
#trim_trailing_white_space(filename)
|
61
|
-
end
|
62
|
-
|
63
|
-
def file_header(object)
|
64
|
-
header = StringIO.new
|
65
|
-
header.puts "# Copyright:: Copyright #{Time.now.year} Trimble Inc."
|
66
|
-
header.puts "# License:: The MIT License (MIT)"
|
67
|
-
#header.puts "# Generated:: #{Time.now.strftime('%F %R')}"
|
68
|
-
header.string
|
69
|
-
end
|
70
|
-
|
71
|
-
def file_footer(object)
|
72
|
-
return if object.root?
|
73
|
-
footer = StringIO.new
|
74
|
-
footer.puts 'end'
|
75
|
-
footer.string
|
76
|
-
end
|
77
|
-
|
78
|
-
def namespace_definition(object)
|
79
|
-
return if object.root?
|
80
|
-
definition = "#{object.type} #{object.path}"
|
81
|
-
if object.type == :class && object.superclass.name != :Object
|
82
|
-
definition << " < #{object.superclass.path}"
|
83
|
-
end
|
84
|
-
output = StringIO.new
|
85
|
-
output.puts generate_docstring(object)
|
86
|
-
output.puts definition
|
87
|
-
output.string
|
88
|
-
end
|
89
|
-
|
90
|
-
def output_path
|
91
|
-
options.serializer.options[:basepath] || File.join(Dir.pwd, 'stubs')
|
92
|
-
end
|
93
|
-
|
94
|
-
def stubs_root_path
|
95
|
-
ensure_exist(output_path)
|
96
|
-
end
|
97
|
-
|
98
|
-
def stubs_lib_path
|
99
|
-
ensure_exist(File.join(stubs_root_path, 'lib'))
|
100
|
-
end
|
101
|
-
|
102
|
-
def stubs_gem_path
|
103
|
-
ensure_exist(File.join(stubs_lib_path, 'sketchup-api-stubs'))
|
104
|
-
end
|
105
|
-
|
106
|
-
def stubs_path
|
107
|
-
ensure_exist(File.join(stubs_gem_path, 'stubs'))
|
108
|
-
end
|
109
|
-
|
110
|
-
def stub_filename(object)
|
111
|
-
basename = object.path.gsub('::', '/')
|
112
|
-
basename = '_top_level' if basename.empty?
|
113
|
-
File.join(stubs_path, "#{basename}.rb")
|
114
|
-
end
|
115
|
-
|
116
|
-
# A stable sort_by method.
|
117
|
-
#
|
118
|
-
# @param [Enumerable]
|
119
|
-
# @return [Array]
|
120
|
-
def stable_sort_by(list)
|
121
|
-
list.each_with_index.sort_by { |item, i| [yield(item), i] }.map(&:first)
|
122
|
-
end
|
123
|
-
|
124
|
-
CAMELCASE_CONSTANT = /^([A-Z]+[a-z]+)/
|
125
|
-
|
126
|
-
def group_constant(constant)
|
127
|
-
constant_name = constant.name.to_s
|
128
|
-
MANUAL_CONSTANT_GROUPS.each { |rule|
|
129
|
-
if rule[:constants]
|
130
|
-
return rule[:group] if rule[:constants].include?(constant_name)
|
131
|
-
else
|
132
|
-
return rule[:group] if rule[:regex].match(constant_name)
|
133
|
-
end
|
134
|
-
}
|
135
|
-
if constant_name.include?('_')
|
136
|
-
constant_name.split('_').first
|
137
|
-
else
|
138
|
-
constant_name[CAMELCASE_CONSTANT] || constant_name
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
# Sorts and groups constants for easier reading.
|
143
|
-
def generate_constants_grouped(object)
|
144
|
-
constants = run_verifier(object.constants(object_options))
|
145
|
-
# The constants are not sorted before chunking. This is because `chunk` groups
|
146
|
-
# consecutive items - and we want to chunk them based their relationship
|
147
|
-
# with each other. This ensure that constants that doesn't follow the normal
|
148
|
-
# pattern of PREFIX_SOME_NAME will still be grouped next to each other.
|
149
|
-
groups = constants.chunk { |constant|
|
150
|
-
group_constant(constant)
|
151
|
-
}
|
152
|
-
grouped_output = groups.map { |group, group_constants|
|
153
|
-
output = StringIO.new
|
154
|
-
# Each group itself is sorted in order to more easily scan the list.
|
155
|
-
sorted = stable_sort_by(group_constants, &:name)
|
156
|
-
sorted.each { |constant|
|
157
|
-
output.puts " #{constant.name} = nil # Stub value."
|
158
|
-
}
|
159
|
-
output.string
|
160
|
-
}
|
161
|
-
# Finally each group is also sorted, again to ease scanning for a particular
|
162
|
-
# name. We simply use the first character of each group.
|
163
|
-
stable_sort_by(grouped_output) { |item| item.lstrip[0] }.join("\n")
|
164
|
-
end
|
165
|
-
|
166
|
-
# Sort constants without grouping.
|
167
|
-
def generate_constants(object)
|
168
|
-
output = StringIO.new
|
169
|
-
constants = run_verifier(object.constants(object_options))
|
170
|
-
constants = stable_sort_by(constants, &:name)
|
171
|
-
constants.each { |constant|
|
172
|
-
output.puts " #{constant.name} = nil # Stub value."
|
173
|
-
}
|
174
|
-
output.string
|
175
|
-
end
|
176
|
-
|
177
|
-
def generate_mixins(object, scope)
|
178
|
-
output = StringIO.new
|
179
|
-
mixin_type = (scope == :class) ? 'extend' : 'include'
|
180
|
-
mixins = run_verifier(object.mixins(scope))
|
181
|
-
mixins = stable_sort_by(mixins, &:path)
|
182
|
-
mixins.each { |mixin|
|
183
|
-
output.puts " #{mixin_type} #{mixin.path}"
|
184
|
-
}
|
185
|
-
output.string
|
186
|
-
end
|
187
|
-
|
188
|
-
def generate_class_methods(object)
|
189
|
-
generate_methods(object, :class, 'self.')
|
190
|
-
end
|
191
|
-
|
192
|
-
def generate_instance_methods(object)
|
193
|
-
generate_methods(object, :instance)
|
194
|
-
end
|
195
|
-
|
196
|
-
def generate_methods(object, scope, prefix = '')
|
197
|
-
methods = sort_methods(object, scope)
|
198
|
-
signatures = methods.map { |method|
|
199
|
-
output = StringIO.new
|
200
|
-
# Cannot use `methods.signature` here as it would return the C/C++ function
|
201
|
-
# signature. Must generate one from the YARD data.
|
202
|
-
signature = generate_method_signature(method)
|
203
|
-
# NOTE: We must call `generate_docstring` after `generate_method_signature`
|
204
|
-
# because `generate_method_signature` will also clean up docstrings with
|
205
|
-
# a single @overload tag.
|
206
|
-
output.puts generate_docstring(method, 1)
|
207
|
-
output.puts " def #{prefix}#{signature}"
|
208
|
-
output.puts " end"
|
209
|
-
# Include aliases.
|
210
|
-
method.aliases.each { |method_alias|
|
211
|
-
output.puts " alias_method :#{method_alias.name}, :#{method.name}"
|
212
|
-
}
|
213
|
-
output.string
|
214
|
-
}
|
215
|
-
signatures.join("\n")
|
216
|
-
end
|
217
|
-
|
218
|
-
# NOTE: This may modify the docstring of the object.
|
219
|
-
def generate_method_signature(object)
|
220
|
-
signature = "#{object.name}"
|
221
|
-
# If there is a single overload then use that as the parameter list. Many of
|
222
|
-
# the SketchUp Ruby API methods will have this as it was safer to add an
|
223
|
-
# @overload tag instead of renaming the function argument names.
|
224
|
-
overloads = object.docstring.tags(:overload)
|
225
|
-
if overloads.size == 1
|
226
|
-
overload = overloads.first
|
227
|
-
parameters = overload.parameters
|
228
|
-
# Move the tags from the @overload tag to the root of the docstring. No need
|
229
|
-
# for a single overload tag - it's unexpected when reading the source.
|
230
|
-
object.docstring.add_tag(*overload.tags)
|
231
|
-
object.docstring.delete_tags(:overload)
|
232
|
-
else
|
233
|
-
parameters = object.parameters
|
234
|
-
end
|
235
|
-
# Compile the signature for the arguments and default values.
|
236
|
-
params = parameters.map { |param|
|
237
|
-
param.last.nil? ? param.first : param.join(' = ')
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
group: '
|
344
|
-
},
|
345
|
-
# Sketchup::
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
#
|
357
|
-
{
|
358
|
-
|
359
|
-
group: '
|
360
|
-
},
|
361
|
-
|
1
|
+
require 'fileutils'
|
2
|
+
require 'pathname'
|
3
|
+
require 'set'
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
include Helpers::ModuleHelper
|
7
|
+
|
8
|
+
def init
|
9
|
+
generate_stubs
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
# NOTE: Remember to run objects outputted through `run_verifier` first in order
|
14
|
+
# to filter out items that should be excluded by command line arguments.
|
15
|
+
|
16
|
+
def namespace_objects
|
17
|
+
run_verifier(Registry.all(:class, :module))
|
18
|
+
end
|
19
|
+
|
20
|
+
def generate_stubs
|
21
|
+
puts "Generating stubs..."
|
22
|
+
generate_module_stubs(Registry.root)
|
23
|
+
namespace_objects.each do |object|
|
24
|
+
generate_module_stubs(object)
|
25
|
+
end
|
26
|
+
generate_autoloader(namespace_objects)
|
27
|
+
end
|
28
|
+
|
29
|
+
def generate_autoloader(namespace_objects)
|
30
|
+
generator = SketchUpYARD::Stubs::AutoLoadGenerator.new
|
31
|
+
autoload_file = File.join(stubs_gem_path, 'sketchup.rb')
|
32
|
+
File.open(autoload_file, 'w') do |file|
|
33
|
+
generator.generate(namespace_objects, file)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def print_section(io, title, content)
|
38
|
+
return if content.strip.empty?
|
39
|
+
io.puts
|
40
|
+
io.puts " # #{title}"
|
41
|
+
io.puts
|
42
|
+
io.puts content
|
43
|
+
end
|
44
|
+
|
45
|
+
def generate_module_stubs(object)
|
46
|
+
filename = stub_filename(object)
|
47
|
+
ensure_exist(File.dirname(filename))
|
48
|
+
StubFile.open(filename, 'w') { |file|
|
49
|
+
file.puts file_header(object)
|
50
|
+
file.puts
|
51
|
+
file.puts namespace_definition(object)
|
52
|
+
print_section(file, 'Extends', generate_mixins(object, :class))
|
53
|
+
print_section(file, 'Includes', generate_mixins(object, :instance))
|
54
|
+
print_section(file, 'Constants', generate_constants_grouped(object))
|
55
|
+
print_section(file, 'Class Methods', generate_class_methods(object))
|
56
|
+
print_section(file, 'Instance Methods', generate_instance_methods(object))
|
57
|
+
file.puts
|
58
|
+
file.puts file_footer(object)
|
59
|
+
}
|
60
|
+
#trim_trailing_white_space(filename)
|
61
|
+
end
|
62
|
+
|
63
|
+
def file_header(object)
|
64
|
+
header = StringIO.new
|
65
|
+
header.puts "# Copyright:: Copyright #{Time.now.year} Trimble Inc."
|
66
|
+
header.puts "# License:: The MIT License (MIT)"
|
67
|
+
#header.puts "# Generated:: #{Time.now.strftime('%F %R')}"
|
68
|
+
header.string
|
69
|
+
end
|
70
|
+
|
71
|
+
def file_footer(object)
|
72
|
+
return if object.root?
|
73
|
+
footer = StringIO.new
|
74
|
+
footer.puts 'end'
|
75
|
+
footer.string
|
76
|
+
end
|
77
|
+
|
78
|
+
def namespace_definition(object)
|
79
|
+
return if object.root?
|
80
|
+
definition = "#{object.type} #{object.path}"
|
81
|
+
if object.type == :class && object.superclass.name != :Object
|
82
|
+
definition << " < #{object.superclass.path}"
|
83
|
+
end
|
84
|
+
output = StringIO.new
|
85
|
+
output.puts generate_docstring(object)
|
86
|
+
output.puts definition
|
87
|
+
output.string
|
88
|
+
end
|
89
|
+
|
90
|
+
def output_path
|
91
|
+
options.serializer.options[:basepath] || File.join(Dir.pwd, 'stubs')
|
92
|
+
end
|
93
|
+
|
94
|
+
def stubs_root_path
|
95
|
+
ensure_exist(output_path)
|
96
|
+
end
|
97
|
+
|
98
|
+
def stubs_lib_path
|
99
|
+
ensure_exist(File.join(stubs_root_path, 'lib'))
|
100
|
+
end
|
101
|
+
|
102
|
+
def stubs_gem_path
|
103
|
+
ensure_exist(File.join(stubs_lib_path, 'sketchup-api-stubs'))
|
104
|
+
end
|
105
|
+
|
106
|
+
def stubs_path
|
107
|
+
ensure_exist(File.join(stubs_gem_path, 'stubs'))
|
108
|
+
end
|
109
|
+
|
110
|
+
def stub_filename(object)
|
111
|
+
basename = object.path.gsub('::', '/')
|
112
|
+
basename = '_top_level' if basename.empty?
|
113
|
+
File.join(stubs_path, "#{basename}.rb")
|
114
|
+
end
|
115
|
+
|
116
|
+
# A stable sort_by method.
|
117
|
+
#
|
118
|
+
# @param [Enumerable]
|
119
|
+
# @return [Array]
|
120
|
+
def stable_sort_by(list)
|
121
|
+
list.each_with_index.sort_by { |item, i| [yield(item), i] }.map(&:first)
|
122
|
+
end
|
123
|
+
|
124
|
+
CAMELCASE_CONSTANT = /^([A-Z]+[a-z]+)/
|
125
|
+
|
126
|
+
def group_constant(constant)
|
127
|
+
constant_name = constant.name.to_s
|
128
|
+
MANUAL_CONSTANT_GROUPS.each { |rule|
|
129
|
+
if rule[:constants]
|
130
|
+
return rule[:group] if rule[:constants].include?(constant_name)
|
131
|
+
else
|
132
|
+
return rule[:group] if rule[:regex].match(constant_name)
|
133
|
+
end
|
134
|
+
}
|
135
|
+
if constant_name.include?('_')
|
136
|
+
constant_name.split('_').first
|
137
|
+
else
|
138
|
+
constant_name[CAMELCASE_CONSTANT] || constant_name
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Sorts and groups constants for easier reading.
|
143
|
+
def generate_constants_grouped(object)
|
144
|
+
constants = run_verifier(object.constants(object_options))
|
145
|
+
# The constants are not sorted before chunking. This is because `chunk` groups
|
146
|
+
# consecutive items - and we want to chunk them based their relationship
|
147
|
+
# with each other. This ensure that constants that doesn't follow the normal
|
148
|
+
# pattern of PREFIX_SOME_NAME will still be grouped next to each other.
|
149
|
+
groups = constants.chunk { |constant|
|
150
|
+
group_constant(constant)
|
151
|
+
}
|
152
|
+
grouped_output = groups.map { |group, group_constants|
|
153
|
+
output = StringIO.new
|
154
|
+
# Each group itself is sorted in order to more easily scan the list.
|
155
|
+
sorted = stable_sort_by(group_constants, &:name)
|
156
|
+
sorted.each { |constant|
|
157
|
+
output.puts " #{constant.name} = nil # Stub value."
|
158
|
+
}
|
159
|
+
output.string
|
160
|
+
}
|
161
|
+
# Finally each group is also sorted, again to ease scanning for a particular
|
162
|
+
# name. We simply use the first character of each group.
|
163
|
+
stable_sort_by(grouped_output) { |item| item.lstrip[0] }.join("\n")
|
164
|
+
end
|
165
|
+
|
166
|
+
# Sort constants without grouping.
|
167
|
+
def generate_constants(object)
|
168
|
+
output = StringIO.new
|
169
|
+
constants = run_verifier(object.constants(object_options))
|
170
|
+
constants = stable_sort_by(constants, &:name)
|
171
|
+
constants.each { |constant|
|
172
|
+
output.puts " #{constant.name} = nil # Stub value."
|
173
|
+
}
|
174
|
+
output.string
|
175
|
+
end
|
176
|
+
|
177
|
+
def generate_mixins(object, scope)
|
178
|
+
output = StringIO.new
|
179
|
+
mixin_type = (scope == :class) ? 'extend' : 'include'
|
180
|
+
mixins = run_verifier(object.mixins(scope))
|
181
|
+
mixins = stable_sort_by(mixins, &:path)
|
182
|
+
mixins.each { |mixin|
|
183
|
+
output.puts " #{mixin_type} #{mixin.path}"
|
184
|
+
}
|
185
|
+
output.string
|
186
|
+
end
|
187
|
+
|
188
|
+
def generate_class_methods(object)
|
189
|
+
generate_methods(object, :class, 'self.')
|
190
|
+
end
|
191
|
+
|
192
|
+
def generate_instance_methods(object)
|
193
|
+
generate_methods(object, :instance)
|
194
|
+
end
|
195
|
+
|
196
|
+
def generate_methods(object, scope, prefix = '')
|
197
|
+
methods = sort_methods(object, scope)
|
198
|
+
signatures = methods.map { |method|
|
199
|
+
output = StringIO.new
|
200
|
+
# Cannot use `methods.signature` here as it would return the C/C++ function
|
201
|
+
# signature. Must generate one from the YARD data.
|
202
|
+
signature = generate_method_signature(method)
|
203
|
+
# NOTE: We must call `generate_docstring` after `generate_method_signature`
|
204
|
+
# because `generate_method_signature` will also clean up docstrings with
|
205
|
+
# a single @overload tag.
|
206
|
+
output.puts generate_docstring(method, 1)
|
207
|
+
output.puts " def #{prefix}#{signature}"
|
208
|
+
output.puts " end"
|
209
|
+
# Include aliases.
|
210
|
+
method.aliases.each { |method_alias|
|
211
|
+
output.puts " alias_method :#{method_alias.name}, :#{method.name}"
|
212
|
+
}
|
213
|
+
output.string
|
214
|
+
}
|
215
|
+
signatures.join("\n")
|
216
|
+
end
|
217
|
+
|
218
|
+
# NOTE: This may modify the docstring of the object.
|
219
|
+
def generate_method_signature(object)
|
220
|
+
signature = "#{object.name}"
|
221
|
+
# If there is a single overload then use that as the parameter list. Many of
|
222
|
+
# the SketchUp Ruby API methods will have this as it was safer to add an
|
223
|
+
# @overload tag instead of renaming the function argument names.
|
224
|
+
overloads = object.docstring.tags(:overload)
|
225
|
+
if overloads.size == 1
|
226
|
+
overload = overloads.first
|
227
|
+
parameters = overload.parameters
|
228
|
+
# Move the tags from the @overload tag to the root of the docstring. No need
|
229
|
+
# for a single overload tag - it's unexpected when reading the source.
|
230
|
+
object.docstring.add_tag(*overload.tags)
|
231
|
+
object.docstring.delete_tags(:overload)
|
232
|
+
else
|
233
|
+
parameters = object.parameters
|
234
|
+
end
|
235
|
+
# Compile the signature for the arguments and default values.
|
236
|
+
params = parameters.map { |param|
|
237
|
+
param.last.nil? ? param.first : param.join(' = ')
|
238
|
+
if param.last.nil?
|
239
|
+
param.first
|
240
|
+
else
|
241
|
+
if param.first.end_with?(':')
|
242
|
+
# Named param.
|
243
|
+
param.join(' ')
|
244
|
+
else
|
245
|
+
# Positional param.
|
246
|
+
param.join(' = ')
|
247
|
+
end
|
248
|
+
end
|
249
|
+
}.join(', ')
|
250
|
+
signature << "(#{params})" unless params.empty?
|
251
|
+
signature
|
252
|
+
end
|
253
|
+
|
254
|
+
def generate_docstring(object, indent_step = 0)
|
255
|
+
output = StringIO.new
|
256
|
+
indent = ' ' * indent_step
|
257
|
+
docstring = object.docstring
|
258
|
+
docstring.delete_tags(:par) # Remove obsolete @par tags.
|
259
|
+
docstring.to_raw.lines.each { |line|
|
260
|
+
# Naive check for tags with no indent - if it is we insert an extra line
|
261
|
+
# in order to get some space for easier reader. Doing it this way in order
|
262
|
+
# to avoid hacking YARD too much.
|
263
|
+
output.puts "#{indent}#" if line.start_with?('@')
|
264
|
+
# This is the original docstring line.
|
265
|
+
output.puts "#{indent}# #{line}"
|
266
|
+
}
|
267
|
+
output.string
|
268
|
+
end
|
269
|
+
|
270
|
+
def sort_methods(object, scope)
|
271
|
+
methods = run_verifier(object.meths(object_options))
|
272
|
+
objects = methods.select { |method|
|
273
|
+
!method.is_alias? && method.scope == scope
|
274
|
+
}
|
275
|
+
stable_sort_by(objects, &:name)
|
276
|
+
end
|
277
|
+
|
278
|
+
def object_options
|
279
|
+
{
|
280
|
+
:inherited => false,
|
281
|
+
:included => false
|
282
|
+
}
|
283
|
+
end
|
284
|
+
|
285
|
+
|
286
|
+
def ensure_exist(path)
|
287
|
+
unless File.directory?(path)
|
288
|
+
FileUtils.mkdir_p(path)
|
289
|
+
end
|
290
|
+
path
|
291
|
+
end
|
292
|
+
|
293
|
+
|
294
|
+
class StubFile < File
|
295
|
+
|
296
|
+
def puts(*args)
|
297
|
+
case args.size
|
298
|
+
when 0
|
299
|
+
super
|
300
|
+
when 1
|
301
|
+
super trim_trailing_white_space(args[0].to_s)
|
302
|
+
else
|
303
|
+
raise NotImplementedError
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
private
|
308
|
+
|
309
|
+
TRAILING_WHITE_SPACE = /([\t ]+)$/
|
310
|
+
def trim_trailing_white_space(string)
|
311
|
+
string.gsub(TRAILING_WHITE_SPACE, '')
|
312
|
+
end
|
313
|
+
|
314
|
+
end
|
315
|
+
|
316
|
+
|
317
|
+
MANUAL_CONSTANT_GROUPS = [
|
318
|
+
# UI.messagebox return values.
|
319
|
+
{
|
320
|
+
constants: %w{IDABORT IDCANCEL IDIGNORE IDNO IDOK IDRETRY IDYES},
|
321
|
+
group: 'ID_MESSAGEBOX'
|
322
|
+
},
|
323
|
+
# Axes
|
324
|
+
{
|
325
|
+
constants: %w{X_AXIS Y_AXIS Z_AXIS},
|
326
|
+
group: 'AXES'
|
327
|
+
},
|
328
|
+
# Axes 2D
|
329
|
+
{
|
330
|
+
constants: %w{X_AXIS_2D Y_AXIS_2D},
|
331
|
+
group: 'AXES2D'
|
332
|
+
},
|
333
|
+
# Transformation
|
334
|
+
{
|
335
|
+
constants: %w{IDENTITY IDENTITY_2D},
|
336
|
+
group: 'IDENTITY'
|
337
|
+
},
|
338
|
+
# Geom::PolygonMesh
|
339
|
+
{
|
340
|
+
constants: %w{
|
341
|
+
AUTO_SOFTEN HIDE_BASED_ON_INDEX NO_SMOOTH_OR_HIDE SMOOTH_SOFT_EDGES
|
342
|
+
SOFTEN_BASED_ON_INDEX},
|
343
|
+
group: 'SOFTEN'
|
344
|
+
},
|
345
|
+
# Sketchup::Importer
|
346
|
+
# The other constants start with Import, this was odd one out.
|
347
|
+
{
|
348
|
+
constants: %w{ImporterNotFound},
|
349
|
+
group: 'Import'
|
350
|
+
},
|
351
|
+
# Sketchup::Http
|
352
|
+
{
|
353
|
+
constants: %w{DELETE GET HEAD OPTIONS PATCH POST PUT},
|
354
|
+
group: 'HTTP'
|
355
|
+
},
|
356
|
+
# Sketchup::Licensing
|
357
|
+
{
|
358
|
+
constants: %w{EXPIRED LICENSED NOT_LICENSED TRIAL TRIAL_EXPIRED},
|
359
|
+
group: 'EX_LICENSE'
|
360
|
+
},
|
361
|
+
# Sketchup::Model
|
362
|
+
{
|
363
|
+
constants: %w{Make MakeTrial ProLicensed ProTrial},
|
364
|
+
group: 'SU_LICENSE'
|
365
|
+
},
|
366
|
+
# Sketchup::RenderingOptions
|
367
|
+
# Most ROP constants start with ROPSet, with a handful of exceptions.
|
368
|
+
{
|
369
|
+
regex: /^ROP/,
|
370
|
+
group: 'ROP'
|
371
|
+
},
|
372
|
+
]
|