diff --git a/lib/puppet/feature/rdoc1.rb b/lib/puppet/feature/rdoc1.rb deleted file mode 100644 index a7e65c229..000000000 --- a/lib/puppet/feature/rdoc1.rb +++ /dev/null @@ -1,16 +0,0 @@ -require 'puppet/util/feature' - -# We have a version of RDoc compatible with our module documentation tool. -# That is to say, we have the version that comes with Ruby 1.8.7 and earlier, -# and not the version that comes with Ruby 1.9.1 or later. -# -# 1.8 => require 'rdoc/rdoc'; p RDoc::RDoc::VERSION_STRING -# => "RDoc V1.0.1 - 20041108" -# 1.9 => require 'rdoc'; p RDoc::VERSION -# => "3.9.4" # 1.9.2 has 2.5, 1.9.3 has 3.9 -# -# Anything above that whole 1.0.1 thing is no good for us, and since that -# ships with anything in the 1.8 series that we care about (eg: .5, ,7) we can -# totally just use that as a proxy for the correct version of rdoc being -# available. --daniel 2012-03-08 -Puppet.features.add(:rdoc1) { RUBY_VERSION[0,3] == "1.8" } diff --git a/lib/puppet/util/rdoc.rb b/lib/puppet/util/rdoc.rb index 497e9847a..269620d31 100644 --- a/lib/puppet/util/rdoc.rb +++ b/lib/puppet/util/rdoc.rb @@ -1,96 +1,61 @@ require 'puppet/util' module Puppet::Util::RDoc module_function # launch a rdoc documenation process # with the files/dir passed in +files+ def rdoc(outputdir, files, charset = nil) Puppet[:ignoreimport] = true # then rdoc require 'rdoc/rdoc' require 'rdoc/options' # load our parser require 'puppet/util/rdoc/parser' r = RDoc::RDoc.new - if Puppet.features.rdoc1? - RDoc::RDoc::GENERATORS["puppet"] = RDoc::RDoc::Generator.new( - "puppet/util/rdoc/generators/puppet_generator.rb", - :PuppetGenerator, - "puppet" - ) - end - # specify our own format & where to output options = [ "--fmt", "puppet", "--quiet", "--exclude", "/modules/[^/]*/spec/.*$", "--exclude", "/modules/[^/]*/files/.*$", "--exclude", "/modules/[^/]*/tests/.*$", "--exclude", "/modules/[^/]*/templates/.*$", "--op", outputdir ] - if !Puppet.features.rdoc1? || ::Options::OptionList.options.any? { |o| o[0] == "--force-update" } # Options is a root object in the rdoc1 namespace... - options << "--force-update" - end + options << "--force-update" options += [ "--charset", charset] if charset # Rdoc root default is Dir.pwd, but the win32-dir gem monkey patchs Dir.pwd # replacing Ruby's normal / with \. When RDoc generates relative paths it # uses relative_path_from that will generate errors when the slashes don't # properly match. This is a workaround for that issue. if Puppet.features.microsoft_windows? && RDoc::VERSION !~ /^[0-3]\./ options += [ "--root", Dir.pwd.gsub(/\\/, '/')] end options += files # launch the documentation process r.document(options) end # launch an output to console manifest doc def manifestdoc(files) - Puppet[:ignoreimport] = true - files.select { |f| FileTest.file?(f) }.each do |f| - parser = Puppet::Parser::Parser.new(Puppet.lookup(:current_environment)) - parser.file = f - ast = parser.parse - output(f, ast) - end + raise "RDOC SUPPORT FOR MANIFEST HAS BEEN REMOVED - See PUP-3638" end # Outputs to the console the documentation # of a manifest def output(file, ast) - astobj = [] - ast.instantiate('').each do |resource_type| - astobj << resource_type if resource_type.file == file - end - - astobj.sort! {|a,b| a.line <=> b.line }.each do |k| - output_astnode_doc(k) - end + raise "RDOC SUPPORT FOR MANIFEST HAS BEEN REMOVED - See PUP-3638" end def output_astnode_doc(ast) - puts ast.doc if !ast.doc.nil? and !ast.doc.empty? - if Puppet.settings[:document_all] - # scan each underlying resources to produce documentation - code = ast.code.children if ast.code.is_a?(Puppet::Parser::AST::ASTArray) - code ||= ast.code - output_resource_doc(code) unless code.nil? - end + raise "RDOC SUPPORT FOR MANIFEST HAS BEEN REMOVED - See PUP-3638" end def output_resource_doc(code) - code.sort { |a,b| a.line <=> b.line }.each do |stmt| - output_resource_doc(stmt.children) if stmt.is_a?(Puppet::Parser::AST::ASTArray) - - if stmt.is_a?(Puppet::Parser::AST::Resource) - puts stmt.doc if !stmt.doc.nil? and !stmt.doc.empty? - end - end + raise "RDOC SUPPORT FOR MANIFEST HAS BEEN REMOVED - See PUP-3638" end end diff --git a/lib/puppet/util/rdoc/code_objects.rb b/lib/puppet/util/rdoc/code_objects.rb index dd5cc2f32..800b3690d 100644 --- a/lib/puppet/util/rdoc/code_objects.rb +++ b/lib/puppet/util/rdoc/code_objects.rb @@ -1,334 +1,294 @@ require 'rdoc/code_objects' module RDoc # This modules contains various class that are used to hold information # about the various Puppet language structures we found while parsing. # # Those will be mapped to their html counterparts which are defined in # PuppetGenerator. # PuppetTopLevel is a top level (usually a .pp/.rb file) module PuppetTopLevel attr_accessor :module_name, :global end - # Add top level comments to a class or module regardless of whether we are - # using rdoc1 or rdoc2+ + # Add top level comments to a class or module # @api private module AddClassModuleComment def add_comment(comment, location = nil) - if PUPPET_RDOC_VERSION == 1 - self.comment = comment - else super - end end end # PuppetModule holds a Puppet Module # This is mapped to an HTMLPuppetModule # it leverage the RDoc (ruby) module infrastructure class PuppetModule < NormalModule include AddClassModuleComment attr_accessor :facts, :plugins def initialize(name,superclass=nil) @facts = [] @plugins = [] @nodes = {} super(name,superclass) end def add_plugin(plugin) - if PUPPET_RDOC_VERSION == 1 - add_to(@plugins, plugin) - else - add_plugin_rdoc2(plugin) - end - end - - def add_plugin_rdoc2(plugin) name = plugin.name type = plugin.type meth = AnyMethod.new("*args", name) meth.params = "(*args)" meth.visibility = :public meth.document_self = true meth.singleton = false meth.comment = plugin.comment if type == 'function' @function_container ||= add_module(NormalModule, "__functions__") @function_container.add_method(meth) elsif type == 'type' @type_container ||= add_module(NormalModule, "__types__") @type_container.add_method(meth) end end def add_fact(fact) - if PUPPET_RDOC_VERSION == 1 - add_to(@facts, fact) - else - add_fact_rdoc2(fact) - end - end - - def add_fact_rdoc2(fact) @fact_container ||= add_module(NormalModule, "__facts__") confine_str = fact.confine.empty? ? '' : fact.confine.to_s const = Constant.new(fact.name, confine_str, fact.comment) @fact_container.add_constant(const) end - def add_node(name, superclass) - if PUPPET_RDOC_VERSION == 1 - add_node_rdoc1(name, superclass) - else - add_node_rdoc2(name, superclass) - end - end - - def add_node_rdoc1(name, superclass) - cls = @nodes[name] - unless cls - cls = PuppetNode.new(name, superclass) - @nodes[name] = cls if !@done_documenting - cls.parent = self - cls.section = @current_section - end - cls - end - # Adds a module called __nodes__ and adds nodes to it as classes # - def add_node_rdoc2(name,superclass) + def add_node(name,superclass) if cls = @nodes[name] return cls end @node_container ||= add_module(NormalModule, "__nodes__") cls = @node_container.add_class(PuppetNode, name, superclass) @nodes[name] = cls if !@done_documenting cls end def each_fact @facts.each {|c| yield c} end def each_plugin @plugins.each {|c| yield c} end def each_node @nodes.each {|c| yield c} end def nodes @nodes.values end end # PuppetClass holds a puppet class # It is mapped to a HTMLPuppetClass for display # It leverages RDoc (ruby) Class class PuppetClass < ClassModule include AddClassModuleComment attr_accessor :resource_list, :requires, :childs, :realizes def initialize(name, superclass) super(name,superclass) @resource_list = [] @requires = [] @realizes = [] @childs = [] end def aref_prefix 'puppet_class' end def add_resource(resource) add_to(@resource_list, resource) end def is_module? false end def superclass=(superclass) @superclass = superclass end # we're (ab)using the RDoc require system here. # we're adding a required Puppet class, overriding # the RDoc add_require method which sees ruby required files. def add_require(required) add_to(@requires, required) end def add_realize(realized) add_to(@realizes, realized) end def add_child(child) @childs << child end # Look up the given symbol. RDoc only looks for class1::class2.method # or class1::class2#method. Since our definitions are mapped to RDoc methods # but are written class1::class2::define we need to perform the lookup by # ourselves. def find_symbol(symbol, method=nil) result = super(symbol) if not result and symbol =~ /::/ modules = symbol.split(/::/) unless modules.empty? module_name = modules.shift result = find_module_named(module_name) if result last_name = "" previous = nil modules.each do |module_name| previous = result last_name = module_name result = result.find_module_named(module_name) break unless result end unless result result = previous method = last_name end end end if result && method if !result.respond_to?(:find_local_symbol) p result.name p method fail end result = result.find_local_symbol(method) end end result end end # PuppetNode holds a puppet node # It is mapped to a HTMLPuppetNode for display # A node is just a variation of a class class PuppetNode < PuppetClass include AddClassModuleComment def initialize(name, superclass) super(name,superclass) end def is_module? false end end # Plugin holds a native puppet plugin (function,type...) # It is mapped to a HTMLPuppetPlugin for display class Plugin < Context attr_accessor :name, :type def initialize(name, type) super() @name = name @type = type @comment = "" end def <=>(other) @name <=> other.name end def full_name @name end def http_url(prefix) path = full_name.split("::") File.join(prefix, *path) + ".html" end def is_fact? false end def to_s res = self.class.name + ": #{@name} (#{@type})\n" res << @comment.to_s res end end # Fact holds a custom fact # It is mapped to a HTMLPuppetPlugin for display class Fact < Context attr_accessor :name, :confine def initialize(name, confine) super() @name = name @confine = confine @comment = "" end def <=>(other) @name <=> other.name end def is_fact? true end def full_name @name end def to_s res = self.class.name + ": #{@name}\n" res << @comment.to_s res end end # PuppetResource holds a puppet resource # It is mapped to a HTMLPuppetResource for display # A resource is defined by its "normal" form Type[title] class PuppetResource < CodeObject attr_accessor :type, :title, :params def initialize(type, title, comment, params) super() @type = type @title = title @comment = comment @params = params end def <=>(other) full_name <=> other.full_name end def full_name @type + "[#{@title}]" end def name full_name end def to_s res = @type + "[#{@title}]\n" res << @comment.to_s res end end end diff --git a/lib/puppet/util/rdoc/parser.rb b/lib/puppet/util/rdoc/parser.rb index 6ecd4921c..9fecc2f55 100644 --- a/lib/puppet/util/rdoc/parser.rb +++ b/lib/puppet/util/rdoc/parser.rb @@ -1,22 +1,12 @@ # Puppet "parser" for the rdoc system # The parser uses puppet parser and traverse the AST to instruct RDoc about # our current structures. It also parses ruby files that could contain # either custom facts or puppet plugins (functions, types...) -# rdoc mandatory includes +# rdoc2 includes require "rdoc/code_objects" require "puppet/util/rdoc/code_objects" - -begin - # Rdoc 1 imports - require "rdoc/tokenstream" - require "rdoc/markup/simple_markup/preprocess" - require "rdoc/parsers/parserfactory" - require "puppet/util/rdoc/parser/puppet_parser_rdoc1.rb" -rescue LoadError - # Current version imports - require "rdoc/token_stream" - require "rdoc/markup/pre_process" - require "rdoc/parser" - require "puppet/util/rdoc/parser/puppet_parser_rdoc2.rb" -end +require "rdoc/token_stream" +require "rdoc/markup/pre_process" +require "rdoc/parser" +require "puppet/util/rdoc/parser/puppet_parser_rdoc2.rb" diff --git a/lib/puppet/util/rdoc/parser/puppet_parser_core.rb b/lib/puppet/util/rdoc/parser/puppet_parser_core.rb index 4d29cc127..9cb5d9efa 100644 --- a/lib/puppet/util/rdoc/parser/puppet_parser_core.rb +++ b/lib/puppet/util/rdoc/parser/puppet_parser_core.rb @@ -1,477 +1,258 @@ # Functionality common to both our RDoc version 1 and 2 parsers. module RDoc::PuppetParserCore SITE = "__site__" def self.included(base) base.class_eval do attr_accessor :input_file_name, :top_level # parser registration into RDoc - parse_files_matching(/\.(rb|pp)$/) + parse_files_matching(/\.(rb)$/) end end # called with the top level file def initialize(top_level, file_name, body, options, stats) @options = options @stats = stats @input_file_name = file_name @top_level = top_level @top_level.extend(RDoc::PuppetTopLevel) @progress = $stderr unless options.quiet end # main entry point def scan environment = Puppet.lookup(:current_environment) - known_resource_types = environment.known_resource_types - unless known_resource_types.watching_file?(@input_file_name) - Puppet.info "rdoc: scanning #{@input_file_name}" - if @input_file_name =~ /\.pp$/ - @parser = Puppet::Parser::Parser.new(environment) - @parser.file = @input_file_name - @parser.parse.instantiate('').each do |type| - known_resource_types.add type - end - end - end - scan_top_level(@top_level, environment) @top_level end # Due to a bug in RDoc, we need to roll our own find_module_named # The issue is that RDoc tries harder by asking the parent for a class/module # of the name. But by doing so, it can mistakenly use a module of same name # but from which we are not descendant. def find_object_named(container, name) return container if container.name == name container.each_classmodule do |m| return m if m.name == name end nil end # walk down the namespace and lookup/create container as needed def get_class_or_module(container, name) # class ::A -> A is in the top level if name =~ /^::/ container = @top_level end names = name.split('::') final_name = names.pop names.each do |name| prev_container = container container = find_object_named(container, name) container ||= prev_container.add_class(RDoc::PuppetClass, name, nil) end [container, final_name] end # split_module tries to find if +path+ belongs to the module path # if it does, it returns the module name, otherwise if we are sure # it is part of the global manifest path, "__site__" is returned. # And finally if this path couldn't be mapped anywhere, nil is returned. def split_module(path, environment) # find a module fullpath = File.expand_path(path) Puppet.debug "rdoc: testing #{fullpath}" - if fullpath =~ /(.*)\/([^\/]+)\/(?:manifests|plugins|lib)\/.+\.(pp|rb)$/ + if fullpath =~ /(.*)\/([^\/]+)\/(?:manifests|plugins|lib)\/.+\.(rb)$/ modpath = $1 name = $2 Puppet.debug "rdoc: module #{name} into #{modpath} ?" environment.modulepath.each do |mp| if File.identical?(modpath,mp) Puppet.debug "rdoc: found module #{name}" return name end end end - if fullpath =~ /\.(pp|rb)$/ + if fullpath =~ /\.(rb)$/ # there can be paths we don't want to scan under modules # imagine a ruby or manifest that would be distributed as part as a module # but we don't want those to be hosted under environment.modulepath.each do |mp| # check that fullpath is a descendant of mp dirname = fullpath previous = dirname while (dirname = File.dirname(previous)) != previous previous = dirname return nil if File.identical?(dirname,mp) end end end # we are under a global manifests Puppet.debug "rdoc: global manifests" SITE end # create documentation for the top level +container+ def scan_top_level(container, environment) # use the module README as documentation for the module comment = "" %w{README README.rdoc}.each do |rfile| readme = File.join(File.dirname(File.dirname(@input_file_name)), rfile) comment = File.open(readme,"r") { |f| f.read } if FileTest.readable?(readme) end look_for_directives_in(container, comment) unless comment.empty? # infer module name from directory name = split_module(@input_file_name, environment) if name.nil? # skip .pp files that are not in manifests directories as we can't guarantee they're part # of a module or the global configuration. + # PUP-3638, keeping this while it should have no effect since no .pp files are now processed container.document_self = false return end Puppet.debug "rdoc: scanning for #{name}" container.module_name = name container.global=true if name == SITE container, name = get_class_or_module(container,name) mod = container.add_module(RDoc::PuppetModule, name) mod.record_location(@top_level) mod.add_comment(comment, @input_file_name) - if @input_file_name =~ /\.pp$/ - parse_elements(mod, environment.known_resource_types) - elsif @input_file_name =~ /\.rb$/ + if @input_file_name =~ /\.rb$/ parse_plugins(mod) end end - # create documentation for include statements we can find in +code+ - # and associate it with +container+ - def scan_for_include_or_require(container, code) - code = [code] unless code.is_a?(Array) - code.each do |stmt| - scan_for_include_or_require(container,stmt.children) if stmt.is_a?(Puppet::Parser::AST::BlockExpression) - - if stmt.is_a?(Puppet::Parser::AST::Function) and ['include','require'].include?(stmt.name) - stmt.arguments.each do |included| - Puppet.debug "found #{stmt.name}: #{included}" - container.send("add_#{stmt.name}", RDoc::Include.new(included.to_s, stmt.doc)) - end - end - end - end - - # create documentation for realize statements we can find in +code+ - # and associate it with +container+ - def scan_for_realize(container, code) - code = [code] unless code.is_a?(Array) - code.each do |stmt| - scan_for_realize(container,stmt.children) if stmt.is_a?(Puppet::Parser::AST::BlockExpression) - - if stmt.is_a?(Puppet::Parser::AST::Function) and stmt.name == 'realize' - stmt.arguments.each do |realized| - Puppet.debug "found #{stmt.name}: #{realized}" - container.add_realize( RDoc::Include.new(realized.to_s, stmt.doc)) - end - end - end - end - - # create documentation for global variables assignements we can find in +code+ - # and associate it with +container+ - def scan_for_vardef(container, code) - code = [code] unless code.is_a?(Array) - code.each do |stmt| - scan_for_vardef(container,stmt.children) if stmt.is_a?(Puppet::Parser::AST::BlockExpression) - - if stmt.is_a?(Puppet::Parser::AST::VarDef) - Puppet.debug "rdoc: found constant: #{stmt.name} = #{stmt.value}" - container.add_constant(RDoc::Constant.new(stmt.name.to_s, stmt.value.to_s, stmt.doc)) - end - end - end - - # create documentation for resources we can find in +code+ - # and associate it with +container+ - def scan_for_resource(container, code) - code = [code] unless code.is_a?(Array) - code.each do |stmt| - scan_for_resource(container,stmt.children) if stmt.is_a?(Puppet::Parser::AST::BlockExpression) - - if stmt.is_a?(Puppet::Parser::AST::Resource) and !stmt.type.nil? - begin - type = stmt.type.split("::").collect { |s| s.capitalize }.join("::") - stmt.instances.each do |inst| - title = inst.title.is_a?(Puppet::Parser::AST::ASTArray) ? inst.title.to_s.gsub(/\[(.*)\]/,'\1') : inst.title.to_s - Puppet.debug "rdoc: found resource: #{type}[#{title}]" - - param = [] - inst.parameters.children.each do |p| - res = {} - res["name"] = p.param - res["value"] = "#{p.value.to_s}" unless p.value.nil? - - param << res - end - - container.add_resource(RDoc::PuppetResource.new(type, title, stmt.doc, param)) - end - rescue => detail - raise Puppet::ParseError, "impossible to parse resource in #{stmt.file} at line #{stmt.line}: #{detail}", detail.backtrace - end - end - end - end - - # create documentation for a class named +name+ - def document_class(name, klass, container) - Puppet.debug "rdoc: found new class #{name}" - container, name = get_class_or_module(container, name) - - superclass = klass.parent - superclass = "" if superclass.nil? or superclass.empty? - - comment = klass.doc - look_for_directives_in(container, comment) unless comment.empty? - cls = container.add_class(RDoc::PuppetClass, name, superclass) - # it is possible we already encountered this class, while parsing some namespaces - # from other classes of other files. But at that time we couldn't know this class superclass - # so, now we know it and force it. - cls.superclass = superclass - cls.record_location(@top_level) - - # scan class code for include - code = klass.code.children if klass.code.is_a?(Puppet::Parser::AST::BlockExpression) - code ||= klass.code - unless code.nil? - scan_for_include_or_require(cls, code) - scan_for_realize(cls, code) - scan_for_resource(cls, code) if Puppet.settings[:document_all] - end - - cls.add_comment(comment, klass.file) - rescue => detail - raise Puppet::ParseError, "impossible to parse class '#{name}' in #{klass.file} at line #{klass.line}: #{detail}", detail.backtrace - end - - # create documentation for a node - def document_node(name, node, container) - Puppet.debug "rdoc: found new node #{name}" - superclass = node.parent - superclass = "" if superclass.nil? or superclass.empty? - - comment = node.doc - look_for_directives_in(container, comment) unless comment.empty? - n = container.add_node(name, superclass) - n.record_location(@top_level) - - code = node.code.children if node.code.is_a?(Puppet::Parser::AST::BlockExpression) - code ||= node.code - unless code.nil? - scan_for_include_or_require(n, code) - scan_for_realize(n, code) - scan_for_vardef(n, code) - scan_for_resource(n, code) if Puppet.settings[:document_all] - end - - n.add_comment(comment, node.file) - rescue => detail - raise Puppet::ParseError, "impossible to parse node '#{name}' in #{node.file} at line #{node.line}: #{detail}", detail.backtrace - end - - # create documentation for a define - def document_define(name, define, container) - Puppet.debug "rdoc: found new definition #{name}" - # find superclas if any - - # find the parent - # split define name by :: to find the complete module hierarchy - container, name = get_class_or_module(container,name) - - # build up declaration - declaration = "" - define.arguments.each do |arg,value| - declaration << "\$#{arg}" - unless value.nil? - declaration << " => " - case value - when Puppet::Parser::AST::Leaf - declaration << "'#{value.value}'" - when Puppet::Parser::AST::BlockExpression - declaration << "[#{value.children.collect { |v| "'#{v}'" }.join(", ")}]" - else - declaration << "#{value.to_s}" - end - end - declaration << ", " - end - declaration.chop!.chop! if declaration.size > 1 - - # register method into the container - meth = RDoc::AnyMethod.new(declaration, name) - meth.comment = define.doc - container.add_method(meth) - look_for_directives_in(container, meth.comment) unless meth.comment.empty? - meth.params = "( #{declaration} )" - meth.visibility = :public - meth.document_self = true - meth.singleton = false - rescue => detail - raise Puppet::ParseError, "impossible to parse definition '#{name}' in #{define.file} at line #{define.line}: #{detail}", detail.backtrace - end - - # Traverse the AST tree and produce code-objects node - # that contains the documentation - def parse_elements(container, known_resource_types) - Puppet.debug "rdoc: scanning manifest" - - known_resource_types.hostclasses.values.sort { |a,b| a.name <=> b.name }.each do |klass| - name = klass.name - if klass.file == @input_file_name - unless name.empty? - document_class(name,klass,container) - else # on main class document vardefs - code = klass.code.children if klass.code.is_a?(Puppet::Parser::AST::BlockExpression) - code ||= klass.code - scan_for_vardef(container, code) unless code.nil? - end - end - end - - known_resource_types.definitions.each do |name, define| - if define.file == @input_file_name - document_define(name,define,container) - end - end - - known_resource_types.nodes.each do |name, node| - if node.file == @input_file_name - document_node(name.to_s,node,container) - end - end - end - # create documentation for plugins def parse_plugins(container) Puppet.debug "rdoc: scanning plugin or fact" if @input_file_name =~ /\/facter\/[^\/]+\.rb$/ parse_fact(container) else parse_puppet_plugin(container) end end # this is a poor man custom fact parser :-) def parse_fact(container) comments = "" current_fact = nil parsed_facts = [] File.open(@input_file_name) do |of| of.each do |line| # fetch comments if line =~ /^[ \t]*# ?(.*)$/ comments += $1 + "\n" elsif line =~ /^[ \t]*Facter.add\(['"](.*?)['"]\)/ current_fact = RDoc::Fact.new($1,{}) look_for_directives_in(container, comments) unless comments.empty? current_fact.comment = comments parsed_facts << current_fact comments = "" Puppet.debug "rdoc: found custom fact #{current_fact.name}" elsif line =~ /^[ \t]*confine[ \t]*:(.*?)[ \t]*=>[ \t]*(.*)$/ current_fact.confine = { :type => $1, :value => $2 } unless current_fact.nil? else # unknown line type comments ="" end end end parsed_facts.each do |f| container.add_fact(f) f.record_location(@top_level) end end # this is a poor man puppet plugin parser :-) # it doesn't extract doc nor desc :-( def parse_puppet_plugin(container) comments = "" current_plugin = nil File.open(@input_file_name) do |of| of.each do |line| # fetch comments if line =~ /^[ \t]*# ?(.*)$/ comments += $1 + "\n" elsif line =~ /^[ \t]*(?:Puppet::Parser::Functions::)?newfunction[ \t]*\([ \t]*:(.*?)[ \t]*,[ \t]*:type[ \t]*=>[ \t]*(:rvalue|:lvalue)/ current_plugin = RDoc::Plugin.new($1, "function") look_for_directives_in(container, comments) unless comments.empty? current_plugin.comment = comments current_plugin.record_location(@top_level) container.add_plugin(current_plugin) comments = "" Puppet.debug "rdoc: found new function plugins #{current_plugin.name}" elsif line =~ /^[ \t]*Puppet::Type.newtype[ \t]*\([ \t]*:(.*?)\)/ current_plugin = RDoc::Plugin.new($1, "type") look_for_directives_in(container, comments) unless comments.empty? current_plugin.comment = comments current_plugin.record_location(@top_level) container.add_plugin(current_plugin) comments = "" Puppet.debug "rdoc: found new type plugins #{current_plugin.name}" elsif line =~ /module Puppet::Parser::Functions/ # skip else # unknown line type comments ="" end end end end # New instance of the appropriate PreProcess for our RDoc version. def create_rdoc_preprocess raise(NotImplementedError, "This method must be overwritten for whichever version of RDoc this parser is working with") end # look_for_directives_in scans the current +comment+ for RDoc directives def look_for_directives_in(context, comment) preprocess = create_rdoc_preprocess preprocess.handle(comment) do |directive, param| case directive when "stopdoc" context.stop_doc "" when "startdoc" context.start_doc context.force_documentation = true "" when "enddoc" #context.done_documenting = true #"" throw :enddoc when "main" options = Options.instance options.main_page = param "" when "title" options = Options.instance options.title = param "" when "section" context.set_current_section(param, comment) comment.replace("") # 1.8 doesn't support #clear break else warn "Unrecognized directive '#{directive}'" break end end remove_private_comments(comment) end def remove_private_comments(comment) comment.gsub!(/^#--.*?^#\+\+/m, '') comment.sub!(/^#--.*/m, '') end end diff --git a/lib/puppet/util/rdoc/parser/puppet_parser_rdoc1.rb b/lib/puppet/util/rdoc/parser/puppet_parser_rdoc1.rb deleted file mode 100644 index 656d2f7e7..000000000 --- a/lib/puppet/util/rdoc/parser/puppet_parser_rdoc1.rb +++ /dev/null @@ -1,19 +0,0 @@ -require 'puppet/util/rdoc/parser/puppet_parser_core.rb' - -module RDoc - PUPPET_RDOC_VERSION = 1 - - # @api private - class PuppetParserRDoc1 - extend ParserFactory - include PuppetParserCore - - def create_rdoc_preprocess - preprocess = SM::PreProcess.new(@input_file_name, @options.rdoc_include) - end - end - - # For backwards compatibility - # @api private - Parser = PuppetParserRDoc1 -end diff --git a/spec/integration/application/doc_spec.rb b/spec/integration/application/doc_spec.rb index 040dde72d..463bb2dc0 100755 --- a/spec/integration/application/doc_spec.rb +++ b/spec/integration/application/doc_spec.rb @@ -1,57 +1,15 @@ #! /usr/bin/env ruby require 'spec_helper' require 'puppet_spec/files' require 'puppet/application/doc' describe Puppet::Application::Doc do include PuppetSpec::Files - it "should not generate an error when module dir overlaps parent of site.pp (#4798)", - :if => (Puppet.features.rdoc1? and not Puppet.features.microsoft_windows?) do - begin - # Note: the directory structure below is more complex than it - # needs to be, but it's representative of the directory structure - # used in bug #4798. - old_dir = Dir.getwd # Note: can't use chdir with a block because it will generate bogus warnings - tmpdir = tmpfile('doc_spec') - Dir.mkdir(tmpdir) - Dir.chdir(tmpdir) - site_file = 'site.pp' - File.open(site_file, 'w') do |f| - f.puts '# A comment' - end - modules_dir = 'modules' - Dir.mkdir(modules_dir) - rt_dir = File.join(modules_dir, 'rt') - Dir.mkdir(rt_dir) - manifests_dir = File.join(rt_dir, 'manifests') - Dir.mkdir(manifests_dir) - rt_file = File.join(manifests_dir, 'rt.pp') - File.open(rt_file, 'w') do |f| - f.puts '# A class' - f.puts 'class foo { }' - f.puts '# A definition' - f.puts 'define bar { }' - end - - puppet = Puppet::Application[:doc] - puppet.options[:mode] = :rdoc - - env = Puppet::Node::Environment.create(:rdoc, [modules_dir], site_file) - Puppet.override(:current_environment => env) do - expect { puppet.run_command }.to exit_with 0 - end - - Puppet::FileSystem.exist?('doc').should be_true - ensure - Dir.chdir(old_dir) - end - end - it "should respect the -o option" do puppetdoc = Puppet::Application[:doc] puppetdoc.command_line.stubs(:args).returns(['foo', '-o', 'bar']) puppetdoc.parse_options puppetdoc.options[:outputdir].should == 'bar' end end diff --git a/spec/integration/util/rdoc/parser_spec.rb b/spec/integration/util/rdoc/parser_spec.rb index 2fdaf8019..d6a9094de 100755 --- a/spec/integration/util/rdoc/parser_spec.rb +++ b/spec/integration/util/rdoc/parser_spec.rb @@ -1,268 +1,182 @@ #! /usr/bin/env ruby require 'spec_helper' require 'puppet/util/rdoc' describe "RDoc::Parser" do require 'puppet_spec/files' include PuppetSpec::Files let(:document_all) { false } let(:tmp_dir) { tmpdir('rdoc_parser_tmp') } let(:doc_dir) { File.join(tmp_dir, 'doc') } let(:manifests_dir) { File.join(tmp_dir, 'manifests') } let(:modules_dir) { File.join(tmp_dir, 'modules') } let(:modules_and_manifests) do { :site => [ File.join(manifests_dir, 'site.pp'), <<-EOF # The test class comment class test { # The virtual resource comment @notify { virtual: } # The a_notify_resource comment notify { a_notify_resource: message => "a_notify_resource message" } } # The includes_another class comment class includes_another { include another } # The requires_another class comment class requires_another { require another } # node comment node foo { include test $a_var = "var_value" realize Notify[virtual] notify { bar: } } EOF ], :module_readme => [ File.join(modules_dir, 'a_module', 'README'), <<-EOF The a_module README docs. EOF ], :module_init => [ File.join(modules_dir, 'a_module', 'manifests', 'init.pp'), <<-EOF # The a_module class comment class a_module {} class another {} EOF ], :module_type => [ File.join(modules_dir, 'a_module', 'manifests', 'a_type.pp'), <<-EOF # The a_type type comment define a_module::a_type() {} EOF ], :module_plugin => [ File.join(modules_dir, 'a_module', 'lib', 'puppet', 'type', 'a_plugin.rb'), <<-EOF # The a_plugin type comment Puppet::Type.newtype(:a_plugin) do @doc = "Not presented" end EOF ], :module_function => [ File.join(modules_dir, 'a_module', 'lib', 'puppet', 'parser', 'a_function.rb'), <<-EOF # The a_function function comment module Puppet::Parser::Functions newfunction(:a_function, :type => :rvalue) do return end end EOF ], :module_fact => [ File.join(modules_dir, 'a_module', 'lib', 'facter', 'a_fact.rb'), <<-EOF # The a_fact fact comment Facter.add("a_fact") do end EOF ], } end def write_file(file, content) FileUtils.mkdir_p(File.dirname(file)) File.open(file, 'w') do |f| f.puts(content) end end def prepare_manifests_and_modules modules_and_manifests.each do |key,array| write_file(*array) end end def file_exists_and_matches_content(file, *content_patterns) Puppet::FileSystem.exist?(file).should(be_true, "Cannot find #{file}") content_patterns.each do |pattern| content = File.read(file) content.should match(pattern) end end def some_file_exists_with_matching_content(glob, *content_patterns) Dir.glob(glob).select do |f| contents = File.read(f) content_patterns.all? { |p| p.match(contents) } end.should_not(be_empty, "Could not match #{content_patterns} in any of the files found in #{glob}") end around(:each) do |example| env = Puppet::Node::Environment.create(:doc_test_env, [modules_dir], manifests_dir) Puppet.override({:environments => Puppet::Environments::Static.new(env), :current_environment => env}) do example.run end end before :each do prepare_manifests_and_modules Puppet.settings[:document_all] = document_all Puppet.settings[:modulepath] = modules_dir Puppet::Util::RDoc.rdoc(doc_dir, [modules_dir, manifests_dir]) end module RdocTesters - def has_module_rdoc(module_name, *other_test_patterns) - file_exists_and_matches_content(module_path(module_name), /Module:? +#{module_name}/i, *other_test_patterns) - end - - def has_node_rdoc(module_name, node_name, *other_test_patterns) - file_exists_and_matches_content(node_path(module_name, node_name), /#{node_name}/, /node comment/, *other_test_patterns) - end - - def has_defined_type(module_name, type_name) - file_exists_and_matches_content(module_path(module_name), /#{type_name}.*?\(\s*\)/m, "The .*?#{type_name}.*? type comment") - end - - def has_class_rdoc(module_name, class_name, *other_test_patterns) - file_exists_and_matches_content(class_path(module_name, class_name), /#{class_name}.*? class comment/, *other_test_patterns) - end - def has_plugin_rdoc(module_name, type, name) file_exists_and_matches_content(plugin_path(module_name, type, name), /The .*?#{name}.*?\s*#{type} comment/m, /Type.*?#{type}/m) end end shared_examples_for :an_rdoc_site do - it "documents the __site__ module" do - has_module_rdoc("__site__") - end - - it "documents the __site__::test class" do - has_class_rdoc("__site__", "test") - end + # PUP-3274 / PUP-3638 not sure if this should be kept or not - it is now broken +# it "documents the __site__ module" do +# has_module_rdoc("__site__") +# end - it "documents the __site__::foo node" do - has_node_rdoc("__site__", "foo") - end - - it "documents the a_module module" do - has_module_rdoc("a_module", /The .*?a_module.*? .*?README.*?docs/m) - end - - it "documents the a_module::a_module class" do - has_class_rdoc("a_module", "a_module") - end - - it "documents the a_module::a_type defined type" do - has_defined_type("a_module", "a_type") - end + # PUP-3274 / PUP-3638 not sure if this should be kept or not - it is now broken +# it "documents the a_module module" do +# has_module_rdoc("a_module", /The .*?a_module.*? .*?README.*?docs/m) +# end it "documents the a_module::a_plugin type" do has_plugin_rdoc("a_module", :type, 'a_plugin') end it "documents the a_module::a_function function" do has_plugin_rdoc("a_module", :function, 'a_function') end it "documents the a_module::a_fact fact" do has_plugin_rdoc("a_module", :fact, 'a_fact') end - - it "documents included classes" do - has_class_rdoc("__site__", "includes_another", /Included.*?another/m) - end - end - - shared_examples_for :an_rdoc1_site do - it "documents required classes" do - has_class_rdoc("__site__", "requires_another", /Required Classes.*?another/m) - end - - it "documents realized resources" do - has_node_rdoc("__site__", "foo", /Realized Resources.*?Notify\[virtual\]/m) - end - - it "documents global variables" do - has_node_rdoc("__site__", "foo", /Global Variables.*?a_var.*?=.*?var_value/m) - end - - describe "when document_all is true" do - let(:document_all) { true } - - it "documents virtual resource declarations" do - has_class_rdoc("__site__", "test", /Resources.*?Notify\[virtual\]/m, /The virtual resource comment/) - end - - it "documents resources" do - has_class_rdoc("__site__", "test", /Resources.*?Notify\[a_notify_resource\]/m, /message => "a_notify_resource message"/, /The a_notify_resource comment/) - end - end - end - - describe "rdoc1 support", :if => Puppet.features.rdoc1? do - def module_path(module_name); "#{doc_dir}/classes/#{module_name}.html" end - def node_path(module_name, node_name); "#{doc_dir}/nodes/**/*.html" end - def class_path(module_name, class_name); "#{doc_dir}/classes/#{module_name}/#{class_name}.html" end - def plugin_path(module_name, type, name); "#{doc_dir}/plugins/#{name}.html" end - - include RdocTesters - - def has_node_rdoc(module_name, node_name, *other_test_patterns) - some_file_exists_with_matching_content(node_path(module_name, node_name), /#{node_name}/, /node comment/, *other_test_patterns) - end - - it_behaves_like :an_rdoc_site - it_behaves_like :an_rdoc1_site - - it "references nodes and classes in the __site__ module" do - file_exists_and_matches_content("#{doc_dir}/classes/__site__.html", /Node.*__site__::foo/, /Class.*__site__::test/) - end - - it "references functions, facts, and type plugins in the a_module module" do - file_exists_and_matches_content("#{doc_dir}/classes/a_module.html", /a_function/, /a_fact/, /a_plugin/, /Class.*a_module::a_module/) - end end - describe "rdoc2 support", :if => !Puppet.features.rdoc1? do + describe "rdoc2 support" do def module_path(module_name); "#{doc_dir}/#{module_name}.html" end - def node_path(module_name, node_name); "#{doc_dir}/#{module_name}/__nodes__/#{node_name}.html" end - def class_path(module_name, class_name); "#{doc_dir}/#{module_name}/#{class_name}.html" end def plugin_path(module_name, type, name); "#{doc_dir}/#{module_name}/__#{type}s__.html" end include RdocTesters it_behaves_like :an_rdoc_site end end diff --git a/spec/unit/util/rdoc/parser_spec.rb b/spec/unit/util/rdoc/parser_spec.rb deleted file mode 100755 index 7ed2cffcc..000000000 --- a/spec/unit/util/rdoc/parser_spec.rb +++ /dev/null @@ -1,608 +0,0 @@ -#! /usr/bin/env ruby -require 'spec_helper' - -describe "RDoc::Parser", :if => Puppet.features.rdoc1? do - before :all do - require 'puppet/resource/type_collection' - require 'puppet/util/rdoc/parser' - require 'puppet/util/rdoc/code_objects' - require 'rdoc/options' - require 'rdoc/rdoc' - end - - include PuppetSpec::Files - - before :each do - stub_file = stub('init.pp', :stat => stub()) - # Ruby 1.8.7 needs the following call to be stubs and not expects - Puppet::FileSystem.stubs(:stat).with('init.pp').returns stub() # stub_file - @top_level = stub_everything 'toplevel', :file_relative_name => "init.pp" - @parser = RDoc::Parser.new(@top_level, "module/manifests/init.pp", nil, Options.instance, RDoc::Stats.new) - end - - describe "when scanning files" do - around(:each) do |example| - Puppet.override({ - :current_environment => Puppet::Node::Environment.create(:doc, [], '/somewhere/etc/manifests/site.pp') - }, - "A fake current environment that the application would have established by now" - ) do - - example.run - end - end - - it "should parse puppet files with the puppet parser" do - @parser.stubs(:scan_top_level) - parser = stub 'parser' - Puppet::Parser::Parser.stubs(:new).returns(parser) - parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new('')).at_least_once - parser.expects(:file=).with("module/manifests/init.pp") - parser.expects(:file=).with do |args| - args =~ /.*\/etc\/manifests\/site.pp/ - end - - @parser.scan - end - - it "should scan the ast for Puppet files" do - parser = stub_everything 'parser' - Puppet::Parser::Parser.stubs(:new).returns(parser) - parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new('')).at_least_once - - @parser.expects(:scan_top_level) - - @parser.scan - end - - it "should return a PuppetTopLevel to RDoc" do - parser = stub_everything 'parser' - Puppet::Parser::Parser.stubs(:new).returns(parser) - parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new('')).at_least_once - - @parser.expects(:scan_top_level) - - @parser.scan.should be_a(RDoc::PuppetTopLevel) - end - - it "should scan the top level even if the file has already parsed" do - known_type = stub 'known_types' - env = Puppet.lookup(:current_environment) - env.stubs(:known_resource_types).returns(known_type) - known_type.expects(:watching_file?).with("module/manifests/init.pp").returns(true) - @parser.expects(:scan_top_level) - - @parser.scan - end - end - - describe "when scanning top level entities" do - let(:environment) { Puppet::Node::Environment.create(:env, []) } - - before :each do - @resource_type_collection = resource_type_collection = stub_everything('resource_type_collection') - environment.stubs(:known_resource_types).returns(@resource_type_collection) - @parser.stubs(:split_module).returns("module") - - @topcontainer = stub_everything 'topcontainer' - @container = stub_everything 'container' - @module = stub_everything 'module' - @container.stubs(:add_module).returns(@module) - @parser.stubs(:get_class_or_module).returns([@container, "module"]) - end - - it "should read any present README as module documentation" do - FileTest.stubs(:readable?).with("module/README").returns(true) - FileTest.stubs(:readable?).with("module/README.rdoc").returns(false) - File.stubs(:open).returns("readme") - @parser.stubs(:parse_elements) - - @module.expects(:add_comment).with("readme", "module/manifests/init.pp") - - @parser.scan_top_level(@topcontainer, environment) - end - - it "should read any present README.rdoc as module documentation" do - FileTest.stubs(:readable?).with("module/README.rdoc").returns(true) - FileTest.stubs(:readable?).with("module/README").returns(false) - File.stubs(:open).returns("readme") - @parser.stubs(:parse_elements) - - @module.expects(:add_comment).with("readme", "module/manifests/init.pp") - - @parser.scan_top_level(@topcontainer, environment) - end - - it "should prefer README.rdoc over README as module documentation" do - FileTest.stubs(:readable?).with("module/README.rdoc").returns(true) - FileTest.stubs(:readable?).with("module/README").returns(true) - File.stubs(:open).with("module/README", "r").returns("readme") - File.stubs(:open).with("module/README.rdoc", "r").returns("readme.rdoc") - @parser.stubs(:parse_elements) - - @module.expects(:add_comment).with("readme.rdoc", "module/manifests/init.pp") - - @parser.scan_top_level(@topcontainer, environment) - end - - it "should tell the container its module name" do - @parser.stubs(:parse_elements) - - @topcontainer.expects(:module_name=).with("module") - - @parser.scan_top_level(@topcontainer, environment) - end - - it "should not document our toplevel if it isn't a valid module" do - @parser.stubs(:split_module).returns(nil) - - @topcontainer.expects(:document_self=).with(false) - @parser.expects(:parse_elements).never - - @parser.scan_top_level(@topcontainer, environment) - end - - it "should set the module as global if we parse the global manifests (ie __site__ module)" do - @parser.stubs(:split_module).returns(RDoc::Parser::SITE) - @parser.stubs(:parse_elements) - - @topcontainer.expects(:global=).with(true) - - @parser.scan_top_level(@topcontainer, environment) - end - - it "should attach this module container to the toplevel container" do - @parser.stubs(:parse_elements) - - @container.expects(:add_module).with(RDoc::PuppetModule, "module").returns(@module) - - @parser.scan_top_level(@topcontainer, environment) - end - - it "should defer ast parsing to parse_elements for this module" do - @parser.expects(:parse_elements).with(@module, @resource_type_collection) - - @parser.scan_top_level(@topcontainer, environment) - end - - it "should defer plugins parsing to parse_plugins for this module" do - @parser.input_file_name = "module/lib/puppet/parser/function.rb" - - @parser.expects(:parse_plugins).with(@module) - - @parser.scan_top_level(@topcontainer, environment) - end - end - - describe "when finding modules from filepath" do - let(:environment) { - Puppet::FileSystem.expects(:directory?).with("/path/to/modules").at_least_once.returns(true) - Puppet::Node::Environment.create(:env, ["/path/to/modules"]) - } - - it "should return the module name for modulized puppet manifests" do - File.stubs(:identical?).with("/path/to/modules", "/path/to/modules").returns(true) - @parser.split_module("/path/to/modules/mymodule/manifests/init.pp", environment).should == "mymodule" - end - - it "should return for manifests not under module path" do - File.stubs(:identical?).returns(false) - @parser.split_module("/path/to/manifests/init.pp", environment).should == RDoc::Parser::SITE - end - - it "should handle windows paths with drive letters", :if => Puppet.features.microsoft_windows? && Puppet.features.rdoc1? do - @parser.split_module("C:/temp/init.pp", environment).should == RDoc::Parser::SITE - end - end - - describe "when parsing AST elements" do - before :each do - @klass = stub_everything 'klass', :file => "module/manifests/init.pp", :name => "myclass", :type => :hostclass - @definition = stub_everything 'definition', :file => "module/manifests/init.pp", :type => :definition, :name => "mydef" - @node = stub_everything 'node', :file => "module/manifests/init.pp", :type => :node, :name => "mynode" - - @resource_type_collection = resource_type_collection = Puppet::Resource::TypeCollection.new("env") - @parser.instance_eval { @known_resource_types = resource_type_collection } - - @container = stub_everything 'container' - end - - it "should document classes in the parsed file" do - @resource_type_collection.add_hostclass(@klass) - - @parser.expects(:document_class).with("myclass", @klass, @container) - - @parser.parse_elements(@container, @resource_type_collection) - end - - it "should not document class parsed in an other file" do - @klass.stubs(:file).returns("/not/same/path/file.pp") - @resource_type_collection.add_hostclass(@klass) - - @parser.expects(:document_class).with("myclass", @klass, @container).never - - @parser.parse_elements(@container, @resource_type_collection) - end - - it "should document vardefs for the main class" do - @klass.stubs(:name).returns :main - @resource_type_collection.add_hostclass(@klass) - - code = stub 'code', :is_a? => false - @klass.stubs(:name).returns("") - @klass.stubs(:code).returns(code) - - @parser.expects(:scan_for_vardef).with(@container, code) - - @parser.parse_elements(@container, @resource_type_collection) - end - - it "should document definitions in the parsed file" do - @resource_type_collection.add_definition(@definition) - - @parser.expects(:document_define).with("mydef", @definition, @container) - - @parser.parse_elements(@container, @resource_type_collection) - end - - it "should not document definitions parsed in an other file" do - @definition.stubs(:file).returns("/not/same/path/file.pp") - @resource_type_collection.add_definition(@definition) - - @parser.expects(:document_define).with("mydef", @definition, @container).never - - @parser.parse_elements(@container, @resource_type_collection) - end - - it "should document nodes in the parsed file" do - @resource_type_collection.add_node(@node) - - @parser.expects(:document_node).with("mynode", @node, @container) - - @parser.parse_elements(@container, @resource_type_collection) - end - - it "should not document node parsed in an other file" do - @node.stubs(:file).returns("/not/same/path/file.pp") - @resource_type_collection.add_node(@node) - - @parser.expects(:document_node).with("mynode", @node, @container).never - - @parser.parse_elements(@container, @resource_type_collection) - end - end - - describe "when documenting definition" do - before(:each) do - @define = stub_everything 'define', :arguments => [], :doc => "mydoc", :file => "file", :line => 42 - @class = stub_everything 'class' - @parser.stubs(:get_class_or_module).returns([@class, "mydef"]) - end - - it "should register a RDoc method to the current container" do - @class.expects(:add_method).with { |m| m.name == "mydef"} - @parser.document_define("mydef", @define, @class) - end - - it "should attach the documentation to this method" do - @class.expects(:add_method).with { |m| m.comment = "mydoc" } - - @parser.document_define("mydef", @define, @class) - end - - it "should produce a better error message on unhandled exception" do - @class.expects(:add_method).raises(ArgumentError) - - lambda { @parser.document_define("mydef", @define, @class) }.should raise_error(Puppet::ParseError, /in file at line 42/) - end - - it "should convert all definition parameter to string" do - arg = stub 'arg' - val = stub 'val' - - @define.stubs(:arguments).returns({arg => val}) - - arg.expects(:to_s).returns("arg") - val.expects(:to_s).returns("val") - - @parser.document_define("mydef", @define, @class) - end - end - - describe "when documenting nodes" do - before :each do - @code = stub_everything 'code' - @node = stub_everything 'node', :doc => "mydoc", :parent => "parent", :code => @code, :file => "file", :line => 42 - @rdoc_node = stub_everything 'rdocnode' - - @class = stub_everything 'class' - @class.stubs(:add_node).returns(@rdoc_node) - end - - it "should add a node to the current container" do - @class.expects(:add_node).with("mynode", "parent").returns(@rdoc_node) - @parser.document_node("mynode", @node, @class) - end - - it "should associate the node documentation to the rdoc node" do - @rdoc_node.expects(:add_comment).with("mydoc", "file") - @parser.document_node("mynode", @node, @class) - end - - it "should scan for include and require" do - @parser.expects(:scan_for_include_or_require).with(@rdoc_node, @code) - @parser.document_node("mynode", @node, @class) - end - - it "should scan for variable definition" do - @parser.expects(:scan_for_vardef).with(@rdoc_node, @code) - @parser.document_node("mynode", @node, @class) - end - - it "should scan for resources if needed" do - Puppet[:document_all] = true - @parser.expects(:scan_for_resource).with(@rdoc_node, @code) - @parser.document_node("mynode", @node, @class) - end - - it "should produce a better error message on unhandled exception" do - @class.stubs(:add_node).raises(ArgumentError) - - lambda { @parser.document_node("mynode", @node, @class) }.should raise_error(Puppet::ParseError, /in file at line 42/) - end - end - - describe "when documenting classes" do - before :each do - @code = stub_everything 'code' - @class = stub_everything 'class', :doc => "mydoc", :parent => "parent", :code => @code, :file => "file", :line => 42 - @rdoc_class = stub_everything 'rdoc-class' - - @module = stub_everything 'class' - @module.stubs(:add_class).returns(@rdoc_class) - @parser.stubs(:get_class_or_module).returns([@module, "myclass"]) - end - - it "should add a class to the current container" do - @module.expects(:add_class).with(RDoc::PuppetClass, "myclass", "parent").returns(@rdoc_class) - @parser.document_class("mynode", @class, @module) - end - - it "should set the superclass" do - @rdoc_class.expects(:superclass=).with("parent") - @parser.document_class("mynode", @class, @module) - end - - it "should associate the node documentation to the rdoc class" do - @rdoc_class.expects(:add_comment).with("mydoc", "file") - @parser.document_class("mynode", @class, @module) - end - - it "should scan for include and require" do - @parser.expects(:scan_for_include_or_require).with(@rdoc_class, @code) - @parser.document_class("mynode", @class, @module) - end - - it "should scan for resources if needed" do - Puppet[:document_all] = true - @parser.expects(:scan_for_resource).with(@rdoc_class, @code) - @parser.document_class("mynode", @class, @module) - end - - it "should produce a better error message on unhandled exception" do - @module.stubs(:add_class).raises(ArgumentError) - - lambda { @parser.document_class("mynode", @class, @module) }.should raise_error(Puppet::ParseError, /in file at line 42/) - end - end - - describe "when scanning for includes and requires" do - - def create_stmt(name) - stmt_value = stub "#{name}_value", :to_s => "myclass" - - Puppet::Parser::AST::Function.new( - :name => name, - :arguments => [stmt_value], - :doc => 'mydoc' - ) - end - - before(:each) do - @class = stub_everything 'class' - @code = stub_everything 'code' - @code.stubs(:is_a?).with(Puppet::Parser::AST::BlockExpression).returns(true) - end - - it "should also scan mono-instruction code" do - @class.expects(:add_include).with { |i| i.is_a?(RDoc::Include) and i.name == "myclass" and i.comment == "mydoc" } - - @parser.scan_for_include_or_require(@class, create_stmt("include")) - end - - it "should register recursively includes to the current container" do - @code.stubs(:children).returns([ create_stmt("include") ]) - - @class.expects(:add_include)#.with { |i| i.is_a?(RDoc::Include) and i.name == "myclass" and i.comment == "mydoc" } - @parser.scan_for_include_or_require(@class, [@code]) - end - - it "should register requires to the current container" do - @code.stubs(:children).returns([ create_stmt("require") ]) - - @class.expects(:add_require).with { |i| i.is_a?(RDoc::Include) and i.name == "myclass" and i.comment == "mydoc" } - @parser.scan_for_include_or_require(@class, [@code]) - end - end - - describe "when scanning for realized virtual resources" do - - def create_stmt - stmt_value = stub "resource_ref", :to_s => "File[\"/tmp/a\"]" - Puppet::Parser::AST::Function.new( - :name => 'realize', - :arguments => [stmt_value], - :doc => 'mydoc' - ) - end - - before(:each) do - @class = stub_everything 'class' - @code = stub_everything 'code' - @code.stubs(:is_a?).with(Puppet::Parser::AST::BlockExpression).returns(true) - end - - it "should also scan mono-instruction code" do - @class.expects(:add_realize).with { |i| i.is_a?(RDoc::Include) and i.name == "File[\"/tmp/a\"]" and i.comment == "mydoc" } - - @parser.scan_for_realize(@class,create_stmt) - end - - it "should register recursively includes to the current container" do - @code.stubs(:children).returns([ create_stmt ]) - - @class.expects(:add_realize).with { |i| i.is_a?(RDoc::Include) and i.name == "File[\"/tmp/a\"]" and i.comment == "mydoc" } - @parser.scan_for_realize(@class, [@code]) - end - end - - describe "when scanning for variable definition" do - before :each do - @class = stub_everything 'class' - - @stmt = stub_everything 'stmt', :name => "myvar", :value => "myvalue", :doc => "mydoc" - @stmt.stubs(:is_a?).with(Puppet::Parser::AST::BlockExpression).returns(false) - @stmt.stubs(:is_a?).with(Puppet::Parser::AST::VarDef).returns(true) - - @code = stub_everything 'code' - @code.stubs(:is_a?).with(Puppet::Parser::AST::BlockExpression).returns(true) - end - - it "should recursively register variables to the current container" do - @code.stubs(:children).returns([ @stmt ]) - - @class.expects(:add_constant).with { |i| i.is_a?(RDoc::Constant) and i.name == "myvar" and i.comment == "mydoc" } - @parser.scan_for_vardef(@class, [ @code ]) - end - - it "should also scan mono-instruction code" do - @class.expects(:add_constant).with { |i| i.is_a?(RDoc::Constant) and i.name == "myvar" and i.comment == "mydoc" } - - @parser.scan_for_vardef(@class, @stmt) - end - end - - describe "when scanning for resources" do - before :each do - @class = stub_everything 'class' - @stmt = Puppet::Parser::AST::Resource.new( - :type => "File", - :instances => Puppet::Parser::AST::BlockExpression.new(:children => [ - Puppet::Parser::AST::ResourceInstance.new( - :title => Puppet::Parser::AST::Name.new(:value => "myfile"), - :parameters => Puppet::Parser::AST::BlockExpression.new(:children => []) - ) - ]), - :doc => 'mydoc' - ) - - @code = stub_everything 'code' - @code.stubs(:is_a?).with(Puppet::Parser::AST::BlockExpression).returns(true) - end - - it "should register a PuppetResource to the current container" do - @code.stubs(:children).returns([ @stmt ]) - - @class.expects(:add_resource).with { |i| i.is_a?(RDoc::PuppetResource) and i.title == "myfile" and i.comment == "mydoc" } - @parser.scan_for_resource(@class, [ @code ]) - end - - it "should also scan mono-instruction code" do - @class.expects(:add_resource).with { |i| i.is_a?(RDoc::PuppetResource) and i.title == "myfile" and i.comment == "mydoc" } - - @parser.scan_for_resource(@class, @stmt) - end - end - - describe "when parsing plugins" do - before :each do - @container = stub 'container' - end - - it "should delegate parsing custom facts to parse_facts" do - @parser = RDoc::Parser.new(@top_level, "module/manifests/lib/puppet/facter/test.rb", nil, Options.instance, RDoc::Stats.new) - - @parser.expects(:parse_fact).with(@container) - @parser.parse_plugins(@container) - end - - it "should delegate parsing plugins to parse_plugins" do - @parser = RDoc::Parser.new(@top_level, "module/manifests/lib/puppet/functions/test.rb", nil, Options.instance, RDoc::Stats.new) - - @parser.expects(:parse_puppet_plugin).with(@container) - @parser.parse_plugins(@container) - end - end - - describe "when parsing plugins" do - before :each do - @container = stub_everything 'container' - end - - it "should add custom functions to the container" do - File.stubs(:open).yields("# documentation - module Puppet::Parser::Functions - newfunction(:myfunc, :type => :rvalue) do |args| - File.dirname(args[0]) - end - end".split("\n")) - - @container.expects(:add_plugin).with do |plugin| - plugin.comment == "documentation\n" #and - plugin.name == "myfunc" - end - - @parser.parse_puppet_plugin(@container) - end - - it "should add custom types to the container" do - File.stubs(:open).yields("# documentation - Puppet::Type.newtype(:mytype) do - end".split("\n")) - - @container.expects(:add_plugin).with do |plugin| - plugin.comment == "documentation\n" #and - plugin.name == "mytype" - end - - @parser.parse_puppet_plugin(@container) - end - end - - describe "when parsing facts" do - before :each do - @container = stub_everything 'container' - File.stubs(:open).yields(["# documentation", "Facter.add('myfact') do", "confine :kernel => :linux", "end"]) - end - - it "should add facts to the container" do - @container.expects(:add_fact).with do |fact| - fact.comment == "documentation\n" and - fact.name == "myfact" - end - - @parser.parse_fact(@container) - end - - it "should add confine to the parsed facts" do - ourfact = nil - @container.expects(:add_fact).with do |fact| - ourfact = fact - true - end - - @parser.parse_fact(@container) - ourfact.confine.should == { :type => "kernel", :value => ":linux" } - end - end -end diff --git a/spec/unit/util/rdoc_spec.rb b/spec/unit/util/rdoc_spec.rb index f71bf7939..fb9494b98 100755 --- a/spec/unit/util/rdoc_spec.rb +++ b/spec/unit/util/rdoc_spec.rb @@ -1,141 +1,119 @@ #! /usr/bin/env ruby require 'spec_helper' require 'puppet/util/rdoc' require 'rdoc/rdoc' describe Puppet::Util::RDoc do describe "when generating RDoc HTML documentation" do before :each do @rdoc = stub_everything 'rdoc' RDoc::RDoc.stubs(:new).returns(@rdoc) end it "should tell the parser to ignore import" do Puppet.expects(:[]=).with(:ignoreimport, true) Puppet::Util::RDoc.rdoc("output", []) end it "should tell RDoc to generate documentation using the Puppet generator" do @rdoc.expects(:document).with { |args| args.include?("--fmt") and args.include?("puppet") } Puppet::Util::RDoc.rdoc("output", []) end it "should tell RDoc to be quiet" do @rdoc.expects(:document).with { |args| args.include?("--quiet") } Puppet::Util::RDoc.rdoc("output", []) end it "should pass charset to RDoc" do @rdoc.expects(:document).with { |args| args.include?("--charset") and args.include?("utf-8") } Puppet::Util::RDoc.rdoc("output", [], "utf-8") end - describe "with rdoc1", :if => Puppet.features.rdoc1? do - it "should install the Puppet HTML Generator into RDoc generators" do - Puppet::Util::RDoc.rdoc("output", []) - - RDoc::RDoc::GENERATORS["puppet"].file_name.should == "puppet/util/rdoc/generators/puppet_generator.rb" - end - - it "should tell RDoc to force updates of indices when RDoc supports it" do - ::Options::OptionList.stubs(:options).returns([["--force-update", "-U", 0 ]]) - @rdoc.expects(:document).with { |args| args.include?("--force-update") } - - Puppet::Util::RDoc.rdoc("output", []) - end - - it "should not tell RDoc to force updates of indices when RDoc doesn't support it" do - ::Options::OptionList.stubs(:options).returns([]) - @rdoc.expects(:document).never.with { |args| args.include?("--force-update") } - - Puppet::Util::RDoc.rdoc("output", []) - end - end - it "should tell RDoc to use the given outputdir" do @rdoc.expects(:document).with { |args| args.include?("--op") and args.include?("myoutputdir") } Puppet::Util::RDoc.rdoc("myoutputdir", []) end it "should tell RDoc to exclude all files under any modules//files section" do @rdoc.expects(:document).with { |args| args.include?("--exclude") and args.include?("/modules/[^/]*/files/.*$") } Puppet::Util::RDoc.rdoc("myoutputdir", []) end it "should tell RDoc to exclude all files under any modules//templates section" do @rdoc.expects(:document).with { |args| args.include?("--exclude") and args.include?("/modules/[^/]*/templates/.*$") } Puppet::Util::RDoc.rdoc("myoutputdir", []) end it "should give all the source directories to RDoc" do @rdoc.expects(:document).with { |args| args.include?("sourcedir") } Puppet::Util::RDoc.rdoc("output", ["sourcedir"]) end end describe "when running a manifest documentation" do - it "should tell the parser to ignore import" do - Puppet.expects(:[]=).with(:ignoreimport, true) - - Puppet::Util::RDoc.manifestdoc([]) - end - - it "should use a parser with the correct environment" do - FileTest.stubs(:file?).returns(true) - Puppet::Util::RDoc.stubs(:output) - - parser = stub_everything - Puppet::Parser::Parser.stubs(:new).with{ |env| env.is_a?(Puppet::Node::Environment) }.returns(parser) - - parser.expects(:file=).with("file") - parser.expects(:parse) - - Puppet::Util::RDoc.manifestdoc(["file"]) - end - - it "should puppet parse all given files" do - FileTest.stubs(:file?).returns(true) - Puppet::Util::RDoc.stubs(:output) - - parser = stub_everything - Puppet::Parser::Parser.stubs(:new).returns(parser) - - parser.expects(:file=).with("file") - parser.expects(:parse) - - Puppet::Util::RDoc.manifestdoc(["file"]) - end - - it "should call output for each parsed file" do - FileTest.stubs(:file?).returns(true) - - ast = stub_everything - parser = stub_everything - Puppet::Parser::Parser.stubs(:new).returns(parser) - parser.stubs(:parse).returns(ast) - - Puppet::Util::RDoc.expects(:output).with("file", ast) - - Puppet::Util::RDoc.manifestdoc(["file"]) - end - - describe "when outputing documentation" do - it "should output doc for ast classes, nodes and definitions in order of increasing line number" do - byline = sequence('documentation outputs in line order') - Puppet::Util::RDoc.expects(:puts).with("im a class\n").in_sequence(byline) - Puppet::Util::RDoc.expects(:puts).with("im a node\n").in_sequence(byline) - Puppet::Util::RDoc.expects(:puts).with("im a define\n").in_sequence(byline) - # any other output must fail - Puppet::Util::RDoc.manifestdoc([my_fixture('basic.pp')]) - end - end +# it "should tell the parser to ignore import" do +# Puppet.expects(:[]=).with(:ignoreimport, true) +# +# Puppet::Util::RDoc.manifestdoc([]) +# end + +# it "should use a parser with the correct environment" do +# FileTest.stubs(:file?).returns(true) +# Puppet::Util::RDoc.stubs(:output) +# +# parser = stub_everything +# Puppet::Parser::Parser.stubs(:new).with{ |env| env.is_a?(Puppet::Node::Environment) }.returns(parser) +# +# parser.expects(:file=).with("file") +# parser.expects(:parse) +# +# Puppet::Util::RDoc.manifestdoc(["file"]) +# end + +# it "should puppet parse all given files" do +# FileTest.stubs(:file?).returns(true) +# Puppet::Util::RDoc.stubs(:output) +# +# parser = stub_everything +# Puppet::Parser::Parser.stubs(:new).returns(parser) +# +# parser.expects(:file=).with("file") +# parser.expects(:parse) +# +# Puppet::Util::RDoc.manifestdoc(["file"]) +# end + +# it "should call output for each parsed file" do +# FileTest.stubs(:file?).returns(true) +# +# ast = stub_everything +# parser = stub_everything +# Puppet::Parser::Parser.stubs(:new).returns(parser) +# parser.stubs(:parse).returns(ast) +# +# Puppet::Util::RDoc.expects(:output).with("file", ast) +# +# Puppet::Util::RDoc.manifestdoc(["file"]) +# end + +# describe "when outputing documentation" do +# it "should output doc for ast classes, nodes and definitions in order of increasing line number" do +# byline = sequence('documentation outputs in line order') +# Puppet::Util::RDoc.expects(:puts).with("im a class\n").in_sequence(byline) +# Puppet::Util::RDoc.expects(:puts).with("im a node\n").in_sequence(byline) +# Puppet::Util::RDoc.expects(:puts).with("im a define\n").in_sequence(byline) +# # any other output must fail +# Puppet::Util::RDoc.manifestdoc([my_fixture('basic.pp')]) +# end +# end end end