module Striuct::InstanceMethods

Public Class Methods

new(*values) click to toggle source
# File lib/striuct/instancemethods/object.rb, line 15
def initialize(*values)
  _initialize_database

  replace_values(*values)
  excess_autonyms = _autonyms.last(size - values.size)
  _set_defaults(*excess_autonyms)

  each_autonym do |autonym|
    _check_must(autonym)
  end
end

Public Instance Methods

==(other) click to toggle source

@return [Boolean]

# File lib/striuct/instancemethods/compare.rb, line 8
def ==(other)
  other.instance_of?(self.class) &&
    each_pair.all? { |autonym, val| other._get(autonym) == val }
end
Also aliased as: ===
===(other)
Alias for: ==
[](key)
Alias for: fetch_by_key
[]=(key, value) click to toggle source

@param [Symbol, String, to_sym, Integer, to_int] key - name / index @return value

# File lib/striuct/instancemethods/setter.rb, line 9
def []=(key, value)
  autonym = autonym_for_key(key)
  _set(autonym, value)
rescue InvalidWritingError
  $!.set_backtrace(
    ["#{$!.backtrace[-1].sub(/[^:]+\z/) { '' }}in `[#{key.inspect}(#{autonym})]=': #{$!.message}", $!.backtrace[-1]]
  )

  raise
end
Also aliased as: assign
_valid?(pattern, value) click to toggle source

@param [Proc, Method, ===] pattern @param [Object] value

# File lib/striuct/instancemethods/validation.rb, line 9
def _valid?(pattern, value)
  !!(
    case pattern
    when Proc
      instance_exec(value, &pattern)
    when Method
      pattern.call(value)
    else
      pattern === value
    end
  )
end
accept?(key, value) click to toggle source

@param [Symbol, String, to_sym, Integer, to_int] key - name / index @param value true if passed under any condition

# File lib/striuct/instancemethods/validation.rb, line 25
def accept?(key, value)
  autonym = autonym_for_key(key)
  return true unless restrict?(autonym)

  begin
    _valid?(condition_for(autonym), value)
  rescue Exception
    false
  end
end
all_locked?() click to toggle source
# File lib/striuct/instancemethods/lock.rb, line 30
def all_locked?
  _autonyms.all? { |autonym| @locks.key?(autonym) }
end
assign(key, value)
Alias for: []=
assign?(key)
Alias for: assigned?
assigned?(key) click to toggle source

@param [Symbol, String, to_sym, Integer, to_int] key - name / index

# File lib/striuct/instancemethods/assign.rb, line 8
def assigned?(key)
  @db.key?(autonym_for_key(key))
end
Also aliased as: assign?
assoc(name) click to toggle source

@param [Symbol, String] name @return [Array] e.g [autonym, value]

# File lib/striuct/instancemethods/hashy.rb, line 81
def assoc(name)
  autonym = autonym_for_member(name)

  [autonym, self[name]]
end
default?(key) click to toggle source

@param [Symbol, String, to_sym, Integer, to_int] key - name / index

# File lib/striuct/instancemethods/default.rb, line 8
def default?(key)
  autonym = autonym_for_key(key)

  default_value_for(autonym) == fetch_by_autonym(autonym)
end
delete_at(key)
Alias for: unassign
delete_if(&block) click to toggle source

@see reject! @yield [autonym, value] @yieldparam [Symbol] autonym @return [Enumerator]

# File lib/striuct/instancemethods/hashy.rb, line 71
def delete_if(&block)
  _check_frozen
  return to_enum(__callee__) unless block

  reject!(&block)
  self
end
each()
Alias for: each_value
each_autonym(&block) click to toggle source

@yield [autonym] @yieldparam [Symbol] autonym - sequential under defined @yieldreturn [self] @return [Enumerator]

# File lib/striuct/instancemethods/enum.rb, line 11
def each_autonym(&block)
  return to_enum(__callee__) { self.class.size } unless block

  self.class.each_autonym(&block)
  self
end
Also aliased as: each_member
each_autonym_with_index() { |autonym, index| ... } click to toggle source

@yield [autonym, index] @yieldparam [Symbol] autonym @yieldparam [Integer] index @yieldreturn [self] @return [Enumerator]

# File lib/striuct/instancemethods/enum.rb, line 62
def each_autonym_with_index
  return to_enum(__callee__) { self.class.size } unless block_given?

  self.class.each_autonym_with_index { |autonym, index| yield autonym, index }
  self
end
Also aliased as: each_member_with_index
each_index() { |index| ... } click to toggle source

@yield [index] @yieldparam [Integer] index @yieldreturn [self] @return [Enumerator]

# File lib/striuct/instancemethods/enum.rb, line 50
def each_index
  return to_enum(__callee__) { self.class.size } unless block_given?

  self.class.each_index { |index| yield index }
  self
end
each_member(&block)
Alias for: each_autonym
each_member_with_index()
each_pair() { |autonym, _get(autonym)| ... } click to toggle source

@yield [autonym, value] @yieldparam [Symbol] autonym @yieldparam [Object] value @yieldreturn [self] @return [Enumerator] @see each_autonym @see each_value

# File lib/striuct/instancemethods/enum.rb, line 40
def each_pair
  return to_enum(__callee__) { self.class.size } unless block_given?

  each_autonym { |autonym| yield autonym, _get(autonym) }
end
each_pair_with_index() { |autonym, value, index| ... } click to toggle source

@yield [autonym, value, index] @yieldparam [Symbol] autonym @yieldparam [Integer] index @yieldreturn [self] @return [Enumerator]

# File lib/striuct/instancemethods/enum.rb, line 88
def each_pair_with_index
  return to_enum(__callee__) { self.class.size } unless block_given?

  index = 0
  each_pair do |autonym, value|
    yield autonym, value, index
    index += 1
  end
end
each_value() { |_get(autonym)| ... } click to toggle source

@yield [value] @yieldparam [Object] value - sequential under defined @see each_autonym @yieldreturn [self] @return [Enumerator]

# File lib/striuct/instancemethods/enum.rb, line 25
def each_value
  return to_enum(__callee__) { self.class.size } unless block_given?

  each_autonym { |autonym| yield _get(autonym) }
end
Also aliased as: each
each_value_with_index() { |value, index| ... } click to toggle source

@yield [value, index] @yieldparam [Integer] index @yieldreturn [self] @return [Enumerator]

# File lib/striuct/instancemethods/enum.rb, line 75
def each_value_with_index
  return to_enum(__callee__) { self.class.size } unless block_given?

  each_value.with_index { |value, index| yield value, index }
end
Also aliased as: each_with_index
each_with_index()
empty?() click to toggle source

true if all members are not yet assigned

# File lib/striuct/instancemethods/assign.rb, line 29
def empty?
  _autonyms.none? { |autonym| @db.key?(autonym) }
end
eql?(other) click to toggle source
# File lib/striuct/instancemethods/compare.rb, line 15
def eql?(other)
  other.instance_of?(self.class) && other._db.eql?(@db)
end
fetch(key)
Alias for: fetch_by_key
fetch_by_autonym(autonym) click to toggle source

@param [Symbol, String, to_sym] autonym

# File lib/striuct/instancemethods/getter.rb, line 8
def fetch_by_autonym(autonym)
  autonym = autonym.to_sym
  raise NameError unless autonym?(autonym)

  _get(autonym)
end
fetch_by_index(index) click to toggle source

@param [Integer, to_int] index

# File lib/striuct/instancemethods/getter.rb, line 21
def fetch_by_index(index)
  _get(autonym_for_index(index))
end
fetch_by_key(key) click to toggle source

@param [Symbol, String, to_sym, Integer, to_int] key - name / index

# File lib/striuct/instancemethods/getter.rb, line 26
def fetch_by_key(key)
  _get(autonym_for_key(key))
end
Also aliased as: [], fetch
fetch_by_member(member) click to toggle source

@param [Symbol, String, to_sym] member

# File lib/striuct/instancemethods/getter.rb, line 16
def fetch_by_member(member)
  _get(autonym_for_member(member))
end
fetch_values(*keys) { || ... } click to toggle source

@return [Array] @raise [ArgumentError] if the keys contains an unmatched

key and no block is given
# File lib/striuct/instancemethods/values.rb, line 31
def fetch_values(*keys, &block)
  keys.map { |key|
    if key?(key)
      fetch_by_key(key)
    else
      if block
        yield
      else
        raise ArgumentError, "`#{key}' is not matched"
      end
    end
  }
end
flatten(level=1) click to toggle source

@see Hash#flatten @return [Array]

# File lib/striuct/instancemethods/hashy.rb, line 94
def flatten(level=1)
  each_pair.to_a.flatten(level)
end
freeze() click to toggle source

@return [self]

Calls superclass method
# File lib/striuct/instancemethods/object.rb, line 8
def freeze
  @db.freeze; @locks.freeze
  super
end
has_value?(value) click to toggle source

@group Like Ruby's Hash

# File lib/striuct/instancemethods/hashy.rb, line 7
def has_value?(value)
  @db.value?(value)
end
Also aliased as: value?
hash() click to toggle source

@return [Integer]

# File lib/striuct/instancemethods/compare.rb, line 20
def hash
  @db.hash
end
inspect() click to toggle source

@return [String]

# File lib/striuct/instancemethods/to_s.rb, line 8
def inspect
  (+"#<struct' #{self.class}").tap { |s|
    each_pair do |autonym, value|
      suffix = (with_default?(autonym) && default?(autonym)) ? '/default' : nil
      label_valid = valid?(autonym) ? nil : :invalid
      label_lock = locked?(autonym) ? :locked : nil
      label_must = must?(autonym) ? :must : nil
      labels = [label_valid, label_lock, label_must].select { |elm| elm }

      s << " #{autonym}=#{value.inspect}#{suffix}"
      unless labels.empty?
        s << '('
        s << labels.join(', ')
        s << ')'
      end
      s << ','
    end

    s.chop!
    s << '>'
  }
end
keep_if(&block) click to toggle source

@see select! @yield [autonym, value] @yieldparam [Symbol] autonym @return [Enumerator]

# File lib/striuct/instancemethods/hashy.rb, line 39
def keep_if(&block)
  _check_frozen
  return to_enum(__callee__) unless block

  select!(&block)
  self
end
lock(key) click to toggle source

@param [Symbol, String, to_sym, Integer, to_int] key - name / index @return [self]

# File lib/striuct/instancemethods/lock.rb, line 9
def lock(key)
  _check_frozen

  @locks[autonym_for_key(key)] = true
  self
end
lock_all() click to toggle source

@return [self]

# File lib/striuct/instancemethods/lock.rb, line 17
def lock_all
  _check_frozen

  each_autonym do |autonym|
    @locks[autonym] = true
  end
end
locked?(key) click to toggle source

@param [Symbol, String, to_sym, Integer, to_int] key - name / index

# File lib/striuct/instancemethods/lock.rb, line 26
def locked?(key)
  @locks.key?(autonym_for_key(key))
end
rassoc(value) click to toggle source

@return [Array] [autonym, value]

# File lib/striuct/instancemethods/hashy.rb, line 88
def rassoc(value)
  each_pair.find { |_, val| val == value }
end
reject(&block) click to toggle source

@see reject! @yield [autonym, value] @yieldparam [Symbol] autonym @return [Striuct]

# File lib/striuct/instancemethods/hashy.rb, line 112
def reject(&block)
  return to_enum(__callee__) unless block

  dup.tap { |r| r.reject!(&block) }
end
reject!() { |autonym, value| ... } click to toggle source

@see select! keep falsy only (unassign truthy member) @yield [autonym, value] @yieldparam [Symbol] autonym @return [Enumerator]

# File lib/striuct/instancemethods/hashy.rb, line 52
def reject!
  _check_frozen
  return to_enum(__callee__) unless block_given?

  modified = false
  each_pair do |autonym, value|
    if yield autonym, value
      unassign(autonym)
      modified = true
    end
  end

  modified ? self : nil
end
replace_values(*values) click to toggle source

@return [self]

# File lib/striuct/instancemethods/values.rb, line 46
def replace_values(*values)
  unless values.size <= size
    raise ArgumentError, "struct size differs (max: #{size})"
  end

  values.each_with_index do |value, index|
    _set(autonym_for_index(index), value)
  end

  self
end
secure?() click to toggle source

freezed, fixed familiar members, all members passed any condition

# File lib/striuct/instancemethods/safety.rb, line 8
def secure?
  (frozen? || all_locked?) && self.class.closed? && strict?
end
select(&block) click to toggle source

@see select! @yield [autonym, value] @yieldparam [Symbol] autonym @return [Striuct]

# File lib/striuct/instancemethods/hashy.rb, line 102
def select(&block)
  return to_enum(__callee__) unless block

  dup.tap { |r| r.select!(&block) }
end
select!() { |autonym, value| ... } click to toggle source

keep truthy only (unassign falsy member) @yield [autonym, value] @yieldparam [Symbol] autonym @see each_pair @return [Enumerator] @yieldreturn [self] @yieldreturn [nil]

# File lib/striuct/instancemethods/hashy.rb, line 20
def select!
  _check_frozen
  return to_enum(__callee__) unless block_given?

  modified = false
  each_pair do |autonym, value|
    unless yield autonym, value
      unassign(autonym)
      modified = true
    end
  end

  modified ? self : nil
end
strict?() click to toggle source

all members passed under any condition

# File lib/striuct/instancemethods/validation.rb, line 46
def strict?
  each_pair.all? { |autonym, value| sufficient?(autonym, value) }
end
sufficient?(key, value=self[key]) click to toggle source

@param [Symbol, String, to_sym, Integer, to_int] key - name / index @param value - if no argument and use current assigned value true if passed under any condition

# File lib/striuct/instancemethods/validation.rb, line 39
def sufficient?(key, value=self[key])
  accept?(key, value)
end
Also aliased as: valid?
to_a()
Alias for: values
to_h(include_no_assign: true) click to toggle source

@param [Boolean] include_no_assign @return [Hash]

# File lib/striuct/instancemethods/cast.rb, line 19
def to_h(include_no_assign: true)
  return @db.dup unless include_no_assign

  each_pair.to_a.to_h
end
to_s() click to toggle source

@return [String]

# File lib/striuct/instancemethods/to_s.rb, line 32
def to_s
  (+"#<struct' #{self.class}").tap { |s|
    each_pair do |autonym, value|
      s << " #{autonym}=#{value.inspect},"
    end

    s.chop!
    s << '>'
  }
end
to_striuct() click to toggle source

@return [self]

# File lib/striuct/instancemethods/cast.rb, line 8
def to_striuct
  self
end
to_struct() click to toggle source

@return [Struct]

# File lib/striuct/instancemethods/cast.rb, line 13
def to_struct
  self.class.to_struct_class.new(*values)
end
unassign(key) click to toggle source

@param [Symbol, String, to_sym, Integer, to_int] key - name / index @return value / nil - value assigned under the key

# File lib/striuct/instancemethods/assign.rb, line 16
def unassign(key)
  _check_frozen
  _check_locked(key)
  if must?(key)
    raise InvalidOperationError, "`#{key}` require a value under `must` option"
  end

  @db.delete(autonym_for_key(key))
end
Also aliased as: delete_at
valid?(key, value=self[key])
Alias for: sufficient?
value?(value)
Alias for: has_value?
values() click to toggle source

@return [Array]

# File lib/striuct/instancemethods/cast.rb, line 26
def values
  each_value.to_a
end
Also aliased as: to_a
values_at(*keys) click to toggle source

@param [Integer, to_int, Range] keys @return [Array]

# File lib/striuct/instancemethods/values.rb, line 9
def values_at(*keys)
  [].tap { |r|
    keys.each do |key|
      case key
      when ->v { v.respond_to?(:to_int) }
        r << fetch_by_index(key)
      when Range
        key.each do |idx|
          raise TypeError unless idx.respond_to?(:to_int)

          r << fetch_by_index(idx)
        end
      else
        raise TypeError
      end
    end
  }
end

Protected Instance Methods

_db() click to toggle source
# File lib/striuct/instancemethods/compare.rb, line 26
def _db
  @db
end
_get(autonym) click to toggle source

@param [Symbol] autonym - MUST already converted to native autonym

# File lib/striuct/instancemethods/getter.rb, line 36
def _get(autonym)
  value = @db[autonym]

  if with_safety_getter?(autonym) && !accept?(autonym, value)
    raise InvalidReadingError,
          "#{value.inspect} is deficient for #{autonym} in #{self.class}"
  end

  value
end

Private Instance Methods

_autonyms() click to toggle source
# File lib/striuct/instancemethods/delegate_class_methods.rb, line 33
def _autonyms
  self.class.__send__(:_autonyms)
end
_check_frozen() click to toggle source
# File lib/striuct/instancemethods/object.rb, line 52
def _check_frozen
  raise "can't modify frozen #{self.class}" if frozen?
end
_check_locked(key) click to toggle source
# File lib/striuct/instancemethods/object.rb, line 56
def _check_locked(key)
  raise "can't modify locked member `#{key}`" if locked?(key)
end
_check_must(key) click to toggle source
# File lib/striuct/instancemethods/object.rb, line 60
def _check_must(key)
  if must?(key) && !assigned?(key)
    raise InvalidOperationError, "`#{key}` require a value under `must` option"
  end
end
_initialize_database() click to toggle source
# File lib/striuct/instancemethods/object.rb, line 48
def _initialize_database
  @db, @locks = {}, {}
end
_set(autonym, value) click to toggle source

@param [Symbol] autonym - MUST already converted to native autonym @return value

# File lib/striuct/instancemethods/setter.rb, line 26
def _set(autonym, value)
  _check_frozen
  _check_locked(autonym)

  if with_adjuster?(autonym)
    begin
      value = instance_exec(value, &adjuster_for(autonym))
    rescue Exception
      raise InvalidAdjustingError
    end
  end

  if with_safety_setter?(autonym) && !accept?(autonym, value)
    raise InvalidWritingError,
          "#{value.inspect} is deficient for #{autonym} in #{self.class}"
  end

  @db[autonym] = value
rescue InvalidValueError
  unless /in \[\]=/.match?(caller(2..2).first.slice(/([^:]+)\z/))
    $!.backtrace.delete_if { |s| /#{Regexp.escape(File.dirname(__FILE__))}/ =~ s }
    $!.backtrace.first.sub!(/([^:]+)\z/) { "in `#{autonym}='" }
  end

  raise
end
_set_defaults(*target_autonyms) click to toggle source

@param [Symbol] target_autonyms - MUST already converted to native autonym @return [self]

# File lib/striuct/instancemethods/default.rb, line 18
def _set_defaults(*target_autonyms)
  target_autonyms.each do |autonym|
    if with_default?(autonym)
      default = default_value_for(autonym)
      _set(autonym, (
        if default_type_for(autonym) == :lazy
          args = [self, autonym][0, default.arity]
          default.call(*args)
        else
          default
        end
      ))
    end
  end

  self
end
initialize_copy(original) click to toggle source
# File lib/striuct/instancemethods/object.rb, line 44
def initialize_copy(original)
  @db, @locks = @db.dup, {}
end
initialize_for_pairs(pairs) click to toggle source
# File lib/striuct/instancemethods/object.rb, line 27
def initialize_for_pairs(pairs)
  _initialize_database

  excess_autonyms = _autonyms.dup
  pairs.each_pair do |key, value|
    autonym = autonym_for_key(key)
    self[autonym] = value
    excess_autonyms.delete(autonym)
  end

  _set_defaults(*excess_autonyms)

  excess_autonyms.each do |autonym|
    _check_must(autonym)
  end
end
unlock(key) click to toggle source

@param [Symbol, String, to_sym, Integer, to_int] key - name / index @return [self]

# File lib/striuct/instancemethods/lock.rb, line 38
def unlock(key)
  _check_frozen

  @locks.delete(autonym_for_key(key))
  self
end
unlock_all() click to toggle source

@return [self]

# File lib/striuct/instancemethods/lock.rb, line 46
def unlock_all
  _check_frozen

  @locks.clear
  self
end