require 'ostruct' # An adapter class that conforms a Pops model instance + adapters to the # interface expected by YARD handlers. # # FIXME: Inhertiting from OpenStruct is a bit of a hack. It allows attributes # to be declared as needed but in the long run understandibility of the code # would be improved by having a concrete model. class PuppetX::PuppetLabs::Strings::Pops::YARDStatement < OpenStruct attr_reader :pops_obj, :comments def initialize(pops_obj) # Initialize OpenStruct super({}) unless pops_obj.is_a? Puppet::Pops::Model::PopsObject raise ArgumentError, "A YARDStatement can only be initialized from a PopsObject. Got a: #{pops_obj.class}" end @pops_obj = pops_obj @pos_adapter = Puppet::Pops::Adapters::SourcePosAdapter.adapt(@pops_obj) # FIXME: Perhaps this should be a seperate adapter? @comments = extract_comments end def type pops_obj.class end def line @line ||= @pos_adapter.line end def source @source ||= @pos_adapter.extract_text end # FIXME: I don't know quite what these are supposed to do, but they show up # quite often in the YARD handler code. Figure out whether they are # necessary. alias_method :show, :source def comments_hash_flag; nil end def comments_range; nil end private # TODO: This stuff should probably be part of a separate class/adapter. COMMENT_PATTERN = /^\s*#.*\n/ def extract_comments comments = [] program = pops_obj.eAllContainers.find {|c| c.is_a?(Puppet::Pops::Model::Program) } # FIXME: Horribly inefficient. Multiple copies. Generator pattern would # be much better. source_text = program.source_text.lines.to_a source_text.slice(0, line-1).reverse.each do |line| if COMMENT_PATTERN.match(line) # FIXME: The gsub trims comments, but is extremely optimistic: It # assumes only one space separates the comment body from the # comment character. # NOTE: We cannot just trim any amount of whitespace as indentation # is sometimes significant in markdown. We would need a real parser. # Comments which begin with some whitespace, a hash and then some # tabs and spaces should be scrubbed. Comments which just have a # solitary hash then a newline should keep that newline since newlines # are significant in markdown. comments.unshift line.gsub(/^\s*#[\t ]/, '').gsub(/^\s*#\n/, "\n") else # No comment found on this line. We must be done piecing together a # comment block. break end end # Stick everything back together. comments.join end end