LoginSignup
2
3

More than 5 years have passed since last update.

非Rails環境で素クラスに#attributesメソッドを実装する

Posted at

RailsのActiveRecord(実際はActiveModel)を使うとattr_accessorで定義したアクセサとアサインされた値のキーバリューを#attributesメソッドで取得できる。

RailsやActiveModelが無い環境の素のクラスでも#attributesメソッドを使いたいので、やってみた結果。黒魔術。

module Hoge
  module Concerns
    # Add feature of #attributes, #attributes=, and .attributes to super class by orverriding Module.attr_accessor.
    # ref. http://techblog.clara.jp/2014/09/ruby_attr_accessor/
    module Attributes

      def self.included(base)
        base.extend(ClassMethods)
      end

      def attributes
        self.class.attributes.map {|k| [k, self.instance_variable_get("@#{k}")] }.to_h
      end

      def to_h
        self.class.attributes.select{|k| self.instance_variable_defined?("@#{k}") }.map {|k| [k, self.instance_variable_get("@#{k}")] }.to_h
      end

      def attributes=(attrs)
        attrs.each do |k, v|
          assign_attribute(k, v)
        end
      end

      private

      def assign_attribute(k, v)
        if respond_to?("#{k}=")
          public_send("#{k}=", v)
        else
          raise UnknownAttributeError, "attribute `#{k}` can not be assinged to #{self}"
        end
      end

      public

      module ClassMethods
        def attributes
          @attributes ||=
            self.superclass.instance_variable_get("@attributes").try(:dup) || Set.new
        end

        private

        def attr_accessor(*args)
          self.attributes.merge args
          super
        end
      end
    end
  end
end

参考

Ruby: attr_accessor を拡張する

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3