Puppet Function: consul::sorted_json

Defined in:
lib/puppet/functions/consul/sorted_json.rb
Function type:
Ruby 4.x API

Overview

consul::sorted_json(Optional[Any] $unsorted_hash = {}, Optional[Any] $pretty = false, Optional[Any] $indent_len = 4)Any

Parameters:

  • unsorted_hash (Optional[Any]) (defaults to: {})
  • pretty (Optional[Any]) (defaults to: false)
  • indent_len (Optional[Any]) (defaults to: 4)

Returns:

  • (Any)


3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/puppet/functions/consul/sorted_json.rb', line 3

Puppet::Functions.create_function(:'consul::sorted_json') do
  # This function takes unsorted hash and outputs JSON object making sure the keys are sorted.
  # Optionally you can pass 2 additional parameters, pretty generate and indent length.
  #
  # *Examples:*
  #
  #     -------------------
  #     -- UNSORTED HASH --
  #     -------------------
  #     unsorted_hash = {
  #       'client_addr' => '127.0.0.1',
  #       'bind_addr'   => '192.168.34.56',
  #       'start_join'  => [
  #         '192.168.34.60',
  #         '192.168.34.61',
  #         '192.168.34.62',
  #       ],
  #       'ports'       => {
  #         'rpc'   => 8567,
  #         'https' => 8500,
  #         'http'  => -1,
  #       },
  #     }
  #
  #     -----------------
  #     -- SORTED JSON --
  #     -----------------
  #
  #     consul::sorted_json(unsorted_hash)
  #
  #     {"bind_addr":"192.168.34.56","client_addr":"127.0.0.1",
  #     "ports":{"http":-1,"https":8500,"rpc":8567},
  #     "start_join":["192.168.34.60","192.168.34.61","192.168.34.62"]}
  #
  #     ------------------------
  #     -- PRETTY SORTED JSON --
  #     ------------------------
  #     Params: data <hash>, pretty <true|false>, indent <int>.
  #
  #     consul::sorted_json(unsorted_hash, true, 4)
  #
  #     {
  #         "bind_addr": "192.168.34.56",
  #         "client_addr": "127.0.0.1",
  #         "ports": {
  #             "http": -1,
  #             "https": 8500,
  #             "rpc": 8567
  #         },
  #         "start_join": [
  #             "192.168.34.60",
  #             "192.168.34.61",
  #             "192.168.34.62"
  #         ]
  #     }
  #
  def sorted_json(unsorted_hash = {}, pretty = false, indent_len = 4)
    # simplify jsonification of standard types
    simple_generate = lambda do |obj, quoted|
      case obj
      when NilClass, :undef
        'null'
      when Integer, Float, TrueClass, FalseClass
        quoted ? obj.to_s.to_json : obj.to_json
      else
        # Should be a string
        # keep string integers unquoted
        obj =~ %r{\A-?(0|[1-9]\d*)\z} && !quoted ? obj : obj.to_json
      end
    end

    sorted_generate = lambda do |obj, quoted|
      case obj
      when NilClass, :undef, Integer, Float, TrueClass, FalseClass, String
        return simple_generate.call(obj, quoted)
      when Array
        array_ret = []
        obj.each do |a|
          array_ret.push(sorted_generate.call(a, quoted))
        end
        return '[' << array_ret.join(',') << ']'
      when Hash
        ret = []
        obj.keys.sort.each do |k|
          # Stringify all children of node_meta, meta, and tags
          quote_children = k =~ %r{\A(node_meta|meta|tags|args)\z} || quoted ? true : false
          ret.push(k.to_json << ':' << sorted_generate.call(obj[k], quote_children))
        end
        return '{' << ret.join(',') << '}'
      else
        raise Exception, "Unable to handle object of type #{obj.class.name} with value #{obj.inspect}"
      end
    end

    sorted_pretty_generate = lambda do |obj, sorted_pretty_indent_len = 4, level = 0, quoted|
      # Indent length
      indent = ' ' * sorted_pretty_indent_len

      case obj
      when NilClass, :undef, Integer, Float, TrueClass, FalseClass, String
        return simple_generate.call(obj, quoted)
      when Array
        array_ret = []

        # We need to increase the level count before #each so the objects inside are indented twice.
        # When we come out of #each we decrease the level count so the closing brace lines up properly.
        #
        # If you start with level = 1, the count will be as follows
        #
        # "start_join": [     <-- level == 1
        #   "192.168.50.20",  <-- level == 2
        #   "192.168.50.21",  <-- level == 2
        #   "192.168.50.22"   <-- level == 2
        # ] <-- closing brace <-- level == 1
        #
        level += 1
        obj.each do |a|
          array_ret.push(sorted_pretty_generate.call(a, sorted_pretty_indent_len, level, quoted))
        end
        level -= 1

        return "[\n#{indent * (level + 1)}" << array_ret.join(",\n#{indent * (level + 1)}") << "\n#{indent * level}]"

      when Hash
        ret = []

        # This level works in a similar way to the above
        level += 1
        obj.keys.sort.each do |k|
          # Stringify all children of node_meta, meta, and tags
          quote_children = k =~ %r{\A(node_meta|meta|tags|args)\z} || quoted ? true : false
          ret.push((indent * level).to_s << k.to_json << ': ' << sorted_pretty_generate.call(obj[k], sorted_pretty_indent_len, level, quote_children))
        end
        level -= 1

        return "{\n" << ret.join(",\n") << "\n#{indent * level}}"
      else
        raise Exception, "Unable to handle object of type #{obj.class.name} with value #{obj.inspect}"
      end
    end

    if pretty
      sorted_pretty_generate.call(unsorted_hash, indent_len, false) << "\n"
    else
      sorted_generate.call(unsorted_hash, false)
    end
  end
end