Sha256: 899f06fb0acf3e1441d778b193c5d1007146784a53b7ab6316502c7e5373a8d5

Contents?: true

Size: 1.9 KB

Versions: 5

Compression:

Stored size: 1.9 KB

Contents

# frozen_string_literal: true

module SumsUp
  module Core
    # SumTypes are just modules with a meta-programmed methods to construct
    # variants. Use SumType.build to define a new one.
    #
    # Each variant class must have the following constants defined:
    #
    # * VARIANT - Symbol name of the variant
    # * MEMBERS - Array of Symbols which enumerate the variant's arguments
    #
    class SumType < Module
      private_class_method :new

      def self.build(variant_classes)
        new do
          const_set(:VARIANTS, variant_classes.freeze)

          variant_classes.each do |variant_class|
            variant_name = variant_class.const_get(:VARIANT)
            class_name = SumType.variant_class_name(variant_name)
            initializer = SumType.variant_initializer(variant_class)

            const_set(class_name, variant_class)
            define_singleton_method(variant_name, &initializer)

            variant_class.include(self)
          end
        end
      end

      def self.variant_class_name(variant_name)
        Strings
          .snake_to_class(variant_name.to_s)
          .to_sym
      end

      # Variants without any members are frozen by default for performance.
      # Pass `memo: false` to its initializer to opt out of this behavior:
      #
      #   Maybe = SumsUp.define(:nothing, just: :value)
      #
      #   frozen_nothing = Maybe.nothing
      #   unfrozen_nothing = Maybe.nothing(memo: false)
      #
      #   # Variants with members are never frozen.
      #   unfrozen_just = Maybe.just(1)
      #
      def self.variant_initializer(variant_class)
        if variant_class.const_get(:MEMBERS).empty?
          dup_if_overridden(variant_class.new.freeze)
        else
          variant_class.method(:new)
        end
      end

      def self.dup_if_overridden(frozen)
        proc do |memo: true|
          memo ? frozen : frozen.dup
        end
      end
    end
  end
end

Version data entries

5 entries across 5 versions & 1 rubygems

Version Path
sums_up-1.2.2 lib/sums_up/core/sum_type.rb
sums_up-1.2.1 lib/sums_up/core/sum_type.rb
sums_up-1.2.0 lib/sums_up/core/sum_type.rb
sums_up-1.1.0 lib/sums_up/core/sum_type.rb
sums_up-1.0.0 lib/sums_up/core/sum_type.rb