module ArrayAttribute extend ActiveSupport::Concern class_methods do # Defines `_string`, `_string=`, and `=` # methods for converting an array attribute to or from a string. # # The `=` setter parses strings into an array using the # `parse` regex. The resulting strings can be converted to another type # with the `cast` option. def array_attribute(name, parse: /[^[:space:]]+/, cast: :itself) mod = Module.new do define_method "#{name}_string" do send(name).join(" ") end define_method "#{name}_string=" do |value| raise ArgumentError, "#{name} must be a String" unless value.respond_to?(:to_str) send("#{name}=", value) end define_method "#{name}=" do |value| if value.respond_to?(:to_str) super value.to_str.scan(parse).map(&cast) elsif value.respond_to?(:to_a) super value.to_a else raise ArgumentError, "#{name} must be a String or an Array" end end end prepend mod end end end