Created
May 23, 2021 13:40
-
-
Save alpaca-tc/80b9fd778b38695bae639006a803ecbf to your computer and use it in GitHub Desktop.
渡された値でクラスを初期化する型
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Usage | |
# attribute :wrapped_type, klass: UserModel, array: true | |
class WrappedType < ActiveModel::Type::Value | |
KEYWORD_PARAMETERS = %i[keyreq key].freeze | |
private_constant(:KEYWORD_PARAMETERS) | |
# @param [Class, String] klass 変換したいクラス | |
# @param [Boolean] array 配列で変換するかどうか | |
def initialize(klass:, array: false) | |
super() | |
@wrap_klass = klass | |
@array = array | |
end | |
# @param [any, Array, Hash] value 変換したい値。Hash の場合は `value { '0' => { }, '1' => { } }` 形式の、Controllerから渡ってくるようなHash | |
def cast(value) | |
if @array | |
cast_array(value) | |
else | |
cast_value(value) | |
end | |
end | |
private | |
def cast_value(value) | |
_cast(value) unless value.nil? | |
end | |
def cast_array(values) | |
if values.blank? | |
[] | |
elsif values.respond_to?(:keys) && values.keys.all? { |key| key.match?(/^\d+$/) } | |
values.values.map { |value| _cast(value) } | |
elsif values.respond_to?(:each) | |
values.map { |value| _cast(value) } | |
else | |
raise ArgumentError, "value is not enumerable. #{values}" | |
end | |
end | |
def _cast(value) | |
if value.is_a?(klass) | |
value | |
elsif keyword_parameters? | |
klass.new(**value) | |
else | |
klass.new(value) | |
end | |
end | |
def keyword_parameters? | |
if defined?(@keyword_parameters) | |
@keyword_parameters | |
else | |
# 引数が全てキーワード引数かどうか | |
@keyword_parameters = klass.instance_method(:initialize).parameters.all? { |(key, _)| KEYWORD_PARAMETERS.include?(key) } | |
end | |
end | |
def klass | |
@klass ||= if @wrap_klass.respond_to?(:constantize) | |
@wrap_klass.constantize | |
else | |
@wrap_klass | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment