watir 2.0.4 → 3.0.0.rc1
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.
- 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
|