AXElements 0.7.8 → 0.8.0

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.
Files changed (64) hide show
  1. data/.yardopts +1 -10
  2. data/README.markdown +7 -14
  3. data/ext/accessibility/key_coder/key_coder.c +7 -0
  4. data/lib/AXElements.rb +0 -2
  5. data/lib/accessibility/core.rb +180 -123
  6. data/lib/accessibility/dsl.rb +310 -191
  7. data/lib/accessibility/enumerators.rb +9 -8
  8. data/lib/accessibility/errors.rb +7 -8
  9. data/lib/accessibility/factory.rb +16 -9
  10. data/lib/accessibility/graph.rb +68 -22
  11. data/lib/accessibility/highlighter.rb +86 -0
  12. data/lib/accessibility/pp_inspector.rb +4 -4
  13. data/lib/accessibility/qualifier.rb +11 -9
  14. data/lib/accessibility/string.rb +12 -4
  15. data/lib/accessibility/translator.rb +19 -10
  16. data/lib/accessibility/version.rb +3 -1
  17. data/lib/accessibility.rb +42 -17
  18. data/lib/ax/application.rb +90 -30
  19. data/lib/ax/button.rb +5 -2
  20. data/lib/ax/element.rb +133 -149
  21. data/lib/ax/pop_up_button.rb +12 -0
  22. data/lib/ax/radio_button.rb +5 -2
  23. data/lib/ax/row.rb +2 -2
  24. data/lib/ax/static_text.rb +5 -2
  25. data/lib/ax/systemwide.rb +24 -12
  26. data/lib/ax_elements/awesome_print.rb +13 -0
  27. data/lib/ax_elements/exception_workaround.rb +5 -0
  28. data/lib/ax_elements/nsarray_compat.rb +1 -0
  29. data/lib/ax_elements.rb +2 -1
  30. data/lib/minitest/ax_elements.rb +60 -4
  31. data/lib/mouse.rb +47 -20
  32. data/lib/rspec/expectations/ax_elements.rb +180 -88
  33. data/rakelib/doc.rake +7 -0
  34. data/test/helper.rb +2 -1
  35. data/test/integration/accessibility/test_dsl.rb +126 -18
  36. data/test/integration/accessibility/test_errors.rb +1 -1
  37. data/test/integration/ax/test_element.rb +17 -0
  38. data/test/integration/minitest/test_ax_elements.rb +33 -38
  39. data/test/integration/rspec/expectations/test_ax_elements.rb +68 -19
  40. data/test/sanity/accessibility/test_core.rb +45 -37
  41. data/test/sanity/accessibility/test_highlighter.rb +56 -0
  42. data/test/sanity/ax/test_application.rb +8 -0
  43. data/test/sanity/ax/test_element.rb +7 -3
  44. data/test/sanity/minitest/test_ax_elements.rb +2 -0
  45. data/test/sanity/rspec/expectations/test_ax_elements.rb +3 -0
  46. data/test/sanity/test_accessibility.rb +9 -0
  47. data/test/sanity/test_mouse.rb +2 -2
  48. metadata +11 -38
  49. data/docs/AccessibilityTips.markdown +0 -119
  50. data/docs/Acting.markdown +0 -340
  51. data/docs/Debugging.markdown +0 -165
  52. data/docs/Inspecting.markdown +0 -261
  53. data/docs/KeyboardEvents.markdown +0 -122
  54. data/docs/NewBehaviour.markdown +0 -151
  55. data/docs/Notifications.markdown +0 -271
  56. data/docs/Searching.markdown +0 -250
  57. data/docs/TestingExtensions.markdown +0 -52
  58. data/docs/images/all_the_buttons.jpg +0 -0
  59. data/docs/images/next_version.png +0 -0
  60. data/docs/images/ui_hierarchy.dot +0 -34
  61. data/docs/images/ui_hierarchy.png +0 -0
  62. data/lib/accessibility/debug.rb +0 -164
  63. data/test/integration/accessibility/test_debug.rb +0 -44
  64. data/test/sanity/accessibility/test_debug.rb +0 -63
@@ -30,11 +30,12 @@ module Accessibility::Enumerators
30
30
  end
31
31
 
32
32
  ##
33
- # @note Explicitly defined so that escaping at the first found element
34
- # actually works. Since only a single `break` is called when an
35
- # item is found it does not fully escape the method. Technically,
36
- # we need to do this with other 'escape-early' iteraters, but
37
- # they aren't being used...yet.
33
+ # @note Explicitly defined so that escaping at the first found
34
+ # element actually works. Since only a single `break` is
35
+ # called when an item is found it does not fully escape the
36
+ # built in implementation. Technically, we need to do this
37
+ # with other 'escape-early' iteraters, but they aren't
38
+ # being used...yet.
38
39
  #
39
40
  # Override `Enumerable#find` for performance reasons.
40
41
  def find
@@ -60,14 +61,14 @@ module Accessibility::Enumerators
60
61
  until stack.empty?
61
62
  current = stack.shift
62
63
  yield current
63
- # needed to reverse it since child ordering seems to matter in practice
64
+ # needed to reverse, child ordering matters in practice
64
65
  stack.unshift *current.children
65
66
  end
66
67
  end
67
68
 
68
69
  ##
69
- # Walk the UI element tree and yield both the element and the level
70
- # that the element is at relative to the root.
70
+ # Walk the UI element tree and yield both the element and the
71
+ # level that the element is at relative to the root.
71
72
  #
72
73
  # @yieldparam [AX::Element,AXUIElementRef]
73
74
  # @yieldparam [Number]
@@ -1,32 +1,31 @@
1
- require 'accessibility/debug'
2
-
3
1
  ##
4
2
  # Error raised when an implicit search fails to return a result.
5
3
  class Accessibility::SearchFailure < NoMethodError
6
4
 
5
+ # @param [AX::Element]
6
+ # @param [#to_s]
7
+ # @param [Hash{Symbol=>Object}]
7
8
  def initialize searcher, searchee, filters
8
9
  filters = {} unless filters.kind_of? Hash
9
10
  msg = "Could not find `#{pp_searchee searchee, filters}` "
10
11
  msg << "as a child of #{searcher.class}\n"
11
12
  msg << "Element Path:\n\t" << path_to(searcher)
12
13
  # @todo Consider turning this on by default
13
- msg << "\nSubtree:\n\t" << debug(searcher) if Accessibility::Debug.on?
14
+ msg << "\nSubtree:\n\n" << subtree_for(searcher) if Accessibility.debug?
14
15
  super msg
15
16
  end
16
17
 
17
18
 
18
19
  private
19
20
 
21
+ # Nice string representation of what was being searched for
20
22
  def pp_searchee searchee, filters
21
23
  Accessibility::Qualifier.new(searchee, filters).describe
22
24
  end
23
25
 
26
+ # Nice string representation of element's path from the application root
24
27
  def path_to element
25
- Accessibility::Debug.path(element).map! { |x| x.inspect }.join("\n\t")
26
- end
27
-
28
- def debug searcher
29
- Accessibility::Debug.text_subtree(searcher)
28
+ element.ancestry.map! { |x| x.inspect }.join("\n\t")
30
29
  end
31
30
 
32
31
  end
@@ -9,13 +9,20 @@ module AX; end
9
9
  # Mixin made for processing low level data from AXAPI methods.
10
10
  module Accessibility::Factory
11
11
 
12
+ # @todo This should provide alternate #to_ruby functionality for
13
+ # the __NSCFType class in order to avoid the overhead of
14
+ # checking type information (or at least reducing it).
15
+ # However, it will force the lower level to always wrap
16
+ # element references; this should be ok most of the time
17
+ # but makes testing a bit of a pain...hmmm
18
+
12
19
  ##
13
- # Processes any given data from an AXAPI method and wraps it if
14
- # needed. Meant for taking a return value from {Accessibility::Core#attr:for:}
15
- # and friends.
20
+ # Processes any given data from an AXAPI function and wraps it if
21
+ # needed. Meant for taking a return value from
22
+ # {Accessibility::Core#attribute} and friends.
16
23
  #
17
- # Generally, used to process an `AXValue` into a `CGPoint` or an
18
- # `AXUIElementRef` into some kind of {AX::Element} object.
24
+ # Generally, used to process an `AXUIElementRef` into a some kind
25
+ # of {AX::Element} subclass.
19
26
  def process value
20
27
  return nil if value.nil? # CFGetTypeID(nil) crashes runtime
21
28
  case CFGetTypeID(value)
@@ -73,7 +80,7 @@ module Accessibility::Factory
73
80
  subrole = ref.subrole
74
81
  # Some objects claim to have a subrole but return nil
75
82
  if subrole
76
- class_for(TRANSLATOR.unprefix(subrole), and: role).new ref
83
+ class_for2(TRANSLATOR.unprefix(subrole), role).new ref
77
84
  else
78
85
  class_for(role).new ref
79
86
  end
@@ -118,12 +125,12 @@ module Accessibility::Factory
118
125
  # @param [#to_s]
119
126
  # @param [#to_s]
120
127
  # @return [Class]
121
- def class_for subrole, and: role
128
+ def class_for2 subrole, role
122
129
  # @todo it would be nice if we didn't have to lookup twice
123
130
  if AX.const_defined? subrole, false
124
131
  AX.const_get subrole
125
132
  else
126
- create_class subrole, with_superclass: role
133
+ create_class2 subrole, role
127
134
  end
128
135
  end
129
136
 
@@ -145,7 +152,7 @@ module Accessibility::Factory
145
152
  # @param [#to_s] name
146
153
  # @param [#to_s] superklass
147
154
  # @return [Class]
148
- def create_class name, with_superclass: superklass
155
+ def create_class2 name, superklass
149
156
  unless AX.const_defined? superklass, false
150
157
  create_class superklass
151
158
  end
@@ -4,11 +4,13 @@
4
4
  # an image for the graph.
5
5
  #
6
6
  # You can learn more about generating graphs in the
7
- # {file:docs/Debugging.markdown Debugging} tutorial.
7
+ # [Debugging tutorial](http://github.com/Marketcircle/AXElements/wiki/Debugging).
8
+ #
9
+ # [Learn more about GraphViz](http://www.graphviz.org/).
8
10
  class Accessibility::Graph
9
11
 
10
12
  ##
11
- # @todo Graphs could be a lot nicer looking. That is, nodes could be much
13
+ # @todo Graphs could be nicer looking. That is, nodes could be much
12
14
  # more easily identifiable, by allowing different classes to tell
13
15
  # the node more about itself. A mixin module/protocol should
14
16
  # probably be created, just as with the inspector mixin, and added
@@ -35,38 +37,82 @@ class Accessibility::Graph
35
37
 
36
38
  # @return [String]
37
39
  def to_dot
38
- "#{@id} #{identifier} #{shape}"
40
+ "#{@id} #{identifier} [shape=#{shape}] [style=#{style}] [color=#{colour}]"
39
41
  end
40
42
 
41
43
 
42
44
  private
43
45
 
44
- EMPTY_STRING = ''
45
- NAMESPACE = '::'
46
-
47
46
  def identifier
48
47
  klass = @element.class.to_s.split(NAMESPACE).last
49
- ident = @element.pp_identifier
48
+ ident = @element.pp_identifier.dup
49
+ if ident.length > 12
50
+ ident = "#{ident[0...12]}..."
51
+ end
52
+ ident << '"' if ident[1] == QUOTE && ident[-1] != QUOTE
50
53
  ident.gsub! /"/, '\"'
54
+ ident.gsub! /\\/, '\\'
51
55
  "[label = \"#{klass}#{ident}\"]"
52
56
  end
53
57
 
54
58
  def shape
55
- @element.actions.empty? ? OVAL : BOX
59
+ (@element.attribute(:focused) && OCTAGON) ||
60
+ (@element.actions.empty? && OVAL) ||
61
+ BOX
56
62
  end
57
63
 
58
- def enabled
59
- FILL if @element.enabled?
64
+ def style
65
+ # fill in the node if it is disabled (greyed out effect)
66
+ if @element.attributes.include?(:enabled)
67
+ return FILLED unless @element.attribute(:enabled)
68
+ end
69
+ # bold if focused and no children
70
+ if @element.attribute(:focused)
71
+ return BOLD if @element.size_of(:children).zero?
72
+ end
73
+ SOLID
60
74
  end
61
75
 
62
- def focus
63
- BOLD if @element.focused?
76
+ def colour
77
+ if @element.attributes.include?(:enabled)
78
+ return GREY unless @element.attribute(:enabled)
79
+ end
80
+ BLACK
64
81
  end
65
82
 
66
- OVAL = '[shape = oval]'
67
- BOX = '[shape = box]'
68
- BOLD = '[style = bold]'
69
- FILL = '[style = filled] [color = "grey"]'
83
+ # @private
84
+ # @return [String]
85
+ EMPTY_STRING = ''
86
+ # @private
87
+ # @return [String]
88
+ NAMESPACE = '::'
89
+ # @private
90
+ # @return [String]
91
+ QUOTE = '"'
92
+ # @private
93
+ # @return [String]
94
+ OVAL = 'oval'
95
+ # @private
96
+ # @return [String]
97
+ BOX = 'box'
98
+ # @private
99
+ # @return [String]
100
+ OCTAGON = 'doubleoctagon'
101
+ # @private
102
+ # @return [String]
103
+ BOLD = 'bold'
104
+ # @private
105
+ # @return [String]
106
+ FILLED = 'filled'
107
+ # @private
108
+ # @return [String]
109
+ SOLID = 'solid'
110
+ # @private
111
+ # @return [String]
112
+ GREY = 'grey'
113
+ # @private
114
+ # @return [String]
115
+ BLACK = 'black'
70
116
  end
71
117
 
72
118
  ##
@@ -83,8 +129,7 @@ class Accessibility::Graph
83
129
  # @param [Accessibility::Graph::Node]
84
130
  # @param [Accessibility::Graph::Node]
85
131
  def initialize head, tail
86
- @head = head
87
- @tail = tail
132
+ @head, @tail = head, tail
88
133
  end
89
134
 
90
135
  # @return [String]
@@ -117,7 +162,7 @@ class Accessibility::Graph
117
162
  # exploit the ordering of a breadth-first enumeration to simplify
118
163
  # the creation of edges for the graph. This only works because
119
164
  # the UI hiearchy is a simple tree.
120
- @edge_queue = Array.new(root.size_of(:children), root_node)
165
+ @edge_queue = Array.new(root.children.size, root_node)
121
166
  end
122
167
 
123
168
  ##
@@ -130,7 +175,8 @@ class Accessibility::Graph
130
175
  Accessibility::Enumerators::BreadthFirst.new(nodes.last.element).each do |element|
131
176
  nodes << node = Node.new(element)
132
177
  edges << Edge.new(node, @edge_queue.shift)
133
- @edge_queue.concat Array.new(element.size_of(:children), node)
178
+ # should use #size_of(:children), but that doesn't in all cases
179
+ @edge_queue.concat Array.new(element.children.size, node)
134
180
  end
135
181
  end
136
182
 
@@ -141,9 +187,9 @@ class Accessibility::Graph
141
187
  # @return [String]
142
188
  def to_dot
143
189
  graph = "digraph {\n"
144
- graph << nodes.map(&:to_dot).join("\n")
190
+ graph << nodes.map(&:to_dot).join(";\n")
145
191
  graph << "\n\n"
146
- graph << edges.map(&:to_dot).join("\n")
192
+ graph << edges.map(&:to_dot).join(";\n")
147
193
  graph << "\n}\n"
148
194
  end
149
195
 
@@ -0,0 +1,86 @@
1
+ framework 'AppKit'
2
+ require 'accessibility/version'
3
+
4
+ ##
5
+ # A screen highlighter for debugging. When you initialize a highligter
6
+ # object it will highlight the given bounds on the screen.
7
+ #
8
+ # Highligter objects can have their colour configured at initialization,
9
+ # and can also have a timeout to automatically stop displaying.
10
+ #
11
+ # @example
12
+ #
13
+ # h = Accessibility::Highlighter.new(CGRectMake(100,100,100,100))
14
+ # # when you are done...
15
+ # h.stop
16
+ #
17
+ class Accessibility::Highlighter < NSWindow
18
+
19
+ # @param [CGRect]
20
+ # @param [Hash] opts
21
+ # @option opts [Number] :timeout
22
+ # @option opts [NSColor] :colour (NSColor.magentaColor)
23
+ def initialize bounds, opts = {}
24
+ colour = opts[:colour] || opts[:color] || NSColor.magentaColor
25
+
26
+ bounds.flip! # we assume the rect is in the other co-ordinate system
27
+
28
+ initWithContentRect bounds,
29
+ styleMask: NSBorderlessWindowMask,
30
+ backing: NSBackingStoreBuffered,
31
+ defer: true
32
+ setOpaque false
33
+ setAlphaValue 0.20
34
+ setLevel NSStatusWindowLevel
35
+ setBackgroundColor colour
36
+ setIgnoresMouseEvents true
37
+ setFrame bounds, display: false
38
+ makeKeyAndOrderFront NSApp
39
+
40
+ if opts.has_key? :timeout
41
+ Dispatch::Queue.new(queue_id).after opts[:timeout] do
42
+ self.stop
43
+ end
44
+ end
45
+ end
46
+
47
+ ##
48
+ # Tell the highlighter to stop displaying.
49
+ #
50
+ # @return [self]
51
+ def stop
52
+ close
53
+ end
54
+
55
+
56
+ private
57
+
58
+ def queue_id
59
+ "com.marketcircle.axelements.window_killer_#{hash}"
60
+ end
61
+ end
62
+
63
+
64
+ ##
65
+ # AXElements extensions to `CGRect`.
66
+ class CGRect
67
+ ##
68
+ # Treats the rect as belonging to one co-ordinate system and then
69
+ # converts it to the other system.
70
+ #
71
+ # This is useful because accessibility API's expect to work with
72
+ # the flipped co-ordinate system (origin in top left), but AppKit
73
+ # prefers to use the cartesian co-ordinate system (origin in bottom
74
+ # left).
75
+ #
76
+ # @return [CGRect]
77
+ def flip!
78
+ screen_height = NSMaxY(NSScreen.mainScreen.frame)
79
+ origin.y = screen_height - NSMaxY(self)
80
+ self
81
+ end
82
+ end
83
+
84
+
85
+ # Initialize the shared application so that windows can be created
86
+ NSApplication.sharedApplication
@@ -13,8 +13,8 @@
13
13
  module Accessibility::PPInspector
14
14
 
15
15
  ##
16
- # Create an identifier for `self` using various attributes that should
17
- # make it very easy to identify the element.
16
+ # Create an identifier for the receiver by using various attributes
17
+ # that should make it very easy to identify the element.
18
18
  #
19
19
  # @return [String]
20
20
  def pp_identifier
@@ -55,7 +55,7 @@ module Accessibility::PPInspector
55
55
 
56
56
  ##
57
57
  # Create a string that succinctly encodes the screen coordinates
58
- # of `self`.
58
+ # of the receiver.
59
59
  #
60
60
  # @return [String]
61
61
  def pp_position
@@ -69,7 +69,7 @@ module Accessibility::PPInspector
69
69
 
70
70
  ##
71
71
  # Create a string that nicely presents the number of children
72
- # that `self` has.
72
+ # that the receiver has.
73
73
  #
74
74
  # @return [String]
75
75
  def pp_children
@@ -10,7 +10,7 @@ class Accessibility::Qualifier
10
10
  # Initialize a qualifier with the kind of object that you want to
11
11
  # qualify and a dictionary of filter criteria. You can optionally
12
12
  # pass a block if your qualification criteria is too complicated
13
- # for key/value pairs and the blocks return value will be used to
13
+ # for key/value pairs; the blocks return value will be used to
14
14
  # determine if an element qualifies.
15
15
  #
16
16
  # @example
@@ -22,7 +22,7 @@ class Accessibility::Qualifier
22
22
  # element.children.size > 5 && NSContainsRect(element.bounds, rect)
23
23
  # end
24
24
  #
25
- # @param [#to_s] klass
25
+ # @param [#to_s]
26
26
  # @param [Hash]
27
27
  # @yield Optional block that can qualify an element
28
28
  def initialize klass, criteria
@@ -41,6 +41,10 @@ class Accessibility::Qualifier
41
41
  the_right_type?(element) && meets_criteria?(element)
42
42
  end
43
43
 
44
+ ##
45
+ # Return a compact description of the qualifier. If the qualifier
46
+ # includes a block then a checkmarked box will be included.
47
+ #
44
48
  # @return [String]
45
49
  def describe
46
50
  "#{@klass}#{@criteria.ax_pp}#{@block ? '[✔]' : ''}"
@@ -49,16 +53,14 @@ class Accessibility::Qualifier
49
53
 
50
54
  private
51
55
 
52
- ##
53
56
  # @private
54
- #
55
- # Local reference to the {Accessibility::Translator}.
56
- #
57
57
  # @return [Accessibility::Translator]
58
58
  TRANSLATOR = Accessibility::Translator.instance
59
59
 
60
60
  ##
61
61
  # Take a hash of search filters and generate an optimized search
62
+ # array. This is done to avoid checking types for each call to
63
+ # {#qualifies?}.
62
64
  #
63
65
  # @param [Hash]
64
66
  def compile criteria
@@ -118,11 +120,11 @@ class Accessibility::Qualifier
118
120
  end
119
121
 
120
122
  def parameterized_match attr, param, regexp, element
121
- element.attribute(attr, for_parameter: param).to_s.match regexp
123
+ element.parameterized_attribute(attr, param).to_s.match regexp
122
124
  end
123
125
 
124
126
  def parameterized_equality attr, param, value, element
125
- element.attribute(attr, for_parameter: param) == value
127
+ element.parameterized_attribute(attr, param) == value
126
128
  end
127
129
 
128
130
  def block_check element
@@ -133,7 +135,7 @@ end
133
135
 
134
136
 
135
137
  ##
136
- # Extensions to `NSDictionary`.
138
+ # AXElements extensions to `NSDictionary`.
137
139
  class NSDictionary
138
140
  ##
139
141
  # Format the hash for AXElements pretty printing.
@@ -26,7 +26,7 @@ module Accessibility::String
26
26
  # {Accessibility::String::EventGenerator::CUSTOM}.
27
27
  #
28
28
  # For more details on event generation, read the
29
- # {file:docs/KeyboardEvents.markdown Keyboard Events} documentation.
29
+ # [Keyboarding documentation](http://github.com/Marketcircle/AXElements/wiki/Keyboarding).
30
30
  #
31
31
  # @param [String]
32
32
  # @return [Array<Array(Fixnum,Boolean)>]
@@ -43,7 +43,7 @@ module Accessibility::String
43
43
  # @example
44
44
  #
45
45
  # Lexer.new("Hai").lex # => ['H','a','i']
46
- # Lexer.new("\\CAPSLOCK").lex # => [["\\CAPSLOCK"]]
46
+ # Lexer.new("\\CONTROL").lex # => [["\\CONTROL"]]
47
47
  # Lexer.new("\\COMMAND+a").lex # => [["\\COMMAND", ['a']]]
48
48
  # Lexer.new("One\nTwo").lex # => ['O','n','e',"\n",'T','w','o']
49
49
  #
@@ -132,10 +132,13 @@ module Accessibility::String
132
132
  end
133
133
 
134
134
  # @private
135
+ # @return [String]
135
136
  SPACE = " "
136
137
  # @private
138
+ # @return [String]
137
139
  PLUS = "+"
138
140
  # @private
141
+ # @return [String]
139
142
  CUSTOM_ESCAPE = "\\"
140
143
  end
141
144
 
@@ -150,8 +153,8 @@ module Accessibility::String
150
153
  # # Upper case 'A'
151
154
  # EventGenerator.new(["A"]).generate # => [[56,true],[70,true],[70,false],[56,false]]
152
155
  #
153
- # # Press the caps lock button, turn it on
154
- # EventGenerator.new([["\\CAPS"]]).generate # => [[0x39,true],[0x39,false]]
156
+ # # Press the volume up key
157
+ # EventGenerator.new([["\\F12"]]).generate # => [[0x6F,true],[0x6F,false]]
155
158
  #
156
159
  # # Hotkey, press and hold command key and then 'a', then release both
157
160
  # EventGenerator.new([["\\CMD",["a"]]]).generate # => [[55,true],[70,true],[70,false],[55,false]]
@@ -470,14 +473,19 @@ module Accessibility::String
470
473
  end
471
474
 
472
475
  # @private
476
+ # @return [String]
473
477
  EMPTY_STRING = ""
474
478
  # @private
479
+ # @return [Array(Number,Boolean)]
475
480
  OPTION_DOWN = [58, true]
476
481
  # @private
482
+ # @return [Array(Number,Boolean)]
477
483
  OPTION_UP = [58, false]
478
484
  # @private
485
+ # @return [Array(Number,Boolean)]
479
486
  SHIFT_DOWN = [56, true]
480
487
  # @private
488
+ # @return [Array(Number,Boolean)]
481
489
  SHIFT_UP = [56, false]
482
490
  end
483
491
 
@@ -16,9 +16,16 @@ end
16
16
 
17
17
  ##
18
18
  # Maintain all the rules for transforming Cocoa constants into something
19
- # a little more Rubyish.
19
+ # a little more Rubyish and taking the Rubyish symbols and translating
20
+ # them back to Cocoa constants.
20
21
  class Accessibility::Translator
21
22
 
23
+ ##
24
+ # Get the singleton instance of the {Accessibility::Translator} class.
25
+ # This is meant to mimic the important functionality of the
26
+ # `Singleton` mix-in.
27
+ #
28
+ # @return [Accessibility::Translator]
22
29
  def self.instance
23
30
  @instance ||= new
24
31
  end
@@ -54,6 +61,14 @@ class Accessibility::Translator
54
61
  @unprefixes[key]
55
62
  end
56
63
 
64
+ ##
65
+ # Take an array of Cocoa accessibility constants and return an
66
+ # array of shortened Ruby symbols.
67
+ #
68
+ # @example
69
+ #
70
+ # rubyize ["AXRole", "AXTitleUIElement"] # => [:role, :title_ui_element]
71
+ #
57
72
  # @return [Array<Symbol>]
58
73
  def rubyize keys
59
74
  keys.map { |x| @rubyisms[x] }
@@ -102,7 +117,9 @@ class Accessibility::Translator
102
117
 
103
118
  ##
104
119
  # Try to turn an arbitrary symbol into a notification constant, and
105
- # then get the value of the constant.
120
+ # then get the value of the constant. If it cannot be turned into
121
+ # a notification constant then the original string parameter will
122
+ # be returned.
106
123
  #
107
124
  # @param [#to_s]
108
125
  # @return [String]
@@ -156,19 +173,11 @@ class Accessibility::Translator
156
173
  end
157
174
  end
158
175
 
159
- ##
160
176
  # @private
161
- #
162
- # Cached for performance.
163
- #
164
177
  # @return [String]
165
178
  EMPTY_STRING = ''
166
179
 
167
- ##
168
180
  # @private
169
- #
170
- # Performance hack.
171
- #
172
181
  # @return [String]
173
182
  QUESTION_MARK = '?'
174
183
  end
@@ -1,6 +1,8 @@
1
+ ##
2
+ # The main AXElements namespace.
1
3
  module Accessibility
2
4
  # @return [String]
3
- VERSION = '0.7.8'
5
+ VERSION = '0.8.0'
4
6
 
5
7
  # @return [String]
6
8
  CODE_NAME = 'Clefairy'