1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 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 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
|
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module Gapic
##
# Config is a simple DSL for creating Configuration classes.
#
# @example
# require "gapic/config"
#
# class SampleConfig
# extend Gapic::Config
#
# config_attr :name, nil, String, nil
# config_attr :active, true, true, false
# config_attr :count, nil, Numeric, nil
# config_attr :env, :production, String, Symbol
#
# def initialize parent_config = nil
# @parent_config = parent_config unless parent_config.nil?
# yield self if block_given?
# end
# end
#
# config = SampleConfig.new
#
# config.name #=> nil
# config.name = "thor" #=> "thor"
# config.name #=> "thor"
# config.name = :thor # ArgumentError
#
module Config
##
# Add configuration attribute methods to the configuratin class.
#
# @param [String, Symbol] name The name of the option
# @param [Object, nil] default Initial value (nil is allowed)
# @param [Array] valid_values A list of valid types
#
def config_attr name, default, *valid_values, &validator
name = String(name).to_sym
name_setter = :"#{name}="
raise NameError, "invalid config name #{name}" if name !~ /^[a-zA-Z]\w*$/ || name == :parent_config
raise NameError, "method #{name} already exists" if method_defined? name
raise NameError, "method #{name_setter} already exists" if method_defined? name_setter
raise ArgumentError, "validation must be provided" if validator.nil? && valid_values.empty?
validator ||= ->(value) { valid_values.any? { |v| v === value } }
name_ivar = :"@#{name}"
create_getter name_ivar, name, default
create_setter name_ivar, name_setter, default, validator
end
private
def create_getter name_ivar, name, default
define_method name do
return instance_variable_get name_ivar if instance_variable_defined? name_ivar
if instance_variable_defined? :@parent_config
parent = instance_variable_get :@parent_config
return parent.__send__ name if parent.respond_to? name
end
default
end
end
def create_setter name_ivar, name_setter, default, validator
define_method name_setter do |new_value|
valid_value = validator.call new_value
if new_value.nil?
# Always allow nil when a default value is present
valid_value ||= !default.nil?
valid_value ||= begin
# Allow nil if parent config has the getter method.
parent = instance_variable_get :@parent_config if instance_variable_defined? :@parent_config
parent&.respond_to? name_setter
end
end
raise ArgumentError unless valid_value
if new_value.nil?
remove_instance_variable name_ivar if instance_variable_defined? name_ivar
else
instance_variable_set name_ivar, new_value
end
end
end
end
end
|