Class: Chamber::Settings

Inherits:
Object
  • Object
show all
Defined in:
lib/chamber/settings.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(decryption_keys: {}, encryption_keys: {}, namespaces: [], pre_filters: [ Filters::NamespaceFilter, ], post_filters: [ Filters::DecryptionFilter, Filters::EnvironmentFilter, Filters::FailedDecryptionFilter, Filters::TranslateSecureKeysFilter, ], secure_key_prefix: '_secure_', settings: {}, **_args) ⇒ Settings

rubocop:disable Metrics/ParameterLists



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
# File 'lib/chamber/settings.rb', line 34

def initialize(
                decryption_keys:   {},
                encryption_keys:   {},
                namespaces:        [],
                pre_filters:       [
                                     Filters::NamespaceFilter,
                                   ],
                post_filters:      [
                                     Filters::DecryptionFilter,
                                     Filters::EnvironmentFilter,
                                     Filters::FailedDecryptionFilter,
                                     Filters::TranslateSecureKeysFilter,
                                   ],
                secure_key_prefix: '_secure_',
                settings:          {},
                **_args
              )

  ::Chamber::Refinements::Enumerable.deep_validate_keys(settings, &:to_s)

  self.decryption_keys   = (decryption_keys || {}).transform_keys(&:to_s)
  self.encryption_keys   = (encryption_keys || {}).transform_keys(&:to_s)
  self.namespaces        = NamespaceSet.new(namespaces)
  self.post_filters      = post_filters
  self.pre_filters       = pre_filters
  self.raw_data          = settings.deep_dup
  self.secure_key_prefix = secure_key_prefix
end

Instance Attribute Details

#decryption_keysObject

Returns the value of attribute decryption_keys.



26
27
28
# File 'lib/chamber/settings.rb', line 26

def decryption_keys
  @decryption_keys
end

#encryption_keysObject

Returns the value of attribute encryption_keys.



26
27
28
# File 'lib/chamber/settings.rb', line 26

def encryption_keys
  @encryption_keys
end

#namespacesObject

Returns the value of attribute namespaces.



31
32
33
# File 'lib/chamber/settings.rb', line 31

def namespaces
  @namespaces
end

#post_filtersObject

Returns the value of attribute post_filters.



26
27
28
# File 'lib/chamber/settings.rb', line 26

def post_filters
  @post_filters
end

#pre_filtersObject

Returns the value of attribute pre_filters.



26
27
28
# File 'lib/chamber/settings.rb', line 26

def pre_filters
  @pre_filters
end

#secure_key_prefixObject

Returns the value of attribute secure_key_prefix.



26
27
28
# File 'lib/chamber/settings.rb', line 26

def secure_key_prefix
  @secure_key_prefix
end

Instance Method Details

#==(other) ⇒ Object

Internal: Determines whether a Settings is equal to another hash-like object.

Returns a Boolean



225
226
227
# File 'lib/chamber/settings.rb', line 225

def ==(other)
  to_hash == other.to_hash
end

#[](key) ⇒ Object



240
241
242
243
244
245
246
247
248
# File 'lib/chamber/settings.rb', line 240

def [](key)
  fail ::Chamber::Errors::InvalidKeyType, 'Bracket access with anything other than a String is unsupported.' unless key.is_a?(::String)

  data.fetch(key)
rescue ::KeyError => error
  missing_setting_name = error.message.gsub(/.*key not found: "([^"]+)".*/, '\1')

  raise ::Chamber::Errors::MissingSetting.new(missing_setting_name, [])
end

#decryptedObject



289
290
291
292
293
294
# File 'lib/chamber/settings.rb', line 289

def decrypted
  Settings.new(**.merge(
                 settings:     raw_data,
                 post_filters: [Filters::DecryptionFilter],
               ))
end

#dig(*args) ⇒ Object



266
267
268
269
270
271
272
# File 'lib/chamber/settings.rb', line 266

def dig(*args)
  dig!(*args)
rescue ::Chamber::Errors::MissingSetting,
       ::Chamber::Errors::MissingIndex

  nil
end

#dig!(*args) ⇒ Object



250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/chamber/settings.rb', line 250

def dig!(*args)
  args.inject(data) do |data_value, bracket_value|
    key = bracket_value.is_a?(::Symbol) ? bracket_value.to_s : bracket_value

    data_value.fetch(key)
  end
rescue ::KeyError => error
  missing_setting_name = error.message.gsub(/.*key not found: "([^"]+)".*/, '\1')

  raise ::Chamber::Errors::MissingSetting.new(missing_setting_name, args)
rescue ::IndexError => error
  missing_index_number = error.message.gsub(/.*index (\d+) outside.*/, '\1')

  raise ::Chamber::Errors::MissingIndex.new(missing_index_number, args)
end

#encryptedObject



296
297
298
299
300
301
302
# File 'lib/chamber/settings.rb', line 296

def encrypted
  Settings.new(**.merge(
                 settings:     raw_data,
                 pre_filters:  [Filters::EncryptionFilter],
                 post_filters: [],
               ))
end

#eql?(other) ⇒ Boolean

Internal: Determines whether a Settings is equal to another Settings.

Returns a Boolean

Returns:

  • (Boolean)


234
235
236
237
238
# File 'lib/chamber/settings.rb', line 234

def eql?(other)
  other.is_a?(Chamber::Settings) &&
  data        == other.data &&
  namespaces  == other.namespaces
end

#insecureObject



304
305
306
307
308
309
310
# File 'lib/chamber/settings.rb', line 304

def insecure
  Settings.new(**.merge(
                 settings:     raw_data,
                 pre_filters:  [Filters::InsecureFilter],
                 post_filters: [Filters::TranslateSecureKeysFilter],
               ))
end

#merge(other) ⇒ Object

Internal: Merges a Settings object with another Settings object or a hash-like object.

Also, if merging Settings, it will merge all other Settings data as well.

Example:

settings        = Settings.new settings: { my_setting:        'my value' }
other_settings  = Settings.new settings: { my_other_setting:  'my other value' }

settings.merge other_settings

settings
# => {
  'my_setting'        => 'my value',
  'my_other_setting'  => 'my other value',
}

Returns a new Settings object



201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/chamber/settings.rb', line 201

def merge(other)
  other_settings = case other
                   when Settings
                     other
                   when Hash
                     Settings.new(settings: other)
                   end

  # rubocop:disable Layout/LineLength
  Settings.new(
    encryption_keys: encryption_keys.any? ? encryption_keys : other_settings.encryption_keys,
    decryption_keys: decryption_keys.any? ? decryption_keys : other_settings.decryption_keys,
    namespaces:      (namespaces + other_settings.namespaces),
    settings:        raw_data.deep_merge(other_settings.raw_data),
  )
  # rubocop:enable Layout/LineLength
end

#securableObject



274
275
276
277
278
279
# File 'lib/chamber/settings.rb', line 274

def securable
  Settings.new(**.merge(
                 settings:    raw_data,
                 pre_filters: [Filters::SecureFilter],
               ))
end

#secureObject



281
282
283
284
285
286
287
# File 'lib/chamber/settings.rb', line 281

def secure
  Settings.new(**.merge(
                 settings:     raw_data,
                 pre_filters:  [Filters::EncryptionFilter],
                 post_filters: [Filters::TranslateSecureKeysFilter],
               ))
end

#to_concatenated_name_hash(hierarchical_separator = '_') ⇒ Object



168
169
170
171
172
173
174
175
176
177
178
# File 'lib/chamber/settings.rb', line 168

def to_concatenated_name_hash(hierarchical_separator = '_')
  concatenated_name_hash = {}

  to_flattened_name_hash.each_pair do |flattened_name, value|
    concatenated_name = flattened_name.join(hierarchical_separator)

    concatenated_name_hash[concatenated_name] = value
  end

  concatenated_name_hash.sort
end

#to_environmentObject

Internal: Converts a Settings object into a hash that is compatible as an environment variable hash.

Example:

settings = Settings.new settings: {
                          my_setting:     'my value',
                          my_sub_setting: {
                            my_sub_sub_setting_1: 'my sub value 1',
                            my_sub_sub_setting_2: 'my sub value 2',
                          }
settings.to_environment
# => {
  'MY_SETTING'                          => 'my value',
  'MY_SUB_SETTING_MY_SUB_SUB_SETTING_1' => 'my sub value 1',
  'MY_SUB_SETTING_MY_SUB_SUB_SETTING_2' => 'my sub value 2',
}

Returns a Hash sorted alphabetically by the names of the keys



85
86
87
88
89
# File 'lib/chamber/settings.rb', line 85

def to_environment
  to_concatenated_name_hash('_').each_with_object({}) do |pair, env_hash|
    env_hash[pair[0].upcase] = pair[1].to_s
  end
end

#to_flattened_name_hash(hash = data, parent_keys = []) ⇒ Object

Internal: Returns a hash which contains the flattened name hierarchy of the setting as the keys and the values of each setting as the value.

Examples:

Settings.new(settings: {
               my_setting: 'value',
               there:      'was not that easy?',
               level_1:    {
                 level_2:    {
                   some_setting: 'hello',
                   another:      'goodbye',
                 },
                 body:       'gracias',
               },
             }).to_flattened_name_hash
# => {
  ['my_setting']                         => 'value',
  ['there']                              => 'was not that easy?',
  ['level_1', 'level_2', 'some_setting'] => 'hello',
  ['level_1', 'level_2', 'another']      => 'goodbye',
  ['level_1', 'body']                    => 'gracias',
}

Returns a Hash



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/chamber/settings.rb', line 151

def to_flattened_name_hash(hash = data, parent_keys = [])
  flattened_name_hash = {}

  hash.each_pair do |key, value|
    flattened_name_components = parent_keys.dup.push(key)

    if value.respond_to?(:each_pair)
      flattened_name_hash.merge! to_flattened_name_hash(value,
                                                        flattened_name_components)
    else
      flattened_name_hash[flattened_name_components] = value
    end
  end

  flattened_name_hash
end

#to_hashObject

Internal: Returns the Settings data as a Hash for easy manipulation. Changes made to the hash will not be reflected in the original Settings object.

Returns a Hash



121
122
123
# File 'lib/chamber/settings.rb', line 121

def to_hash
  data.deep_dup
end

#to_s(hierarchical_separator: '_', pair_separator: ' ', value_surrounder: '"', name_value_separator: '=') ⇒ Object

Internal: Converts a Settings object into a String with a format that will work well when working with the shell.

Examples:

Settings.new( settings: {
                my_key:       'my value',
                my_other_key: 'my other value',
              } ).to_s
# => 'MY_KEY="my value" MY_OTHER_KEY="my other value"'


103
104
105
106
107
108
109
110
111
112
# File 'lib/chamber/settings.rb', line 103

def to_s(hierarchical_separator: '_',
         pair_separator:         ' ',
         value_surrounder:       '"',
         name_value_separator:   '=')
  pairs = to_concatenated_name_hash(hierarchical_separator).to_a.map do |key, value|
    "#{key.upcase}#{name_value_separator}#{value_surrounder}#{value}#{value_surrounder}"
  end

  pairs.join(pair_separator)
end