Commit 9b4991ca authored by Rene Saarsoo's avatar Rene Saarsoo
Browse files

Refactor warnings system.

Create four warning classes to handle a particular set of warnings:

- Warning::Basic -- the usual warnings :tag, :link, :global, ...
- Warning::Nodoc -- the :nodoc warning type together with its
  parameters.
- Warnings::Deprecated -- the old :no_doc* warnings which delegate to
  the new :nodoc warning.
- Warning::All -- composite warning that allows enabling/disabling all
  warning types together.

Then inside Warning::Registry delegate #set and #enabled? calls to these
warnings.
parent c420b06e
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
module JsDuck
  module Warning

    # A composite warning, encompassing all the other warning types.
    class All

      # Creates a deprecated warning with a mapping to :nodoc warning
      # type with given parameters.  The warning is disabled by
      # default.
      def initialize(warnings)
        @warnings = warnings
      end

      # Enables/disables all warnings.
      def set(enabled, path_pattern=nil, params=[])
        # When used with a path_pattern, only add the pattern to the rules
        # where it can have an effect - otherwise we get a warning.
        @warnings.each do |w|
          w.set(enabled, path_pattern, params) unless path_pattern && w.enabled? == enabled
        end
      end

      # Doesn't make sense to check if the :all warning is enabled.
      def enabled?(filename="", params=[])
        raise "Warning type 'all' must not be checked for enabled/disabled"
      end

      # The all-warning is documented separately
      def doc
        nil
      end

    end

  end
end
+49 −0
Original line number Diff line number Diff line
module JsDuck
  module Warning

    # A basic warning type.
    class Basic

      # Creates a simple warning with a message text.
      # The warning is disabled by default.
      def initialize(type, msg)
        @type = type
        @msg = msg
        @enabled = false
        @patterns = []
      end

      # Enables or disables the warning.
      # Optionally enables/disables it for files matching a path_pattern.
      def set(enabled, path_pattern=nil, params=[])
        if path_pattern
          if @enabled == enabled
            raise "Warning rule '#{enabled ? '+' : '-'}#{@type}:#{path_pattern}' has no effect"
          else
            @patterns << Regexp.new(Regexp.escape(path_pattern))
          end
        else
          @enabled = enabled
          @patterns = []
        end
      end

      # True when warning is enabled for the given filename.
      # (The params parameter is ignored).
      def enabled?(filename="", params=[])
        if @patterns.any? {|re| filename =~ re }
          !@enabled
        else
          @enabled
        end
      end

      # Documentation for the warning.
      def doc
        " #{@enabled ? '+' : '-'}#{@type} - #{@msg}"
      end

    end

  end
end
+38 −0
Original line number Diff line number Diff line
module JsDuck
  module Warning

    # A deprecated :no_doc* warning which maps to the new :nodoc
    # warning.
    class Deprecated

      # Creates a deprecated warning with a mapping to :nodoc warning
      # type with given parameters.  The warning is disabled by
      # default.
      def initialize(type, msg, nodoc, params)
        @type = type
        @msg = msg
        @enabled = false
        @nodoc = nodoc
        @params = params
      end

      # Enables or disables the mapped :nodoc warning.
      def set(enabled, path_pattern=nil, params=[])
        @nodoc.set(enabled, path_pattern, @params)
        raise "Warning type #{@type} is deprecated, use nodoc(#{@params.join(',')}) instead"
      end

      # This method shouldn't be called.
      def enabled?(filename="", params=[])
        raise "Deprecated warning '#{@type}' must not be checked for enabled/disabled"
      end

      # Documentation for the warning.
      def doc
        " -#{@type} - #{@msg} DEPRECATED"
      end

    end

  end
end
+35 −5
Original line number Diff line number Diff line
@@ -3,12 +3,13 @@ require 'set'
module JsDuck
  module Warning

    # Missing documentation warnings management
    # Missing documentation warning.
    class Nodoc

      TYPES = Set[nil, :class, :member, :param]
      VISIBILITIES = Set[nil, :public, :protected, :private]

      # Creates the :nodoc warning type
      def initialize
        @rules = []
        # disable by default
@@ -16,7 +17,10 @@ module JsDuck
      end

      # Enables or disables a particular sub-warning
      def set(enabled, type=nil, visibility=nil, path_pattern=nil)
      def set(enabled, path_pattern=nil, params=[])
        type = params[0]
        visibility = params[1]

        unless TYPES.include?(type) && VISIBILITIES.include?(visibility)
          raise "Invalid warning parameters: nodoc(#{type},#{visibility})"
        end
@@ -29,9 +33,13 @@ module JsDuck
        }
      end

      # True when the warning is enabled for the given
      # type/visibility/filename combination.
      def enabled?(type, visibility, filename)
      # True when the warning is enabled for the given filename and
      # params combination, where the params contain type and
      # visibility setting.
      def enabled?(filename="", params=[])
        type = params[0]
        visibility = params[1]

        # Filter out rules that apply to our current item
        matches = @rules.find_all do |r|
          (r[:type].nil? || r[:type] == type) &&
@@ -42,6 +50,28 @@ module JsDuck
        return matches.last[:enabled]
      end

      # Extensive documentation for :nodoc warning
      def doc
        [
          "",
          " -nodoc(<type>,<visibility>) - Missing documentation",
          "",
          "     This warning can take parameters with the following values:",
          "",
          "     <type> = class | member | param",
          "     <visibility> = public | protected | private",
          "",
          "     So, to report missing documentation of public classes:",
          "",
          "         --warnings='+nodoc(class,public)'",
          "",
          "     Or, to report missing docs of all protected items in /etc:",
          "",
          "         --warnings='+nodoc(,protected):/etc/'",
          "",
        ]
      end

    end

  end
+38 −55
Original line number Diff line number Diff line
require 'jsduck/warning/basic'
require 'jsduck/warning/nodoc'
require 'jsduck/warning/deprecated'
require 'jsduck/warning/all'

module JsDuck
  module Warning
@@ -7,7 +10,11 @@ module JsDuck
    class Registry

      def initialize
        @docs = [
        @warnings = []
        @warnings_map = {}

        # Basic warnings
        [
          [:global, "Member doesn't belong to any class"],
          [:inheritdoc, "@inheritdoc referring to unknown class or member"],
          [:extend, "@extend/mixin/requires/uses referring to unknown class"],
@@ -41,52 +48,37 @@ module JsDuck

          [:aside, "Problem with @aside tag"],
          [:hide, "Problem with @hide tag"],
        ].each do |w|
          register(w[0], Warning::Basic.new(w[0], w[1]))
        end

          [:nodoc, "Missing documentation"],
        ]

        @deprecated = {
          :no_doc => {:msg => "Alias for +nodoc(class,public)", :params => [:class, :public]},
          :no_doc_member => {:msg => "Alias for +nodoc(member,public)", :params => [:member, :public]},
          :no_doc_param => {:msg => "Alias for +nodoc(param,public)", :params => [:param, :public]},
        }
        # :nodoc warning
        register(:nodoc, Warning::Nodoc.new)

        @nodoc = Warning::Nodoc.new
        # :all warning (encompasses all other warning types)
        register(:all, Warning::All.new(@warnings.clone))

        # Turn off all warnings by default.
        # This is good for testing.
        # When running JSDuck app, the Options class enables most warnings.
        @warnings = {}
        @docs.each do |w|
          @warnings[w[0]] = {:enabled => false, :patterns => []}
        end
        # :deprecated warnings (linking to :nodoc warning)
        [
          {:type => :no_doc, :msg => "Alias for nodoc(class,public)", :params => [:class, :public]},
          {:type => :no_doc_member, :msg => "Alias for nodoc(member,public)", :params => [:member, :public]},
          {:type => :no_doc_param, :msg => "Alias for nodoc(param,public)", :params => [:param, :public]},
        ].each do |w|
          register(w[:type], Warning::Deprecated.new(w[:type], w[:msg], @warnings_map[:nodoc], w[:params]))
        end

      # Enables or disables a particular warning
      # or all warnings when type == :all.
      # Additionally a filename pattern can be specified.
      def set(type, enabled, pattern=nil, params=[])
        if type == :all
          # When used with a pattern, only add the pattern to the rules
          # where it can have an effect - otherwise we get a warning.
          @warnings.each_key do |key|
            set(key, enabled, pattern) unless pattern && @warnings[key][:enabled] == enabled
      end
        elsif type == :nodoc
          @nodoc.set(enabled, params[0], params[1], pattern)
        elsif @deprecated[type]
          params = @deprecated[type][:params]
          @nodoc.set(enabled, params[0], params[1], pattern)
        elsif @warnings.has_key?(type)
          if pattern
            if @warnings[type][:enabled] == enabled
              raise "Warning rule '#{enabled ? '+' : '-'}#{type}:#{pattern}' has no effect"
            else
              @warnings[type][:patterns] << Regexp.new(Regexp.escape(pattern))
            end
          else
            @warnings[type] = {:enabled => enabled, :patterns => []}

      def register(type, warning)
        @warnings << warning
        @warnings_map[type] = warning
      end

      # Enables or disables a particular warning type.
      # Additionally a filename pattern and params for the warning can be specified.
      def set(type, enabled, path_pattern=nil, params=[])
        if @warnings_map[type]
          @warnings_map[type].set(enabled, path_pattern, params)
        else
          raise "Warning of type '#{type}' doesn't exist"
        end
@@ -94,26 +86,17 @@ module JsDuck

      # get documentation for all warnings
      def doc
        @docs.map {|w| " #{@warnings[w[0]][:enabled] ? '+' : '-'}#{w[0]} - #{w[1]}" }
        @warnings.map {|w| w.doc }.compact.flatten
      end

      # True when the warning is enabled for the given type and filename
      # combination.
      # True when the warning is enabled for the given type and
      # filename combination.
      def enabled?(type, filename, params=[])
        if type == :nodoc
          return @nodoc.enabled?(params[0], params[1], filename)
        end

        rule = @warnings[type]
        if rule[:patterns].any? {|re| filename =~ re }
          !rule[:enabled]
        else
          rule[:enabled]
        end
        @warnings_map[type].enabled?(filename, params)
      end

      def has?(type)
        @warnings.has_key?(type)
        @warnings_map.has_key?(type)
      end

    end
Loading