minibidi 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +29 -0
- data/Rakefile +7 -0
- data/bin/console +6 -0
- data/lib/minibidi/browser.rb +131 -0
- data/lib/minibidi/browser_process.rb +24 -0
- data/lib/minibidi/browsing_context.rb +29 -0
- data/lib/minibidi/firefox.rb +7 -0
- data/lib/minibidi/firefox_launcher.rb +162 -0
- data/lib/minibidi/version.rb +3 -0
- data/lib/minibidi.rb +11 -0
- data/minibidi.gemspec +32 -0
- metadata +140 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 607b907a85631222aca0cf29e33cdcc76af704464e8a64ee19b9e2da1b6c3b75
|
4
|
+
data.tar.gz: 527e055f3473a2c08f26157d466f2759a210476e97e63d341f90e91b7053315a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2a470c291ead662299187dff8f4cf4b3eaffa7308ad3ad15adee38ce39fa5112d93941ceabd120a7e7d47bd2153a36d449c18935364d90f346b5fac5def8ac3f
|
7
|
+
data.tar.gz: 6ca0eff8038b65628ebf1e66040c5ed7d6b4ffbcd997084e018feeb8911974295e13c61d0d79652b74b20e54dd11ca60df332e992ece59c6231fe3265a4c3030
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2024 YusukeIwaki
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# minibidi: Mini WebDriver BiDi binding for Ruby
|
2
|
+
|
3
|
+
```ruby
|
4
|
+
require 'minibidi'
|
5
|
+
|
6
|
+
Minibidi::Firefox.launch do |browser|
|
7
|
+
context = browser.create_browsing_context
|
8
|
+
context.navigate("https://github.com/YusukeIwaki")
|
9
|
+
data = context.capture_screenshot(origin: :viewport, format: { type: :png })
|
10
|
+
|
11
|
+
open('YusukeIwaki.png', 'wb') do |f|
|
12
|
+
f.write(data)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
```
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
|
19
|
+
Add this line to your application's Gemfile:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
gem 'minibidi'
|
23
|
+
```
|
24
|
+
|
25
|
+
And then execute `bundle install`
|
26
|
+
|
27
|
+
## License
|
28
|
+
|
29
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'async'
|
2
|
+
require 'async/variable'
|
3
|
+
|
4
|
+
module Minibidi
|
5
|
+
class Browser
|
6
|
+
def initialize(async_websocket_connection)
|
7
|
+
@websocket = async_websocket_connection
|
8
|
+
@debug_protocol = %w[1 true].include?(ENV['DEBUG'])
|
9
|
+
|
10
|
+
Async do
|
11
|
+
while data = async_websocket_connection.read
|
12
|
+
if message = Protocol::WebSocket::JSONMessage.wrap(data)
|
13
|
+
handle_received_message_from_websocket(message.to_h)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
bidi_call_async('session.new', {
|
19
|
+
capabilities: {
|
20
|
+
alwaysMatch: {
|
21
|
+
acceptInsecureCerts: false,
|
22
|
+
webSocketUrl:true,
|
23
|
+
},
|
24
|
+
},
|
25
|
+
}).wait
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_browsing_context(&block)
|
29
|
+
res = bidi_call_async('browsingContext.create', { type: :tab, userContext: :default }).wait
|
30
|
+
browsing_context = BrowsingContext.new(self, res[:context])
|
31
|
+
if block
|
32
|
+
begin
|
33
|
+
block.call(browsing_context)
|
34
|
+
ensure
|
35
|
+
browsing_context.close
|
36
|
+
end
|
37
|
+
else
|
38
|
+
browsing_context
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def close
|
43
|
+
bidi_call_async('browser.close').wait
|
44
|
+
end
|
45
|
+
|
46
|
+
def bidi_call_async(method_, params = {})
|
47
|
+
with_message_id do |message_id|
|
48
|
+
Async do
|
49
|
+
@message_results[message_id] = Async::Variable.new
|
50
|
+
|
51
|
+
send_message_to_websocket({
|
52
|
+
id: message_id,
|
53
|
+
method: method_,
|
54
|
+
params: params,
|
55
|
+
})
|
56
|
+
|
57
|
+
value = @message_results[message_id].value
|
58
|
+
if value.is_a?(ErrorData)
|
59
|
+
raise value.to_error
|
60
|
+
else
|
61
|
+
value
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def with_message_id(&block)
|
70
|
+
unless @message_id
|
71
|
+
@message_id = 1
|
72
|
+
@message_results = {}
|
73
|
+
end
|
74
|
+
|
75
|
+
message_id = @message_id
|
76
|
+
@message_id += 1
|
77
|
+
block.call(message_id)
|
78
|
+
end
|
79
|
+
|
80
|
+
def send_message_to_websocket(payload)
|
81
|
+
debug_print_send(payload)
|
82
|
+
message = Protocol::WebSocket::JSONMessage.generate(payload)
|
83
|
+
message.send(@websocket)
|
84
|
+
@websocket.flush
|
85
|
+
end
|
86
|
+
|
87
|
+
def handle_received_message_from_websocket(payload)
|
88
|
+
debug_print_recv(payload)
|
89
|
+
|
90
|
+
if payload[:id]
|
91
|
+
if variable = @message_results.delete(payload[:id])
|
92
|
+
case payload[:type]
|
93
|
+
when 'success'
|
94
|
+
variable.resolve(payload[:result])
|
95
|
+
when 'error'
|
96
|
+
variable.resolve(ErrorData.parse(payload))
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class ErrorData < Data.define(:type, :message, :stacktrace)
|
103
|
+
def self.parse(payload)
|
104
|
+
# {:type=>"error", :id=>1, :error=>"invalid argument", :message=>"method: string value expected", :stacktrace=>"RemoteError@chrome://remote/content/shared/RemoteError.sys.mjs:8:8\nWebDriverError@chrome://remote/content/shared/webdriver/Errors.sys.mjs:193:5\nInvalidArgumentError@chrome://remote/content/shared/webdriver/Errors.sys.mjs:384:5\nassert.that/<@chrome://remote/content/shared/webdriver/Assert.sys.mjs:485:13\nassert.string@chrome://remote/content/shared/webdriver/Assert.sys.mjs:385:53\nonPacket@chrome://remote/content/webdriver-bidi/WebDriverBiDiConnection.sys.mjs:172:19\nonMessage@chrome://remote/content/server/WebSocketTransport.sys.mjs:127:18\nhandleEvent@chrome://remote/content/server/WebSocketTransport.sys.mjs:109:14\n"}
|
105
|
+
new(
|
106
|
+
type: payload[:error],
|
107
|
+
message: payload[:message],
|
108
|
+
stacktrace: payload[:stacktrace].split("\n"),
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
112
|
+
def to_error
|
113
|
+
Error.new("#{type}: #{message}\n#{stacktrace.join("\n")}")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
class Error < StandardError ; end
|
118
|
+
|
119
|
+
def debug_print_send(hash)
|
120
|
+
return unless @debug_protocol
|
121
|
+
|
122
|
+
puts "SEND > #{hash}"
|
123
|
+
end
|
124
|
+
|
125
|
+
def debug_print_recv(hash)
|
126
|
+
return unless @debug_protocol
|
127
|
+
|
128
|
+
puts "RECV < #{hash}"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Minibidi
|
2
|
+
class BrowserProcess
|
3
|
+
def initialize(*command)
|
4
|
+
stdin, @stdout, @stderr, @thread = Open3.popen3(*command, { pgroup: true })
|
5
|
+
stdin.close
|
6
|
+
@pid = @thread.pid
|
7
|
+
rescue Errno::ENOENT => err
|
8
|
+
raise LaunchError.new("Failed to launch browser process: #{err}")
|
9
|
+
end
|
10
|
+
|
11
|
+
def kill
|
12
|
+
Process.kill(:KILL, @pid)
|
13
|
+
rescue Errno::ESRCH
|
14
|
+
# already killed
|
15
|
+
end
|
16
|
+
|
17
|
+
def dispose
|
18
|
+
[@stdout, @stderr].each { |io| io.close unless io.closed? }
|
19
|
+
@thread.terminate
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :stdout, :stderr
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module Minibidi
|
4
|
+
class BrowsingContext
|
5
|
+
def initialize(browser, context_id)
|
6
|
+
@browser = browser
|
7
|
+
@context_id = context_id
|
8
|
+
end
|
9
|
+
|
10
|
+
def navigate(url)
|
11
|
+
bidi_call_async('browsingContext.navigate', { url: url, wait: :interactive }).wait
|
12
|
+
end
|
13
|
+
|
14
|
+
def capture_screenshot(origin:, format:)
|
15
|
+
result = bidi_call_async('browsingContext.captureScreenshot', {
|
16
|
+
origin: origin,
|
17
|
+
format: format,
|
18
|
+
}).wait
|
19
|
+
|
20
|
+
Base64.strict_decode64(result[:data])
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def bidi_call_async(method_, params = {})
|
26
|
+
@browser.bidi_call_async(method_, params.merge({ context: @context_id }))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
require 'async'
|
2
|
+
require 'async/http/endpoint'
|
3
|
+
require 'async/websocket'
|
4
|
+
require 'open3'
|
5
|
+
require 'protocol/websocket/json_message'
|
6
|
+
require 'timeout'
|
7
|
+
require 'tmpdir'
|
8
|
+
|
9
|
+
module Minibidi
|
10
|
+
class FirefoxLauncher
|
11
|
+
def launch(&block)
|
12
|
+
raise ArgumentError, "block is required" unless block
|
13
|
+
|
14
|
+
Dir.mktmpdir('minibidi') do |tmp|
|
15
|
+
create_user_profile(tmp)
|
16
|
+
|
17
|
+
proc = BrowserProcess.new(
|
18
|
+
"/Applications/Firefox Developer Edition.app/Contents/MacOS/firefox",
|
19
|
+
"--remote-debugging-port=0",
|
20
|
+
"--profile #{tmp}",
|
21
|
+
"--no-remote",
|
22
|
+
"--foreground",
|
23
|
+
"about:blank",
|
24
|
+
)
|
25
|
+
at_exit { proc.kill }
|
26
|
+
trap(:INT) { proc.kill ; exit 130 }
|
27
|
+
trap(:TERM) { proc.kill ; proc.dispose }
|
28
|
+
trap(:HUP) { proc.kill ; proc.dispose }
|
29
|
+
|
30
|
+
endpoint = wait_for_ws_endpoint(proc)
|
31
|
+
|
32
|
+
Async::Reactor.run do
|
33
|
+
Async::WebSocket::Client.connect(Async::HTTP::Endpoint.parse("#{endpoint}/session")) do |async_websocket_connection|
|
34
|
+
browser = Browser.new(async_websocket_connection)
|
35
|
+
begin
|
36
|
+
block.call(browser)
|
37
|
+
ensure
|
38
|
+
browser.close
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def create_user_profile(profile_dir)
|
48
|
+
open(File.join(profile_dir, 'user.js'), 'w') do |f|
|
49
|
+
f.write(template_for_user_profile)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def template_for_user_profile
|
54
|
+
# execute the code below to create a template of user profile for Firefox.
|
55
|
+
# -----------
|
56
|
+
# import { createProfile } from '@puppeteer/browsers';
|
57
|
+
#
|
58
|
+
# await createProfile('firefox', {
|
59
|
+
# path: './my_prefs',
|
60
|
+
# preferences: {
|
61
|
+
# 'remote.active-protocols': 1,
|
62
|
+
# 'fission.webContentIsolationStrategy': 0,
|
63
|
+
# }
|
64
|
+
# })
|
65
|
+
<<~JS
|
66
|
+
user_pref("app.normandy.api_url", "");
|
67
|
+
user_pref("app.update.checkInstallTime", false);
|
68
|
+
user_pref("app.update.disabledForTesting", true);
|
69
|
+
user_pref("apz.content_response_timeout", 60000);
|
70
|
+
user_pref("browser.contentblocking.features.standard", "-tp,tpPrivate,cookieBehavior0,-cm,-fp");
|
71
|
+
user_pref("browser.dom.window.dump.enabled", true);
|
72
|
+
user_pref("browser.newtabpage.activity-stream.feeds.system.topstories", false);
|
73
|
+
user_pref("browser.newtabpage.enabled", false);
|
74
|
+
user_pref("browser.pagethumbnails.capturing_disabled", true);
|
75
|
+
user_pref("browser.safebrowsing.blockedURIs.enabled", false);
|
76
|
+
user_pref("browser.safebrowsing.downloads.enabled", false);
|
77
|
+
user_pref("browser.safebrowsing.malware.enabled", false);
|
78
|
+
user_pref("browser.safebrowsing.phishing.enabled", false);
|
79
|
+
user_pref("browser.search.update", false);
|
80
|
+
user_pref("browser.sessionstore.resume_from_crash", false);
|
81
|
+
user_pref("browser.shell.checkDefaultBrowser", false);
|
82
|
+
user_pref("browser.startup.homepage", "about:blank");
|
83
|
+
user_pref("browser.startup.homepage_override.mstone", "ignore");
|
84
|
+
user_pref("browser.startup.page", 0);
|
85
|
+
user_pref("browser.tabs.disableBackgroundZombification", false);
|
86
|
+
user_pref("browser.tabs.warnOnCloseOtherTabs", false);
|
87
|
+
user_pref("browser.tabs.warnOnOpen", false);
|
88
|
+
user_pref("browser.translations.automaticallyPopup", false);
|
89
|
+
user_pref("browser.uitour.enabled", false);
|
90
|
+
user_pref("browser.urlbar.suggest.searches", false);
|
91
|
+
user_pref("browser.usedOnWindows10.introURL", "");
|
92
|
+
user_pref("browser.warnOnQuit", false);
|
93
|
+
user_pref("datareporting.healthreport.documentServerURI", "http://dummy.test/dummy/healthreport/");
|
94
|
+
user_pref("datareporting.healthreport.logging.consoleEnabled", false);
|
95
|
+
user_pref("datareporting.healthreport.service.enabled", false);
|
96
|
+
user_pref("datareporting.healthreport.service.firstRun", false);
|
97
|
+
user_pref("datareporting.healthreport.uploadEnabled", false);
|
98
|
+
user_pref("datareporting.policy.dataSubmissionEnabled", false);
|
99
|
+
user_pref("datareporting.policy.dataSubmissionPolicyBypassNotification", true);
|
100
|
+
user_pref("devtools.jsonview.enabled", false);
|
101
|
+
user_pref("dom.disable_open_during_load", false);
|
102
|
+
user_pref("dom.file.createInChild", true);
|
103
|
+
user_pref("dom.ipc.reportProcessHangs", false);
|
104
|
+
user_pref("dom.max_chrome_script_run_time", 0);
|
105
|
+
user_pref("dom.max_script_run_time", 0);
|
106
|
+
user_pref("extensions.autoDisableScopes", 0);
|
107
|
+
user_pref("extensions.enabledScopes", 5);
|
108
|
+
user_pref("extensions.getAddons.cache.enabled", false);
|
109
|
+
user_pref("extensions.installDistroAddons", false);
|
110
|
+
user_pref("extensions.screenshots.disabled", true);
|
111
|
+
user_pref("extensions.update.enabled", false);
|
112
|
+
user_pref("extensions.update.notifyUser", false);
|
113
|
+
user_pref("extensions.webservice.discoverURL", "http://dummy.test/dummy/discoveryURL");
|
114
|
+
user_pref("focusmanager.testmode", true);
|
115
|
+
user_pref("general.useragent.updates.enabled", false);
|
116
|
+
user_pref("geo.provider.testing", true);
|
117
|
+
user_pref("geo.wifi.scan", false);
|
118
|
+
user_pref("hangmonitor.timeout", 0);
|
119
|
+
user_pref("javascript.options.showInConsole", true);
|
120
|
+
user_pref("media.gmp-manager.updateEnabled", false);
|
121
|
+
user_pref("media.sanity-test.disabled", true);
|
122
|
+
user_pref("network.cookie.sameSite.laxByDefault", false);
|
123
|
+
user_pref("network.http.prompt-temp-redirect", false);
|
124
|
+
user_pref("network.http.speculative-parallel-limit", 0);
|
125
|
+
user_pref("network.manage-offline-status", false);
|
126
|
+
user_pref("network.sntp.pools", "dummy.test");
|
127
|
+
user_pref("plugin.state.flash", 0);
|
128
|
+
user_pref("privacy.trackingprotection.enabled", false);
|
129
|
+
user_pref("remote.enabled", true);
|
130
|
+
user_pref("security.certerrors.mitm.priming.enabled", false);
|
131
|
+
user_pref("security.fileuri.strict_origin_policy", false);
|
132
|
+
user_pref("security.notification_enable_delay", 0);
|
133
|
+
user_pref("services.settings.server", "http://dummy.test/dummy/blocklist/");
|
134
|
+
user_pref("signon.autofillForms", false);
|
135
|
+
user_pref("signon.rememberSignons", false);
|
136
|
+
user_pref("startup.homepage_welcome_url", "about:blank");
|
137
|
+
user_pref("startup.homepage_welcome_url.additional", "");
|
138
|
+
user_pref("toolkit.cosmeticAnimations.enabled", false);
|
139
|
+
user_pref("toolkit.startup.max_resumed_crashes", -1);
|
140
|
+
user_pref("remote.active-protocols", 1);
|
141
|
+
user_pref("fission.webContentIsolationStrategy", 0);
|
142
|
+
JS
|
143
|
+
end
|
144
|
+
|
145
|
+
def wait_for_ws_endpoint(browser_process)
|
146
|
+
lines = []
|
147
|
+
Timeout.timeout(30) do
|
148
|
+
loop do
|
149
|
+
line = browser_process.stderr.readline
|
150
|
+
/^WebDriver BiDi listening on (ws:\/\/.*)$/.match(line) do |m|
|
151
|
+
return m[1].gsub(/\r/, '')
|
152
|
+
end
|
153
|
+
lines << line
|
154
|
+
end
|
155
|
+
end
|
156
|
+
rescue EOFError
|
157
|
+
raise LaunchError.new(lines.join("\n"))
|
158
|
+
rescue Timeout::Error
|
159
|
+
raise LaunchError.new("Timed out after 30 seconds while trying to connect to the browser.")
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
data/lib/minibidi.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require "minibidi/version"
|
2
|
+
|
3
|
+
require 'minibidi/browser'
|
4
|
+
require 'minibidi/browsing_context'
|
5
|
+
require 'minibidi/browser_process'
|
6
|
+
require 'minibidi/firefox'
|
7
|
+
require 'minibidi/firefox_launcher'
|
8
|
+
|
9
|
+
module Minibidi
|
10
|
+
class LaunchError < StandardError ; end
|
11
|
+
end
|
data/minibidi.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "minibidi/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "minibidi"
|
8
|
+
spec.version = Minibidi::VERSION
|
9
|
+
spec.authors = ["YusukeIwaki"]
|
10
|
+
spec.email = ["q7w8e9w8q7w8e9@yahoo.co.jp"]
|
11
|
+
|
12
|
+
spec.summary = "Mini WebDriver BiDi binding for Ruby"
|
13
|
+
spec.homepage = 'https://github.com/YusukeIwaki/minibidi'
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
17
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/}) || f.include?(".git")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
spec.bindir = 'exe'
|
22
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
|
+
spec.require_paths = ['lib']
|
24
|
+
|
25
|
+
spec.required_ruby_version = ">= 3.2" # Dependency for socketry/async and Data.define
|
26
|
+
spec.add_dependency "async"
|
27
|
+
spec.add_dependency "async-websocket"
|
28
|
+
spec.add_development_dependency "bundler"
|
29
|
+
spec.add_development_dependency "minitest"
|
30
|
+
spec.add_development_dependency "pry"
|
31
|
+
spec.add_development_dependency "rake"
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: minibidi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- YusukeIwaki
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-04-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: async
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: async-websocket
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description:
|
98
|
+
email:
|
99
|
+
- q7w8e9w8q7w8e9@yahoo.co.jp
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- Gemfile
|
105
|
+
- LICENSE.txt
|
106
|
+
- README.md
|
107
|
+
- Rakefile
|
108
|
+
- bin/console
|
109
|
+
- lib/minibidi.rb
|
110
|
+
- lib/minibidi/browser.rb
|
111
|
+
- lib/minibidi/browser_process.rb
|
112
|
+
- lib/minibidi/browsing_context.rb
|
113
|
+
- lib/minibidi/firefox.rb
|
114
|
+
- lib/minibidi/firefox_launcher.rb
|
115
|
+
- lib/minibidi/version.rb
|
116
|
+
- minibidi.gemspec
|
117
|
+
homepage: https://github.com/YusukeIwaki/minibidi
|
118
|
+
licenses:
|
119
|
+
- MIT
|
120
|
+
metadata: {}
|
121
|
+
post_install_message:
|
122
|
+
rdoc_options: []
|
123
|
+
require_paths:
|
124
|
+
- lib
|
125
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - ">="
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '3.2'
|
130
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
|
+
requirements:
|
132
|
+
- - ">="
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
requirements: []
|
136
|
+
rubygems_version: 3.5.3
|
137
|
+
signing_key:
|
138
|
+
specification_version: 4
|
139
|
+
summary: Mini WebDriver BiDi binding for Ruby
|
140
|
+
test_files: []
|