Class: Algebrick::ProductVariant

Inherits:
Type show all
Includes:
FieldMethodReaders
Defined in:
lib/algebrick/product_variant.rb

Overview

Representation of Product and Variant types. The class behaves differently based on #kind. noinspection RubyTooManyMethodsInspection

Instance Attribute Summary (collapse)

Instance Method Summary (collapse)

Methods included from FieldMethodReaders

#add_all_field_method_readers, #add_field_method_reader, #add_field_method_readers, #field_names, #field_names?

Methods inherited from Type

#inspect, #match, #name

Methods included from Reclude

#include, #included, #included_into

Methods included from MatcherDelegations

#!, #&, #>, #>>, #case, #|, #~

Methods included from Matching

#any, #match, match_value, #on

Methods included from TypeCheck

#Child!, #Child?, #Match!, #Match?, #Type!, #Type?, error

Constructor Details

- (ProductVariant) initialize(name, &definition)

Returns a new instance of ProductVariant



26
27
28
29
30
# File 'lib/algebrick/product_variant.rb', line 26

def initialize(name, &definition)
  super(name, &definition)
  @to_be_kind_of = []
  @final_variants  = false
end

Instance Attribute Details

- (Object) fields (readonly)

Returns the value of attribute fields



24
25
26
# File 'lib/algebrick/product_variant.rb', line 24

def fields
  @fields
end

- (Object) variants (readonly)

Returns the value of attribute variants



24
25
26
# File 'lib/algebrick/product_variant.rb', line 24

def variants
  @variants
end

Instance Method Details

- (Object) ==(other)



95
96
97
98
# File 'lib/algebrick/product_variant.rb', line 95

def ==(other)
  other.kind_of? ProductVariant and
      variants == other.variants and fields == other.fields
end

- (Object) add_field_names(names) (private)



185
186
187
188
189
190
191
192
193
# File 'lib/algebrick/product_variant.rb', line 185

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

- (Object) apply_be_kind_of



105
106
107
108
109
110
# 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 unless v == self } if @variants
  end
end

- (Object) assigned_types



165
166
167
# File 'lib/algebrick/product_variant.rb', line 165

def assigned_types
  @assigned_types or raise TypeError, "#{self} does not have assigned types"
end

- (Object) assigned_types=(assigned_types)

Raises:

  • (TypeError)


169
170
171
172
# 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

- (Object) be_kind_of(type)



100
101
102
103
# File 'lib/algebrick/product_variant.rb', line 100

def be_kind_of(type)
  @to_be_kind_of << type
  apply_be_kind_of
end

- (Object) call(*field_matchers)

Raises:

  • (TypeError)


112
113
114
115
# 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

- (Object) field(name)



62
63
64
# File 'lib/algebrick/product_variant.rb', line 62

def field(name)
  fields[field_indexes[name]]
end

- (Object) field_indexes



58
59
60
# File 'lib/algebrick/product_variant.rb', line 58

def field_indexes
  @field_indexes or raise TypeError, "field names not defined on #{self}"
end

- (Object) final!



66
67
68
69
# File 'lib/algebrick/product_variant.rb', line 66

def final!
  @final_variants = true
  self
end

- (Object) kind

noinspection RubyCaseWithoutElseBlockInspection



152
153
154
155
156
157
158
159
160
161
162
163
# 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

- (Object) new(*fields) Also known as: []

Raises:

  • (TypeError)


88
89
90
91
# File 'lib/algebrick/product_variant.rb', line 88

def new(*fields)
  raise TypeError, "#{self} does not have fields" unless @constructor
  @constructor.new *fields
end

- (Object) product_to_s (private)



176
177
178
179
180
181
182
183
# 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

- (Object) set_fields(fields_or_hash)

Raises:

  • (TypeError)


32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# 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

- (Object) set_variants(*variants)

Raises:

  • (TypeError)


71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# 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

- (Object) to_m



117
118
119
120
121
122
123
124
125
126
127
128
# 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

- (Object) to_s



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# 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
            variant.name
          end
        end.join(' | ') +
        ')'
  when :variant
    "#{name}(#{variants.map(&:name).join ' | '})"
  else
    raise
  end
end