class OptionalArgument::Store
@note
-
Don’t include Enumerable
"To be Enumerable" is not necessary for this class. Because main role is just to hold options.
-
Depends only ‘/A_+func_*z/` on implementing for this class. Because `func` is kept for public API of options.
Public Class Methods
@param name [Symbol, String, to_sym]
# File lib/optionalargument/store/singleton_class.rb, line 108 def adjuster?(name) member?(name) && @adjusters.key?(autonym_for_name(name)) end
@param name [Symbol, String, to_sym]
# File lib/optionalargument/store/singleton_class.rb, line 88 def aliased?(name) member?(name) && !autonym?(name) && !deprecated?(name) end
@return [Array<Symbol>]
# File lib/optionalargument/store/singleton_class.rb, line 68 def aliases @names.each_key.select { |name| aliased?(name) } end
@param name [Symbol, String, to_sym]
# File lib/optionalargument/store/singleton_class.rb, line 78 def autonym?(name) @names.value?(name.to_sym) end
@param name [Symbol, String, to_sym] @return [Symbol]
# File lib/optionalargument/store/singleton_class.rb, line 51 def autonym_for_name(name) @names.fetch(name.to_sym) end
@return [Array<Symbol>] - autonym, autonym, …
# File lib/optionalargument/store/singleton_class.rb, line 58 def autonyms @names.values.uniq end
@param name [Symbol, String, to_sym]
# File lib/optionalargument/store/singleton_class.rb, line 103 def condition?(name) member?(name) && @conditions.key?(autonym_for_name(name)) end
@param name [Symbol, String, to_sym]
# File lib/optionalargument/store/singleton_class.rb, line 98 def default?(name) member?(name) && @default_values.key?(autonym_for_name(name)) end
@param name [Symbol, String, to_sym]
# File lib/optionalargument/store/singleton_class.rb, line 93 def deprecated?(name) @deprecateds.include?(name.to_sym) end
@return [Array<Symbol>]
# File lib/optionalargument/store/singleton_class.rb, line 73 def deprecateds @deprecateds.dup end
@param name [Symbol, String, to_sym]
# File lib/optionalargument/store/singleton_class.rb, line 83 def member?(name) @names.key?(name.to_sym) end
@return [Array<Symbol>]
# File lib/optionalargument/store/singleton_class.rb, line 63 def members @names.keys end
for debug @return [Hash] - autonym/alias/deprecated => autonym, …
# File lib/optionalargument/store/singleton_class.rb, line 114 def names_with_autonym @names.dup end
@param [Boolean] defined_only @param [Exception] exception @return [Store] instance of a Store’s subclass
# File lib/optionalargument/store/singleton_class.rb, line 23 def parse(options, defined_only: true, exception: nil) begin unless options.respond_to?(:each_pair) raise MalformedOptionsError, 'options must be key-value pairs' end autonym_hash = _autonym_hash_for(options, defined_only) _scan_hash!(autonym_hash) new(autonym_hash) rescue MalformedOptionsError, InvalidWritingError => err if replacement = exception raise replacement.new, err else raise err end end end
Private Class Methods
@param autonym [Symbol] @param adjuster [#call] @return [adjuster]
# File lib/optionalargument/store/singleton_class.rb, line 339 def _add_adjuster(autonym, adjuster) unless adjuster.respond_to?(:call) raise TypeError, "#{adjuster.inspect} is wrong object for adjuster" end @adjusters[autonym] = adjuster end
@param autonym [Symbol] @param condition [#===] @return [condition]
# File lib/optionalargument/store/singleton_class.rb, line 328 def _add_condition(autonym, condition) unless condition.respond_to?(:===) raise TypeError, "#{condition.inspect} is wrong object for condition" end @conditions[autonym] = condition end
@param autonym [Symbol] @return [value]
# File lib/optionalargument/store/singleton_class.rb, line 321 def _add_default(autonym, value) @default_values[autonym] = value end
@param names [Array<Symbol>] @return [nil]
# File lib/optionalargument/store/singleton_class.rb, line 290 def _add_deprecated(*names) @deprecateds.concat(names) nil end
@param autonym [Symbol] @param name [Symbol] @return [name]
# File lib/optionalargument/store/singleton_class.rb, line 298 def _add_member(autonym, name) if member?(name) raise NameError, "already defined the name: #{name}" end @names[name] = autonym _def_instance_methods(name) end
@param autonym [Symbol] @return [autonym]
# File lib/optionalargument/store/singleton_class.rb, line 284 def _add_must(autonym) @must_autonyms << autonym end
@param autonym [Symbol] @param requirements [Array<Symbol, String, to_sym>] @return [nil]
# File lib/optionalargument/store/singleton_class.rb, line 310 def _add_requirements(autonym, requirements) unless requirements.kind_of?(Array) && requirements.all? { |name| name.respond_to?(:to_sym) } raise ArgumentError, '`requirements` requires to be Array<Symbol, String>' end @requirements[autonym] = requirements.map(&:to_sym).uniq nil end
@param options [#each_pair] @param defined_only [Boolean] @return [Hash]
# File lib/optionalargument/store/singleton_class.rb, line 359 def _autonym_hash_for(options, defined_only) hash = {} options.each_pair do |key, value| key = key.to_sym if member?(key) autonym = autonym_for_name(key) raise KeyConflictError, key if hash.key?(autonym) if deprecated?(key) warn("`#{key}` is deprecated, use `#{autonym}`") end hash[autonym] = _validate_value(autonym, value) else if defined_only raise MalformedOptionsError, %Q!unknown defined name "#{key}"! end end end hash end
@return [nil]
# File lib/optionalargument/store/singleton_class.rb, line 452 def _check_requirements @requirements.each_pair do |autonym, names| names.map! { |name| if member?(name) autonym_for_name(name) else raise ArgumentError, "`#{autonym}` with invalid requirements `#{names}`" end } end nil end
@param name [Symbol] @return [nil]
# File lib/optionalargument/store/singleton_class.rb, line 229 def _def_instance_methods(name) autonym = autonym_for_name(name) fetcher = :"fetch_by_#{name}" define_method(fetcher) do self[autonym] end alias_method(name, fetcher) with_predicator = :"with_#{name}?" define_method(with_predicator) do with?(autonym) end predicator = :"#{name}?" alias_method(predicator, with_predicator) overrides = [name, fetcher, with_predicator, predicator].select { |callee| Store.method_defined?(callee) || Store.private_method_defined?(callee) } unless overrides.empty? warn("override methods: #{overrides.join(', ')}") end nil end
@param autonyms [Array<Symbol>] @return [Hash] autonym => default_value
# File lib/optionalargument/store/singleton_class.rb, line 441 def _default_pairs_for(*autonyms) {}.tap { |h| autonyms.each do |autonym| if default?(autonym) h[autonym] = _validate_value(autonym, @default_values.fetch(autonym)) end end } end
@return [nil]
# File lib/optionalargument/store/singleton_class.rb, line 139 def _fix raise 'no assigned members yet' if @names.empty? instance_variables.each do |var| instance_variable_get(var).freeze end _check_requirements nil end
@return [nil]
# File lib/optionalargument/store/singleton_class.rb, line 125 def _init @names = {} # {autonym/alias/deprecated => autonym, ...} @must_autonyms = [] # [autonym, autonym, ...] @conflict_autonym_sets = [] # [[*autonyms], [*autonyms], ...] @requirements = {} # {autonym => [*requirements], ...] @deprecateds = [] # [deprecated, deprecated, ...] @default_values = {} # {autonym => value, ...} @conditions = {} # {autonym => condition, ...} @adjusters = {} # {autonym => adjuster, ...} nil end
@param autonym_hash [Hash] @return [autonym_hash]
# File lib/optionalargument/store/singleton_class.rb, line 349 def _scan_hash!(autonym_hash) received_autonyms = autonym_hash.keys.map { |key| autonym_for_name(key) } _validate_autonym_combinations(*received_autonyms) autonym_hash.update(_default_pairs_for(*(autonyms - received_autonyms))) autonym_hash end
@param received_autonyms [Array<Symbol>] @raise [MalformedOptionsError, KeyConflictError] if invalid autonym combinations @return [nil]
# File lib/optionalargument/store/singleton_class.rb, line 387 def _validate_autonym_combinations(*received_autonyms) _validate_shortage_keys(*received_autonyms) _validate_requirements(*received_autonyms) _validate_conflicts(*received_autonyms) nil end
@param received_autonyms [Array<Symbol>] @raise [KeyConflictError] @return [nil]
# File lib/optionalargument/store/singleton_class.rb, line 426 def _validate_conflicts(*received_autonyms) conflicts = @conflict_autonym_sets.find { |conflict_autonym_set| (conflict_autonym_set - received_autonyms).empty? } if conflicts raise KeyConflictError, "conflict combination thrown: #{conflicts.join(', ')}" end nil end
@param received_autonyms [Array<Symbol>] @raise [MalformedOptionsError] @return [nil]
# File lib/optionalargument/store/singleton_class.rb, line 411 def _validate_requirements(*received_autonyms) received_autonyms.each do |autonym| shortage_keys = @requirements.fetch(autonym) - received_autonyms unless shortage_keys.empty? raise MalformedOptionsError, "shortage option parameter for #{autonym}: #{shortage_keys.join(', ')}" end end nil end
@param received_autonyms [Array<Symbol>] @raise [MalformedOptionsError] @return [nil]
# File lib/optionalargument/store/singleton_class.rb, line 397 def _validate_shortage_keys(*received_autonyms) shortage_keys = @must_autonyms - received_autonyms unless shortage_keys.empty? raise MalformedOptionsError, "shortage option parameter: #{shortage_keys.join(', ')}" end nil end
@param autonym [Symbol] @return [value]
# File lib/optionalargument/store/singleton_class.rb, line 261 def _validate_value(autonym, value) if adjuster?(autonym) adjuster = @adjusters.fetch(autonym) begin value = adjuster.call(value) rescue Exception => err raise InvalidAdjustingError, err end end if condition?(autonym) condition = @conditions.fetch(autonym) unless condition === value raise InvalidWritingError, "#{value.inspect} is deficient for #{condition}" end end value end
@param autonym1 [Symbol, String, to_sym] @param autonym2 [Symbol, String, to_sym] @param autonyms [Symbol, String, to_sym] @return [nil]
# File lib/optionalargument/store/singleton_class.rb, line 204 def add_conflict(autonym1, autonym2, *autonyms) autonyms = [autonym1, autonym2, *autonyms].map(&:to_sym) raise ArgumentError unless autonyms == autonyms.uniq not_autonyms = (autonyms - @names.values) unless not_autonyms.empty? raise ArgumentError, "contain not autonym: #{not_autonyms.join(', ')}" end raise if @conflict_autonym_sets.include?(autonyms) @conflict_autonym_sets << autonyms nil end
@param [Symbol, String, to_sym] autonym @param [Boolean] must @param [#===] condition @param [Array<Symbol, String, to_sym>] aliases @param [Array<Symbol, String, to_sym>] deprecateds @param [Array<Symbol, String, to_sym>] requirements @param [#call] adjuster @return [void]
# File lib/optionalargument/store/singleton_class.rb, line 163 def add_option(autonym, condition: nil, adjuster: nil, must: false, default: nil, requirements: [].freeze, deprecateds: [].freeze, aliases: [].freeze) autonym = autonym.to_sym if condition _add_condition(autonym, condition) end if adjuster _add_adjuster(autonym, adjuster) end if must unless default.nil? raise KeyConflictError, '"must" conflict with "default"' end _add_must(autonym) end unless default.nil? _add_default(autonym, default) end _add_requirements(autonym, requirements) _add_deprecated(*deprecateds) [autonym, *aliases, *deprecateds].each do |name| _add_member(autonym, name.to_sym) end nil end
@param pairs [Hash, to_hash]
# File lib/optionalargument/store.rb, line 21 def initialize(pairs) @pairs = pairs end
Public Instance Methods
@return [Boolean]
# File lib/optionalargument/store.rb, line 77 def ==(other) other.instance_of?(__class__) && (other._pairs === @pairs) end
@param name [Symbol, String, to_sym]
# File lib/optionalargument/store.rb, line 35 def [](name) @pairs[_autonym_for_name(name)] end
@param name [Symbol, String, to_sym] @return [Symbol]
# File lib/optionalargument/store.rb, line 27 def autonym_for_name(name) __class__.autonym_for_name(name) end
@yield [autonym, value] @yieldparam autonym [Symbol] @yieldreturn [self] @return [Enumerator]
# File lib/optionalargument/store.rb, line 55 def each_pair(&block) return _to_enum(__method__) { @pairs.size } unless block @pairs.each_pair(&block) self end
# File lib/optionalargument/store.rb, line 72 def eql?(other) other.instance_of?(__class__) && other._pairs.eql?(@pairs) end
@return [Integer]
# File lib/optionalargument/store.rb, line 68 def hash @pairs.hash end
@return [String]
# File lib/optionalargument/store.rb, line 45 def inspect "#<optargs: #{@pairs.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')}>" end
@return [Hash]
# File lib/optionalargument/store.rb, line 63 def to_h @pairs.to_hash.dup end
@param name [Symbol, String, to_sym]
# File lib/optionalargument/store.rb, line 40 def with?(name) @pairs.key?(_autonym_for_name(name)) end
Protected Instance Methods
# File lib/optionalargument/store.rb, line 85 def _pairs @pairs end