File: value/core/product/named-tuple.rb

Overview
Module Structure
Class Hierarchy
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: Umu#6
  module: Value#8
  module: Core#10
has properties
function: make_named_tuple / 4 #242
  module: Product#12
  class: Named#14
inherits from
  Abstract ( Umu::Value::Core::Product )
has properties
alias: values objs #15
attribute: index_by_label [R] #16
method: initialize / 4 #19
method: labels #32
method: each #37
method: to_s #47
method: pretty_print / 1 #56
method: select_by_label / 3 #67
method: modify / 3 #85
method: meth_to_string / 3 #112
method: meth_is_equal / 4 #131
method: meth_is_less_than / 4 #154

Class Hierarchy

Code

   1  # coding: utf-8
   2  # frozen_string_literal: true
   3 
   4 
   5 
   6  module Umu
   7 
   8  module Value
   9 
  10  module Core
  11 
  12  module Product
  13 
  14  class Named < Abstract
  15      alias values objs
  16      attr_reader :index_by_label
  17 
  18 
  19      def initialize(fst_value, snd_value, tail_values, index_by_label)
  20          ASSERT.kind_of fst_value,      ::Object
  21          ASSERT.kind_of snd_value,      ::Object
  22          ASSERT.kind_of tail_values,    ::Array
  23          ASSERT.kind_of index_by_label, ::Hash
  24          ASSERT.assert index_by_label.size == 2 + tail_values.size
  25 
  26          super(fst_value, snd_value, tail_values)
  27 
  28          @index_by_label = index_by_label.freeze
  29      end
  30 
  31 
  32      def labels
  33          self.index_by_label.keys
  34      end
  35 
  36 
  37      def each
  38          self.index_by_label.each do |label, index|
  39              ASSERT.kind_of label, ::Symbol
  40              ASSERT.kind_of index, ::Integer
  41 
  42              yield label, self.values[index]
  43          end
  44      end
  45 
  46 
  47      def to_s
  48          format("(%s)",
  49              self.map { |label, value|
  50                  format "%s:%s", label.to_s, value.to_s
  51              }.join(' ')
  52          )
  53      end
  54 
  55 
  56      def pretty_print(q)
  57          PRT.group_for_enum q, self, bb:'(', eb:')', join:' ' do
  58              |label, value|
  59 
  60              q.text label.to_s
  61              q.text ':'
  62              q.pp value
  63          end
  64      end
  65 
  66 
  67      def select_by_label(sel_lab, loc, env)
  68          ASSERT.kind_of sel_lab,     ::Symbol
  69          ASSERT.kind_of loc,         LOC::Entry
  70 
  71          opt_index = self.index_by_label[sel_lab]
  72          unless opt_index
  73              raise X::SelectionError.new(
  74                  loc,
  75                  env,
  76                  "Unknown selector label: '%s'", sel_lab.to_s
  77              )
  78          end
  79          index = opt_index
  80 
  81          ASSERT.kind_of self.values[index], VC::Top
  82      end
  83 
  84 
  85      def modify(value_by_label, loc, env)
  86          ASSERT.kind_of value_by_label,  ::Hash
  87          ASSERT.kind_of loc,             LOC::Entry
  88 
  89          mut_values = self.values.dup
  90          value_by_label.each_key do |label, expr|
  91              index = self.index_by_label[label]
  92              unless index
  93                  raise X::SelectionError.new(
  94                      loc,
  95                      env,
  96                      "Unknown modifier label: '%s'", label.to_s
  97                  )
  98              end
  99 
 100              mut_values[index] = value_by_label[label]
 101          end
 102 
 103          VC.make_named_tuple self.index_by_label, *mut_values
 104      end
 105 
 106 
 107      define_instance_method(
 108          :meth_to_string,
 109          :'to-s', [],
 110          [], VCA::String
 111      )
 112      def meth_to_string(loc, env, event)
 113          VC.make_string(
 114              format("(%s)",
 115                  self.map { |label, value|
 116                      format("%s:%s",
 117                              label.to_s,
 118                              value.meth_to_string(loc, env, event).val
 119                      )
 120                  }.join(' ')
 121              )
 122          )
 123      end
 124 
 125 
 126      define_instance_method(
 127          :meth_is_equal,
 128          :'==', [],
 129          [VC::Top], VCA::Bool
 130      )
 131      def meth_is_equal(loc, env, event, other)
 132          ASSERT.kind_of other, VC::Top
 133 
 134          unless other.kind_of?(self.class) && self.arity == other.arity
 135              return VC.make_false
 136          end
 137 
 138          VC.make_bool(
 139              self.values.zip(other.values).all? {
 140                  |self_value, other_value|
 141 
 142                  other_value.kind_of?(self_value.class) &&
 143                  self_value.meth_is_equal(loc, env, event, other_value).true?
 144              }
 145          )
 146      end
 147 
 148 
 149      define_instance_method(
 150          :meth_is_less_than,
 151          :'<', [],
 152          [self], VCA::Bool
 153      )
 154      def meth_is_less_than(loc, env, event, other)
 155          ASSERT.kind_of other, VCP::Named
 156 
 157          unless other.kind_of?(self.class) && self.arity == other.arity
 158              raise X::TypeError.new(
 159                  loc,
 160                  env,
 161                  "Expected a named tuple of %d element, but %d: %s",
 162                      self.arity, other.arity, other.to_s
 163              )
 164          end
 165 
 166          result, _index = self.index_by_label.map { |label, index|
 167              [label, self.values[index]]
 168          }.zip(
 169              other.index_by_label.map { |label, index|
 170                  [label, other.values[index]]
 171              }
 172          ).inject([VC.make_false, 0]) {
 173              |
 174                  (res, index),
 175                  ((self_label, self_value), (other_label, other_value))
 176              |
 177              ASSERT.kind_of res,         VCA::Bool
 178              ASSERT.kind_of index,       ::Integer
 179              ASSERT.kind_of self_label,  ::Symbol
 180              ASSERT.kind_of self_value,  VC::Top
 181              ASSERT.kind_of other_value, VC::Top
 182              ASSERT.kind_of other_label, ::Symbol
 183 
 184  =begin
 185              pp({index: index,
 186                  self_label: self_label, self_value: self_value,
 187                  other_label: other_label, other_value: other_value
 188              })
 189  =end
 190 
 191              unless self_label == other_label
 192                  raise X::TypeError.new(
 193                      loc,
 194                      env,
 195                      "Expected '%s:' " +
 196                              "as label for #%d named tuple element, " +
 197                              "but '%s:'",
 198                          self_label.to_s, index + 1, other_label
 199                  )
 200              end
 201 
 202              unless other_value.kind_of?(self_value.class)
 203                  raise X::TypeError.new(
 204                      loc,
 205                      env,
 206                      "In %d's element of tuple, " +
 207                              "expected a %s, but %s : %s",
 208                          index + 1,
 209                          self_value.type_sym,
 210                          other_value.to_s,
 211                          other_value.type_sym
 212                  )
 213              end
 214 
 215              if self_value.meth_is_less_than(        # self < other
 216                  loc, env, event, other_value
 217              ).true?
 218                  break VC.make_true
 219              elsif self_value.meth_is_equal(         # self = other
 220                  loc, env, event, other_value
 221              ).true?
 222                  [res, index + 1]
 223              elsif other_value.meth_is_less_than(    # self > other
 224                  loc, env, event, self_value
 225              ).true?
 226                  break VC.make_false
 227              else
 228                  ASSERT.abort 'No case'
 229              end
 230          }
 231 
 232          ASSERT.kind_of result, VCA::Bool
 233      end
 234  end
 235  Named.freeze
 236 
 237  end # Umu::Value::Core::Product
 238 
 239 
 240  module_function
 241 
 242      def make_named_tuple(index_by_label, fst_value, snd_value, *tail_values)
 243          ASSERT.kind_of index_by_label, ::Hash
 244          ASSERT.kind_of fst_value,      ::Object
 245          ASSERT.kind_of snd_value,      ::Object
 246          ASSERT.kind_of tail_values,    ::Array
 247 
 248          Product::Named.new(
 249              fst_value, snd_value, tail_values.freeze, index_by_label.freeze
 250          ).freeze
 251      end
 252 
 253  end # Umu::Value::Core
 254 
 255  end # Umu::Value
 256 
 257  end # Umu