class Webgen::PathHandler::Api

Path handler for Ruby API documentation via rdoc.

Constants

MANDATORY_INFOS

The mandatory meta info keys that need to be set on an api path.

Public Instance Methods

adapt_rdoc_class(api_path, klass) click to toggle source

Adapt a RDoc class/module object to provide a different output path depending on the output_structure meta information of the API path.

    # File lib/webgen/path_handler/api.rb
143 def adapt_rdoc_class(api_path, klass)
144   case api_path['output_structure']
145   when 'hierarchical'
146     api_path['use_proxy_path'] = false
147     def klass.http_url(prefix)
148       if classes_and_modules.size > 0
149         super(prefix).sub(/\.html/, '/index.html')
150       else
151         super(prefix)
152       end
153     end
154   else
155     api_path['use_proxy_path'] = true
156   end
157 end
create_fragment_node_for_constant(api_path, parent_node, constant) click to toggle source

Create a fragment node for the given constant.

A link definition entry for the method is also created.

    # File lib/webgen/path_handler/api.rb
198 def create_fragment_node_for_constant(api_path, parent_node, constant)
199   constant_url = "#{parent_node.alcn.sub(/#.*$/, '')}##{constant.name}"
200   path = Webgen::Path.new(constant_url,
201                           {'handler' => 'copy', 'modified_at' => api_path['modified_at'],
202                            'parent_alcn' => parent_node.alcn,
203                            'pipeline' => [], 'no_output' => true, 'title' => constant.name})
204   @website.ext.path_handler.create_secondary_nodes(path)
205   add_link_definition(api_path, constant.full_name, constant_url, constant.full_name)
206 end
create_fragment_node_for_method(api_path, parent_node, method) click to toggle source

Create a fragment node for the given method.

A link definition entry for the method is also created.

    # File lib/webgen/path_handler/api.rb
246 def create_fragment_node_for_method(api_path, parent_node, method)
247   method_url = "#{parent_node.alcn.sub(/#.*$/, '')}##{method.aref}"
248   path = Webgen::Path.new(method_url,
249                           {'handler' => 'copy', 'modified_at' => api_path['modified_at'],
250                             'parent_alcn' => parent_node.alcn,
251                             'pipeline' => [], 'no_output' => true, 'title' => method.name})
252   @website.ext.path_handler.create_secondary_nodes(path)
253   add_link_definition(api_path, method.full_name, method_url, method.full_name)
254 end
create_fragment_nodes_for_attributes(api_path, parent_node, klass) click to toggle source

Creates fragment nodes for attributes under the “Attributes” fragment.

    # File lib/webgen/path_handler/api.rb
210 def create_fragment_nodes_for_attributes(api_path, parent_node, klass)
211   return if klass.attributes.none? {|attr| attr.display? }
212   attributes_url = "#{parent_node.alcn}#Attributes"
213   path = Webgen::Path.new(attributes_url,
214                           {'handler' => 'copy', 'modified_at' => api_path['modified_at'],
215                             'parent_alcn' => parent_node.alcn,
216                            'pipeline' => [], 'no_output' => true, 'title' => "Attributes"})
217   attr_node = @website.ext.path_handler.create_secondary_nodes(path).first
218   klass.attributes.sort_by(&:name).each do |attribute|
219     create_fragment_node_for_method(api_path, attr_node, attribute)
220   end
221 end
create_fragment_nodes_for_constants(api_path, klass_node, klass) click to toggle source

Creates fragment nodes for constants under the “Constants” fragment.

    # File lib/webgen/path_handler/api.rb
182 def create_fragment_nodes_for_constants(api_path, klass_node, klass)
183   return if klass.constants.none? {|const| const.display? }
184   constants_url = "#{klass_node.alcn}#Constants"
185   path = Webgen::Path.new(constants_url,
186                           {'handler' => 'copy', 'modified_at' => api_path['modified_at'],
187                            'pipeline' => [], 'no_output' => true, 'title' => "Constants"})
188   const_node = @website.ext.path_handler.create_secondary_nodes(path).first
189   klass.constants.sort_by(&:name).each do |const|
190     create_fragment_node_for_constant(api_path, const_node, const)
191   end
192 end
create_fragment_nodes_for_methods(api_path, klass_node, klass) click to toggle source

Creates fragment nodes for methods under the “Class Methods” or “Instance Methods” fragments.

    # File lib/webgen/path_handler/api.rb
226 def create_fragment_nodes_for_methods(api_path, klass_node, klass)
227   ["Class", "Instance"].each do |type|
228     method_list = klass.send("#{type.downcase}_method_list")
229     next if method_list.empty?
230     meth_url = "#{klass_node.alcn}##{type}-Methods"
231     path = Webgen::Path.new(meth_url,
232                             {'handler' => 'copy', 'modified_at' => api_path['modified_at'],
233                               'pipeline' => [], 'no_output' => true,
234                               'title' => "#{type} Methods"})
235     meth_node = @website.ext.path_handler.create_secondary_nodes(path).first
236     method_list.sort_by(&:name).each do |method|
237       create_fragment_node_for_method(api_path, meth_node, method)
238     end
239   end
240 end
create_nodes(path, blocks) click to toggle source

Create the feed nodes.

   # File lib/webgen/path_handler/api.rb
24 def create_nodes(path, blocks)
25   if MANDATORY_INFOS.any? {|t| path.meta_info[t].nil?}
26     raise Webgen::NodeCreationError.new("At least one of #{MANDATORY_INFOS.join('/')} is missing",
27                                         "path_handler.api", path)
28   end
29 
30   path['api_name'] ||= path.basename
31   path['dir_name'] ||= path.basename
32 
33   cache_dir = @website.tmpdir(File.join('path_handler.api', path['api_name']))
34   rdoc = rdoc_object(path['rdoc_options'], cache_dir)
35   output_flag_file = rdoc.output_flag_file(cache_dir)
36 
37   dir_node = create_directory(path, Webgen::Path.new(path.parent_path + path['dir_name'] + '/'), false)
38 
39   api = OpenStruct.new
40   api.directory = dir_node
41   api.class_nodes = {}
42   api.file_nodes = {}
43 
44   rdoc.store.all_classes_and_modules.sort.each do |klass|
45     adapt_rdoc_class(path, klass)
46     klass_node = create_page_node_for_class(path, dir_node, klass, output_flag_file)
47     api.class_nodes[klass.full_name] = klass_node
48     klass_node.node_info[:api] = api
49     create_fragment_nodes_for_constants(path, klass_node, klass)
50     create_fragment_nodes_for_attributes(path, klass_node, klass)
51     create_fragment_nodes_for_methods(path, klass_node, klass)
52   end
53 
54   rdoc.store.all_files.sort.each do |file|
55     next unless file.text?
56     file_node = create_page_node_for_file(path, dir_node, file, output_flag_file)
57     api.file_nodes[file.full_name] = file_node
58     file_node.node_info[:api] = api
59   end
60 
61   nil
62 end
create_page_node_for_class(api_path, dir_node, klass, output_flag_file) click to toggle source

Create a page node for the given class klass and return it.

A link definition entry for the class is also created.

    # File lib/webgen/path_handler/api.rb
163 def create_page_node_for_class(api_path, dir_node, klass, output_flag_file)
164   klass_path_str = klass.http_url(dir_node.alcn)
165 
166   create_directory(api_path, Webgen::Path.new(File.dirname(klass_path_str) + '/'), api_path['use_proxy_path'])
167 
168   path = Webgen::Path.new(klass_path_str, 'handler' => 'page', 'modified_at' => api_path['modified_at'],
169                           'title' => "#{klass.full_name}", 'api_class_name' => klass.full_name,
170                           'api_name' => api_path['api_name'], 'template' => api_path['api_template'])
171   node = @website.ext.path_handler.create_secondary_nodes(path).first
172 
173   node.node_info[:rdoc_object] = klass
174   @website.ext.item_tracker.add(node, :file, output_flag_file)
175   add_link_definition(api_path, klass.full_name, node.alcn, klass.full_name)
176 
177   node
178 end
create_page_node_for_file(api_path, dir_node, file, output_flag_file) click to toggle source

Create a page node for the given file and return it.

    # File lib/webgen/path_handler/api.rb
258 def create_page_node_for_file(api_path, dir_node, file, output_flag_file)
259   file_path_str = file.http_url(dir_node.alcn)
260 
261   create_directory(api_path, Webgen::Path.new(File.dirname(file_path_str) + '/'))
262 
263   path = Webgen::Path.new(file_path_str, 'handler' => 'page', 'modified_at' => api_path['modified_at'],
264                           'title' => "File #{file.full_name}", 'api_file_name' => file.full_name,
265                           'api_name' => api_path['api_name'], 'template' => api_path['api_template'])
266   node = @website.ext.path_handler.create_secondary_nodes(path).first
267 
268   node.node_info[:rdoc_object] = file
269   @website.ext.item_tracker.add(node, :file, output_flag_file)
270 
271   node
272 end
rdoc_object(options, cache_dir) click to toggle source

Create the RDoc instance and use it for generating the API data.

If possible, cached data available under cache_dir is used.

    # File lib/webgen/path_handler/api.rb
 87     def rdoc_object(options, cache_dir)
 88       start_time = Time.now
 89 
 90       rdoc = RDoc::RDoc.new
 91       rdoc.options = rdoc_options(options)
 92       rdoc.store = rdoc_store(rdoc.options, cache_dir)
 93 
 94       rdoc.last_modified.replace(rdoc.setup_output_dir(cache_dir, false))
 95 
 96       if !(rdoc.parse_files(rdoc.options.files)).empty?
 97         rdoc.store.complete(rdoc.options.visibility)
 98         rdoc.store.save
 99         rdoc.update_output_dir(cache_dir, start_time, rdoc.last_modified)
100       end
101       rdoc.store.load_all
102 
103       # We need a dummy generator with some methods
104       rdoc.generator = Object.new
105       def (rdoc.generator).class_dir; nil; end
106       def (rdoc.generator).file_dir; nil; end
107 
108       rdoc
109     end
110     protected :rdoc_object
111 
112     # Return a fully initialized RDoc::Options object.
113     #
114     # Some of the user specified options may not be used if they would interfere with this class'
115     # job.
116     def rdoc_options(user_options)
117       user_options = Shellwords.split(user_options) if user_options.kind_of?(String)
118       options = RDoc::Options.new
119       options.parse(user_options)
120       options.verbosity = 0
121       options.dry_run = false
122       options.update_output_dir = true
123       options.force_output = false
124       options.finish
125       options
126     end
127     protected :rdoc_options
128 
129     # Return a fully initialized RDoc::Store object.
130     def rdoc_store(options, cache_dir)
131       store = RDoc::Store.new(cache_dir)
132       store.encoding = options.encoding
133       store.dry_run = options.dry_run
134       store.main = options.main_page
135       store.title = options.title
136       store.load_cache
137       store
138     end
139     protected :rdoc_store
140 
141     # Adapt a RDoc class/module object to provide a different output path depending on the
142     # output_structure meta information of the API path.
143     def adapt_rdoc_class(api_path, klass)
144       case api_path['output_structure']
145       when 'hierarchical'
146         api_path['use_proxy_path'] = false
147         def klass.http_url(prefix)
148           if classes_and_modules.size > 0
149             super(prefix).sub(/\.html/, '/index.html')
150           else
151             super(prefix)
152           end
153         end
154       else
155         api_path['use_proxy_path'] = true
156       end
157     end
158     protected :adapt_rdoc_class
159 
160     # Create a page node for the given class +klass+ and return it.
161     #
162     # A link definition entry for the class is also created.
163     def create_page_node_for_class(api_path, dir_node, klass, output_flag_file)
164       klass_path_str = klass.http_url(dir_node.alcn)
165 
166       create_directory(api_path, Webgen::Path.new(File.dirname(klass_path_str) + '/'), api_path['use_proxy_path'])
167 
168       path = Webgen::Path.new(klass_path_str, 'handler' => 'page', 'modified_at' => api_path['modified_at'],
169                               'title' => "#{klass.full_name}", 'api_class_name' => klass.full_name,
170                               'api_name' => api_path['api_name'], 'template' => api_path['api_template'])
171       node = @website.ext.path_handler.create_secondary_nodes(path).first
172 
173       node.node_info[:rdoc_object] = klass
174       @website.ext.item_tracker.add(node, :file, output_flag_file)
175       add_link_definition(api_path, klass.full_name, node.alcn, klass.full_name)
176 
177       node
178     end
179     protected :create_page_node_for_class
180 
181     # Creates fragment nodes for constants under the "Constants" fragment.
182     def create_fragment_nodes_for_constants(api_path, klass_node, klass)
183       return if klass.constants.none? {|const| const.display? }
184       constants_url = "#{klass_node.alcn}#Constants"
185       path = Webgen::Path.new(constants_url,
186                               {'handler' => 'copy', 'modified_at' => api_path['modified_at'],
187                                'pipeline' => [], 'no_output' => true, 'title' => "Constants"})
188       const_node = @website.ext.path_handler.create_secondary_nodes(path).first
189       klass.constants.sort_by(&:name).each do |const|
190         create_fragment_node_for_constant(api_path, const_node, const)
191       end
192     end
193     protected :create_fragment_nodes_for_constants
194 
195     # Create a fragment node for the given constant.
196     #
197     # A link definition entry for the method is also created.
198     def create_fragment_node_for_constant(api_path, parent_node, constant)
199       constant_url = "#{parent_node.alcn.sub(/#.*$/, '')}##{constant.name}"
200       path = Webgen::Path.new(constant_url,
201                               {'handler' => 'copy', 'modified_at' => api_path['modified_at'],
202                                'parent_alcn' => parent_node.alcn,
203                                'pipeline' => [], 'no_output' => true, 'title' => constant.name})
204       @website.ext.path_handler.create_secondary_nodes(path)
205       add_link_definition(api_path, constant.full_name, constant_url, constant.full_name)
206     end
207     protected :create_fragment_node_for_constant
208 
209     # Creates fragment nodes for attributes under the "Attributes" fragment.
210     def create_fragment_nodes_for_attributes(api_path, parent_node, klass)
211       return if klass.attributes.none? {|attr| attr.display? }
212       attributes_url = "#{parent_node.alcn}#Attributes"
213       path = Webgen::Path.new(attributes_url,
214                               {'handler' => 'copy', 'modified_at' => api_path['modified_at'],
215                                 'parent_alcn' => parent_node.alcn,
216                                'pipeline' => [], 'no_output' => true, 'title' => "Attributes"})
217       attr_node = @website.ext.path_handler.create_secondary_nodes(path).first
218       klass.attributes.sort_by(&:name).each do |attribute|
219         create_fragment_node_for_method(api_path, attr_node, attribute)
220       end
221     end
222     protected :create_fragment_nodes_for_attributes
223 
224     # Creates fragment nodes for methods under the "Class Methods" or "Instance Methods"
225     # fragments.
226     def create_fragment_nodes_for_methods(api_path, klass_node, klass)
227       ["Class", "Instance"].each do |type|
228         method_list = klass.send("#{type.downcase}_method_list")
229         next if method_list.empty?
230         meth_url = "#{klass_node.alcn}##{type}-Methods"
231         path = Webgen::Path.new(meth_url,
232                                 {'handler' => 'copy', 'modified_at' => api_path['modified_at'],
233                                   'pipeline' => [], 'no_output' => true,
234                                   'title' => "#{type} Methods"})
235         meth_node = @website.ext.path_handler.create_secondary_nodes(path).first
236         method_list.sort_by(&:name).each do |method|
237           create_fragment_node_for_method(api_path, meth_node, method)
238         end
239       end
240     end
241     protected :create_fragment_nodes_for_attributes
242 
243     # Create a fragment node for the given method.
244     #
245     # A link definition entry for the method is also created.
246     def create_fragment_node_for_method(api_path, parent_node, method)
247       method_url = "#{parent_node.alcn.sub(/#.*$/, '')}##{method.aref}"
248       path = Webgen::Path.new(method_url,
249                               {'handler' => 'copy', 'modified_at' => api_path['modified_at'],
250                                 'parent_alcn' => parent_node.alcn,
251                                 'pipeline' => [], 'no_output' => true, 'title' => method.name})
252       @website.ext.path_handler.create_secondary_nodes(path)
253       add_link_definition(api_path, method.full_name, method_url, method.full_name)
254     end
255     protected :create_fragment_node_for_method
256 
257     # Create a page node for the given file and return it.
258     def create_page_node_for_file(api_path, dir_node, file, output_flag_file)
259       file_path_str = file.http_url(dir_node.alcn)
260 
261       create_directory(api_path, Webgen::Path.new(File.dirname(file_path_str) + '/'))
262 
263       path = Webgen::Path.new(file_path_str, 'handler' => 'page', 'modified_at' => api_path['modified_at'],
264                               'title' => "File #{file.full_name}", 'api_file_name' => file.full_name,
265                               'api_name' => api_path['api_name'], 'template' => api_path['api_template'])
266       node = @website.ext.path_handler.create_secondary_nodes(path).first
267 
268       node.node_info[:rdoc_object] = file
269       @website.ext.item_tracker.add(node, :file, output_flag_file)
270 
271       node
272     end
273     protected :create_page_node_for_file
274 
275     # Add a link definition for the given node.
276     def add_link_definition(api_path, link_name, url, title)
277       link = if api_path['prefix_link_defs']
278                "#{api_path['api_name']}:#{link_name}"
279              else
280                link_name
281              end
282       @website.ext.link_definitions[link] = [url, title]
283     end
284     protected :add_link_definition
285 
286   end
287 
288 end
rdoc_options(user_options) click to toggle source

Return a fully initialized RDoc::Options object.

Some of the user specified options may not be used if they would interfere with this class' job.

    # File lib/webgen/path_handler/api.rb
116 def rdoc_options(user_options)
117   user_options = Shellwords.split(user_options) if user_options.kind_of?(String)
118   options = RDoc::Options.new
119   options.parse(user_options)
120   options.verbosity = 0
121   options.dry_run = false
122   options.update_output_dir = true
123   options.force_output = false
124   options.finish
125   options
126 end
rdoc_store(options, cache_dir) click to toggle source

Return a fully initialized RDoc::Store object.

    # File lib/webgen/path_handler/api.rb
130 def rdoc_store(options, cache_dir)
131   store = RDoc::Store.new(cache_dir)
132   store.encoding = options.encoding
133   store.dry_run = options.dry_run
134   store.main = options.main_page
135   store.title = options.title
136   store.load_cache
137   store
138 end

Private Instance Methods

create_directory(api_path, path, set_proxy_path = true) click to toggle source

Create a directory for the path, applying needed meta information from the api path.

Also creates the parent directories when necessary.

   # File lib/webgen/path_handler/api.rb
67 def create_directory(api_path, path, set_proxy_path = true)
68   if (dir = @website.tree[path.alcn])
69     return dir
70   end
71 
72   parent_path = Webgen::Path.new(path.parent_path)
73   if !@website.tree[parent_path.alcn]
74     create_directory(api_path, parent_path)
75   end
76 
77   path['modified_at'] = api_path['modified_at']
78   path['handler'] = 'directory'
79   path['proxy_path'] ||= "../#{path.basename}.html" if set_proxy_path
80   @website.ext.path_handler.create_secondary_nodes(path).first
81 end