class Algebrick::ProductVariant
Representation of Product and Variant types. The class behaves differently based on #kind.
noinspection RubyTooManyMethodsInspection
Attributes
fields[R]
variants[R]
Public Class Methods
new(name, &definition)
click to toggle source
Calls superclass method
# File lib/algebrick/product_variant.rb, line 26 def initialize(name, &definition) super(name, &definition) @to_be_kind_of = [] @final_variants = false end
Public Instance Methods
==(other)
click to toggle source
# File lib/algebrick/product_variant.rb, line 95 def ==(other) other.kind_of? ProductVariant and variants == other.variants and fields == other.fields end
apply_be_kind_of()
click to toggle source
# File lib/algebrick/product_variant.rb, line 105 def apply_be_kind_of @to_be_kind_of.each do |type| @constructor.send :include, type if @constructor variants.each { |v| v.be_kind_of type if v != self && v.respond_to?(:be_kind_of) } if @variants end end
assigned_types()
click to toggle source
# File lib/algebrick/product_variant.rb, line 165 def assigned_types @assigned_types or raise TypeError, "#{self} does not have assigned types" end
assigned_types=(assigned_types)
click to toggle source
# File lib/algebrick/product_variant.rb, line 169 def assigned_types=(assigned_types) raise TypeError, "#{self} assigned types already set" if @assigned_types @assigned_types = assigned_types end
be_kind_of(type)
click to toggle source
# File lib/algebrick/product_variant.rb, line 100 def be_kind_of(type) @to_be_kind_of << type apply_be_kind_of end
call(*field_matchers)
click to toggle source
# File lib/algebrick/product_variant.rb, line 112 def call(*field_matchers) raise TypeError, "#{self} does not have any fields" unless @fields Matchers::Product.new self, *field_matchers end
field(name)
click to toggle source
# File lib/algebrick/product_variant.rb, line 62 def field(name) fields[field_indexes[name]] end
field_indexes()
click to toggle source
# File lib/algebrick/product_variant.rb, line 58 def field_indexes @field_indexes or raise TypeError, "field names not defined on #{self}" end
final!()
click to toggle source
# File lib/algebrick/product_variant.rb, line 66 def final! @final_variants = true self end
kind()
click to toggle source
noinspection RubyCaseWithoutElseBlockInspection
# File lib/algebrick/product_variant.rb, line 152 def kind @kind ||= case when @fields && !@variants :product when @fields && @variants :product_variant when !@fields && @variants :variant when !@fields && !@variants raise TypeError, 'fields or variants have to be set' end end
new(*fields)
click to toggle source
# File lib/algebrick/product_variant.rb, line 88 def new(*fields) raise TypeError, "#{self} does not have fields" unless @constructor @constructor.new *fields end
Also aliased as: []
set_fields(fields_or_hash)
click to toggle source
# File lib/algebrick/product_variant.rb, line 32 def set_fields(fields_or_hash) raise TypeError, 'can be set only once' if @fields @kind = nil fields, keys = case fields_or_hash when Hash [fields_or_hash.values, fields_or_hash.keys] when Array [fields_or_hash, nil] else raise ArgumentError end add_field_names keys if keys fields.all? { |f| Type! f, Type, Class, Module } raise TypeError, 'there is no product with zero fields' unless fields.size > 0 define_method(:value) { @fields.first } if fields.size == 1 @fields = fields @constructor = Class.new( field_names? ? ProductConstructors::Named : ProductConstructors::Basic). tap { |c| c.type = self } const_set :Constructor, @constructor apply_be_kind_of self end
set_variants(*variants)
click to toggle source
# File lib/algebrick/product_variant.rb, line 71 def set_variants(*variants) raise TypeError, 'can be set only once' if @variants && @final_variants @kind = nil variants.all? { |v| Type! v, Type, Class } @variants ||= [] @variants += variants apply_be_kind_of variants.each do |v| if v.respond_to? :be_kind_of v.be_kind_of self else v.send :include, self end end self end
to_m()
click to toggle source
# File lib/algebrick/product_variant.rb, line 117 def to_m case kind when :product Matchers::Product.new self when :product_variant Matchers::Variant.new self when :variant Matchers::Variant.new self else raise end end
to_s()
click to toggle source
# File lib/algebrick/product_variant.rb, line 130 def to_s case kind when :product product_to_s when :product_variant name + '(' + variants.map do |variant| if variant == self product_to_s else sub_type variant end end.join(' | ') + ')' when :variant "#{name}(#{variants.map { |v| sub_type v }.join ' | '})" else raise end end
Private Instance Methods
add_field_names(names)
click to toggle source
# File lib/algebrick/product_variant.rb, line 191 def add_field_names(names) @field_names = names names.all? { |k| Type! k, Symbol } dict = @field_indexes = Hash.new { |_, k| raise ArgumentError, "unknown field #{k.inspect} in #{self}" }. update names.each_with_index.inject({}) { |h, (k, i)| h.update k => i } define_method(:[]) { |key| @fields[dict[key]] } # TODO use attr_readers to speed things up end
product_to_s()
click to toggle source
# File lib/algebrick/product_variant.rb, line 176 def product_to_s fields_str = if field_names? field_names.zip(fields).map { |name, field| "#{name}: #{field.name}" } else fields.map(&:name) end "#{name}(#{fields_str.join ', '})" end
sub_type(type)
click to toggle source
# File lib/algebrick/product_variant.rb, line 185 def sub_type(type) return type.name unless type.name.nil? return '(recursive)' if type == self # FIXME: will not catch deeper recursions return type.to_s end