class Struct

Constants

SUPPORT_KEYWORD_P

Public Class Methods

new(*args, defaults: {}, &block) click to toggle source

@param [Array<Symbol>] args @param [Hash{ Symbol => Object }] defaults

# File lib/benchmark_driver/struct.rb, line 18
def new(*args, defaults: {}, &block)
  # Polyfill `keyword_init: true`
  if ::Struct::SUPPORT_KEYWORD_P
    klass = ::Struct.new(*args, keyword_init: true, &block)
  else
    klass = keyword_init_struct(*args, &block)
  end

  # Default value config
  configure_defaults(klass, defaults)

  # Force deeply freezing members
  force_deep_freeze(klass)

  klass
end

Private Class Methods

configure_defaults(klass, defaults) click to toggle source
# File lib/benchmark_driver/struct.rb, line 57
def configure_defaults(klass, defaults)
  class << klass
    attr_accessor :defaults
  end
  klass.defaults = defaults

  klass.prepend(Module.new {
    def initialize(**)
      super
      self.class.defaults.each do |key, value|
        if public_send(key).nil?
          begin
            value = value.dup
          rescue TypeError # for Ruby <= 2.3, like `true.dup`
          end
          public_send("#{key}=", value)
        end
      end
    end
  })

  def klass.inherited(child)
    child.defaults = self.defaults
  end
end
force_deep_freeze(klass) click to toggle source
# File lib/benchmark_driver/struct.rb, line 83
def force_deep_freeze(klass)
  klass.class_eval do
    def freeze
      members.each do |member|
        value = public_send(member)
        if value.is_a?(Array)
          value.each(&:freeze)
        end
        value.freeze
      end
      super
    end
  end
end
freeze() click to toggle source
Calls superclass method
# File lib/benchmark_driver/struct.rb, line 85
def freeze
  members.each do |member|
    value = public_send(member)
    if value.is_a?(Array)
      value.each(&:freeze)
    end
    value.freeze
  end
  super
end
initialize(**args) click to toggle source

@param [Hash{ Symbol => Object }] args

# File lib/benchmark_driver/struct.rb, line 42
def initialize(**args)
  args.each do |key, value|
    unless members.include?(key)
      raise ArgumentError.new("unknown keywords: #{key}")
      next
    end

    public_send("#{key}=", value)
  end
end
keyword_init_struct(*args, &block) click to toggle source

Polyfill for Ruby < 2.5.0

# File lib/benchmark_driver/struct.rb, line 38
def keyword_init_struct(*args, &block)
  ::Struct.new(*args).tap do |klass|
    klass.prepend(Module.new {
      # @param [Hash{ Symbol => Object }] args
      def initialize(**args)
        args.each do |key, value|
          unless members.include?(key)
            raise ArgumentError.new("unknown keywords: #{key}")
            next
          end

          public_send("#{key}=", value)
        end
      end
    })
    klass.prepend(Module.new(&block))
  end
end