puppet-strings/lib/puppet_x/puppetlabs/strings/yard/handlers/provider_handler.rb

96 lines
3.3 KiB
Ruby

# Handles `dispatch` calls within a future parser function declaration. For
# now, it just treats any docstring as an `@overlaod` tag and attaches the
# overload to the parent function.
class PuppetX::PuppetLabs::Strings::YARD::Handlers::PuppetProviderHandler < YARD::Handlers::Ruby::Base
include PuppetX::PuppetLabs::Strings::YARD::CodeObjects
handles :command_call, :call
process do
@heredoc_helper = HereDocHelper.new
# Puppet types always begin with:
# Puppet::Types.newtype...
# Therefore, we match the corresponding trees which look like this:
# s(:call,
# s(:const_path_ref,
# s(:var_ref, s(:const, "Puppet", ...), ...),
# s(:const, "Type", ...),
# You think this is ugly? It's better than the alternative.
return unless statement.children.length > 2
first = statement.children.first.first
return unless (first.source == 'Puppet::Type') ||
(first.type == :var_ref &&
first.source == 'Type') &&
statement[2].source == 'provide'
i = statement.index { |s| YARD::Parser::Ruby::AstNode === s && s.type == :ident && s.source == 'provide' }
provider_name = statement[i+1].jump(:ident).source
type_name = statement.jump(:symbol).first.source
obj = ProviderObject.new(:root, "#{provider_name}_provider")
docstring = nil
features = []
commands = []
confines = {}
defaults = {}
do_block = statement.jump(:do_block)
do_block.traverse do |node|
if is_a_func_call_named?('desc', node)
content = node.jump(:tstring_content)
# if we found the string content extract its source
if content != node
# The docstring is either the source stripped of heredoc
# annotations or the raw source.
if @heredoc_helper.is_heredoc?(content.source)
docstring = @heredoc_helper.process_heredoc content.source
else
docstring = content.source
end
end
elsif is_a_func_call_named?('confine', node)
node.traverse do |s|
if s.type == :assoc
k = s.first.jump(:ident).source
v = s[1].first.source
confines[k] = v
end
end
elsif is_a_func_call_named?('has_feature', node)
list = node.jump :list
if list != nil && list != node
features += list.map { |s| s.source if YARD::Parser::Ruby::AstNode === s }.compact
end
elsif is_a_func_call_named?('commands', node)
assoc = node.jump(:assoc)
if assoc && assoc != node
ident = assoc.jump(:ident)
if ident && ident != assoc
commands << ident.source
end
end
elsif is_a_func_call_named?('defaultfor', node)
node.traverse do |s|
if s.type == :assoc
k = s.first.jump(:ident).source
v = s[1].first.source
defaults[k] = v
end
end
end
end
obj.features = features
obj.commands = commands
obj.confines = confines
obj.defaults = defaults
obj.type_name = type_name
obj.header_name = provider_name
register_docstring(obj, docstring, nil)
register obj
end
def is_a_func_call_named?(name, node)
(node.type == :fcall || node.type == :command || node.type == :vcall) && node.children.first.source == name
end
end