lib/playwright/playwright_api.rb
module Playwright class PlaywrightApi # Wrap ChannelOwner / ApiImplementation. # Playwright::ChannelOwners::XXXXX will be wrapped as Playwright::XXXXX # Playwright::YYYYImpl will be wrapped as Playwright::YYYY # Playwright::XXXXX is automatically generated by development/generate_api # # @param channel_owner [ChannelOwner|ApiImplementation] # @note Intended for internal use only. def self.wrap(channel_owner_or_api_implementation) case channel_owner_or_api_implementation when ChannelOwner ChannelOwnerWrapper.new(channel_owner_or_api_implementation).wrap when ApiImplementation ApiImplementationWrapper.new(channel_owner_or_api_implementation).wrap else channel_owner_or_api_implementation end end # Unwrap ChannelOwner / ApiImplementation. # @note Intended for internal use only. def self.unwrap(api) case api when PlaywrightApi api.instance_variable_get(:@impl) else api end end class ChannelOwnerWrapper def initialize(impl) impl_class_name = impl.class.name unless impl_class_name.include?("::ChannelOwners::") raise "#{impl_class_name} is not ChannelOwners" end @impl = impl end def wrap api_class = detect_class_for(@impl.class) if api_class @impl._api ||= api_class.new(@impl) else raise NotImplementedError.new("Playwright::#{expected_class_name_for(@impl.class)} is not implemented") end end private def expected_class_name_for(klass) klass.name.split("::ChannelOwners::").last end def superclass_exist?(klass) ![::Playwright::ChannelOwner, Object].include?(klass.superclass) end def detect_class_for(klass) class_name = expected_class_name_for(klass) if ::Playwright.const_defined?(class_name) ::Playwright.const_get(class_name) elsif superclass_exist?(klass) detect_class_for(klass.superclass) else nil end end end class ApiImplementationWrapper def initialize(impl) impl_class_name = impl.class.name unless impl_class_name.end_with?("Impl") raise "#{impl_class_name} is not Impl" end @impl = impl end def wrap api_class = detect_class_for(@impl.class) if api_class api_class.new(@impl) else raise NotImplementedError.new("Playwright::#{expected_class_name_for(@impl.class)} is not implemented") end end private def expected_class_name_for(klass) # KeyboardImpl -> Keyboard # MouseImpl -> Mouse klass.name[0...-4].split("::").last end def detect_class_for(klass) class_name = expected_class_name_for(klass) if ::Playwright.const_defined?(class_name) ::Playwright.const_get(class_name) else nil end end end # @param impl [Playwright::ChannelOwner|Playwright::ApiImplementation] def initialize(impl) @impl = impl end # @param block [Proc] private def wrap_block_call(block) return nil unless block.is_a?(Proc) -> (*args) { wrapped_args = args.map { |arg| wrap_impl(arg) } block.call(*wrapped_args) } end private def wrap_impl(object, visited: {}) if object.is_a?(Array) unless visited[object] visited[object] = [] object.each { |obj| visited[object] << wrap_impl(obj) } end visited[object] elsif object.is_a?(Hash) unless visited[object] visited[object] = {} object.each do |key, obj| visited[object][key] = wrap_impl(obj, visited: visited) end end visited[object] else ::Playwright::PlaywrightApi.wrap(object) end end private def unwrap_impl(object, visited: {}) if object.is_a?(Array) unless visited[object] visited[object] = [] object.each { |obj| visited[object] << unwrap_impl(obj) } end visited[object] elsif object.is_a?(Hash) unless visited[object] visited[object] = {} object.each do |key, obj| visited[object][key] = unwrap_impl(obj, visited: visited) end end visited[object] elsif object.is_a?(PlaywrightApi) ::Playwright::PlaywrightApi.unwrap(object) else object end end end end