Class: Backports::Data

Inherits:
Object show all
Defined in:
lib/backports/3.2.0/data.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(**named_values) ⇒ Data

Returns a new instance of Data.



88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/backports/3.2.0/data.rb', line 88

def initialize(**named_values)
  given = named_values.keys
  missing = members - given
  unless missing.empty?
    missing = missing.map(&:inspect).join(", ")
    raise ArgumentError, "missing keywords: #{missing}"
  end
  if members.size < given.size
    extra = (given - members).map(&:inspect).join(", ")
    raise ArgumentError, "unknown keywords: #{extra}"
  end
  @__members__ = named_values.freeze
  freeze
end

Class Method Details

.define(*members, &block) ⇒ Object

Raises:

  • (ArgumentError)


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
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/backports/3.2.0/data.rb', line 30

def self.define(*members, &block)
  members.each do |m|
    raise TypeError, "#{m} is not a Symbol" unless m.is_a?(Symbol) || m.is_a?(String)
    raise ArgumentError, "invalid data member: #{m}" if m.end_with?("=")
  end
  members = members.map(&:to_sym)
  raise ArgumentError, "duplicate members" if members.uniq!

  klass = instance_eval <<-"end_define", __FILE__, __LINE__ + 1
    Class.new(::Backports::Data) do     # Class.new(::Data) do
      def self.members       #   def self.members
        #{members.inspect}   #     [:a_member, :another_member]
      end                    #   end
    end                      # end
  end_define

  members.each do |m|
    klass.define_method(m) { @__members__[m]}
  end

  class << klass
    def new(*values, **named_values)
      if named_values.empty?
        if values.size > members.size
          raise ArgumentError, "wrong number of arguments (given #{values.size}, expected 0..#{members.size})"
        end
        super(**members.first(values.size).zip(values).to_h)
      else
        unless values.empty?
          raise ArgumentError, "wrong number of arguments (given #{values.size}, expected 0)"
        end
        super(**named_values)
      end
    end
    undef :define
  end

  klass.class_eval(&block) if block

  klass
end

Instance Method Details

#==(other) ⇒ Object



78
79
80
81
82
# File 'lib/backports/3.2.0/data.rb', line 78

def ==(other)
  return false unless other.instance_of?(self.class)

  @__members__ == other.to_h
end

#deconstructObject



19
20
21
# File 'lib/backports/3.2.0/data.rb', line 19

def deconstruct
  @__members__.values
end

#deconstruct_keys(keys_or_nil) ⇒ Object

Raises:

  • (TypeError)


23
24
25
26
27
28
# File 'lib/backports/3.2.0/data.rb', line 23

def deconstruct_keys(keys_or_nil)
  return @__members__ unless keys_or_nil

  raise TypeError, "Expected symbols" unless keys_or_nil.is_a?(Array) && keys_or_nil.all? {|s| s.is_a?(Symbol)}
  @__members__.slice(*keys_or_nil)
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


72
73
74
75
76
# File 'lib/backports/3.2.0/data.rb', line 72

def eql?(other)
  return false unless other.instance_of?(self.class)

  @__members__.eql?(other.to_h)
end

#hashObject



84
85
86
# File 'lib/backports/3.2.0/data.rb', line 84

def hash
  @__members__.hash
end

#initialize_copy(other) ⇒ Object

Why is ‘initialize_copy` specialized in MRI and not just `initialize_dup`? Let’s follow the pattern anyways



105
106
107
108
# File 'lib/backports/3.2.0/data.rb', line 105

def initialize_copy(other)
  @__members__ = other.to_h
  freeze
end

#inspectObject



110
111
112
113
114
# File 'lib/backports/3.2.0/data.rb', line 110

def inspect
  data = @__members__.map {|k, v| "#{k}=#{v.inspect}"}.join(", ")
  space = data != "" && self.class.name ? " " : ""
  "#<data #{self.class.name}#{space}#{data}>"
end

#marshal_dumpObject



116
117
118
# File 'lib/backports/3.2.0/data.rb', line 116

def marshal_dump
  @__members__
end

#marshal_load(members) ⇒ Object



120
121
122
123
# File 'lib/backports/3.2.0/data.rb', line 120

def marshal_load(members)
  @__members__ = members
  freeze
end

#membersObject

class method defined in ‘define`



126
127
128
# File 'lib/backports/3.2.0/data.rb', line 126

def members
  self.class.members
end

#to_h(&block) ⇒ Object



134
135
136
# File 'lib/backports/3.2.0/data.rb', line 134

def to_h(&block)
  @__members__.to_h(&block)
end

#with(**update) ⇒ Object



138
139
140
141
142
# File 'lib/backports/3.2.0/data.rb', line 138

def with(**update)
  return self if update.empty?

  self.class.new(**@__members__.merge(update))
end