Loading lib/jsduck/doc_scanner.rb +12 −1 Original line number Diff line number Diff line require 'jsduck/tag_registry' require 'jsduck/standard_tag_parser' module JsDuck Loading @@ -21,6 +21,9 @@ module JsDuck # Provides access to the tag that's currently being parsed attr_reader :current_tag # Provides access to StringScanner attr_reader :input # Appends new @tag to parsed tags list def add_tag(tag) if tag.is_a?(Hash) Loading @@ -32,6 +35,14 @@ module JsDuck @current_tag[:doc] = "" unless @current_tag.has_key?(:doc) end # Parses standard pattern governing several builtin tags. # # @tag {Type} [some.name=default] # def standard_tag(tagdef) StandardTagParser.new(self).parse(tagdef) end # matches {type} if possible and sets it on @current_tag # Also checks for {optionality=} in type definition. def maybe_type Loading lib/jsduck/standard_tag_parser.rb 0 → 100644 +134 −0 Original line number Diff line number Diff line module JsDuck # Helper in parsing the standard tag pattern with type definition # followed by name and default value: # # @tag {Type} [some.name=default] # class StandardTagParser # Initialized with DocScanner instance def initialize(doc_scanner) @ds = doc_scanner end # Parses our tag. def parse(tagdef) tag = tagdef add_type(tag) add_name_with_default(tag) tag end # matches {type} if possible and sets it on @current_tag # Also checks for {optionality=} in type definition. def add_type(tag) if hw.look(/\{/) tdf = typedef tag[:type] = tdf[:type] tag[:optional] = true if tdf[:optional] end end # matches {...=} and returns text inside brackets def typedef match(/\{/) name = parse_balanced(/\{/, /\}/, /[^{}'"]*/) if name =~ /=$/ name = name.chop optional = true else optional = nil end match(/\}/) return {:type => name, :optional => optional} end # matches: <ident-chain> | "[" <ident-chain> [ "=" <default-value> ] "]" def add_name_with_default(tag) if hw.match(/\[/) tag[:name] = hw.ident_chain if hw.match(/=/) tag[:default] = hw.default_value end hw.match(/\]/) tag[:optional] = true else tag[:name] = hw.ident_chain end end # Attempts to allow balanced braces in default value. # When the nested parsing doesn't finish at closing "]", # roll back to beginning and simply grab anything up to closing "]". def default_value start_pos = @ds.input.pos value = parse_balanced(/\[/, /\]/, /[^\[\]'"]*/) if look(/\]/) value else @ds.input.pos = start_pos match(/[^\]]*/) end end # Helper method to parse a string up to a closing brace, # balancing opening-closing braces in between. # # @param re_open The beginning brace regex # @param re_close The closing brace regex # @param re_rest Regex to match text without any braces and strings def parse_balanced(re_open, re_close, re_rest) result = parse_with_strings(re_rest) while look(re_open) result += match(re_open) result += parse_balanced(re_open, re_close, re_rest) result += match(re_close) result += parse_with_strings(re_rest) end result end # Helper for parse_balanced to parse rest of the text between # braces, taking account the strings which might occur there. def parse_with_strings(re_rest) result = match(re_rest) while look(/['"]/) result += parse_string('"') if look(/"/) result += parse_string("'") if look(/'/) result += match(re_rest) end result end # Parses "..." or '...' including the escape sequence \' or '\" def parse_string(quote) re_quote = Regexp.new(quote) re_rest = Regexp.new("(?:[^"+quote+"\\\\]|\\\\.)*") match(re_quote) + match(re_rest) + (match(re_quote) || "") end ### Forward these calls to DocScanner def ident_chain @ds.ident_chain end def look(re) @ds.look(re) end def match(re) @ds.match(re) end def hw @ds.hw self end end end lib/jsduck/tag/cfg.rb +3 −4 Original line number Diff line number Diff line Loading @@ -9,10 +9,9 @@ module JsDuck::Tag # @cfg {Type} [name=default] (required) ... def parse(p) p.add_tag(:cfg) p.maybe_type p.maybe_name_with_default p.current_tag[:optional] = false if parse_required(p) tag = p.standard_tag({:tagname => :cfg}) tag[:optional] = false if parse_required(p) tag end def parse_required(p) Loading lib/jsduck/tag/css_var.rb +1 −3 Original line number Diff line number Diff line Loading @@ -9,9 +9,7 @@ module JsDuck::Tag # @var {Type} [name=default] ... def parse(p) p.add_tag(:css_var) p.maybe_type p.maybe_name_with_default p.standard_tag({:tagname => :css_var}) end end end lib/jsduck/tag/enum.rb +3 −4 Original line number Diff line number Diff line Loading @@ -9,10 +9,9 @@ module JsDuck::Tag # @enum {Type} [name=default] ... def parse(p) # @enum is a special case of class p.add_tag(:class) p.current_tag[:enum] = true p.maybe_type p.maybe_name_with_default tag = p.standard_tag({:tagname => :class}) tag[:enum] = true tag end end Loading Loading
lib/jsduck/doc_scanner.rb +12 −1 Original line number Diff line number Diff line require 'jsduck/tag_registry' require 'jsduck/standard_tag_parser' module JsDuck Loading @@ -21,6 +21,9 @@ module JsDuck # Provides access to the tag that's currently being parsed attr_reader :current_tag # Provides access to StringScanner attr_reader :input # Appends new @tag to parsed tags list def add_tag(tag) if tag.is_a?(Hash) Loading @@ -32,6 +35,14 @@ module JsDuck @current_tag[:doc] = "" unless @current_tag.has_key?(:doc) end # Parses standard pattern governing several builtin tags. # # @tag {Type} [some.name=default] # def standard_tag(tagdef) StandardTagParser.new(self).parse(tagdef) end # matches {type} if possible and sets it on @current_tag # Also checks for {optionality=} in type definition. def maybe_type Loading
lib/jsduck/standard_tag_parser.rb 0 → 100644 +134 −0 Original line number Diff line number Diff line module JsDuck # Helper in parsing the standard tag pattern with type definition # followed by name and default value: # # @tag {Type} [some.name=default] # class StandardTagParser # Initialized with DocScanner instance def initialize(doc_scanner) @ds = doc_scanner end # Parses our tag. def parse(tagdef) tag = tagdef add_type(tag) add_name_with_default(tag) tag end # matches {type} if possible and sets it on @current_tag # Also checks for {optionality=} in type definition. def add_type(tag) if hw.look(/\{/) tdf = typedef tag[:type] = tdf[:type] tag[:optional] = true if tdf[:optional] end end # matches {...=} and returns text inside brackets def typedef match(/\{/) name = parse_balanced(/\{/, /\}/, /[^{}'"]*/) if name =~ /=$/ name = name.chop optional = true else optional = nil end match(/\}/) return {:type => name, :optional => optional} end # matches: <ident-chain> | "[" <ident-chain> [ "=" <default-value> ] "]" def add_name_with_default(tag) if hw.match(/\[/) tag[:name] = hw.ident_chain if hw.match(/=/) tag[:default] = hw.default_value end hw.match(/\]/) tag[:optional] = true else tag[:name] = hw.ident_chain end end # Attempts to allow balanced braces in default value. # When the nested parsing doesn't finish at closing "]", # roll back to beginning and simply grab anything up to closing "]". def default_value start_pos = @ds.input.pos value = parse_balanced(/\[/, /\]/, /[^\[\]'"]*/) if look(/\]/) value else @ds.input.pos = start_pos match(/[^\]]*/) end end # Helper method to parse a string up to a closing brace, # balancing opening-closing braces in between. # # @param re_open The beginning brace regex # @param re_close The closing brace regex # @param re_rest Regex to match text without any braces and strings def parse_balanced(re_open, re_close, re_rest) result = parse_with_strings(re_rest) while look(re_open) result += match(re_open) result += parse_balanced(re_open, re_close, re_rest) result += match(re_close) result += parse_with_strings(re_rest) end result end # Helper for parse_balanced to parse rest of the text between # braces, taking account the strings which might occur there. def parse_with_strings(re_rest) result = match(re_rest) while look(/['"]/) result += parse_string('"') if look(/"/) result += parse_string("'") if look(/'/) result += match(re_rest) end result end # Parses "..." or '...' including the escape sequence \' or '\" def parse_string(quote) re_quote = Regexp.new(quote) re_rest = Regexp.new("(?:[^"+quote+"\\\\]|\\\\.)*") match(re_quote) + match(re_rest) + (match(re_quote) || "") end ### Forward these calls to DocScanner def ident_chain @ds.ident_chain end def look(re) @ds.look(re) end def match(re) @ds.match(re) end def hw @ds.hw self end end end
lib/jsduck/tag/cfg.rb +3 −4 Original line number Diff line number Diff line Loading @@ -9,10 +9,9 @@ module JsDuck::Tag # @cfg {Type} [name=default] (required) ... def parse(p) p.add_tag(:cfg) p.maybe_type p.maybe_name_with_default p.current_tag[:optional] = false if parse_required(p) tag = p.standard_tag({:tagname => :cfg}) tag[:optional] = false if parse_required(p) tag end def parse_required(p) Loading
lib/jsduck/tag/css_var.rb +1 −3 Original line number Diff line number Diff line Loading @@ -9,9 +9,7 @@ module JsDuck::Tag # @var {Type} [name=default] ... def parse(p) p.add_tag(:css_var) p.maybe_type p.maybe_name_with_default p.standard_tag({:tagname => :css_var}) end end end
lib/jsduck/tag/enum.rb +3 −4 Original line number Diff line number Diff line Loading @@ -9,10 +9,9 @@ module JsDuck::Tag # @enum {Type} [name=default] ... def parse(p) # @enum is a special case of class p.add_tag(:class) p.current_tag[:enum] = true p.maybe_type p.maybe_name_with_default tag = p.standard_tag({:tagname => :class}) tag[:enum] = true tag end end Loading