Commit 3ec879ab authored by Rene Saarsoo's avatar Rene Saarsoo
Browse files

Replaced Subclasses with Relations.

Using that implemented subclasses and mixed_into exports.

Relations provides access to 3 things:

- class lookup by name
- subclass lookup by class
- mixed into classes lookup by class

So now we have just one object to pass around for these purposes.
parent a4a6720f
Loading
Loading
Loading
Loading
+20 −22
Original line number Diff line number Diff line
@@ -6,7 +6,7 @@ require 'jsduck/class'
require 'jsduck/tree'
require 'jsduck/tree_icons'
require 'jsduck/members'
require 'jsduck/subclasses'
require 'jsduck/relations'
require 'jsduck/page'
require 'jsduck/timer'
require 'json'
@@ -45,14 +45,14 @@ module JsDuck

      parsed_files = @timer.time(:parsing) { parallel_parse(@input_files) }
      result = @timer.time(:aggregating) { aggregate(parsed_files) }
      classes = @timer.time(:aggregating) { filter_classes(result) }
      relations = @timer.time(:aggregating) { filter_classes(result) }

      if @export == :json
        @timer.time(:generating) { write_json(@output_dir+"/output", classes) }
        @timer.time(:generating) { write_json(@output_dir+"/output", relations) }
      else
        @timer.time(:generating) { write_tree(@output_dir+"/output/tree.js", classes) }
        @timer.time(:generating) { write_members(@output_dir+"/output/members.js", classes) }
        @timer.time(:generating) { write_pages(@output_dir+"/output", classes) }
        @timer.time(:generating) { write_tree(@output_dir+"/output/tree.js", relations) }
        @timer.time(:generating) { write_members(@output_dir+"/output/members.js", relations) }
        @timer.time(:generating) { write_pages(@output_dir+"/output", relations) }
      end

      @timer.report if @verbose
@@ -85,10 +85,10 @@ module JsDuck
    # Filters out class-documentations, converting them to Class objects.
    # For each other type, prints a warning message and discards it
    def filter_classes(docs)
      classes = {}
      classes = []
      docs.each do |d|
        if d[:tagname] == :class
          classes[d[:name]] = Class.new(d, classes)
          classes << Class.new(d)
        else
          type = d[:tagname].to_s
          name = d[:name]
@@ -97,45 +97,43 @@ module JsDuck
          puts "Warning: Ignoring #{type}: #{name} in #{file} line #{line}"
        end
      end
      classes.values
      Relations.new(classes)
    end

    # Given array of doc-objects, generates namespace tree and writes it
    # Given all classes, generates namespace tree and writes it
    # in JSON form into a file.
    def write_tree(filename, docs)
      tree = Tree.new.create(docs)
    def write_tree(filename, relations)
      tree = Tree.new.create(relations.classes)
      icons = TreeIcons.new.extract_icons(tree)
      js = "Docs.classData = " + JSON.generate( tree ) + ";"
      js += "Docs.icons = " + JSON.generate( icons ) + ";"
      File.open(filename, 'w') {|f| f.write(js) }
    end

    # Given array of doc-objects, generates members data for search and writes in
    # Given all classes, generates members data for search and writes in
    # in JSON form into a file.
    def write_members(filename, docs)
      members = Members.new.create(docs)
    def write_members(filename, relations)
      members = Members.new.create(relations.classes)
      js = "Docs.membersData = " + JSON.generate( {:data => members} ) + ";"
      File.open(filename, 'w') {|f| f.write(js) }
    end

    # Writes documentation page for each class
    # We do it in parallel using as many processes as available CPU-s
    def write_pages(path, docs)
      subclasses = Subclasses.new(docs)
    def write_pages(path, relations)
      cache = {}
      Parallel.each(docs) do |cls|
      Parallel.each(relations.classes) do |cls|
        filename = path + "/" + cls[:name] + ".html"
        puts "Writing to #{filename} ..." if @verbose
        html = Page.new(cls, subclasses, cache).to_html
        html = Page.new(cls, relations, cache).to_html
        File.open(filename, 'w') {|f| f.write(html) }
      end
    end

    # Writes JSON export file for each class
    def write_json(path, docs)
      subclasses = Subclasses.new(docs)
    def write_json(path, relations)
      cache = {}
      Parallel.each(docs) do |cls|
      Parallel.each(relations.classes) do |cls|
        filename = path + "/" + cls[:name] + ".json"
        puts "Writing to #{filename} ..." if @verbose
        hash = cls.to_hash
+8 −4
Original line number Diff line number Diff line
@@ -4,9 +4,11 @@ module JsDuck
  # methods on it.  Otherwise it acts like Hash, providing the []
  # method.
  class Class
    def initialize(doc, classes={})
    attr_accessor :relations

    def initialize(doc)
      @doc = doc
      @classes = classes
      @relations = nil
    end

    def [](key)
@@ -37,8 +39,8 @@ module JsDuck
    # Looks up class object by name
    # When not found, prints warning message.
    def lookup(classname)
      if @classes[classname]
        @classes[classname]
      if @relations[classname]
        @relations[classname]
      elsif classname != "Object"
        puts "Warning: Class #{classname} not found in #{@doc[:filename]} line #{@doc[:linenr]}"
      end
@@ -60,6 +62,8 @@ module JsDuck
      doc.delete(:event)
      doc[:component] = inherits_from?("Ext.Component")
      doc[:superclasses] = superclasses.collect {|cls| cls.full_name }
      doc[:subclasses] = @relations.subclasses(self).collect {|cls| cls.full_name }
      doc[:mixedInto] = @relations.mixed_into(self).collect {|cls| cls.full_name }
      doc
    end

+5 −5
Original line number Diff line number Diff line
@@ -12,12 +12,12 @@ module JsDuck
    # Initializes doc page generator
    #
    # - cls : the Class object for which to generate documentation
    # - subclasses : lookup table for easy access to subclasses
    # - relations : access to subclasses, mixins, etc
    # - cache : cache for already generated HTML rows for class members
    #
    def initialize(cls, subclasses = {}, cache = {})
    def initialize(cls, relations, cache = {})
      @cls = cls
      @subclasses = subclasses
      @relations = relations
      @cache = cache
      @formatter = DocFormatter.new(cls.full_name)
    end
@@ -53,7 +53,7 @@ module JsDuck
        abstract_row("Extends:", @cls.parent ? class_link(@cls.parent.full_name) : "Object"),
        @cls.mixins.length > 0 ? abstract_row("Mixins:", mixins) : "",
        abstract_row("Defind In:", file_link),
        @subclasses[@cls] ? abstract_row("Subclasses:", subclasses) : "",
        @relations.subclasses(@cls).length ? abstract_row("Subclasses:", subclasses) : "",
        @cls[:xtype] ? abstract_row("xtype:", @cls[:xtype]) : "",
        @cls[:author] ? abstract_row("Author:", @cls[:author]) : "",
       "</table>",
@@ -70,7 +70,7 @@ module JsDuck
    end

    def subclasses
      subs = @subclasses[@cls].sort {|a, b| a.short_name <=> b.short_name }
      subs = @relations.subclasses(@cls).sort {|a, b| a.short_name <=> b.short_name }
      subs.collect {|cls| class_link(cls.full_name, cls.short_name) }.join(", ")
    end

+68 −0
Original line number Diff line number Diff line
module JsDuck

  # Provides information about relations between classes.
  #
  # Also provides a place to look up classes by name.
  #
  # The constructor is initialized with array of all available
  # classes.
  class Relations
    # Returns list of all classes
    attr_reader :classes

    def initialize(classes = [])
      @classes = classes

      # First build class lookup table; building lookup tables for
      # mixins and subclasses will depend on that.
      @lookup = {}
      @classes.each do |cls|
        @lookup[cls.full_name] = cls
        cls.relations = self
      end

      @subs = {}
      @mixes = {}
      @classes.each do |cls|
        reg_subclasses(cls)
        reg_mixed_into(cls)
      end
    end

    # Looks up class by name, nil if not found
    def [](classname)
      @lookup[classname]
    end

    def reg_subclasses(cls)
      if !cls.parent
        # do nothing
      elsif @subs[cls.parent.full_name]
        @subs[cls.parent.full_name] << cls
      else
        @subs[cls.parent.full_name] = [cls]
      end
    end

    # Returns subclasses of particular class, empty array if none
    def subclasses(cls)
      @subs[cls.full_name] || []
    end

    def reg_mixed_into(cls)
      cls.mixins.each do |mix|
        if @mixes[mix.full_name]
          @mixes[mix.full_name] << cls
        else
          @mixes[mix.full_name] = [cls]
        end
      end
    end

    # Returns classes having particular mixin, empty array if none
    def mixed_into(cls)
      @mixes[cls.full_name] || []
    end
  end

end

lib/jsduck/subclasses.rb

deleted100644 → 0
+0 −27
Original line number Diff line number Diff line
module JsDuck

  # Provides information about direct descendants of particular class.
  #
  # The constructor is initialized with array of all available
  # classes.  Then through [] method subclasses of particlular class
  # can be asked for.
  class Subclasses
    def initialize(classes)
      @subs = {}
      classes.each do |cls|
        if !cls.parent
          # do nothing
        elsif @subs[cls.parent.full_name]
          @subs[cls.parent.full_name] << cls
        else
          @subs[cls.parent.full_name] = [cls]
        end
      end
    end

    def [](cls)
      @subs[cls.full_name]
    end
  end

end
Loading