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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +15 -15
  3. data/lib/yard-sketchup/patches/c_base_handler.rb +52 -52
  4. data/lib/yard-sketchup/stubs/autoload.rb +134 -134
  5. data/lib/yard-sketchup/templates/changelog/fulldoc/text/setup.rb +44 -44
  6. data/lib/yard-sketchup/templates/coverage/fulldoc/text/setup.rb +41 -41
  7. data/lib/yard-sketchup/templates/default/fulldoc/html/css/rubyapi.css +10 -10
  8. data/lib/yard-sketchup/templates/default/fulldoc/html/css/sketchup.css +141 -141
  9. data/lib/yard-sketchup/templates/default/fulldoc/html/favicon.ico +0 -0
  10. data/lib/yard-sketchup/templates/default/fulldoc/html/full_list_object_types.erb +1 -1
  11. data/lib/yard-sketchup/templates/default/fulldoc/html/images/Ruby.svg +1 -1
  12. data/lib/yard-sketchup/templates/default/fulldoc/html/images/sketchup-logo.svg +19 -19
  13. data/lib/yard-sketchup/templates/default/fulldoc/html/images/trimble-logo-white.svg +29 -29
  14. data/lib/yard-sketchup/templates/default/fulldoc/html/js/sketchup.js +37 -37
  15. data/lib/yard-sketchup/templates/default/fulldoc/html/setup.rb +75 -67
  16. data/lib/yard-sketchup/templates/default/layout/html/embed_meta.erb +78 -78
  17. data/lib/yard-sketchup/templates/default/layout/html/footer.erb +4 -4
  18. data/lib/yard-sketchup/templates/default/layout/html/headers.erb +15 -15
  19. data/lib/yard-sketchup/templates/default/layout/html/layout.erb +56 -55
  20. data/lib/yard-sketchup/templates/default/layout/html/navbar.erb +36 -36
  21. data/lib/yard-sketchup/templates/default/layout/html/setup.rb +25 -25
  22. data/lib/yard-sketchup/templates/default/method_details/html/method_signature.erb +25 -25
  23. data/lib/yard-sketchup/templates/default/method_details/setup.rb +11 -11
  24. data/lib/yard-sketchup/templates/default/module/html/box_info.erb +37 -37
  25. data/lib/yard-sketchup/templates/default/module/html/constant_summary.erb +17 -17
  26. data/lib/yard-sketchup/templates/default/module/html/method_summary.erb +18 -18
  27. data/lib/yard-sketchup/templates/inheritance/fulldoc/text/setup.rb +54 -54
  28. data/lib/yard-sketchup/templates/stubs/fulldoc/text/setup.rb +372 -361
  29. data/lib/yard-sketchup/templates/versions/fulldoc/text/setup.rb +25 -25
  30. data/lib/yard-sketchup/version.rb +3 -3
  31. data/lib/yard-sketchup/yard/html_helper.rb +16 -0
  32. data/lib/yard-sketchup.rb +37 -36
  33. data/yard-sketchup.gemspec +26 -25
  34. 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
- }.join(', ')
239
- signature << "(#{params})" unless params.empty?
240
- signature
241
- end
242
-
243
- def generate_docstring(object, indent_step = 0)
244
- output = StringIO.new
245
- indent = ' ' * indent_step
246
- docstring = object.docstring
247
- docstring.delete_tags(:par) # Remove obsolete @par tags.
248
- docstring.to_raw.lines.each { |line|
249
- # Naive check for tags with no indent - if it is we insert an extra line
250
- # in order to get some space for easier reader. Doing it this way in order
251
- # to avoid hacking YARD too much.
252
- output.puts "#{indent}#" if line.start_with?('@')
253
- # This is the original docstring line.
254
- output.puts "#{indent}# #{line}"
255
- }
256
- output.string
257
- end
258
-
259
- def sort_methods(object, scope)
260
- methods = run_verifier(object.meths(object_options))
261
- objects = methods.select { |method|
262
- !method.is_alias? && method.scope == scope
263
- }
264
- stable_sort_by(objects, &:name)
265
- end
266
-
267
- def object_options
268
- {
269
- :inherited => false,
270
- :included => false
271
- }
272
- end
273
-
274
-
275
- def ensure_exist(path)
276
- unless File.directory?(path)
277
- FileUtils.mkdir_p(path)
278
- end
279
- path
280
- end
281
-
282
-
283
- class StubFile < File
284
-
285
- def puts(*args)
286
- case args.size
287
- when 0
288
- super
289
- when 1
290
- super trim_trailing_white_space(args[0].to_s)
291
- else
292
- raise NotImplementedError
293
- end
294
- end
295
-
296
- private
297
-
298
- TRAILING_WHITE_SPACE = /([\t ]+)$/
299
- def trim_trailing_white_space(string)
300
- string.gsub(TRAILING_WHITE_SPACE, '')
301
- end
302
-
303
- end
304
-
305
-
306
- MANUAL_CONSTANT_GROUPS = [
307
- # UI.messagebox return values.
308
- {
309
- constants: %w{IDABORT IDCANCEL IDIGNORE IDNO IDOK IDRETRY IDYES},
310
- group: 'ID_MESSAGEBOX'
311
- },
312
- # Axes
313
- {
314
- constants: %w{X_AXIS Y_AXIS Z_AXIS},
315
- group: 'AXES'
316
- },
317
- # Axes 2D
318
- {
319
- constants: %w{X_AXIS_2D Y_AXIS_2D},
320
- group: 'AXES2D'
321
- },
322
- # Transformation
323
- {
324
- constants: %w{IDENTITY IDENTITY_2D},
325
- group: 'IDENTITY'
326
- },
327
- # Geom::PolygonMesh
328
- {
329
- constants: %w{
330
- AUTO_SOFTEN HIDE_BASED_ON_INDEX NO_SMOOTH_OR_HIDE SMOOTH_SOFT_EDGES
331
- SOFTEN_BASED_ON_INDEX},
332
- group: 'SOFTEN'
333
- },
334
- # Sketchup::Importer
335
- # The other constants start with Import, this was odd one out.
336
- {
337
- constants: %w{ImporterNotFound},
338
- group: 'Import'
339
- },
340
- # Sketchup::Http
341
- {
342
- constants: %w{DELETE GET HEAD OPTIONS PATCH POST PUT},
343
- group: 'HTTP'
344
- },
345
- # Sketchup::Licensing
346
- {
347
- constants: %w{EXPIRED LICENSED NOT_LICENSED TRIAL TRIAL_EXPIRED},
348
- group: 'EX_LICENSE'
349
- },
350
- # Sketchup::Model
351
- {
352
- constants: %w{Make MakeTrial ProLicensed ProTrial},
353
- group: 'SU_LICENSE'
354
- },
355
- # Sketchup::RenderingOptions
356
- # Most ROP constants start with ROPSet, with a handful of exceptions.
357
- {
358
- regex: /^ROP/,
359
- group: 'ROP'
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
+ ]