AXElements 0.6.0beta2 → 0.7.5

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 (107) hide show
  1. data/.yardopts +1 -2
  2. data/README.markdown +152 -88
  3. data/Rakefile +8 -103
  4. data/docs/Debugging.markdown +9 -2
  5. data/docs/KeyboardEvents.markdown +114 -49
  6. data/docs/Setting.markdown +1 -0
  7. data/docs/images/next_version.png +0 -0
  8. data/ext/accessibility/key_coder/extconf.rb +22 -0
  9. data/ext/accessibility/key_coder/key_coder.c +113 -0
  10. data/lib/AXElements.rb +2 -0
  11. data/lib/accessibility/core.rb +897 -0
  12. data/lib/accessibility/debug.rb +168 -0
  13. data/lib/accessibility/dsl.rb +697 -0
  14. data/lib/accessibility/enumerators.rb +104 -0
  15. data/lib/accessibility/errors.rb +32 -0
  16. data/lib/accessibility/factory.rb +153 -0
  17. data/lib/accessibility/graph.rb +150 -0
  18. data/lib/{ax_elements/inspector.rb → accessibility/pp_inspector.rb} +39 -28
  19. data/lib/accessibility/qualifier.rb +158 -0
  20. data/lib/accessibility/string.rb +494 -0
  21. data/lib/accessibility/translator.rb +178 -0
  22. data/lib/accessibility/version.rb +7 -0
  23. data/lib/accessibility.rb +79 -0
  24. data/lib/ax/application.rb +234 -0
  25. data/lib/{ax_elements/elements → ax}/button.rb +2 -0
  26. data/lib/ax/element.rb +518 -0
  27. data/lib/{ax_elements/elements → ax}/radio_button.rb +2 -0
  28. data/lib/ax/row.rb +37 -0
  29. data/lib/{ax_elements/elements → ax}/static_text.rb +2 -0
  30. data/lib/ax/systemwide.rb +86 -0
  31. data/lib/ax_elements/awesome_print.rb +25 -0
  32. data/lib/ax_elements/exception_workaround.rb +8 -0
  33. data/lib/ax_elements/nsarray_compat.rb +64 -0
  34. data/lib/ax_elements/vendor/inflection_data.rb +65 -0
  35. data/lib/ax_elements/vendor/inflections.rb +172 -0
  36. data/lib/ax_elements/vendor/inflector.rb +306 -0
  37. data/lib/ax_elements.rb +14 -25
  38. data/lib/minitest/ax_elements.rb +112 -12
  39. data/lib/mouse.rb +72 -46
  40. data/lib/rspec/expectations/ax_elements.rb +133 -6
  41. data/rakelib/doc.rake +13 -0
  42. data/rakelib/ext.rake +61 -0
  43. data/rakelib/gem.rake +28 -0
  44. data/rakelib/test.rake +53 -0
  45. data/test/helper.rb +11 -97
  46. data/test/integration/accessibility/test_core.rb +18 -0
  47. data/test/integration/accessibility/test_debug.rb +44 -0
  48. data/test/integration/accessibility/test_dsl.rb +225 -0
  49. data/test/integration/accessibility/test_enumerators.rb +122 -0
  50. data/test/integration/accessibility/test_errors.rb +38 -0
  51. data/test/integration/accessibility/test_notifications.rb +22 -0
  52. data/test/integration/accessibility/test_qualifier.rb +148 -0
  53. data/test/integration/ax/test_application.rb +56 -0
  54. data/test/integration/ax/test_element.rb +46 -0
  55. data/test/integration/ax/test_row.rb +23 -0
  56. data/test/integration/ax_elements/test_nsarray_compat.rb +43 -0
  57. data/test/integration/minitest/test_ax_elements.rb +98 -0
  58. data/test/integration/rspec/expectations/test_ax_elements.rb +58 -0
  59. data/test/integration/test_mouse.rb +35 -0
  60. data/test/sanity/accessibility/test_core.rb +553 -0
  61. data/test/sanity/accessibility/test_debug.rb +63 -0
  62. data/test/sanity/accessibility/test_dsl.rb +75 -0
  63. data/test/sanity/accessibility/test_errors.rb +10 -0
  64. data/test/sanity/accessibility/test_factory.rb +88 -0
  65. data/test/sanity/accessibility/test_pp_inspector.rb +110 -0
  66. data/test/sanity/accessibility/test_qualifier.rb +13 -0
  67. data/test/sanity/accessibility/test_string.rb +238 -0
  68. data/test/sanity/accessibility/test_translator.rb +145 -0
  69. data/test/sanity/ax/test_application.rb +90 -0
  70. data/test/sanity/ax/test_element.rb +80 -0
  71. data/test/sanity/ax/test_systemwide.rb +66 -0
  72. data/test/sanity/ax_elements/test_nsarray_compat.rb +16 -0
  73. data/test/sanity/ax_elements/test_nsobject_inspect.rb +11 -0
  74. data/test/sanity/minitest/test_ax_elements.rb +15 -0
  75. data/test/sanity/rspec/expectations/test_ax_elements.rb +12 -0
  76. data/test/sanity/test_ax_elements.rb +10 -0
  77. data/test/sanity/test_mouse.rb +19 -0
  78. metadata +111 -93
  79. data/LICENSE.txt +0 -25
  80. data/ext/key_coder/extconf.rb +0 -6
  81. data/ext/key_coder/key_coder.m +0 -77
  82. data/lib/ax_elements/accessibility/enumerators.rb +0 -104
  83. data/lib/ax_elements/accessibility/graph.rb +0 -118
  84. data/lib/ax_elements/accessibility/language.rb +0 -347
  85. data/lib/ax_elements/accessibility/qualifier.rb +0 -73
  86. data/lib/ax_elements/accessibility.rb +0 -166
  87. data/lib/ax_elements/core.rb +0 -541
  88. data/lib/ax_elements/element.rb +0 -593
  89. data/lib/ax_elements/elements/application.rb +0 -88
  90. data/lib/ax_elements/elements/row.rb +0 -30
  91. data/lib/ax_elements/elements/systemwide.rb +0 -46
  92. data/lib/ax_elements/macruby_extensions.rb +0 -255
  93. data/lib/ax_elements/notification.rb +0 -37
  94. data/lib/ax_elements/version.rb +0 -9
  95. data/test/elements/test_application.rb +0 -72
  96. data/test/elements/test_row.rb +0 -27
  97. data/test/elements/test_systemwide.rb +0 -38
  98. data/test/test_accessibility.rb +0 -127
  99. data/test/test_blankness.rb +0 -26
  100. data/test/test_core.rb +0 -448
  101. data/test/test_element.rb +0 -939
  102. data/test/test_enumerators.rb +0 -81
  103. data/test/test_inspector.rb +0 -130
  104. data/test/test_language.rb +0 -157
  105. data/test/test_macruby_extensions.rb +0 -303
  106. data/test/test_mouse.rb +0 -5
  107. data/test/test_search_semantics.rb +0 -143
@@ -1,19 +1,119 @@
1
+ require 'ax/element'
2
+ require 'accessibility/qualifier'
3
+
1
4
  ##
2
- #
3
- class MiniTest::Unit::TestCase
4
- # @yield
5
- def assert_exists
6
- begin
7
- yield.blank?
8
- # blank? if nothing found, kind_of Element otherwise
9
- rescue AX::Element::SearchFailure => e
10
- # problem somewhere in the path
11
- end
12
- assert_respond_to
5
+ # AXElements assertions for MiniTest.
6
+ # [Learn more about minitest.](https://github.com/seattlerb/minitest)
7
+ class MiniTest::Assertions
8
+
9
+ ##
10
+ # Test that an element has a specific child. For example, test
11
+ # that a table has a row with certain contents. You can pass any
12
+ # filters that you normally would during a search, including a block.
13
+ #
14
+ # @example
15
+ #
16
+ # assert_has_child table, :row, static_text: { value: 'Mark' }
17
+ #
18
+ # @param [AX::Element]
19
+ # @param [#to_s]
20
+ # @param [Hash]
21
+ # @return [AX::Element]
22
+ def assert_has_child parent, kind, filters = {}, &block
23
+ msg = message {
24
+ child = ax_search_id kind, filters, block
25
+ "Expected #{parent.inspect} to have #{child} as a child"
26
+ }
27
+ result = ax_check_children parent, kind, filters, block
28
+ refute result.blank?, msg
29
+ result
30
+ end
31
+
32
+ ##
33
+ # Test that an element has a specifc descendent. For example, test
34
+ # that a window contains a specific label. You can pass any filters
35
+ # that you normally would during a search, including a block.
36
+ #
37
+ # @example
38
+ #
39
+ # assert_has_descendent window, :static_text, value: /Cake/
40
+ #
41
+ # @param [AX::Element]
42
+ # @param [#to_s]
43
+ # @param [Hash]
44
+ # @return [AX::Element]
45
+ def assert_has_descendent ancestor, kind, filters = {}, &block
46
+ msg = message {
47
+ descendent = ax_search_id kind, filters, block
48
+ "Expected #{ancestor.inspect} to have #{descendent} as a descendent"
49
+ }
50
+ result = ax_check_descendent ancestor, kind, filters, block
51
+ refute result.blank?, msg
52
+ result
13
53
  end
54
+ alias_method :assert_has_descendant, :assert_has_descendent
14
55
 
15
- def refute_exists
56
+ ##
57
+ # Test that an element _does not_ have a specific child. For example,
58
+ # test that a row is no longer in a table. You can pass any filters
59
+ # that you normally would during a search, including a block.
60
+ #
61
+ # @example
62
+ #
63
+ # refute_has_child table, :row, id: 'MyRow'
64
+ #
65
+ # @param [AX::Element]
66
+ # @param [#to_s]
67
+ # @param [Hash]
68
+ # @return [nil]
69
+ def refute_has_child parent, kind, filters = {}, &block
70
+ result = ax_check_children parent, kind, filters, block
71
+ msg = message {
72
+ "Expected #{parent.inspect} not to have #{result} as a child"
73
+ }
74
+ assert result.blank?, msg
75
+ result
16
76
  end
77
+
78
+ ##
79
+ # Test that an element _does not_ have a specific descendent. For
80
+ # example, test that a window does not contain a spinning progress
81
+ # indicator anymore.
82
+ #
83
+ # @example
84
+ #
85
+ # refute_has_descendent window, :busy_indicator
86
+ #
87
+ # @param [AX::Element]
88
+ # @param [#to_s]
89
+ # @param [Hash]
90
+ # @return [nil,Array()]
91
+ def refute_has_descendent ancestor, kind, filters = {}, &block
92
+ result = ax_check_descendent ancestor, kind, filters, block
93
+ msg = message {
94
+ "Expected #{ancestor.inspect} not to have #{result} as a descendent"
95
+ }
96
+ assert result.blank?, msg
97
+ result
98
+ end
99
+ alias_method :refute_has_descendant, :refute_has_descendent
100
+
101
+
102
+ private
103
+
104
+ def ax_search_id kind, filters, block
105
+ Accessibility::Qualifier.new(kind, filters, &block).describe
106
+ end
107
+
108
+ def ax_check_children parent, kind, filters, block
109
+ q = Accessibility::Qualifier.new(kind, filters, &block)
110
+ parent.attribute(:children).find { |x| q.qualifies? x }
111
+ end
112
+
113
+ def ax_check_descendent ancestor, kind, filters, block
114
+ ancestor.search(kind, filters, &block)
115
+ end
116
+
17
117
  end
18
118
 
19
119
  # @todo assertions for minitest/spec
data/lib/mouse.rb CHANGED
@@ -1,16 +1,16 @@
1
+ framework 'ApplicationServices'
2
+
1
3
  ##
2
4
  # [Reference](http://developer.apple.com/library/mac/#documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html).
3
5
  #
4
6
  # @todo Inertial scrolling
5
7
  # @todo Bezier paths
6
8
  # @todo More intelligent default duration
7
- # @todo Point arguments should accept a pair tuple...or should they?
8
9
  # @todo Refactor to try and reuse the same event for a single action
9
10
  # instead of creating new events.
10
11
  # @todo Pause between down/up clicks
11
- module Mouse; end
12
-
13
- class << Mouse
12
+ module Mouse
13
+ extend self
14
14
 
15
15
  ##
16
16
  # Number of animation steps per second.
@@ -60,11 +60,11 @@ class << Mouse
60
60
  # @param [CGPoint]
61
61
  # @param [Float] duration animation duration, in seconds
62
62
  def drag_to point, duration = 0.2
63
- event = CGEventCreateMouseEvent(nil, KCGEventLeftMouseDown, current_position, KCGMouseButtonLeft)
64
- CGEventPost(KCGHIDEventTap, event)
63
+ post new_event(KCGEventLeftMouseDown, current_position, KCGMouseButtonLeft)
64
+
65
65
  animate KCGEventLeftMouseDragged, KCGMouseButtonLeft, current_position, point, duration
66
- event = CGEventCreateMouseEvent(nil, KCGEventLeftMouseUp, current_position, KCGMouseButtonLeft)
67
- CGEventPost(KCGHIDEventTap, event)
66
+
67
+ post new_event(KCGEventLeftMouseUp, current_position, KCGMouseButtonLeft)
68
68
  end
69
69
 
70
70
  ##
@@ -78,18 +78,15 @@ class << Mouse
78
78
  # @param [Fixnum] amount number of units to scroll; positive to scroll
79
79
  # up or negative to scroll down
80
80
  # @param [Float] duration animation duration, in seconds
81
- # @param [Fixnum] units `:line` scrolls by line, `:pixel` scrolls by pixel
81
+ # @param [Symbol] units `:line` scrolls by line, `:pixel` scrolls by pixel
82
82
  def scroll amount, duration = 0.2, units = :line
83
83
  units = UNIT[units] || raise(ArgumentError, "#{units} is not a valid unit")
84
- steps = (FPS * duration).floor
84
+ steps = (FPS * duration).round
85
85
  current = 0.0
86
86
  steps.times do |step|
87
87
  done = (step+1).to_f / steps
88
88
  scroll = ((done - current)*amount).floor
89
- # the fixnum arg represents the number of scroll wheels
90
- # on the mouse we are simulating (up to 3)
91
- event = CGEventCreateScrollWheelEvent(nil, units, 1, scroll)
92
- CGEventPost(KCGHIDEventTap, event)
89
+ post new_scroll_event(units, 1, scroll)
93
90
  sleep QUANTUM
94
91
  current += scroll.to_f / amount
95
92
  end
@@ -99,24 +96,24 @@ class << Mouse
99
96
  # A standard click. Default position is the current position.
100
97
  #
101
98
  # @param [CGPoint]
102
- def click point = current_position
103
- event = CGEventCreateMouseEvent(nil, KCGEventLeftMouseDown, point, KCGMouseButtonLeft)
104
- CGEventPost(KCGHIDEventTap, event)
105
- # @todo Should not set number of sleep frames statically.
106
- 12.times do sleep QUANTUM end
107
- CGEventSetType(event, KCGEventLeftMouseUp)
108
- CGEventPost(KCGHIDEventTap, event)
99
+ def click point = current_position, duration = 12
100
+ event = new_event KCGEventLeftMouseDown, point, KCGMouseButtonLeft
101
+ post event
102
+ duration.times { sleep QUANTUM }
103
+ set event, to: KCGEventLeftMouseUp
104
+ post event
109
105
  end
110
106
 
111
107
  ##
112
108
  # Standard secondary click. Default position is the current position.
113
109
  #
114
110
  # @param [CGPoint]
115
- def secondary_click point = current_position
116
- event = CGEventCreateMouseEvent(nil, KCGEventRightMouseDown, point, KCGMouseButtonRight)
117
- CGEventPost(KCGHIDEventTap, event)
118
- CGEventSetType(event, KCGEventRightMouseUp)
119
- CGEventPost(KCGHIDEventTap, event)
111
+ def secondary_click point = current_position, duration = 12
112
+ event = new_event KCGEventRightMouseDown, point, KCGMouseButtonRight
113
+ post event
114
+ duration.times { sleep QUANTUM }
115
+ set event, to: KCGEventRightMouseUp
116
+ post event
120
117
  end
121
118
  alias_method :right_click, :secondary_click
122
119
 
@@ -125,16 +122,16 @@ class << Mouse
125
122
  #
126
123
  # @param [CGPoint]
127
124
  def double_click point = current_position
128
- event = CGEventCreateMouseEvent(nil, KCGEventLeftMouseDown, point, KCGMouseButtonLeft)
129
- CGEventPost(KCGHIDEventTap, event)
130
- CGEventSetType(event, KCGEventLeftMouseUp)
131
- CGEventPost(KCGHIDEventTap, event)
125
+ event = new_event KCGEventLeftMouseDown, point, KCGMouseButtonLeft
126
+ post event
127
+ set event, to: KCGEventLeftMouseUp
128
+ post event
132
129
 
133
130
  CGEventSetIntegerValueField(event, KCGMouseEventClickState, 2)
134
- CGEventSetType(event, KCGEventLeftMouseDown)
135
- CGEventPost(KCGHIDEventTap, event)
136
- CGEventSetType(event, KCGEventLeftMouseUp)
137
- CGEventPost(KCGHIDEventTap, event)
131
+ set event, to: KCGEventLeftMouseDown
132
+ post event
133
+ set event, to: KCGEventLeftMouseUp
134
+ post event
138
135
  end
139
136
 
140
137
  ##
@@ -151,9 +148,10 @@ class << Mouse
151
148
  #
152
149
  # @param [CGPoint]
153
150
  # @param [Number]
154
- def arbitrary_click point = current_position, button = KCGMouseButtonCenter
151
+ def arbitrary_click point = current_position, button = KCGMouseButtonCenter, duration = 12
155
152
  event = CGEventCreateMouseEvent(nil, KCGEventOtherMouseDown, point, button)
156
153
  CGEventPost(KCGHIDEventTap, event)
154
+ duration.times do sleep QUANTUM end
157
155
  CGEventSetType(event, KCGEventOtherMouseUp)
158
156
  CGEventPost(KCGHIDEventTap, event)
159
157
  end
@@ -166,20 +164,48 @@ class << Mouse
166
164
  # Executes a mouse movement animation. It can be a simple cursor
167
165
  # move or a drag depending on what is passed to `type`.
168
166
  def animate type, button, from, to, duration
169
- steps = (FPS * duration).floor
170
- xstep = (to.x - from.x) / steps
171
- ystep = (to.y - from.y) / steps
172
- steps.times do
173
- from.x += xstep
174
- from.y += ystep
175
- event = CGEventCreateMouseEvent(nil, type, from, button)
176
- CGEventPost(KCGHIDEventTap, event)
167
+ current = current_position
168
+ xstep = (to.x - current.x) / (FPS * duration)
169
+ ystep = (to.y - current.y) / (FPS * duration)
170
+ start = NSDate.date
171
+
172
+ until close_enough?(current, to)
173
+ remaining = to.x - current.x
174
+ current.x += xstep.abs > remaining.abs ? remaining : xstep
175
+
176
+ remaining = to.y - current.y
177
+ current.y += ystep.abs > remaining.abs ? remaining : ystep
178
+
179
+ post new_event(type, current, button)
180
+
177
181
  sleep QUANTUM
182
+ break if NSDate.date.timeIntervalSinceDate(start) > 5.0
183
+ current = current_position
178
184
  end
179
- $stderr.puts 'Not moving anywhere' if from == to
180
- event = CGEventCreateMouseEvent(nil, type, to, button)
185
+ end
186
+
187
+ def close_enough? current, target
188
+ x = current.x - target.x
189
+ y = current.y - target.y
190
+ delta = Math.sqrt((x**2) + (y**2))
191
+ delta <= 1.0
192
+ end
193
+
194
+ def new_event event, position, button
195
+ CGEventCreateMouseEvent(nil, event, position, button)
196
+ end
197
+
198
+ # @param [Fixnum] wheel which scroll wheel to use (value between 1-3)
199
+ def new_scroll_event units, wheel, amount
200
+ CGEventCreateScrollWheelEvent(nil, units, wheel, amount)
201
+ end
202
+
203
+ def post event
181
204
  CGEventPost(KCGHIDEventTap, event)
182
- sleep QUANTUM
205
+ end
206
+
207
+ def set event, to: state
208
+ CGEventSetType(event, state)
183
209
  end
184
210
 
185
211
  end
@@ -1,15 +1,142 @@
1
- require 'rspec/expectations'
1
+ require 'accessibility/qualifier'
2
+ require 'ax/element'
2
3
 
3
4
  ##
4
- # Custom RSpec matchers for AXElements.
5
- module RSpec::Expectations
5
+ # Custom matcher for RSpec to check if an element has the specified
6
+ # child element.
7
+ class Accessibility::HasChildMatcher
8
+
9
+ # @param [#to_s]
10
+ # @param [Hash]
11
+ # @yield
12
+ def initialize kind, filters, &block
13
+ @qualifier = Accessibility::Qualifier.new(kind, filters, &block)
14
+ end
15
+
16
+ # @param [AX::Element]
17
+ def matches? parent
18
+ !search(parent).blank?
19
+ end
20
+
21
+ # @return [String]
22
+ def failure_message_for_should
23
+ "Expected #@parent to have child #{@qualifier.describe}"
24
+ end
25
+
26
+ # @param [AX::Element]
27
+ def does_not_match? parent
28
+ search(parent).blank?
29
+ end
30
+
31
+ # @return [String]
32
+ def failure_message_for_should_not
33
+ "Expected #@parent to NOT have child #@result"
34
+ end
35
+
36
+ ##
37
+ # Implemented to override `NSObject#description`.
38
+ #
39
+ # @return [String]
40
+ def description
41
+ "should have a child that matches #{@qualifier.describe}"
42
+ end
43
+
44
+
45
+ private
46
+
47
+ def search parent
48
+ @parent = parent
49
+ @result = parent.attribute(:children).find { |x| @qualifier.qualifies? x }
50
+ end
51
+
52
+ end
53
+
54
+ ##
55
+ # Assert that the receiving element has the specified child element. You
56
+ # can use any filters you would normally use in a search, including
57
+ # a block.
58
+ #
59
+ # @example
60
+ #
61
+ # window.toolbar.should have_child(:search_field)
62
+ # table.should have_child(:row, static_text: { value: /42/ })
63
+ #
64
+ # search_field.should_not have_child(:busy_indicator)
65
+ #
66
+ # @param [#to_s]
67
+ # @param [Hash]
68
+ # @yield An optional block to be used as part of the search qualifier
69
+ def have_child kind, filters = {}, &block
70
+ Accessibility::HasChildMatcher.new kind, filters, &block
71
+ end
72
+
73
+
74
+ ##
75
+ # Custom matcher for RSpec to check if an element has the specified
76
+ # descendent element.
77
+ class Accessibility::HasDescendentMatcher
78
+
79
+ # @param [#to_s]
80
+ # @param [Hash]
81
+ # @yield
82
+ def initialize kind, filters, &block
83
+ @kind, @filters, @block = kind, filters, block
84
+ @qualifier = Accessibility::Qualifier.new(@kind, @filters, &@block)
85
+ end
86
+
87
+ # @param [AX::Element]
88
+ def matches? ancestor
89
+ !search(ancestor).blank?
90
+ end
91
+
92
+ # @return [String]
93
+ def failure_message_for_should
94
+ "Expected #@ancestor to have descendent #{@qualifier.describe}"
95
+ end
96
+
97
+ # @param [AX::Element]
98
+ def does_not_match? ancestor
99
+ search(ancestor).blank?
100
+ end
101
+
102
+ # @return [String]
103
+ def failure_message_for_should_not
104
+ "Expected #@ancestor to NOT have descendent #@result"
105
+ end
6
106
 
7
107
  ##
8
- # app.window.button.should be_visible
9
- class BeVisible
108
+ # Implemented to override `NSObject#description`.
109
+ #
110
+ # @return [String]
111
+ def description
112
+ "should have a descendent matching #{@qualifier.describe}"
10
113
  end
11
114
 
12
- class BeInFrame
115
+
116
+ private
117
+
118
+ def search ancestor
119
+ @ancestor = ancestor
120
+ @result = ancestor.search(@kind, @filters, &@block)
13
121
  end
14
122
 
15
123
  end
124
+
125
+ ##
126
+ # Assert that the given element has the specified descendent. You can
127
+ # pass any parameters you normally would use during a search,
128
+ # including a block.
129
+ #
130
+ # @example
131
+ #
132
+ # app.main_window.should have_descendent(:button, title: 'Press Me')
133
+ #
134
+ # row.should_not have_descendent(:check_box)
135
+ #
136
+ # @param [#to_s]
137
+ # @param [Hash]
138
+ # @yield An optional block to be used as part of the search qualifier
139
+ def have_descendent kind, filters = {}, &block
140
+ Accessibility::HasDescendentMatcher.new kind, filters, &block
141
+ end
142
+ alias :have_descendant :have_descendent
data/rakelib/doc.rake ADDED
@@ -0,0 +1,13 @@
1
+ # begin
2
+ # require 'yard'
3
+ # YARD::Rake::YardocTask.new
4
+ # rescue LoadError => e
5
+ # $stderr.puts 'It seems as though you do not have yard installed.'
6
+ # command = ENV['RUBY_VERSION'] ? 'rake' : 'sudo macrake'
7
+ # $stderr.puts "You can install it by running `#{command} setup_dev`"
8
+ # end
9
+
10
+ # desc 'Generate Graphviz object graph'
11
+ # task :garden => :yard do
12
+ # sh 'yard graph --full --dependencies --dot="-Tpng:quartz" -f docs/images/AX.dot'
13
+ # end
data/rakelib/ext.rake ADDED
@@ -0,0 +1,61 @@
1
+ module ExtHelpers
2
+ def macruby?
3
+ defined? MACRUBY_REVISION
4
+ end
5
+
6
+ def cruby?
7
+ RUBY_ENGINE == 'ruby'
8
+ end
9
+
10
+ def needs_regeneration? source, bundle
11
+ return true unless File.exists? bundle
12
+ return true unless File.mtime(bundle) > File.mtime(source)
13
+ return true if macruby? && ext_platform(bundle) == :cruby
14
+ return true if cruby? && ext_platform(bundle) == :macruby
15
+ end
16
+
17
+ def ext_platform bundle
18
+ return :macruby if `otool -L #{bundle}`.match /MacRuby/
19
+ return :cruby
20
+ end
21
+ end
22
+
23
+
24
+ namespace :ext do
25
+ extend ExtHelpers
26
+
27
+ desc 'Compile C extensions'
28
+ task :key_coder do
29
+ dir = 'ext/accessibility/key_coder'
30
+ ext = "#{dir}/key_coder"
31
+ if needs_regeneration? "#{ext}.c", "#{ext}.bundle"
32
+ Rake::Task['clobber_key_coder'].execute
33
+ Dir.chdir(dir) do
34
+ ruby 'extconf.rb'
35
+ sh 'make'
36
+ end
37
+ cp "#{ext}.bundle", 'lib/accessibility'
38
+ end
39
+ end
40
+ end
41
+
42
+
43
+ desc 'Remove files generated by compiling key_coder'
44
+ task :clobber_key_coder do
45
+ Dir.glob('{lib,ext}/**/*{.bundle,.o}').each do |file|
46
+ $stdout.puts "rm #{file}"
47
+ rm_f file
48
+ end
49
+ file = 'rm ext/accessibility/key_coder/Makefile'
50
+ $stdout.puts file
51
+ rm_f file
52
+ end
53
+
54
+ desc 'Remove files generated by compiling extensions'
55
+ task :clobber_ext => [:clobber_key_coder]
56
+
57
+
58
+ if RUBY_ENGINE == 'macruby'
59
+ require 'rake/compiletask'
60
+ Rake::CompileTask.new
61
+ end
data/rakelib/gem.rake ADDED
@@ -0,0 +1,28 @@
1
+ require 'rubygems/package_task'
2
+
3
+ ax_elements = Gem::Specification.load('AXElements.gemspec')
4
+ Gem::PackageTask.new(ax_elements) { }
5
+
6
+ desc 'Build and install gem (not including deps)'
7
+ task :install => :gem do
8
+ require 'rubygems/installer'
9
+ Gem::Installer.new("pkg/#{ax_elements.file_name}").install
10
+ end
11
+
12
+ desc 'Install dependencies for development'
13
+ task :setup_dev do
14
+ require 'rubygems/dependency_installer'
15
+ spec.development_dependencies.each do |dep|
16
+ puts "Installing #{dep.name} (#{dep.requirement})"
17
+ Gem::DependencyInstaller.new.install(dep.name, dep.requirement)
18
+ end
19
+ end
20
+
21
+ ax_typer = Gem::Specification.load('AXTyper.gemspec')
22
+ Gem::PackageTask.new(ax_typer) { }
23
+
24
+ desc 'Build and install AXTyper'
25
+ task :install_typer => :gem do
26
+ require 'rubygems/installer'
27
+ Gem::Installer.new("pkg/#{ax_typer.file_name}").install
28
+ end
data/rakelib/test.rake ADDED
@@ -0,0 +1,53 @@
1
+ desc 'Start up irb with AXElements loaded'
2
+ task :console => :ext do
3
+ irb = ENV['RUBY_VERSION'] ? 'irb' : 'macirb'
4
+ sh "#{irb} -Ilib -rubygems -rax_elements"
5
+ end
6
+
7
+ desc 'Open the fixture app'
8
+ task :run_fixture => :fixture do
9
+ sh 'open test/fixture/Release/AXElementsTester.app'
10
+ end
11
+
12
+ desc 'Build the test fixture'
13
+ task :fixture do
14
+ sh 'cd test/AXElementsTester && xcodebuild'
15
+ end
16
+
17
+ desc 'Remove the built fixture app'
18
+ task :clobber_fixture do
19
+ $stdout.puts 'rm -rf test/fixture'
20
+ rm_rf 'test/fixture'
21
+ end
22
+ task :clobber => :clobber_fixture
23
+
24
+ require 'rake/testtask'
25
+ namespace :test do
26
+ Rake::TestTask.new(:sanity) do |t|
27
+ t.libs << '.'
28
+ t.pattern = "test/sanity/**/test_*.rb"
29
+ end
30
+ task :sanity => [:ext, :fixture]
31
+
32
+ Rake::TestTask.new(:integration) do |t|
33
+ t.libs << '.'
34
+ t.pattern = "test/integration/**/test_*.rb"
35
+ end
36
+ task :integration => [:ext, :fixture]
37
+
38
+ desc 'Run tests for the string parser'
39
+ Rake::TestTask.new(:string) do |t|
40
+ t.libs << '.'
41
+ t.pattern = "test/sanity/accessibility/test_string.rb"
42
+ end
43
+ task :string => :ext
44
+
45
+ desc 'Run tests under CRuby (where applicable)'
46
+ task :cruby do
47
+ if ENV['RUBY_VERSION'] # using rvm
48
+ puts sh 'rvm 1.9.3 do rake test:string'
49
+ else
50
+ sh 'rake test:string'
51
+ end
52
+ end
53
+ end