Class: SimplyGenius::Atmos::SettingsHash
- Inherits:
-
Hashie::Mash
- Object
- Hashie::Mash
- SimplyGenius::Atmos::SettingsHash
- Includes:
- GemLogger::LoggerSupport, Hashie::Extensions::DeepFetch, Hashie::Extensions::DeepMerge, Exceptions
- Defined in:
- lib/simplygenius/atmos/settings_hash.rb
Constant Summary collapse
- PATH_PATTERN =
/[\.\[\]]/
- INTERP_PATTERN =
/(\#?\#\{([^\}]+)\})/
Instance Attribute Summary collapse
-
#_root_ ⇒ Object
Returns the value of attribute root.
-
#enable_expansion ⇒ Object
Returns the value of attribute enable_expansion.
-
#error_resolver ⇒ Object
Returns the value of attribute error_resolver.
Class Method Summary collapse
Instance Method Summary collapse
-
#each ⇒ Object
allows expansion when iterating.
- #expand(value) ⇒ Object
- #expand_results(name, &blk) ⇒ Object
- #expand_string(obj) ⇒ Object
- #expanding_reader(key) ⇒ Object (also: #[])
- #fetch(key, *args) ⇒ Object
- #format_error(msg, expr, ex = nil) ⇒ Object
- #notation_get(key) ⇒ Object
- #notation_put(key, value, additive: true) ⇒ Object
-
#to_a ⇒ Object
allows expansion for to_a (which doesn’t use each).
Instance Attribute Details
#_root_ ⇒ Object
Returns the value of attribute root.
17 18 19 |
# File 'lib/simplygenius/atmos/settings_hash.rb', line 17 def _root_ @_root_ end |
#enable_expansion ⇒ Object
Returns the value of attribute enable_expansion.
17 18 19 |
# File 'lib/simplygenius/atmos/settings_hash.rb', line 17 def enable_expansion @enable_expansion end |
#error_resolver ⇒ Object
Returns the value of attribute error_resolver.
17 18 19 |
# File 'lib/simplygenius/atmos/settings_hash.rb', line 17 def error_resolver @error_resolver end |
Class Method Details
.add_config(yml_file, key, value, additive: true) ⇒ Object
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/simplygenius/atmos/settings_hash.rb', line 169 def self.add_config(yml_file, key, value, additive: true) orig_config_with_comments = File.read(yml_file) comment_places = {} comment_lines = [] orig_config_with_comments.each_line do |line| line.gsub!(/\s+$/, "\n") if line =~ /^\s*(#.*)?$/ comment_lines << line else if comment_lines.present? comment_places[line.chomp] = comment_lines comment_lines = [] end end end comment_places["<EOF>"] = comment_lines orig_config = SettingsHash.new((YAML.load_file(yml_file) rescue {})) # expansion disabled by default, but being explicit since we don't want # expansion when mutating config files from generators orig_config.enable_expansion = false orig_config.notation_put(key, value, additive: additive) new_config_no_comments = YAML.dump(orig_config.to_hash) new_config_no_comments.sub!(/\A---\n/, "") new_yml = "" new_config_no_comments.each_line do |line| line.gsub!(/\s+$/, "\n") cline = comment_places.keys.find {|k| line =~ /^#{k}/ } comments = comment_places[cline] comments.each {|comment| new_yml << comment } if comments new_yml << line end comment_places["<EOF>"].each {|comment| new_yml << comment } return new_yml end |
Instance Method Details
#each ⇒ Object
allows expansion when iterating
58 59 60 61 62 |
# File 'lib/simplygenius/atmos/settings_hash.rb', line 58 def each each_key do |key| yield key, self[key] end end |
#expand(value) ⇒ Object
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/simplygenius/atmos/settings_hash.rb', line 111 def (value) result = value case value when Hash value when String (value) when Enumerable value.map! {|v| (v)} # HACK: accounting for the case when someone wants to force an override using '^' as the first list item, when # there is no upstream to override (i.e. merge proc doesn't get triggered as key is unique, so just added verbatim) value.delete_at(0) if value[0] == "^" value else value end end |
#expand_results(name, &blk) ⇒ Object
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/simplygenius/atmos/settings_hash.rb', line 21 def (name, &blk) # NOTE: we lookup locally first, then globally if a value is missing # locally. To force a global lookup, use the explicit qualifier like # "_root_.path.to.config" value = blk.call(name) if value.nil? && _root_ && enable_expansion value = _root_[name] end if value.kind_of?(self.class) && value._root_.nil? value._root_ = _root_ || self end enable_expansion ? (value) : value end |
#expand_string(obj) ⇒ Object
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 |
# File 'lib/simplygenius/atmos/settings_hash.rb', line 82 def (obj) result = obj result.scan(INTERP_PATTERN).each do |substr, statement| # TODO: add an explicit check for cycles instead of relying on Stack error begin if substr.start_with?('##') val = substr[1..-1] else # TODO: be consistent with dot notation between eval and # notation_get. eval ends up calling Hashie method_missing, # which returns nil if a key doesn't exist, causing a nil # exception for next item in chain, while notation_get returns # nil gracefully for the entire chain (preferred) val = eval(statement, binding, __FILE__) end rescue SystemStackError => e raise ConfigInterpolationError.new(format_error("Cycle in interpolated config", substr)) rescue StandardError => e raise ConfigInterpolationError.new(format_error("Failing config statement", substr, e)) end result = result.sub(substr, val.to_s) end result = true if result == "true" result = false if result == "false" result end |
#expanding_reader(key) ⇒ Object Also known as: []
39 40 41 |
# File 'lib/simplygenius/atmos/settings_hash.rb', line 39 def (key) (key) {|k| orig_reader(k) } end |
#fetch(key, *args) ⇒ Object
43 44 45 |
# File 'lib/simplygenius/atmos/settings_hash.rb', line 43 def fetch(key, *args) (key) {|k| super(k, *args) } end |
#format_error(msg, expr, ex = nil) ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/simplygenius/atmos/settings_hash.rb', line 69 def format_error(msg, expr, ex=nil) file, line = nil, nil if error_resolver file, line = error_resolver.call(expr) end file_msg = file.nil? ? "" : " in #{File.basename(file)}:#{line}" msg = "#{msg} '#{expr}'#{file_msg}" if ex msg += " => #{ex.class} #{ex.}" end return msg end |
#notation_get(key) ⇒ Object
129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/simplygenius/atmos/settings_hash.rb', line 129 def notation_get(key) path = key.to_s.split(PATH_PATTERN).compact path = path.collect {|p| p =~ /^\d+$/ ? p.to_i : p } result = nil begin result = deep_fetch(*path) rescue Hashie::Extensions::DeepFetch::UndefinedPathError => e logger.debug("Settings missing value for key='#{key}'") end return result end |
#notation_put(key, value, additive: true) ⇒ Object
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 |
# File 'lib/simplygenius/atmos/settings_hash.rb', line 143 def notation_put(key, value, additive: true) path = key.to_s.split(PATH_PATTERN).compact path = path.collect {|p| p =~ /^\d+$/ ? p.to_i : p } current_level = self path.each_with_index do |p, i| if i == path.size - 1 if additive && current_level[p].is_a?(Array) current_level[p] = current_level[p] | Array(value) else current_level[p] = value end else if current_level[p].nil? if path[i+1].is_a?(Integer) current_level[p] = [] else current_level[p] = {} end end end current_level = current_level[p] end end |
#to_a ⇒ Object
allows expansion for to_a (which doesn’t use each)
65 66 67 |
# File 'lib/simplygenius/atmos/settings_hash.rb', line 65 def to_a self.collect {|k, v| [k, v]} end |