maicher maicher - 19 days ago 8
Ruby Question

Splat (*) operator and attr_extras gem

Some time ago I found that attr_extras gem can be used for creating class attributes.

Writing:

class Foo
attr_private_initialize :bar
end


replaces:

class Foo
def initialize(bar)
@bar = bar
end

private

attr_reader :bar
end


My question is, does
attr_extras
gem support handling splat (
*
) operators in constructors?

I would like to get following result:

def initialize(*bar)
@bar = bar
end


I don't see this functionality documented, so I think this is impossible, however maybe someone knows how to do it using this gem?

Answer

No, it does not support that. Here's the code.

In short, given the dynamic nature of initializer, it already defines all arguments as splatted array and then takes it apart into individual values (to be used in readers and whatnot). You can't have nested splats, so it's impossible to do with this gem (the current implementation, anyway).

klass.send(:define_method, :initialize) do |*values|
  validate_arity.call(values.length, self.class)

  names.zip(values).each do |name_or_names, value|
    if name_or_names.is_a?(Array)
      hash = value || {}

      known_keys = name_or_names.map { |name| name.to_s.sub(/!\z/, "").to_sym }
      unknown_keys = hash.keys - known_keys
      if unknown_keys.any?
        raise ArgumentError, "Got unknown keys: #{unknown_keys.inspect}; allowed keys: #{known_keys.inspect}"
      end

      name_or_names.each do |name|
        set_ivar_from_hash.call(self, name, hash)
      end
    else
      name = name_or_names
      instance_variable_set("@#{name}", value)
    end
  end

  if block
    instance_eval(&block)
  end
end
Comments