Sha256: 9a5cbf6d2b0e50a9407a27307c22a701e03077dd876da7366b7a900ce138bc7f

Contents?: true

Size: 1.29 KB

Versions: 1

Compression:

Stored size: 1.29 KB

Contents

require "ivo/version"
require 'ivo/value'

module Ivo
  def self.new(*attrs, &block)
    Class.new do
      include Ivo.value *attrs

      class_eval &block if block
    end
  end

  def self.value(*attrs)
    # a: nil, b: nil
    keyword_args = attrs.map { |attr| "#{attr}: nil" }.join ', '

    # a, b
    args = attrs.map { |attr| "#{attr} = nil" }.join ', '

    # @a = a
    # @b = b
    instance_variable_assignments = attrs.map { |attr| "@#{attr} = #{attr}" }.join "\n"

    equality_check = begin
      checks = ['self.class == other.class']
      attrs.each { |attr| checks << "#{attr} == other.#{attr}" }
      checks.join ' && '
    end

    hash = attrs.map { |attr| "#{attr}.hash" }.join ' ^ '

    code = <<~RUBY
      def self.included(base)
        base.extend ClassMethods
      end

      module ClassMethods
        def with(#{keyword_args})
          new #{attrs.join ', '}
        end
      end

      def initialize(#{args})
        #{instance_variable_assignments}
        freeze
      end

      def ==(other)
        #{equality_check}
      end

      def hash
        #{hash}
      end
    RUBY

    Module.new do
      module_eval code

      attr_reader *attrs

      def eql?(other)
        self == other
      end
    end
  end

  def self.call(attrs = nil)
    Value.new attrs
  end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
ivo-0.4.0 lib/ivo.rb