Merge pull request #126 from whopper/PDOC-136/3x_function_return

(PDOC-136) Detect return type syntax in Puppet Language functions
This commit is contained in:
Jesse Scott 2016-11-14 11:36:40 -08:00 committed by GitHub
commit bf68ae0022
6 changed files with 131 additions and 4 deletions

View File

@ -27,6 +27,7 @@ env:
- PUPPET_GEM_VERSION="~> 4.5.0" CHECK=spec
- PUPPET_GEM_VERSION="~> 4.6.0" CHECK=spec
- PUPPET_GEM_VERSION="~> 4.7.0" CHECK=spec
- PUPPET_GEM_VERSION="~> 4.8.0" CHECK=spec
- PUPPET_GEM_VERSION="~> 4" CHECK=spec
- PUPPET_GEM_VERSION="~> 4" CHECK=rubocop

View File

@ -20,7 +20,7 @@ class PuppetStrings::Yard::Handlers::Puppet::FunctionHandler < PuppetStrings::Ya
set_parameter_types(object)
# Add a return tag
add_return_tag(object)
add_return_tag(object, statement.type)
# Set the parameters on the object
object.parameters = statement.parameters.map { |p| [p.name, p.value] }
@ -30,13 +30,18 @@ class PuppetStrings::Yard::Handlers::Puppet::FunctionHandler < PuppetStrings::Ya
end
private
def add_return_tag(object)
def add_return_tag(object, type=nil)
tag = object.tag(:return)
if tag
tag.types = ['Any'] unless tag.types
if (type && tag.types) && (type != tag.types)
log.warn "Documented return type does not match return type in function definition near #{statement.file}:#{statement.line}."
end
tag.types = type ? [type] : tag.types || ['Any']
return
end
log.warn "Missing @return tag near #{statement.file}:#{statement.line}."
object.add_tag YARD::Tags::Tag.new(:return, '', 'Any')
type = type || 'Any'
object.add_tag YARD::Tags::Tag.new(:return, '', type)
end
end

View File

@ -134,6 +134,7 @@ module PuppetStrings::Yard::Parsers::Puppet
# Implements the Puppet function statement.
class FunctionStatement < ParameterizedStatement
attr_reader :name
attr_reader :type
# Initializes the Puppet function statement.
# @param [Puppet::Pops::Model::FunctionDefinition] object The model object for the function statement.
@ -141,6 +142,13 @@ module PuppetStrings::Yard::Parsers::Puppet
def initialize(object, file)
super(object, file)
@name = object.name
if object.respond_to? :return_type
type = object.return_type
if type
adapter = ::Puppet::Pops::Adapters::SourcePosAdapter.adapt(type)
@type = adapter.extract_text.gsub('>> ', '')
end
end
end
end
end

View File

@ -10,6 +10,9 @@ PuppetStrings::Yard.setup!
# Enable testing of Puppet functions if running against 4.1+
TEST_PUPPET_FUNCTIONS = Gem::Dependency.new('', '>= 4.1.0').match?('', Puppet::PUPPETVERSION)
# Enable testing of Puppet language functions declared with return type if running against 4.8+
TEST_FUNCTION_RETURN_TYPE = Gem::Dependency.new('', '>= 4.8.0').match?('', Puppet::PUPPETVERSION)
RSpec.configure do |config|
config.mock_with :mocha

View File

@ -68,6 +68,11 @@ SOURCE
expect(tags[2].name).to eq('param3')
expect(tags[2].text).to eq('Third param.')
expect(tags[2].types).to eq(['String'])
tags = object.docstring.tags(:return)
expect(tags.size).to eq(1)
expect(tags[0].tag_name).to eq('return')
expect(tags[0].text).to eq('Returns nothing.')
expect(tags[0].types).to eq(['Undef'])
tags = object.docstring.tags(:api)
expect(tags.size).to eq(1)
expect(tags[0].text).to eq('public')
@ -166,4 +171,71 @@ SOURCE
expect{ subject }.to output(/\[warn\]: Missing @return tag near \(stdin\):5\./).to_stdout_from_any_process
end
end
describe 'parsing a function with a missing @return tag and return type specified in the function definition', if: TEST_FUNCTION_RETURN_TYPE do
let(:source) { <<-SOURCE
# A simple foo function.
function foo() >> String {
notice 'hello world'
}
SOURCE
}
it 'should register a function object with the correct return type' do
expect{ subject }.to output(/\[warn\]: Missing @return tag near \(stdin\):2\./).to_stdout_from_any_process
expect(subject.size).to eq(1)
object = subject.first
expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Function)
tags = object.docstring.tags(:return)
expect(tags.size).to eq(1)
expect(tags[0].tag_name).to eq('return')
expect(tags[0].text).to eq('')
expect(tags[0].types).to eq(['String'])
end
end
describe 'parsing a function with a conflicting return tag and type in function definition', if: TEST_FUNCTION_RETURN_TYPE do
let(:source) { <<-SOURCE
# A simple foo function.
# @return [Integer] this is a lie.
function foo() >> Struct[{'a' => Integer[1, 10]}] {
notice 'hello world'
}
SOURCE
}
it 'should prefer the return type from the function definition' do
expect{ subject }.to output(/\[warn\]: Documented return type does not match return type in function definition near \(stdin\):3\./).to_stdout_from_any_process
expect(subject.size).to eq(1)
object = subject.first
expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Function)
tags = object.docstring.tags(:return)
expect(tags.size).to eq(1)
expect(tags[0].tag_name).to eq('return')
expect(tags[0].text).to eq('this is a lie.')
expect(tags[0].types).to eq(["Struct[{'a' => Integer[1, 10]}]"])
end
end
describe 'parsing a function without a return tag or return type in the function definition' do
let(:source) { <<-SOURCE
# A simple foo function.
function foo() {
notice 'hello world'
}
SOURCE
}
it 'should add a return tag with a default type value of Any' do
expect{ subject }.to output(/\[warn\]: Missing @return tag near \(stdin\):2\./).to_stdout_from_any_process
expect(subject.size).to eq(1)
object = subject.first
expect(object).to be_a(PuppetStrings::Yard::CodeObjects::Function)
tags = object.docstring.tags(:return)
expect(tags.size).to eq(1)
expect(tags[0].tag_name).to eq('return')
expect(tags[0].text).to eq('')
expect(tags[0].types).to eq(['Any'])
end
end
end

View File

@ -168,4 +168,42 @@ SOURCE
expect(statement.parameters[2].value).to eq('hi')
end
end
describe 'parsing puppet functions with return type in defintion', if: TEST_FUNCTION_RETURN_TYPE do
let(:source) { <<SOURCE
# A simple foo function.
# @return Returns a string
function foo() >> String {
notice world
}
SOURCE
}
it 'should parse the puppet function statement' do
subject.parse
expect(subject.enumerator.size).to eq(1)
statement = subject.enumerator.first
expect(statement).to be_a(PuppetStrings::Yard::Parsers::Puppet::FunctionStatement)
expect(statement.type).to eq('String')
end
end
describe 'parsing puppet functions with complex return types in defintion', if: TEST_FUNCTION_RETURN_TYPE do
let(:source) { <<SOURCE
# A simple foo function.
# @return Returns a struct with a hash including one key which must be an integer between 1 and 10.
function foo() >> Struct[{'a' => Integer[1, 10]}] {
notice world
}
SOURCE
}
it 'should parse the puppet function statement' do
subject.parse
expect(subject.enumerator.size).to eq(1)
statement = subject.enumerator.first
expect(statement).to be_a(PuppetStrings::Yard::Parsers::Puppet::FunctionStatement)
expect(statement.type).to eq("Struct\[{'a' => Integer[1, 10]}\]")
end
end
end