Module: Mangrove::Enum

Extended by:
T::Helpers, T::Sig
Defined in:
lib/mangrove/enum.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.extended(receiver) ⇒ void

This method returns an undefined value.

Parameters:

  • receiver (T::Class[T.anything])


90
91
92
93
94
95
96
97
98
99
# File 'lib/mangrove/enum.rb', line 90

def self.extended(receiver)
  code = <<~RUBY
    extend T::Sig
    extend T::Helpers

    abstract!
  RUBY

  receiver.class_eval(code)
end

Instance Method Details

#variants(&block) ⇒ void

This method returns an undefined value.

Parameters:

  • block (T.proc.bind(EnumVariantsScope).void)


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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/mangrove/enum.rb', line 35

def variants(&block)
  receiver = block.send(:binding).receiver

  outer_code = <<~RUBY
    def self.const_missing(id)
      code = <<~NESTED_RUBY
        class \#{id} < \#{caller.send(:binding).receiver.name}
          def initialize(inner)
            @inner = T.let(inner, self.class.instance_variable_get(:@__mangrove__enum_inner_type))
          end

          def inner
            @inner
          end

          def as_super
            T.cast(self, \#{caller.send(:binding).receiver.name})
          end

          def ==(other)
            other.is_a?(self.class) && other.inner == @inner
          end
        end
      NESTED_RUBY

      class_eval(code, __FILE__, __LINE__ + 1)
      class_eval(id.to_s, __FILE__, __LINE__ + 1)
    end
  RUBY

  original_const_missing = receiver.method(:const_missing)

  receiver.class_eval(outer_code, __FILE__, __LINE__ + 1)
  EnumVariantsScope.new(receiver).call(&block)

  # Mark as sealed hear because we can not define classes in const_missing after marking as sealed
  receiver.send(:eval, "sealed!", nil, __FILE__, __LINE__)

  variants = constants.filter_map { |variant_name|
    maybe_variant = receiver.const_get(variant_name, false)

    if maybe_variant.instance_variable_defined?(:@__mangrove__enum_inner_type)
      maybe_variant
    end
  }

  receiver.class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
    @sorbet_sealed_module_all_subclasses = #{variants} # @sorbet_sealed_module_all_subclasses = #{variants}
  RUBY

  # Bring back the original const_missing
  receiver.define_singleton_method(:const_missing, original_const_missing)
end