AXElements 0.6.0beta2 → 0.7.5

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