diff --git a/rb/lib/selenium/webdriver/bidi.rb b/rb/lib/selenium/webdriver/bidi.rb index 80fc5b92fbe22..64b1e7c394668 100644 --- a/rb/lib/selenium/webdriver/bidi.rb +++ b/rb/lib/selenium/webdriver/bidi.rb @@ -24,7 +24,6 @@ class BiDi autoload :LogHandler, 'selenium/webdriver/bidi/log_handler' autoload :Browser, 'selenium/webdriver/bidi/browser' autoload :BrowsingContext, 'selenium/webdriver/bidi/browsing_context' - autoload :Struct, 'selenium/webdriver/bidi/struct' autoload :Network, 'selenium/webdriver/bidi/network' autoload :InterceptedRequest, 'selenium/webdriver/bidi/network/intercepted_request' autoload :InterceptedResponse, 'selenium/webdriver/bidi/network/intercepted_response' diff --git a/rb/lib/selenium/webdriver/bidi/browser.rb b/rb/lib/selenium/webdriver/bidi/browser.rb index f6d9e9202fb5c..558ba73c69173 100644 --- a/rb/lib/selenium/webdriver/bidi/browser.rb +++ b/rb/lib/selenium/webdriver/bidi/browser.rb @@ -21,11 +21,12 @@ module Selenium module WebDriver class BiDi class Browser - Window = Struct.new(:handle, :active, :height, :width, :x, :y, :state) do + Window = WebDriver::Types::Struct.define(:handle, :active, :height, :width, :x, :y, :state) do def active? active end end + def initialize(bidi) @bidi = bidi end diff --git a/rb/lib/selenium/webdriver/bidi/log_handler.rb b/rb/lib/selenium/webdriver/bidi/log_handler.rb index 29b3d4dcab0d9..6334b3be95d30 100644 --- a/rb/lib/selenium/webdriver/bidi/log_handler.rb +++ b/rb/lib/selenium/webdriver/bidi/log_handler.rb @@ -21,8 +21,9 @@ module Selenium module WebDriver class BiDi class LogHandler - ConsoleLogEntry = BiDi::Struct.new(:level, :text, :timestamp, :stack_trace, :type, :source, :method, :args) - JavaScriptLogEntry = BiDi::Struct.new(:level, :text, :timestamp, :stack_trace, :type, :source) + BASE_LOG_ENTRY = %i[level source text timestamp stacktrace].freeze + ConsoleLogEntry = WebDriver::Types::Struct.define(*BASE_LOG_ENTRY, :method, :args, :type) + JavaScriptLogEntry = WebDriver::Types::Struct.define(*BASE_LOG_ENTRY, :type) def initialize(bidi) @bidi = bidi diff --git a/rb/lib/selenium/webdriver/common/types.rb b/rb/lib/selenium/webdriver/common/types.rb new file mode 100644 index 0000000000000..5ec2a64352859 --- /dev/null +++ b/rb/lib/selenium/webdriver/common/types.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +module Selenium + module WebDriver + class Types + autoload :Data, 'selenium/webdriver/common/types/data' + autoload :Struct, 'selenium/webdriver/common/types/struct' + + def self.camel_to_snake(camel) + camel = camel.to_s + camel.gsub(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2') + .gsub(/([a-z\d])([A-Z])/, '\1_\2') + .tr('-', '_') + .downcase.delete_prefix('_') + end + + def self.normalize_args(args, opts) + unless args.empty? || (args.length == 1 && args.first.is_a?(Hash)) + raise ArgumentError, 'positional args not allowed; use keywords or a single hash' + end + + raw = opts.any? ? opts : (args.first || {}) + raw.transform_keys { |k| camel_to_snake(k.to_s).to_sym } + end + end + end # WebDriver +end # Selenium diff --git a/rb/lib/selenium/webdriver/common/types/data.rb b/rb/lib/selenium/webdriver/common/types/data.rb new file mode 100644 index 0000000000000..fe54600ca7ee6 --- /dev/null +++ b/rb/lib/selenium/webdriver/common/types/data.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +# Licensed to the Software Freedom Conservancy (SFC) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The SFC licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +module Selenium + module WebDriver + module Types + # + # A subclass of ::Data that allows optional, unordered, camel-cased key-value pairs. + # + # @api private + # + class Data < ::Data + def self.define(*members, &blk) + klass = super(*members.map(&:to_sym), &blk) + + klass.singleton_class.prepend(Module.new do + def new(*args, **opts) + norm = WebDriver::Types.normalize_args(args, opts) + super(*members.map { |m| norm[m] }) + end + end) + + klass + end + end + end # Types + end # WebDriver +end # Selenium diff --git a/rb/lib/selenium/webdriver/bidi/struct.rb b/rb/lib/selenium/webdriver/common/types/struct.rb similarity index 62% rename from rb/lib/selenium/webdriver/bidi/struct.rb rename to rb/lib/selenium/webdriver/common/types/struct.rb index 951f09b8ad03a..30667c305b06f 100644 --- a/rb/lib/selenium/webdriver/bidi/struct.rb +++ b/rb/lib/selenium/webdriver/common/types/struct.rb @@ -19,24 +19,30 @@ module Selenium module WebDriver - class BiDi + module Types class Struct < ::Struct class << self - def new(*args, &block) - super do - define_method(:initialize) do |**kwargs| - converted_kwargs = kwargs.transform_keys { |key| self.class.camel_to_snake(key.to_s).to_sym } - super(*converted_kwargs.values_at(*self.class.members)) + # + # A subclass of ::Struct that allows optional, unordered, camel-cased key-value pairs. + # + # @api private + # + def define(*members, &blk) + klass = super(*members.map(&:to_sym), keyword_init: true, &blk) + + klass.singleton_class.prepend(Module.new do + def new(*args, **opts) + norm = WebDriver::Types.normalize_args(args, opts) + super(**members.to_h { |m| [m, norm[m]] }) end - class_eval(&block) if block - end - end + end) - def camel_to_snake(camel_str) - camel_str.gsub(/([A-Z])/, '_\1').downcase + klass end + + alias new define end end - end # BiDi + end # Types end # WebDriver end # Selenium diff --git a/rb/sig/lib/selenium/webdriver/bidi/browser.rbs b/rb/sig/lib/selenium/webdriver/bidi/browser.rbs index a2e51e3d21004..a42936abad1f3 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/browser.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/browser.rbs @@ -2,7 +2,7 @@ module Selenium module WebDriver class BiDi class Browser - Window: Selenium::WebDriver::BiDi::Browser::Window + Window: WebDriver::Types::Struct @bidi: BiDi diff --git a/rb/sig/lib/selenium/webdriver/bidi/log_handler.rbs b/rb/sig/lib/selenium/webdriver/bidi/log_handler.rbs index 2506df056f819..c30359afdcb5f 100644 --- a/rb/sig/lib/selenium/webdriver/bidi/log_handler.rbs +++ b/rb/sig/lib/selenium/webdriver/bidi/log_handler.rbs @@ -2,13 +2,15 @@ module Selenium module WebDriver class BiDi class LogHandler + BASE_LOG_ENTRY: Array[Symbol] + @bidi: BiDi @log_entry_subscribed: bool - ConsoleLogEntry: Struct + ConsoleLogEntry: WebDriver::Types::Struct - JavaScriptLogEntry: Struct + JavaScriptLogEntry: WebDriver::Types::Struct def initialize: (BiDi bidi) -> void diff --git a/rb/sig/selenium/web_driver/script.rbs b/rb/sig/lib/selenium/webdriver/common/script.rbs similarity index 100% rename from rb/sig/selenium/web_driver/script.rbs rename to rb/sig/lib/selenium/webdriver/common/script.rbs diff --git a/rb/sig/lib/selenium/webdriver/common/types.rbs b/rb/sig/lib/selenium/webdriver/common/types.rbs new file mode 100644 index 0000000000000..0dd2a03fc22fe --- /dev/null +++ b/rb/sig/lib/selenium/webdriver/common/types.rbs @@ -0,0 +1,9 @@ +module Selenium + module WebDriver + module Types + def self.camel_to_snake: (String s) -> String + + def self.normalize_args: (Array[(String | Symbol)] args, Hash[(String | Symbol), untyped] opts) -> Hash[Symbol, untyped] + end + end +end diff --git a/rb/sig/lib/selenium/webdriver/common/types/data.rbs b/rb/sig/lib/selenium/webdriver/common/types/data.rbs new file mode 100644 index 0000000000000..dde103d0c655f --- /dev/null +++ b/rb/sig/lib/selenium/webdriver/common/types/data.rbs @@ -0,0 +1,9 @@ +module Selenium + module WebDriver + module Types + class Data < ::Data + def self.define: (*(String | Symbol) members){ () -> void } -> Data + end + end + end +end diff --git a/rb/sig/lib/selenium/webdriver/common/types/struct.rbs b/rb/sig/lib/selenium/webdriver/common/types/struct.rbs new file mode 100644 index 0000000000000..4681d70cafad7 --- /dev/null +++ b/rb/sig/lib/selenium/webdriver/common/types/struct.rbs @@ -0,0 +1,11 @@ +module Selenium + module WebDriver + module Types + class Struct < ::Struct[untyped] + def self.define: (*(String | Symbol) members) ?{ () -> void } -> Struct + + alias self.new self.define + end + end + end +end