Well, yes, in a sense you are looking at it the wrong way. Regardless of your reasons for wanting to use an approach that relies on dynamically building hashes and arrays, no such approach can work altogether smoothly in Puppet. It's like the guy who went to the doctor, complaining that his head hurt whenever he hit it with a hammer.
Puppet has good reasons for immutable variables. If you want mutable ones, then your only alternative is to move your computation out of DSL. The easiest avenues for that are templates and custom functions. Of the two, I would think the latter is preferable for your case, at least if the constructed composite data objects must persist beyond the evaluation of one template. On the other hand, if you only need them once, for creating one config file, say, then you can do that in a code block at the top of your template, and then use the result later.
There are other alternatives, too, most of them probably worse. For example, you could use a chain of defined types or classes to build up your data objects in functional programming style. Or you could use a template to build a string representation of your composite object, and then split() it into an array, and, if appropriate, convert it into a hash from there. No doubt there are others. PuppetLabs's add-in "stdlib" module has some functions that could be applied to such tasks.
Another option is to go in an altogether different direction. Require the data to be fed to your class in a form that is easy for it to digest, and have your templates use it as the class receives it.
In between, you have the option to make your DSL code a lot cleaner and easier at the expense of making your template a little messier. For example:
myclass.pp
----
class mymodule::myclass($param1 = 'NOT SET', $param2 = 'NOT SET', $param3 = 'NOT SET') {
$params = {
'param1' => $param1,
'param2' => $param2,
'param3' => $param3,
}
template('mytemplate.erb')
}
mytemplate.erb:
----
<%
@params.each do |key, value|
next if value == 'NOT SET'
%><%= key %> = <%= value %> <%
end
%>
That is, build the data object unconditionally, in such a way that it can be easily filtered when it is processed.
John