Class: LeapCli::Config::Object
- Includes:
- Macros
- Defined in:
- lib/leap_cli/config/object.rb
Overview
This class represents the configuration for a single node, service, or tag. Also, all the nested hashes are also of this type.
It is called ‘object’ because it corresponds to an Object in JSON.
Instance Attribute Summary collapse
-
#manager ⇒ Object
(also: #global)
readonly
Returns the value of attribute manager.
-
#node ⇒ Object
readonly
Returns the value of attribute node.
Instance Method Summary collapse
-
#[](key) ⇒ Object
FETCHING VALUES.
-
#deep_merge!(object, prefer_self = false) ⇒ Object
A deep (recursive) merge with another Config::Object.
-
#default ⇒ Object
override behavior of #default() from Hash.
-
#dump_json ⇒ Object
export JSON.
-
#dump_yaml ⇒ Object
export YAML.
- #evaluate(context = @node) ⇒ Object
- #get(key) ⇒ Object
-
#get!(key) ⇒ Object
Like a normal Hash#[], except:.
-
#inherit_from!(object) ⇒ Object
like a reverse deep merge (self takes precedence).
-
#initialize(manager = nil, node = nil) ⇒ Object
constructor
A new instance of Object.
-
#method_missing(method, *args, &block) ⇒ Object
make hash addressable like an object (e.g. obj available as obj.name).
-
#pick(*keys) ⇒ Object
Make a copy of ourselves, except only including the specified keys.
Methods included from Macros
#assert, #authorized_keys, #file, #file_path, #fingerprint, #haproxy_servers, #hex_secret, #hostnames, #hosts_file, #nodes, #nodes_like_me, #provider, #secret, #stunnel_client, #stunnel_port, #stunnel_server, #try_file
Methods inherited from Hash
Constructor Details
#initialize(manager = nil, node = nil) ⇒ Object
Returns a new instance of Object.
27 28 29 30 31 32 33 34 |
# File 'lib/leap_cli/config/object.rb', line 27 def initialize(manager=nil, node=nil) # keep a global pointer around to the config manager. used a lot in the eval strings and templates # (which are evaluated in the context of Config::Object) @manager = manager # an object that is a node as @node equal to self, otherwise all the child objects point back to the top level node. @node = node || self end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
Instance Attribute Details
#manager ⇒ Object (readonly) Also known as: global
Returns the value of attribute manager.
24 25 26 |
# File 'lib/leap_cli/config/object.rb', line 24 def manager @manager end |
#node ⇒ Object (readonly)
Returns the value of attribute node.
23 24 25 |
# File 'lib/leap_cli/config/object.rb', line 23 def node @node end |
Instance Method Details
#[](key) ⇒ Object
FETCHING VALUES
65 66 67 |
# File 'lib/leap_cli/config/object.rb', line 65 def [](key) get(key) end |
#deep_merge!(object, prefer_self = false) ⇒ Object
A deep (recursive) merge with another Config::Object.
If prefer_self is set to true, the value from self will be picked when there is a conflict that cannot be merged.
Merging rules:
-
If a value is a hash, we recursively merge it.
-
If the value is simple, like a string, the new one overwrites the value.
-
If the value is an array:
-
If both old and new values are arrays, the new one replaces the old.
-
If one of the values is simple but the other is an array, the simple is added to the array.
-
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/leap_cli/config/object.rb', line 133 def deep_merge!(object, prefer_self=false) object.each do |key,new_value| old_value = self.fetch key, nil # clean up boolean new_value = true if new_value == "true" new_value = false if new_value == "false" old_value = true if old_value == "true" old_value = false if old_value == "false" # merge hashes if old_value.is_a?(Hash) || new_value.is_a?(Hash) value = Config::Object.new(@manager, @node) old_value.is_a?(Hash) ? value.deep_merge!(old_value) : (value[key] = old_value if !old_value.nil?) new_value.is_a?(Hash) ? value.deep_merge!(new_value, prefer_self) : (value[key] = new_value if !new_value.nil?) # merge nil elsif new_value.nil? value = old_value elsif old_value.nil? value = new_value # merge arrays when one value is not an array elsif old_value.is_a?(Array) && !new_value.is_a?(Array) (value = (old_value.dup << new_value).compact.uniq).delete('REQUIRED') elsif new_value.is_a?(Array) && !old_value.is_a?(Array) (value = (new_value.dup << old_value).compact.uniq).delete('REQUIRED') # catch errors elsif type_mismatch?(old_value, new_value) raise 'Type mismatch. Cannot merge %s (%s) with %s (%s). Key is "%s", name is "%s".' % [ old_value.inspect, old_value.class, new_value.inspect, new_value.class, key, self.class ] # merge strings, numbers, and sometimes arrays else if prefer_self value = old_value else value = new_value end end # save value self[key] = value end self end |
#default ⇒ Object
override behavior of #default() from Hash
85 86 87 |
# File 'lib/leap_cli/config/object.rb', line 85 def default get!('default') end |
#dump_json ⇒ Object
export JSON
51 52 53 54 |
# File 'lib/leap_cli/config/object.rb', line 51 def dump_json evaluate(@node) JSON.sorted_generate(self) end |
#dump_yaml ⇒ Object
export YAML
We use pure ruby yaml exporter ya2yaml instead of SYCK or PSYCH because it allows us greater compatibility regardless of installed ruby version and greater control over how the yaml is exported (sorted keys, in particular).
43 44 45 46 |
# File 'lib/leap_cli/config/object.rb', line 43 def dump_yaml evaluate(@node) ya2yaml(:syck_compatible => true) end |
#evaluate(context = @node) ⇒ Object
56 57 58 59 |
# File 'lib/leap_cli/config/object.rb', line 56 def evaluate(context=@node) evaluate_everything(context) late_evaluate_everything(context) end |
#get(key) ⇒ Object
76 77 78 79 80 81 82 |
# File 'lib/leap_cli/config/object.rb', line 76 def get(key) begin get!(key) rescue NoMethodError nil end end |
#get!(key) ⇒ Object
Like a normal Hash#[], except:
(1) lazily eval dynamic values when we encounter them. (i.e. strings that start with “= ”)
(2) support for nested references in a single string (e.g. [‘a.b’] is the same as [‘a’])
the dot path is always absolute, starting at the top-most object.
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/leap_cli/config/object.rb', line 97 def get!(key) key = key.to_s if key =~ /\./ # for keys with with '.' in them, we start from the root object (@node). keys = key.split('.') value = @node.get!(keys.first) if value.is_a? Config::Object value.get!(keys[1..-1].join('.')) else value end elsif self.has_key?(key) fetch_value(key) else raise NoMethodError.new(key, "No method '#{key}' for #{self.class}") end end |
#inherit_from!(object) ⇒ Object
like a reverse deep merge (self takes precedence)
188 189 190 |
# File 'lib/leap_cli/config/object.rb', line 188 def inherit_from!(object) self.deep_merge!(object, true) end |
#pick(*keys) ⇒ Object
Make a copy of ourselves, except only including the specified keys.
Also, the result is flattened to a single hash, so a key of ‘a.b’ becomes ‘a_b’
197 198 199 200 201 202 203 204 205 |
# File 'lib/leap_cli/config/object.rb', line 197 def pick(*keys) keys.map(&:to_s).inject(self.class.new(@manager)) do |hsh, key| value = self.get(key) if !value.nil? hsh[key.gsub('.','_')] = value end hsh end end |