playwright-ruby-client 1.14.beta3 → 1.15.beta3
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 +4 -4
- data/README.md +10 -14
- data/documentation/docs/api/browser.md +4 -0
- data/documentation/docs/api/browser_context.md +5 -1
- data/documentation/docs/api/browser_type.md +2 -0
- data/documentation/docs/api/element_handle.md +30 -5
- data/documentation/docs/api/experimental/android_device.md +2 -0
- data/documentation/docs/api/frame.md +32 -6
- data/documentation/docs/api/locator.md +67 -38
- data/documentation/docs/api/mouse.md +11 -0
- data/documentation/docs/api/page.md +38 -7
- data/documentation/docs/api/request.md +34 -1
- data/documentation/docs/api/response.md +37 -2
- data/documentation/docs/api/selectors.md +29 -3
- data/documentation/docs/api/tracing.md +42 -8
- data/documentation/docs/api/worker.md +12 -11
- data/documentation/docs/article/getting_started.md +10 -1
- data/documentation/docs/article/guides/download_playwright_driver.md +9 -0
- data/documentation/docs/article/guides/inspector.md +1 -1
- data/documentation/docs/article/guides/playwright_on_alpine_linux.md +56 -3
- data/documentation/docs/article/guides/rails_integration.md +4 -2
- data/documentation/docs/article/guides/rails_integration_with_null_driver.md +86 -0
- data/documentation/docs/article/guides/recording_video.md +1 -1
- data/documentation/docs/article/guides/semi_automation.md +2 -2
- data/documentation/docs/article/guides/use_storage_state.md +78 -0
- data/documentation/docs/include/api_coverage.md +15 -0
- data/documentation/docusaurus.config.js +1 -0
- data/documentation/package.json +2 -2
- data/documentation/src/pages/index.js +0 -1
- data/documentation/static/img/playwright-ruby-client.png +0 -0
- data/documentation/yarn.lock +625 -549
- data/lib/playwright/channel.rb +36 -2
- data/lib/playwright/channel_owners/artifact.rb +6 -2
- data/lib/playwright/channel_owners/browser.rb +4 -0
- data/lib/playwright/channel_owners/browser_context.rb +21 -14
- data/lib/playwright/channel_owners/browser_type.rb +0 -1
- data/lib/playwright/channel_owners/element_handle.rb +10 -2
- data/lib/playwright/channel_owners/frame.rb +8 -0
- data/lib/playwright/channel_owners/page.rb +20 -4
- data/lib/playwright/channel_owners/playwright.rb +9 -0
- data/lib/playwright/channel_owners/request.rb +53 -17
- data/lib/playwright/channel_owners/response.rb +48 -5
- data/lib/playwright/connection.rb +8 -11
- data/lib/playwright/http_headers.rb +0 -6
- data/lib/playwright/locator_impl.rb +8 -0
- data/lib/playwright/mouse_impl.rb +9 -0
- data/lib/playwright/raw_headers.rb +61 -0
- data/lib/playwright/{route_handler_entry.rb → route_handler.rb} +30 -2
- data/lib/playwright/tracing_impl.rb +18 -7
- data/lib/playwright/transport.rb +2 -0
- data/lib/playwright/utils.rb +8 -1
- data/lib/playwright/version.rb +2 -2
- data/lib/playwright/web_socket_transport.rb +2 -0
- data/lib/playwright.rb +46 -5
- data/lib/playwright_api/android.rb +6 -6
- data/lib/playwright_api/android_device.rb +11 -9
- data/lib/playwright_api/browser.rb +12 -8
- data/lib/playwright_api/browser_context.rb +12 -8
- data/lib/playwright_api/browser_type.rb +9 -7
- data/lib/playwright_api/cdp_session.rb +7 -7
- data/lib/playwright_api/console_message.rb +6 -6
- data/lib/playwright_api/dialog.rb +6 -6
- data/lib/playwright_api/element_handle.rb +31 -8
- data/lib/playwright_api/frame.rb +35 -12
- data/lib/playwright_api/js_handle.rb +6 -6
- data/lib/playwright_api/locator.rb +39 -0
- data/lib/playwright_api/mouse.rb +8 -0
- data/lib/playwright_api/page.rb +43 -15
- data/lib/playwright_api/playwright.rb +6 -6
- data/lib/playwright_api/request.rb +33 -7
- data/lib/playwright_api/response.rb +31 -8
- data/lib/playwright_api/route.rb +6 -6
- data/lib/playwright_api/selectors.rb +38 -7
- data/lib/playwright_api/tracing.rb +33 -4
- data/lib/playwright_api/web_socket.rb +6 -6
- data/lib/playwright_api/worker.rb +8 -8
- metadata +8 -4
@@ -31,17 +31,12 @@ module Playwright
|
|
31
31
|
@transport.stop
|
32
32
|
end
|
33
33
|
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
end
|
38
|
-
|
39
|
-
callback = Concurrent::Promises.resolvable_future
|
40
|
-
@waiting_for_object[guid] = callback
|
41
|
-
callback.value!
|
34
|
+
def initialize_playwright
|
35
|
+
result = send_message_to_server('', 'initialize', { sdkLanguage: 'ruby' })
|
36
|
+
ChannelOwners::Playwright.from(result['playwright'])
|
42
37
|
end
|
43
38
|
|
44
|
-
def async_send_message_to_server(guid, method, params)
|
39
|
+
def async_send_message_to_server(guid, method, params, metadata: nil)
|
45
40
|
callback = Concurrent::Promises.resolvable_future
|
46
41
|
|
47
42
|
with_generated_id do |id|
|
@@ -54,7 +49,9 @@ module Playwright
|
|
54
49
|
guid: guid,
|
55
50
|
method: method,
|
56
51
|
params: replace_channels_with_guids(params),
|
52
|
+
metadata: metadata || {},
|
57
53
|
}
|
54
|
+
|
58
55
|
begin
|
59
56
|
@transport.send_message(message)
|
60
57
|
rescue => err
|
@@ -67,8 +64,8 @@ module Playwright
|
|
67
64
|
callback
|
68
65
|
end
|
69
66
|
|
70
|
-
def send_message_to_server(guid, method, params)
|
71
|
-
async_send_message_to_server(guid, method, params).value!
|
67
|
+
def send_message_to_server(guid, method, params, metadata: nil)
|
68
|
+
async_send_message_to_server(guid, method, params, metadata: metadata).value!
|
72
69
|
end
|
73
70
|
|
74
71
|
private
|
@@ -303,6 +303,14 @@ module Playwright
|
|
303
303
|
trial: trial)
|
304
304
|
end
|
305
305
|
|
306
|
+
def set_checked(checked, **options)
|
307
|
+
if checked
|
308
|
+
check(**options)
|
309
|
+
else
|
310
|
+
uncheck(**options)
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
306
314
|
def all_inner_texts
|
307
315
|
@frame.eval_on_selector_all(@selector, 'ee => ee.map(e => e.innerText)')
|
308
316
|
end
|
@@ -44,5 +44,14 @@ module Playwright
|
|
44
44
|
def dblclick(x, y, button: nil, delay: nil)
|
45
45
|
click(x, y, button: button, clickCount: 2, delay: delay)
|
46
46
|
end
|
47
|
+
|
48
|
+
def wheel(deltaX, deltaY)
|
49
|
+
params = {
|
50
|
+
deltaX: deltaX,
|
51
|
+
deltaY: deltaY,
|
52
|
+
}
|
53
|
+
@channel.send_message_to_server('mouseWheel', params)
|
54
|
+
nil
|
55
|
+
end
|
47
56
|
end
|
48
57
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Playwright
|
2
|
+
class RawHeaders
|
3
|
+
def initialize(headers_array)
|
4
|
+
h_array = []
|
5
|
+
h_map = {}
|
6
|
+
headers_array.each do |header|
|
7
|
+
name = header['name']
|
8
|
+
key = name.downcase
|
9
|
+
value = header['value']
|
10
|
+
|
11
|
+
h_array << [name, value]
|
12
|
+
h_map[key] ||= []
|
13
|
+
h_map[key] << value
|
14
|
+
end
|
15
|
+
|
16
|
+
@headers_array = h_array
|
17
|
+
@headers_map = h_map
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [String|nil]
|
21
|
+
def get(name)
|
22
|
+
key = name.downcase
|
23
|
+
values = @headers_map[key]
|
24
|
+
if values
|
25
|
+
join(key, values)
|
26
|
+
else
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# @return [Array<String>]
|
32
|
+
def get_all(name)
|
33
|
+
values = @headers_map[name.downcase]
|
34
|
+
if values
|
35
|
+
values.dup
|
36
|
+
else
|
37
|
+
[]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def headers
|
42
|
+
@headers_map.map do |key, values|
|
43
|
+
[key, join(key, values)]
|
44
|
+
end.to_h
|
45
|
+
end
|
46
|
+
|
47
|
+
def headers_array
|
48
|
+
@headers_array.map do |name, value|
|
49
|
+
{ name: name, value: value }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private def join(key, values)
|
54
|
+
if key == 'set-cookie'
|
55
|
+
values.join("\n")
|
56
|
+
else
|
57
|
+
values.join(", ")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -1,15 +1,43 @@
|
|
1
1
|
module Playwright
|
2
|
-
class
|
2
|
+
class RouteHandler
|
3
|
+
class CountDown
|
4
|
+
def initialize(count)
|
5
|
+
@count = count
|
6
|
+
end
|
7
|
+
|
8
|
+
def handle
|
9
|
+
return false if @count <= 0
|
10
|
+
|
11
|
+
@count = @count - 1
|
12
|
+
true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class StubCounter
|
17
|
+
def handle
|
18
|
+
true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
3
22
|
# @param url [String]
|
4
23
|
# @param base_url [String|nil]
|
5
24
|
# @param handler [Proc]
|
6
|
-
|
25
|
+
# @param times [Integer|nil]
|
26
|
+
def initialize(url, base_url, handler, times)
|
7
27
|
@url_value = url
|
8
28
|
@url_matcher = UrlMatcher.new(url, base_url: base_url)
|
9
29
|
@handler = handler
|
30
|
+
@counter =
|
31
|
+
if times
|
32
|
+
CountDown.new(times)
|
33
|
+
else
|
34
|
+
StubCounter.new
|
35
|
+
end
|
10
36
|
end
|
11
37
|
|
12
38
|
def handle(route, request)
|
39
|
+
return false unless @counter.handle
|
40
|
+
|
13
41
|
if @url_matcher.match?(request.url)
|
14
42
|
@handler.call(route, request)
|
15
43
|
true
|
@@ -12,19 +12,30 @@ module Playwright
|
|
12
12
|
snapshots: snapshots,
|
13
13
|
}.compact
|
14
14
|
@channel.send_message_to_server('tracingStart', params)
|
15
|
+
@channel.send_message_to_server('tracingStartChunk')
|
16
|
+
end
|
17
|
+
|
18
|
+
def start_chunk
|
19
|
+
@channel.send_message_to_server('tracingStartChunk')
|
20
|
+
end
|
21
|
+
|
22
|
+
def stop_chunk(path: nil)
|
23
|
+
do_stop_chunk(path: path)
|
15
24
|
end
|
16
25
|
|
17
|
-
# Stop tracing.
|
18
26
|
def stop(path: nil)
|
19
|
-
|
27
|
+
do_stop_chunk(path: path)
|
20
28
|
@channel.send_message_to_server('tracingStop')
|
21
29
|
end
|
22
30
|
|
23
|
-
private def
|
24
|
-
resp = @channel.send_message_to_server('
|
25
|
-
artifact = ChannelOwners::Artifact.
|
26
|
-
|
27
|
-
|
31
|
+
private def do_stop_chunk(path:)
|
32
|
+
resp = @channel.send_message_to_server('tracingStopChunk', save: !path.nil?)
|
33
|
+
artifact = ChannelOwners::Artifact.from_nullable(resp)
|
34
|
+
return unless artifact
|
35
|
+
|
36
|
+
if @context.browser.send(:remote?)
|
37
|
+
artifact.update_as_remote
|
38
|
+
end
|
28
39
|
artifact.save_as(path)
|
29
40
|
artifact.delete
|
30
41
|
end
|
data/lib/playwright/transport.rb
CHANGED
data/lib/playwright/utils.rb
CHANGED
@@ -3,7 +3,6 @@ module Playwright
|
|
3
3
|
module PrepareBrowserContextOptions
|
4
4
|
# @see https://github.com/microsoft/playwright/blob/5a2cfdbd47ed3c3deff77bb73e5fac34241f649d/src/client/browserContext.ts#L265
|
5
5
|
private def prepare_browser_context_options(params)
|
6
|
-
params[:sdkLanguage] = 'ruby'
|
7
6
|
if params[:noViewport] == 0
|
8
7
|
params.delete(:noViewport)
|
9
8
|
params[:noDefaultViewport] = true
|
@@ -11,6 +10,14 @@ module Playwright
|
|
11
10
|
if params[:extraHTTPHeaders]
|
12
11
|
params[:extraHTTPHeaders] = ::Playwright::HttpHeaders.new(params[:extraHTTPHeaders]).as_serialized
|
13
12
|
end
|
13
|
+
if params[:record_har_path]
|
14
|
+
params[:recordHar] = {
|
15
|
+
path: params.delete(:record_har_path)
|
16
|
+
}
|
17
|
+
if params[:record_har_omit_content]
|
18
|
+
params[:recordHar][:omitContent] = params.delete(:record_har_omit_content)
|
19
|
+
end
|
20
|
+
end
|
14
21
|
if params[:record_video_dir]
|
15
22
|
params[:recordVideo] = {
|
16
23
|
dir: params.delete(:record_video_dir)
|
data/lib/playwright/version.rb
CHANGED
data/lib/playwright.rb
CHANGED
@@ -20,7 +20,8 @@ require 'playwright/channel_owner'
|
|
20
20
|
require 'playwright/http_headers'
|
21
21
|
require 'playwright/input_files'
|
22
22
|
require 'playwright/connection'
|
23
|
-
require 'playwright/
|
23
|
+
require 'playwright/raw_headers'
|
24
|
+
require 'playwright/route_handler'
|
24
25
|
require 'playwright/select_option_values'
|
25
26
|
require 'playwright/timeout_settings'
|
26
27
|
require 'playwright/transport'
|
@@ -35,16 +36,18 @@ Dir[File.join(__dir__, 'playwright_api', '*.rb')].each { |f| require f }
|
|
35
36
|
|
36
37
|
module Playwright
|
37
38
|
class Execution
|
38
|
-
def initialize(connection, playwright)
|
39
|
+
def initialize(connection, playwright, browser = nil)
|
39
40
|
@connection = connection
|
40
41
|
@playwright = playwright
|
42
|
+
@browser = browser
|
41
43
|
end
|
42
44
|
|
43
45
|
def stop
|
46
|
+
@browser&.close
|
44
47
|
@connection.stop
|
45
48
|
end
|
46
49
|
|
47
|
-
attr_reader :playwright
|
50
|
+
attr_reader :playwright, :browser
|
48
51
|
end
|
49
52
|
|
50
53
|
# Recommended to call this method with block.
|
@@ -64,7 +67,7 @@ module Playwright
|
|
64
67
|
|
65
68
|
execution =
|
66
69
|
begin
|
67
|
-
playwright = connection.
|
70
|
+
playwright = connection.initialize_playwright
|
68
71
|
Execution.new(connection, PlaywrightApi.wrap(playwright))
|
69
72
|
rescue
|
70
73
|
connection.stop
|
@@ -100,7 +103,7 @@ module Playwright
|
|
100
103
|
|
101
104
|
execution =
|
102
105
|
begin
|
103
|
-
playwright = connection.
|
106
|
+
playwright = connection.initialize_playwright
|
104
107
|
Execution.new(connection, PlaywrightApi.wrap(playwright))
|
105
108
|
rescue
|
106
109
|
connection.stop
|
@@ -117,4 +120,42 @@ module Playwright
|
|
117
120
|
execution
|
118
121
|
end
|
119
122
|
end
|
123
|
+
|
124
|
+
# Connects to Playwright server, launched by `npx playwright launch-server chromium` or `playwright.chromium.launchServer()`
|
125
|
+
#
|
126
|
+
# Playwright.connect_to_browser_server('ws://....') do |browser|
|
127
|
+
# page = browser.new_page
|
128
|
+
# ...
|
129
|
+
# end
|
130
|
+
#
|
131
|
+
# @experimental
|
132
|
+
module_function def connect_to_browser_server(ws_endpoint, &block)
|
133
|
+
require 'playwright/web_socket_client'
|
134
|
+
require 'playwright/web_socket_transport'
|
135
|
+
|
136
|
+
transport = WebSocketTransport.new(ws_endpoint: ws_endpoint)
|
137
|
+
connection = Connection.new(transport)
|
138
|
+
connection.async_run
|
139
|
+
|
140
|
+
execution =
|
141
|
+
begin
|
142
|
+
playwright = connection.initialize_playwright
|
143
|
+
browser = playwright.send(:pre_launched_browser)
|
144
|
+
browser.send(:update_as_remote)
|
145
|
+
Execution.new(connection, PlaywrightApi.wrap(playwright), PlaywrightApi.wrap(browser))
|
146
|
+
rescue
|
147
|
+
connection.stop
|
148
|
+
raise
|
149
|
+
end
|
150
|
+
|
151
|
+
if block
|
152
|
+
begin
|
153
|
+
block.call(execution.browser)
|
154
|
+
ensure
|
155
|
+
execution.stop
|
156
|
+
end
|
157
|
+
else
|
158
|
+
execution
|
159
|
+
end
|
160
|
+
end
|
120
161
|
end
|
@@ -38,20 +38,20 @@ module Playwright
|
|
38
38
|
|
39
39
|
# -- inherited from EventEmitter --
|
40
40
|
# @nodoc
|
41
|
-
def
|
42
|
-
event_emitter_proxy.
|
41
|
+
def off(event, callback)
|
42
|
+
event_emitter_proxy.off(event, callback)
|
43
43
|
end
|
44
44
|
|
45
45
|
# -- inherited from EventEmitter --
|
46
46
|
# @nodoc
|
47
|
-
def
|
48
|
-
event_emitter_proxy.
|
47
|
+
def once(event, callback)
|
48
|
+
event_emitter_proxy.once(event, callback)
|
49
49
|
end
|
50
50
|
|
51
51
|
# -- inherited from EventEmitter --
|
52
52
|
# @nodoc
|
53
|
-
def
|
54
|
-
event_emitter_proxy.
|
53
|
+
def on(event, callback)
|
54
|
+
event_emitter_proxy.on(event, callback)
|
55
55
|
end
|
56
56
|
|
57
57
|
private def event_emitter_proxy
|
@@ -46,6 +46,7 @@ module Playwright
|
|
46
46
|
command: nil,
|
47
47
|
deviceScaleFactor: nil,
|
48
48
|
extraHTTPHeaders: nil,
|
49
|
+
forcedColors: nil,
|
49
50
|
geolocation: nil,
|
50
51
|
hasTouch: nil,
|
51
52
|
httpCredentials: nil,
|
@@ -62,11 +63,12 @@ module Playwright
|
|
62
63
|
record_video_size: nil,
|
63
64
|
reducedMotion: nil,
|
64
65
|
screen: nil,
|
66
|
+
strictSelectors: nil,
|
65
67
|
timezoneId: nil,
|
66
68
|
userAgent: nil,
|
67
69
|
viewport: nil,
|
68
70
|
&block)
|
69
|
-
wrap_impl(@impl.launch_browser(acceptDownloads: unwrap_impl(acceptDownloads), baseURL: unwrap_impl(baseURL), bypassCSP: unwrap_impl(bypassCSP), colorScheme: unwrap_impl(colorScheme), command: unwrap_impl(command), deviceScaleFactor: unwrap_impl(deviceScaleFactor), extraHTTPHeaders: unwrap_impl(extraHTTPHeaders), geolocation: unwrap_impl(geolocation), hasTouch: unwrap_impl(hasTouch), httpCredentials: unwrap_impl(httpCredentials), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), isMobile: unwrap_impl(isMobile), javaScriptEnabled: unwrap_impl(javaScriptEnabled), locale: unwrap_impl(locale), noViewport: unwrap_impl(noViewport), offline: unwrap_impl(offline), permissions: unwrap_impl(permissions), record_har_omit_content: unwrap_impl(record_har_omit_content), record_har_path: unwrap_impl(record_har_path), record_video_dir: unwrap_impl(record_video_dir), record_video_size: unwrap_impl(record_video_size), reducedMotion: unwrap_impl(reducedMotion), screen: unwrap_impl(screen), timezoneId: unwrap_impl(timezoneId), userAgent: unwrap_impl(userAgent), viewport: unwrap_impl(viewport), &wrap_block_call(block)))
|
71
|
+
wrap_impl(@impl.launch_browser(acceptDownloads: unwrap_impl(acceptDownloads), baseURL: unwrap_impl(baseURL), bypassCSP: unwrap_impl(bypassCSP), colorScheme: unwrap_impl(colorScheme), command: unwrap_impl(command), deviceScaleFactor: unwrap_impl(deviceScaleFactor), extraHTTPHeaders: unwrap_impl(extraHTTPHeaders), forcedColors: unwrap_impl(forcedColors), geolocation: unwrap_impl(geolocation), hasTouch: unwrap_impl(hasTouch), httpCredentials: unwrap_impl(httpCredentials), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), isMobile: unwrap_impl(isMobile), javaScriptEnabled: unwrap_impl(javaScriptEnabled), locale: unwrap_impl(locale), noViewport: unwrap_impl(noViewport), offline: unwrap_impl(offline), permissions: unwrap_impl(permissions), record_har_omit_content: unwrap_impl(record_har_omit_content), record_har_path: unwrap_impl(record_har_path), record_video_dir: unwrap_impl(record_video_dir), record_video_size: unwrap_impl(record_video_size), reducedMotion: unwrap_impl(reducedMotion), screen: unwrap_impl(screen), strictSelectors: unwrap_impl(strictSelectors), timezoneId: unwrap_impl(timezoneId), userAgent: unwrap_impl(userAgent), viewport: unwrap_impl(viewport), &wrap_block_call(block)))
|
70
72
|
end
|
71
73
|
|
72
74
|
# Performs a long tap on the widget defined by `selector`.
|
@@ -162,14 +164,20 @@ module Playwright
|
|
162
164
|
raise NotImplementedError.new('web_views is not implemented yet.')
|
163
165
|
end
|
164
166
|
|
167
|
+
# @nodoc
|
168
|
+
def tree
|
169
|
+
wrap_impl(@impl.tree)
|
170
|
+
end
|
171
|
+
|
165
172
|
# @nodoc
|
166
173
|
def tap_on(selector, duration: nil, timeout: nil)
|
167
174
|
wrap_impl(@impl.tap_on(unwrap_impl(selector), duration: unwrap_impl(duration), timeout: unwrap_impl(timeout)))
|
168
175
|
end
|
169
176
|
|
177
|
+
# -- inherited from EventEmitter --
|
170
178
|
# @nodoc
|
171
|
-
def
|
172
|
-
|
179
|
+
def off(event, callback)
|
180
|
+
event_emitter_proxy.off(event, callback)
|
173
181
|
end
|
174
182
|
|
175
183
|
# -- inherited from EventEmitter --
|
@@ -184,12 +192,6 @@ module Playwright
|
|
184
192
|
event_emitter_proxy.on(event, callback)
|
185
193
|
end
|
186
194
|
|
187
|
-
# -- inherited from EventEmitter --
|
188
|
-
# @nodoc
|
189
|
-
def off(event, callback)
|
190
|
-
event_emitter_proxy.off(event, callback)
|
191
|
-
end
|
192
|
-
|
193
195
|
private def event_emitter_proxy
|
194
196
|
@event_emitter_proxy ||= EventEmitterProxy.new(self, @impl)
|
195
197
|
end
|