Search code examples
rubychef-infraerubis

Chef erubis template: Format output based on value's classes


In my Chef cookbook (for mailman), I want use an attribute that is a hash and contains all the configuration options I want to write into a template (similar to how it's done in the chef-client cookbook).

So I want to have in my attributes:

default[:myapp][:config] = {
  "I_AM_A_STRING" => "fooo",
  "I_AM_AN_INT" => 123,
  "I_AM_AN_ARRAY" => ["abc", "cde"]
}

As output, I want the following (mailman compatible):

I_AM_A_STRING = 'fooo'
I_AM_AN_INT = 123
I_AM_AN_ARRAY = ['abc', 'cde']

However, it does not work.

To debug the problem, I have the following code in my erubis template:

<% node[:myapp][:config].each_pair do |key, value| -%>
  <% case value.class %>
  <% when Chef::Node::ImmutableArray %>
# <%= key %> is type <%= value.class %>, used when Chef::Node::ImmutableArray
<%= key %> = ['<%= value.join("','") %>']
  <% when Fixnum %>
# <%= key %> is type <%= value.class %>, used when Fixnum
<%= key %> = <%= value %> #fixnum
  <% when String %>
# <%= key %> is type <%= value.class %>, used when String
<%= key %> = '<%= value %>' #string
  <% else %>
# <%= key %> is type <%= value.class %>, used else
<%= key %> = '<%= value %>'
  <% end -%>
<% end -%>

So I want to use the case .. when to distinguish between value.class. However, none of the when conditions matches. So the output is:

# I_AM_A_STRING is type String, used else
I_AM_A_STRING = 'fooo'
# I_AM_AN_INT is type Fixnum, used else
I_AM_AN_INT = '123'
# I_AM_AN_ARRAY is type Chef::Node::ImmutableArray, used else
I_AM_AN_ARRAY = '["abc", "cde"]'

When I try when Whatever.class, the first when matches for all types.

What am I doing wrong?


Solution

  • Looks like you mean

       <% case value %>
    

    instead of

      <% case value.class %>
    

    That's how case..when works in ruby. It's often the case you need to switch based on value (or even a range of values ), and also on type.

    It let's you do things like this in ruby (and hence also in erubis/eruby):

    def f(x)
      case x
        when String then "#{x} is a String"
        when 42 then "It's #{x==42}, x is 42"
        when 21..27 then "#{x} is in 21..27"
        when Fixnum then "#{x} is numeric, that's all I know"
        else "Can't say."
      end
    end
    
    f(1)        # "1 is numeric, that's all I know" 
    f(25)       # "25 is in 21..27"  
    f("hello")  # "hello is a String"
    f(false)    # "Can't say."