diff --git a/app/logical/concerns/array_attribute.rb b/app/logical/concerns/array_attribute.rb new file mode 100644 index 000000000..128e4f288 --- /dev/null +++ b/app/logical/concerns/array_attribute.rb @@ -0,0 +1,36 @@ +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 diff --git a/app/logical/concerns/normalizable.rb b/app/logical/concerns/normalizable.rb index 7cad97e61..e3b1b54d2 100644 --- a/app/logical/concerns/normalizable.rb +++ b/app/logical/concerns/normalizable.rb @@ -3,10 +3,14 @@ module Normalizable class_methods do def normalize(attribute, method_name) - define_method("#{attribute}=") do |value| - normalized_value = self.class.send(method_name, value) - super(normalized_value) + mod = Module.new do + define_method("#{attribute}=") do |value| + normalized_value = self.class.send(method_name, value) + super(normalized_value) + end end + + prepend mod end private diff --git a/app/models/application_record.rb b/app/models/application_record.rb index fc8391890..67fab07f0 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -4,6 +4,7 @@ class ApplicationRecord < ActiveRecord::Base include Deletable include Mentionable include Normalizable + include ArrayAttribute extend HasBitFlags extend Searchable @@ -157,37 +158,6 @@ class ApplicationRecord < ActiveRecord::Base end end - concerning :AttributeMethods do - 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) - 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 - end - end - def warnings @warnings ||= ActiveModel::Errors.new(self) end diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index d9da10bd4..20531edac 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -10,12 +10,13 @@ class WikiPage < ApplicationRecord normalize :body, :normalize_text normalize :other_names, :normalize_other_names + array_attribute :other_names # XXX must come after `normalize :other_names` + validates :title, tag_name: true, presence: true, uniqueness: true, if: :title_changed? validates :body, presence: true, unless: -> { is_deleted? || other_names.present? } validate :validate_rename validate :validate_other_names - array_attribute :other_names has_one :tag, :foreign_key => "name", :primary_key => "title" has_one :artist, -> { active }, foreign_key: "name", primary_key: "title" has_many :versions, -> {order("wiki_page_versions.id ASC")}, :class_name => "WikiPageVersion", :dependent => :destroy diff --git a/test/unit/wiki_page_test.rb b/test/unit/wiki_page_test.rb index 9b37af9f3..4b846115b 100644 --- a/test/unit/wiki_page_test.rb +++ b/test/unit/wiki_page_test.rb @@ -101,6 +101,10 @@ class WikiPageTest < ActiveSupport::TestCase should normalize_attribute(:other_names).from(["ABC"]).to(["ABC"]) should normalize_attribute(:other_names).from(["foo", "foo"]).to(["foo"]) should normalize_attribute(:other_names).from(%w[foo*bar baz baz 加賀(艦これ)]).to(%w[foo*bar baz 加賀(艦これ)]) + + should normalize_attribute(:other_names).from("foo foo").to(["foo"]) + should normalize_attribute(:other_names).from("foo bar").to(["foo", "bar"]) + should normalize_attribute(:other_names).from("_foo_ Bar").to(["foo", "Bar"]) end context "during title validation" do