Class: Puppeteer::Page
- Inherits:
-
Object
- Object
- Puppeteer::Page
- Includes:
- EventCallbackable, IfPresent
- Defined in:
- lib/puppeteer/page.rb,
lib/puppeteer/page/screenshot_options.rb
Defined Under Namespace
Classes: ScreenshotOptions, ScriptTag, StyleTag, TargetCrashedError
Instance Attribute Summary collapse
-
#accessibility ⇒ Object
readonly
Returns the value of attribute accessibility.
-
#coverage ⇒ Object
readonly
Returns the value of attribute coverage.
-
#javascript_enabled ⇒ Object
/** * @param number, latitude: number, accuracy: (number|undefined)} options */ async setGeolocation(options) { const { longitude, latitude, accuracy = 0} = options; if (longitude < -180 || longitude > 180) throw new Error(`Invalid longitude “$longitude”: precondition -180 <= LONGITUDE <= 180 failed.`); if (latitude < -90 || latitude > 90) throw new Error(`Invalid latitude “$latitude”: precondition -90 <= LATITUDE <= 90 failed.`); if (accuracy < 0) throw new Error(`Invalid accuracy “$accuracy”: precondition 0 <= ACCURACY failed.`); await this._client.send('Emulation.setGeolocationOverride', latitude, accuracy); }.
-
#keyboard ⇒ Object
readonly
Returns the value of attribute keyboard.
-
#mouse ⇒ Object
readonly
Returns the value of attribute mouse.
-
#target ⇒ Object
readonly
/** * @param number, latitude: number, accuracy: (number|undefined)} options */ async setGeolocation(options) { const { longitude, latitude, accuracy = 0} = options; if (longitude < -180 || longitude > 180) throw new Error(`Invalid longitude “$longitude”: precondition -180 <= LONGITUDE <= 180 failed.`); if (latitude < -90 || latitude > 90) throw new Error(`Invalid latitude “$latitude”: precondition -90 <= LATITUDE <= 90 failed.`); if (accuracy < 0) throw new Error(`Invalid accuracy “$accuracy”: precondition 0 <= ACCURACY failed.`); await this._client.send('Emulation.setGeolocationOverride', latitude, accuracy); }.
-
#touch_screen ⇒ Object
readonly
Returns the value of attribute touch_screen.
-
#viewport ⇒ Object
Returns the value of attribute viewport.
Class Method Summary collapse
Instance Method Summary collapse
- #add_script_tag(script_tag) ⇒ !Promise<!ElementHandle>
- #add_style_tag(style_tag) ⇒ !Promise<!ElementHandle>
- #async_click ⇒ Future
- #async_wait_for_navigation ⇒ Future
- #authenticate(username: nil, password: nil) ⇒ Object
- #browser ⇒ Object
- #browser_context ⇒ Object
- #cache_enabled=(enabled) ⇒ Object
- #click(selector, delay: nil, button: nil, click_count: nil) ⇒ Object
- #close ⇒ Object
- #closed? ⇒ boolean
- #content ⇒ String
- #content=(html) ⇒ Object
- #default_navigation_timeout=(timeout) ⇒ Object
- #default_timeout=(timeout) ⇒ Object
- #emulate(device) ⇒ Object
- #emulate_timezone(timezone_id) ⇒ Object
- #evaluate(page_function, *args) ⇒ !Promise<*>
- #evaluate_handle(page_function, *args) ⇒ !Promise<!Puppeteer.JSHandle>
- #extra_http_headers=(headers) ⇒ Object
- #focus(selector) ⇒ Object
- #frames ⇒ Object
- #go_back(timeout: nil, wait_until: nil) ⇒ Object
- #go_forward(timeout: nil, wait_until: nil) ⇒ Object
- #goto(url, referer: nil, timeout: nil, wait_until: nil) ⇒ Object
- #hover(selector) ⇒ Object
- #init ⇒ Object
-
#initialize(client, target, ignore_https_errors, screenshot_task_queue) ⇒ Page
constructor
A new instance of Page.
- #main_frame ⇒ Object
- #offline_mode=(enabled) ⇒ Object
- #query_objects(prototype_handle) ⇒ !Promise<!Puppeteer.JSHandle>
- #reload(timeout: nil, wait_until: nil) ⇒ !Promise<?Puppeteer.Response>
- #request_interception=(value) ⇒ Object
-
#S(selector) ⇒ !Promise<?Puppeteer.ElementHandle>
`$()` in JavaScript.
-
#screenshot(options = {}) ⇒ Object
/** * @param !ScreenshotOptions= options * @return !Promise<!Buffer|!String> */.
- #select(selector, *values) ⇒ !Promise<!Array<string>>
- #set_content(html, timeout: nil, wait_until: nil) ⇒ Object
-
#Seval(selector, page_function, *args) ⇒ !Promise<(!Object|undefined)>
`$eval()` in JavaScript.
-
#SS(selector) ⇒ !Promise<!Array<!Puppeteer.ElementHandle>>
`$$()` in JavaScript.
-
#SSeval(selector, page_function, *args) ⇒ !Promise<(!Object|undefined)>
`$$eval()` in JavaScript.
-
#Sx(expression) ⇒ !Promise<!Array<!Puppeteer.ElementHandle>>
`$x()` in JavaScript.
- #tap(selector) ⇒ Object
- #title ⇒ !Promise<string>
- #type(selector, text, delay: nil) ⇒ Object
- #url ⇒ String
- #user_agent=(user_agent) ⇒ Object
- #wait_for_function(page_function, options = {}, *args) ⇒ !Promise<!Puppeteer.JSHandle>
- #wait_for_selector(selector, visible: nil, hidden: nil, timeout: nil) ⇒ !Promise<?Puppeteer.ElementHandle>
- #wait_for_xpath(xpath, visible: nil, hidden: nil, timeout: nil) ⇒ !Promise<?Puppeteer.ElementHandle>
- #workers ⇒ Object
Methods included from IfPresent
Methods included from EventCallbackable
#add_event_listener, #emit_event, #on_event, #remove_event_listener
Constructor Details
#initialize(client, target, ignore_https_errors, screenshot_task_queue) ⇒ Page
Returns a new instance of Page.
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/puppeteer/page.rb', line 29 def initialize(client, target, ignore_https_errors, screenshot_task_queue) @closed = false @client = client @target = target @keyboard = Puppeteer::Keyboard.new(client) @mouse = Puppeteer::Mouse.new(client, @keyboard) @timeout_settings = Puppeteer::TimeoutSettings.new @touchscreen = Puppeteer::TouchScreen.new(client, @keyboard) # @accessibility = Accessibility.new(client) @frame_manager = Puppeteer::FrameManager.new(client, self, ignore_https_errors, @timeout_settings) @emulation_manager = Puppeteer::EmulationManager.new(client) # @tracing = Tracing.new(client) @page_bindings = {} # @coverage = Coverage.new(client) @javascript_enabled = true @screenshot_task_queue = screenshot_task_queue @workers = {} @client.on_event 'Target.attachedToTarget' do |event| if event['targetInfo']['type'] != 'worker' # If we don't detach from service workers, they will never die. await @client.('Target.detachFromTarget', sessionId: event['sessionId']) next end session = Puppeteer::Connection.from_session(@client).session(event['sessionId']) # const worker = new Worker(session, event.targetInfo.url, this._addConsoleMessage.bind(this), this._handleException.bind(this)); # this._workers.set(event.sessionId, worker); # this.emit(Events.Page.WorkerCreated, worker); end @client.on_event 'Target.detachedFromTarget' do |event| session_id = event['sessionId'] worker = @workers[session_id] next unless worker emit_event('Events.Page.WorkerDestroyed', worker) @workers.delete(session_id) end @frame_manager.on_event 'Events.FrameManager.FrameAttached' do |event| emit_event 'Events.Page.FrameAttached', event end @frame_manager.on_event 'Events.FrameManager.FrameDetached' do |event| emit_event 'Events.Page.FrameDetached', event end @frame_manager.on_event 'Events.FrameManager.FrameNavigated' do |event| emit_event 'Events.Page.FrameNavigated', event end network_manager = @frame_manager.network_manager network_manager.on_event 'Events.NetworkManager.Request' do |event| emit_event 'Events.Page.Request', event end network_manager.on_event 'Events.NetworkManager.Response' do |event| emit_event 'Events.Page.Response', event end network_manager.on_event 'Events.NetworkManager.RequestFailed' do |event| emit_event 'Events.Page.RequestFailed', event end network_manager.on_event 'Events.NetworkManager.RequestFinished' do |event| emit_event 'Events.Page.RequestFinished', event end # this._fileChooserInterceptionIsDisabled = false; # this._fileChooserInterceptors = new Set(); @client.on_event 'Page.domContentEventFired' do |event| emit_event 'Events.Page.DOMContentLoaded' end @client.on_event 'Page.loadEventFired' do |event| emit_event 'Events.Page.Load' end # client.on('Runtime.consoleAPICalled', event => this._onConsoleAPI(event)); # client.on('Runtime.bindingCalled', event => this._onBindingCalled(event)); # client.on('Page.javascriptDialogOpening', event => this._onDialog(event)); # client.on('Runtime.exceptionThrown', exception => this._handleException(exception.exceptionDetails)); # client.on('Inspector.targetCrashed', event => this._onTargetCrashed()); # client.on('Performance.metrics', event => this._emitMetrics(event)); @client.on_event 'Log.entryAdded' do |event| handle_log_entry_added(event) end # client.on('Page.fileChooserOpened', event => this._onFileChooser(event)); @target.on_close do emit_event 'Events.Page.Close' @closed = true end end |
Instance Attribute Details
#accessibility ⇒ Object (readonly)
Returns the value of attribute accessibility.
219 220 221 |
# File 'lib/puppeteer/page.rb', line 219 def accessibility @accessibility end |
#coverage ⇒ Object (readonly)
Returns the value of attribute coverage.
219 220 221 |
# File 'lib/puppeteer/page.rb', line 219 def coverage @coverage end |
#javascript_enabled ⇒ Object
/**
* @param {!{longitude: number, latitude: number, accuracy: (number|undefined)}} options
*/
async setGeolocation(options)
const { longitude, latitude, accuracy = 0 = options;
if (longitude < -180 || longitude > 180)
throw new Error(`Invalid longitude "$longitude": precondition -180 <= LONGITUDE <= 180 failed.`);
if (latitude < -90 || latitude > 90)
throw new Error(`Invalid latitude "$latitude": precondition -90 <= LATITUDE <= 90 failed.`);
if (accuracy < 0)
throw new Error(`Invalid accuracy "$accuracy": precondition 0 <= ACCURACY failed.`);
await this._client.send('Emulation.setGeolocationOverride', latitude, accuracy);
}
176 177 178 |
# File 'lib/puppeteer/page.rb', line 176 def javascript_enabled @javascript_enabled end |
#keyboard ⇒ Object (readonly)
Returns the value of attribute keyboard.
219 220 221 |
# File 'lib/puppeteer/page.rb', line 219 def keyboard @keyboard end |
#mouse ⇒ Object (readonly)
Returns the value of attribute mouse.
935 936 937 |
# File 'lib/puppeteer/page.rb', line 935 def mouse @mouse end |
#target ⇒ Object (readonly)
/**
* @param {!{longitude: number, latitude: number, accuracy: (number|undefined)}} options
*/
async setGeolocation(options)
const { longitude, latitude, accuracy = 0 = options;
if (longitude < -180 || longitude > 180)
throw new Error(`Invalid longitude "$longitude": precondition -180 <= LONGITUDE <= 180 failed.`);
if (latitude < -90 || latitude > 90)
throw new Error(`Invalid latitude "$latitude": precondition -90 <= LATITUDE <= 90 failed.`);
if (accuracy < 0)
throw new Error(`Invalid accuracy "$accuracy": precondition 0 <= ACCURACY failed.`);
await this._client.send('Emulation.setGeolocationOverride', latitude, accuracy);
}
176 177 178 |
# File 'lib/puppeteer/page.rb', line 176 def target @target end |
#touch_screen ⇒ Object (readonly)
Returns the value of attribute touch_screen.
219 220 221 |
# File 'lib/puppeteer/page.rb', line 219 def touch_screen @touch_screen end |
#viewport ⇒ Object
Returns the value of attribute viewport.
758 759 760 |
# File 'lib/puppeteer/page.rb', line 758 def @viewport end |
Class Method Details
.create(client, target, ignore_https_errors, default_viewport, screenshot_task_queue) ⇒ !Promise<!Page>
16 17 18 19 20 21 22 23 |
# File 'lib/puppeteer/page.rb', line 16 def self.create(client, target, ignore_https_errors, , screenshot_task_queue) page = Puppeteer::Page.new(client, target, ignore_https_errors, screenshot_task_queue) page.init if page. = end page end |
Instance Method Details
#add_script_tag(script_tag) ⇒ !Promise<!ElementHandle>
357 358 359 |
# File 'lib/puppeteer/page.rb', line 357 def add_script_tag(script_tag) main_frame.add_script_tag(script_tag) end |
#add_style_tag(style_tag) ⇒ !Promise<!ElementHandle>
373 374 375 |
# File 'lib/puppeteer/page.rb', line 373 def add_style_tag(style_tag) main_frame.add_style_tag(style_tag) end |
#async_click ⇒ Future
950 951 952 |
# File 'lib/puppeteer/page.rb', line 950 async def async_click(selector, delay: nil, button: nil, click_count: nil) click(selector, delay: delay, button: , click_count: click_count) end |
#async_wait_for_navigation ⇒ Future
632 633 634 |
# File 'lib/puppeteer/page.rb', line 632 async def (timeout: nil, wait_until: nil) (timeout: timeout, wait_until: wait_until) end |
#authenticate(username: nil, password: nil) ⇒ Object
411 412 413 |
# File 'lib/puppeteer/page.rb', line 411 def authenticate(username: nil, password: nil) @frame_manager.network_manager.authenticate(username: username, password: password) end |
#browser ⇒ Object
178 179 180 |
# File 'lib/puppeteer/page.rb', line 178 def browser @target.browser end |
#browser_context ⇒ Object
182 183 184 |
# File 'lib/puppeteer/page.rb', line 182 def browser_context @target.browser_context end |
#cache_enabled=(enabled) ⇒ Object
777 778 779 |
# File 'lib/puppeteer/page.rb', line 777 def cache_enabled=(enabled) @frame_manager.network_manager.cache_enabled = enabled end |
#click(selector, delay: nil, button: nil, click_count: nil) ⇒ Object
941 942 943 |
# File 'lib/puppeteer/page.rb', line 941 def click(selector, delay: nil, button: nil, click_count: nil) main_frame.click(selector, delay: delay, button: , click_count: click_count) end |
#close ⇒ Object
919 920 921 922 923 924 925 926 927 928 |
# File 'lib/puppeteer/page.rb', line 919 def close # assert(!!this._client._connection, 'Protocol error: Connection closed. Most likely the page has been closed.'); # const runBeforeUnload = !!options.runBeforeUnload; # if (runBeforeUnload) { # await this._client.send('Page.close'); # } else { # await this._client._connection.send('Target.closeTarget', { targetId: this._target._targetId }); # await this._target._isClosedPromise; # } end |
#closed? ⇒ boolean
931 932 933 |
# File 'lib/puppeteer/page.rb', line 931 def closed? @closed end |
#content ⇒ String
590 591 592 |
# File 'lib/puppeteer/page.rb', line 590 def content main_frame.content end |
#content=(html) ⇒ Object
601 602 603 |
# File 'lib/puppeteer/page.rb', line 601 def content=(html) main_frame.set_content(html) end |
#default_navigation_timeout=(timeout) ⇒ Object
239 240 241 |
# File 'lib/puppeteer/page.rb', line 239 def (timeout) @timeout_settings. = timeout end |
#default_timeout=(timeout) ⇒ Object
244 245 246 |
# File 'lib/puppeteer/page.rb', line 244 def default_timeout=(timeout) @timeout_settings.default_timeout = timeout end |
#emulate(device) ⇒ Object
697 698 699 700 |
# File 'lib/puppeteer/page.rb', line 697 def emulate(device) self. = device. self.user_agent = device.user_agent end |
#emulate_timezone(timezone_id) ⇒ Object
741 742 743 744 745 746 747 748 749 |
# File 'lib/puppeteer/page.rb', line 741 def emulate_timezone(timezone_id) @client.('Emulation.setTimezoneOverride', timezoneId: timezoneId || '') rescue => err if err..include?('Invalid timezone') raise ArgumentError.new("Invalid timezone ID: #{timezone_id}") else raise err end end |
#evaluate(page_function, *args) ⇒ !Promise<*>
763 764 765 |
# File 'lib/puppeteer/page.rb', line 763 def evaluate(page_function, *args) main_frame.evaluate(page_function, *args) end |
#evaluate_handle(page_function, *args) ⇒ !Promise<!Puppeteer.JSHandle>
265 266 267 268 |
# File 'lib/puppeteer/page.rb', line 265 def evaluate_handle(page_function, *args) context = main_frame.execution_context context.evaluate_handle(page_function, *args) end |
#extra_http_headers=(headers) ⇒ Object
416 417 418 |
# File 'lib/puppeteer/page.rb', line 416 def extra_http_headers=(headers) @frame_manager.network_manager.extra_http_headers = headers end |
#focus(selector) ⇒ Object
955 956 957 |
# File 'lib/puppeteer/page.rb', line 955 def focus(selector) main_frame.focus(selector) end |
#frames ⇒ Object
221 222 223 |
# File 'lib/puppeteer/page.rb', line 221 def frames @frame_manager.frames end |
#go_back(timeout: nil, wait_until: nil) ⇒ Object
674 675 676 |
# File 'lib/puppeteer/page.rb', line 674 def go_back(timeout: nil, wait_until: nil) go(-1, timeout: timeout, wait_until: wait_until) end |
#go_forward(timeout: nil, wait_until: nil) ⇒ Object
680 681 682 |
# File 'lib/puppeteer/page.rb', line 680 def go_forward(timeout: nil, wait_until: nil) go(+1, timeout: timeout, wait_until: wait_until) end |
#goto(url, referer: nil, timeout: nil, wait_until: nil) ⇒ Object
609 610 611 |
# File 'lib/puppeteer/page.rb', line 609 def goto(url, referer: nil, timeout: nil, wait_until: nil) main_frame.goto(url, referer: referer, timeout: timeout, wait_until: wait_until) end |
#hover(selector) ⇒ Object
960 961 962 |
# File 'lib/puppeteer/page.rb', line 960 def hover(selector) main_frame.hover(selector) end |
#init ⇒ Object
116 117 118 119 120 121 122 123 |
# File 'lib/puppeteer/page.rb', line 116 def init await_all( @frame_manager.async_init, @client.('Target.setAutoAttach', autoAttach: true, waitForDebuggerOnStart: false, flatten: true), @client.('Performance.enable'), @client.('Log.enable'), ) end |
#main_frame ⇒ Object
215 216 217 |
# File 'lib/puppeteer/page.rb', line 215 def main_frame @frame_manager.main_frame end |
#offline_mode=(enabled) ⇒ Object
234 235 236 |
# File 'lib/puppeteer/page.rb', line 234 def offline_mode=(enabled) @frame_manager.network_manager.offline_mode = enabled end |
#query_objects(prototype_handle) ⇒ !Promise<!Puppeteer.JSHandle>
272 273 274 275 |
# File 'lib/puppeteer/page.rb', line 272 def query_objects(prototype_handle) context = main_frame.execution_context context.query_objects(prototype_handle) end |
#reload(timeout: nil, wait_until: nil) ⇒ !Promise<?Puppeteer.Response>
615 616 617 618 619 620 621 |
# File 'lib/puppeteer/page.rb', line 615 def reload(timeout: nil, wait_until: nil) # const [response] = await Promise.all([ # this.waitForNavigation(options), # this._client.send('Page.reload') # ]); # return response; end |
#request_interception=(value) ⇒ Object
230 231 232 |
# File 'lib/puppeteer/page.rb', line 230 def request_interception=(value) @frame_manager.network_manager.request_interception = value end |
#S(selector) ⇒ !Promise<?Puppeteer.ElementHandle>
`$()` in JavaScript. $ is not allowed to use as a method name in Ruby.
251 252 253 |
# File 'lib/puppeteer/page.rb', line 251 def S(selector) main_frame.S(selector) end |
#screenshot(options = {}) ⇒ Object
/**
* @param {!ScreenshotOptions=} options
* @return {!Promise<!Buffer|!String>}
*/
790 791 792 793 794 795 |
# File 'lib/puppeteer/page.rb', line 790 def screenshot( = {}) = ScreenshotOptions.new() # @screenshot_task_queue.post_task(-> { screenshot_task(screenshot_options.type, screenshot_options) }) screenshot_task(.type, ) end |
#select(selector, *values) ⇒ !Promise<!Array<string>>
967 968 969 |
# File 'lib/puppeteer/page.rb', line 967 def select(selector, *values) main_frame.select(selector, *values) end |
#set_content(html, timeout: nil, wait_until: nil) ⇒ Object
596 597 598 |
# File 'lib/puppeteer/page.rb', line 596 def set_content(html, timeout: nil, wait_until: nil) main_frame.set_content(html, timeout: timeout, wait_until: wait_until) end |
#Seval(selector, page_function, *args) ⇒ !Promise<(!Object|undefined)>
`$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
282 283 284 |
# File 'lib/puppeteer/page.rb', line 282 def Seval(selector, page_function, *args) main_frame.Seval(selector, page_function, *args) end |
#SS(selector) ⇒ !Promise<!Array<!Puppeteer.ElementHandle>>
`$$()` in JavaScript. $ is not allowed to use as a method name in Ruby.
258 259 260 |
# File 'lib/puppeteer/page.rb', line 258 def SS(selector) main_frame.SS(selector) end |
#SSeval(selector, page_function, *args) ⇒ !Promise<(!Object|undefined)>
`$$eval()` in JavaScript. $ is not allowed to use as a method name in Ruby.
291 292 293 |
# File 'lib/puppeteer/page.rb', line 291 def SSeval(selector, page_function, *args) main_frame.SSeval(selector, page_function, *args) end |
#Sx(expression) ⇒ !Promise<!Array<!Puppeteer.ElementHandle>>
`$x()` in JavaScript. $ is not allowed to use as a method name in Ruby.
298 299 300 |
# File 'lib/puppeteer/page.rb', line 298 def Sx(expression) main_frame.Sx(expression) end |
#tap(selector) ⇒ Object
972 973 974 |
# File 'lib/puppeteer/page.rb', line 972 def tap(selector) main_frame.tap(selector) end |
#title ⇒ !Promise<string>
782 783 784 |
# File 'lib/puppeteer/page.rb', line 782 def title @title end |
#type(selector, text, delay: nil) ⇒ Object
979 980 981 |
# File 'lib/puppeteer/page.rb', line 979 def type(selector, text, delay: nil) main_frame.type(selector, text, delay: delay) end |
#url ⇒ String
585 586 587 |
# File 'lib/puppeteer/page.rb', line 585 def url main_frame.url end |
#user_agent=(user_agent) ⇒ Object
421 422 423 |
# File 'lib/puppeteer/page.rb', line 421 def user_agent=(user_agent) @frame_manager.network_manager.user_agent = user_agent end |
#wait_for_function(page_function, options = {}, *args) ⇒ !Promise<!Puppeteer.JSHandle>
1011 1012 1013 |
# File 'lib/puppeteer/page.rb', line 1011 def wait_for_function(page_function, = {}, *args) main_frame.wait_for_function(page_function, , *args) end |
#wait_for_selector(selector, visible: nil, hidden: nil, timeout: nil) ⇒ !Promise<?Puppeteer.ElementHandle>
996 997 998 |
# File 'lib/puppeteer/page.rb', line 996 def wait_for_selector(selector, visible: nil, hidden: nil, timeout: nil) main_frame.wait_for_selector(selector, visible: visible, hidden: hidden, timeout: timeout) end |
#wait_for_xpath(xpath, visible: nil, hidden: nil, timeout: nil) ⇒ !Promise<?Puppeteer.ElementHandle>
1003 1004 1005 |
# File 'lib/puppeteer/page.rb', line 1003 def wait_for_xpath(xpath, visible: nil, hidden: nil, timeout: nil) main_frame.wait_for_xpath(xpath, visible: visible, hidden: hidden, timeout: timeout) end |
#workers ⇒ Object
225 226 227 |
# File 'lib/puppeteer/page.rb', line 225 def workers @workers.values end |