6

I have a simple class that, on initialization, takes between one and eight parameters. It sets the accessors to these to use later. Rubocop is trying to arrest me for the ABC being too high, but I'm not sure if there's actually anything wrong with what I've done. Is this a case where I just disable the inspection on my initialize?

class Foo
  attr_accessor :one, :two, :three, :four
  attr_accessor :five, :six, :seven, :eight

  def initialize(p={})
    @one = p[:one] if p[:one].present?
    # ...
    @eight = p[:eight] if p[:eight].present?
  end
end

My only thought on reducing size would be to do something like iterating through all my attr_accessors on initialize, seeing if there is a corresponding symbol passed through in the has, and if so assigning it.

class Foo
  attr_accessor :one, :two, :three, :four
  attr_accessor :five, :six, :seven, :eight

  def initialize(p={})
    instance_variables.each do |variable|
      send("@#{variable}") = p["#{send(variable)}".to_sym] if p["#{send(variable)}".to_sym].present?
    end
  end
end

But this seems kind of weak.

4

2 回答 2

5

Here is one of the ways to achieve what you are trying to do:

class Foo
  attr_accessor(*%i[one two three four five six seven eight])

  def initialize(p = {})
    p.keys.each { |k| instance_variable_set("@#{k}", p.fetch(k, nil)) }
  end
end

Check out for Hash#fetch method.

You can also use it to just access the key-value pairs of p variable, if you instead of 8 variables decide to go with one (@p)


EDIT

Just out of curiosity wrote this version (some meta programming used) - it will dynamically add attr_accessor for added instance variables:

class Foo
  def initialize(p = {})
    p.keys.each do |k|
      instance_variable_set("@#{k}", p.fetch(k, nil))
      self.class.__send__(:attr_accessor, k)
    end
  end
end

What is happening, is we take provided to initialize method argument (hash p), get its keys and create instance variables from them, assigning each variable with value corresponding to the key. Then we're defining attr_accessor for each of the keys.

a = Foo.new(a: 2, b: 3)
#=> #<Foo:0x00000002d63ad8 @a=2, @b=3>
于 2016-01-14T14:15:19.323 回答
2

You shouldn't assign each of those as different variables. You should rather save that to a variable as a single hash, and access the hash when you need the values. In fact, you already seem to have a variable p. So keep that as @p = p.

于 2016-01-14T14:15:28.603 回答