Class: Value

Inherits:
Struct
  • Object
show all
Defined in:
lib/value.rb

Overview

Value generates Struct classes with safer constructors. It is designed to provide a superset of the interface of the Values gem, with better performance, by subclassing actual native Structs.

Value constructors require all mandatory arguments to be provided, and supply default values for all optional arguments. Additionally, the resulting instance is frozen. To obtain a mutable Value, dup the result.

Value structure classes are created similarly to ‘Struct`s, with the addition that optional arguments are may be specified as keyword arguments: `ValueType = Value.new(:a, :b, c: default_value)`. The default values to optional arguments are saved at class creation time and supplied as default constructor arguments to instances. Default values are aliased, so providing mutable defaults is discouraged. Lazily-evaluated defaults can be provided by supplying `Value.lazy { … }` as a default. The lazy block will be evaluated at each instantiation time.

Two instance constructors are provided, with positional and keyword arguments.

Value types may be constructed with positional arguments using new. Arguments are provided in the same order as specified at class initialization time, with mandatory arguments before optional ones. For example: ‘ValueType.new(1, 2)`, `ValueType.new(1, 2, 3)`

Value types may be constructed with keyword arguments using with. For example: ‘ValueType.with(a: 1, b: 2, c: 3)`

Defined Under Namespace

Classes: LazyDefault

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.lazy(&proc) ⇒ Object



70
71
72
# File 'lib/value.rb', line 70

def lazy(&proc)
  LazyDefault.new(proc)
end

.new(*required_args, **optional_args, &block) ⇒ Object



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

def new(*required_args, **optional_args, &block)
  arguments = {}
  required_args.each { |arg| arguments[arg] = true }
  optional_args.each_key { |arg| arguments[arg] = false }
  validate_names(*arguments.keys)

  clazz = super(*arguments.keys, &nil)

  # define class and instance methods in modules so that the class can
  # override them
  keyword_constructor = generate_keyword_constructor(arguments)
  class_method_module = Module.new do
    module_eval(keyword_constructor)

    optional_args.each do |name, value|
      method_name = :"__constructor_default_#{name}"
      if value.is_a?(LazyDefault)
        define_method(method_name, &value.proc)
      else
        define_method(method_name) { value }
      end
    end
  end
  clazz.extend(class_method_module)

  constructor = generate_constructor(arguments)
  instance_method_module = Module.new do
    module_eval(constructor)
  end
  clazz.include(instance_method_module)

  # Evaluate the block in the context of the class
  clazz.class_eval(&block) if block_given?

  clazz
end

Instance Method Details

#with(**kwargs) ⇒ Object



137
138
139
140
# File 'lib/value.rb', line 137

def with(**kwargs)
  return self if kwargs.empty?
  self.class.with(**to_h.merge(kwargs))
end