summaryrefslogtreecommitdiff
path: root/lib/mime/types/container.rb
blob: e56ee2af7825e5d5a6342f495c75502df40be28d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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
57
58
# frozen_string_literal: true

require 'set'
require 'forwardable'

# MIME::Types requires a serializable keyed container that returns an empty Set
# on a key miss. Hash#default_value cannot be used because, while it traverses
# the Marshal format correctly, it won't survive any other serialization
# format (plus, a default of a mutable object resuls in a shared mess).
# Hash#default_proc cannot be used without a wrapper because it prevents
# Marshal serialization (and doesn't survive the round-trip).
class MIME::Types::Container
  extend Forwardable

  def initialize
    @container = {}
  end

  def [](key)
    container[key] || EMPTY_SET
  end

  def_delegators :@container,
    :count,
    :each_value,
    :keys,
    :merge,
    :merge!,
    :select,
    :values

  def add(key, value)
    (container[key] ||= Set.new).add(value)
  end

  def marshal_dump
    {}.merge(container)
  end

  def marshal_load(hash)
    @container = hash
  end

  def encode_with(coder)
    container.each { |k, v| coder[k] = v.to_a }
  end

  def init_with(coder)
    coder.map.each { |k, v| container[k] = Set[*v] }
  end

  private

  attr_reader :container

  EMPTY_SET = Set.new.freeze
  private_constant :EMPTY_SET
end