aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel/lib/active_model/type/registry.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activemodel/lib/active_model/type/registry.rb')
-rw-r--r--activemodel/lib/active_model/type/registry.rb62
1 files changed, 62 insertions, 0 deletions
diff --git a/activemodel/lib/active_model/type/registry.rb b/activemodel/lib/active_model/type/registry.rb
new file mode 100644
index 0000000000..a19dc0f011
--- /dev/null
+++ b/activemodel/lib/active_model/type/registry.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+module ActiveModel
+ # :stopdoc:
+ module Type
+ class Registry
+ def initialize
+ @registrations = []
+ end
+
+ def register(type_name, klass = nil, **options, &block)
+ block ||= proc { |_, *args| klass.new(*args) }
+ registrations << registration_klass.new(type_name, block, **options)
+ end
+
+ def lookup(symbol, *args)
+ registration = find_registration(symbol, *args)
+
+ if registration
+ registration.call(self, symbol, *args)
+ else
+ raise ArgumentError, "Unknown type #{symbol.inspect}"
+ end
+ end
+
+ private
+ attr_reader :registrations
+
+ def registration_klass
+ Registration
+ end
+
+ def find_registration(symbol, *args)
+ registrations.find { |r| r.matches?(symbol, *args) }
+ end
+ end
+
+ class Registration
+ # Options must be taken because of https://bugs.ruby-lang.org/issues/10856
+ def initialize(name, block, **)
+ @name = name
+ @block = block
+ end
+
+ def call(_registry, *args, **kwargs)
+ if kwargs.any? # https://bugs.ruby-lang.org/issues/10856
+ block.call(*args, **kwargs)
+ else
+ block.call(*args)
+ end
+ end
+
+ def matches?(type_name, *args, **kwargs)
+ type_name == name
+ end
+
+ private
+ attr_reader :name, :block
+ end
+ end
+ # :startdoc:
+end