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.
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/mangrove/enum.rb', line 120 def self.extended(receiver) code = <<~RUBY extend T::Sig extend T::Helpers abstract! def self.deserialize(hash) klass = const_get(hash[:type] || hash["type"]) value = hash[:value] || hash["value"] begin klass.new(value) rescue TypeError klass.new(klass.deserialize(value)) end end RUBY receiver.class_eval(code) end |
Instance Method Details
#variants(&block) ⇒ void
This method returns an undefined value.
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 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# 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 serialize(inner_serialization_methods: [:serialize, :to_h]) serialized_inner = begin serialized_klass = [ Hash, String, Numeric, TrueClass, FalseClass, NilClass, Array ] if serialized_klass.any? { |klass| @inner.is_a?(klass) } @inner else inner_serialization_methods.find do |method_name| if @inner.respond_to?(method_name, true) maybe_hash = @inner.send(method_name) if maybe_hash.is_a?(Hash) break maybe_hash end end end end end { type: self.class.name, value: serialized_inner } 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 |