Module: Aws::Templates::Utils
- Includes:
- Exception
- Defined in:
- lib/aws/templates/utils.rb,
lib/aws/templates/utils/default.rb,
lib/aws/templates/utils/guarded.rb,
lib/aws/templates/utils/options.rb,
lib/aws/templates/utils/as_named.rb,
lib/aws/templates/utils/autoload.rb,
lib/aws/templates/utils/memoized.rb,
lib/aws/templates/utils/dependent.rb,
lib/aws/templates/utils/recursive.rb,
lib/aws/templates/utils/dependency.rb,
lib/aws/templates/utils/late_bound.rb,
lib/aws/templates/utils/inheritable.rb,
lib/aws/templates/utils/inspectable.rb,
lib/aws/templates/utils/parametrized.rb,
lib/aws/templates/utils/contextualized.rb,
lib/aws/templates/utils/artifact_storage.rb,
lib/aws/templates/utils/parametrized/getter.rb,
lib/aws/templates/utils/parametrized/nested.rb,
lib/aws/templates/utils/contextualized/filter.rb,
lib/aws/templates/utils/dependency/refinements.rb,
lib/aws/templates/utils/parametrized/constraint.rb,
lib/aws/templates/utils/parametrized/getter/dsl.rb,
lib/aws/templates/utils/parametrized/getter/path.rb,
lib/aws/templates/utils/contextualized/filter/add.rb,
lib/aws/templates/utils/contextualized/filter/dsl.rb,
lib/aws/templates/utils/parametrized/getter/as_is.rb,
lib/aws/templates/utils/parametrized/getter/value.rb,
lib/aws/templates/utils/contextualized/filter/copy.rb,
lib/aws/templates/utils/contextualized/refinements.rb,
lib/aws/templates/utils/parametrized/getter/one_of.rb,
lib/aws/templates/utils/contextualized/filter/chain.rb,
lib/aws/templates/utils/contextualized/filter/proxy.rb,
lib/aws/templates/utils/parametrized/constraint/dsl.rb,
lib/aws/templates/utils/parametrized/transformation.rb,
lib/aws/templates/utils/contextualized/filter/remove.rb,
lib/aws/templates/utils/contextualized/filter/scoped.rb,
lib/aws/templates/utils/parametrized/constraint/enum.rb,
lib/aws/templates/utils/contextualized/filter/identity.rb,
lib/aws/templates/utils/contextualized/filter/override.rb,
lib/aws/templates/utils/parametrized/constraint/all_of.rb,
lib/aws/templates/utils/parametrized/constraint/matches.rb,
lib/aws/templates/utils/parametrized/constraint/not_nil.rb,
lib/aws/templates/utils/parametrized/transformation/dsl.rb,
lib/aws/templates/utils/parametrized/constraint/requires.rb,
lib/aws/templates/utils/parametrized/constraint/condition.rb,
lib/aws/templates/utils/parametrized/transformation/as_hash.rb,
lib/aws/templates/utils/parametrized/transformation/as_list.rb,
lib/aws/templates/utils/parametrized/transformation/as_chain.rb,
lib/aws/templates/utils/parametrized/transformation/as_module.rb,
lib/aws/templates/utils/parametrized/transformation/as_object.rb,
lib/aws/templates/utils/parametrized/transformation/as_string.rb,
lib/aws/templates/utils/parametrized/transformation/as_boolean.rb,
lib/aws/templates/utils/parametrized/transformation/as_integer.rb,
lib/aws/templates/utils/parametrized/transformation/as_rendered.rb,
lib/aws/templates/utils/parametrized/constraint/depends_on_value.rb,
lib/aws/templates/utils/parametrized/getter/as_instance_variable.rb,
lib/aws/templates/utils/parametrized/constraint/satisfies_condition.rb,
lib/aws/templates/utils/contextualized/filter/recursive_schema_filter.rb
Overview
Variable utility functions used through the code.
Defines auxiliary functions set and serves as the namespace for the framework modules.
Defined Under Namespace
Modules: AsNamed, Autoload, Contextualized, Default, Dependent, Guarded, Inheritable, Inspectable, LateBound, Memoized, Parametrized, Recursive Classes: ArtifactStorage, Dependency, Lazy, Options
Constant Summary collapse
- RECURSIVE_METHODS =
%i[keys [] include?].freeze
- PARAMETRIZED_METHODS =
[:parameter_names].freeze
- DELETED_MARKER =
Deletion marker
Since Options use lazy merging (effectively keeping all hashes passed during initialization immutable) and iterates through all of them during value look-up, we need a way of marking some branch as deleted when deletion operation is invoked on an Options object. So, the algorithm marks branch with the object to stop iteration during look-up.
Object.new
- PATH_REGEXP =
Regexp.compile('::|[.]|/')
Class Method Summary collapse
- ._lookup_recursively(value, path) ⇒ Object
- ._merge_back(result, b) ⇒ Object
- ._merge_forward(a, b, blk) ⇒ Object
-
.deep_dup(original) ⇒ Object
Duplicate hash recursively.
-
.hashable?(obj) ⇒ Boolean
If object is hashable.
- .hashify(v) ⇒ Object
-
.list?(obj) ⇒ Boolean
If object is a list.
-
.lookup(value, path) ⇒ Object
Get a parameter from resulting hash or any nested part of it.
- .lookup_module(str) ⇒ Object
-
.merge(a, b, &blk) ⇒ Object
Merges two nested hashes.
-
.parametrized?(obj) ⇒ Boolean
If the object is “parametrized”.
-
.recursive?(obj) ⇒ Boolean
If the object is “recursive”.
-
.scalar?(obj) ⇒ Boolean
If the object is “scalar”.
-
.select_recursively(container, &blk) ⇒ Object
Select object recursively.
-
.set_recursively(container, value, path) ⇒ Object
Sets a value in hierarchy.
Class Method Details
._lookup_recursively(value, path) ⇒ Object
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/aws/templates/utils.rb', line 181 def self._lookup_recursively(value, path) current_key = path.shift # is there a value defined for the key in the current recursive structure? if value.include?(current_key) # yes - look-up the rest of the path return_value = lookup(value[current_key], path) # if value was still not found - resorting to wildcard path return_value.nil? ? lookup(value[:*], path) : return_value elsif value.include?(:*) # if there is no key but the recursive has a default value defined - dive into the # wildcard branch lookup(value[:*], path) end end |
._merge_back(result, b) ⇒ Object
119 120 121 122 123 |
# File 'lib/aws/templates/utils.rb', line 119 def self._merge_back(result, b) b.keys .reject { |k| result.include?(k) } .each_with_object(result) { |k, res| res[k] = hashify(b[k]) } end |
._merge_forward(a, b, blk) ⇒ Object
113 114 115 116 117 |
# File 'lib/aws/templates/utils.rb', line 113 def self._merge_forward(a, b, blk) a.keys.each_with_object({}) do |k, hsh| hsh[k] = b[k].nil? ? hashify(a[k]) : merge(a[k], b[k], &blk) end end |
.deep_dup(original) ⇒ Object
Duplicate hash recursively
Duplicate the hash and all nested hashes recursively
73 74 75 76 77 78 79 80 |
# File 'lib/aws/templates/utils.rb', line 73 def self.deep_dup(original) return original unless Utils.hashable?(original) duplicate = original.dup.to_hash duplicate.each_pair { |k, v| duplicate[k] = deep_dup(v) } duplicate end |
.hashable?(obj) ⇒ Boolean
If object is hashable
Checks if object can be transformed into Hash
46 47 48 |
# File 'lib/aws/templates/utils.rb', line 46 def self.hashable?(obj) obj.respond_to?(:to_hash) end |
.hashify(v) ⇒ Object
125 126 127 128 |
# File 'lib/aws/templates/utils.rb', line 125 def self.hashify(v) return v unless Utils.recursive?(v) v.keys.each_with_object({}) { |k, hsh| hsh[k] = hashify(v[k]) } end |
.list?(obj) ⇒ Boolean
If object is a list
Checks if object can be transformed into Array
65 66 67 |
# File 'lib/aws/templates/utils.rb', line 65 def self.list?(obj) obj.respond_to?(:to_ary) end |
.lookup(value, path) ⇒ Object
Get a parameter from resulting hash or any nested part of it
The method can access resulting hash as a tree performing traverse as needed. Also, it handles nil-pointer situations correctly so you will get no exception but just ‘nil’ even when the whole branch you’re trying to access don’t exist or contains non-hash value somewhere in the middle. Also, the method recognizes asterisk (*) hash records which is an analog of match-all or default values for some sub-branch.
-
path
- an array representing path of the value in the nestedhash
Example
opts = Options.new(
'a' => {
'b' => 'c',
'*' => { '*' => 2 }
},
'd' => 1
)
opts.to_hash # => { 'a' => { 'b' => 'c', '*' => { '*' => 2 } }, 'd' => 1 }
opts['a'] # => Options.new('b' => 'c', '*' => { '*' => 2 })
opts['a', 'b'] # => 'c'
opts['d', 'e'] # => nil
# multi-level wildcard match
opts['a', 'z', 'r'] # => 2
168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/aws/templates/utils.rb', line 168 def self.lookup(value, path) # we stop lookup and return nil if nil is encountered return if value.nil? # value was deleted in this layer raise Exception::OptionValueDeleted.new(path) if value == DELETED_MARKER # we reached our target! returning it return value if path.nil? || path.empty? # we still have some part of path to traverse but scalar was found raise Exception::OptionScalarOnTheWay.new(value, path) if Utils.scalar?(value) _lookup_recursively(value, path.dup) end |
.lookup_module(str) ⇒ Object
240 241 242 243 244 245 246 247 248 |
# File 'lib/aws/templates/utils.rb', line 240 def self.lookup_module(str) target = str.split(PATH_REGEXP) .inject(::Object.lazy) { |acc, elem| acc.const_get(elem.modulize) } .reduce raise "#{str} == #{target} which is not a module" unless target.is_a?(Module) target end |
.merge(a, b, &blk) ⇒ Object
Merges two nested hashes
The core element of the whole framework. The principle is simple: both arguments are transformed to hashes if they support :to_hash method, the resulting hashes are merged with the standard method with creating a new hash. Second element takes preference if the function reached bottom level of recursion with only scalars left.
Raises ArgumentError if a and b have incompatible types hence they can’t be merged
Example
Options.merge('a', 'b') # => 'b'
Options.merge({'1'=>'2'}, {'3'=>'4'}) # => {'1'=>'2', '3'=>'4'}
Options.merge(
{ '1' => { '2' => '3' } },
{ '1' => { '4' => '5' } }
) # => { '1' => { '2' => '3', '4'=>'5' } }
Recursively merge two “recursive” objects PS: Yes I know that there is “merge” method for hashes.
105 106 107 108 109 110 111 |
# File 'lib/aws/templates/utils.rb', line 105 def self.merge(a, b, &blk) unless Utils.recursive?(a) && Utils.recursive?(b) return hashify(blk.nil? ? b : blk.call(a, b)) end _merge_back(_merge_forward(a, b, blk), b) end |
.parametrized?(obj) ⇒ Boolean
If the object is “parametrized”
Checks if object satisfies “parametrized” concept. See PARAMETRIZED_METHODS for the list of methods
57 58 59 |
# File 'lib/aws/templates/utils.rb', line 57 def self.parametrized?(obj) PARAMETRIZED_METHODS.all? { |m| obj.respond_to?(m) } end |
.recursive?(obj) ⇒ Boolean
If the object is “recursive”
Checks if object satisfies “recursive” concept. See RECURSIVE_METHODS for the list of methods
30 31 32 |
# File 'lib/aws/templates/utils.rb', line 30 def self.recursive?(obj) RECURSIVE_METHODS.all? { |m| obj.respond_to?(m) } end |
.scalar?(obj) ⇒ Boolean
If the object is “scalar”
Checks if object satisfies “scalar” concept.
38 39 40 |
# File 'lib/aws/templates/utils.rb', line 38 def self.scalar?(obj) !obj.respond_to?(:[]) end |
.select_recursively(container, &blk) ⇒ Object
Select object recursively
Selects objects recursively from the specified container with specified block predicate.
-
container
- container to recursively select items from -
blk
- the predicate
227 228 229 230 231 232 233 234 235 236 |
# File 'lib/aws/templates/utils.rb', line 227 def self.select_recursively(container, &blk) container.keys.each_with_object([]) do |k, collection| value = container[k] if blk.call(value) collection << value elsif Utils.recursive?(value) collection.concat(select_recursively(value, &blk)) end end end |
.set_recursively(container, value, path) ⇒ Object
Sets a value in hierarchy
Sets a path in a nested recursive hash structure to the specified value
-
container
- container with the specified path -
value
- the value to set the path to -
path
- path containing the target value
205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/aws/templates/utils.rb', line 205 def self.set_recursively(container, value, path) last_key = path.pop last_branch = path.inject(container) do |obj, current_key| raise Exception::OptionScalarOnTheWay.new(obj, path) unless Utils.recursive?(obj) if obj.include?(current_key) obj[current_key] else obj[current_key] = {} end end last_branch[last_key] = value end |