watir 2.0.4 → 3.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +41 -0
- data/VERSION +1 -1
- data/lib/watir/collections.rb +9 -17
- data/lib/watir/container.rb +2 -14
- data/lib/watir/core.rb +1 -0
- data/lib/watir/dialogs/file_field.rb +4 -2
- data/lib/watir/element.rb +146 -90
- data/lib/watir/element_collections.rb +13 -11
- data/lib/watir/form.rb +4 -2
- data/lib/watir/frame.rb +15 -3
- data/lib/watir/ie-class.rb +100 -128
- data/lib/watir/image.rb +10 -13
- data/lib/watir/input_elements.rb +92 -156
- data/lib/watir/locator.rb +61 -66
- data/lib/watir/non_control_elements.rb +8 -1
- data/lib/watir/table.rb +89 -242
- data/lib/watir/window.rb +68 -0
- metadata +21 -14
data/CHANGES
CHANGED
@@ -1,3 +1,44 @@
|
|
1
|
+
== 3.0.0 - 2012/01/13 - more conformance with WatirSpec
|
2
|
+
|
3
|
+
* Button#text returns value if exists instead of text
|
4
|
+
* Browser#goto prepends url automatically with http:// if scheme is missing
|
5
|
+
* Browser#element(s)_by_(xpath/css) are now private methods - use #element(:css => ...) and #element(:xpath => ...) instead
|
6
|
+
* Browser#label supports searching by :for attribute
|
7
|
+
* Browser#options method for searching <option> elements
|
8
|
+
* Browser#body, #thead, #tfoot, #tbody, #frameset and #fieldset added
|
9
|
+
* Browser#window and Browser#windows added implementing window switching API (https://github.com/jarib/watirspec/blob/master/window_switching_spec.rb)
|
10
|
+
* Element#present? returns false if exception is thrown by #exists? or #visible?
|
11
|
+
* Element#style returns CSS text instead of OLE object
|
12
|
+
* Element#text returns an empty string for non-visible elements
|
13
|
+
* Element#parent returns correct instance of Element class (e.g. Div instead of Element)
|
14
|
+
* Element#focus focuses document before focusing on the element
|
15
|
+
* Element#right_click and Element#double_click added
|
16
|
+
* Element#to_subtype added which returns specific instance of Watir::Element subclass
|
17
|
+
* Element#send_keys added
|
18
|
+
* Element#eql? as an alias for Element#== added
|
19
|
+
* Element#tag_name added
|
20
|
+
* ElementCollection#[] method supports negative indexes like regular Arrays
|
21
|
+
* ElementCollection#[] returns always an object, even if the index is out of bounds
|
22
|
+
* FileField#set and Image#save uses correct Windows file path (e.g. convert "\"-es into "/"-es)
|
23
|
+
* FileField#set raises Errno::ENOENT instead of WatirException if file doesn't exist
|
24
|
+
* FileField#value= as an alias for FileField#set added
|
25
|
+
* Font#color, #face and #size added
|
26
|
+
* Form#submit triggers onSubmit event and doesn't submit the form if event's callback returns false
|
27
|
+
* Frame#execute_script added
|
28
|
+
* Image#file_size, #height and #width return integer instead of a string
|
29
|
+
* Image#save blocking fixed
|
30
|
+
* Meta#content and #http_equiv added
|
31
|
+
* Option code rewritten, causing changes in its API
|
32
|
+
* SelectList code rewritten, causing changes in its API
|
33
|
+
* SelectList#(selected_)options returns now Options collection instead of an array of strings
|
34
|
+
* Table and its subelements code rewritten, causing changes in its API
|
35
|
+
* Table#strings and #hashes added
|
36
|
+
* TextField#label added
|
37
|
+
* searching elements will find only correct types - e.g. using Browser#div returns only DIV element even if all other provided selectors match
|
38
|
+
* all selectors and tag of the element needs to match even if searching by :id
|
39
|
+
* supporting html5 data-* attributes by using :data_* for locating and #data_* for retrieving attribute values
|
40
|
+
* many other internal changes
|
41
|
+
|
1
42
|
== Version 2.0.4 - 2011/10/29
|
2
43
|
|
3
44
|
* IE#execute_script escapes multi-line JavaScript scripts
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
3.0.0.rc1
|
data/lib/watir/collections.rb
CHANGED
@@ -1,25 +1,13 @@
|
|
1
1
|
module Watir
|
2
2
|
class InputElementCollections < ElementCollections
|
3
3
|
def each
|
4
|
-
@container.
|
4
|
+
@container.locator_for(InputElementLocator, element_class::INPUT_TYPES, @how, @what, element_class).each {|element| yield element}
|
5
5
|
end
|
6
6
|
end
|
7
7
|
|
8
|
-
class Frames < ElementCollections
|
9
|
-
def each
|
10
|
-
@container.locator_for(FrameLocator, @how, @what).each {|element| yield element}
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
class Forms < ElementCollections
|
15
|
-
def each
|
16
|
-
@container.locator_for(FormLocator, @how, @what).each {|element| yield element}
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
8
|
class HTMLElements < ElementCollections
|
21
9
|
def each
|
22
|
-
@container.locator_for(
|
10
|
+
@container.locator_for(TaggedElementLocator, ["*"], @how, @what, Element).each { |element| yield element }
|
23
11
|
end
|
24
12
|
end
|
25
13
|
|
@@ -44,10 +32,14 @@ module Watir
|
|
44
32
|
class Inses < ElementCollections
|
45
33
|
def element_class; Ins; end
|
46
34
|
end
|
47
|
-
|
48
|
-
|
35
|
+
|
36
|
+
class TableSectionCollection < ElementCollections
|
37
|
+
def element_class; TableSection; end
|
38
|
+
end
|
39
|
+
|
40
|
+
%w[Form Frame Link Li Map Area Image Table TableRow TableCell TableHeader TableFooter TableBody
|
49
41
|
Label Pre P Span Div Dl Dt Dd Strong Em Del
|
50
|
-
Font H1 H2 H3 H4 H5 H6 Meta Ol Ul].each do |element|
|
42
|
+
Font H1 H2 H3 H4 H5 H6 Meta Ol Ul FieldSet Option].each do |element|
|
51
43
|
module_eval %Q{
|
52
44
|
class #{element}s < ElementCollections; end
|
53
45
|
}
|
data/lib/watir/container.rb
CHANGED
@@ -98,20 +98,8 @@ module Watir
|
|
98
98
|
# Not for external use, but cannot set to private due to usages in Element
|
99
99
|
# classes.
|
100
100
|
|
101
|
-
def
|
102
|
-
locator =
|
103
|
-
locator.set_specifier how, what
|
104
|
-
locator
|
105
|
-
end
|
106
|
-
|
107
|
-
def tagged_element_locator(tag, how, what, klass=nil)
|
108
|
-
locator = TaggedElementLocator.new self, tag, klass
|
109
|
-
locator.set_specifier how, what
|
110
|
-
locator
|
111
|
-
end
|
112
|
-
|
113
|
-
def locator_for(locator_class, how, what)
|
114
|
-
locator = locator_class.new self
|
101
|
+
def locator_for(locator_class, tags, how, what, klass)
|
102
|
+
locator = locator_class.new self, tags, klass
|
115
103
|
locator.set_specifier how, what
|
116
104
|
locator
|
117
105
|
end
|
data/lib/watir/core.rb
CHANGED
@@ -8,12 +8,14 @@ module Watir
|
|
8
8
|
assert_file_exists(file_path)
|
9
9
|
assert_exists
|
10
10
|
click_no_wait
|
11
|
-
set_file_name file_path
|
11
|
+
set_file_name file_path.gsub(File::SEPARATOR, File::ALT_SEPARATOR)
|
12
12
|
open_button.click
|
13
13
|
end
|
14
14
|
|
15
|
+
alias_method :value=, :set
|
16
|
+
|
15
17
|
def assert_file_exists(file_path)
|
16
|
-
raise
|
18
|
+
raise Errno::ENOENT, "#{file_path} has to exist to set!" unless File.exists?(file_path)
|
17
19
|
end
|
18
20
|
|
19
21
|
def set_file_name(path_to_file)
|
data/lib/watir/element.rb
CHANGED
@@ -31,10 +31,14 @@ module Watir
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def locate
|
34
|
-
return if
|
35
|
-
|
36
|
-
|
37
|
-
|
34
|
+
return if self.class == Element
|
35
|
+
|
36
|
+
tags = @how.is_a?(Hash) && @how[:tag_name] ? [@how[:tag_name].upcase] :
|
37
|
+
self.class.const_defined?(:TAG) ? [self.class::TAG] :
|
38
|
+
self.class.const_defined?(:TAGS) ? self.class::TAGS :
|
39
|
+
[self.class.name.split("::").last.upcase]
|
40
|
+
@o = @container.locator_for(TaggedElementLocator, tags, @how, @what, self.class).locate
|
41
|
+
end
|
38
42
|
|
39
43
|
# Return the ole object, allowing any methods of the DOM that Watir doesn't support to be used.
|
40
44
|
def ole_object
|
@@ -50,19 +54,18 @@ module Watir
|
|
50
54
|
end
|
51
55
|
|
52
56
|
private
|
53
|
-
def self.def_wrap(
|
54
|
-
|
55
|
-
class_eval "def #{ruby_method_name}
|
57
|
+
def self.def_wrap(method_name, ole_method_name=nil)
|
58
|
+
class_eval "def #{method_name}
|
56
59
|
assert_exists
|
57
|
-
ole_object.invoke('#{ole_method_name}')
|
60
|
+
ole_object.invoke('#{ole_method_name || method_name}')
|
58
61
|
end"
|
59
62
|
end
|
60
63
|
|
61
|
-
def self.def_wrap_guard(method_name)
|
64
|
+
def self.def_wrap_guard(method_name, ole_method_name = nil)
|
62
65
|
class_eval "def #{method_name}
|
63
66
|
assert_exists
|
64
67
|
begin
|
65
|
-
ole_object.invoke('#{method_name}')
|
68
|
+
ole_object.invoke('#{ole_method_name || method_name}')
|
66
69
|
rescue
|
67
70
|
''
|
68
71
|
end
|
@@ -74,8 +77,12 @@ module Watir
|
|
74
77
|
def assert_exists
|
75
78
|
locate
|
76
79
|
unless ole_object
|
77
|
-
|
78
|
-
|
80
|
+
if self.is_a?(Frame)
|
81
|
+
raise UnknownFrameException.new(Watir::Exception.message_for_unable_to_locate(@how, @what))
|
82
|
+
else
|
83
|
+
raise UnknownObjectException.new(
|
84
|
+
Watir::Exception.message_for_unable_to_locate(@how, @what))
|
85
|
+
end
|
79
86
|
end
|
80
87
|
end
|
81
88
|
|
@@ -97,10 +104,6 @@ module Watir
|
|
97
104
|
# return the title of the element
|
98
105
|
def_wrap_guard :title
|
99
106
|
|
100
|
-
def_wrap_guard :currentstyle
|
101
|
-
# return current style instead of the inline style of the element
|
102
|
-
alias style currentstyle
|
103
|
-
|
104
107
|
def_wrap_guard :alt
|
105
108
|
def_wrap_guard :src
|
106
109
|
|
@@ -108,8 +111,6 @@ module Watir
|
|
108
111
|
def_wrap_guard :type # input elements only
|
109
112
|
# return the url the link points to
|
110
113
|
def_wrap :href # link only
|
111
|
-
# return the ID of the control that this label is associated with
|
112
|
-
def_wrap :for, :htmlFor # label only
|
113
114
|
# return the class name of the element
|
114
115
|
# raise an ObjectNotFound exception if the object cannot be found
|
115
116
|
def_wrap :class_name, :className
|
@@ -117,6 +118,55 @@ module Watir
|
|
117
118
|
def_wrap :unique_number, :uniqueNumber
|
118
119
|
# Return the outer html of the object - see http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/outerhtml.asp?frame=true
|
119
120
|
def_wrap :html, :outerHTML
|
121
|
+
# Return the "for" attribute for label
|
122
|
+
def_wrap_guard :for, :htmlFor
|
123
|
+
# Return the content attribute for meta tag
|
124
|
+
def_wrap_guard :content
|
125
|
+
# Return the http-equiv attribute for meta tag
|
126
|
+
def_wrap_guard :http_equiv, :httpEquiv
|
127
|
+
# Return font tag attributes
|
128
|
+
def_wrap_guard :color
|
129
|
+
def_wrap_guard :face
|
130
|
+
def_wrap_guard :size
|
131
|
+
# Return option label attribute
|
132
|
+
def_wrap_guard :label
|
133
|
+
# Return table rules attribute
|
134
|
+
def_wrap_guard :rules
|
135
|
+
# Return td headers attribute
|
136
|
+
def_wrap_guard :headers
|
137
|
+
|
138
|
+
def tag_name
|
139
|
+
assert_exists
|
140
|
+
@o.tagName.downcase
|
141
|
+
end
|
142
|
+
|
143
|
+
# returns specific Element subclass for current Element
|
144
|
+
def to_subtype
|
145
|
+
assert_exists
|
146
|
+
|
147
|
+
tag = tag_name
|
148
|
+
if tag == "html"
|
149
|
+
html_element(:ole_object, ole_object)
|
150
|
+
elsif tag == "input"
|
151
|
+
self.send(ole_object.invoke('type'), :ole_object, ole_object)
|
152
|
+
elsif tag == "select"
|
153
|
+
self.select_list(:ole_object, ole_object)
|
154
|
+
else
|
155
|
+
self.send(tag.downcase, :ole_object, ole_object)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# send keys to element
|
160
|
+
def send_keys(key_string)
|
161
|
+
focus
|
162
|
+
page_container.send_keys key_string
|
163
|
+
end
|
164
|
+
|
165
|
+
# return the css style as a string
|
166
|
+
def style
|
167
|
+
assert_exists
|
168
|
+
ole_object.style.cssText
|
169
|
+
end
|
120
170
|
|
121
171
|
# return the text before the element
|
122
172
|
def before_text # label only
|
@@ -138,18 +188,18 @@ module Watir
|
|
138
188
|
end
|
139
189
|
end
|
140
190
|
|
141
|
-
# Return the innerText of the object
|
191
|
+
# Return the innerText of the object or an empty string if the object is
|
192
|
+
# not visible
|
142
193
|
# Raise an ObjectNotFound exception if the object cannot be found
|
143
194
|
def text
|
144
195
|
assert_exists
|
145
|
-
|
196
|
+
visible? ? ole_object.innerText.strip : ""
|
146
197
|
end
|
147
198
|
|
148
199
|
# IE9 only returns empty string for ole_object.name for non-input elements
|
149
200
|
# so get at it through the attribute which will make the matchers work
|
150
201
|
def name
|
151
|
-
|
152
|
-
ole_object.getAttribute('name') || ''
|
202
|
+
attribute_value('name') || ''
|
153
203
|
end
|
154
204
|
|
155
205
|
def __ole_inner_elements
|
@@ -165,7 +215,9 @@ module Watir
|
|
165
215
|
# Return the element immediately containing self.
|
166
216
|
def parent
|
167
217
|
assert_exists
|
168
|
-
|
218
|
+
parent_element = ole_object.parentelement
|
219
|
+
return unless parent_element
|
220
|
+
result = Element.new(parent_element).to_subtype
|
169
221
|
result.set_container self
|
170
222
|
result
|
171
223
|
end
|
@@ -178,6 +230,8 @@ module Watir
|
|
178
230
|
ole_object.sourceindex <=> other.ole_object.sourceindex
|
179
231
|
end
|
180
232
|
|
233
|
+
alias_method :eql?, :==
|
234
|
+
|
181
235
|
# Return true if self is contained earlier in the html than other.
|
182
236
|
alias :before? :<
|
183
237
|
# Return true if self is contained later in the html than other.
|
@@ -256,9 +310,18 @@ module Watir
|
|
256
310
|
@container.wait
|
257
311
|
end
|
258
312
|
|
313
|
+
def right_click
|
314
|
+
perform_action {fire_event("oncontextmenu"); @container.wait}
|
315
|
+
end
|
316
|
+
|
317
|
+
def double_click
|
318
|
+
perform_action {fire_event("ondblclick"); @container.wait}
|
319
|
+
end
|
320
|
+
|
259
321
|
def replace_method(method)
|
260
322
|
method == 'click' ? 'click!' : method
|
261
323
|
end
|
324
|
+
|
262
325
|
private :replace_method
|
263
326
|
|
264
327
|
def build_method(method_name, *args)
|
@@ -271,6 +334,7 @@ module Watir
|
|
271
334
|
end
|
272
335
|
"#{replace_method(method_name)}(#{arguments.join(',')})"
|
273
336
|
end
|
337
|
+
|
274
338
|
private :build_method
|
275
339
|
|
276
340
|
def generate_ruby_code(element, method_name, *args)
|
@@ -280,6 +344,7 @@ module Watir
|
|
280
344
|
"require '#{File.expand_path(File.dirname(__FILE__))}/core';#{element}.#{method};"
|
281
345
|
return ruby_code
|
282
346
|
end
|
347
|
+
|
283
348
|
private :generate_ruby_code
|
284
349
|
|
285
350
|
def spawned_no_wait_command(command)
|
@@ -297,15 +362,12 @@ module Watir
|
|
297
362
|
private :spawned_no_wait_command
|
298
363
|
|
299
364
|
def click!
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
# so this seems to be the safest change and also works fine in IE8
|
307
|
-
ole_object.click(0)
|
308
|
-
highlight(:clear)
|
365
|
+
perform_action do
|
366
|
+
# Not sure why but in IE9 Document mode, passing a parameter
|
367
|
+
# to click seems to work. Firing the onClick event breaks other tests
|
368
|
+
# so this seems to be the safest change and also works fine in IE8
|
369
|
+
ole_object.click(0)
|
370
|
+
end
|
309
371
|
end
|
310
372
|
|
311
373
|
# Flash the element the specified number of times.
|
@@ -326,15 +388,12 @@ module Watir
|
|
326
388
|
# raises: UnknownObjectException if the object is not found
|
327
389
|
# ObjectDisabledException if the object is currently disabled
|
328
390
|
def fire_event(event)
|
329
|
-
|
330
|
-
assert_enabled
|
331
|
-
highlight(:set)
|
332
|
-
dispatch_event(event)
|
333
|
-
@container.wait
|
334
|
-
highlight(:clear)
|
391
|
+
perform_action {dispatch_event(event); @container.wait}
|
335
392
|
end
|
336
393
|
|
337
394
|
def dispatch_event(event)
|
395
|
+
assert_exists
|
396
|
+
|
338
397
|
if IE.version_parts.first.to_i >= 9
|
339
398
|
if @container.page_container.document_mode.to_i >= 9
|
340
399
|
ole_object.dispatchEvent(create_event(event))
|
@@ -347,34 +406,34 @@ module Watir
|
|
347
406
|
end
|
348
407
|
|
349
408
|
def create_event(event)
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
end
|
374
|
-
event = @container.page_container.document.createEvent(event_type)
|
375
|
-
event.send event_name, *event_args
|
376
|
-
event
|
409
|
+
event =~ /on(.*)/i
|
410
|
+
event = $1 if $1
|
411
|
+
event.downcase!
|
412
|
+
# See http://www.howtocreate.co.uk/tutorials/javascript/domevents
|
413
|
+
case event
|
414
|
+
when 'abort', 'blur', 'change', 'error', 'focus', 'load',
|
415
|
+
'reset', 'resize', 'scroll', 'select', 'submit', 'unload'
|
416
|
+
event_name = :initEvent
|
417
|
+
event_type = 'HTMLEvents'
|
418
|
+
event_args = [event, true, true]
|
419
|
+
when 'keydown', 'keypress', 'keyup'
|
420
|
+
event_name = :initKeyboardEvent
|
421
|
+
event_type = 'KeyboardEvent'
|
422
|
+
# 'type', bubbles, cancelable, windowObject, ctrlKey, altKey, shiftKey, metaKey, keyCode, charCode
|
423
|
+
event_args = [event, true, true, @container.page_container.document.parentWindow.window, false, false, false, false, 0, 0]
|
424
|
+
when 'click', 'dblclick', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup',
|
425
|
+
'contextmenu', 'drag', 'dragstart', 'dragenter', 'dragover', 'dragleave', 'dragend', 'drop', 'selectstart'
|
426
|
+
event_name = :initMouseEvent
|
427
|
+
event_type = 'MouseEvents'
|
428
|
+
# 'type', bubbles, cancelable, windowObject, detail, screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget
|
429
|
+
event_args = [event, true, true, @container.page_container.document.parentWindow.window, 1, 0, 0, 0, 0, false, false, false, false, 0, @container.page_container.document]
|
430
|
+
else
|
431
|
+
raise UnhandledEventException, "Don't know how to trigger event '#{event}'"
|
377
432
|
end
|
433
|
+
event = @container.page_container.document.createEvent(event_type)
|
434
|
+
event.send event_name, *event_args
|
435
|
+
event
|
436
|
+
end
|
378
437
|
|
379
438
|
# This method sets focus on the active element.
|
380
439
|
# raises: UnknownObjectException if the object is not found
|
@@ -382,6 +441,7 @@ module Watir
|
|
382
441
|
def focus
|
383
442
|
assert_exists
|
384
443
|
assert_enabled
|
444
|
+
@page_container.focus
|
385
445
|
ole_object.focus
|
386
446
|
end
|
387
447
|
|
@@ -401,7 +461,7 @@ module Watir
|
|
401
461
|
# raises: UnknownObjectException if the object is not found
|
402
462
|
def enabled?
|
403
463
|
assert_exists
|
404
|
-
|
464
|
+
!disabled
|
405
465
|
end
|
406
466
|
|
407
467
|
# If any parent element isn't visible then we cannot write to the
|
@@ -432,36 +492,32 @@ module Watir
|
|
432
492
|
# Returns null if attribute doesn't exist.
|
433
493
|
def attribute_value(attribute_name)
|
434
494
|
assert_exists
|
435
|
-
|
495
|
+
ole_object.getAttribute(attribute_name)
|
496
|
+
end
|
497
|
+
|
498
|
+
def perform_action
|
499
|
+
assert_exists
|
500
|
+
assert_enabled
|
501
|
+
highlight(:set)
|
502
|
+
yield
|
503
|
+
highlight(:clear)
|
436
504
|
end
|
437
505
|
|
506
|
+
private :perform_action
|
507
|
+
|
438
508
|
def method_missing(method_name, *args, &block)
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
509
|
+
meth = method_name.to_s
|
510
|
+
if meth =~ /(.*)_no_wait/ && self.respond_to?($1)
|
511
|
+
perform_action do
|
512
|
+
ruby_code = generate_ruby_code(self, $1, *args)
|
513
|
+
system(spawned_no_wait_command(ruby_code))
|
514
|
+
end
|
515
|
+
elsif meth =~ /^data_(.*)/
|
516
|
+
self.send(:attribute_value, meth.gsub("_", "-")) || ''
|
446
517
|
else
|
447
518
|
super
|
448
519
|
end
|
449
520
|
end
|
450
|
-
|
451
|
-
|
452
|
-
class ElementMapper # Still to be used
|
453
|
-
include Container
|
454
|
-
|
455
|
-
def initialize wrapper_class, container, how, what
|
456
|
-
@wrapper_class = wrapper_class
|
457
|
-
set_container
|
458
|
-
@how = how
|
459
|
-
@what = what
|
460
|
-
end
|
461
|
-
|
462
|
-
def method_missing method, *args
|
463
|
-
locate
|
464
|
-
@wrapper_class.new(@o).send(method, *args)
|
465
|
-
end
|
521
|
+
|
466
522
|
end
|
467
523
|
end
|