class Google::Cloud::Config

Configuration mechanism for Google Cloud libraries. A Config object contains a list of predefined keys, some of which are values and others of which are subconfigurations, i.e. categories. Field access is generally validated to ensure that the field is defined, and when a a value is set, it is validated for the correct type. Warnings are printed when a validation fails.

You generally access fields and subconfigs by calling accessor methods. Methods meant for “administration” such as adding options, are named with a trailing “!” or “?” so they don't pollute the method namespace. It is also possible to access a field using the `[]` operator.

Note that config objects inherit from `BasicObject`. This means it does not define many methods you might expect to find in most Ruby objects. For example, `to_s`, `inspect`, `is_a?`, `instance_variable_get`, and so forth.

@example

require "google/cloud/config"

config = Google::Cloud::Config.create do |c|
  c.add_field! :opt1, 10
  c.add_field! :opt2, :one, enum: [:one, :two, :three]
  c.add_field! :opt3, "hi", match: [String, Symbol]
  c.add_field! :opt4, "hi", match: /^[a-z]+$/, allow_nil: true
  c.add_config! :sub do |c2|
    c2.add_field! :opt5, false
  end
end

config.opt1             #=> 10
config.opt1 = 20        #=> 20
config.opt1             #=> 20
config.opt1 = "hi"      #=> "hi" (but prints a warning)
config.opt1 = nil       #=> nil (but prints a warning)

config.opt2             #=> :one
config.opt2 = :two      #=> :two
config.opt2             #=> :two
config.opt2 = :four     #=> :four (but prints a warning)

config.opt3             #=> "hi"
config.opt3 = "hiho"    #=> "hiho"
config.opt3             #=> "hiho"
config.opt3 = "HI"      #=> "HI" (but prints a warning)

config.opt4             #=> "yo"
config.opt4 = :yo       #=> :yo (Strings and Symbols allowed)
config.opt4             #=> :yo
config.opt4 = 3.14      #=> 3.14 (but prints a warning)
config.opt4 = nil       #=> nil (no warning: nil allowed)

config.sub              #=> <Google::Cloud::Config>

config.sub.opt5         #=> false
config.sub.opt5 = true  #=> true  (true and false allowed)
config.sub.opt5         #=> true
config.sub.opt5 = nil   #=> nil (but prints a warning)

config.opt9 = "hi"      #=> "hi" (warning about unknown key)
config.opt9             #=> "hi" (no warning: key now known)
config.sub.opt9         #=> nil (warning about unknown key)

Constants

ILLEGAL_KEYS

@private a list of key names that are technically illegal because they clash with method names.

OPEN_VALIDATOR

@private A validator that allows all values

SUBCONFIG

@private sentinel indicating a subconfig in the validators hash

Public Class Methods

config?(obj) click to toggle source

Determines if the given object is a config. Useful because Config does not define the `is_a?` method.

@return [boolean]

# File lib/google/cloud/config.rb, line 104
def self.config? obj
  Config.send :===, obj
end
create(show_warnings: true) { |config| ... } click to toggle source

Constructs a Config object. If a block is given, yields `self` to the block, which makes it convenient to initialize the structure by making calls to `add_field!` and `add_config!`.

@param [boolean] show_warnings Whether to print warnings when a

validation fails. Defaults to `true`.

@return [Config] The constructed Config object.

# File lib/google/cloud/config.rb, line 92
def self.create show_warnings: true
  config = new [], show_warnings: show_warnings
  yield config if block_given?
  config
end
credentials_from_env(*vars) click to toggle source

Search the given environment variable names for valid credential data that can be passed to `Google::Auth::Credentials.new`. If a variable contains a valid file path, returns that path as a string. If a variable contains valid JSON, returns the parsed JSON as a hash. If no variables contain valid data, returns nil. @private

# File lib/google/cloud/config.rb, line 430
def self.credentials_from_env *vars
  vars.each do |var|
    data = ::ENV[var]
    next unless data
    str = data.strip
    return str if ::File.file? str
    json = begin
      ::JSON.parse str
    rescue ::StandardError
      nil
    end
    return json if json.is_a? ::Hash
  end
  nil
end
deferred(&block) click to toggle source

@private Create a configuration value that will be invoked when retrieved.

# File lib/google/cloud/config.rb, line 450
def self.deferred &block
  DeferredValue.new(&block)
end
new(legacy_categories = {}) click to toggle source

Internal constructor. Generally you should not call `new` directly, but instead use the `Config.create` method. The initializer is used directly by a few older clients that expect a legacy interface.

@private

# File lib/google/cloud/config.rb, line 115
def initialize legacy_categories = {}, opts = {}
  @show_warnings = opts.fetch :show_warnings, false
  @values = {}
  @defaults = {}
  @validators = {}
  add_options legacy_categories
end

Public Instance Methods

[](key) click to toggle source

Get the option or subconfig with the given name.

@param [Symbol, String] key The option or subconfig name @return [Object] The option value or subconfig object

# File lib/google/cloud/config.rb, line 309
def [] key
  key = resolve_key! key
  warn! "Key #{key.inspect} does not exist. Returning nil." unless @validators.key? key
  value = @values[key]
  value = value.call if Config::DeferredValue === value
  value
end
[]=(key, value) click to toggle source

Assign an option with the given name to the given value.

@param [Symbol, String] key The option name @param [Object] value The new option value

# File lib/google/cloud/config.rb, line 297
def []= key, value
  key = resolve_key! key
  validate_value! key, @validators[key], value
  @values[key] = value
end
add_alias!(key, to_key) click to toggle source

Cause a key to be an alias of another key. The two keys will refer to the same field.

# File lib/google/cloud/config.rb, line 235
def add_alias! key, to_key
  key = validate_new_key! key
  @values.delete key
  @defaults.delete key
  @validators[key] = to_key.to_sym
  self
end
add_config!(key, config = nil) { |config| ... } click to toggle source

Add a subconfiguration field to this configuration.

You must provide a key, which becomes the method name that you use to navigate to the subconfig. Names may comprise only letters, numerals, and underscores, and must begin with a letter.

If you provide a block, the subconfig object is passed to the block, so you can easily add fields to the subconfig.

You may also pass in a config object that already exists. This will “attach” that configuration in this location.

@param [String, Symbol] key The name of the subconfig @param [Config] config A config object to attach here. If not provided,

creates a new config.

@return [Config] self for chaining

# File lib/google/cloud/config.rb, line 218
def add_config! key, config = nil, &block
  key = validate_new_key! key
  if config.nil?
    config = Config.create(&block)
  elsif block
    yield config
  end
  @values[key] = config
  @defaults[key] = config
  @validators[key] = SUBCONFIG
  self
end
add_field!(key, initial = nil, opts = {}) click to toggle source

Add a value field to this configuration.

You must provide a key, which becomes the field name in this config. Field names may comprise only letters, numerals, and underscores, and must begin with a letter. This will create accessor methods for the new configuration key.

You may pass an initial value (which defaults to nil if not provided).

You may also specify how values are validated. Validation is defined as follows:

  • If you provide a block or a `:validator` option, it is used as the validator. A proposed value is passed to the proc, which should return `true` or `false` to indicate whether the value is valid.

  • If you provide a `:match` option, it is compared to the proposed value using the `===` operator. You may, for example, provide a class, a regular expression, or a range. If you pass an array, the value is accepted if any of the elements match.

  • If you provide an `:enum` option, it should be an `Enumerable`. A proposed value is valid if it is included.

  • Otherwise if you do not provide any of the above options, then a default validation strategy is inferred from the initial value:

    • If the initial is `true` or `false`, then either boolean value is considered valid. This is the same as `enum: [true, false]`.

    • If the initial is `nil`, then any object is considered valid.

    • Otherwise, any object of the same class as the initial value is considered valid. This is effectively the same as `match: initial.class`.

  • You may also provide the `:allow_nil` option, which, if set to true, alters any of the above validators to allow `nil` values.

In many cases, you may find that the default validation behavior (interpreted from the initial value) is sufficient. If you want to accept any value, use `match: Object`.

@param [String, Symbol] key The name of the option @param [Object] initial Initial value (defaults to nil) @param [Hash] opts Validation options

@return [Config] self for chaining

# File lib/google/cloud/config.rb, line 188
def add_field! key, initial = nil, opts = {}, &block
  key = validate_new_key! key
  opts[:validator] = block if block
  validator = resolve_validator! initial, opts
  validate_value! key, validator, initial
  @values[key] = initial
  @defaults[key] = initial
  @validators[key] = validator
  self
end
add_options(legacy_categories) click to toggle source

Legacy method of adding subconfigs. This is used by older versions of the stackdriver client libraries but should not be used in new code.

@deprecated @private

# File lib/google/cloud/config.rb, line 130
def add_options legacy_categories
  [legacy_categories].flatten(1).each do |sub_key|
    case sub_key
    when ::Symbol
      add_config! sub_key, Config.new
    when ::Hash
      sub_key.each do |k, v|
        add_config! k, Config.new(v)
      end
    else
      raise ArgumentError "Category must be a Symbol or Hash"
    end
  end
end
alias?(key) click to toggle source

Check if the given key has been explicitly added as an alias. If so, return the target, otherwise return nil.

@param [Symbol] key The key to check for. @return [Symbol,nil] The alias target, or nil if not an alias.

# File lib/google/cloud/config.rb, line 358
def alias? key
  target = @validators[key.to_sym]
  target.is_a?(::Symbol) ? target : nil
end
aliases!() click to toggle source

Return a list of alias names.

@return [Array<Symbol>] a list of alias names as symbols.

# File lib/google/cloud/config.rb, line 386
def aliases!
  @validators.keys.find_all { |key| @validators[key].is_a? ::Symbol }
end
delete!(key = nil) click to toggle source

Remove the given key from the configuration, deleting any validation and value. If the key is omitted, delete all keys. If the key is an alias, deletes the alias but leaves the original.

@param [Symbol, nil] key The key to delete. If omitted or `nil`,

delete all fields and subconfigs.
# File lib/google/cloud/config.rb, line 278
def delete! key = nil
  if key.nil?
    @values.clear
    @defaults.clear
    @validators.clear
  else
    @values.delete key
    @defaults.delete key
    @validators.delete key
  end
  self
end
field?(key) click to toggle source

Check if the given key has been explicitly added as a field name.

@param [Symbol] key The key to check for. @return [boolean]

# File lib/google/cloud/config.rb, line 336
def field? key
  @validators[key.to_sym].is_a? ::Proc
end
Also aliased as: respond_to?
fields!() click to toggle source

Return a list of explicitly added field names.

@return [Array<Symbol>] a list of field names as symbols.

# File lib/google/cloud/config.rb, line 368
def fields!
  @validators.keys.find_all { |key| @validators[key].is_a? ::Proc }
end
inspect()
Alias for: to_s!
method_missing(name, *args) click to toggle source

@private Dynamic methods accessed as keys.

Calls superclass method
# File lib/google/cloud/config.rb, line 458
def method_missing name, *args
  name_str = name.to_s
  super unless name_str =~ /^[a-zA-Z]\w*=?$/
  if name_str.end_with? "="
    self[name_str[0...-1]] = args.first
  else
    self[name]
  end
end
nil?() click to toggle source

@private Implement standard nil check

@return [false]

# File lib/google/cloud/config.rb, line 483
def nil?
  false
end
option?(key)
Alias for: value_set?
reset!(key = nil) click to toggle source

Restore the original default value of the given key. If the key is omitted, restore the original defaults for all keys, and all keys of subconfigs, recursively.

@param [Symbol, nil] key The key to reset. If omitted or `nil`,

recursively reset all fields and subconfigs.
# File lib/google/cloud/config.rb, line 251
def reset! key = nil
  if key.nil?
    @values.each_key { |k| reset! k }
  else
    key = key.to_sym
    if @defaults.key? key
      @values[key] = @defaults[key]
      @values[key].reset! if @validators[key] == SUBCONFIG
    elsif @values.key? key
      warn! "Key #{key.inspect} has not been added, but has a value." \
            " Removing the value."
      @values.delete key
    else
      warn! "Key #{key.inspect} does not exist. Nothing to reset."
    end
  end
  self
end
respond_to?(key)
Alias for: field?
respond_to_missing?(name, include_private) click to toggle source

@private Dynamic methods accessed as keys.

Calls superclass method
# File lib/google/cloud/config.rb, line 472
def respond_to_missing? name, include_private
  return true if value_set? name.to_s.chomp("=")
  super
end
subconfig?(key) click to toggle source

Check if the given key has been explicitly added as a subconfig name.

@param [Symbol] key The key to check for. @return [boolean]

# File lib/google/cloud/config.rb, line 347
def subconfig? key
  @validators[key.to_sym] == SUBCONFIG
end
subconfigs!() click to toggle source

Return a list of explicitly added subconfig names.

@return [Array<Symbol>] a list of subconfig names as symbols.

# File lib/google/cloud/config.rb, line 377
def subconfigs!
  @validators.keys.find_all { |key| @validators[key] == SUBCONFIG }
end
to_h!() click to toggle source

Returns a nested hash representation of this configuration state, including subconfigs. Only explicitly added fields and subconfigs are included.

@return [Hash]

# File lib/google/cloud/config.rb, line 413
def to_h!
  h = {}
  @validators.each_key do |k|
    v = @values[k]
    h[k] = Config.config?(v) ? v.to_h! : v.inspect
  end
  h
end
to_s!() click to toggle source

Returns a string representation of this configuration state, including subconfigs. Only explicitly added fields and subconfigs are included.

@return [String]

# File lib/google/cloud/config.rb, line 396
def to_s!
  elems = @validators.keys.map do |k|
    v = @values[k]
    vstr = Config.config?(v) ? v.to_s! : v.inspect
    " #{k}=#{vstr}"
  end
  "<Config:#{elems.join}>"
end
Also aliased as: inspect
value_set?(key) click to toggle source

Check if the given key has been set in this object. Returns true if the key has been added as a normal field, subconfig, or alias, or if it has not been added explicitly but still has a value.

@param [Symbol] key The key to check for. @return [boolean]

# File lib/google/cloud/config.rb, line 325
def value_set? key
  @values.key? resolve_key! key
end
Also aliased as: option?

Private Instance Methods

build_enum_validator!(allowed, allow_nil) click to toggle source
# File lib/google/cloud/config.rb, line 555
def build_enum_validator! allowed, allow_nil
  allowed = ::Kernel.Array(allowed)
  allowed += [nil] if allow_nil && !allowed.include?(nil)
  ->(val) { allowed.include? val }
end
build_match_validator!(matches, allow_nil) click to toggle source
# File lib/google/cloud/config.rb, line 549
def build_match_validator! matches, allow_nil
  matches = ::Kernel.Array(matches)
  matches += [nil] if allow_nil && !matches.include?(nil)
  ->(val) { matches.any? { |m| m.send :===, val } }
end
build_proc_validator!(proc, allow_nil) click to toggle source
# File lib/google/cloud/config.rb, line 561
def build_proc_validator! proc, allow_nil
  ->(val) { proc.call(val) || (allow_nil && val.nil?) }
end
resolve_key!(key) click to toggle source
# File lib/google/cloud/config.rb, line 514
def resolve_key! key
  key = key.to_sym
  alias_target = @validators[key]
  alias_target.is_a?(::Symbol) ? alias_target : key
end
resolve_validator!(initial, opts) click to toggle source
# File lib/google/cloud/config.rb, line 531
def resolve_validator! initial, opts
  allow_nil = initial.nil? || opts[:allow_nil]
  if opts.key? :validator
    build_proc_validator! opts[:validator], allow_nil
  elsif opts.key? :match
    build_match_validator! opts[:match], allow_nil
  elsif opts.key? :enum
    build_enum_validator! opts[:enum], allow_nil
  elsif [true, false].include? initial
    build_enum_validator! [true, false], allow_nil
  elsif initial.nil?
    OPEN_VALIDATOR
  else
    klass = Config.config?(initial) ? Config : initial.class
    build_match_validator! klass, allow_nil
  end
end
validate_new_key!(key) click to toggle source
# File lib/google/cloud/config.rb, line 520
def validate_new_key! key
  key_str = key.to_s
  key = key.to_sym
  if key_str !~ /^[a-zA-Z]\w*$/ || ILLEGAL_KEYS.include?(key)
    warn! "Illegal key name: #{key_str.inspect}. Method dispatch will" \
          " not work for this key."
  end
  warn! "Key #{key.inspect} already exists. It will be replaced." if @validators.key? key
  key
end
validate_value!(key, validator, value) click to toggle source
# File lib/google/cloud/config.rb, line 565
def validate_value! key, validator, value
  value = value.call if Config::DeferredValue === value
  case validator
  when ::Proc
    unless validator.call value
      warn! "Invalid value #{value.inspect} for key #{key.inspect}." \
            " Setting anyway."
    end
  when Config
    if value != validator
      warn! "Key #{key.inspect} refers to a subconfig and shouldn't" \
            " be changed. Setting anyway."
    end
  else
    warn! "Key #{key.inspect} has not been added. Setting anyway."
  end
end
warn!(msg) click to toggle source
# File lib/google/cloud/config.rb, line 583
def warn! msg
  return unless @show_warnings
  location = ::Kernel.caller_locations.find do |s|
    !s.to_s.include? "/google/cloud/config.rb:"
  end
  ::Kernel.warn "#{msg} at #{location}"
end