diff --git a/lib/jsduck/assets.rb b/lib/jsduck/assets.rb index 02085a51f13dc9543ea64ca2ceb3bba3cbe14a96..d28089a0230912615c6ff134bdd93418b623c7e0 100644 --- a/lib/jsduck/assets.rb +++ b/lib/jsduck/assets.rb @@ -27,8 +27,7 @@ module JsDuck @relations = relations @opts = opts - doc_formatter = DocFormatter.new(@opts) - doc_formatter.relations = @relations + doc_formatter = DocFormatter.new(@relations, @opts) @images = Img::DirSet.new(@opts.images, "images") @welcome = Welcome.create(@opts.welcome, doc_formatter) diff --git a/lib/jsduck/batch_formatter.rb b/lib/jsduck/batch_formatter.rb index 402083a131b0482a019e19bbdc7662df35ff835b..0553db6f6f23f64d6b56187a65d015c576c394b0 100644 --- a/lib/jsduck/batch_formatter.rb +++ b/lib/jsduck/batch_formatter.rb @@ -45,8 +45,7 @@ module JsDuck # Factory method to create new ClassFormatter instances. def self.create_class_formatter(relations, opts) - doc_formatter = DocFormatter.new(opts) - doc_formatter.relations = relations + doc_formatter = DocFormatter.new(relations, opts) doc_formatter.images = Img::DirSet.new(opts.images, "images") class_formatter = ClassFormatter.new(relations, doc_formatter) diff --git a/lib/jsduck/doc_formatter.rb b/lib/jsduck/doc_formatter.rb index 433d14347d1f2df4d7f6209b80a707950562e39a..3e2fcee91ae39a38c1fbd1129e09313bbc34d6f1 100644 --- a/lib/jsduck/doc_formatter.rb +++ b/lib/jsduck/doc_formatter.rb @@ -3,6 +3,8 @@ require 'strscan' require 'rdiscount' require 'jsduck/html_stack' require 'jsduck/inline/link' +require 'jsduck/inline/auto_link' +require 'jsduck/inline/link_renderer' require 'jsduck/inline/img' require 'jsduck/inline/video' require 'jsduck/inline/example' @@ -15,9 +17,11 @@ module JsDuck # Creates a formatter configured with options originating from # command line. For the actual effect of the options see # Inline::* classes. - def initialize(opts={}) + def initialize(relations={}, opts={}) @opts = opts - @inline_link = Inline::Link.new(opts) + @link_renderer = Inline::LinkRenderer.new(relations, opts) + @inline_link = Inline::Link.new(@link_renderer) + @auto_link = Inline::AutoLink.new(@link_renderer) @inline_img = Inline::Img.new(opts) @inline_video = Inline::Video.new(opts) @inline_example = Inline::Example.new(opts) @@ -37,6 +41,7 @@ module JsDuck # Context#blah is meant. def class_context=(cls) @inline_link.class_context = cls + @auto_link.class_context = cls end # Sets up instance to work in context of particular doc object. @@ -45,6 +50,7 @@ module JsDuck @doc_context = doc @inline_video.doc_context = doc @inline_link.doc_context = doc + @auto_link.doc_context = doc @inline_img.doc_context = doc end @@ -53,15 +59,6 @@ module JsDuck @doc_context end - # JsDuck::Relations for looking up class names. - # - # When auto-creating class links from CamelCased names found from - # text, we check the relations object to see if a class with that - # name actually exists. - def relations=(relations) - @inline_link.relations = relations - end - # Formats doc-comment for placement into HTML. # Renders it with Markdown-formatter and replaces @link-s. def format(input) @@ -127,7 +124,7 @@ module JsDuck # Replace class names in the following text up to next "<" or "{" # but only when we're not inside ... text = s.scan(/[^{<]+/) - out += tags.open?("a") ? text : @inline_link.create_magic_links(text) + out += tags.open?("a") ? text : @auto_link.replace(text) end end @@ -136,7 +133,7 @@ module JsDuck # Creates a link based on the link template. def link(cls, member, anchor_text, type=nil, static=nil) - @inline_link.link(cls, member, anchor_text, type, static) + @link_renderer.link(cls, member, anchor_text, type, static) end end diff --git a/lib/jsduck/inline/auto_link.rb b/lib/jsduck/inline/auto_link.rb new file mode 100644 index 0000000000000000000000000000000000000000..c118b2d70f7061df7d55ebea74f4ec7120c8ec60 --- /dev/null +++ b/lib/jsduck/inline/auto_link.rb @@ -0,0 +1,106 @@ +require 'jsduck/logger' + +module JsDuck + module Inline + + # Takes care of the auto-detection of links in text. + class AutoLink + # Sets up instance to work in context of particular class, so it + # knows that #blah is in context of SomeClass. + attr_accessor :class_context + + # Sets up instance to work in context of particular doc object. + # Used for error reporting. + attr_accessor :doc_context + + def initialize(link_renderer) + @class_context = "" + @doc_context = {} + @relations = link_renderer.relations + @renderer = link_renderer + @magic_link_re = magic_link_re + end + + # Looks input text for patterns like: + # + # My.ClassName + # MyClass#method + # #someProperty + # + # and converts them to links, as if they were surrounded with + # {@link} tag. One notable exception is that Foo is not created to + # link, even when Foo class exists, but Foo.Bar is. This is to + # avoid turning normal words into links. For example: + # + # Math involves a lot of numbers. Ext JS is a JavaScript framework. + # + # In these sentences we don't want to link "Math" and "Ext" to the + # corresponding JS classes. And that's why we auto-link only + # class names containing a dot "." + # + def replace(input) + input.gsub(@magic_link_re) do + cls = $1 || $3 + member = $2 || $4 + replace_magic_link(cls, member) + end + end + + private + + # Generates regex for auto-linking class and member names in text. + def magic_link_re + ident_re = "(?:[A-Za-z_$][A-Za-z0-9_$]*)" + cls_re = "(#{ident_re}(?:\\.#{ident_re})*)" + ns_cls_re = "(#{ident_re}(?:\\.#{ident_re})+)" + member_re = "(?:#(#{ident_re}))" + /#{cls_re}#{member_re}|#{ns_cls_re}|#{member_re}/m + end + + def replace_magic_link(cls, member) + if cls && member + if @relations[cls] && @renderer.get_matching_member(cls, {:name => member}) + return @renderer.link(cls, member, cls+"."+member) + else + warn_magic_link("#{cls}##{member} links to non-existing " + (@relations[cls] ? "member" : "class")) + end + elsif cls + if @relations[cls] + return @renderer.link(cls, nil, cls) + else + cls2, member2 = split_to_cls_and_member(cls) + if @relations[cls2] && @renderer.get_matching_member(cls2, {:name => member2}) + return @renderer.link(cls2, member2, cls2+"."+member2) + elsif cls =~ /\.(js|css|html|php)\Z/ + # Ignore common filenames + else + warn_magic_link("#{cls} links to non-existing class") + end + end + else + if @renderer.get_matching_member(@class_context, {:name => member}) + return @renderer.link(@class_context, member, member) + elsif member =~ /\A([A-F0-9]{3}|[A-F0-9]{6})\Z/i || member =~ /\A[0-9]/ + # Ignore HEX color codes and + # member names beginning with number + else + warn_magic_link("##{member} links to non-existing member") + end + end + + return "#{cls}#{member ? '#' : ''}#{member}" + end + + def split_to_cls_and_member(str) + parts = str.split(/\./) + return [parts.slice(0, parts.length-1).join("."), parts.last] + end + + def warn_magic_link(msg) + Logger.warn(:link_auto, msg, @doc_context[:filename], @doc_context[:linenr]) + end + + end + + end +end diff --git a/lib/jsduck/inline/link.rb b/lib/jsduck/inline/link.rb index bf39ac3b46e1300c3d9636e182248ed949184017..41f61f6c5fef6aa1697b49eb3ee06c730d120829 100644 --- a/lib/jsduck/inline/link.rb +++ b/lib/jsduck/inline/link.rb @@ -1,4 +1,3 @@ -require 'jsduck/util/html' require 'jsduck/logger' require 'jsduck/tag_registry' @@ -19,28 +18,11 @@ module JsDuck # Used for error reporting. attr_accessor :doc_context - # JsDuck::Relations for looking up class names. - # - # When auto-creating class links from CamelCased names found from - # text, we check the relations object to see if a class with that - # name actually exists. - attr_accessor :relations - - def initialize(opts={}) + def initialize(link_renderer) @class_context = "" @doc_context = {} - @relations = {} - - # Template HTML that replaces {@link Class#member anchor text}. - # Can contain placeholders: - # - # %c - full class name (e.g. "Ext.Panel") - # %m - class member name prefixed with member type (e.g. "method-urlEncode") - # %# - inserts "#" if member name present - # %- - inserts "-" if member name present - # %a - anchor text for link - @tpl = opts[:link_tpl] || '%a' - + @relations = link_renderer.relations + @renderer = link_renderer @re = /\{@link\s+(\S*?)(?:\s+(.+?))?\}/m end @@ -86,7 +68,7 @@ module JsDuck Logger.warn(:link, "#{full_link} links to non-existing class", file, line) return text elsif member - ms = find_members(cls, {:name => member, :tagname => type, :static => static}) + ms = @renderer.find_members(cls, {:name => member, :tagname => type, :static => static}) if ms.length == 0 Logger.warn(:link, "#{full_link} links to non-existing member", file, line) return text @@ -108,120 +90,12 @@ module JsDuck end end - return link(cls, member, text, type, static) + return @renderer.link(cls, member, text, type, static) else - return link(cls, false, text) + return @renderer.link(cls, false, text) end end - # Looks input text for patterns like: - # - # My.ClassName - # MyClass#method - # #someProperty - # - # and converts them to links, as if they were surrounded with - # {@link} tag. One notable exception is that Foo is not created to - # link, even when Foo class exists, but Foo.Bar is. This is to - # avoid turning normal words into links. For example: - # - # Math involves a lot of numbers. Ext JS is a JavaScript framework. - # - # In these sentences we don't want to link "Math" and "Ext" to the - # corresponding JS classes. And that's why we auto-link only - # class names containing a dot "." - # - def create_magic_links(input) - cls_re = "([A-Z][A-Za-z0-9.]*[A-Za-z0-9])" - member_re = "(?:#([A-Za-z0-9]+))" - - input.gsub(/\b#{cls_re}#{member_re}?\b|#{member_re}\b/m) do - replace_magic_link($1, $2 || $3) - end - end - - def replace_magic_link(cls, member) - if cls && member - if @relations[cls] && get_matching_member(cls, {:name => member}) - return link(cls, member, cls+"."+member) - else - warn_magic_link("#{cls}##{member} links to non-existing " + (@relations[cls] ? "member" : "class")) - end - elsif cls && cls =~ /\./ - if @relations[cls] - return link(cls, nil, cls) - else - cls2, member2 = split_to_cls_and_member(cls) - if @relations[cls2] && get_matching_member(cls2, {:name => member2}) - return link(cls2, member2, cls2+"."+member2) - elsif cls =~ /\.(js|css|html|php)\Z/ - # Ignore common filenames - else - warn_magic_link("#{cls} links to non-existing class") - end - end - elsif !cls && member - if get_matching_member(@class_context, {:name => member}) - return link(@class_context, member, member) - elsif member =~ /\A([A-F0-9]{3}|[A-F0-9]{6})\Z/i || member =~ /\A[0-9]/ - # Ignore HEX color codes and - # member names beginning with number - else - warn_magic_link("##{member} links to non-existing member") - end - end - - return "#{cls}#{member ? '#' : ''}#{member}" - end - - def split_to_cls_and_member(str) - parts = str.split(/\./) - return [parts.slice(0, parts.length-1).join("."), parts.last] - end - - def warn_magic_link(msg) - Logger.warn(:link_auto, msg, @doc_context[:filename], @doc_context[:linenr]) - end - - # applies the link template - def link(cls, member, anchor_text, type=nil, static=nil) - # Use the canonical class name for link (not some alternateClassName) - cls = @relations[cls][:name] - # prepend type name to member name - member = member && get_matching_member(cls, {:name => member, :tagname => type, :static => static}) - - @tpl.gsub(/(%[\w#-])/) do - case $1 - when '%c' - cls - when '%m' - member ? member[:id] : "" - when '%#' - member ? "#" : "" - when '%-' - member ? "-" : "" - when '%a' - Util::HTML.escape(anchor_text||"") - else - $1 - end - end - end - - def get_matching_member(cls, query) - ms = find_members(cls, query) - if ms.length > 1 - instance_ms = ms.find_all {|m| !m[:static] } - instance_ms.length > 0 ? instance_ms[0] : ms.find_all {|m| m[:static] }[0] - else - ms[0] - end - end - - def find_members(cls, query) - @relations[cls] ? @relations[cls].find_members(query) : [] - end - end end diff --git a/lib/jsduck/inline/link_renderer.rb b/lib/jsduck/inline/link_renderer.rb new file mode 100644 index 0000000000000000000000000000000000000000..6d81848ec3bfbca73d1df954cf894f8f125df3a8 --- /dev/null +++ b/lib/jsduck/inline/link_renderer.rb @@ -0,0 +1,69 @@ +require 'jsduck/util/html' + +module JsDuck + module Inline + + # Renders HTML link class or member. + class LinkRenderer + # Access to relations object, used by Inline::Link and + # Inline::AutoLink. + attr_reader :relations + + def initialize(relations={}, opts={}) + @relations = relations + + # Template HTML that replaces {@link Class#member anchor text}. + # Can contain placeholders: + # + # %c - full class name (e.g. "Ext.Panel") + # %m - class member name prefixed with member type (e.g. "method-urlEncode") + # %# - inserts "#" if member name present + # %- - inserts "-" if member name present + # %a - anchor text for link + @tpl = opts[:link_tpl] || '%a' + end + + # Generates HTML link to class or member applying the link + # template. + def link(cls, member, anchor_text, type=nil, static=nil) + # Use the canonical class name for link (not some alternateClassName) + cls = @relations[cls][:name] + # prepend type name to member name + member = member && get_matching_member(cls, {:name => member, :tagname => type, :static => static}) + + @tpl.gsub(/(%[\w#-])/) do + case $1 + when '%c' + cls + when '%m' + member ? member[:id] : "" + when '%#' + member ? "#" : "" + when '%-' + member ? "-" : "" + when '%a' + Util::HTML.escape(anchor_text||"") + else + $1 + end + end + end + + def get_matching_member(cls, query) + ms = find_members(cls, query) + if ms.length > 1 + instance_ms = ms.find_all {|m| !m[:static] } + instance_ms.length > 0 ? instance_ms[0] : ms.find_all {|m| m[:static] }[0] + else + ms[0] + end + end + + def find_members(cls, query) + @relations[cls] ? @relations[cls].find_members(query) : [] + end + + end + + end +end diff --git a/spec/doc_formatter_spec.rb b/spec/doc_formatter_spec.rb index 7cbe18d1c3653d984bfdfb47f13244b6cfb8869f..00629342b3809288e5a74fdc599468dbd69dd563 100644 --- a/spec/doc_formatter_spec.rb +++ b/spec/doc_formatter_spec.rb @@ -11,37 +11,37 @@ describe JsDuck::DocFormatter do end end - before do - @formatter = JsDuck::DocFormatter.new(:img_tpl => '%a') - @formatter.class_context = "Context" - @formatter.images = ImageDirMock.new - @formatter.relations = JsDuck::Relations.new([ - JsDuck::Class.new({ - :name => "Context", - :members => [ - {:tagname => :method, :name => "bar", :id => "method-bar"}, - {:tagname => :method, :name => "id", :id => "static-method-id", - :static => true}, - ], - }), - JsDuck::Class.new({ - :name => 'Ext.Msg' - }), - JsDuck::Class.new({ - :name => "Foo", - :members => [ - {:tagname => :cfg, :name => "bar", :id => "cfg-bar"}, - {:tagname => :method, :name => "id", :id => "static-method-id", - :static => true}, - {:tagname => :method, :name => "privMeth", :id => "method-privMeth", :private => true}, - ], - :alternateClassNames => ["FooBar"] - }), - ]) - end - describe "#replace" do + before do + relations = JsDuck::Relations.new([ + JsDuck::Class.new({ + :name => "Context", + :members => [ + {:tagname => :method, :name => "bar", :id => "method-bar"}, + {:tagname => :method, :name => "id", :id => "static-method-id", + :static => true}, + ], + }), + JsDuck::Class.new({ + :name => 'Ext.Msg' + }), + JsDuck::Class.new({ + :name => "Foo", + :members => [ + {:tagname => :cfg, :name => "bar", :id => "cfg-bar"}, + {:tagname => :method, :name => "id", :id => "static-method-id", + :static => true}, + {:tagname => :method, :name => "privMeth", :id => "method-privMeth", :private => true}, + ], + :alternateClassNames => ["FooBar"] + }), + ]) + @formatter = JsDuck::DocFormatter.new(relations, :img_tpl => '%a') + @formatter.class_context = "Context" + @formatter.images = ImageDirMock.new + end + # {@link ...} it "replaces {@link Ext.Msg} with link to class" do @@ -137,238 +137,282 @@ describe JsDuck::DocFormatter do @formatter.replace("{@video vimeo 123456 Alt text}").should =~ // end + end - # auto-conversion of identifiable ClassNames to links - describe "auto-detect" do - before do - @formatter.class_context = "Context" - @formatter.images = ImageDirMock.new - @formatter.relations = JsDuck::Relations.new([ - JsDuck::Class.new({:name => 'Foo.Bar'}), - JsDuck::Class.new({:name => 'Foo.Bar.Blah'}), - JsDuck::Class.new({ - :name => 'Ext.form.Field', - :members => [ - {:tagname => :method, :name => "getValues", :id => "method-getValues"} - ] - }), - JsDuck::Class.new({ - :name => 'Ext.XTemplate', - :alternateClassNames => ['Ext.AltXTemplate'] - }), - JsDuck::Class.new({ - :name => 'Ext', - :members => [ - {:tagname => :method, :name => "encode", :id => "method-encode"} - ] - }), - JsDuck::Class.new({ - :name => "Context", - :members => [ - {:tagname => :method, :name => "bar", :id => "method-bar"}, - {:tagname => :method, :name => "privMeth", :id => "method-privMeth", :private => true}, - ] - }), - ]) - end + # auto-conversion of identifiable ClassNames to links + describe "#replace auto-detect" do + before do + relations = JsDuck::Relations.new([ + JsDuck::Class.new({:name => 'Foo.Bar'}), + JsDuck::Class.new({:name => 'Foo.Bar.Blah'}), + JsDuck::Class.new({ + :name => 'Ext.form.Field', + :members => [ + {:tagname => :method, :name => "getValues", :id => "method-getValues"} + ] + }), + JsDuck::Class.new({ + :name => 'Ext.XTemplate', + :alternateClassNames => ['Ext.AltXTemplate'] + }), + JsDuck::Class.new({ + :name => 'Ext', + :members => [ + {:tagname => :method, :name => "encode", :id => "method-encode"} + ] + }), + JsDuck::Class.new({ + :name => "Context", + :members => [ + {:tagname => :method, :name => "bar", :id => "method-bar"}, + {:tagname => :method, :name => "privMeth", :id => "method-privMeth", :private => true}, + ] + }), + JsDuck::Class.new({ + :name => "downcase.ClassName", + :members => [ + {:tagname => :method, :name => "blah", :id => "method-blah"}, + ] + }), + JsDuck::Class.new({ + :name => "_us.In_Cls_Name", + :members => [ + {:tagname => :method, :name => "_sss", :id => "method-_sss"}, + ] + }), + JsDuck::Class.new({ + :name => "$Class", + :members => [ + {:tagname => :method, :name => "$sss", :id => "method-S-sss"}, + ] + }), + ]) + @formatter = JsDuck::DocFormatter.new(relations, :img_tpl => '%a') + @formatter.class_context = "Context" + @formatter.images = ImageDirMock.new + end - it "doesn't recognize John as class name" do - @formatter.replace("John is lazy").should == - "John is lazy" - end + it "doesn't recognize John as class name" do + @formatter.replace("John is lazy").should == + "John is lazy" + end - it "doesn't recognize Bla.Bla as class name" do - @formatter.replace("Unknown Bla.Bla class").should == - "Unknown Bla.Bla class" - end + it "doesn't recognize Bla.Bla as class name" do + @formatter.replace("Unknown Bla.Bla class").should == + "Unknown Bla.Bla class" + end - it "doesn't recognize Ext as class name" do - @formatter.replace("Talking about Ext JS").should == - "Talking about Ext JS" - end + it "doesn't recognize Ext as class name" do + @formatter.replace("Talking about Ext JS").should == + "Talking about Ext JS" + end - it "converts Foo.Bar to class link" do - @formatter.replace("Look at Foo.Bar").should == - 'Look at Foo.Bar' - end + it "converts Foo.Bar to class link" do + @formatter.replace("Look at Foo.Bar").should == + 'Look at Foo.Bar' + end - it "converts FooBar.Blah to class link" do - @formatter.replace("Look at Foo.Bar.Blah").should == - 'Look at Foo.Bar.Blah' - end + it "converts FooBar.Blah to class link" do + @formatter.replace("Look at Foo.Bar.Blah").should == + 'Look at Foo.Bar.Blah' + end - it "converts Ext.form.Field to class link" do - @formatter.replace("Look at Ext.form.Field").should == - 'Look at Ext.form.Field' - end + it "converts Ext.form.Field to class link" do + @formatter.replace("Look at Ext.form.Field").should == + 'Look at Ext.form.Field' + end - it "converts Ext.XTemplate to class link" do - @formatter.replace("Look at Ext.XTemplate").should == - 'Look at Ext.XTemplate' - end + it "converts Ext.XTemplate to class link" do + @formatter.replace("Look at Ext.XTemplate").should == + 'Look at Ext.XTemplate' + end - it "links alternate classname to canonical classname" do - @formatter.replace("Look at Ext.AltXTemplate").should == - 'Look at Ext.AltXTemplate' - end + it "links alternate classname to canonical classname" do + @formatter.replace("Look at Ext.AltXTemplate").should == + 'Look at Ext.AltXTemplate' + end - it "converts ClassName ending with dot to class link" do - @formatter.replace("Look at Foo.Bar.").should == - 'Look at Foo.Bar.' - end + it "converts downcase.ClassName to class link" do + @formatter.replace("Look at downcase.ClassName").should == + 'Look at downcase.ClassName' + end - it "converts ClassName ending with comma to class link" do - @formatter.replace("Look at Foo.Bar, it's great!").should == - 'Look at Foo.Bar, it\'s great!' - end + it "converts classname with underscores to class link" do + @formatter.replace("Look at _us.In_Cls_Name").should == + 'Look at _us.In_Cls_Name' + end - it "converts two ClassNames in one line to links" do - @formatter.replace("See: Foo.Bar, Ext.XTemplate").should == - 'See: Foo.Bar, Ext.XTemplate' - end + it "converts ClassName ending with dot to class link" do + @formatter.replace("Look at Foo.Bar.").should == + 'Look at Foo.Bar.' + end - # Links to #members + it "converts ClassName ending with comma to class link" do + @formatter.replace("Look at Foo.Bar, it's great!").should == + 'Look at Foo.Bar, it\'s great!' + end - it "converts Ext#encode to method link" do - @formatter.replace("Look at Ext#encode").should == - 'Look at Ext.encode' - end + it "converts two ClassNames in one line to links" do + @formatter.replace("See: Foo.Bar, Ext.XTemplate").should == + 'See: Foo.Bar, Ext.XTemplate' + end - it "converts Ext.form.Field#getValues to method link" do - @formatter.replace("Look at Ext.form.Field#getValues").should == - 'Look at Ext.form.Field.getValues' - end + # Links to #members - it "converts Ext.encode to method link" do - @formatter.replace("Look at Ext.encode").should == - 'Look at Ext.encode' - end + it "converts Ext#encode to method link" do + @formatter.replace("Look at Ext#encode").should == + 'Look at Ext.encode' + end - it "converts #bar to link to current class method" do - @formatter.replace("Look at #bar method").should == - 'Look at bar method' - end + it "converts Ext.form.Field#getValues to method link" do + @formatter.replace("Look at Ext.form.Field#getValues").should == + 'Look at Ext.form.Field.getValues' + end - it "converts #privMeth to link to private method" do - @formatter.replace("Look at #privMeth method").should == - 'Look at privMeth method' - end + it "converts downcase.ClassName#blah to method link" do + @formatter.replace("Look at downcase.ClassName#blah").should == + 'Look at downcase.ClassName.blah' + end - it "Doesn't convert #unknown to link" do - @formatter.replace("Ahh, an #unknown method").should == - 'Ahh, an #unknown method' - end + it 'converts $Class#$sss to method link' do + @formatter.replace('Look at $Class#$sss').should == + 'Look at $Class.$sss' + end + + it "converts Ext.encode to method link" do + @formatter.replace("Look at Ext.encode").should == + 'Look at Ext.encode' + end - # Ensure links aren't created inside ... or {@link} and {@img} tags. + it "converts #bar to link to current class method" do + @formatter.replace("Look at #bar method").should == + 'Look at bar method' + end - it "doesn't create links inside {@link} tag" do - @formatter.replace("{@link Foo.Bar a Foo.Bar link}").should == - 'a Foo.Bar link' - end + it "converts #privMeth to link to private method" do + @formatter.replace("Look at #privMeth method").should == + 'Look at privMeth method' + end - it "doesn't create links inside {@img} tag" do - @formatter.replace("{@img some/file.jpg a Foo.Bar image}").should == - 'a Foo.Bar image' - end + it "Doesn't convert #unknown to link" do + @formatter.replace("Ahh, an #unknown method").should == + 'Ahh, an #unknown method' + end - it "doesn't create links inside HTML tags" do - @formatter.replace('').should == - '' - end + # Ensure links aren't created inside ... or {@link} and {@img} tags. - it "doesn't create links inside multiline HTML tags" do - @formatter.replace('').should == - '' - end + it "doesn't create links inside {@link} tag" do + @formatter.replace("{@link Foo.Bar a Foo.Bar link}").should == + 'a Foo.Bar link' + end - it "doesn't create links inside ..." do - @formatter.replace('See Foo.Bar').should == - 'See Foo.Bar' - end + it "doesn't create links inside {@img} tag" do + @formatter.replace("{@img some/file.jpg a Foo.Bar image}").should == + 'a Foo.Bar image' + end - it "creates links inside ..." do - @formatter.replace('See Foo.Bar').should == - 'See Foo.Bar' - end + it "doesn't create links inside HTML tags" do + @formatter.replace('').should == + '' + end - it "doesn't create links inside ..." do - @formatter.replace('See Foo.Bar').should == - 'See Foo.Bar' - end + it "doesn't create links inside multiline HTML tags" do + @formatter.replace('').should == + '' + end - it "creates links after ..." do - @formatter.replace('See Foo.Bar and Ext.XTemplate.').should == - 'See Foo.Bar and Ext.XTemplate.' - end + it "doesn't create links inside ..." do + @formatter.replace('See Foo.Bar').should == + 'See Foo.Bar' + end - it "doesn't create links inside nested tags" do - @formatter.replace('See Foo.Bar Ext.XTemplate').should == - 'See Foo.Bar Ext.XTemplate' - end + it "creates links inside ..." do + @formatter.replace('See Foo.Bar').should == + 'See Foo.Bar' + end - it "handles unclosed HTML tags" do - @formatter.replace('Malformed ..." do + @formatter.replace('See Foo.Bar').should == + 'See Foo.Bar' + end + it "creates links after ..." do + @formatter.replace('See Foo.Bar and Ext.XTemplate.').should == + 'See Foo.Bar and Ext.XTemplate.' end - describe "with type information" do - before do - @formatter.relations = JsDuck::Relations.new([ - JsDuck::Class.new({ - :name => 'Foo', - :members => [ - {:tagname => :method, :name => "select", :id => "method-select"}, - {:tagname => :event, :name => "select", :id => "event-select"}, - ] - }) - ]) - end + it "doesn't create links inside nested tags" do + @formatter.replace('See Foo.Bar Ext.XTemplate').should == + 'See Foo.Bar Ext.XTemplate' + end - it "replaces {@link Foo#method-select} with link to method" do - @formatter.replace("Look at {@link Foo#method-select}").should == - 'Look at Foo.select' - end + it "handles unclosed HTML tags" do + @formatter.replace('Malformed Foo.select' - end + end + + describe "#replace with type information" do + before do + relations = JsDuck::Relations.new([ + JsDuck::Class.new({ + :name => 'Foo', + :members => [ + {:tagname => :method, :name => "select", :id => "method-select"}, + {:tagname => :event, :name => "select", :id => "event-select"}, + ] + }) + ]) + @formatter = JsDuck::DocFormatter.new(relations) end - describe "with staticality information" do - before do - @formatter.relations = JsDuck::Relations.new([ - JsDuck::Class.new({ - :name => 'Foo', - :members => [ - {:tagname => :method, :name => "select", :id => "method-select"}, - {:tagname => :method, :name => "select", :id => "static-method-select", - :static => true}, - ] - }) - ]) - end + it "replaces {@link Foo#method-select} with link to method" do + @formatter.replace("Look at {@link Foo#method-select}").should == + 'Look at Foo.select' + end - it "replaces {@link Foo#select} with link to instance method" do - @formatter.replace("Look at {@link Foo#select}").should == - 'Look at Foo.select' - end + it "replaces {@link Foo#event-select} with link to event" do + @formatter.replace("Look at {@link Foo#event-select}").should == + 'Look at Foo.select' + end + end - it "replaces {@link Foo#static-select} with link to static method" do - @formatter.replace("Look at {@link Foo#static-select}").should == - 'Look at Foo.select' - end + describe "#replace with staticality information" do + before do + relations = JsDuck::Relations.new([ + JsDuck::Class.new({ + :name => 'Foo', + :members => [ + {:tagname => :method, :name => "select", :id => "method-select"}, + {:tagname => :method, :name => "select", :id => "static-method-select", + :static => true}, + ] + }) + ]) + @formatter = JsDuck::DocFormatter.new(relations) + end - it "replaces {@link Foo#static-method-select} with link to static method" do - @formatter.replace("Look at {@link Foo#static-method-select}").should == - 'Look at Foo.select' - end + it "replaces {@link Foo#select} with link to instance method" do + @formatter.replace("Look at {@link Foo#select}").should == + 'Look at Foo.select' + end + + it "replaces {@link Foo#static-select} with link to static method" do + @formatter.replace("Look at {@link Foo#static-select}").should == + 'Look at Foo.select' + end + + it "replaces {@link Foo#static-method-select} with link to static method" do + @formatter.replace("Look at {@link Foo#static-method-select}").should == + 'Look at Foo.select' end end describe "#format" do + before do + @formatter = JsDuck::DocFormatter.new + end # Just a sanity check that Markdown formatting works it "converts Markdown to HTML" do diff --git a/spec/type_parser_spec.rb b/spec/type_parser_spec.rb index 35435a99f42683ccc0401d8174569cbd1b3ca1b5..b8e7cd7491247e7ab233a59251046f3c51d2057f 100644 --- a/spec/type_parser_spec.rb +++ b/spec/type_parser_spec.rb @@ -325,8 +325,7 @@ describe JsDuck::TypeParser do it "links primitive types to classes" do relations = JsDuck::Relations.new([JsDuck::Class.new({:name => "String"})]) - doc_formatter = JsDuck::DocFormatter.new - doc_formatter.relations = relations + doc_formatter = JsDuck::DocFormatter.new(relations) p = JsDuck::TypeParser.new(relations, doc_formatter) p.parse("string") p.out.should == 'string'