Class: Redmine::Value

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

Overview

Base class for immutable value objects.

Value objects with the same attributes are considered equal. Value objects cannot be modified, but new values can be constructed by applying new attribute values to existing values.

Direct Known Subclasses

Issue, IssueChange, IssueEvent, Project

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attrs = {}) ⇒ Value

Returns a new instance of Value.

Parameters:

  • attrs (Hash) (defaults to: {})


53
54
55
56
57
58
59
# File 'lib/redmine/value.rb', line 53

def initialize(attrs = {})
  attrs.to_h.each do |name, value|
    send(:"#{name}=", value)
  end
  @hash = self.class.hash ^ to_a.hash
  freeze
end

Instance Attribute Details

#hashObject (readonly)

Returns the value of attribute hash.



8
9
10
# File 'lib/redmine/value.rb', line 8

def hash
  @hash
end

Class Method Details

.attribute(name, type: nil, path: nil) ⇒ nil

Define a new attribute for this value. Attributes can be casted into a specific type, and can optionally be read from a path inside a nested structure (see Rubys ‘dig` method).

Parameters:

  • name (Symbol, #to_sym)
  • type (Class, #parse) (defaults to: nil)

    conversion method or class that can be used to parse the incoming values.

  • path (Array) (defaults to: nil)

    for ‘dig` to retrieve nested values

Returns:

  • (nil)


38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/redmine/value.rb', line 38

def self.attribute(name, type: nil, path: nil)
  attributes << name.to_sym
  attr_reader name

  define_method :"#{name}=" do |value|
    value = value.dig(*Array(path)) if path && value.respond_to?(:dig)
    parsed_value = self.class.parse_value(value, type)
    instance_variable_set(:"@#{name}", parsed_value)
  end

  private :"#{name}="
  nil
end

.attributesObject

List of all known attributes supported by this Value.



11
12
13
# File 'lib/redmine/value.rb', line 11

def self.attributes
  @attributes ||= []
end

.parse_value(value, type = nil) ⇒ Object

Returns value parsed to ‘type`.

Parameters:

  • value (Object)

    raw data to be tranformed into ‘type`.

  • type (Object, #parse) (defaults to: nil)

Returns:

  • (Object)

    value parsed to ‘type`



18
19
20
21
22
23
24
25
26
27
# File 'lib/redmine/value.rb', line 18

def self.parse_value(value, type = nil)
  case type
  when ->(t) { t.nil? } then value
  when ->(t) { t === value } then value
  when ->(t) { t.respond_to?(:parse) } then type.parse(value)
  when ->(t) { Kernel.respond_to?(t.to_s) }
    Kernel.send(type.to_s, value)
  else raise ArgumentError, "Invalid type #{type.inspect}"
  end
end

Instance Method Details

#eql?(other) ⇒ Bool Also known as: ==

Returns:

  • (Bool)


73
74
75
# File 'lib/redmine/value.rb', line 73

def eql?(other)
  hash == other.hash
end

#to_aArray

Returns:

  • (Array)


84
85
86
# File 'lib/redmine/value.rb', line 84

def to_a
  self.class.attributes.map { |attr| [attr, send(attr)] }
end

#to_hHash

Returns:

  • (Hash)


79
80
81
# File 'lib/redmine/value.rb', line 79

def to_h
  Hash[to_a]
end

#with(attrs = {}) ⇒ Value

Create a new value based on the current value, but with the incoming attributes assigned. This “changes” the value, but leaves the original value intact – as you’ll get a new instance instead.

Parameters:

  • attrs (Hash) (defaults to: {})

    new attributes to be merged with this value’s attributes.

Returns:



68
69
70
# File 'lib/redmine/value.rb', line 68

def with(attrs = {})
  self.class.new(to_h.merge(attrs))
end