> * macro names may resemble names of puppet variables/bindings, e.g.
> 'foo::bar::geez'
> * stored in a hierarchy of directories, that is (for macro
> 'foo::bar::geez'):
>
> + lib/puppet/parser/macros/
> + foo/
> + bar/
> + geez.rb
>
> * they're a little bit easier to implement than functions, because
> arity checking is provided out of the box
>
> In some cases these macros may be more handy than 'params' classes when
> defining defaults for parameters. For example defaults for defined types
> which vary from instance to instance, or values which are hard to be
> computed in puppet DSL may be easily handled with macros.
>
I have been working on a new API for functions that I hope we will be
able to finish for Puppet 4.0. I have just started and have looked at
the work dalen and zaphod42 did earlier.
The need for a new API is because the 3x API requires values to be
presented to functions in a particular way (empty strings instead of
undef is one of those). If we want to fix that we do need to have a new
API. I will come back later and present ideas in more detail (I am not
quite done with exploration yet).
Requirements as I see them:
* Must be redefinable in different environments / be reloadable
* Support fully qualified names
* Support arity (fixed and variable)
* Support default arguments
* Support the new type system with automatic type checking
* Support overloading of one function (i.e. multiple signatures)
* Be easy to write for simple functions
* Easy to test
* Callable direct from Ruby
* Protected from exposure from "too much non API" to reduce future
migration issues
So far, I am leaning against a design that:
* Uses regular ruby methods with regular parameter declaration (easier
for users - no need to parse the array args are internally passed).
* One function per ruby file (easier to autoload)
* A call to a newfunction "factory" method that creates the function
class/module internally - thus enabling using anonymous modules
(more or less required to be able to reload/redefine).
* Creation call looks horrible if all the desired features are
to be passed using a hash of options - hence, for more advanced
options, additional methods are implemented.
* Move Functions out of the Puppet::Parser namespace - they are not part
of the parser!
As an example - here is a simple function from 3x
Puppet::Parser::Functions::newfunction(:sha1, :type => :rvalue,
:arity => 1,
:doc => "Returns a SHA1 hash value from a provided string.") do
|args|
Digest::SHA1.hexdigest(args[0])
end
Rewritten it would be:
Puppet::Functions.create_function(:sha1) do
# Returns a SHA1 hash value from a provided string.
def sha1(str)
Digest::SHA1.hexdigest(str)
end
end
If we want to do more - handle multiple signatures, get automatic type
checking etc. Additional calls that defines those are required.
This part is what I am working on now - something along the lines of:
dispatch(:sha1, 'String[1]') # one arg == non empty string
(I am leaving out lots of detail here because ideas are half baked)
I want to be able to:
* Support simple calls
* Calls to different methods depending on signature
* Support Polymorphic dispatch (based on type of first arg) just
like the future parser/evaluator does.
I am also contemplating if we want to tie function more closely to
the type of the first argument to allow addition of functions with the
same name that operates on a different type - don't know how valuable
that would be in the Puppet Language though.
Hope to have a more complete proposal in a couple of weeks time.
Regards
- henrik