vapir-common 1.8.1 → 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/vapir-common.rb +2 -0
- data/lib/vapir-common/config.rb +29 -7
- data/lib/vapir-common/container.rb +124 -56
- data/lib/vapir-common/element.rb +11 -2
- data/lib/vapir-common/element_class_and_module.rb +1 -1
- data/lib/vapir-common/elements/elements.rb +1 -0
- data/lib/vapir-common/external/core_extensions.rb +14 -4
- data/lib/vapir-common/specifier.rb +20 -7
- data/lib/vapir-common/version.rb +1 -1
- metadata +5 -5
data/lib/vapir-common.rb
CHANGED
@@ -4,6 +4,8 @@ require 'vapir-common/browser'
|
|
4
4
|
require 'vapir-common/exceptions'
|
5
5
|
require 'vapir-common/config'
|
6
6
|
module Vapir
|
7
|
+
# requires the winwindow library, raising a more informative error message than the default
|
8
|
+
# on failure.
|
7
9
|
def self.require_winwindow
|
8
10
|
begin
|
9
11
|
require 'winwindow'
|
data/lib/vapir-common/config.rb
CHANGED
@@ -5,6 +5,7 @@ module Vapir
|
|
5
5
|
class Error < StandardError; end
|
6
6
|
class BadKeyError < Error; end
|
7
7
|
class NoValueError < Error; end
|
8
|
+
class InvalidValueError < Error; end
|
8
9
|
|
9
10
|
# represents a valid option on a Configuration. consists of a key and criteria
|
10
11
|
# for which a value is valid for that key.
|
@@ -34,7 +35,7 @@ module Vapir
|
|
34
35
|
when 'false', false
|
35
36
|
false
|
36
37
|
else
|
37
|
-
raise
|
38
|
+
raise InvalidValueError, "value should look like a boolean for key #{key}; instead got #{value.inspect}"
|
38
39
|
end
|
39
40
|
when :numeric
|
40
41
|
case value
|
@@ -44,13 +45,21 @@ module Vapir
|
|
44
45
|
begin
|
45
46
|
Float(value)
|
46
47
|
rescue ArgumentError
|
47
|
-
raise
|
48
|
+
raise InvalidValueError, "value should look like a number for key #{key}; instead got #{value.inspect}"
|
48
49
|
end
|
49
50
|
else
|
50
|
-
raise
|
51
|
+
raise InvalidValueError, "value should look like a number for key #{key}; instead got #{value.inspect}"
|
52
|
+
end
|
53
|
+
when :positive_integer
|
54
|
+
if value.is_a?(Integer) && value > 0
|
55
|
+
value
|
56
|
+
elsif value.is_a?(String) && value.strip =~ /\A\d+\z/ && value.to_i > 0
|
57
|
+
value.to_i
|
58
|
+
else
|
59
|
+
raise InvalidValueError, "value should be a positive integer; got #{value.inspect}"
|
51
60
|
end
|
52
61
|
else
|
53
|
-
raise ArgumentError, "invalid validator given: #{@
|
62
|
+
raise ArgumentError, "invalid validator given: #{@validator.inspect}\nvalidator should be nil for unspecified, a Proc, or a symbol indicating a known validator type"
|
54
63
|
end
|
55
64
|
end
|
56
65
|
end
|
@@ -129,6 +138,14 @@ module Vapir
|
|
129
138
|
def defined_key?(key)
|
130
139
|
locally_defined_key?(key) || (parent && parent.defined_key?(key))
|
131
140
|
end
|
141
|
+
# returns an array of keys defined on the current configuration
|
142
|
+
def defined_keys
|
143
|
+
recognized_keys.select{|key| defined_key?(key) }
|
144
|
+
end
|
145
|
+
# returns a hash of currently defined configuration keys and values
|
146
|
+
def defined_hash
|
147
|
+
(@parent ? @parent.defined_hash : {}).merge(@config_hash).freeze
|
148
|
+
end
|
132
149
|
# raises an error if the given key is not in an acceptable format. the key should be a string
|
133
150
|
# or symbol consisting of alphanumerics and underscorse, beginning with an alpha or underscore.
|
134
151
|
def validate_key_format!(key)
|
@@ -212,7 +229,7 @@ module Vapir
|
|
212
229
|
end
|
213
230
|
# see Configuration#with_config
|
214
231
|
def with_config(hash, &block)
|
215
|
-
|
232
|
+
config.with_config(hash, &block)
|
216
233
|
end
|
217
234
|
private
|
218
235
|
# takes a hash of given options, a map of config keys, and a list of other allowed keys.
|
@@ -287,8 +304,9 @@ module Vapir
|
|
287
304
|
end
|
288
305
|
end
|
289
306
|
|
307
|
+
# :stopdoc:
|
290
308
|
@configurations = []
|
291
|
-
def (@configurations).update_from_source
|
309
|
+
def (@configurations).update_from_source # :nodoc:
|
292
310
|
self.each do |c|
|
293
311
|
if c.respond_to?(:update_from_source)
|
294
312
|
c.update_from_source
|
@@ -298,15 +316,18 @@ module Vapir
|
|
298
316
|
|
299
317
|
@configurations.push(@base_configuration=Configuration.new(nil) do |config|
|
300
318
|
config.create_update(:attach_timeout, 30, :validator => :numeric)
|
319
|
+
config.create_update(:close_timeout, 16, :validator => :numeric)
|
320
|
+
config.create_update(:quit_timeout, 8, :validator => :numeric)
|
301
321
|
config.create(:default_browser, :validator => proc do |val|
|
302
322
|
require 'vapir-common/browsers'
|
303
323
|
unless (val.is_a?(String) || val.is_a?(Symbol)) && (real_key = Vapir::SupportedBrowsers.keys.detect{|key| key.to_s==val.to_s })
|
304
|
-
raise
|
324
|
+
raise Vapir::Configuration::InvalidValueError, "default_browser should be a string or symbol matching a supported browser - one of: #{Vapir::SupportedBrowsers.keys.join(', ')}. instead got #{val.inspect}"
|
305
325
|
end
|
306
326
|
real_key
|
307
327
|
end)
|
308
328
|
config.create_update(:highlight_color, 'yellow')
|
309
329
|
config.create_update(:wait, true, :validator => :boolean)
|
330
|
+
config.create_update(:wait_timeout, 120, :validator => :numeric)
|
310
331
|
config.create_update(:type_keys, false, :validator => :boolean)
|
311
332
|
config.create_update(:typing_interval, 0, :validator => :numeric)
|
312
333
|
config.create_update(:warn_deprecated, true, :validator => :boolean)
|
@@ -337,5 +358,6 @@ module Vapir
|
|
337
358
|
@env_configuration.update_from_source
|
338
359
|
|
339
360
|
@configuration_parent = @configurations.last
|
361
|
+
# :startdoc:
|
340
362
|
extend Configurable # makes Vapir.config which is the in-process user-configurable one, overriding base, yaml, and env
|
341
363
|
end
|
@@ -180,63 +180,8 @@ module Vapir
|
|
180
180
|
# returns an array of text nodes below this element in the DOM heirarchy which are visible -
|
181
181
|
# that is, their parent element is visible.
|
182
182
|
def visible_text_nodes
|
183
|
-
# TODO: needs tests
|
184
183
|
assert_exists do
|
185
|
-
|
186
|
-
proc do |node, parent_visibility|
|
187
|
-
case node.nodeType
|
188
|
-
when 1, 9 # TODO: name a constant ELEMENT_NODE, rather than magic number
|
189
|
-
style= node.nodeType==1 ? base_element_class.element_object_style(node, document_object) : nil
|
190
|
-
our_visibility = style && (visibility=style.invoke('visibility'))
|
191
|
-
unless our_visibility && ['hidden', 'collapse', 'visible'].include?(our_visibility=our_visibility.strip.downcase)
|
192
|
-
our_visibility = parent_visibility
|
193
|
-
end
|
194
|
-
display = style && style.invoke('display')
|
195
|
-
if display && display.strip.downcase=='none'
|
196
|
-
[]
|
197
|
-
else
|
198
|
-
Vapir::Element.object_collection_to_enumerable(node.childNodes).inject([]) do |result, child_node|
|
199
|
-
result + recurse.call(child_node, our_visibility)
|
200
|
-
end
|
201
|
-
end
|
202
|
-
when 3 # TODO: name a constant TEXT_NODE, rather than magic number
|
203
|
-
if parent_visibility && ['hidden','collapse'].include?(parent_visibility.downcase)
|
204
|
-
[]
|
205
|
-
else
|
206
|
-
[node.data]
|
207
|
-
end
|
208
|
-
else
|
209
|
-
#Kernel.warn("ignoring node of type #{node.nodeType}")
|
210
|
-
[]
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
# determine the current visibility and display. TODO: this is copied/adapted from #visible?; should DRY
|
216
|
-
element_to_check=containing_object
|
217
|
-
real_visibility=nil
|
218
|
-
while element_to_check #&& !element_to_check.instanceof(nsIDOMDocument)
|
219
|
-
if (style=base_element_class.element_object_style(element_to_check, document_object))
|
220
|
-
# only pay attention to the innermost definition that really defines visibility - one of 'hidden', 'collapse' (only for table elements),
|
221
|
-
# or 'visible'. ignore 'inherit'; keep looking upward.
|
222
|
-
# this makes it so that if we encounter an explicit 'visible', we don't pay attention to any 'hidden' further up.
|
223
|
-
# this style is inherited - may be pointless for firefox, but IE uses the 'inherited' value. not sure if/when ff does.
|
224
|
-
if real_visibility==nil && (visibility=style.invoke('visibility'))
|
225
|
-
visibility=visibility.strip.downcase
|
226
|
-
if ['hidden', 'collapse', 'visible'].include?(visibility)
|
227
|
-
real_visibility=visibility
|
228
|
-
end
|
229
|
-
end
|
230
|
-
# check for display property. this is not inherited, and a parent with display of 'none' overrides an immediate visibility='visible'
|
231
|
-
display=style.invoke('display')
|
232
|
-
if display && (display=display.strip.downcase)=='none'
|
233
|
-
# if display is none, then this element is not visible, and thus has no visible text nodes underneath.
|
234
|
-
return []
|
235
|
-
end
|
236
|
-
end
|
237
|
-
element_to_check=element_to_check.parentNode
|
238
|
-
end
|
239
|
-
recurse_text_nodes.call(containing_object, real_visibility)
|
184
|
+
visible_text_nodes_method.call(containing_object, document_object)
|
240
185
|
end
|
241
186
|
end
|
242
187
|
# returns an visible text inside this element by concatenating text nodes below this element in the DOM heirarchy which are visible.
|
@@ -286,6 +231,128 @@ module Vapir
|
|
286
231
|
element_class
|
287
232
|
end
|
288
233
|
|
234
|
+
# takes one argument, a proc.
|
235
|
+
# this will be yielded successive dom nodes, and should return true if the node matches whatever
|
236
|
+
# criteria you care to match; false otherwise.
|
237
|
+
#
|
238
|
+
# returns an ElementCollection consisting of the deepest elements within the dom heirarchy
|
239
|
+
# which match the given match_proc_or_function.
|
240
|
+
def base_innermost_by_node(match_proc)
|
241
|
+
ElementCollection.new(self, base_element_class, extra_for_contained.merge(:candidates => proc do |container|
|
242
|
+
ycomb do |innermost_matching_nodes|
|
243
|
+
proc do |container_node|
|
244
|
+
child_nodes = Vapir::Element.object_collection_to_enumerable(container_node.childNodes)
|
245
|
+
matched_child_elements=child_nodes.select do |node|
|
246
|
+
node.nodeType==1 && match_proc.call(node)
|
247
|
+
end
|
248
|
+
if matched_child_elements.empty?
|
249
|
+
[container_node]
|
250
|
+
else
|
251
|
+
matched_child_elements.map do |matched_child_element|
|
252
|
+
innermost_matching_nodes.call(matched_child_element)
|
253
|
+
end.inject([], &:+)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end.call(container.containing_object)
|
257
|
+
end))
|
258
|
+
end
|
259
|
+
alias innermost_by_node base_innermost_by_node
|
260
|
+
# takes text or regexp, and returns an ElementCollection consisting of deepest (innermost) elements in the dom heirarchy whose visible text
|
261
|
+
# matches what's given (by substring for text; by regexp match for regexp)
|
262
|
+
def base_innermost_matching_visible_text(text_or_regexp)
|
263
|
+
innermost_by_node(proc do |node|
|
264
|
+
visible_text_nodes_method.call(node, document_object).join('')[text_or_regexp] # String#[] works with either text or regexp - returns the matched substring or nil
|
265
|
+
end)
|
266
|
+
end
|
267
|
+
alias innermost_matching_visible_text base_innermost_matching_visible_text
|
268
|
+
|
269
|
+
private
|
270
|
+
# returns a proc that takes a node and a document object, and returns
|
271
|
+
# true if the element's display property will allow it to be displayed; false if not.
|
272
|
+
def element_displayed_method
|
273
|
+
@element_displayed_method ||= proc do |node, document_object|
|
274
|
+
style= node.nodeType==1 ? base_element_class.element_object_style(node, document_object) : nil
|
275
|
+
display = style && style.invoke('display')
|
276
|
+
displayed = display ? display.strip.downcase!='none' : true
|
277
|
+
displayed
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
# returns a proc that takes a node and a document object, and returns
|
282
|
+
# the visibility of that node, obtained by ascending the dom until an explicit
|
283
|
+
# definition for visibility is found.
|
284
|
+
def element_real_visibility_method
|
285
|
+
@element_real_visibility_method ||= proc do |element_to_check, document_object|
|
286
|
+
real_visibility=nil
|
287
|
+
while element_to_check && real_visibility==nil
|
288
|
+
style = base_element_class.element_object_style(element_to_check, document_object)
|
289
|
+
if style
|
290
|
+
# only pay attention to the innermost definition that really defines visibility - one of 'hidden', 'collapse' (only for table elements),
|
291
|
+
# or 'visible'. ignore 'inherit'; keep looking upward.
|
292
|
+
# this makes it so that if we encounter an explicit 'visible', we don't pay attention to any 'hidden' further up.
|
293
|
+
# this style is inherited - may be pointless for firefox, but IE uses the 'inherited' value. not sure if/when ff does.
|
294
|
+
if style.invoke('visibility')
|
295
|
+
visibility=style.invoke('visibility').strip.downcase
|
296
|
+
if ['hidden', 'collapse', 'visible'].include?(visibility)
|
297
|
+
real_visibility=visibility
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
element_to_check=element_to_check.parentNode
|
302
|
+
end
|
303
|
+
real_visibility
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
# returns a proc that takes a node and a document object, and returns
|
308
|
+
# an Array of strings, each of which is the data of a text node beneath the given node which
|
309
|
+
# is visible.
|
310
|
+
def visible_text_nodes_method
|
311
|
+
@visible_text_nodes_method ||= proc do |element_object, document_object|
|
312
|
+
recurse_text_nodes=ycomb do |recurse|
|
313
|
+
proc do |node, parent_visibility|
|
314
|
+
case node.nodeType
|
315
|
+
when 1, 9 # TODO: name a constant ELEMENT_NODE, rather than magic number
|
316
|
+
style= node.nodeType==1 ? base_element_class.element_object_style(node, document_object) : nil
|
317
|
+
our_visibility = style && (visibility=style.invoke('visibility'))
|
318
|
+
unless our_visibility && ['hidden', 'collapse', 'visible'].include?(our_visibility=our_visibility.strip.downcase)
|
319
|
+
our_visibility = parent_visibility
|
320
|
+
end
|
321
|
+
if !element_displayed_method.call(node, document_object)
|
322
|
+
[]
|
323
|
+
else
|
324
|
+
Vapir::Element.object_collection_to_enumerable(node.childNodes).inject([]) do |result, child_node|
|
325
|
+
result + recurse.call(child_node, our_visibility)
|
326
|
+
end
|
327
|
+
end
|
328
|
+
when 3 # TODO: name a constant TEXT_NODE, rather than magic number
|
329
|
+
if parent_visibility && ['hidden','collapse'].include?(parent_visibility.downcase)
|
330
|
+
[]
|
331
|
+
else
|
332
|
+
[node.data]
|
333
|
+
end
|
334
|
+
else
|
335
|
+
#Kernel.warn("ignoring node of type #{node.nodeType}")
|
336
|
+
[]
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
# determine the current visibility and display.
|
342
|
+
element_to_check=element_object
|
343
|
+
while element_to_check
|
344
|
+
if !element_displayed_method.call(element_to_check, document_object)
|
345
|
+
# check for display property. this is not inherited, and a parent with display of 'none' overrides an immediate visibility='visible'
|
346
|
+
# if display is none, then this element is not visible, and thus has no visible text nodes underneath.
|
347
|
+
return []
|
348
|
+
end
|
349
|
+
element_to_check=element_to_check.parentNode
|
350
|
+
end
|
351
|
+
recurse_text_nodes.call(element_object, element_real_visibility_method.call(element_object, document_object))
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
public
|
289
356
|
# shows the available objects on the current container.
|
290
357
|
# This is usually only used for debugging or writing new test scripts.
|
291
358
|
# This is a nice feature to help find out what HTML objects are on a page
|
@@ -333,3 +400,4 @@ module Vapir
|
|
333
400
|
end
|
334
401
|
end
|
335
402
|
end
|
403
|
+
|
data/lib/vapir-common/element.rb
CHANGED
@@ -449,7 +449,7 @@ module Vapir
|
|
449
449
|
def visible?
|
450
450
|
assert_exists do
|
451
451
|
element_to_check=element_object
|
452
|
-
#nsIDOMDocument=
|
452
|
+
#nsIDOMDocument=firefox_socket.Components.interfaces.nsIDOMDocument
|
453
453
|
really_visible=nil
|
454
454
|
while element_to_check #&& !element_to_check.instanceof(nsIDOMDocument)
|
455
455
|
if (style=element_object_style(element_to_check, document_object))
|
@@ -579,22 +579,28 @@ module Vapir
|
|
579
579
|
@container
|
580
580
|
end
|
581
581
|
|
582
|
+
# the Vapir::Browser this element is on
|
582
583
|
attr_reader :browser
|
584
|
+
# the Vapir::PageContainer containing this element (a Browser, Frame, or ModalDialogDocument)
|
583
585
|
attr_reader :page_container
|
584
586
|
|
585
587
|
def document_object
|
586
588
|
assert_container
|
587
589
|
@container.document_object
|
588
590
|
end
|
591
|
+
# returns the content window object of the current page on the browser (this is the 'window'
|
592
|
+
# object in javascript).
|
589
593
|
def content_window_object
|
590
594
|
assert_container
|
591
595
|
@container.content_window_object
|
592
596
|
end
|
597
|
+
# returns the underlying object representing the browser.
|
593
598
|
def browser_window_object
|
594
599
|
assert_container
|
595
600
|
@container.browser_window_object
|
596
601
|
end
|
597
602
|
|
603
|
+
# used by inspect, to_s, and pretty_print to determine what to show
|
598
604
|
def attributes_for_stringifying
|
599
605
|
attributes_to_inspect=self.class.attributes_to_inspect
|
600
606
|
unless exists?
|
@@ -621,6 +627,9 @@ module Vapir
|
|
621
627
|
" "+attr.first+'='+attr.last.inspect
|
622
628
|
end.join('') + ">"
|
623
629
|
end
|
630
|
+
# returns a string representation of this element with each attribute on its own line. this
|
631
|
+
# returns the same information as #inspect, but formatted somewhat more readably. you might
|
632
|
+
# also be interested in pretty-printing the element; see the pp library.
|
624
633
|
def to_s
|
625
634
|
attrs=attributes_for_stringifying
|
626
635
|
longest_label=attrs.inject(0) {|max, attr| [max, attr.first.size].max }
|
@@ -647,7 +656,7 @@ module Vapir
|
|
647
656
|
def object_collection_to_enumerable(object)
|
648
657
|
if object.is_a?(Enumerable)
|
649
658
|
object
|
650
|
-
elsif Object.const_defined?('
|
659
|
+
elsif Object.const_defined?('JavascriptObject') && object.is_a?(JavascriptObject)
|
651
660
|
object.to_array
|
652
661
|
elsif Object.const_defined?('WIN32OLE') && object.is_a?(WIN32OLE)
|
653
662
|
array=[]
|
@@ -4,7 +4,7 @@ module Vapir
|
|
4
4
|
# this module is for methods that should go on both common element modules (ie, TextField) as well
|
5
5
|
# as browser-specific element classes (ie, Firefox::TextField).
|
6
6
|
module ElementClassAndModuleMethods
|
7
|
-
# takes an element_object (
|
7
|
+
# takes an element_object (JavascriptObject or WIN32OLE), and finds the most specific class
|
8
8
|
# that is < self whose specifiers match it. Returns an instance of that class using the given
|
9
9
|
# element_object.
|
10
10
|
#
|
@@ -178,6 +178,7 @@ module Vapir
|
|
178
178
|
# Raises ObjectDisabledException if the object is disabled
|
179
179
|
# Raises ObjectReadOnlyException if the object is read only
|
180
180
|
def append(value, options={})
|
181
|
+
raise ArgumentError, "Text field value must be a string! Got #{value.inspect}" unless value.is_a?(String)
|
181
182
|
options={:blur => true, :change => true, :select => true, :focus => true}.merge(options)
|
182
183
|
assert_enabled
|
183
184
|
assert_not_readonly
|
@@ -34,13 +34,23 @@ unless :to_proc.respond_to?(:to_proc)
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
+
class Hash
|
38
|
+
# returns a hash whose keys are the intersection of the keys of this hash and the keys given
|
39
|
+
# as arguments to this function. values are the same as in this hash.
|
40
|
+
def select_keys(*keys)
|
41
|
+
keys.inject(self.class.new) do |hash,key|
|
42
|
+
self.key?(key) ? hash.merge(key => self[key]) : hash
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
37
47
|
module Kernel
|
38
48
|
# this is the Y-combinator, which allows anonymous recursive functions. for a simple example,
|
39
49
|
# to define a recursive function to return the length of an array:
|
40
50
|
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
51
|
+
# length = ycomb do |len|
|
52
|
+
# proc{|list| list == [] ? 0 : len.call(list[1..-1]) }
|
53
|
+
# end
|
44
54
|
#
|
45
55
|
# see https://secure.wikimedia.org/wikipedia/en/wiki/Fixed_point_combinator#Y_combinator
|
46
56
|
# and chapter 9 of the little schemer, available as the sample chapter at http://www.ccs.neu.edu/home/matthias/BTLS/
|
@@ -50,7 +60,7 @@ module Kernel
|
|
50
60
|
module_function :ycomb
|
51
61
|
|
52
62
|
def warn_with_caller(message)
|
53
|
-
Kernel.warn "#{message}\ncalled from: #{caller[1..-1].map{|c|"\n\t"+c}}"
|
63
|
+
Kernel.warn "#{message}\ncalled from: #{caller[1..-1].map{|c|"\n\t"+c}.join('')}"
|
54
64
|
end
|
55
65
|
module_function :warn_with_caller
|
56
66
|
end
|
@@ -109,6 +109,16 @@ module Vapir
|
|
109
109
|
names.first.is_a?(String) &&
|
110
110
|
container.containing_object.object_respond_to?(:getElementsByName) &&
|
111
111
|
specifiers.all?{|specifier| specifier[:tagName].is_a?(String) && %w(BUTTON TEXTAREA APPLET SELECT FORM FRAME IFRAME IMG A INPUT OBJECT MAP PARAM META).include?(specifier[:tagName].upcase) }
|
112
|
+
# thing to determine if object_respond_to?(:getElementsByClassName) is lying. returns
|
113
|
+
# true if the thing is full of lies.
|
114
|
+
getElementsByClassName_lies = proc do
|
115
|
+
Object.const_defined?('WIN32OLERuntimeError') && begin
|
116
|
+
container.containing_object.getElementsByClassName('dummy')
|
117
|
+
false
|
118
|
+
rescue WIN32OLERuntimeError, NoMethodError
|
119
|
+
true
|
120
|
+
end
|
121
|
+
end
|
112
122
|
if can_use_getElementById
|
113
123
|
candidates= if by_id=container.containing_object.getElementById(ids.first)
|
114
124
|
[by_id]
|
@@ -117,7 +127,7 @@ module Vapir
|
|
117
127
|
end
|
118
128
|
elsif can_use_getElementsByName
|
119
129
|
candidates=container.containing_object.getElementsByName(names.first)#.to_array
|
120
|
-
elsif classNames.size==1 && classNames.first.is_a?(String) && container.containing_object.object_respond_to?(:getElementsByClassName)
|
130
|
+
elsif classNames.size==1 && classNames.first.is_a?(String) && container.containing_object.object_respond_to?(:getElementsByClassName) && !getElementsByClassName_lies.call
|
121
131
|
candidates=container.containing_object.getElementsByClassName(classNames.first)
|
122
132
|
elsif tags.size==1 && tags.first.is_a?(String)
|
123
133
|
candidates=container.containing_object.getElementsByTagName(tags.first)
|
@@ -127,7 +137,7 @@ module Vapir
|
|
127
137
|
# return:
|
128
138
|
if candidates.is_a?(Array)
|
129
139
|
candidates
|
130
|
-
elsif Object.const_defined?('
|
140
|
+
elsif Object.const_defined?('JavascriptObject') && candidates.is_a?(JavascriptObject)
|
131
141
|
candidates.to_array
|
132
142
|
elsif Object.const_defined?('WIN32OLE') && candidates.is_a?(WIN32OLE)
|
133
143
|
candidates.send :extend, Enumerable
|
@@ -141,15 +151,15 @@ module Vapir
|
|
141
151
|
unless specifiers_list.is_a?(Enumerable) && specifiers_list.all?{|spec| spec.is_a?(Hash)}
|
142
152
|
raise ArgumentError, "specifiers_list should be a list of Hashes!"
|
143
153
|
end
|
144
|
-
if Object.const_defined?('
|
145
|
-
# optimize for
|
154
|
+
if Object.const_defined?('JavascriptObject') && (candidates.is_a?(JavascriptObject) || (candidates.length != 0 && candidates.all?{|c| c.is_a?(JavascriptObject)}))
|
155
|
+
# optimize for firefox by moving code to the other side of the socket, rather than talking across it a whole lot
|
146
156
|
# this javascript should be exactly the same as the ruby in the else (minus WIN32OLE optimization) -
|
147
157
|
# just written in javascript instead of ruby.
|
148
158
|
#
|
149
159
|
# Note that the else block works perfectly fine, but is much much slower due to the amount of
|
150
160
|
# socket activity.
|
151
|
-
|
152
|
-
match_candidates_js=
|
161
|
+
firefox_socket= candidates.is_a?(JavascriptObject) ? candidates.firefox_socket : candidates.first.firefox_socket
|
162
|
+
match_candidates_js=JavascriptObject.new("
|
153
163
|
(function(candidates, specifiers_list, aliases)
|
154
164
|
{ candidates=$A(candidates);
|
155
165
|
specifiers_list=$A(specifiers_list);
|
@@ -214,7 +224,7 @@ module Vapir
|
|
214
224
|
});
|
215
225
|
return matched_candidates;
|
216
226
|
})
|
217
|
-
",
|
227
|
+
", firefox_socket, :debug_name => 'match_candidates_function')
|
218
228
|
matched_candidates=match_candidates_js.call(candidates, specifiers_list, aliases)
|
219
229
|
if block_given?
|
220
230
|
matched_candidates.to_array.each do |matched_candidate|
|
@@ -301,6 +311,9 @@ module Vapir
|
|
301
311
|
|
302
312
|
# This is on the Vapir module itself because it's used in a number of other places, should be in a broad namespace.
|
303
313
|
module_function
|
314
|
+
# fuzzily matches the given attribute with the given 'what'. if 'what' is a regexp, matches it
|
315
|
+
# against attr; if it's a string, downcases and strips before comparing; tries a couple other
|
316
|
+
# things; falls back to normal equality-checking. read the source for more information.
|
304
317
|
def fuzzy_match(attr, what)
|
305
318
|
# IF YOU CHANGE THIS, CHANGE THE JAVASCRIPT REIMPLEMENTATION IN match_candidates
|
306
319
|
case what
|
data/lib/vapir-common/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vapir-common
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 51
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 1.
|
8
|
+
- 9
|
9
|
+
- 0
|
10
|
+
version: 1.9.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ethan
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-08-04 00:00:00 -04:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|