Loading lib/jsduck/log/warnings_parser.rb 0 → 100644 +166 −0 Original line number Diff line number Diff line require 'strscan' module JsDuck module Log # Parses the warnings passed in from command line # # Grammar: # # <warnings> := <warning> [ "," <warning> ]* # # <warning> := ["+" | "-"] <type> [<params-block>] [<path-block>] # # <type> := \w+ # # <params-block> := "(" [<params>] ")" # # <params> := <param> [ "," <param> ]* # # <param> := \w+ | "" # # <path-block> := ":" <path> # # <path> := .* # class WarningsParser def initialize(string) @scanner = StringScanner.new(string) end # Parses the warnings string. # # For example the following string: # # +tag,-nodoc(class,private):/some/path # # is parsed into the following structure: # # [ # { # :type => :tag, # :enabled => true, # :params => [], # :path => nil, # }, # { # :type => :nodoc, # :enabled => false, # :params => [:class, :private], # :path => "/some/path", # }, # ] # # When scanning fails, raises an exception with a descriptive # message. def parse results = [] while !eos? results << warning match(/,/) end results end private def warning return { :enabled => enabled, :type => type, :params => params, :path => path, } end def enabled if match(/\+/) true elsif match(/-/) false else true end end def type require(/\w+/).to_sym end def params if match(/\(/) ps = [] while !look(/\)/) ps << param break unless match(/,/) end require(/\)/) ps else [] end end def param if p = match(/\w+/) p.to_sym elsif look(/,/) nil else unexpected_char end end def path if match(/:/) match(/[^,]*/).strip else nil end end # scans a pattern, throws error on failure def require(re) if m = match(re) m else unexpected_char end end # Reports unexpected character def unexpected_char # do successful empty scan, so we can use #pre_match and #post_match @scanner.scan(//) raise "Unexpected '#{@scanner.peek(1)}' at --warnings='#{@scanner.pre_match}<HERE>#{@scanner.post_match}'" end # scans a pattern, ignoring the optional whitespace before it def match(re) skip_ws @scanner.scan(re) end def look(re) skip_ws @scanner.check(re) end def eos? skip_ws @scanner.eos? end def skip_ws @scanner.scan(/\s*/) end end end end lib/jsduck/options.rb +7 −9 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ require 'jsduck/util/io' require 'jsduck/util/parallel' require 'jsduck/tag_registry' require 'jsduck/js/ext_patterns' require 'jsduck/log/warnings_parser' module JsDuck Loading Loading @@ -672,7 +673,7 @@ module JsDuck Logger.verbose = true end opts.on('--warnings=+A,-B,+C', Array, opts.on('--warnings=+A,-B,+C', "Turns warnings selectively on/off.", "", " +all - to turn on all warnings.", Loading @@ -696,15 +697,12 @@ module JsDuck "(Those with '+' in front of them default to on)", "", *Logger.doc_warnings) do |warnings| warnings.each do |op| # XXX: Can't rely any more on the Array type of OptionParser if op =~ /^([-+]?)(\w+)(?:\(([^)]*)\))?(?::(.*))?$/ enable = !($1 == "-") name = $2.to_sym params = ($3 || "").split(/,/).map {|p| p.strip }.map {|p| (p == "") ? nil : p.to_sym } path = $4 Logger.set_warning(name, enable, path, params) begin Log::WarningsParser.new(warnings).parse.each do |w| Logger.set_warning(w[:type], w[:enabled], w[:path], w[:params]) end rescue Exception => e Logger.warn(nil, e.message) end end Loading spec/log_warnings_parser_spec.rb 0 → 100644 +130 −0 Original line number Diff line number Diff line require "jsduck/log/warnings_parser" describe JsDuck::Log::WarningsParser do def parse(s) JsDuck::Log::WarningsParser.new(s).parse end describe "parsing empty string" do it "results in empty array" do parse("").should == [] end end describe "parsing +foo,bar_bar,-baz" do let(:warnings) { parse("+foo, bar_bar, -baz") } it "results in 3 warning defs" do warnings.length.should == 3 end describe "first" do let(:w) { warnings[0] } it "is of type :foo" do w[:type].should == :foo end it "is enabled" do w[:enabled].should == true end end describe "second" do let(:w) { warnings[1] } it "is of type :bar_bar" do w[:type].should == :bar_bar end it "is enabled" do w[:enabled].should == true end end describe "third" do let(:w) { warnings[2] } it "is of type :baz" do w[:type].should == :baz end it "is disabled" do w[:enabled].should == false end end end describe "parsing foo:/some/path" do let(:w) { parse("foo:/some/path ")[0] } it "detects path" do w[:path].should == "/some/path" end end describe "parsing two warnings with path" do let(:warnings) { parse("foo:/some/path,bar:/other/path") } it "detects two warnings" do warnings.length.should == 2 end end describe "parsing nodoc(class,public)" do let(:w) { parse("nodoc(class,public)")[0] } it "detects params" do w[:params].should == [:class, :public] end end describe "parsing nodoc(,private)" do let(:w) { parse("nodoc(,private)")[0] } it "detects also empty params" do w[:params].should == [nil, :private] end end describe "parsing invalid warning type" do it "raises an exception" do begin parse("?123") rescue Exception => e e.message.should == "Unexpected '?' at --warnings='<HERE>?123'" end end end describe "parsing invalid stuff after warning type" do it "raises an exception" do begin parse("tag?123") rescue Exception => e e.message.should == "Unexpected '?' at --warnings='tag<HERE>?123'" end end end describe "parsing invalid warning param" do it "raises an exception" do begin parse("nodoc(?)") rescue Exception => e e.message.should == "Unexpected '?' at --warnings='nodoc(<HERE>?)'" end end end describe "parsing invalid stuff after warning param" do it "raises an exception" do begin parse("nodoc(foo?)") rescue Exception => e e.message.should == "Unexpected '?' at --warnings='nodoc(foo<HERE>?)'" end end end end Loading
lib/jsduck/log/warnings_parser.rb 0 → 100644 +166 −0 Original line number Diff line number Diff line require 'strscan' module JsDuck module Log # Parses the warnings passed in from command line # # Grammar: # # <warnings> := <warning> [ "," <warning> ]* # # <warning> := ["+" | "-"] <type> [<params-block>] [<path-block>] # # <type> := \w+ # # <params-block> := "(" [<params>] ")" # # <params> := <param> [ "," <param> ]* # # <param> := \w+ | "" # # <path-block> := ":" <path> # # <path> := .* # class WarningsParser def initialize(string) @scanner = StringScanner.new(string) end # Parses the warnings string. # # For example the following string: # # +tag,-nodoc(class,private):/some/path # # is parsed into the following structure: # # [ # { # :type => :tag, # :enabled => true, # :params => [], # :path => nil, # }, # { # :type => :nodoc, # :enabled => false, # :params => [:class, :private], # :path => "/some/path", # }, # ] # # When scanning fails, raises an exception with a descriptive # message. def parse results = [] while !eos? results << warning match(/,/) end results end private def warning return { :enabled => enabled, :type => type, :params => params, :path => path, } end def enabled if match(/\+/) true elsif match(/-/) false else true end end def type require(/\w+/).to_sym end def params if match(/\(/) ps = [] while !look(/\)/) ps << param break unless match(/,/) end require(/\)/) ps else [] end end def param if p = match(/\w+/) p.to_sym elsif look(/,/) nil else unexpected_char end end def path if match(/:/) match(/[^,]*/).strip else nil end end # scans a pattern, throws error on failure def require(re) if m = match(re) m else unexpected_char end end # Reports unexpected character def unexpected_char # do successful empty scan, so we can use #pre_match and #post_match @scanner.scan(//) raise "Unexpected '#{@scanner.peek(1)}' at --warnings='#{@scanner.pre_match}<HERE>#{@scanner.post_match}'" end # scans a pattern, ignoring the optional whitespace before it def match(re) skip_ws @scanner.scan(re) end def look(re) skip_ws @scanner.check(re) end def eos? skip_ws @scanner.eos? end def skip_ws @scanner.scan(/\s*/) end end end end
lib/jsduck/options.rb +7 −9 Original line number Diff line number Diff line Loading @@ -6,6 +6,7 @@ require 'jsduck/util/io' require 'jsduck/util/parallel' require 'jsduck/tag_registry' require 'jsduck/js/ext_patterns' require 'jsduck/log/warnings_parser' module JsDuck Loading Loading @@ -672,7 +673,7 @@ module JsDuck Logger.verbose = true end opts.on('--warnings=+A,-B,+C', Array, opts.on('--warnings=+A,-B,+C', "Turns warnings selectively on/off.", "", " +all - to turn on all warnings.", Loading @@ -696,15 +697,12 @@ module JsDuck "(Those with '+' in front of them default to on)", "", *Logger.doc_warnings) do |warnings| warnings.each do |op| # XXX: Can't rely any more on the Array type of OptionParser if op =~ /^([-+]?)(\w+)(?:\(([^)]*)\))?(?::(.*))?$/ enable = !($1 == "-") name = $2.to_sym params = ($3 || "").split(/,/).map {|p| p.strip }.map {|p| (p == "") ? nil : p.to_sym } path = $4 Logger.set_warning(name, enable, path, params) begin Log::WarningsParser.new(warnings).parse.each do |w| Logger.set_warning(w[:type], w[:enabled], w[:path], w[:params]) end rescue Exception => e Logger.warn(nil, e.message) end end Loading
spec/log_warnings_parser_spec.rb 0 → 100644 +130 −0 Original line number Diff line number Diff line require "jsduck/log/warnings_parser" describe JsDuck::Log::WarningsParser do def parse(s) JsDuck::Log::WarningsParser.new(s).parse end describe "parsing empty string" do it "results in empty array" do parse("").should == [] end end describe "parsing +foo,bar_bar,-baz" do let(:warnings) { parse("+foo, bar_bar, -baz") } it "results in 3 warning defs" do warnings.length.should == 3 end describe "first" do let(:w) { warnings[0] } it "is of type :foo" do w[:type].should == :foo end it "is enabled" do w[:enabled].should == true end end describe "second" do let(:w) { warnings[1] } it "is of type :bar_bar" do w[:type].should == :bar_bar end it "is enabled" do w[:enabled].should == true end end describe "third" do let(:w) { warnings[2] } it "is of type :baz" do w[:type].should == :baz end it "is disabled" do w[:enabled].should == false end end end describe "parsing foo:/some/path" do let(:w) { parse("foo:/some/path ")[0] } it "detects path" do w[:path].should == "/some/path" end end describe "parsing two warnings with path" do let(:warnings) { parse("foo:/some/path,bar:/other/path") } it "detects two warnings" do warnings.length.should == 2 end end describe "parsing nodoc(class,public)" do let(:w) { parse("nodoc(class,public)")[0] } it "detects params" do w[:params].should == [:class, :public] end end describe "parsing nodoc(,private)" do let(:w) { parse("nodoc(,private)")[0] } it "detects also empty params" do w[:params].should == [nil, :private] end end describe "parsing invalid warning type" do it "raises an exception" do begin parse("?123") rescue Exception => e e.message.should == "Unexpected '?' at --warnings='<HERE>?123'" end end end describe "parsing invalid stuff after warning type" do it "raises an exception" do begin parse("tag?123") rescue Exception => e e.message.should == "Unexpected '?' at --warnings='tag<HERE>?123'" end end end describe "parsing invalid warning param" do it "raises an exception" do begin parse("nodoc(?)") rescue Exception => e e.message.should == "Unexpected '?' at --warnings='nodoc(<HERE>?)'" end end end describe "parsing invalid stuff after warning param" do it "raises an exception" do begin parse("nodoc(foo?)") rescue Exception => e e.message.should == "Unexpected '?' at --warnings='nodoc(foo<HERE>?)'" end end end end