module RDoc::PuppetParserCore

Functionality common to both our RDoc version 1 and 2 parsers.

Constants

SITE

Public Class Methods

included(base) click to toggle source
   # File lib/puppet/util/rdoc/parser/puppet_parser_core.rb
 7 def self.included(base)
 8   base.class_eval do
 9     attr_accessor :input_file_name, :top_level
10 
11     # parser registration into RDoc
12     parse_files_matching(/\.(rb)$/)
13   end
14 end
new(top_level, file_name, body, options, stats) click to toggle source

called with the top level file

   # File lib/puppet/util/rdoc/parser/puppet_parser_core.rb
17 def initialize(top_level, file_name, body, options, stats)
18   @options = options
19   @stats   = stats
20   @input_file_name = file_name
21   @top_level = top_level
22   @top_level.extend(RDoc::PuppetTopLevel)
23   @progress = $stderr unless options.quiet
24 end

Public Instance Methods

create_rdoc_preprocess() click to toggle source

New instance of the appropriate PreProcess for our RDoc version.

    # File lib/puppet/util/rdoc/parser/puppet_parser_core.rb
215 def create_rdoc_preprocess
216   raise(NotImplementedError, "This method must be overwritten for whichever version of RDoc this parser is working with")
217 end
find_object_named(container, name) click to toggle source

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.

   # File lib/puppet/util/rdoc/parser/puppet_parser_core.rb
37 def find_object_named(container, name)
38   return container if container.name == name
39   container.each_classmodule do |m|
40     return m if m.name == name
41   end
42   nil
43 end
get_class_or_module(container, name) click to toggle source

walk down the namespace and lookup/create container as needed

   # File lib/puppet/util/rdoc/parser/puppet_parser_core.rb
46 def get_class_or_module(container, name)
47 
48   # class ::A -> A is in the top level
49   if name =~ /^::/
50     container = @top_level
51   end
52 
53   names = name.split('::')
54 
55   final_name = names.pop
56   names.each do |n|
57     prev_container = container
58     container = find_object_named(container, n)
59     container ||= prev_container.add_class(RDoc::PuppetClass, n, nil)
60   end
61   [container, final_name]
62 end
look_for_directives_in(context, comment) click to toggle source

look_for_directives_in scans the current comment for RDoc directives

    # File lib/puppet/util/rdoc/parser/puppet_parser_core.rb
220 def look_for_directives_in(context, comment)
221   preprocess = create_rdoc_preprocess
222 
223   preprocess.handle(comment) do |directive, param|
224     case directive
225     when "stopdoc"
226       context.stop_doc
227       ""
228     when "startdoc"
229       context.start_doc
230       context.force_documentation = true
231       ""
232     when "enddoc"
233       #context.done_documenting = true
234       #""
235       throw :enddoc
236     when "main"
237       options = Options.instance
238       options.main_page = param
239       ""
240     when "title"
241       options = Options.instance
242       options.title = param
243       ""
244     when "section"
245       context.set_current_section(param, comment)
246       comment.replace("") # 1.8 doesn't support #clear
247       break
248     else
249       warn "Unrecognized directive '#{directive}'"
250       break
251     end
252   end
253   remove_private_comments(comment)
254 end
parse_fact(container) click to toggle source

this is a poor man custom fact parser :-)

    # File lib/puppet/util/rdoc/parser/puppet_parser_core.rb
149 def parse_fact(container)
150   comments = ""
151   current_fact = nil
152   parsed_facts = []
153   File.open(@input_file_name) do |of|
154     of.each do |line|
155       # fetch comments
156       if line =~ /^[ \t]*# ?(.*)$/
157         comments += $1 + "\n"
158       elsif line =~ /^[ \t]*(Facter.add|Puppet\.runtime\[:facter\].add)\(['"](.*?)['"]\)/
159         current_fact = RDoc::Fact.new($1,{})
160         look_for_directives_in(container, comments) unless comments.empty?
161         current_fact.comment = comments
162         parsed_facts << current_fact
163         comments = ""
164         Puppet.debug "rdoc: found custom fact #{current_fact.name}"
165       elsif line =~ /^[ \t]*confine[ \t]*:(.*?)[ \t]*=>[ \t]*(.*)$/
166         current_fact.confine = { :type => $1, :value => $2 } unless current_fact.nil?
167       else # unknown line type
168         comments =""
169       end
170     end
171   end
172   parsed_facts.each do |f|
173     container.add_fact(f)
174     f.record_location(@top_level)
175   end
176 end
parse_plugins(container) click to toggle source

create documentation for plugins

    # File lib/puppet/util/rdoc/parser/puppet_parser_core.rb
139 def parse_plugins(container)
140   Puppet.debug "rdoc: scanning plugin or fact"
141   if @input_file_name =~ /\/facter\/[^\/]+\.rb$/
142     parse_fact(container)
143   else
144     parse_puppet_plugin(container)
145   end
146 end
parse_puppet_plugin(container) click to toggle source

this is a poor man puppet plugin parser :-) it doesn't extract doc nor desc :-(

    # File lib/puppet/util/rdoc/parser/puppet_parser_core.rb
180 def parse_puppet_plugin(container)
181   comments = ""
182   current_plugin = nil
183 
184   File.open(@input_file_name) do |of|
185     of.each do |line|
186       # fetch comments
187       if line =~ /^[ \t]*# ?(.*)$/
188         comments += $1 + "\n"
189       elsif line =~ /^[ \t]*(?:Puppet::Parser::Functions::)?newfunction[ \t]*\([ \t]*:(.*?)[ \t]*,[ \t]*:type[ \t]*=>[ \t]*(:rvalue|:lvalue)/
190         current_plugin = RDoc::Plugin.new($1, "function")
191         look_for_directives_in(container, comments) unless comments.empty?
192         current_plugin.comment = comments
193         current_plugin.record_location(@top_level)
194         container.add_plugin(current_plugin)
195         comments = ""
196         Puppet.debug "rdoc: found new function plugins #{current_plugin.name}"
197       elsif line =~ /^[ \t]*Puppet::Type.newtype[ \t]*\([ \t]*:(.*?)\)/
198         current_plugin = RDoc::Plugin.new($1, "type")
199         look_for_directives_in(container, comments) unless comments.empty?
200         current_plugin.comment = comments
201         current_plugin.record_location(@top_level)
202         container.add_plugin(current_plugin)
203         comments = ""
204         Puppet.debug "rdoc: found new type plugins #{current_plugin.name}"
205       elsif line =~ /module Puppet::Parser::Functions/
206         # skip
207       else # unknown line type
208         comments =""
209       end
210     end
211   end
212 end
remove_private_comments(comment) click to toggle source
    # File lib/puppet/util/rdoc/parser/puppet_parser_core.rb
256 def remove_private_comments(comment)
257   comment.gsub!(/^#--.*?^#\+\+/m, '')
258   comment.sub!(/^#--.*/m, '')
259 end
scan() click to toggle source

main entry point

   # File lib/puppet/util/rdoc/parser/puppet_parser_core.rb
27 def scan
28   environment = Puppet.lookup(:current_environment)
29   scan_top_level(@top_level, environment)
30   @top_level
31 end
scan_top_level(container, environment) click to toggle source

create documentation for the top level container

    # File lib/puppet/util/rdoc/parser/puppet_parser_core.rb
103 def scan_top_level(container, environment)
104   # use the module README as documentation for the module
105   comment = ""
106   %w{README README.rdoc}.each do |rfile|
107     readme = File.join(File.dirname(File.dirname(@input_file_name)), rfile)
108     # module README should be UTF-8, not default system encoding
109     comment = File.open(readme,"r:UTF-8") { |f| f.read } if FileTest.readable?(readme)
110   end
111   look_for_directives_in(container, comment) unless comment.empty?
112 
113   # infer module name from directory
114   name = split_module(@input_file_name, environment)
115   if name.nil?
116     # skip .pp files that are not in manifests directories as we can't guarantee they're part
117     # of a module or the global configuration.
118     # PUP-3638, keeping this while it should have no effect since no .pp files are now processed
119     container.document_self = false
120     return
121   end
122 
123   Puppet.debug "rdoc: scanning for #{name}"
124 
125   container.module_name = name
126   container.global=true if name == SITE
127 
128   container, name  = get_class_or_module(container,name)
129   mod = container.add_module(RDoc::PuppetModule, name)
130   mod.record_location(@top_level)
131   mod.add_comment(comment, @top_level)
132 
133   if @input_file_name =~ /\.rb$/
134     parse_plugins(mod)
135   end
136 end
split_module(path, environment) click to toggle source

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.

    # File lib/puppet/util/rdoc/parser/puppet_parser_core.rb
 68 def split_module(path, environment)
 69   # find a module
 70   fullpath = File.expand_path(path)
 71   Puppet.debug "rdoc: testing #{fullpath}"
 72   if fullpath =~ /(.*)\/([^\/]+)\/(?:manifests|plugins|lib)\/.+\.(rb)$/
 73     modpath = $1
 74     name = $2
 75     Puppet.debug "rdoc: module #{name} into #{modpath} ?"
 76     environment.modulepath.each do |mp|
 77       if File.identical?(modpath,mp)
 78         Puppet.debug "rdoc: found module #{name}"
 79         return name
 80       end
 81     end
 82   end
 83   if fullpath =~ /\.(rb)$/
 84     # there can be paths we don't want to scan under modules
 85     # imagine a ruby or manifest that would be distributed as part as a module
 86     # but we don't want those to be hosted under <site>
 87     environment.modulepath.each do |mp|
 88       # check that fullpath is a descendant of mp
 89       dirname = fullpath
 90       previous = dirname
 91       while (dirname = File.dirname(previous)) != previous
 92         previous = dirname
 93         return nil if File.identical?(dirname,mp)
 94       end
 95     end
 96   end
 97   # we are under a global manifests
 98   Puppet.debug "rdoc: global manifests"
 99   SITE
100 end