Module: Rstructural::Struct

Defined in:
lib/rstructural/struct.rb

Class Method Summary collapse

Class Method Details

.new(*attributes, __caller: nil, &block) ⇒ Object



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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/rstructural/struct.rb', line 5

def self.new(*attributes, __caller: nil, &block)
  begin
    kaller = __caller || caller
    names = kaller.map do |stack|
      # ".../hoge.rb:7:in `<module:Hoge>'"
      if (m = stack.match(/\A.+in `<(module|class):(.+)>.+/))
        m[2]
      end
    end.reject(&:nil?).reverse
    file_name, line_num = kaller[0].split(':')
    line_executed = File.readlines(file_name)[line_num.to_i - 1]
    names << line_executed.match(/\A\s*(\S+)\s*=/)[1] # "  Point = Struct.new(:x, :y)\n"
    class_name = names.join('::')
  rescue StandardError
    class_name = 'Struct'
  end
  Class.new.tap do |k|
    k.class_eval <<~RUBY
    def initialize(#{attributes.join(', ')})
      #{attributes.map { |attr| "@#{attr} = #{attr}" }.join("\n")}
    end

    #{attributes.map { |attr| "attr_reader(:#{attr})" }.join("\n")}

    def self.name
      "#{class_name}"
    end

    def self.to_s
      "<#{class_name}>"
    end

    def copy(#{attributes.map { |attr| "#{attr}: self.#{attr}"}.join(', ')})
      self.class.new(#{attributes.map { |attr| "#{attr}" }.join(', ')})
    end

    def [](key)
      _key = ("@" + key.to_s).to_sym
      self.instance_variable_get(_key)
    end

    def ==(other)
      return false if other.class != self.class
      #{attributes.empty? ? true : attributes.map { |attr| "other.#{attr} == self.#{attr}" }.join(" && ")}
    end

    def inspect
      if #{attributes.empty?}
        "#{class_name}"
      else
        __attrs = Array[#{attributes.map { |attr| "'#{attr}: ' + (@#{attr}.nil? ? 'nil' : @#{attr}.to_s)" }.join(', ')}].join(", ")
        "#{class_name}(" + __attrs + ")"
      end
    end

    alias :to_s :inspect

    def deconstruct
      [#{attributes.map { |attr| "@#{attr}" }.join(', ')}]
    end

    def deconstruct_keys(keys = nil)
      {#{attributes.map { |attr| "'#{attr}'.to_sym => @#{attr}" }.join(', ')}}
    end
    RUBY
    k.class_eval(&block) if block
  end
end