module Striuct::ClassMethods
Constants
- ANYTHING
@group Macro for Member Definition
- CONFLICT_MANAGEMENT_LEVELS
@return [Hash] Symbol => Hash
- DEFAULT_CONFLICT_MANAGEMENT_LEVEL
@return [Symbol]
- NAMING_RISKS
@return [Hash] Symbol => Fixnum
Attributes
Public Instance Methods
Sequential apply all adjusters. @param adjuster1 [Proc, to_proc] @param adjuster2 [Proc, to_proc] @param adjusters [Proc, to_proc] @return [Proc]
# File lib/striuct/classmethods/adjustment.rb, line 29 def INJECT(adjuster1, adjuster2, *adjusters) adjusters = [adjuster1, adjuster2, *adjusters] unless adjusters.all? { |f| adjustable?(f) } raise ArgumentError, 'wrong object for adjuster' end ->v { adjusters.reduce(v) { |ret, adjuster| adjuster.call(ret) } } end
Accept any parser when that respond to parse method. @param parser [#parse] @return [Proc]
# File lib/striuct/classmethods/adjustment.rb, line 44 def PARSE(parser) if !::Integer.equal?(parser) && !parser.respond_to?(:parse) raise ArgumentError, 'wrong object for parser' end ->v { if ::Integer.equal?(parser) ::Kernel.Integer(v) else parser.parse( case v when String v when ->_ { v.respond_to?(:to_str) } v.to_str when ->_ { v.respond_to?(:read) } v.read else raise TypeError, 'wrong object for parsing source' end ) end } end
Adjuster Builders Apply adjuster when passed pattern. @param pattern [Proc, Method, ===] @param adjuster [Proc, to_proc] @return [Proc]
# File lib/striuct/classmethods/adjustment.rb, line 12 def WHEN(pattern, adjuster) unless Eqq.valid?(pattern) raise ArgumentError, 'wrong object for pattern' end unless Striuct.adjustable?(adjuster) raise ArgumentError, 'wrong object for adjuster' end ->v { _valid?(pattern, v) ? adjuster.call(v) : v } end
@param [Symbol, String, to_sym, Integer, to_int] key - name / index
# File lib/striuct/classmethods/adjustment.rb, line 70 def adjuster_for(key) autonym = autonym_for_key(key) raise KeyError unless with_adjuster?(autonym) _attributes_for(autonym).adjuster end
@return [Hash] alias => autonym
# File lib/striuct/classmethods/names.rb, line 65 def aliases @aliases.dup end
@param [Symbol, String, to_sym] autonym @return [Array<Symbol>]
# File lib/striuct/classmethods/names.rb, line 55 def aliases_for_autonym(autonym) raise TypeError unless autonym.respond_to?(:to_sym) autonym = autonym.to_sym raise NameError unless with_aliases?(autonym) @aliases.select { |_als, aut| autonym == aut }.keys end
@return [Array<Symbol>]
# File lib/striuct/classmethods/names.rb, line 15 def all_members @autonyms + @aliases.keys end
for debug @return [Hash]
# File lib/striuct/classmethods/inner.rb, line 9 def attributes { autonyms: @autonyms.dup, aliases: @aliases.dup, conflict_management_level: @conflict_management_level, attributes_each_autonym: @attributes.dup } end
@param [Symbol, String, to_sym] als @return [Symbol]
# File lib/striuct/classmethods/names.rb, line 21 def autonym_for_alias(als) @aliases.fetch(als.to_sym) rescue NoMethodError raise TypeError rescue KeyError raise NameError end
@param [Index, to_int] index @return [Symbol] autonym
# File lib/striuct/classmethods/names.rb, line 41 def autonym_for_index(index) @autonyms.fetch(index) end
@param [Symbol, String, to_sym, Integer, to_int] key - name / index @return [Symbol] autonym
# File lib/striuct/classmethods/names.rb, line 47 def autonym_for_key(key) key.respond_to?(:to_sym) ? autonym_for_member(key) : autonym_for_index(key) rescue NameError, IndexError, TypeError raise KeyError end
@param [Symbol, String, to_sym] name - autonym / aliased @return [Symbol]
# File lib/striuct/classmethods/names.rb, line 31 def autonym_for_member(name) raise TypeError unless name.respond_to?(:to_sym) name = name.to_sym @autonyms.include?(name) ? name : autonym_for_alias(name) end
@return [Array<Symbol>]
# File lib/striuct/classmethods/names.rb, line 8 def autonyms @autonyms.dup end
@return [Class]
# File lib/striuct/classmethods/copy.rb, line 8 def clone ret = super ret.__send__(:close_member) if closed? ret end
# File lib/striuct/classmethods/fix.rb, line 13 def closed? [@autonyms, @attributes, @aliases].any?(&:frozen?) end
@param [Object] name acceptable the name into own member, under protect level of runtime
# File lib/striuct/classmethods/conflict_management.rb, line 30 def cname?(name) _check_safety_naming(name.to_sym) { |r| r } rescue Exception false end
@param [Symbol, String, to_sym, Integer, to_int] key - name / index
# File lib/striuct/classmethods/validation.rb, line 8 def condition_for(key) autonym = autonym_for_key(key) raise KeyError unless with_condition?(autonym) _attributes_for(autonym).condition end
@param [Symbol, String, to_sym, Integer, to_int] key - name / index @return [Symbol] :value / :proc
# File lib/striuct/classmethods/default.rb, line 17 def default_type_for(key) autonym = autonym_for_key(key) raise KeyError unless with_default?(autonym) _attributes_for(autonym).default_type end
@param [Symbol, String, to_sym, Integer, to_int] key - name / index
# File lib/striuct/classmethods/default.rb, line 8 def default_value_for(key) autonym = autonym_for_key(key) raise KeyError unless with_default?(autonym) _attributes_for(autonym).default_value end
for build the fixed object @param [Boolean] lock @param [Boolean] strict @yieldparam [Striuct] instance @yieldreturn [Striuct] instance @return [void]
# File lib/striuct/classmethods/constructor.rb, line 33 def define(lock: true, strict: true) raise ArgumentError, 'must with block' unless block_given? new.tap { |instance| yield instance yets = autonyms.select { |autonym| !instance.assigned?(autonym) } unless yets.empty? raise "not assigned members are, yet '#{yets.inspect} in #{self}'" end invalids = autonyms.select { |autonym| !instance.valid?(autonym) } if strict && !invalids.empty? raise InvalidWritingError, "invalids members are, yet '#{invalids.inspect} in #{self}'" end instance.lock_all if lock } end
@return [Class]
# File lib/striuct/classmethods/copy.rb, line 15 def dup copy_variables!(super) end
@yield [autonym] @yieldparam [Symbol] autonym - sequential under defined @yieldreturn [Class] self @return [Enumerator]
# File lib/striuct/classmethods/enum.rb, line 11 def each_autonym return to_enum(__callee__) { size } unless block_given? @autonyms.each { |autonym| yield autonym } self end
@yield [autonym, index] @yieldparam [Symbol] autonym @yieldparam [Integer] index @yieldreturn [Class] self @return [Enumerator]
# File lib/striuct/classmethods/enum.rb, line 36 def each_autonym_with_index return to_enum(__callee__) { size } unless block_given? @autonyms.each_with_index { |autonym, index| yield autonym, index } self end
@yield [index] @yieldparam [Integer] Index @yieldreturn [Class] self @return [Enumerator]
# File lib/striuct/classmethods/enum.rb, line 24 def each_index return to_enum(__callee__) { size } unless block_given? @autonyms.each_index { |index| yield index } self end
@param [Hash, Struct, Striuct
, each_pair] pairs @return [Striuct]
# File lib/striuct/classmethods/constructor.rb, line 16 def for_pairs(pairs) raise ArgumentError, 'no pairs object' unless pairs.respond_to?(:each_pair) raise ArgumentError unless pairs.each_pair { |key, _value| all_members.include?(key.to_sym) } instance = allocate instance.__send__(:initialize_for_pairs, pairs) instance end
@return [Striuct]
# File lib/striuct/classmethods/constructor.rb, line 8 def for_values(*values) new_instance(*values) end
@return [self]
# File lib/striuct/classmethods/fix.rb, line 8 def freeze [@autonyms, @attributes, @aliases].each(&:freeze) super end
@param [Symbol, String, to_sym] als
# File lib/striuct/classmethods/predicate.rb, line 19 def has_alias?(als) als = als.to_sym rescue NoMethodError false else @aliases.key?(als) end
@param [Symbol, String, to_sym] name
# File lib/striuct/classmethods/predicate.rb, line 8 def has_autonym?(name) name = name.to_sym rescue NoMethodError false else @autonyms.include?(name) end
@param [Integer, to_int] index
# File lib/striuct/classmethods/predicate.rb, line 42 def has_index?(index) @autonyms.fetch(index) rescue Exception false else true end
@param [Symbol, String, to_sym, Integer, to_int] key - name / index
# File lib/striuct/classmethods/predicate.rb, line 53 def has_key?(key) has_member?(key) || has_index?(key) end
@param [Symbol, String, to_sym] name
# File lib/striuct/classmethods/predicate.rb, line 31 def has_member?(name) autonym_for_member(name) rescue Exception false else true end
@return [Integer]
# File lib/striuct/classmethods/length.rb, line 8 def length @autonyms.length end
@return [Class]
# File lib/striuct/classmethods/to_struct.rb, line 8 def to_struct_class raise 'No defined members' if autonyms.empty? struct_cls = ::Struct.new(*autonyms) return struct_cls unless name const_suffix = name.slice(/[^:]+\z/).to_sym if ::Striuct::Structs.const_defined?(const_suffix, false) && (already_cls = ::Striuct::Structs.const_get(const_suffix, false)).members == autonyms raise unless already_cls.superclass.equal?(Struct) already_cls else ::Striuct::Structs.const_set(const_suffix, struct_cls) end end
@param [Symbol, String, to_sym, Integer, to_int] key - name / index
# File lib/striuct/classmethods/predicate.rb, line 122 def with_adjuster?(key) autonym = autonym_for_key(key) rescue Exception false else _attributes_for(autonym).with_adjuster? end
@param [Symbol, String, to_sym] autonym
# File lib/striuct/classmethods/predicate.rb, line 60 def with_aliases?(autonym) autonym = autonym.to_sym rescue NoMethodError false else @aliases.value?(autonym) end
@param [Symbol, String, to_sym, Integer, to_int] key - name / index
# File lib/striuct/classmethods/predicate.rb, line 78 def with_condition?(key) autonym = autonym_for_key(key) rescue Exception false else _attributes_for(autonym).with_condition? end
@param [Symbol, String, to_sym, Integer, to_int] key - name / index
# File lib/striuct/classmethods/predicate.rb, line 69 def with_default?(key) autonym = autonym_for_key(key) rescue Exception false else _attributes_for(autonym).with_default? end
@param [Symbol, String, to_sym, Integer, to_int] key - name / index
# File lib/striuct/classmethods/predicate.rb, line 89 def with_must?(key) autonym = autonym_for_key(key) rescue Exception false else _attributes_for(autonym).with_must? end
@param [Symbol, String, to_sym, Integer, to_int] key - name / index
# File lib/striuct/classmethods/predicate.rb, line 100 def with_safety_getter?(key) autonym = autonym_for_key(key) rescue Exception false else _attributes_for(autonym).with_safety_getter? end
@param [Symbol, String, to_sym, Integer, to_int] key - name / index
# File lib/striuct/classmethods/predicate.rb, line 111 def with_safety_setter?(key) autonym = autonym_for_key(key) rescue Exception false else _attributes_for(autonym).with_safety_setter? end
Private Instance Methods
# File lib/striuct/classmethods/inner.rb, line 27 def _add_autonym(autonym) autonym = autonym.to_sym raise NameError, 'already defined' if member?(autonym) @attributes[autonym] = Attributes.new @autonyms << autonym end
# File lib/striuct/classmethods/inner.rb, line 35 def _attributes_for(autonym) @attributes.fetch(autonym) end
for direct access inner data from own instance @return [Hash] alias => autonym
# File lib/striuct/classmethods/names.rb, line 73 def _autonyms @autonyms end
# File lib/striuct/classmethods/inner.rb, line 43 def _check_closed raise "can't modify closed member attributes in #{self}" if closed? end
# File lib/striuct/classmethods/inner.rb, line 39 def _check_frozen raise "can't modify frozen Class" if frozen? end
@param [Symbol] name @return [void] @yieldreturn [Boolean]
# File lib/striuct/classmethods/conflict_management.rb, line 69 def _check_safety_naming(name) estimation = _estimate_naming(name) risk = NAMING_RISKS.fetch(estimation) plevels = CONFLICT_MANAGEMENT_LEVELS.fetch(@conflict_management_level) caution = "undesirable naming '#{name}', because #{estimation}" r = ( case when risk >= plevels.fetch(:error) raise NameError, caution unless block_given? false when risk >= plevels.fetch(:warn) warn(caution) unless block_given? false else true end ) yield r if block_given? end
# File lib/striuct/classmethods/inner.rb, line 47 def _def_getter(autonym) define_method(autonym) do _get(autonym) end nil end
# File lib/striuct/classmethods/inner.rb, line 55 def _def_setter(autonym, condition, &adjuster) unless ANYTHING.equal?(condition) _attributes_for(autonym).condition = condition end if adjuster _attributes_for(autonym).adjuster = adjuster end define_method(:"#{autonym}=") do |value| _set(autonym, value) end nil end
@param [Symbol] name @return [Symbol]
# File lib/striuct/classmethods/conflict_management.rb, line 94 def _estimate_naming(name) if (instance_methods + private_instance_methods).include?(name) return :conflict end return :no_ascii unless name.encoding.equal?(Encoding::ASCII) case name when /\W/, /\A[^a-zA-Z_]/, :'' :no_identifier when /\Aeach/, /\A__[^_]*__\z/, /\A_[^_]*\z/, /[!?]\z/, /\Ato_/ :bad_manners when /\A[a-zA-Z_]\w*\z/ :strict else raise 'must not happen' end end
# File lib/striuct/classmethods/inner.rb, line 20 def _init @autonyms = [] @attributes = {}.extend HashDeepDupulicatable # autonym => Attributes @aliases = {} # aliased => autonym @conflict_management_level = DEFAULT_CONFLICT_MANAGEMENT_LEVEL end
@param [Symbol, String, to_sym] autonym @param [#===, Proc, Method] pattern @param [Proc] default_proc @param [Boolean] must @param [Boolean] writer_validation @param [Boolean] reader_validation @return [void]
# File lib/striuct/classmethods/macro.rb, line 20 def add_member(autonym, pattern=ANYTHING, default_value: nil, default_proc: nil, must: false, writer_validation: true, reader_validation: false, &adjuster) _check_frozen _check_closed raise ArgumentError if !default_value.nil? && default_proc autonym = autonym.to_sym # First definition for an autonym raise ArgumentError, %Q!already exist name "#{autonym}"! if member?(autonym) _check_safety_naming(autonym) _add_autonym(autonym) _attributes_for(autonym).safety_setter = writer_validation _attributes_for(autonym).safety_getter = reader_validation if must _attributes_for(autonym).must = true end _def_getter(autonym) _def_setter(autonym, pattern, &adjuster) case when !default_value.nil? set_default_value(autonym, default_value) when default_proc set_default_value(autonym, &default_proc) end nil end
@param [Symbol, String, to_sym] autonym @param [Symbol, String, to_sym] autonyms @return [nil]
# File lib/striuct/classmethods/macro.rb, line 58 def add_members(autonym, *autonyms) _check_frozen _check_closed [autonym, *autonyms].each { |name| add_member(name) } nil end
@param [Symbol, String, to_sym] aliased @param [Symbol, String, to_sym] autonym @return [nil]
# File lib/striuct/classmethods/macro.rb, line 69 def alias_member(aliased, autonym) _check_frozen _check_closed autonym = autonym_for_member(autonym) aliased = aliased.to_sym raise ArgumentError, %Q!already exist name "#{aliased}"! if member?(aliased) _check_safety_naming(aliased) alias_method(aliased, autonym) alias_method(:"#{aliased}=", :"#{autonym}=") @aliases[aliased] = autonym nil end
@return [self]
# File lib/striuct/classmethods/fix.rb, line 20 def close_member [@autonyms, @attributes, @aliases].each(&:freeze) self end
@param [Symbol, String, to_sym] level @see [#set_conflict_management_level] @yieldreturn [self] @return [void] @raise [ArgumentError] if no block given temp scope of a conflict_management_level
# File lib/striuct/classmethods/conflict_management.rb, line 56 def conflict_management(level=DEFAULT_CONFLICT_MANAGEMENT_LEVEL) before = @conflict_management_level set_conflict_management_level(level) yield ensure @conflict_management_level = before self end
@return [familiar_class]
# File lib/striuct/classmethods/copy.rb, line 36 def copy_variables!(familiar_class) autonyms = @autonyms.dup aliases = @aliases.dup attributes = @attributes.deep_dup conflict_management = @conflict_management_level familiar_class.class_eval do @autonyms = autonyms @aliases = aliases @attributes = attributes @conflict_management_level = conflict_management end familiar_class end
# File lib/striuct/classmethods/copy.rb, line 21 def inherited(subclass) ret = super(subclass) copy_variables!(subclass) ret end
# File lib/striuct/classmethods/copy.rb, line 27 def initialize_copy(original) ret = super(original) @autonyms = @autonyms.dup @aliases = @aliases.dup @attributes = @attributes.deep_dup ret end
@param [Symbol, String, to_sym] level @return [Symbol] level change level of management conflict member names
# File lib/striuct/classmethods/conflict_management.rb, line 43 def set_conflict_management_level(level) level = level.to_sym raise NameError unless CONFLICT_MANAGEMENT_LEVELS.key?(level) @conflict_management_level = level end
@param [Symbol, String, to_sym] name @return [nil]
# File lib/striuct/classmethods/macro.rb, line 86 def set_default_value(name, value=nil, &block) _check_frozen _check_closed autonym = autonym_for_member(name) raise "already settled default value for #{name}" if with_default?(autonym) if block unless value.nil? raise ArgumentError, 'can not use default-value with default-proc' end _attributes_for(autonym).set_default(block, :lazy) else _attributes_for(autonym).set_default(value, :value) end nil end