Class: AX::Element Abstract
- Inherits:
-
Object
- Object
- AX::Element
- Includes:
- Accessibility::Factory, Accessibility::PPInspector
- Defined in:
- lib/ax/element.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) ⇒ Array<AX::Element>
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
#size
of 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 = {}, &block) ⇒ 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 = {}, &block) ⇒ 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? ⇒ Object
Whether or not the object is "blank".
-
#bounds ⇒ CGRect
(also: #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, include_objc_super = false) ⇒ 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::Factory
Methods included from Accessibility::PPInspector
#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
.
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 |
# File 'lib/ax/element.rb', line 331 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 paramaterized_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.
467 468 469 |
# File 'lib/ax/element.rb', line 467 def == other @ref == other.instance_variable_get(:@ref) end |
#actions ⇒ Array<Symbol>
List of available actions.
206 207 208 |
# File 'lib/ax/element.rb', line 206 def actions @actions ||= TRANSLATOR.rubyize @ref.actions end |
#ancestor(kind, filters = {}, &block) ⇒ 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.
273 274 275 276 277 278 279 280 |
# File 'lib/ax/element.rb', line 273 def ancestor kind, filters = {}, &block qualifier = Accessibility::Qualifier.new(kind, filters, &block) element = attribute :parent until qualifier.qualifies? element element = element.attribute :parent end element end |
#ancestry(*elements) ⇒ Array<AX::Element>
Get a list of elements, starting with the receiver and riding the hierarchy up to the top level object (i.e. the Application).
92 93 94 95 96 97 98 99 100 |
# File 'lib/ax/element.rb', line 92 def ancestry *elements elements = [self] if elements.empty? element = elements.last if element.attributes.include? :parent ancestry(elements << element.parent) else elements end end |
#application ⇒ AX::Application
Get the application object for the element.
438 439 440 |
# File 'lib/ax/element.rb', line 438 def application process @ref.application end |
#attribute(attr) ⇒ Object
Get the value of an attribute. This method will return nil
if
the attribute does not have a value, if the element does not have
the attribute, or if the element is dead. There is an execption
for the :children
attribute which is always guaranteed to return
an array.
57 58 59 |
# File 'lib/ax/element.rb', line 57 def attribute attr process @ref.attribute TRANSLATOR.cocoaify attr 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? ⇒ Object
Whether or not the object is "blank". The concept of blankness
borrowed from Active Support
and is true if the object is falsey
or #empty?
.
This method is used by implicit searching in AXElements to determine if searches yielded responses.
443 444 445 |
# File 'lib/ax/element.rb', line 443 def blank? false end |
#bounds ⇒ CGRect Also known as: rect
Get the bounding rectangle for the element.
429 430 431 |
# File 'lib/ax/element.rb', line 429 def bounds CGRect.new(attribute(:position), attribute(:size)) end |
#children ⇒ Array<AX::Element>
Fetch the children elements for the current element. If the current element does not have children then an empty array will be returned.
77 78 79 |
# File 'lib/ax/element.rb', line 77 def children attribute :children 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 end |
#inspect ⇒ String
Get relevant details about the current object.
361 362 363 364 365 366 367 368 |
# File 'lib/ax/element.rb', line 361 def inspect msg = "#<#{self.class}" << pp_identifier 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.
391 392 393 394 395 396 397 398 |
# File 'lib/ax/element.rb', line 391 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, which is not necessarily related to visibility.
452 453 454 |
# File 'lib/ax/element.rb', line 452 def invalid? @ref.role.nil? end |
#methods(include_super = true, include_objc_super = false) ⇒ Object
Like #respond_to?, this is overriden to include attribute methods. Though, it does include dynamic predicate methods at the moment.
459 460 461 |
# File 'lib/ax/element.rb', line 459 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.
188 189 190 191 |
# File 'lib/ax/element.rb', line 188 def parameterized_attribute attr, param param = param.relative_to(@ref.value.size) if value.kind_of? Range process @ref.parameterized_attribute(TRANSLATOR.cocoaify(attr), param) 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.
225 226 227 |
# File 'lib/ax/element.rb', line 225 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.
405 406 407 408 409 410 |
# File 'lib/ax/element.rb', line 405 def respond_to? name key = TRANSLATOR.cocoaify name.chomp(EQUALS) @ref.attributes.include?(key) || @ref.parameterized_attributes.include?(key) || super end |
#search(kind, filters = {}, &block) ⇒ 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 Tutorial for the details on search semantics.
247 248 249 250 251 252 253 254 255 256 257 |
# File 'lib/ax/element.rb', line 247 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.
416 417 418 419 420 421 422 |
# File 'lib/ax/element.rb', line 416 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.
377 378 379 |
# File 'lib/ax/element.rb', line 377 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 |