Class: AX::Element Abstract
- Inherits:
-
Object
- Object
- AX::Element
- Includes:
- Accessibility::PrettyPrinter
- Defined in:
- lib/ax/element.rb,
lib/accessibility/factory.rb
Overview
The abstract base class for all accessibility objects. AX::Element
composes low level AXUIElementRef objects into a more Rubyish
interface.
This abstract base class provides generic functionality that all accessibility objects require.
Direct Known Subclasses
Application, Button, Menu, PopUpButton, RadioButton, Row, ScrollArea, StaticText, SystemWide
Attributes collapse
-
#ancestry(elements = self) ⇒ Array<AX::Element>
(also: #lineage)
Get a list of elements, starting with the receiver and riding the hierarchy up to the top level object (i.e. the Application).
-
#attribute(attr) ⇒ Object
Get the value of an attribute.
-
#attributes ⇒ Array<Symbol>
Cache of available attributes.
-
#children ⇒ Array<AX::Element>
Fetch the children elements for the current element.
-
#description ⇒ String
Get the accessibility description for the element.
-
#pid ⇒ Fixnum
Get the process identifier for the application that the element belongs to.
-
#set(attr, value) ⇒ Object
Set a writable attribute on the element to the given value.
-
#size_of(attr) ⇒ Number
Return the
#sizeof an attribute. -
#writable?(attr) ⇒ Boolean
Check whether or not an attribute is writable.
Parameterized Attributes collapse
-
#parameterized_attribute(attr, param) ⇒ Object
Get the value for a parameterized attribute.
-
#parameterized_attributes ⇒ Array<Symbol>
List of available parameterized attributes.
Actions collapse
-
#actions ⇒ Array<Symbol>
List of available actions.
-
#perform(action) ⇒ Boolean
Tell an object to trigger an action.
Search collapse
-
#ancestor(kind, filters = {}) { ... } ⇒ AX::Element?
Search for an ancestor of the current element.
-
#method_missing(method, *args, &block) ⇒ Object
We use #method_missing to dynamically handle requests to lookup attributes or search for elements in the view hierarchy.
-
#search(kind, filters = {}) { ... } ⇒ AX::Element, ...
Perform a breadth first search through the view hierarchy rooted at the current element.
Instance Method Summary collapse
-
#==(other) ⇒ Object
(also: #eql?, #equal?)
Overridden so that equality testing would work.
-
#application ⇒ AX::Application
Get the application object for the element.
- #blank? ⇒ Boolean
-
#bounds ⇒ CGRect
(also: #to_rect)
Get the bounding rectangle for the element.
-
#initialize(ref) ⇒ Element
constructor
A new instance of Element.
-
#inspect ⇒ String
Get relevant details about the current object.
-
#inspect_subtree ⇒ String
Get the relevant details about the receiver and also the children and further descendents of the receiver.
-
#invalid? ⇒ Boolean
Return whether or not the receiver is "dead".
-
#methods(include_super = true) ⇒ Object
Like #respond_to?, this is overriden to include attribute methods.
-
#respond_to?(name) ⇒ Boolean
Overriden to respond properly with regards to dynamic attribute lookups, but will return false for potential implicit searches.
-
#to_point ⇒ CGPoint
(also: #hitpoint)
Get the center point of the element.
-
#to_s ⇒ String
An "alias" for #inspect.
Methods included from Accessibility::PrettyPrinter
#pp_checkbox, #pp_children, #pp_identifier, #pp_position
Constructor Details
#initialize(ref) ⇒ Element
Returns a new instance of Element.
26 27 28 |
# File 'lib/ax/element.rb', line 26 def initialize ref @ref = ref end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *args, &block) ⇒ Object
We use #method_missing to dynamically handle requests to lookup attributes or search for elements in the view hierarchy. An attribute lookup is always tried first, followed by a parameterized attribute lookup, and then finally a search.
Failing all lookups, this method calls super, which will probably
raise an exception; however, most elements have children and so it
is more likely that you will get an Accessibility::SearchFailure
in cases where you sholud get a NoMethodError.
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 |
# File 'lib/ax/element.rb', line 337 def method_missing method, *args, &block return set(method.chomp(EQUALS), args.first) if method[-1] == EQUALS key = TRANSLATOR.cocoaify method if @ref.attributes.include? key return attribute(method) elsif @ref.parameterized_attributes.include? key return parameterized_attribute(method, args.first) elsif @ref.attributes.include? KAXChildrenAttribute if (result = search(method, *args, &block)).blank? raise Accessibility::SearchFailure.new(self, method, args.first, &block) else return result end else super end end |
Instance Method Details
#==(other) ⇒ Object Also known as: eql?, equal?
Overridden so that equality testing would work.
A hack, but the only sane way I can think of to test for equivalency.
481 482 483 |
# File 'lib/ax/element.rb', line 481 def == other @ref == other.instance_variable_get(:@ref) end |
#actions ⇒ Array<Symbol>
List of available actions.
207 208 209 |
# File 'lib/ax/element.rb', line 207 def actions @actions ||= TRANSLATOR.rubyize @ref.actions end |
#ancestor(kind, filters = {}) { ... } ⇒ AX::Element?
Search for an ancestor of the current element.
As the opposite of #search, this also takes filters, and can be used to find a specific ancestor for the current element.
Returns nil if no ancestor is found.
278 279 280 281 282 283 284 285 286 |
# File 'lib/ax/element.rb', line 278 def ancestor kind, filters = {}, &block qualifier = Accessibility::Qualifier.new(kind, filters, &block) element = self until qualifier.qualifies? element element = element.attribute :parent return nil unless element end element end |
#ancestry(elements = self) ⇒ Array<AX::Element> Also known as: lineage
Get a list of elements, starting with the receiver and riding the hierarchy up to the top level object (i.e. the Application)
91 92 93 94 95 96 97 98 99 |
# File 'lib/ax/element.rb', line 91 def ancestry elements = self elements = Array(elements) element = elements.last if element.attributes.include? :parent ancestry(elements << element.attribute(:parent)) else elements end end |
#application ⇒ AX::Application
Get the application object for the element.
444 445 446 |
# File 'lib/ax/element.rb', line 444 def application @ref.application.to_ruby end |
#attribute(attr) ⇒ Object
Get the value of an attribute. This method will return nil if
the attribute does not have a value or if the element is dead. The
execption to the rule is that the :children attribute will always
return an array unless the element does not have the :children
attribute.
57 58 59 |
# File 'lib/ax/element.rb', line 57 def attribute attr @ref.attribute(TRANSLATOR.cocoaify(attr)).to_ruby end |
#attributes ⇒ Array<Symbol>
Cache of available attributes.
41 42 43 |
# File 'lib/ax/element.rb', line 41 def attributes @attrs ||= TRANSLATOR.rubyize @ref.attributes end |
#blank? ⇒ Boolean
449 450 451 |
# File 'lib/ax/element.rb', line 449 def blank? false end |
#bounds ⇒ CGRect Also known as: to_rect
Get the bounding rectangle for the element.
435 436 437 |
# File 'lib/ax/element.rb', line 435 def bounds CGRect.new(attribute(:position), attribute(:size)) end |
#children ⇒ Array<AX::Element>
Fetch the children elements for the current element.
76 77 78 |
# File 'lib/ax/element.rb', line 76 def children @ref.children.to_ruby end |
#description ⇒ String
Get the accessibility description for the element.
This overrides the inherited NSObject#description. If you want a
description of the object then you should use #inspect instead.
68 69 70 |
# File 'lib/ax/element.rb', line 68 def description attribute(:description).to_ruby end |
#inspect ⇒ String
Get relevant details about the current object.
367 368 369 370 371 372 373 374 |
# File 'lib/ax/element.rb', line 367 def inspect msg = "#<#{self.class}" << pp_identifier.to_s msg << pp_position if attributes.include? :position msg << pp_children if attributes.include? :children msg << pp_checkbox(:enabled) if attributes.include? :enabled msg << pp_checkbox(:focused) if attributes.include? :focused msg << '>' end |
#inspect_subtree ⇒ String
Get the relevant details about the receiver and also the children and further descendents of the receiver. Each generation down the tree will be indented one level further.
397 398 399 400 401 402 403 404 |
# File 'lib/ax/element.rb', line 397 def inspect_subtree output = self.inspect + "\n" enum = Accessibility::Enumerators::DepthFirst.new self enum.each_with_level do |element, depth| output << "\t"*depth + element.inspect + "\n" end output end |
#invalid? ⇒ Boolean
Return whether or not the receiver is "dead".
A dead element is one that is no longer in the app's view hierarchy. This is not directly related to visibility, but an element that is invalid will not be visible, but an invisible element might not be invalid.
460 461 462 |
# File 'lib/ax/element.rb', line 460 def invalid? @ref.invalid? end |
#methods(include_super = true) ⇒ Object
Like #respond_to?, this is overriden to include attribute methods. Though, it does include dynamic predicate methods at the moment.
468 469 470 |
# File 'lib/ax/element.rb', line 468 def methods include_super = true, include_objc_super = false super.concat(attributes).concat(parameterized_attributes) end |
#parameterized_attribute(attr, param) ⇒ Object
Get the value for a parameterized attribute.
189 190 191 192 |
# File 'lib/ax/element.rb', line 189 def parameterized_attribute attr, param param = param.relative_to(@ref.value.size) if param.kind_of? Range @ref.parameterized_attribute(TRANSLATOR.cocoaify(attr), param).to_ruby end |
#parameterized_attributes ⇒ Array<Symbol>
List of available parameterized attributes. Most elements have no parameterized attributes, but the ones that do have many.
176 177 178 |
# File 'lib/ax/element.rb', line 176 def parameterized_attributes @param_attrs ||= TRANSLATOR.rubyize @ref.parameterized_attributes end |
#perform(action) ⇒ Boolean
Tell an object to trigger an action.
For instance, you can tell a button to call the same method that would be called when pressing a button, except that the mouse will not move over to the button to press it, nor will the keyboard be used.
226 227 228 |
# File 'lib/ax/element.rb', line 226 def perform action @ref.perform TRANSLATOR.cocoaify action end |
#pid ⇒ Fixnum
Get the process identifier for the application that the element belongs to.
111 112 113 |
# File 'lib/ax/element.rb', line 111 def pid @ref.pid end |
#respond_to?(name) ⇒ Boolean
Overriden to respond properly with regards to dynamic attribute lookups, but will return false for potential implicit searches.
This does not work for predicate methods at the moment.
411 412 413 414 415 416 |
# File 'lib/ax/element.rb', line 411 def respond_to? name key = TRANSLATOR.cocoaify name.chomp(EQUALS) @ref.attributes.include?(key) || @ref.parameterized_attributes.include?(key) || super end |
#search(kind, filters = {}) { ... } ⇒ AX::Element, ...
Perform a breadth first search through the view hierarchy rooted at the current element. If you are concerned about the return value of this method, you can call #blank? on the return object.
See the Searching wiki for the details on search semantics.
249 250 251 252 253 254 255 256 257 258 259 |
# File 'lib/ax/element.rb', line 249 def search kind, filters = {}, &block kind = kind.to_s qualifier = Accessibility::Qualifier.new(kind, filters, &block) tree = Accessibility::Enumerators::BreadthFirst.new(self) if TRANSLATOR.singularize(kind) == kind tree.find { |element| qualifier.qualifies? element } else tree.find_all { |element| qualifier.qualifies? element } end end |
#set(attr, value) ⇒ Object
Set a writable attribute on the element to the given value.
155 156 157 158 159 160 161 |
# File 'lib/ax/element.rb', line 155 def set attr, value unless writable? attr raise ArgumentError, "#{attr} is read-only for #{inspect}" end value = value.relative_to(@ref.value.size) if value.kind_of? Range @ref.set TRANSLATOR.cocoaify(attr), value end |
#size_of(attr) ⇒ Number
Return the #size of an attribute. This only works for attributes
that are a collection. This exists because it is much more
efficient to find out how many children exist using this API
instead of getting the children array and asking for the size.
128 129 130 |
# File 'lib/ax/element.rb', line 128 def size_of attr @ref.size_of TRANSLATOR.cocoaify attr end |
#to_point ⇒ CGPoint Also known as: hitpoint
Get the center point of the element.
422 423 424 425 426 427 428 |
# File 'lib/ax/element.rb', line 422 def to_point size = attribute :size point = attribute :position point.x += size.width / 2 point.y += size.height / 2 point end |
#to_s ⇒ String
Since #inspect is often overridden by subclasses, this cannot
be an alias.
An "alias" for #inspect.
383 384 385 |
# File 'lib/ax/element.rb', line 383 def to_s inspect end |
#writable?(attr) ⇒ Boolean
Check whether or not an attribute is writable.
141 142 143 |
# File 'lib/ax/element.rb', line 141 def writable? attr @ref.writable? TRANSLATOR.cocoaify attr end |