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']) return 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] return 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.
217 218 219 |
# File 'lib/puppeteer/page.rb', line 217 def accessibility @accessibility end |
#coverage ⇒ Object (readonly)
Returns the value of attribute coverage.
217 218 219 |
# File 'lib/puppeteer/page.rb', line 217 def coverage @coverage end |
#javascript_enabled ⇒ Object
/**
* @param {!{longitude: number, latitude: number, accuracy: (number|undefined)}}
*/
async setGeolocation(options)
const { longitude, latitude, accuracy = 0 = ;
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.
217 218 219 |
# File 'lib/puppeteer/page.rb', line 217 def keyboard @keyboard end |
#mouse ⇒ Object (readonly)
Returns the value of attribute mouse.
933 934 935 |
# File 'lib/puppeteer/page.rb', line 933 def mouse @mouse end |
#target ⇒ Object (readonly)
/**
* @param {!{longitude: number, latitude: number, accuracy: (number|undefined)}}
*/
async setGeolocation(options)
const { longitude, latitude, accuracy = 0 = ;
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.
217 218 219 |
# File 'lib/puppeteer/page.rb', line 217 def touch_screen @touch_screen end |
#viewport ⇒ Object
Returns the value of attribute viewport.
756 757 758 |
# File 'lib/puppeteer/page.rb', line 756 def 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>
355 356 357 |
# File 'lib/puppeteer/page.rb', line 355 def add_script_tag(script_tag) main_frame.add_script_tag(script_tag) end |
#add_style_tag(style_tag) ⇒ !Promise<!ElementHandle>
371 372 373 |
# File 'lib/puppeteer/page.rb', line 371 def add_style_tag(style_tag) main_frame.add_style_tag(style_tag) end |
#async_click ⇒ Future
948 949 950 |
# File 'lib/puppeteer/page.rb', line 948 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
630 631 632 |
# File 'lib/puppeteer/page.rb', line 630 async def (timeout: nil, wait_until: nil) (timeout: timeout, wait_until: wait_until) end |
#authenticate(username: nil, password: nil) ⇒ Object
409 410 411 |
# File 'lib/puppeteer/page.rb', line 409 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
775 776 777 |
# File 'lib/puppeteer/page.rb', line 775 def cache_enabled=(enabled) @frame_manager.network_manager.cache_enabled = enabled end |
#click(selector, delay: nil, button: nil, click_count: nil) ⇒ Object
939 940 941 |
# File 'lib/puppeteer/page.rb', line 939 def click(selector, delay: nil, button: nil, click_count: nil) main_frame.click(selector, delay: delay, button: , click_count: click_count) end |
#close ⇒ Object
917 918 919 920 921 922 923 924 925 926 |
# File 'lib/puppeteer/page.rb', line 917 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
929 930 931 |
# File 'lib/puppeteer/page.rb', line 929 def closed? @closed end |
#content ⇒ String
588 589 590 |
# File 'lib/puppeteer/page.rb', line 588 def content main_frame.content end |
#content=(html) ⇒ Object
599 600 601 |
# File 'lib/puppeteer/page.rb', line 599 def content=(html) main_frame.set_content(html) end |
#default_navigation_timeout=(timeout) ⇒ Object
237 238 239 |
# File 'lib/puppeteer/page.rb', line 237 def (timeout) @timeout_settings. = timeout end |
#default_timeout=(timeout) ⇒ Object
242 243 244 |
# File 'lib/puppeteer/page.rb', line 242 def default_timeout=(timeout) @timeout_settings.default_timeout = timeout end |
#emulate(device) ⇒ Object
695 696 697 698 |
# File 'lib/puppeteer/page.rb', line 695 def emulate(device) self. = device. self.user_agent = device.user_agent end |
#emulate_timezone(timezone_id) ⇒ Object
739 740 741 742 743 744 745 746 747 |
# File 'lib/puppeteer/page.rb', line 739 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<*>
761 762 763 |
# File 'lib/puppeteer/page.rb', line 761 def evaluate(page_function, *args) main_frame.evaluate(page_function, *args) end |
#evaluate_handle(page_function, *args) ⇒ !Promise<!Puppeteer.JSHandle>
263 264 265 266 |
# File 'lib/puppeteer/page.rb', line 263 def evaluate_handle(page_function, *args) context = main_frame.execution_context context.evaluate_handle(page_function, *args) end |
#extra_http_headers=(headers) ⇒ Object
414 415 416 |
# File 'lib/puppeteer/page.rb', line 414 def extra_http_headers=(headers) @frame_manager.network_manager.extra_http_headers = headers end |
#focus(selector) ⇒ Object
953 954 955 |
# File 'lib/puppeteer/page.rb', line 953 def focus(selector) main_frame.focus(selector) end |
#frames ⇒ Object
219 220 221 |
# File 'lib/puppeteer/page.rb', line 219 def frames @frame_manager.frames end |
#go_back(timeout: nil, wait_until: nil) ⇒ Object
672 673 674 |
# File 'lib/puppeteer/page.rb', line 672 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
678 679 680 |
# File 'lib/puppeteer/page.rb', line 678 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
607 608 609 |
# File 'lib/puppeteer/page.rb', line 607 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
958 959 960 |
# File 'lib/puppeteer/page.rb', line 958 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
213 214 215 |
# File 'lib/puppeteer/page.rb', line 213 def main_frame @frame_manager.main_frame end |
#offline_mode=(enabled) ⇒ Object
232 233 234 |
# File 'lib/puppeteer/page.rb', line 232 def offline_mode=(enabled) @frame_manager.network_manager.offline_mode = enabled end |
#query_objects(prototype_handle) ⇒ !Promise<!Puppeteer.JSHandle>
270 271 272 273 |
# File 'lib/puppeteer/page.rb', line 270 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>
613 614 615 616 617 618 619 |
# File 'lib/puppeteer/page.rb', line 613 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
228 229 230 |
# File 'lib/puppeteer/page.rb', line 228 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.
249 250 251 |
# File 'lib/puppeteer/page.rb', line 249 def S(selector) main_frame.S(selector) end |
#screenshot(options = {}) ⇒ Object
/**
* @param {!ScreenshotOptions=}
* @return {!Promise<!Buffer|!String>}
*/
788 789 790 791 792 793 |
# File 'lib/puppeteer/page.rb', line 788 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>>
965 966 967 |
# File 'lib/puppeteer/page.rb', line 965 def select(selector, *values) main_frame.select(selector, *values) end |
#set_content(html, timeout: nil, wait_until: nil) ⇒ Object
594 595 596 |
# File 'lib/puppeteer/page.rb', line 594 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.
280 281 282 |
# File 'lib/puppeteer/page.rb', line 280 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.
256 257 258 |
# File 'lib/puppeteer/page.rb', line 256 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.
289 290 291 |
# File 'lib/puppeteer/page.rb', line 289 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.
296 297 298 |
# File 'lib/puppeteer/page.rb', line 296 def Sx(expression) main_frame.Sx(expression) end |
#tap(selector) ⇒ Object
970 971 972 |
# File 'lib/puppeteer/page.rb', line 970 def tap(selector) main_frame.tap(selector) end |
#title ⇒ !Promise<string>
780 781 782 |
# File 'lib/puppeteer/page.rb', line 780 def title @title end |
#type(selector, text, delay: nil) ⇒ Object
977 978 979 |
# File 'lib/puppeteer/page.rb', line 977 def type(selector, text, delay: nil) main_frame.type(selector, text, delay: delay) end |
#url ⇒ String
583 584 585 |
# File 'lib/puppeteer/page.rb', line 583 def url main_frame.url end |
#user_agent=(user_agent) ⇒ Object
419 420 421 |
# File 'lib/puppeteer/page.rb', line 419 def user_agent=(user_agent) @frame_manager.network_manager.user_agent = user_agent end |
#wait_for_function(page_function, options = {}, *args) ⇒ !Promise<!Puppeteer.JSHandle>
1009 1010 1011 |
# File 'lib/puppeteer/page.rb', line 1009 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>
994 995 996 |
# File 'lib/puppeteer/page.rb', line 994 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>
1001 1002 1003 |
# File 'lib/puppeteer/page.rb', line 1001 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
223 224 225 |
# File 'lib/puppeteer/page.rb', line 223 def workers @workers.values end |