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
@@ -31,8 +31,9 @@ require 'accessibility/version'
31
31
  # still work out ok.
32
32
  # @todo I feel a bit weird having to instantiate a new pointer every
33
33
  # time I want to fetch an attribute. Since allocations are costly,
34
- # it hurts performance a lot when it comes to searches. I wonder if
35
- # it would pay off to have a pool of pointers...
34
+ # and searching requires _many_ AXAPI calls, it hurts performance
35
+ # a lot when it comes to searches. I wonder if it would pay off
36
+ # to have a pool of pointers...
36
37
  #
37
38
  # Core abstraction layer that that interacts with OS X Accessibility
38
39
  # APIs (AXAPI). This is actually just a mixin for `AXUIElementRef` objects
@@ -85,8 +86,11 @@ module Accessibility::Core
85
86
  # will be unwrapped for you, if you expect to get a {CFRange} you
86
87
  # will be given a {Range} instead.
87
88
  #
88
- # As a convention, if the backing element is no longer alive then
89
- # you will receive `nil` for any attribute.
89
+ # As a convention, if the backing element is no longer alive, or
90
+ # the attribute does not exist, or a system failure occurs then
91
+ # you will receive `nil` for any attribute except for
92
+ # `KAXChildrenAttribute`. `KAXChildrenAttribute` will always return
93
+ # an array.
90
94
  #
91
95
  # @example
92
96
  # attribute KAXTitleAttribute # => "HotCocoa Demo"
@@ -94,14 +98,15 @@ module Accessibility::Core
94
98
  # attribute KAXParentAttribute # => #<AXUIElementRef>
95
99
  # attribute KAXNoValueAttribute # => nil
96
100
  #
97
- # @param [String] name an attribute constant
101
+ # @param [String]
98
102
  def attribute name
99
103
  ptr = Pointer.new :id
100
104
  case code = AXUIElementCopyAttributeValue(self, name, ptr)
101
105
  when 0
102
106
  ptr.value.to_ruby
103
107
  when KAXErrorNoValue, KAXErrorAttributeUnsupported,
104
- KAXErrorFailure, KAXErrorInvalidUIElement then
108
+ KAXErrorFailure, KAXErrorInvalidUIElement,
109
+ KAXErrorIllegalArgument then
105
110
  name == KAXChildrenAttribute ? [] : nil
106
111
  else
107
112
  handle_error code, name
@@ -109,13 +114,14 @@ module Accessibility::Core
109
114
  end
110
115
 
111
116
  ##
112
- # Shortcut for getting the `KAXRoleAttribute`.
117
+ # Shortcut for getting the `KAXRoleAttribute`. Remember that
118
+ # dead elements may return `nil` for their role.
113
119
  #
114
120
  # @example
115
121
  #
116
122
  # role # => KAXWindowRole
117
123
  #
118
- # @return [String]
124
+ # @return [String,nil]
119
125
  def role
120
126
  attribute KAXRoleAttribute
121
127
  end
@@ -136,7 +142,9 @@ module Accessibility::Core
136
142
  end
137
143
 
138
144
  ##
139
- # Shortcut for getting the `KAXChildrenAttribute`.
145
+ # Shortcut for getting the `KAXChildrenAttribute`. This is guaranteed
146
+ # to alwayl return an array or raise an exception, unless the object
147
+ # you are querying is behaving maliciously.
140
148
  #
141
149
  # @example
142
150
  #
@@ -159,6 +167,33 @@ module Accessibility::Core
159
167
  attribute KAXValueAttribute
160
168
  end
161
169
 
170
+ ##
171
+ # Get the process identifier (PID) of the application that the element
172
+ # belongs to.
173
+ #
174
+ # This method will return `0` if the element is dead or if the receiver
175
+ # is the the system wide element.
176
+ #
177
+ # @example
178
+ #
179
+ # pid # => 12345
180
+ # system_wide.pid # => 0
181
+ #
182
+ # @return [Fixnum]
183
+ def pid
184
+ @pid ||= (
185
+ ptr = Pointer.new :int
186
+ case code = AXUIElementGetPid(self, ptr)
187
+ when 0
188
+ ptr.value
189
+ when KAXErrorInvalidUIElement
190
+ self == system_wide ? 0 : handle_error(code)
191
+ else
192
+ handle_error code
193
+ end
194
+ )
195
+ end
196
+
162
197
  ##
163
198
  # Get the size of the array for attributes that would return an array.
164
199
  # When performance matters, this is much faster than getting the array
@@ -172,7 +207,7 @@ module Accessibility::Core
172
207
  # size_of KAXChildrenAttribute # => 19
173
208
  # size_of KAXRowsAttribute # => 100
174
209
  #
175
- # @param [String] name an attribute constant
210
+ # @param [String]
176
211
  # @return [Number]
177
212
  def size_of name
178
213
  ptr = Pointer.new :long_long
@@ -188,14 +223,18 @@ module Accessibility::Core
188
223
  end
189
224
 
190
225
  ##
191
- # Returns whether or not an attribute is writable.
226
+ # Returns whether or not an attribute is writable. You should check
227
+ # writability before trying call {#set} for the attribute.
228
+ #
229
+ # In case of internal error or if the element dies, this method will
230
+ # return `false`.
192
231
  #
193
232
  # @example
194
233
  #
195
234
  # writable? KAXSizeAttribute # => true
196
235
  # writable? KAXTitleAttribute # => false
197
236
  #
198
- # @param [String] name an attribute constant
237
+ # @param [String]
199
238
  def writable? name
200
239
  ptr = Pointer.new :bool
201
240
  case code = AXUIElementIsAttributeSettable(self, name, ptr)
@@ -210,24 +249,24 @@ module Accessibility::Core
210
249
  end
211
250
 
212
251
  ##
213
- # @note This method does not check writability of the attribute
214
- # you are setting. If you need to check, use {#writable?}
215
- # first.
216
- #
217
- # Set the given value to the given attribute. You do not need to
252
+ # Set the given value for the given attribute. You do not need to
218
253
  # worry about wrapping objects first, `Range` objects will also
219
254
  # be automatically converted into `CFRange` objects and then
220
255
  # wrapped.
221
256
  #
222
- # Unlike when reading attributes, writing to a dead element will
223
- # raise an exception.
257
+ # This method does not check writability of the attribute you are
258
+ # setting. If you need to check, use {#writable?} first to check.
259
+ #
260
+ # Unlike when reading attributes, writing to a dead element, and
261
+ # other error conditions, will raise an exception.
224
262
  #
225
263
  # @example
264
+ #
226
265
  # set KAXValueAttribute, "hi" # => "hi"
227
266
  # set KAXSizeAttribute, [250,250] # => [250,250]
228
267
  # set KAXVisibleRangeAttribute, 0..-3 # => 0..-3
229
268
  #
230
- # @param [String] name an attribute constant
269
+ # @param [String]
231
270
  def set name, value
232
271
  code = AXUIElementSetAttributeValue(self, name, value.to_ax)
233
272
  if code.zero?
@@ -248,6 +287,9 @@ module Accessibility::Core
248
287
  # Most elements do not have parameterized attributes, but the ones
249
288
  # that do, have many.
250
289
  #
290
+ # Similar to {#attributes}, this method will also return an empty
291
+ # array if the element is dead.
292
+ #
251
293
  # @example
252
294
  #
253
295
  # parameterized_attributes # => ["AXStringForRange", ...]
@@ -266,20 +308,24 @@ module Accessibility::Core
266
308
  end
267
309
 
268
310
  ##
269
- # Fetch the given pramaeterized attribute value using the given parameter.
270
- # Only `AXUIElementRef` objects will be given raw, `Boxed` objects will be
271
- # unwrapped for you automatically and `CFRange` objects will be turned into
272
- # `Range` objects. Similarly, you do not need to worry about wrapping the
273
- # parameter as that will be done for you.
311
+ # Fetch the given pramaeterized attribute value for the given parameter.
312
+ # Only `AXUIElementRef` objects will be returned in their raw form,
313
+ # {Boxed} objects will be unwrapped for you automatically and {CFRange}
314
+ # objects will be turned into {Range} objects. Similarly, you do not
315
+ # need to worry about wrapping the parameter as that will be done for you.
316
+ #
317
+ # As a convention, if the backing element is no longer alive, or the
318
+ # attribute does not exist, or a system failure occurs then you will
319
+ # receive `nil`.
274
320
  #
275
321
  # @example
276
322
  #
277
- # attribute KAXStringForRangeParameterizedAttribute, for_param: 1..10
323
+ # parameterized_attribute KAXStringForRangeParameterizedAttribute, 1..10
278
324
  # # => "ello, worl"
279
325
  #
280
- # @param [String] attr an attribute constant
281
- # @param [Object] param
282
- def attribute name, for_parameter: param
326
+ # @param [String]
327
+ # @param [Object]
328
+ def parameterized_attribute name, param
283
329
  ptr = Pointer.new :id
284
330
  case code = AXUIElementCopyParameterizedAttributeValue(self, name, param.to_ax, ptr)
285
331
  when 0
@@ -297,8 +343,8 @@ module Accessibility::Core
297
343
 
298
344
  ##
299
345
  # Get the list of actions that the element can perform. If an element
300
- # does not have actions, then an empty list will be returned.
301
- # Dead elements will also return an empty array.
346
+ # does not have actions, then an empty list will be returned. Dead
347
+ # elements will also return an empty array.
302
348
  #
303
349
  # @example
304
350
  #
@@ -318,7 +364,8 @@ module Accessibility::Core
318
364
 
319
365
  ##
320
366
  # Ask an element to perform the given action. This method will always
321
- # return true or raise an exception. Actions should never fail.
367
+ # return true or raise an exception. Actions should never fail, but
368
+ # there are some extreme edge cases (e.g. out of memory, etc.).
322
369
  #
323
370
  # Unlike when reading attributes, performing an action on a dead element
324
371
  # will raise an exception.
@@ -327,7 +374,7 @@ module Accessibility::Core
327
374
  #
328
375
  # perform KAXPressAction # => true
329
376
  #
330
- # @param [String] action an action constant
377
+ # @param [String]
331
378
  # @return [Boolean]
332
379
  def perform action
333
380
  code = AXUIElementPerformAction(self, action)
@@ -351,7 +398,7 @@ module Accessibility::Core
351
398
  # keyup).
352
399
  #
353
400
  # You can learn more about keyboard events from the
354
- # {file:docs/KeyboardEvents.markdown Keyboard Events} documentation.
401
+ # [Keyboard Events documentation](http://github.com/Marketcircle/AXElements/wiki/Keyboarding).
355
402
  #
356
403
  # @example
357
404
  #
@@ -365,14 +412,12 @@ module Accessibility::Core
365
412
  events.each do |event|
366
413
  code = AXUIElementPostKeyboardEvent(self, 0, *event)
367
414
  handle_error code unless code.zero?
368
- sleep KEY_RATE
415
+ sleep @@key_rate
369
416
  end
370
417
  sleep 0.1 # in many cases, UI is not done updating right away
371
418
  end
372
419
 
373
420
  ##
374
- # @todo Make this runtime configurable.
375
- #
376
421
  # The delay between key presses. The default value is `0.01`, which
377
422
  # should be about 50 characters per second (down and up are separate
378
423
  # events).
@@ -382,12 +427,15 @@ module Accessibility::Core
382
427
  # were tried, but were way too big.
383
428
  #
384
429
  # @return [Number]
385
- KEY_RATE = case ENV['KEY_RATE']
386
- when 'VERY_SLOW' then 0.9
387
- when 'SLOW' then 0.09
388
- when nil then 0.009
389
- else ENV['KEY_RATE'].to_f
390
- end
430
+ def key_rate
431
+ @@key_rate
432
+ end
433
+ @@key_rate = case ENV['KEY_RATE']
434
+ when 'VERY_SLOW' then 0.9
435
+ when 'SLOW' then 0.09
436
+ when nil then 0.009
437
+ else ENV['KEY_RATE'].to_f
438
+ end
391
439
 
392
440
 
393
441
  # @group Element Hierarchy Entry Points
@@ -401,13 +449,16 @@ module Accessibility::Core
401
449
  # system (origin is in the top-left, increasing downward and to the right
402
450
  # as if reading a book in English).
403
451
  #
404
- # If more than one element is at the position then the
405
- # z-order of the elements will be used to determine which is
406
- # "on top".
452
+ # If more than one element is at the position then the z-order of the
453
+ # elements will be used to determine which is "on top".
454
+ #
455
+ # This method will safely return `nil` if there is no UI element at the
456
+ # give point.
407
457
  #
408
458
  # @example
409
459
  #
410
460
  # element_at [453, 200] # table
461
+ # element_at CGPoint.new(453, 200) # table
411
462
  #
412
463
  # @param [#to_point]
413
464
  # @return [AXUIElementRef,nil]
@@ -426,15 +477,15 @@ module Accessibility::Core
426
477
  end
427
478
 
428
479
  ##
429
- # Get the application accessibility object/token for an application
430
- # given the process identifier (PID) for that application.
480
+ # Get the application object object/token for an application given the
481
+ # process identifier (PID) for that application.
431
482
  #
432
483
  # @example
433
484
  #
434
485
  # app = application_for 54743 # => #<AXUIElementRefx00000000>
435
486
  # CFShow(app)
436
487
  #
437
- # @param [Fixnum]
488
+ # @param [Number]
438
489
  # @return [AXUIElementRef]
439
490
  def application_for pid
440
491
  spin_run_loop
@@ -505,17 +556,19 @@ module Accessibility::Core
505
556
 
506
557
  ##
507
558
  # @todo Should passing around a context be supported?
559
+ # @todo If a block is passed instead of an observer, then implicitly create
560
+ # the observer.
508
561
  #
509
562
  # Register a notification observer for a specific event.
510
563
  #
511
564
  # @example
512
565
  #
513
- # register observer, to_receive: KAXWindowCreatedNotification
566
+ # register observer, KAXWindowCreatedNotification
514
567
  #
515
568
  # @param [AXObserverRef]
516
569
  # @param [String]
517
570
  # @return [Boolean]
518
- def register observer, to_receive: notif
571
+ def register observer, notif
519
572
  case code = AXObserverAddNotification(observer, self, notif, nil)
520
573
  when 0 then true
521
574
  else handle_error code, notif, observer, nil, nil
@@ -525,10 +578,14 @@ module Accessibility::Core
525
578
  ##
526
579
  # Unregister a notification that has been previously setup.
527
580
  #
581
+ # @example
582
+ #
583
+ # unregister observer, KAXWindowCreatedNotification
584
+ #
528
585
  # @param [AXObserverRef]
529
586
  # @param [String]
530
587
  # @return [Boolean]
531
- def unregister observer, from_receiving: notif
588
+ def unregister observer, notif
532
589
  case code = AXObserverRemoveNotification(observer, self, notif)
533
590
  when 0 then true
534
591
  else handle_error code, notif, observer, nil, nil
@@ -538,43 +595,6 @@ module Accessibility::Core
538
595
 
539
596
  # @group Misc.
540
597
 
541
- ##
542
- # Ask whether or not AXAPI is enabled.
543
- #
544
- # @example
545
- #
546
- # enabled? # => true
547
- #
548
- # # After unchecking "Enable access for assistive devices" in System Prefs
549
- # enabled? # => false
550
- #
551
- def enabled?
552
- AXAPIEnabled()
553
- end
554
-
555
- ##
556
- # Get the process identifier (PID) of the application that the element
557
- # belongs to.
558
- #
559
- # @example
560
- #
561
- # pid # => 12345
562
- #
563
- # @return [Fixnum]
564
- def pid
565
- @pid ||= (
566
- ptr = Pointer.new :int
567
- case code = AXUIElementGetPid(self, ptr)
568
- when 0
569
- ptr.value
570
- when KAXErrorInvalidUIElement
571
- self == system_wide ? 0 : handle_error(code)
572
- else
573
- handle_error code
574
- end
575
- )
576
- end
577
-
578
598
  ##
579
599
  # Create a new reference to the system wide object. This is very useful when
580
600
  # working with the system wide object as caching the system wide reference
@@ -590,7 +610,8 @@ module Accessibility::Core
590
610
  end
591
611
 
592
612
  ##
593
- # Returns the application reference that the element belongs to.
613
+ # Returns the application reference for the application that the receiver
614
+ # belongs to.
594
615
  #
595
616
  # @return [AXUIElementRef]
596
617
  def application
@@ -605,7 +626,7 @@ module Accessibility::Core
605
626
  #
606
627
  # spin_run_loop # not much to it
607
628
  #
608
- # @return [self] returns the receiver
629
+ # @return [void]
609
630
  def spin_run_loop
610
631
  NSRunLoop.currentRunLoop.runUntilDate Time.now
611
632
  end
@@ -619,8 +640,8 @@ module Accessibility::Core
619
640
  #
620
641
  # Setting the global timeout to `0` seconds will reset the timeout value
621
642
  # to the system default. Apple does not appear to have publicly documented
622
- # what the system default is though, so I can't tell you what that value
623
- # is.
643
+ # what the system default is and there is no API to check what the value
644
+ # is set to, so I can't tell you what the current value is.
624
645
  #
625
646
  # @param [Number]
626
647
  # @return [Number]
@@ -647,18 +668,21 @@ module Accessibility::Core
647
668
  raise klass, msg, caller(1)
648
669
  end
649
670
 
671
+ # @return [String]
650
672
  def handle_failure *args
651
673
  "A system failure occurred with #{inspect}, stopping to be safe"
652
674
  end
653
675
 
676
+ # @todo this is a pretty crappy way of handling the various illegal
677
+ # argument cases
678
+ # @return [String]
654
679
  def handle_illegal_argument *args
655
680
  case args.size
656
681
  when 0
657
682
  "#{inspect} is not an AXUIElementRef"
658
683
  when 1
659
- "Either the element #{inspect} " +
660
- "or the attribute/action/callback #{args.first.inspect} " +
661
- "is not a legal argument"
684
+ "Either the element #{inspect} or the attribute/action/callback " +
685
+ "#{args.first.inspect} is not a legal argument"
662
686
  when 2
663
687
  "You can't get/set #{args.first.inspect} with/to " +
664
688
  "#{args[1].inspect} for #{inspect}"
@@ -666,70 +690,76 @@ module Accessibility::Core
666
690
  "The point #{args.first.to_point.inspect} is not a valid point, " +
667
691
  "or #{inspect} is not an AXUIElementRef"
668
692
  when 4
669
- "Either the observer #{args[1].inspect}, " +
670
- "the element #{inspect}, or " +
671
- "the notification #{args.first.inspect} " +
672
- "is not a legitimate argument"
693
+ "Either the observer #{args[1].inspect}, the element #{inspect}, " +
694
+ "or the notification #{args.first.inspect} is not a legitimate argument"
673
695
  end
674
696
  end
675
697
 
698
+ # @return [String]
676
699
  def handle_invalid_element *args
677
700
  "#{inspect} is no longer a valid reference"
678
701
  end
679
702
 
703
+ # @return [String]
680
704
  def handle_invalid_observer *args
681
- "#{args[1].inspect} is no longer a valid observer for " +
682
- "#{inspect} or was never valid"
705
+ "#{args[1].inspect} is no longer a valid observer for #{inspect} or was never valid"
683
706
  end
684
707
 
685
708
  # @param [AXUIElementRef]
709
+ # @return [String]
686
710
  def handle_cannot_complete *args
687
711
  spin_run_loop
688
712
  app = NSRunningApplication.runningApplicationWithProcessIdentifier pid
689
713
  if app
690
- "An unspecified error occurred using #{inspect} with AXAPI" +
691
- ", maybe a timeout :("
714
+ "An unspecified error occurred using #{inspect} with AXAPI, maybe a timeout :("
692
715
  else
693
716
  "Application for pid=#{pid} is no longer running. Maybe it crashed?"
694
717
  end
695
718
  end
696
719
 
720
+ # @return [String]
697
721
  def handle_attr_unsupported *args
698
722
  "#{inspect} does not have a #{args.first.inspect} attribute"
699
723
  end
700
724
 
725
+ # @return [String]
701
726
  def handle_action_unsupported *args
702
727
  "#{inspect} does not have a #{args.first.inspect} action"
703
728
  end
704
729
 
730
+ # @return [String]
705
731
  def handle_notif_unsupported *args
706
732
  "#{inspect} does not support the #{args.first.inspect} notification"
707
733
  end
708
734
 
735
+ # @return [String]
709
736
  def handle_not_implemented *args
710
737
  "The program that owns #{inspect} does not work with AXAPI properly"
711
738
  end
712
739
 
713
740
  # @todo Does this really neeed to raise an exception? Seems
714
741
  # like a warning would be sufficient.
742
+ # @return [String]
715
743
  def handle_notif_registered *args
716
- "You have already registered to hear about #{args[0].inspect} " +
717
- "from #{inspect}"
744
+ "You have already registered to hear about #{args[0].inspect} from #{inspect}"
718
745
  end
719
746
 
747
+ # @return [String]
720
748
  def handle_notif_not_registered *args
721
- "You have not registered to hear about #{args[0].inspect} " +
722
- "from #{inspect}"
749
+ "You have not registered to hear about #{args[0].inspect} from #{inspect}"
723
750
  end
724
751
 
752
+ # @return [String]
725
753
  def handle_api_disabled *args
726
- 'AXAPI has been disabled'
754
+ "AXAPI has been disabled"
727
755
  end
728
756
 
757
+ # @return [String]
729
758
  def handle_param_attr_unsupported *args
730
759
  "#{inspect} does not have a #{args[0].inspect} parameterized attribute"
731
760
  end
732
761
 
762
+ # @return [String]
733
763
  def handle_not_enough_precision
734
764
  'AXAPI said there was not enough precision ¯\(°_o)/¯'
735
765
  end
@@ -738,24 +768,18 @@ module Accessibility::Core
738
768
 
739
769
 
740
770
  ##
741
- # @private
742
- #
743
771
  # `Pointer` type encoding for `CFArrayRef` objects.
744
772
  #
745
773
  # @return [String]
746
774
  ARRAY = '^{__CFArray}'
747
775
 
748
776
  ##
749
- # @private
750
- #
751
777
  # `Pointer` type encoding for `AXUIElementRef` objects.
752
778
  #
753
779
  # @return [String]
754
780
  ELEMENT = '^{__AXUIElement}'
755
781
 
756
782
  ##
757
- # @private
758
- #
759
783
  # `Pointer` type encoding for `AXObserverRef` objects.
760
784
  #
761
785
  # @return [String]
@@ -821,7 +845,7 @@ module Accessibility::ValueUnwrapper
821
845
  end
822
846
  end
823
847
 
824
- # hack to find the proper class
848
+ # hack to find the __NSCFType class
825
849
  klass = AXUIElementCreateSystemWide().class
826
850
  klass.send :include, Accessibility::Core
827
851
  klass.send :include, Accessibility::ValueUnwrapper
@@ -838,7 +862,7 @@ class Boxed
838
862
  #
839
863
  # @return [Number]
840
864
  def self.ax_value
841
- raise NotImplementedError, "#{self.class} cannot be wraped"
865
+ raise NotImplementedError, "#{inspect}:#{self.class} cannot be wraped"
842
866
  end
843
867
 
844
868
  ##
@@ -848,8 +872,8 @@ class Boxed
848
872
  #
849
873
  # @example
850
874
  #
851
- # CGPointMake(12, 34).to_ax # => #<AXValueRef:0x455678e2>
852
- # CGSizeMake(56, 78).to_ax # => #<AXValueRef:0x555678e2>
875
+ # CGPoint.new(12, 34).to_ax # => #<AXValueRef:0x455678e2>
876
+ # CGSize.new(56, 78).to_ax # => #<AXValueRef:0x555678e2>
853
877
  #
854
878
  # @return [AXValueRef]
855
879
  def to_ax
@@ -861,18 +885,34 @@ class Boxed
861
885
  end
862
886
 
863
887
  # AXElements extensions for `CFRange`.
864
- class << CFRange; def ax_value; KAXValueCFRangeType; end end
888
+ class << CFRange
889
+ # (see Boxed.ax_value)
890
+ def ax_value; KAXValueCFRangeType end
891
+ end
865
892
  # AXElements extensions for `CGSize`.
866
- class << CGSize; def ax_value; KAXValueCGSizeType; end end
893
+ class << CGSize
894
+ # (see Boxed.ax_value)
895
+ def ax_value; KAXValueCGSizeType end
896
+ end
867
897
  # AXElements extensions for `CGRect`.
868
- class << CGRect; def ax_value; KAXValueCGRectType; end end
898
+ class << CGRect
899
+ # (see Boxed.ax_value)
900
+ def ax_value; KAXValueCGRectType end
901
+ end
869
902
  # AXElements extensions for `CGPoint`.
870
- class << CGPoint; def ax_value; KAXValueCGPointType; end end
903
+ class << CGPoint
904
+ # (see Boxed.ax_value)
905
+ def ax_value; KAXValueCGPointType end
906
+ end
871
907
 
872
908
 
873
909
  # AXElements extensions for `NSObject`.
874
910
  class NSObject
911
+ ##
912
+ # Return an object safe for passing to AXAPI.
875
913
  def to_ax; self end
914
+ ##
915
+ # Return a usable object from an AXAPI pointer.
876
916
  def to_ruby; self end
877
917
  end
878
918
 
@@ -914,3 +954,20 @@ class CGPoint
914
954
  # @return [CGPoint]
915
955
  def to_point; self end
916
956
  end
957
+
958
+
959
+ ##
960
+ # AXElements extensions for `NSURL`.
961
+ class NSString
962
+ ##
963
+ # Create an NSURL using the receiver as the initialization string.
964
+ # If the receiver is not a valid URL then `nil` will be returned.
965
+ #
966
+ # This exists because of
967
+ # [rdar://11207662](http://openradar.appspot.com/11207662).
968
+ #
969
+ # @return [NSURL,nil]
970
+ def to_url
971
+ NSURL.URLWithString self
972
+ end
973
+ end