Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

attr_accessor which transforms nil into string on write

Tags:

ruby

I have a data object that contains dozens of attr_accessor fields for various inputs. Can I somehow define the class so that all setters for all fields will e.g. set the value as an empty string instead of the attempted nil?

like image 395
Tatu Lahtela Avatar asked Mar 16 '13 16:03

Tatu Lahtela


2 Answers

Here's a little module to do it:

module NilToBlankAttrAccessor

  def nil_to_blank_attr_accessor(attr)
    attr_reader attr
    define_method "#{attr}=" do |value|
      value = '' if value.nil?
      instance_variable_set "@#{attr}", value
    end
  end

end

Just mix it in:

class Foo
  extend NilToBlankAttrAccessor
  nil_to_blank_attr_accessor :bar
end

And use it:

foo = Foo.new
foo.bar = nil
p foo.bar        # => ""
foo.bar = 'abc'
p foo.bar        # => "abc"

How it works

NilToBlankAttrAccessor#nil_to_blank_attr_accessor first defines the attr_reader normally:

    attr_reader attr

Then it defines the writer by defining a method with the same name as the accessor, only with an "=" at the end. So, for attribute :bar, the method is named bar=

    define_method "#{attr}=" do |value|
      ...
    end

Now it needs to set the variable. First it turns nil into an empty string:

      value = '' if value.nil?

Then use instance_variable_set, which does an instance variable assignment where the instance variable isn't known until runtime.

      instance_variable_set "@#{attr}", value

Class Foo needs nil_to_blank_attr_accessor to be a class method, not an instance method, so it uses extend instead of include:

class Foo
  extend NilToBlankAttrAccessor
  ...
end
like image 71
Wayne Conrad Avatar answered Dec 01 '22 02:12

Wayne Conrad


Instead of doing

object.foo = given_input

you should do

object.foo = given_input.nil? ? "" : given_input

or if you want to turn false into "" as well, then

object.foo = given_input || ""
like image 41
sawa Avatar answered Dec 01 '22 01:12

sawa