Module: ValueObjectStruct

Defined in:
lib/value_object_struct.rb

Overview

The ValueObjectStruct module provides the ValueObjectStruct.class_with_attributes method for defining immutable value object classes based on ruby’s Struct class.

Class Method Summary collapse

Class Method Details

.class_with_attributes(*attributes) ⇒ Object

ValueObjectStruct.class_with_attributes accepts a list of member attributes specified by Symbol and returns a Class that inherits from a Struct class defined with those attributes.

The constructor for the resulting class accepts a Hash of attribute value assignments. Attributes must be specified by symbolic key. Undeclared attributes are ignored. Declared attributes of the value object which are not explicitly initialized are set to the default value of the initializing Hash (usually nil).

The class also provides two factory methods: ::for_values, which accepts an ordered list of attribute values like the Struct class constructor, and ::value, which accepts a hash of attribute value assignments, constructs the value object, and then freezes it before returning it.

Value object instances are Struct instances with private attribute write access, including both named attribute writers and Hash or Array style bracketed subscript assignment. If all attribute values are nil, the value object is considered empty.



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
# File 'lib/value_object_struct.rb', line 30

def self.class_with_attributes(*attributes)
  Struct.new(*attributes).tap do |klass|
    klass.class_eval <<-"RUBY", __FILE__, __LINE__

      def self.value(attributes={})
        new(attributes).freeze
      end

      def initialize(attributes={})
        values = members.map { |m| attributes[m] }
        super(*values)
      end

      def self.for_values(*values)
        attributes = {}
        members.each_with_index { |m,i| attributes[m] = values[i] }
        new(attributes)
      end

      def empty?
        values.all?(&:nil?)
      end

      def attributes
        members.each_with_object({}) { |m,h| h[m.to_s] = self[m] }
      end

      alias_method :attribute, :[]

      private :[]=

      private #{attributes.map {|attr| ":" + attr.to_s + "=" }.join(", ")}

      undef_method :to_a

    RUBY
  end
end