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, line 144
def adapt_rdoc_class(api_path, klass)
  case api_path['output_structure']
  when 'hierarchical'
    api_path['use_proxy_path'] = false
    def klass.http_url(prefix)
      if classes_and_modules.size > 0
        super(prefix).sub(/\.html/, '/index.html')
      else
        super(prefix)
      end
    end
  else
    api_path['use_proxy_path'] = true
  end
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, line 199
def create_fragment_node_for_constant(api_path, parent_node, constant)
  constant_url = "#{parent_node.alcn.sub(/#.*$/, '')}##{constant.name}"
  path = Webgen::Path.new(constant_url,
                          {'handler' => 'copy', 'modified_at' => api_path['modified_at'],
                           'parent_alcn' => parent_node.alcn,
                           'pipeline' => [], 'no_output' => true, 'title' => constant.name})
  @website.ext.path_handler.create_secondary_nodes(path)
  add_link_definition(api_path, constant.full_name, constant_url, constant.full_name)
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, line 247
def create_fragment_node_for_method(api_path, parent_node, method)
  method_url = "#{parent_node.alcn.sub(/#.*$/, '')}##{method.aref}"
  path = Webgen::Path.new(method_url,
                          {'handler' => 'copy', 'modified_at' => api_path['modified_at'],
                            'parent_alcn' => parent_node.alcn,
                            'pipeline' => [], 'no_output' => true, 'title' => method.name})
  @website.ext.path_handler.create_secondary_nodes(path)
  add_link_definition(api_path, method.full_name, method_url, method.full_name)
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, line 211
def create_fragment_nodes_for_attributes(api_path, parent_node, klass)
  return if klass.attributes.none? {|attr| attr.display? }
  attributes_url = "#{parent_node.alcn}#Attributes"
  path = Webgen::Path.new(attributes_url,
                          {'handler' => 'copy', 'modified_at' => api_path['modified_at'],
                            'parent_alcn' => parent_node.alcn,
                           'pipeline' => [], 'no_output' => true, 'title' => "Attributes"})
  attr_node = @website.ext.path_handler.create_secondary_nodes(path).first
  klass.attributes.sort_by(&:name).each do |attribute|
    create_fragment_node_for_method(api_path, attr_node, attribute)
  end
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, line 183
def create_fragment_nodes_for_constants(api_path, klass_node, klass)
  return if klass.constants.none? {|const| const.display? }
  constants_url = "#{klass_node.alcn}#Constants"
  path = Webgen::Path.new(constants_url,
                          {'handler' => 'copy', 'modified_at' => api_path['modified_at'],
                           'pipeline' => [], 'no_output' => true, 'title' => "Constants"})
  const_node = @website.ext.path_handler.create_secondary_nodes(path).first
  klass.constants.sort_by(&:name).each do |const|
    create_fragment_node_for_constant(api_path, const_node, const)
  end
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, line 227
def create_fragment_nodes_for_methods(api_path, klass_node, klass)
  ["Class", "Instance"].each do |type|
    method_list = klass.send("#{type.downcase}_method_list")
    next if method_list.empty?
    meth_url = "#{klass_node.alcn}##{type}-Methods"
    path = Webgen::Path.new(meth_url,
                            {'handler' => 'copy', 'modified_at' => api_path['modified_at'],
                              'pipeline' => [], 'no_output' => true,
                              'title' => "#{type} Methods"})
    meth_node = @website.ext.path_handler.create_secondary_nodes(path).first
    method_list.sort_by(&:name).each do |method|
      create_fragment_node_for_method(api_path, meth_node, method)
    end
  end
end
create_nodes(path, blocks) click to toggle source

Create the feed nodes.

# File lib/webgen/path_handler/api.rb, line 24
def create_nodes(path, blocks)
  if MANDATORY_INFOS.any? {|t| path.meta_info[t].nil?}
    raise Webgen::NodeCreationError.new("At least one of #{MANDATORY_INFOS.join('/')} is missing",
                                        "path_handler.api", path)
  end

  path['api_name'] ||= path.basename
  path['dir_name'] ||= path.basename

  cache_dir = @website.tmpdir(File.join('path_handler.api', path['api_name']))
  rdoc = rdoc_object(path['rdoc_options'], cache_dir)
  output_flag_file = rdoc.output_flag_file(cache_dir)

  dir_node = create_directory(path, Webgen::Path.new(path.parent_path + path['dir_name'] + '/'), false)

  api = OpenStruct.new
  api.directory = dir_node
  api.class_nodes = {}
  api.file_nodes = {}

  rdoc.store.all_classes_and_modules.sort.each do |klass|
    adapt_rdoc_class(path, klass)
    klass_node = create_page_node_for_class(path, dir_node, klass, output_flag_file)
    api.class_nodes[klass.full_name] = klass_node
    klass_node.node_info[:api] = api
    create_fragment_nodes_for_constants(path, klass_node, klass)
    create_fragment_nodes_for_attributes(path, klass_node, klass)
    create_fragment_nodes_for_methods(path, klass_node, klass)
  end

  rdoc.store.all_files.sort.each do |file|
    next unless file.text?
    file_node = create_page_node_for_file(path, dir_node, file, output_flag_file)
    api.file_nodes[file.full_name] = file_node
    file_node.node_info[:api] = api
  end

  nil
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, line 164
def create_page_node_for_class(api_path, dir_node, klass, output_flag_file)
  klass_path_str = klass.http_url(dir_node.alcn)

  create_directory(api_path, Webgen::Path.new(File.dirname(klass_path_str) + '/'), api_path['use_proxy_path'])

  path = Webgen::Path.new(klass_path_str, 'handler' => 'page', 'modified_at' => api_path['modified_at'],
                          'title' => "#{klass.full_name}", 'api_class_name' => klass.full_name,
                          'api_name' => api_path['api_name'], 'template' => api_path['api_template'])
  node = @website.ext.path_handler.create_secondary_nodes(path).first

  node.node_info[:rdoc_object] = klass
  @website.ext.item_tracker.add(node, :file, output_flag_file)
  add_link_definition(api_path, klass.full_name, node.alcn, klass.full_name)

  node
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, line 259
def create_page_node_for_file(api_path, dir_node, file, output_flag_file)
  file_path_str = file.http_url(dir_node.alcn)

  create_directory(api_path, Webgen::Path.new(File.dirname(file_path_str) + '/'))

  path = Webgen::Path.new(file_path_str, 'handler' => 'page', 'modified_at' => api_path['modified_at'],
                          'title' => "File #{file.full_name}", 'api_file_name' => file.full_name,
                          'api_name' => api_path['api_name'], 'template' => api_path['api_template'])
  node = @website.ext.path_handler.create_secondary_nodes(path).first

  node.node_info[:rdoc_object] = file
  @website.ext.item_tracker.add(node, :file, output_flag_file)

  node
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, line 87
    def rdoc_object(options, cache_dir)
      start_time = Time.now

      rdoc = RDoc::RDoc.new
      rdoc.options = rdoc_options(options)
      rdoc.store = rdoc_store(rdoc.options, cache_dir)

      rdoc.exclude = rdoc.options.exclude
      rdoc.last_modified.replace(rdoc.setup_output_dir(cache_dir, false))

      if !(rdoc.parse_files(rdoc.options.files)).empty?
        rdoc.store.complete(rdoc.options.visibility)
        rdoc.store.save
        rdoc.update_output_dir(cache_dir, start_time, rdoc.last_modified)
      end
      rdoc.store.load_all

      # We need a dummy generator with some methods
      rdoc.generator = Object.new
      def (rdoc.generator).class_dir; nil; end
      def (rdoc.generator).file_dir; nil; end

      rdoc
    end
    protected :rdoc_object

    # 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.
    def rdoc_options(user_options)
      user_options = Shellwords.split(user_options) if user_options.kind_of?(String)
      options = RDoc::Options.new
      options.parse(user_options)
      options.verbosity = 0
      options.dry_run = false
      options.update_output_dir = true
      options.force_output = false
      options.finish
      options
    end
    protected :rdoc_options

    # Return a fully initialized RDoc::Store object.
    def rdoc_store(options, cache_dir)
      store = RDoc::Store.new(cache_dir)
      store.encoding = options.encoding
      store.dry_run = options.dry_run
      store.main = options.main_page
      store.title = options.title
      store.load_cache
      store
    end
    protected :rdoc_store

    # Adapt a RDoc class/module object to provide a different output path depending on the
    # output_structure meta information of the API path.
    def adapt_rdoc_class(api_path, klass)
      case api_path['output_structure']
      when 'hierarchical'
        api_path['use_proxy_path'] = false
        def klass.http_url(prefix)
          if classes_and_modules.size > 0
            super(prefix).sub(/\.html/, '/index.html')
          else
            super(prefix)
          end
        end
      else
        api_path['use_proxy_path'] = true
      end
    end
    protected :adapt_rdoc_class

    # Create a page node for the given class +klass+ and return it.
    #
    # A link definition entry for the class is also created.
    def create_page_node_for_class(api_path, dir_node, klass, output_flag_file)
      klass_path_str = klass.http_url(dir_node.alcn)

      create_directory(api_path, Webgen::Path.new(File.dirname(klass_path_str) + '/'), api_path['use_proxy_path'])

      path = Webgen::Path.new(klass_path_str, 'handler' => 'page', 'modified_at' => api_path['modified_at'],
                              'title' => "#{klass.full_name}", 'api_class_name' => klass.full_name,
                              'api_name' => api_path['api_name'], 'template' => api_path['api_template'])
      node = @website.ext.path_handler.create_secondary_nodes(path).first

      node.node_info[:rdoc_object] = klass
      @website.ext.item_tracker.add(node, :file, output_flag_file)
      add_link_definition(api_path, klass.full_name, node.alcn, klass.full_name)

      node
    end
    protected :create_page_node_for_class

    # Creates fragment nodes for constants under the "Constants" fragment.
    def create_fragment_nodes_for_constants(api_path, klass_node, klass)
      return if klass.constants.none? {|const| const.display? }
      constants_url = "#{klass_node.alcn}#Constants"
      path = Webgen::Path.new(constants_url,
                              {'handler' => 'copy', 'modified_at' => api_path['modified_at'],
                               'pipeline' => [], 'no_output' => true, 'title' => "Constants"})
      const_node = @website.ext.path_handler.create_secondary_nodes(path).first
      klass.constants.sort_by(&:name).each do |const|
        create_fragment_node_for_constant(api_path, const_node, const)
      end
    end
    protected :create_fragment_nodes_for_constants

    # Create a fragment node for the given constant.
    #
    # A link definition entry for the method is also created.
    def create_fragment_node_for_constant(api_path, parent_node, constant)
      constant_url = "#{parent_node.alcn.sub(/#.*$/, '')}##{constant.name}"
      path = Webgen::Path.new(constant_url,
                              {'handler' => 'copy', 'modified_at' => api_path['modified_at'],
                               'parent_alcn' => parent_node.alcn,
                               'pipeline' => [], 'no_output' => true, 'title' => constant.name})
      @website.ext.path_handler.create_secondary_nodes(path)
      add_link_definition(api_path, constant.full_name, constant_url, constant.full_name)
    end
    protected :create_fragment_node_for_constant

    # Creates fragment nodes for attributes under the "Attributes" fragment.
    def create_fragment_nodes_for_attributes(api_path, parent_node, klass)
      return if klass.attributes.none? {|attr| attr.display? }
      attributes_url = "#{parent_node.alcn}#Attributes"
      path = Webgen::Path.new(attributes_url,
                              {'handler' => 'copy', 'modified_at' => api_path['modified_at'],
                                'parent_alcn' => parent_node.alcn,
                               'pipeline' => [], 'no_output' => true, 'title' => "Attributes"})
      attr_node = @website.ext.path_handler.create_secondary_nodes(path).first
      klass.attributes.sort_by(&:name).each do |attribute|
        create_fragment_node_for_method(api_path, attr_node, attribute)
      end
    end
    protected :create_fragment_nodes_for_attributes

    # Creates fragment nodes for methods under the "Class Methods" or "Instance Methods"
    # fragments.
    def create_fragment_nodes_for_methods(api_path, klass_node, klass)
      ["Class", "Instance"].each do |type|
        method_list = klass.send("#{type.downcase}_method_list")
        next if method_list.empty?
        meth_url = "#{klass_node.alcn}##{type}-Methods"
        path = Webgen::Path.new(meth_url,
                                {'handler' => 'copy', 'modified_at' => api_path['modified_at'],
                                  'pipeline' => [], 'no_output' => true,
                                  'title' => "#{type} Methods"})
        meth_node = @website.ext.path_handler.create_secondary_nodes(path).first
        method_list.sort_by(&:name).each do |method|
          create_fragment_node_for_method(api_path, meth_node, method)
        end
      end
    end
    protected :create_fragment_nodes_for_attributes

    # Create a fragment node for the given method.
    #
    # A link definition entry for the method is also created.
    def create_fragment_node_for_method(api_path, parent_node, method)
      method_url = "#{parent_node.alcn.sub(/#.*$/, '')}##{method.aref}"
      path = Webgen::Path.new(method_url,
                              {'handler' => 'copy', 'modified_at' => api_path['modified_at'],
                                'parent_alcn' => parent_node.alcn,
                                'pipeline' => [], 'no_output' => true, 'title' => method.name})
      @website.ext.path_handler.create_secondary_nodes(path)
      add_link_definition(api_path, method.full_name, method_url, method.full_name)
    end
    protected :create_fragment_node_for_method

    # Create a page node for the given file and return it.
    def create_page_node_for_file(api_path, dir_node, file, output_flag_file)
      file_path_str = file.http_url(dir_node.alcn)

      create_directory(api_path, Webgen::Path.new(File.dirname(file_path_str) + '/'))

      path = Webgen::Path.new(file_path_str, 'handler' => 'page', 'modified_at' => api_path['modified_at'],
                              'title' => "File #{file.full_name}", 'api_file_name' => file.full_name,
                              'api_name' => api_path['api_name'], 'template' => api_path['api_template'])
      node = @website.ext.path_handler.create_secondary_nodes(path).first

      node.node_info[:rdoc_object] = file
      @website.ext.item_tracker.add(node, :file, output_flag_file)

      node
    end
    protected :create_page_node_for_file

    # Add a link definition for the given node.
    def add_link_definition(api_path, link_name, url, title)
      link = if api_path['prefix_link_defs']
               "#{api_path['api_name']}:#{link_name}"
             else
               link_name
             end
      @website.ext.link_definitions[link] = [url, title]
    end
    protected :add_link_definition

  end

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, line 117
def rdoc_options(user_options)
  user_options = Shellwords.split(user_options) if user_options.kind_of?(String)
  options = RDoc::Options.new
  options.parse(user_options)
  options.verbosity = 0
  options.dry_run = false
  options.update_output_dir = true
  options.force_output = false
  options.finish
  options
end
rdoc_store(options, cache_dir) click to toggle source

Return a fully initialized RDoc::Store object.

# File lib/webgen/path_handler/api.rb, line 131
def rdoc_store(options, cache_dir)
  store = RDoc::Store.new(cache_dir)
  store.encoding = options.encoding
  store.dry_run = options.dry_run
  store.main = options.main_page
  store.title = options.title
  store.load_cache
  store
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, line 67
def create_directory(api_path, path, set_proxy_path = true)
  if (dir = @website.tree[path.alcn])
    return dir
  end

  parent_path = Webgen::Path.new(path.parent_path)
  if !@website.tree[parent_path.alcn]
    create_directory(api_path, parent_path)
  end

  path['modified_at'] = api_path['modified_at']
  path['handler'] = 'directory'
  path['proxy_path'] ||= "../#{path.basename}.html" if set_proxy_path
  @website.ext.path_handler.create_secondary_nodes(path).first
end