# 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