Loading doc_comment.rb +2 −198 Original line number Diff line number Diff line require 'strscan' require 'pp' module JsDuck class DocComment def initialize(input) @current_tag = {:doc => ""} @tags = {:default => @current_tag} parse(purify(input)) def initialize(tags) @tags = tags end # Sets the name property of the default at-tag. Loading Loading @@ -53,198 +49,6 @@ module JsDuck def [](tagname) @tags[tagname] end # Extracts content inside /** ... */ def purify(input) result = [] input.each_line do |line| line.chomp! if line =~ /\A\/\*\*/ || line =~ /\*\/\Z/ then # ignore first and last line elsif line =~ /\A\s*\*\s?(.*)\Z/ then result << $1 else result << line end end return result.join("\n") end def parse(input) @input = StringScanner.new(input) while !@input.eos? do if look(/@class\b/) then at_class elsif look(/@extends\b/) then at_extends elsif look(/@event\b/) then at_event elsif look(/@function\b/) then at_function elsif look(/@constructor\b/) then at_constructor elsif look(/@param\b/) then at_param elsif look(/@return\b/) then at_return elsif look(/@cfg\b/) then at_cfg elsif look(/@/) then @current_tag[:doc] += @input.scan(/@/) elsif look(/[^@]/) then @current_tag[:doc] += @input.scan(/[^@]+/) end end trim_docs end # The parsing process can leave whitespace at the ends of # doc-strings, here we get rid of it. def trim_docs # trim the :doc property of each at-tag @tags.each_value do |tag| if tag.instance_of?(Hash) && tag[:doc] tag[:doc].strip! end end # trim :doc properties of parameters @tags[:param] && @tags[:param].each {|p| p[:doc].strip!} end # matches @class name ... def at_class match(/@class/) @current_tag = @tags[:class] = {:doc => ""} skip_white if look(/\w/) then @current_tag[:name] = ident_chain end skip_white end # matches @extends name ... def at_extends match(/@extends/) unless @tags[:class] @tags[:class] = {:doc => ""} end @current_tag = @tags[:class] skip_white if look(/\w/) then @current_tag[:extends] = ident_chain end skip_white end # matches @event name ... def at_event match(/@event/) @current_tag = @tags[:event] = {:doc => ""} skip_white if look(/\w/) then @current_tag[:name] = ident end skip_white end # matches @function name ... def at_function match(/@function/) @current_tag = @tags[:function] = {:doc => ""} skip_white if look(/\w/) then @current_tag[:name] = ident end skip_white end # matches @constructor ... # Which is equivalent of: @function constructor ... def at_constructor match(/@constructor/) @current_tag = @tags[:function] = {:doc => "", :name => "constructor"} skip_white end # matches @param {type} variable ... def at_param match(/@param/) @current_tag = {:doc => ""} if @tags[:param] then @tags[:param] << @current_tag else @tags[:param] = [@current_tag] end skip_white if look(/\{/) then @current_tag[:type] = typedef end skip_white if look(/\w/) then @current_tag[:name] = ident end skip_white end # matches @return {type} ... def at_return match(/@return/) @current_tag = @tags[:return] = {:doc => ""} skip_white if look(/\{/) then @current_tag[:type] = typedef end skip_white end # matches @cfg {type} name ... def at_cfg match(/@cfg/) @current_tag = @tags[:cfg] = {:doc => ""} skip_white if look(/\{/) then @current_tag[:type] = typedef end skip_white if look(/\w/) then @current_tag[:name] = ident end skip_white end # matches {...} and returns text inside brackets def typedef match(/\{/) name = @input.scan(/[^}]+/) match(/\}/) return name end # matches chained.identifier.name and returns it def ident_chain @input.scan(/[\w.]+/) end # matches identifier and returns its name def ident @input.scan(/\w+/) end def look(re) @input.check(re) end def match(re) @input.scan(re) end def skip_white @input.scan(/\s+/) end def print pp @tags end end end doc_comment_parser.rb 0 → 100644 +206 −0 Original line number Diff line number Diff line require 'strscan' module JsDuck class DocCommentParser def parse(input) @current_tag = {:doc => ""} @tags = {:default => @current_tag} @input = StringScanner.new(purify(input)) parse_loop trim_docs @tags end def [](tagname) @tags[tagname] end # Extracts content inside /** ... */ def purify(input) result = [] input.each_line do |line| line.chomp! if line =~ /\A\/\*\*/ || line =~ /\*\/\Z/ then # ignore first and last line elsif line =~ /\A\s*\*\s?(.*)\Z/ then result << $1 else result << line end end return result.join("\n") end def parse_loop while !@input.eos? do if look(/@class\b/) then at_class elsif look(/@extends\b/) then at_extends elsif look(/@event\b/) then at_event elsif look(/@function\b/) then at_function elsif look(/@constructor\b/) then at_constructor elsif look(/@param\b/) then at_param elsif look(/@return\b/) then at_return elsif look(/@cfg\b/) then at_cfg elsif look(/@/) then @current_tag[:doc] += @input.scan(/@/) elsif look(/[^@]/) then @current_tag[:doc] += @input.scan(/[^@]+/) end end end # The parsing process can leave whitespace at the ends of # doc-strings, here we get rid of it. def trim_docs # trim the :doc property of each at-tag @tags.each_value do |tag| if tag.instance_of?(Hash) && tag[:doc] tag[:doc].strip! end end # trim :doc properties of parameters @tags[:param] && @tags[:param].each {|p| p[:doc].strip!} end # matches @class name ... def at_class match(/@class/) @current_tag = @tags[:class] = {:doc => ""} skip_white if look(/\w/) then @current_tag[:name] = ident_chain end skip_white end # matches @extends name ... def at_extends match(/@extends/) unless @tags[:class] @tags[:class] = {:doc => ""} end @current_tag = @tags[:class] skip_white if look(/\w/) then @current_tag[:extends] = ident_chain end skip_white end # matches @event name ... def at_event match(/@event/) @current_tag = @tags[:event] = {:doc => ""} skip_white if look(/\w/) then @current_tag[:name] = ident end skip_white end # matches @function name ... def at_function match(/@function/) @current_tag = @tags[:function] = {:doc => ""} skip_white if look(/\w/) then @current_tag[:name] = ident end skip_white end # matches @constructor ... # Which is equivalent of: @function constructor ... def at_constructor match(/@constructor/) @current_tag = @tags[:function] = {:doc => "", :name => "constructor"} skip_white end # matches @param {type} variable ... def at_param match(/@param/) @current_tag = {:doc => ""} if @tags[:param] then @tags[:param] << @current_tag else @tags[:param] = [@current_tag] end skip_white if look(/\{/) then @current_tag[:type] = typedef end skip_white if look(/\w/) then @current_tag[:name] = ident end skip_white end # matches @return {type} ... def at_return match(/@return/) @current_tag = @tags[:return] = {:doc => ""} skip_white if look(/\{/) then @current_tag[:type] = typedef end skip_white end # matches @cfg {type} name ... def at_cfg match(/@cfg/) @current_tag = @tags[:cfg] = {:doc => ""} skip_white if look(/\{/) then @current_tag[:type] = typedef end skip_white if look(/\w/) then @current_tag[:name] = ident end skip_white end # matches {...} and returns text inside brackets def typedef match(/\{/) name = @input.scan(/[^}]+/) match(/\}/) return name end # matches chained.identifier.name and returns it def ident_chain @input.scan(/[\w.]+/) end # matches identifier and returns its name def ident @input.scan(/\w+/) end def look(re) @input.check(re) end def match(re) @input.scan(re) end def skip_white @input.scan(/\s+/) end end end parser.rb +3 −1 Original line number Diff line number Diff line require 'lexer' require 'doc_comment_parser' require 'doc_comment' module JsDuck Loading @@ -6,13 +7,14 @@ module JsDuck class Parser def initialize(input) @lex = Lexer.new(input) @doc_parser = DocCommentParser.new @docs = [] end def parse while !@lex.empty? do if look(:doc_comment) then doc = DocComment.new(match(:doc_comment)) doc = DocComment.new(@doc_parser.parse(match(:doc_comment))) block = code_block if block[:type] == :function then doc.set_default_name(*block[:name]) if block[:name] Loading tc_doc_comment.rb→tc_doc_comment_parser.rb +13 −9 Original line number Diff line number Diff line require "doc_comment" require "doc_comment_parser" require "test/unit" class TestDocComment < Test::Unit::TestCase class TestDocCommentParser < Test::Unit::TestCase def parse_single(doc) return JsDuck::DocCommentParser.new.parse(doc) end def test_function doc = JsDuck::DocComment.new("/** doc = parse_single("/** * @function foo * Some docs. * @param {Number} x doc for x Loading @@ -29,7 +33,7 @@ class TestDocComment < Test::Unit::TestCase end def test_constructor doc = JsDuck::DocComment.new("/** doc = parse_single("/** * @constructor * Some docs. */") Loading @@ -38,7 +42,7 @@ class TestDocComment < Test::Unit::TestCase end def test_class doc = JsDuck::DocComment.new("/** doc = parse_single("/** * @class my.package.Foo * @extends my.Bar * Some docs. Loading @@ -49,7 +53,7 @@ class TestDocComment < Test::Unit::TestCase end def test_event doc = JsDuck::DocComment.new("/** doc = parse_single("/** * @event mousedown * Fires when the mouse button is depressed. */") Loading @@ -58,7 +62,7 @@ class TestDocComment < Test::Unit::TestCase end def test_cfg doc = JsDuck::DocComment.new("/** doc = parse_single("/** * @cfg {Boolean} enabled * True to enable this. */") Loading @@ -68,7 +72,7 @@ class TestDocComment < Test::Unit::TestCase end def test_long_docs doc = JsDuck::DocComment.new("/** doc = parse_single("/** * @function foo * * Some docs. Loading @@ -88,7 +92,7 @@ class TestDocComment < Test::Unit::TestCase end def test_typeless_docs doc = JsDuck::DocComment.new("/** doc = parse_single("/** * @param x doc1 * @return doc2 */") Loading Loading
doc_comment.rb +2 −198 Original line number Diff line number Diff line require 'strscan' require 'pp' module JsDuck class DocComment def initialize(input) @current_tag = {:doc => ""} @tags = {:default => @current_tag} parse(purify(input)) def initialize(tags) @tags = tags end # Sets the name property of the default at-tag. Loading Loading @@ -53,198 +49,6 @@ module JsDuck def [](tagname) @tags[tagname] end # Extracts content inside /** ... */ def purify(input) result = [] input.each_line do |line| line.chomp! if line =~ /\A\/\*\*/ || line =~ /\*\/\Z/ then # ignore first and last line elsif line =~ /\A\s*\*\s?(.*)\Z/ then result << $1 else result << line end end return result.join("\n") end def parse(input) @input = StringScanner.new(input) while !@input.eos? do if look(/@class\b/) then at_class elsif look(/@extends\b/) then at_extends elsif look(/@event\b/) then at_event elsif look(/@function\b/) then at_function elsif look(/@constructor\b/) then at_constructor elsif look(/@param\b/) then at_param elsif look(/@return\b/) then at_return elsif look(/@cfg\b/) then at_cfg elsif look(/@/) then @current_tag[:doc] += @input.scan(/@/) elsif look(/[^@]/) then @current_tag[:doc] += @input.scan(/[^@]+/) end end trim_docs end # The parsing process can leave whitespace at the ends of # doc-strings, here we get rid of it. def trim_docs # trim the :doc property of each at-tag @tags.each_value do |tag| if tag.instance_of?(Hash) && tag[:doc] tag[:doc].strip! end end # trim :doc properties of parameters @tags[:param] && @tags[:param].each {|p| p[:doc].strip!} end # matches @class name ... def at_class match(/@class/) @current_tag = @tags[:class] = {:doc => ""} skip_white if look(/\w/) then @current_tag[:name] = ident_chain end skip_white end # matches @extends name ... def at_extends match(/@extends/) unless @tags[:class] @tags[:class] = {:doc => ""} end @current_tag = @tags[:class] skip_white if look(/\w/) then @current_tag[:extends] = ident_chain end skip_white end # matches @event name ... def at_event match(/@event/) @current_tag = @tags[:event] = {:doc => ""} skip_white if look(/\w/) then @current_tag[:name] = ident end skip_white end # matches @function name ... def at_function match(/@function/) @current_tag = @tags[:function] = {:doc => ""} skip_white if look(/\w/) then @current_tag[:name] = ident end skip_white end # matches @constructor ... # Which is equivalent of: @function constructor ... def at_constructor match(/@constructor/) @current_tag = @tags[:function] = {:doc => "", :name => "constructor"} skip_white end # matches @param {type} variable ... def at_param match(/@param/) @current_tag = {:doc => ""} if @tags[:param] then @tags[:param] << @current_tag else @tags[:param] = [@current_tag] end skip_white if look(/\{/) then @current_tag[:type] = typedef end skip_white if look(/\w/) then @current_tag[:name] = ident end skip_white end # matches @return {type} ... def at_return match(/@return/) @current_tag = @tags[:return] = {:doc => ""} skip_white if look(/\{/) then @current_tag[:type] = typedef end skip_white end # matches @cfg {type} name ... def at_cfg match(/@cfg/) @current_tag = @tags[:cfg] = {:doc => ""} skip_white if look(/\{/) then @current_tag[:type] = typedef end skip_white if look(/\w/) then @current_tag[:name] = ident end skip_white end # matches {...} and returns text inside brackets def typedef match(/\{/) name = @input.scan(/[^}]+/) match(/\}/) return name end # matches chained.identifier.name and returns it def ident_chain @input.scan(/[\w.]+/) end # matches identifier and returns its name def ident @input.scan(/\w+/) end def look(re) @input.check(re) end def match(re) @input.scan(re) end def skip_white @input.scan(/\s+/) end def print pp @tags end end end
doc_comment_parser.rb 0 → 100644 +206 −0 Original line number Diff line number Diff line require 'strscan' module JsDuck class DocCommentParser def parse(input) @current_tag = {:doc => ""} @tags = {:default => @current_tag} @input = StringScanner.new(purify(input)) parse_loop trim_docs @tags end def [](tagname) @tags[tagname] end # Extracts content inside /** ... */ def purify(input) result = [] input.each_line do |line| line.chomp! if line =~ /\A\/\*\*/ || line =~ /\*\/\Z/ then # ignore first and last line elsif line =~ /\A\s*\*\s?(.*)\Z/ then result << $1 else result << line end end return result.join("\n") end def parse_loop while !@input.eos? do if look(/@class\b/) then at_class elsif look(/@extends\b/) then at_extends elsif look(/@event\b/) then at_event elsif look(/@function\b/) then at_function elsif look(/@constructor\b/) then at_constructor elsif look(/@param\b/) then at_param elsif look(/@return\b/) then at_return elsif look(/@cfg\b/) then at_cfg elsif look(/@/) then @current_tag[:doc] += @input.scan(/@/) elsif look(/[^@]/) then @current_tag[:doc] += @input.scan(/[^@]+/) end end end # The parsing process can leave whitespace at the ends of # doc-strings, here we get rid of it. def trim_docs # trim the :doc property of each at-tag @tags.each_value do |tag| if tag.instance_of?(Hash) && tag[:doc] tag[:doc].strip! end end # trim :doc properties of parameters @tags[:param] && @tags[:param].each {|p| p[:doc].strip!} end # matches @class name ... def at_class match(/@class/) @current_tag = @tags[:class] = {:doc => ""} skip_white if look(/\w/) then @current_tag[:name] = ident_chain end skip_white end # matches @extends name ... def at_extends match(/@extends/) unless @tags[:class] @tags[:class] = {:doc => ""} end @current_tag = @tags[:class] skip_white if look(/\w/) then @current_tag[:extends] = ident_chain end skip_white end # matches @event name ... def at_event match(/@event/) @current_tag = @tags[:event] = {:doc => ""} skip_white if look(/\w/) then @current_tag[:name] = ident end skip_white end # matches @function name ... def at_function match(/@function/) @current_tag = @tags[:function] = {:doc => ""} skip_white if look(/\w/) then @current_tag[:name] = ident end skip_white end # matches @constructor ... # Which is equivalent of: @function constructor ... def at_constructor match(/@constructor/) @current_tag = @tags[:function] = {:doc => "", :name => "constructor"} skip_white end # matches @param {type} variable ... def at_param match(/@param/) @current_tag = {:doc => ""} if @tags[:param] then @tags[:param] << @current_tag else @tags[:param] = [@current_tag] end skip_white if look(/\{/) then @current_tag[:type] = typedef end skip_white if look(/\w/) then @current_tag[:name] = ident end skip_white end # matches @return {type} ... def at_return match(/@return/) @current_tag = @tags[:return] = {:doc => ""} skip_white if look(/\{/) then @current_tag[:type] = typedef end skip_white end # matches @cfg {type} name ... def at_cfg match(/@cfg/) @current_tag = @tags[:cfg] = {:doc => ""} skip_white if look(/\{/) then @current_tag[:type] = typedef end skip_white if look(/\w/) then @current_tag[:name] = ident end skip_white end # matches {...} and returns text inside brackets def typedef match(/\{/) name = @input.scan(/[^}]+/) match(/\}/) return name end # matches chained.identifier.name and returns it def ident_chain @input.scan(/[\w.]+/) end # matches identifier and returns its name def ident @input.scan(/\w+/) end def look(re) @input.check(re) end def match(re) @input.scan(re) end def skip_white @input.scan(/\s+/) end end end
parser.rb +3 −1 Original line number Diff line number Diff line require 'lexer' require 'doc_comment_parser' require 'doc_comment' module JsDuck Loading @@ -6,13 +7,14 @@ module JsDuck class Parser def initialize(input) @lex = Lexer.new(input) @doc_parser = DocCommentParser.new @docs = [] end def parse while !@lex.empty? do if look(:doc_comment) then doc = DocComment.new(match(:doc_comment)) doc = DocComment.new(@doc_parser.parse(match(:doc_comment))) block = code_block if block[:type] == :function then doc.set_default_name(*block[:name]) if block[:name] Loading
tc_doc_comment.rb→tc_doc_comment_parser.rb +13 −9 Original line number Diff line number Diff line require "doc_comment" require "doc_comment_parser" require "test/unit" class TestDocComment < Test::Unit::TestCase class TestDocCommentParser < Test::Unit::TestCase def parse_single(doc) return JsDuck::DocCommentParser.new.parse(doc) end def test_function doc = JsDuck::DocComment.new("/** doc = parse_single("/** * @function foo * Some docs. * @param {Number} x doc for x Loading @@ -29,7 +33,7 @@ class TestDocComment < Test::Unit::TestCase end def test_constructor doc = JsDuck::DocComment.new("/** doc = parse_single("/** * @constructor * Some docs. */") Loading @@ -38,7 +42,7 @@ class TestDocComment < Test::Unit::TestCase end def test_class doc = JsDuck::DocComment.new("/** doc = parse_single("/** * @class my.package.Foo * @extends my.Bar * Some docs. Loading @@ -49,7 +53,7 @@ class TestDocComment < Test::Unit::TestCase end def test_event doc = JsDuck::DocComment.new("/** doc = parse_single("/** * @event mousedown * Fires when the mouse button is depressed. */") Loading @@ -58,7 +62,7 @@ class TestDocComment < Test::Unit::TestCase end def test_cfg doc = JsDuck::DocComment.new("/** doc = parse_single("/** * @cfg {Boolean} enabled * True to enable this. */") Loading @@ -68,7 +72,7 @@ class TestDocComment < Test::Unit::TestCase end def test_long_docs doc = JsDuck::DocComment.new("/** doc = parse_single("/** * @function foo * * Some docs. Loading @@ -88,7 +92,7 @@ class TestDocComment < Test::Unit::TestCase end def test_typeless_docs doc = JsDuck::DocComment.new("/** doc = parse_single("/** * @param x doc1 * @return doc2 */") Loading