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
 6 def self.included(base)
 7   base.class_eval do
 8     attr_accessor :input_file_name, :top_level
 9 
10     # parser registration into RDoc
11     parse_files_matching(/\.(rb)$/)
12   end
13 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
16 def initialize(top_level, file_name, body, options, stats)
17   @options = options
18   @stats   = stats
19   @input_file_name = file_name
20   @top_level = top_level
21   @top_level.extend(RDoc::PuppetTopLevel)
22   @progress = $stderr unless options.quiet
23 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
214 def create_rdoc_preprocess
215   raise(NotImplementedError, "This method must be overwritten for whichever version of RDoc this parser is working with")
216 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
36 def find_object_named(container, name)
37   return container if container.name == name
38   container.each_classmodule do |m|
39     return m if m.name == name
40   end
41   nil
42 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
45 def get_class_or_module(container, name)
46 
47   # class ::A -> A is in the top level
48   if name =~ /^::/
49     container = @top_level
50   end
51 
52   names = name.split('::')
53 
54   final_name = names.pop
55   names.each do |n|
56     prev_container = container
57     container = find_object_named(container, n)
58     container ||= prev_container.add_class(RDoc::PuppetClass, n, nil)
59   end
60   [container, final_name]
61 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
219 def look_for_directives_in(context, comment)
220   preprocess = create_rdoc_preprocess
221 
222   preprocess.handle(comment) do |directive, param|
223     case directive
224     when "stopdoc"
225       context.stop_doc
226       ""
227     when "startdoc"
228       context.start_doc
229       context.force_documentation = true
230       ""
231     when "enddoc"
232       #context.done_documenting = true
233       #""
234       throw :enddoc
235     when "main"
236       options = Options.instance
237       options.main_page = param
238       ""
239     when "title"
240       options = Options.instance
241       options.title = param
242       ""
243     when "section"
244       context.set_current_section(param, comment)
245       comment.replace("") # 1.8 doesn't support #clear
246       break
247     else
248       warn "Unrecognized directive '#{directive}'"
249       break
250     end
251   end
252   remove_private_comments(comment)
253 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
148 def parse_fact(container)
149   comments = ""
150   current_fact = nil
151   parsed_facts = []
152   File.open(@input_file_name) do |of|
153     of.each do |line|
154       # fetch comments
155       if line =~ /^[ \t]*# ?(.*)$/
156         comments += $1 + "\n"
157       elsif line =~ /^[ \t]*Facter.add\(['"](.*?)['"]\)/
158         current_fact = RDoc::Fact.new($1,{})
159         look_for_directives_in(container, comments) unless comments.empty?
160         current_fact.comment = comments
161         parsed_facts << current_fact
162         comments = ""
163         Puppet.debug "rdoc: found custom fact #{current_fact.name}"
164       elsif line =~ /^[ \t]*confine[ \t]*:(.*?)[ \t]*=>[ \t]*(.*)$/
165         current_fact.confine = { :type => $1, :value => $2 } unless current_fact.nil?
166       else # unknown line type
167         comments =""
168       end
169     end
170   end
171   parsed_facts.each do |f|
172     container.add_fact(f)
173     f.record_location(@top_level)
174   end
175 end
parse_plugins(container) click to toggle source

create documentation for plugins

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

main entry point

   # File lib/puppet/util/rdoc/parser/puppet_parser_core.rb
26 def scan
27   environment = Puppet.lookup(:current_environment)
28   scan_top_level(@top_level, environment)
29   @top_level
30 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
102 def scan_top_level(container, environment)
103   # use the module README as documentation for the module
104   comment = ""
105   %w{README README.rdoc}.each do |rfile|
106     readme = File.join(File.dirname(File.dirname(@input_file_name)), rfile)
107     # module README should be UTF-8, not default system encoding
108     comment = File.open(readme,"r:UTF-8") { |f| f.read } if FileTest.readable?(readme)
109   end
110   look_for_directives_in(container, comment) unless comment.empty?
111 
112   # infer module name from directory
113   name = split_module(@input_file_name, environment)
114   if name.nil?
115     # skip .pp files that are not in manifests directories as we can't guarantee they're part
116     # of a module or the global configuration.
117     # PUP-3638, keeping this while it should have no effect since no .pp files are now processed
118     container.document_self = false
119     return
120   end
121 
122   Puppet.debug "rdoc: scanning for #{name}"
123 
124   container.module_name = name
125   container.global=true if name == SITE
126 
127   container, name  = get_class_or_module(container,name)
128   mod = container.add_module(RDoc::PuppetModule, name)
129   mod.record_location(@top_level)
130   mod.add_comment(comment, @top_level)
131 
132   if @input_file_name =~ /\.rb$/
133     parse_plugins(mod)
134   end
135 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
67 def split_module(path, environment)
68   # find a module
69   fullpath = File.expand_path(path)
70   Puppet.debug "rdoc: testing #{fullpath}"
71   if fullpath =~ /(.*)\/([^\/]+)\/(?:manifests|plugins|lib)\/.+\.(rb)$/
72     modpath = $1
73     name = $2
74     Puppet.debug "rdoc: module #{name} into #{modpath} ?"
75     environment.modulepath.each do |mp|
76       if File.identical?(modpath,mp)
77         Puppet.debug "rdoc: found module #{name}"
78         return name
79       end
80     end
81   end
82   if fullpath =~ /\.(rb)$/
83     # there can be paths we don't want to scan under modules
84     # imagine a ruby or manifest that would be distributed as part as a module
85     # but we don't want those to be hosted under <site>
86     environment.modulepath.each do |mp|
87       # check that fullpath is a descendant of mp
88       dirname = fullpath
89       previous = dirname
90       while (dirname = File.dirname(previous)) != previous
91         previous = dirname
92         return nil if File.identical?(dirname,mp)
93       end
94     end
95   end
96   # we are under a global manifests
97   Puppet.debug "rdoc: global manifests"
98   SITE
99 end