Class: BlockKit::TypedArray

Inherits:
Array
  • Object
show all
Defined in:
lib/block_kit/typed_array.rb

Overview

Custom array class that maintains type constraints during mutation

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(item_type, *args) ⇒ TypedArray

Returns a new instance of TypedArray.



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/block_kit/typed_array.rb', line 8

def initialize(item_type, *args)
  @item_type = item_type

  # Array.new supports three different argument signatures:
  #
  # 1. Array.new(size = nil, object = nil): creates an array of the given size
  #    filled with the given object
  # 2. Array.new(array): creates a new array that is a copy of the given array
  # 3. Array.new(size, &block): creates a new array of the given size, passing
  #    each index to the block and using the block's return value to fill the array
  #
  # We need to handle all three cases, as they all result in filling the array.
  # Calling `super(*)` and then `map!` does not work, as it does not end up
  # modifying the array for some reason.
  if args.size == 1 && args.first.is_a?(::Array)
    super(args.first.map { |item| item_type.cast(item) }.compact)
  elsif args.size == 2
    super(args[0], item_type.cast(item)).compact!
  elsif args.size == 1 && block_given?
    super(args[0]) { |index| item_type.cast(yield(index)) }
  end
end

Instance Attribute Details

#item_typeObject (readonly)

Returns the value of attribute item_type.



6
7
8
# File 'lib/block_kit/typed_array.rb', line 6

def item_type
  @item_type
end

Instance Method Details

#<<(item) ⇒ Object

Override methods that modify the array to ensure type constraints



32
33
34
# File 'lib/block_kit/typed_array.rb', line 32

def <<(item)
  super(item_type.cast(item)).tap(&:compact!)
end

#[]=(position, *args) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/block_kit/typed_array.rb', line 48

def []=(position, *args)
  if args.length == 0
    # array[1] = value
    super(position, item_type.cast(position))
  elsif args.length == 1
    if position.is_a?(Range)
      # array[1..3] = [x, y, z]
      value = args[0]
      if value.is_a?(::Array)
        super(position, value.map { |item| item_type.cast(item) })
      else
        super(position, item_type.cast(value))
      end
    else
      # array[1] = value
      super(position, item_type.cast(args[0]))
    end
  else
    # array[1, 2] = [x, y]
    length, value = args
    if value.is_a?(::Array)
      super(position, length, value.map { |item| item_type.cast(item) })
    else
      super(position, length, item_type.cast(value))
    end
  end

  compact!
end

#collect!(&block) ⇒ Object



100
101
102
# File 'lib/block_kit/typed_array.rb', line 100

def collect!(&block)
  super { |item| item_type.cast(yield(item)) }.compact
end

#concat(other_array) ⇒ Object



104
105
106
# File 'lib/block_kit/typed_array.rb', line 104

def concat(other_array)
  super(other_array.map { |item| item_type.cast(item) }).compact
end

#fill(*args, &block) ⇒ Object



82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/block_kit/typed_array.rb', line 82

def fill(*args, &block)
  if block_given?
    # If a block is given, we need to intercept its results
    modified_block = proc { |*block_args| item_type.cast(yield(*block_args)) }
    super(*args, &modified_block)
  elsif args.size > 0
    # No block, so the last argument is the value to fill with
    value = args.pop
    super(*args, item_type.cast(value))
  else
    super
  end
end

#insert(index, *items) ⇒ Object



44
45
46
# File 'lib/block_kit/typed_array.rb', line 44

def insert(index, *items)
  super(index, *items.map { |item| item_type.cast(item) }.compact)
end

#map!(&block) ⇒ Object



96
97
98
# File 'lib/block_kit/typed_array.rb', line 96

def map!(&block)
  super { |item| item_type.cast(yield(item)) }.compact
end

#push(*items) ⇒ Object



36
37
38
# File 'lib/block_kit/typed_array.rb', line 36

def push(*items)
  super(*items.map { |item| item_type.cast(item) }.compact)
end

#replace(other_array) ⇒ Object



78
79
80
# File 'lib/block_kit/typed_array.rb', line 78

def replace(other_array)
  super(other_array.map { |item| item_type.cast(item) }.compact)
end

#unshift(*items) ⇒ Object



40
41
42
# File 'lib/block_kit/typed_array.rb', line 40

def unshift(*items)
  super(*items.map { |item| item_type.cast(item) }.compact)
end