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
data/lib/ax/element.rb CHANGED
@@ -1,18 +1,22 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- require 'ax_elements/vendor/inflector'
3
+ require 'accessibility/core'
4
+ require 'accessibility/factory'
5
+ require 'accessibility/translator'
4
6
  require 'accessibility/enumerators'
5
7
  require 'accessibility/qualifier'
6
8
  require 'accessibility/errors'
7
9
  require 'accessibility/pp_inspector'
8
- require 'accessibility/factory'
9
- require 'accessibility/core'
10
10
 
11
11
  ##
12
12
  # @abstract
13
13
  #
14
- # The abstract base class for all accessibility objects. This class
15
- # provides generic functionality that all accessibility objects require.
14
+ # The abstract base class for all accessibility objects. `AX::Element`
15
+ # composes low level `AXUIElementRef` objects into a more Rubyish
16
+ # interface.
17
+ #
18
+ # This abstract base class provides generic functionality that all
19
+ # accessibility objects require.
16
20
  class AX::Element
17
21
  include Accessibility::PPInspector
18
22
  include Accessibility::Factory
@@ -39,10 +43,11 @@ class AX::Element
39
43
  end
40
44
 
41
45
  ##
42
- # @todo Consider returning `nil` if the element does not have
43
- # the given attribute.
44
- #
45
- # Get the value of an attribute.
46
+ # Get the value of an attribute. This method will return `nil` if
47
+ # the attribute does not have a value, if the element does not have
48
+ # the attribute, or if the element is dead. There is an execption
49
+ # for the `:children` attribute which is always guaranteed to return
50
+ # an array.
46
51
  #
47
52
  # @example
48
53
  #
@@ -54,9 +59,12 @@ class AX::Element
54
59
  end
55
60
 
56
61
  ##
57
- # Needed to override inherited `NSObject#description` as some
58
- # elements have a `description` attribute. If you want a description
59
- # of the object then you should use {#inspect} instead.
62
+ # Get the accessibility description for the element.
63
+ #
64
+ # This overrides the inherited `NSObject#description`. If you want a
65
+ # description of the object then you should use {#inspect} instead.
66
+ #
67
+ # @return [String]
60
68
  def description
61
69
  attribute :description
62
70
  end
@@ -71,20 +79,24 @@ class AX::Element
71
79
  end
72
80
 
73
81
  ##
74
- # Return the `#size` of an attribute. This only works for attributes
75
- # that are a collection. This exists because it is _much_ more
76
- # efficient to find out how many `children` exist using this API
77
- # instead of getting the children array and asking for the size.
82
+ # Get a list of elements, starting with the receiver and riding
83
+ # the hierarchy up to the top level object (i.e. the {AX::Application}).
78
84
  #
79
85
  # @example
80
86
  #
81
- # table.size_of :rows # => 111
82
- # window.size_of :children # => 16
87
+ # element = AX::DOCK.list.application_dock_item
88
+ # element.ancestry
89
+ # # => [#<AX::ApplicationDockItem...>, #<AX::List...>, #<AX::Application...>]
83
90
  #
84
- # @param [#to_sym]
85
- # @return [Number]
86
- def size_of attr
87
- @ref.size_of TRANSLATOR.cocoaify attr
91
+ # @return [Array<AX::Element>]
92
+ def ancestry *elements
93
+ elements = [self] if elements.empty?
94
+ element = elements.last
95
+ if element.attributes.include? :parent
96
+ ancestry(elements << element.parent)
97
+ else
98
+ elements
99
+ end
88
100
  end
89
101
 
90
102
  ##
@@ -100,6 +112,23 @@ class AX::Element
100
112
  @ref.pid
101
113
  end
102
114
 
115
+ ##
116
+ # Return the `#size` of an attribute. This only works for attributes
117
+ # that are a collection. This exists because it is _much_ more
118
+ # efficient to find out how many `children` exist using this API
119
+ # instead of getting the children array and asking for the size.
120
+ #
121
+ # @example
122
+ #
123
+ # table.size_of :rows # => 111
124
+ # window.size_of :children # => 16
125
+ #
126
+ # @param [#to_sym]
127
+ # @return [Number]
128
+ def size_of attr
129
+ @ref.size_of TRANSLATOR.cocoaify attr
130
+ end
131
+
103
132
  ##
104
133
  # Check whether or not an attribute is writable.
105
134
  #
@@ -125,7 +154,7 @@ class AX::Element
125
154
  # @return the value that you were setting is returned
126
155
  def set attr, value
127
156
  unless writable? attr
128
- raise NoMethodError, "#{attr} is read-only for #{inspect}"
157
+ raise ArgumentError, "#{attr} is read-only for #{inspect}"
129
158
  end
130
159
  value = value.relative_to(@ref.value.size) if value.kind_of? Range
131
160
  @ref.set TRANSLATOR.cocoaify(attr), value
@@ -153,14 +182,12 @@ class AX::Element
153
182
  #
154
183
  # @example
155
184
  #
156
- # text_field.attribute :string_for_range, for_param: (2..8).relative_to(10)
185
+ # text_field.parameterized_attribute :string_for_range, 2..8
157
186
  #
158
187
  # @param [#to_sym]
159
- def attribute attr, for_parameter: param
160
- if rattr = TRANSLATOR.cocoaify(attr)
161
- param = param.relative_to(@ref.value.size) if value.kind_of? Range
162
- process @ref.attribute(rattr, for_parameter: param)
163
- end
188
+ def parameterized_attribute attr, param
189
+ param = param.relative_to(@ref.value.size) if value.kind_of? Range
190
+ process @ref.parameterized_attribute(TRANSLATOR.cocoaify(attr), param)
164
191
  end
165
192
 
166
193
 
@@ -196,11 +223,7 @@ class AX::Element
196
223
  # @param [#to_sym]
197
224
  # @return [Boolean] true if successful
198
225
  def perform action
199
- if raction = TRANSLATOR.cocoaify(action)
200
- @ref.perform raction
201
- else
202
- false
203
- end
226
+ @ref.perform TRANSLATOR.cocoaify action
204
227
  end
205
228
 
206
229
 
@@ -208,14 +231,15 @@ class AX::Element
208
231
 
209
232
  ##
210
233
  # Perform a breadth first search through the view hierarchy rooted at
211
- # the current element.
234
+ # the current element. If you are concerned about the return value of
235
+ # this method, you can call {#blank?} on the return object.
212
236
  #
213
- # See the {file:docs/Searching.markdown Searching} tutorial for the
214
- # details on searching.
237
+ # See the [Searching Tutorial](http://github.com/Marketcircle/AXElements/wiki/Searching)
238
+ # for the details on search semantics.
215
239
  #
216
240
  # @example Find the dock icon for the Finder app
217
241
  #
218
- # AX::DOCK.search( :application_dock_item, title:'Finder' )
242
+ # AX::DOCK.search(:application_dock_item, title:'Finder')
219
243
  #
220
244
  # @param [#to_s]
221
245
  # @param [Hash{Symbol=>Object}]
@@ -233,7 +257,7 @@ class AX::Element
233
257
  end
234
258
 
235
259
  ##
236
- # Search for an ancestor of the current elemenet.
260
+ # Search for an ancestor of the current element.
237
261
  #
238
262
  # As the opposite of {#search}, this also takes filters, and can
239
263
  # be used to find a specific ancestor for the current element.
@@ -261,22 +285,30 @@ class AX::Element
261
285
  # lookup is always tried first, followed by a parameterized attribute
262
286
  # lookup, and then finally a search.
263
287
  #
264
- # Failing all lookups, this method calls `super`.
288
+ # Failing all lookups, this method calls `super`, which will probably
289
+ # raise an exception; however, most elements have children and so it
290
+ # is more likely that you will get an {Accessibility::SearchFailure}
291
+ # in cases where you sholud get a `NoMethodError`.
265
292
  #
266
293
  # @example
267
294
  #
268
- # mail = AX::Application.application_with_bundle_identifier 'com.apple.mail'
295
+ # mail = Accessibility.application_with_bundle_identifier 'com.apple.mail'
269
296
  #
270
297
  # # attribute lookup
271
298
  # window = mail.focused_window
272
299
  # # is equivalent to
273
300
  # window = mail.attribute :focused_window
274
301
  #
302
+ # # attribute setting
303
+ # window.position = CGPoint.new(100, 100)
304
+ # # is equivalent to
305
+ # window.set :position, CGPoint.new(100, 100)
306
+ #
275
307
  # # parameterized attribute lookup
276
- # window.title_ui_element.string_for_range (1..10).relative_to(100)
308
+ # window.title_ui_element.string_for_range 1..10
277
309
  # # is equivalent to
278
310
  # title = window.attribute :title_ui_element
279
- # title.param_attribute :string_for_range, for_param: (1..10).relative_to(100)
311
+ # title.parameterized_attribute :string_for_range, 1..10
280
312
  #
281
313
  # # simple single element search
282
314
  # window.button # => You want the first Button that is found
@@ -293,7 +325,7 @@ class AX::Element
293
325
  # # is equivalent to
294
326
  # window.search :button, title: 'Log In'
295
327
  #
296
- # # attribute and element search failure
328
+ # # searching from #method_missing will #raise if nothing is found
297
329
  # window.application # => SearchFailure is raised
298
330
  #
299
331
  def method_missing method, *args, &block
@@ -301,10 +333,10 @@ class AX::Element
301
333
 
302
334
  key = TRANSLATOR.cocoaify method
303
335
  if @ref.attributes.include? key
304
- return attribute method
336
+ return attribute(method)
305
337
 
306
338
  elsif @ref.parameterized_attributes.include? key
307
- return attribute(method, for_parameter: args.first)
339
+ return paramaterized_attribute(method, args.first)
308
340
 
309
341
  elsif @ref.attributes.include? KAXChildrenAttribute
310
342
  if (result = search(method, *args, &block)).blank?
@@ -319,78 +351,11 @@ class AX::Element
319
351
  end
320
352
  end
321
353
 
322
-
323
- # @group Notifications
324
-
325
- def notifs
326
- @notifs ||= {}
327
- end
328
-
329
- ##
330
- # Register to receive notification of the given event being completed
331
- # by the given element.
332
- #
333
- # {file:docs/Notifications.markdown Notifications} are a way to put
334
- # non-polling delays into your scripts.
335
- #
336
- # Use this method to register to be notified of the specified event in
337
- # an application.
338
- #
339
- # The block is optional. The block will be given the sender of the
340
- # notification, which will almost always be `self`, and also the name
341
- # of the notification being received. The block should return a
342
- # boolean value that decides if the notification received is the
343
- # expected one.
344
- #
345
- # @example
346
- #
347
- # on_notification(:window_created) { |sender|
348
- # puts "#{sender.inspect} sent the ':window_created' notification"
349
- # true
350
- # }
351
- #
352
- # @param [#to_s] notif the name of the notification
353
- # @yield Validate the notification; the block should return truthy if
354
- # the notification received is the expected one and the script can
355
- # stop waiting, otherwise should return falsy.
356
- # @yieldparam [String] notif the name of the notification
357
- # @yieldparam [AXUIElementRef] element the element that sent the notification
358
- # @yieldreturn [Boolean]
359
- # @return [Array(Observer, String, CFRunLoopSource)]
360
- def on_notification name, &block
361
- notif = TRANSLATOR.guess_notification name
362
- observer = @ref.observer &notif_callback_for(&block)
363
- source = @ref.run_loop_source_for observer
364
- @ref.register observer, to_receive: notif
365
- CFRunLoopAddSource(CFRunLoopGetCurrent(), source, KCFRunLoopDefaultMode)
366
- notifs[name] = [observer, notif, source]
367
- end
368
-
369
- def unregister_notification name
370
- unless notifs.has_key? name
371
- raise ArgumentError, "You have no registrations for #{name}"
372
- end
373
- _unregister_notification *notifs.delete(name)
374
- end
375
-
376
- ##
377
- # Cancel _all_ notification registrations for this object. Simple and
378
- # clean, but a blunt tool at best. This will have to do for the time
379
- # being...
380
- #
381
- # @return [nil]
382
- def unregister_all
383
- notifs.keys.each do |notif|
384
- unregister_notification notif
385
- end
386
- nil
387
- end
388
-
389
354
  # @endgroup
390
355
 
391
356
 
392
357
  ##
393
- # Overriden to produce cleaner output.
358
+ # Get relevant details about the current object.
394
359
  #
395
360
  # @return [String]
396
361
  def inspect
@@ -413,6 +378,25 @@ class AX::Element
413
378
  inspect
414
379
  end
415
380
 
381
+ ##
382
+ # Get the relevant details about the receiver and also the children
383
+ # and further descendents of the receiver. Each generation down the
384
+ # tree will be indented one level further.
385
+ #
386
+ # @example
387
+ #
388
+ # puts app.inspect_subtree
389
+ #
390
+ # @return [String]
391
+ def inspect_subtree
392
+ output = self.inspect + "\n"
393
+ enum = Accessibility::Enumerators::DepthFirst.new self
394
+ enum.each_with_level do |element, depth|
395
+ output << "\t"*depth + element.inspect + "\n"
396
+ end
397
+ output
398
+ end
399
+
416
400
  ##
417
401
  # Overriden to respond properly with regards to dynamic attribute
418
402
  # lookups, but will return false for potential implicit searches.
@@ -430,22 +414,22 @@ class AX::Element
430
414
  #
431
415
  # @return [CGPoint]
432
416
  def to_point
433
- size = attribute :size
434
- point = attribute :position
417
+ size = attribute :size
418
+ point = attribute :position
435
419
  point.x += size.width / 2
436
420
  point.y += size.height / 2
437
421
  point
438
422
  end
423
+ alias_method :hitpoint, :to_point
439
424
 
440
425
  ##
441
426
  # Get the bounding rectangle for the element.
442
427
  #
443
428
  # @return [CGRect]
444
429
  def bounds
445
- point = attribute :position
446
- size = attribute :size
447
- CGRectMake(*point, *size)
430
+ CGRect.new(attribute(:position), attribute(:size))
448
431
  end
432
+ alias_method :rect, :bounds
449
433
 
450
434
  ##
451
435
  # Get the application object for the element.
@@ -455,24 +439,31 @@ class AX::Element
455
439
  process @ref.application
456
440
  end
457
441
 
458
- ##
459
- # Concept borrowed from `Active Support`. It is used during implicit
460
- # searches to determine if searches yielded responses.
442
+ # (see NilClass#blank?)
461
443
  def blank?
462
444
  false
463
445
  end
464
446
 
465
447
  ##
466
- # @todo Need to add '?' to predicate methods, but how?
448
+ # Return whether or not the receiver is "dead".
467
449
  #
450
+ # A dead element is one that is no longer in the app's view
451
+ # hierarchy, which is not necessarily related to visibility.
452
+ def invalid?
453
+ @ref.role.nil?
454
+ end
455
+
456
+ ##
468
457
  # Like {#respond_to?}, this is overriden to include attribute methods.
458
+ # Though, it does include dynamic predicate methods at the moment.
469
459
  def methods include_super = true, include_objc_super = false
470
460
  super.concat(attributes).concat(parameterized_attributes)
471
461
  end
472
462
 
473
463
  ##
474
- # Overridden so that equality testing would work. A hack, but the only
475
- # sane way I can think of to test for equivalency.
464
+ # Overridden so that equality testing would work.
465
+ #
466
+ # A hack, but the only sane way I can think of to test for equivalency.
476
467
  def == other
477
468
  @ref == other.instance_variable_get(:@ref)
478
469
  end
@@ -482,36 +473,29 @@ class AX::Element
482
473
 
483
474
  private
484
475
 
485
- ##
486
476
  # @private
487
- #
488
- # Performance hack.
489
- #
490
477
  # @return [String]
491
478
  EQUALS = '='
492
479
 
493
- def notif_callback_for
494
- # we are ignoring the context pointer since this is OO
495
- Proc.new do |observer, sender, notif, _|
496
- break unless yield(process sender) if block_given?
497
- _unregister_notification observer, notif, run_loop_source_for(observer)
498
- CFRunLoopStop(CFRunLoopGetCurrent())
499
- end
500
- end
480
+ end
481
+
501
482
 
483
+ # Extensions so checking `#blank?` on search result "just works".
484
+ class NSArray
485
+ # (see NilClass#blank?)
486
+ alias_method :blank?, :empty?
487
+ end
488
+
489
+ # Extensions so checking `#blank?` on search result "just works".
490
+ class NilClass
502
491
  ##
503
- # @todo What are the implications of removing the run loop source?
504
- # Taking it out would clobber other notifications that are using
505
- # the same source, so we would have to check if we can remove it.
492
+ # Whether or not the object is "blank". The concept of blankness
493
+ # borrowed from `Active Support` and is true if the object is falsey
494
+ # or `#empty?`.
506
495
  #
507
- def _unregister_notification observer, notif, source
508
- CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, KCFRunLoopDefaultMode)
509
- @ref.unregister observer, from_receiving: notif
496
+ # This method is used by implicit searching in AXElements to
497
+ # determine if searches yielded responses.
498
+ def blank?
499
+ true
510
500
  end
511
-
512
501
  end
513
-
514
-
515
- # Extensions so checking #blank? on search result "just works".
516
- class NSArray; alias_method :blank?, :empty? end
517
- class NilClass; def blank?; true end end
@@ -0,0 +1,12 @@
1
+ require 'ax/element'
2
+
3
+ ##
4
+ # UI Element for pop up buttons.
5
+ class AX::PopUpButton < AX::Element
6
+ end
7
+
8
+ ##
9
+ # An alias for {AX::PopUpButton}.
10
+ #
11
+ # @return [Class]
12
+ AX::PopUp = AX::PopUpButton
@@ -13,8 +13,11 @@ class AX::RadioButton < AX::Element
13
13
  #
14
14
  # @return [Boolean]
15
15
  def == other
16
- return attribute(:title) == other if other.kind_of? NSString
17
- return super
16
+ if other.kind_of? NSString
17
+ attribute(:title) == other
18
+ else
19
+ super
20
+ end
18
21
  end
19
22
 
20
23
  end
data/lib/ax/row.rb CHANGED
@@ -2,13 +2,13 @@ require 'ax/element'
2
2
  require 'accessibility/qualifier'
3
3
 
4
4
  ##
5
- # UI Element for the row in a table, outline, etc.
5
+ # UI Element for the row in a table, outline view, etc.
6
6
  class AX::Row < AX::Element
7
7
 
8
8
  ##
9
9
  # Retrieve the child in a row that corresponds to a specific column.
10
10
  # You must pass filters here in the same way that you would for a
11
- # search.
11
+ # search or wait.
12
12
  #
13
13
  # This is useful for tables where it is difficult to identify which
14
14
  # row item is the one you want based on the row items themselves.
@@ -12,8 +12,11 @@ class AX::StaticText < AX::Element
12
12
  #
13
13
  # @return [Boolean]
14
14
  def == other
15
- return super unless other.kind_of? NSString
16
- return attribute(:value) == other
15
+ if other.kind_of? NSString
16
+ attribute(:value) == other
17
+ else
18
+ super
19
+ end
17
20
  end
18
21
 
19
22
  end
data/lib/ax/systemwide.rb CHANGED
@@ -23,25 +23,37 @@ class AX::SystemWide < AX::Element
23
23
  #
24
24
  # Generate keyboard events by simulating keyboard input.
25
25
  #
26
- # See the {file:docs/KeyboardEvents.markdown Keyboard} documentation for
27
- # more information on how to format strings.
26
+ # See the
27
+ # [Keyboarding documentation](http://github.com/Marketcircle/AXElements/wiki/Keyboarding)
28
+ # for more information on how to format strings.
28
29
  #
29
30
  # @return [Boolean]
30
31
  def type string
31
32
  @ref.post keyboard_events_for string
32
33
  true
33
34
  end
35
+ alias_method :type_string, :type
34
36
 
35
- # @todo doc and cleanup
36
- def keydown modifier
37
- @ref.post [[EventGenerator::CUSTOM[modifier], true]]
38
- true
39
- end
40
-
41
- # @todo doc and cleanup
42
- def keyup modifier
43
- @ref.post [[EventGenerator::CUSTOM[modifier], false]]
44
- true
37
+ ##
38
+ # Press the given modifier key and hold it down while yielding to the
39
+ # given block.
40
+ #
41
+ # @example
42
+ #
43
+ # hold_key "\\CONTROL" do
44
+ # drag_mouse_to point
45
+ # end
46
+ #
47
+ # @param [String]
48
+ # @return [Number,nil]
49
+ def hold_modifier key
50
+ code = EventGenerator::CUSTOM[key]
51
+ raise ArgumentError, "Invalid modifier `#{key}' given" unless code
52
+ @ref.post [[code, true]]
53
+ yield
54
+ ensure # if block raises the button might stuck, so ensure it is released
55
+ @ref.post [[code,false]] if code
56
+ code
45
57
  end
46
58
 
47
59
  ##
@@ -1,12 +1,21 @@
1
1
  require 'awesome_print'
2
2
 
3
+ ##
4
+ # `AwesomePrint` extension for AXElements.
3
5
  module AwesomePrint::AXElements
4
6
 
7
+ ##
8
+ # Perform the silly `alias_method_chain` stuff that AwesomePrint
9
+ # expects.
5
10
  def self.included base
6
11
  base.send :alias_method, :cast_without_ax_elements, :cast
7
12
  base.send :alias_method, :cast, :cast_with_ax_elements
8
13
  end
9
14
 
15
+ ##
16
+ # Format {AX::Element} objects for AwesomePrint. For the time
17
+ # being, just work-around the default AwesomePrint output by
18
+ # using the default `#inpspect` for {AX::Element}.
10
19
  def cast_with_ax_elements object, type
11
20
  cast = cast_without_ax_elements object, type
12
21
  cast = :ax_element if object.kind_of? ::AX::Element
@@ -16,6 +25,10 @@ module AwesomePrint::AXElements
16
25
 
17
26
  private
18
27
 
28
+ ##
29
+ # Give the awesome output for an {AX::Element} object.
30
+ #
31
+ # @return [String]
19
32
  def awesome_ax_element object
20
33
  object.inspect
21
34
  end
@@ -2,6 +2,11 @@
2
2
  # Workaround for MacRuby ticket #1334
3
3
  class Exception
4
4
  alias_method :original_message, :message
5
+ #
6
+ # Override the message method to force the backtrace to be
7
+ # included.
8
+ #
9
+ # @return [String]
5
10
  def message
6
11
  "#{original_message}\n\t#{backtrace.join("\n\t")}"
7
12
  end
@@ -53,6 +53,7 @@ module Accessibility::NSArrayCompat
53
53
  private
54
54
 
55
55
  # @private
56
+ # @return [Accessibility::Translator]
56
57
  TRANSLATOR = Accessibility::Translator.instance
57
58
 
58
59
  end
data/lib/ax_elements.rb CHANGED
@@ -6,13 +6,14 @@ include Accessibility::DSL
6
6
  # The Mac OS X dock application.
7
7
  #
8
8
  # @return [AX::Application]
9
- AX::DOCK = app_with_bundle_identifier 'com.apple.dock'
9
+ AX::DOCK = AX::Application.new('com.apple.dock')
10
10
 
11
11
  # Load explicitly defined elements that are optional
12
12
  require 'ax/button'
13
13
  require 'ax/radio_button'
14
14
  require 'ax/row'
15
15
  require 'ax/static_text'
16
+ require 'ax/pop_up_button'
16
17
 
17
18
  # Misc things that we need to load
18
19
  require 'ax_elements/nsarray_compat'