Commit fd4f1cea authored by Rene Saarsoo's avatar Rene Saarsoo
Browse files

Show info about overridden members.

For each member we now show a list of all the members that it overrides
(if there are any). No more needs one wonder if the method happens to
override a method in some parent class or mixin - the information is
right the in the docs.

This implementation mostly works. However I have to refactor it around a
bit to ensure it doesn't misbehave when parallel-processing is used.
parent be641d68
Loading
Loading
Loading
Loading
+22 −3
Original line number Diff line number Diff line
@@ -124,7 +124,7 @@ module JsDuck
      all_members = parent ? parent.members_hash(type, context) : {}

      mixins.each do |mix|
        all_members.merge!(mix.members_hash(type, context))
        all_members.merge!(mix.members_hash(type, context)) {|k,o,n| store_overrides(k,o,n)}
      end

      # For static members, exclude everything not explicitly marked as inheritable
@@ -132,19 +132,38 @@ module JsDuck
        all_members.delete_if {|key, member| !member[:inheritable] }
      end

      all_members.merge!(local_members_hash(type, context))
      all_members.merge!(local_members_hash(type, context)) {|k,o,n| store_overrides(k,o,n)}

      # If singleton has static members, include them as if they were
      # instance members.  Otherwise they will be completely excluded
      # from the docs, as the static members block is not created for
      # singletons.
      if @doc[:singleton] && @doc[:statics][type].length > 0
        all_members.merge!(local_members_hash(type, :statics))
        all_members.merge!(local_members_hash(type, :statics)) {|k,o,n| store_overrides(k,o,n)}
      end

      all_members
    end

    # Invoked when merge! finds two members with the same name.
    # New member always overrides the old, but inside new we keep
    # a list of members it overrides.  Normally one member will
    # override one other member, but a member from mixin can override
    # multiple members - although there's not a single such case in
    # ExtJS, we have to handle it.
    #
    # Every overridden member is listed just once.
    def store_overrides(key, old, new)
      # Sometimes a class is included multiple times (like Ext.Base)
      # resulting in its members overriding themselves.  Because of
      # this, ignore overriding itself.
      if new[:owner] != old[:owner]
        new[:overrides] = [] unless new[:overrides]
        new[:overrides] << old unless new[:overrides].any? {|m| m[:owner] == old[:owner] }
      end
      new
    end

    # Helper method to get the direct members of this class
    def local_members_hash(type, context)
      local_members = {}
+9 −2
Original line number Diff line number Diff line
@@ -109,8 +109,10 @@ module JsDuck
      ]
    end

    def render_link(cls_name)
        return "<a href='#!/api/#{cls_name}' rel='#{cls_name}' class='docClass'>#{cls_name}</a>"
    def render_link(cls_name, member=nil)
      id = member ? cls_name + "-" + member[:id] : cls_name
      label = member ? cls_name + "." + member[:name] : cls_name
      return "<a href='#!/api/#{id}' rel='#{id}' class='docClass'>#{label}</a>"
    end

    def render_member_sections
@@ -242,6 +244,11 @@ module JsDuck

      doc << render_params_and_return(m)

      if m[:overrides]
        overrides = m[:overrides].map {|o| render_link(o[:owner], o) }.join(", ")
        doc << "<p>Overrides: #{overrides}</p>"
      end

      doc
    end

+87 −0
Original line number Diff line number Diff line
require "jsduck/aggregator"
require "jsduck/source_file"
require "jsduck/class"
require "jsduck/relations"
require "jsduck/tag/static"
require "jsduck/meta_tag_registry"

describe JsDuck::Aggregator do
  before(:all) do
    JsDuck::MetaTagRegistry.instance.register([JsDuck::Tag::Static.new])
  end

  def parse(string)
    agr = JsDuck::Aggregator.new
    agr.aggregate(JsDuck::SourceFile.new(string))
    JsDuck::Relations.new(agr.result.map {|cls| JsDuck::Class.new(cls) })
  end

  shared_examples_for "override" do
    it "gets :override property" do
      @method.should have_key(:overrides)
    end

    it "lists parent method in :override property" do
      @method[:overrides][0][:owner].should == "Parent"
    end
  end

  describe "method overriding parent class method" do
    before do
      @docs = parse(<<-EOF)
        /** @class Parent */
          /** @method foo */

        /** @class Child @extends Parent */
          /** @method foo */
      EOF
      @method = @docs["Child"].members(:method)[0]
    end

    it_should_behave_like "override"
  end

  describe "mixin method overriding parent class method" do
    before do
      @docs = parse(<<-EOF)
        /** @class Parent */
          /** @method foo */
        /** @class Mixin */
          /** @method foo */

        /** @class Child @extends Parent @mixins Mixin */
      EOF
      @method = @docs["Child"].members(:method)[0]
    end

    it_should_behave_like "override"
  end

  describe "mixin method overriding multiple parent class methods" do
    before do
      @docs = parse(<<-EOF)
        /** @class Parent1 */
          /** @method foo */
        /** @class Parent2 */
          /** @method foo */
        /** @class Mixin */
          /** @method foo */

        /** @class Child1 @extends Parent1 @mixins Mixin */
        /** @class Child2 @extends Parent2 @mixins Mixin */
      EOF
      # Call #members on two child classes, this will init the
      # :overrides in Mixin class
      @docs["Child1"].members(:method)
      @docs["Child2"].members(:method)

      @method = @docs["Mixin"].members(:method)[0]
    end

    it "gets :override property listing multiple methods" do
      @method[:overrides].length.should == 2
    end
  end

end