Class: RSpectre::KeywordStruct

Inherits:
Module
  • Object
show all
Defined in:
lib/rspectre/keyword_struct.rb

Overview

Heavily influenced by dkubb/equalizer, mbj/concord, and mbj/anima

Instance Method Summary collapse

Constructor Details

#initialize(*names) ⇒ KeywordStruct

rubocop:disable Lint/MissingSuper



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
# File 'lib/rspectre/keyword_struct.rb', line 6

def initialize(*names) # rubocop:disable Lint/MissingSuper
  raise 'Specify at least one keyword name!' if names.empty?

  names.each do |name|
    next if /\A\w+\z/.match?(name)

    raise "Invalid keyword name #{name.inspect}!"
  end

  @module =
    Module.new do
      attr_reader(*names)

      define_method(:eql?) do |other|
        other.instance_of?(self.class) && names.all? do |name|
          __send__(name).eql?(other.__send__(name))
        end
      end
      alias_method :==, :eql?

      define_method(:hash) do
        [self.class, *names.map { |name| __send__(name) }].hash
      end

      define_method(:inspect) do
        class_name = self.class.name || self.class.inspect
        attributes = names.map { |name| "#{name}=#{__send__(name).inspect}" }.join(' ')
        "#<#{class_name} #{attributes}>"
      end
    end.tap do |generated_module|
      generated_module.class_eval(<<~RUBY, __FILE__, __LINE__ + 1) # rubocop:disable Style/DocumentDynamicEvalDefinition
        def initialize(#{names.map { |name| "#{name}:" }.join(', ')})
          #{names.map { |name| "@#{name} = #{name}" }.join("\n  ")}
        end
      RUBY
    end
end

Instance Method Details

#included(descendant) ⇒ Object



44
45
46
# File 'lib/rspectre/keyword_struct.rb', line 44

def included(descendant)
  descendant.include(@module)
end