AXElements 0.7.8 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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'