Class: OptionalArgument::Store

Inherits:
Object
  • Object
show all
Extended by:
Validation::Adjustment, Validation::Condition
Defined in:
lib/optionalargument/store.rb,
lib/optionalargument/store/singleton_class.rb

Overview

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 keeped for public API of options.

Specific Constructor collapse

DEFAULT_PARSE_OPTIONS =
{
  defined_only: true,
  exception: nil
}.freeze

Define options collapse

DEFAULT_ADD_OPT_OPTIONS =
{
  must:         false,
  aliases:      [].freeze,
  deprecateds:  [].freeze,
  requirements: [].freeze
}.freeze

Specific Constructor collapse

Access option names collapse

Build and Fix Class's structure - Inner API collapse

Define options collapse

Define options - Inner API collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(pairs) ⇒ Store

Returns a new instance of Store.

Parameters:

  • pairs (Hash, #to_hash)

22
23
24
# File 'lib/optionalargument/store.rb', line 22

def initialize(pairs)
  @pairs = pairs
end

Class Method Details

._add_adjuster(autonym, adjuster) ⇒ adjuster (private)

Parameters:

  • autonym (Symbol)
  • adjuster (#call)

Returns:

  • (adjuster)

374
375
376
377
378
379
380
# File 'lib/optionalargument/store/singleton_class.rb', line 374

def _add_adjuster(autonym, adjuster)
  unless adjuster.respond_to? :call
    raise TypeError, "#{adjuster.inspect} is wrong object for adjuster"
  end

  @adjusters[autonym] = adjuster
end

._add_condition(autonym, condition) ⇒ condition (private)

Parameters:

  • autonym (Symbol)
  • condition (#===)

Returns:

  • (condition)

363
364
365
366
367
368
369
# File 'lib/optionalargument/store/singleton_class.rb', line 363

def _add_condition(autonym, condition)
  unless condition.respond_to? :===
    raise TypeError, "#{condition.inspect} is wrong object for condition"
  end

  @conditions[autonym] = condition
end

._add_default(autonym, value) ⇒ value (private)

Parameters:

  • autonym (Symbol)

Returns:

  • (value)

356
357
358
# File 'lib/optionalargument/store/singleton_class.rb', line 356

def _add_default(autonym, value)
  @default_values[autonym] = value
end

._add_deprecated(*names) ⇒ nil (private)

Parameters:

  • names (Array<Symbol>)

Returns:

  • (nil)

325
326
327
328
# File 'lib/optionalargument/store/singleton_class.rb', line 325

def _add_deprecated(*names)
  @deprecateds.concat names
  nil
end

._add_member(autonym, name) ⇒ name (private)

Parameters:

  • autonym (Symbol)
  • name (Symbol)

Returns:

  • (name)

333
334
335
336
337
338
339
340
# File 'lib/optionalargument/store/singleton_class.rb', line 333

def _add_member(autonym, name)
  if member? name
    raise NameError, "already defined the name: #{name}"
  end
  
  @names[name] = autonym
  _def_instance_methods name
end

._add_must(autonym) ⇒ autonym (private)

Parameters:

  • autonym (Symbol)

Returns:

  • (autonym)

319
320
321
# File 'lib/optionalargument/store/singleton_class.rb', line 319

def _add_must(autonym)
  @must_autonyms << autonym
end

._add_requirements(autonym, requirements) ⇒ nil (private)

Parameters:

  • autonym (Symbol)
  • requirements (Array<Symbol, String, #to_sym>)

Returns:

  • (nil)

345
346
347
348
349
350
351
352
# File 'lib/optionalargument/store/singleton_class.rb', line 345

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

._autonym_hash_for(options, defined_only) ⇒ Hash (private)

Parameters:

  • options (#each_pair)
  • defined_only (Boolean)

Returns:

  • (Hash)

394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
# File 'lib/optionalargument/store/singleton_class.rb', line 394

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.has_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

._check_requirementsnil (private)

Returns:

  • (nil)

487
488
489
490
491
492
493
494
495
496
497
498
499
500
# File 'lib/optionalargument/store/singleton_class.rb', line 487

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

._def_instance_methods(_name) ⇒ nil (private)

Parameters:

  • _name (Symbol)

Returns:

  • (nil)

258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/optionalargument/store/singleton_class.rb', line 258

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

._default_pairs_for(*autonyms) ⇒ Hash (private)

Returns autonym => default_value.

Parameters:

  • autonyms (Array<Symbol>)

Returns:

  • (Hash)

    autonym => default_value


476
477
478
479
480
481
482
483
484
# File 'lib/optionalargument/store/singleton_class.rb', line 476

def _default_pairs_for(*autonyms)
  {}.tap {|h|
    autonyms.each do |autonym|
      if has_default? autonym
        h[autonym] = _validate_value autonym, @default_values.fetch(autonym)
      end
    end
  }
end

._fixnil (private)

Returns:

  • (nil)

150
151
152
153
154
155
156
157
158
159
160
# File 'lib/optionalargument/store/singleton_class.rb', line 150

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

._initnil (private)

Returns:

  • (nil)

136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/optionalargument/store/singleton_class.rb', line 136

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 => condiiton, ...}
  @adjusters = {}             # {autonym => adjuster, ...}

  nil
end

._scan_hash!(autonym_hash) ⇒ autonym_hash (private)

Parameters:

  • autonym_hash (Hash)

Returns:

  • (autonym_hash)

384
385
386
387
388
389
# File 'lib/optionalargument/store/singleton_class.rb', line 384

def _scan_hash!(autonym_hash)
  recieved_autonyms = autonym_hash.keys.map{|key|autonym_for_name key}
  _validate_autonym_combinations(*recieved_autonyms)
  autonym_hash.update _default_pairs_for(*(autonyms - recieved_autonyms))
  autonym_hash
end

._valid?(condition, value) ⇒ Boolean (private)

Parameters:

  • condition (#===)

Returns:

  • (Boolean)

289
290
291
# File 'lib/optionalargument/store/singleton_class.rb', line 289

def _valid?(condition, value)
  condition === value
end

._validate_autonym_combinations(*recieved_autonyms) ⇒ nil (private)

Parameters:

  • recieved_autonyms (Array<Symbol>)

Returns:

  • (nil)

Raises:


422
423
424
425
426
427
# File 'lib/optionalargument/store/singleton_class.rb', line 422

def _validate_autonym_combinations(*recieved_autonyms)
  _validate_shortage_keys(*recieved_autonyms)
  _validate_requirements(*recieved_autonyms)
  _validate_conflicts(*recieved_autonyms)
  nil
end

._validate_conflicts(*recieved_autonyms) ⇒ nil (private)

Parameters:

  • recieved_autonyms (Array<Symbol>)

Returns:

  • (nil)

Raises:


461
462
463
464
465
466
467
468
469
470
471
472
# File 'lib/optionalargument/store/singleton_class.rb', line 461

def _validate_conflicts(*recieved_autonyms)
  conflicts = @conflict_autonym_sets.find{|conflict_autonym_set|
    (conflict_autonym_set - recieved_autonyms).empty?
  }

  if conflicts
    raise KeyConflictError,
      "conflict conbination thrown: #{conflicts.join(', ')}"
  end

  nil
end

._validate_requirements(*recieved_autonyms) ⇒ nil (private)

Parameters:

  • recieved_autonyms (Array<Symbol>)

Returns:

  • (nil)

Raises:


446
447
448
449
450
451
452
453
454
455
456
# File 'lib/optionalargument/store/singleton_class.rb', line 446

def _validate_requirements(*recieved_autonyms)
  recieved_autonyms.each do |autonym|
    shortage_keys = @requirements.fetch(autonym) - recieved_autonyms
    unless shortage_keys.empty?
      raise MalformedOptionsError,
        "shortage option parameter for #{autonym}: #{shortage_keys.join(', ')}"
    end
  end

  nil
end

._validate_shortage_keys(*recieved_autonyms) ⇒ nil (private)

Parameters:

  • recieved_autonyms (Array<Symbol>)

Returns:

  • (nil)

Raises:


432
433
434
435
436
437
438
439
440
441
# File 'lib/optionalargument/store/singleton_class.rb', line 432

def _validate_shortage_keys(*recieved_autonyms)
  shortage_keys = @must_autonyms - recieved_autonyms
  
  unless shortage_keys.empty?
    raise MalformedOptionsError,
      "shortage option parameter: #{shortage_keys.join(', ')}"
  end

  nil
end

._validate_value(autonym, value) ⇒ value (private)

Parameters:

  • autonym (Symbol)

Returns:

  • (value)

295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
# File 'lib/optionalargument/store/singleton_class.rb', line 295

def _validate_value(autonym, value)
  if has_adjuster? autonym
    adjuster = @adjusters.fetch autonym
    begin
      value = adjuster.call value
    rescue Exception => err
      raise Validation::InvalidAdjustingError, err
    end
  end

  if has_condition? autonym
    condition = @conditions.fetch(autonym)
    
    unless _valid? condition, value
      raise Validation::InvalidWritingError,
        "#{value.inspect} is deficient for #{condition}"
    end
  end

  value
end

.add_conflict(autonym1, autonym2, *autonyms) ⇒ nil (private) Also known as: conflict

Parameters:

  • autonym1 (Symbol, String, #to_sym)
  • autonym2 (Symbol, String, #to_sym)
  • autonyms (Symbol, String, #to_sym)

Returns:

  • (nil)

Raises:

  • (ArgumentError)

234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/optionalargument/store/singleton_class.rb', line 234

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

.add_option(autonym, options = {}) ⇒ nil (private) Also known as: opt, on

Parameters:

  • autonym (Symbol, String, #to_sym)
  • options (Hash) (defaults to: {})

Options Hash (options):

  • :must (Boolean)
  • :default (Object)
  • :aliases (Array<Symbol, String, #to_sym>)
  • :deprecateds (Array<Symbol, String, #to_sym>)
  • :requirements (Array<Symbol, String, #to_sym>)
  • :condition (#===)
  • :adjuster (#call)

Returns:

  • (nil)

185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/optionalargument/store/singleton_class.rb', line 185

def add_option(autonym, options={})
  autonym = autonym.to_sym
  options = DEFAULT_ADD_OPT_OPTIONS.merge options
  KeyValidatable.validate_keys(
    options,
    must: [:must, :aliases, :deprecateds, :requirements],
    let:  [:default, :condition, :adjuster]
  )
  
  if options.has_key? :condition
    _add_condition autonym, options.fetch(:condition)
  end
  
  if options.has_key? :adjuster
    _add_adjuster autonym, options.fetch(:adjuster)
  end
  
  if options.fetch :must
    if options.has_key? :default
      raise KeyConflictError, '"must" conflic with "default"'
    end
    
    _add_must(autonym)
  end

  if options.has_key? :default
    _add_default autonym, options.fetch(:default)
  end

  _add_requirements autonym, options.fetch(:requirements)

  deprecateds = options.fetch :deprecateds

  _add_deprecated(*deprecateds)

  [autonym, *options.fetch(:aliases), *deprecateds].each do |name|
    _add_member autonym, name.to_sym
  end

  nil
end

.aliased?(name) ⇒ Boolean

Parameters:

  • name (Symbol, String, #to_sym)

Returns:

  • (Boolean)

99
100
101
# File 'lib/optionalargument/store/singleton_class.rb', line 99

def aliased?(name)
  member?(name) && !autonym?(name) && !deprecated?(name)
end

.aliasesArray<Symbol>

Returns:

  • (Array<Symbol>)

79
80
81
# File 'lib/optionalargument/store/singleton_class.rb', line 79

def aliases
  @names.each_key.select{|name|aliased? name}
end

.autonym?(name) ⇒ Boolean

Parameters:

  • name (Symbol, String, #to_sym)

Returns:

  • (Boolean)

89
90
91
# File 'lib/optionalargument/store/singleton_class.rb', line 89

def autonym?(name)
  @names.has_value? name.to_sym
end

.autonym_for_name(name) ⇒ Symbol Also known as: autonym_for

Parameters:

  • name (Symbol, String, #to_sym)

Returns:

  • (Symbol)

62
63
64
# File 'lib/optionalargument/store/singleton_class.rb', line 62

def autonym_for_name(name)
  @names.fetch name.to_sym
end

.autonymsArray<Symbol>

Returns - autonym, autonym, …

Returns:

  • (Array<Symbol>)
    • autonym, autonym, ...


69
70
71
# File 'lib/optionalargument/store/singleton_class.rb', line 69

def autonyms
  @names.values.uniq
end

.deprecated?(name) ⇒ Boolean

Parameters:

  • name (Symbol, String, #to_sym)

Returns:

  • (Boolean)

104
105
106
# File 'lib/optionalargument/store/singleton_class.rb', line 104

def deprecated?(name)
  @deprecateds.include? name.to_sym
end

.deprecatedsArray<Symbol>

Returns:

  • (Array<Symbol>)

84
85
86
# File 'lib/optionalargument/store/singleton_class.rb', line 84

def deprecateds
  @deprecateds.dup
end

.has_adjuster?(name) ⇒ Boolean

Parameters:

  • name (Symbol, String, #to_sym)

Returns:

  • (Boolean)

119
120
121
# File 'lib/optionalargument/store/singleton_class.rb', line 119

def has_adjuster?(name)
  member?(name) && @adjusters.has_key?(autonym_for_name(name))
end

.has_condition?(name) ⇒ Boolean

Parameters:

  • name (Symbol, String, #to_sym)

Returns:

  • (Boolean)

114
115
116
# File 'lib/optionalargument/store/singleton_class.rb', line 114

def has_condition?(name)
  member?(name) && @conditions.has_key?(autonym_for_name(name))
end

.has_default?(name) ⇒ Boolean

Parameters:

  • name (Symbol, String, #to_sym)

Returns:

  • (Boolean)

109
110
111
# File 'lib/optionalargument/store/singleton_class.rb', line 109

def has_default?(name)
  member?(name) && @default_values.has_key?(autonym_for_name(name))
end

.member?(name) ⇒ Boolean

Parameters:

  • name (Symbol, String, #to_sym)

Returns:

  • (Boolean)

94
95
96
# File 'lib/optionalargument/store/singleton_class.rb', line 94

def member?(name)
  @names.has_key? name.to_sym
end

.membersArray<Symbol>

Returns:

  • (Array<Symbol>)

74
75
76
# File 'lib/optionalargument/store/singleton_class.rb', line 74

def members
  @names.keys
end

.names_with_autonymHash

for debug

Returns:

  • (Hash)
    • autonym/alias/deprecated => autonym, ...


125
126
127
# File 'lib/optionalargument/store/singleton_class.rb', line 125

def names_with_autonym
  @names.dup
end

.newObject (private)

.parse(options, parsing_options = {}) ⇒ Store Also known as: for_options, for_pairs

Returns instance of a Store's subclass.

Parameters:

  • options (Hash, Struct, #each_pair)
  • parsing_options (Hash) (defaults to: {})

Options Hash (options):

  • :defined_only (Boolean)
  • :exception (Exception)

Returns:

  • (Store)

    instance of a Store's subclass


30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/optionalargument/store/singleton_class.rb', line 30

def parse(options, parsing_options={})
  parsing_options = DEFAULT_PARSE_OPTIONS.merge parsing_options
  KeyValidatable.validate_keys parsing_options,
                               must: [:defined_only, :exception]

  begin
    unless options.respond_to? :each_pair
      raise MalformedOptionsError, 'options must be key-value pairs'
    end

    autonym_hash = _autonym_hash_for options, parsing_options.fetch(:defined_only)
    _scan_hash! autonym_hash

    new autonym_hash
  rescue MalformedOptionsError, Validation::InvalidError => err
    if replacemet = parsing_options.fetch(:exception)
      raise replacemet.new, err
    else
      raise err
    end
  end
end

Instance Method Details

#==(other) ⇒ Boolean Also known as: ===

Returns:

  • (Boolean)

80
81
82
# File 'lib/optionalargument/store.rb', line 80

def ==(other)
  other.instance_of?(__class__) && (other._pairs === @pairs)
end

#[](name) ⇒ Object

Parameters:

  • name (Symbol, String, #to_sym)

36
37
38
# File 'lib/optionalargument/store.rb', line 36

def [](name)
  @pairs[_autonym_for_name name]
end

#_autonym_for_nameSymbol (private)

Parameters:

  • name (Symbol, String, #to_sym)

Returns:

  • (Symbol)

32
33
34
# File 'lib/optionalargument/store.rb', line 32

def autonym_for_name(name)
  __class__.autonym_for_name name
end

#autonym_for_name(name) ⇒ Symbol

Parameters:

  • name (Symbol, String, #to_sym)

Returns:

  • (Symbol)

28
29
30
# File 'lib/optionalargument/store.rb', line 28

def autonym_for_name(name)
  __class__.autonym_for_name name
end

#each_pair {|autonym, value| ... } ⇒ Enumerator

Yields:

  • (autonym, value)

Yield Parameters:

  • autonym (Symbol)

Yield Returns:

  • (self)

Returns:

  • (Enumerator)

58
59
60
61
62
63
# File 'lib/optionalargument/store.rb', line 58

def each_pair(&block)
  return _to_enum(__method__) { @pairs.size } unless block_given?
  
  @pairs.each_pair(&block)
  self
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)

75
76
77
# File 'lib/optionalargument/store.rb', line 75

def eql?(other)
  other.instance_of?(__class__) && (other._pairs.eql? @pairs)
end

#hashInteger

Returns:

  • (Integer)

71
72
73
# File 'lib/optionalargument/store.rb', line 71

def hash
  @pairs.hash
end

#inspectString Also known as: to_s

Returns:

  • (String)

48
49
50
# File 'lib/optionalargument/store.rb', line 48

def inspect
  "#<optargs: #{@pairs.map{|k, v|"#{k}=#{v.inspect}"}.join(', ')}>"
end

#to_hHash

Returns:

  • (Hash)

66
67
68
# File 'lib/optionalargument/store.rb', line 66

def to_h
  @pairs.to_hash.dup
end

#with?(name) ⇒ Boolean Also known as: has_key?

Parameters:

  • name (Symbol, String, #to_sym)

Returns:

  • (Boolean)

41
42
43
# File 'lib/optionalargument/store.rb', line 41

def with?(name)
  @pairs.has_key? _autonym_for_name(name)
end