yard-sketchup 1.4.1 → 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) 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 +155 -141
  9. data/lib/yard-sketchup/templates/default/fulldoc/html/full_list_object_types.erb +1 -1
  10. data/lib/yard-sketchup/templates/default/fulldoc/html/images/Ruby.svg +1 -1
  11. data/lib/yard-sketchup/templates/default/fulldoc/html/images/sketchup-logo.svg +19 -19
  12. data/lib/yard-sketchup/templates/default/fulldoc/html/images/trimble-logo-white.svg +29 -29
  13. data/lib/yard-sketchup/templates/default/fulldoc/html/js/sketchup.js +37 -37
  14. data/lib/yard-sketchup/templates/default/fulldoc/html/setup.rb +75 -75
  15. data/lib/yard-sketchup/templates/default/layout/html/embed_meta.erb +78 -78
  16. data/lib/yard-sketchup/templates/default/layout/html/footer.erb +4 -4
  17. data/lib/yard-sketchup/templates/default/layout/html/headers.erb +15 -15
  18. data/lib/yard-sketchup/templates/default/layout/html/layout.erb +56 -56
  19. data/lib/yard-sketchup/templates/default/layout/html/navbar.erb +36 -36
  20. data/lib/yard-sketchup/templates/default/layout/html/setup.rb +25 -25
  21. data/lib/yard-sketchup/templates/default/method_details/html/method_signature.erb +30 -26
  22. data/lib/yard-sketchup/templates/default/method_details/setup.rb +11 -11
  23. data/lib/yard-sketchup/templates/default/module/html/box_info.erb +37 -37
  24. data/lib/yard-sketchup/templates/default/module/html/constant_summary.erb +19 -17
  25. data/lib/yard-sketchup/templates/default/module/html/method_summary.erb +18 -18
  26. data/lib/yard-sketchup/templates/inheritance/fulldoc/text/setup.rb +54 -54
  27. data/lib/yard-sketchup/templates/stubs/fulldoc/text/setup.rb +372 -372
  28. data/lib/yard-sketchup/templates/versions/fulldoc/text/setup.rb +25 -25
  29. data/lib/yard-sketchup/version.rb +3 -3
  30. data/lib/yard-sketchup/yard/html_helper.rb +16 -16
  31. data/lib/yard-sketchup.rb +37 -37
  32. data/yard-sketchup.gemspec +26 -26
  33. metadata +3 -3
@@ -1,372 +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
- 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
- ]
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
+ ]