AXElements 1.0.0.alpha11 → 1.0.0.beta

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 (48) hide show
  1. data/History.markdown +11 -1
  2. data/README.markdown +10 -8
  3. data/Rakefile +1 -1
  4. data/lib/accessibility/dsl.rb +5 -2
  5. data/lib/accessibility/factory.rb +134 -78
  6. data/lib/accessibility/qualifier.rb +2 -0
  7. data/lib/accessibility/system_info.rb +82 -17
  8. data/lib/accessibility/translator.rb +17 -17
  9. data/lib/accessibility/version.rb +1 -1
  10. data/lib/ax/application.rb +11 -16
  11. data/lib/ax/element.rb +21 -34
  12. data/lib/ax/systemwide.rb +2 -2
  13. data/lib/ax_elements.rb +7 -1
  14. data/lib/ax_elements/active_support_selections.rb +10 -0
  15. data/lib/ax_elements/mri.rb +57 -0
  16. data/lib/ax_elements/nsarray_compat.rb +97 -17
  17. data/rakelib/gem.rake +12 -3
  18. data/rakelib/test.rake +0 -6
  19. data/test/helper.rb +10 -20
  20. data/test/integration/accessibility/test_dsl.rb +6 -14
  21. data/test/integration/accessibility/test_enumerators.rb +0 -1
  22. data/test/integration/accessibility/test_graph.rb +1 -0
  23. data/test/integration/accessibility/test_qualifier.rb +2 -2
  24. data/test/integration/ax/test_application.rb +2 -2
  25. data/test/sanity/accessibility/test_factory.rb +2 -2
  26. data/test/sanity/accessibility/test_pretty_printer.rb +2 -2
  27. data/test/sanity/ax/test_application.rb +1 -1
  28. data/test/sanity/ax/test_element.rb +2 -2
  29. data/test/sanity/ax_elements/test_nsobject_inspect.rb +4 -2
  30. metadata +28 -36
  31. data/ext/accessibility/core/core.c +0 -26
  32. data/lib/accessibility/core.rb +0 -943
  33. data/lib/accessibility/highlighter.rb +0 -86
  34. data/lib/accessibility/statistics.rb +0 -57
  35. data/lib/ax_elements/core_graphics_workaround.rb +0 -7
  36. data/lib/ax_elements/vendor/inflection_data.rb +0 -66
  37. data/lib/ax_elements/vendor/inflections.rb +0 -176
  38. data/lib/ax_elements/vendor/inflector.rb +0 -306
  39. data/lib/minitest/ax_elements.rb +0 -180
  40. data/lib/rspec/expectations/ax_elements.rb +0 -234
  41. data/test/integration/accessibility/test_core.rb +0 -18
  42. data/test/integration/minitest/test_ax_elements.rb +0 -89
  43. data/test/integration/rspec/expectations/test_ax_elements.rb +0 -102
  44. data/test/sanity/accessibility/test_highlighter.rb +0 -56
  45. data/test/sanity/accessibility/test_statistics.rb +0 -57
  46. data/test/sanity/minitest/test_ax_elements.rb +0 -17
  47. data/test/sanity/rspec/expectations/test_ax_elements.rb +0 -15
  48. data/test/test_core.rb +0 -454
data/History.markdown CHANGED
@@ -1,6 +1,10 @@
1
1
  # 1.0.0
2
2
 
3
+ * AXElements can now run on MRI as well as MacRuby
4
+
5
+ * Added `NSScreen.wakeup` to the `NSScreen` class to wake up sleeping displays
3
6
  * Added `Accessibility::SystemInfo` for getting information about the running system
7
+ - Added a `Battery` module for querying information about the battery status
4
8
  * Added `DSL#record` to run a screen recording of the given block (actual video!)
5
9
  * Added `Application.frontmost_application`
6
10
  * Added `Application.menu_bar_owner`
@@ -11,8 +15,14 @@
11
15
  * Added `SystemWide.desktop`
12
16
  * Added History.markdown to track notable changes
13
17
 
14
- * Ported `mouse.rb` to C and moved code to [MRMouse](https://github.com/ferrous26/MRMouse)
18
+ * Moved MiniTest extensions to their own repository/gem [minitest-ax\_elements](https://github.com/AXElements/minitest-ax_elements)
19
+ * Moved RSpec extensions to their own repository/gem [rspec-ax\_elements](https://github.com/AXElements/rspec-ax_elements)
20
+
21
+ * Ported `mouse.rb` to C and moved code to [mouse](https://github.com/AXElements/mouse)
22
+ * Ported `core.rb` to C and moved code to [accessibility\_core](https://github.com/AXElements/accessibility_core)
23
+ * Ported `screen_recorder.rb` to C and moved code to [screen\_recorder](https://github.com/AXElements/screen_recorder)
15
24
 
25
+ * Deprecate `AX::DOCK` constant, use `AX::Application.dock` instead
16
26
  * Remove `Accessibility.application_with_bundle_identifier`; use `AX::Application.new` instead
17
27
  * Remove `Accessibility.application_with_name; use `AX::Application.new` instead
18
28
  * Remove `DSL#subtree_for`; use `Element#inspect_subtree` instead
data/README.markdown CHANGED
@@ -1,4 +1,4 @@
1
- # AXElements
1
+ # AXElements
2
2
 
3
3
  AXElements is a DSL abstraction built on top of the Mac OS X
4
4
  Accessibility and CGEvent APIs that allows code to be written in a
@@ -64,8 +64,10 @@ The code from the demo video is right here:
64
64
 
65
65
  ## Getting Setup
66
66
 
67
- You will need a MacRuby nightly build for installation. You can get help setting
68
- up by referencing the
67
+ You will need Ruby 1.9.3 or a MacRuby nightly build for
68
+ installation. You can get help installing Ruby 1.9.3 from the
69
+ [Ruby Website](http://www.ruby-lang.org), or help installing MacRuby
70
+ from the
69
71
  [Setup MacRuby](https://github.com/MacRuby/MacRuby/wiki/Setting-up-MacRuby)
70
72
  guide on Github.
71
73
 
@@ -95,11 +97,11 @@ Once all the setup is finished, you can start up AXElements in IRB:
95
97
  irb -rubygems -rax_elements
96
98
  ```
97
99
 
98
- __NOTE__: If you are not using RVM, then you should use `macrake`
99
- instead of `rake`, and `macirb` instead of `irb`, etc.. You may also
100
- need to add `sudo` to your command when you install the gem. If you
101
- are not using RVM with MacRuby, but have RVM installed, remember to
102
- disable it like so:
100
+ __NOTE__: If you are not using RVM, but are using MacRuby, then you
101
+ should use `macrake` instead of `rake`, and `macirb` instead of `irb`,
102
+ etc.. You may also need to add `sudo` to your command when you install
103
+ the gem. If you are not using RVM with MacRuby, but have RVM
104
+ installed, remember to disable it like so:
103
105
 
104
106
  ```bash
105
107
  rvm use system
data/Rakefile CHANGED
@@ -11,4 +11,4 @@ desc 'Compile C extensions'
11
11
  task :ext => 'ext:key_coder'
12
12
 
13
13
  desc 'Run all tests'
14
- task :test => ['test:core', 'test:sanity', 'test:integration', 'test:cruby']
14
+ task :test => ['test:sanity', 'test:integration', 'test:cruby']
@@ -1,5 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
+ require 'active_support/core_ext/object/blank'
4
+
3
5
  require 'mouse'
4
6
  require 'ax/element'
5
7
  require 'ax/application'
@@ -8,6 +10,8 @@ require 'ax/scroll_area'
8
10
  require 'ax/menu'
9
11
  require 'accessibility'
10
12
  require 'accessibility/enumerators'
13
+ require 'accessibility/highlighter'
14
+
11
15
 
12
16
  ##
13
17
  # DSL methods for AXElements.
@@ -129,7 +133,7 @@ module Accessibility::DSL
129
133
  # The normal way to raise an exception.
130
134
  def raise *args
131
135
  arg = args.first
132
- arg.kind_of?(AX::Element) ? arg.perform(:raise) : super(*args)
136
+ arg.kind_of?(AX::Element) ? arg.perform(:raise) : Kernel.raise(*args)
133
137
  end
134
138
 
135
139
  ##
@@ -625,7 +629,6 @@ module Accessibility::DSL
625
629
  # @option opts [NSColor] :colour (NSColor.magentaColor)
626
630
  # @return [Accessibility::Highlighter]
627
631
  def highlight obj, opts = {}
628
- require 'accessibility/highlighter'
629
632
  Accessibility::Highlighter.new obj.bounds, opts
630
633
  end
631
634
 
@@ -1,92 +1,27 @@
1
1
  require 'accessibility/core'
2
2
  require 'accessibility/translator'
3
- require 'accessibility/statistics'
4
3
 
5
4
  ##
6
5
  # Namespace container for all the accessibility objects.
7
6
  module AX; class Element; end end
8
7
 
9
8
 
10
- ##
11
- # Extensions to {Accessibility::Element} for the high level abstraction.
12
- # These extensions only make sense in the context of the high level API
13
- # and it requires knowledge of both layers, so the code has been placed
14
- # in its own file.
15
- module Accessibility::Element
16
-
17
- ##
18
- # @todo Should we handle cases where a subrole has a value of
19
- # 'Unknown'? What is the performance impact?
20
- #
21
- # Wrap the low level wrapper with the appropriate high level wrapper.
22
- # This involves determining the proper class in the {AX} namespace,
23
- # possibly creating it on demand, and then instantiating the class to
24
- # wrap the low level object.
25
- #
26
- # Some code paths have been unrolled for efficiency. Don't hate player,
27
- # hate the game.
28
- #
29
- # @return [AX::Element]
30
- def to_ruby
31
- type = AXValueGetType(self)
32
- if type.zero?
33
- to_element
34
- else
35
- to_box type
36
- end
37
- end
38
-
39
- private
40
-
41
- def to_element
42
- STATS.increment :Factory
43
- if roll = self.role
44
- roll = TRANSLATOR.unprefix roll
45
- if attributes.include? KAXSubroleAttribute
46
- subroll = self.subrole
47
- # Some objects claim to have a subrole but return nil
48
- if subroll
49
- class_for2(TRANSLATOR.unprefix(subroll), roll).new self
50
- else
51
- class_for(roll).new self
52
- end
53
- else
54
- class_for(roll).new self
55
- end
56
- else # failsafe in case object dies before we get the role
57
- AX::Element.new self
58
- end
59
- end
60
-
61
- def to_box type
62
- STATS.increment :Unwrap
63
- ptr = Pointer.new BOX_TYPES[type]
64
- AXValueGetValue(self, type, ptr)
65
- ptr.value.to_ruby
66
- end
67
-
68
-
69
- private
9
+ class << AX
70
10
 
71
11
  ##
72
12
  # @private
73
13
  #
74
- # Reference to the singleton instance of the translator.
14
+ # Mutex to make sure we only create one class at a time.
75
15
  #
76
- # @return [Accessibility::Translator]
77
- TRANSLATOR = Accessibility::Translator.instance
16
+ # @return [Mutex]
17
+ MUTEX = Mutex.new
78
18
 
79
19
  ##
80
20
  # @private
81
21
  #
82
- # Serial queue to make sure we only create one class at a time.
22
+ # Find the class for a given role
83
23
  #
84
- # @return [Dispatch::Queue]
85
- CREATE_QUEUE = Dispatch::Queue.new 'com.marketcircle.axelements.create'
86
-
87
- ##
88
- # Find the class for a given role. If the class does not exist it will
89
- # be created.
24
+ # If the class does not exist it will be created.
90
25
  #
91
26
  # @param role [#to_s]
92
27
  # @return [Class]
@@ -99,8 +34,11 @@ module Accessibility::Element
99
34
  end
100
35
 
101
36
  ##
102
- # Find the class for a given subrole and role. If the class does not
103
- # exist it will be created on demand.
37
+ # @private
38
+ #
39
+ # Find the class for a given subrole and role
40
+ #
41
+ # If the class does not exist it will be created on demand.
104
42
  #
105
43
  # @param subrole [#to_s]
106
44
  # @param role [#to_s]
@@ -114,13 +52,15 @@ module Accessibility::Element
114
52
  end
115
53
 
116
54
  ##
117
- # Create a new class in the {AX} namespace that has {AX::Element}
118
- # as the superclass.
55
+ # @private
56
+ #
57
+ # Create a class in the {AX} namespace that has {AX::Element} as the
58
+ # superclass
119
59
  #
120
60
  # @param name [#to_s]
121
61
  # @return [Class]
122
62
  def create_class name
123
- CREATE_QUEUE.sync do
63
+ MUTEX.synchronize do
124
64
  # re-check now that we are in the critical section
125
65
  @klass = if AX.const_defined? name, false
126
66
  AX.const_get name
@@ -133,8 +73,10 @@ module Accessibility::Element
133
73
  end
134
74
 
135
75
  ##
76
+ # @private
77
+ #
136
78
  # Create a new class in the {AX} namesapce that has the given
137
- # `superklass` as the superclass..
79
+ # `superklass` as the superclass
138
80
  #
139
81
  # @param name [#to_s]
140
82
  # @param superklass [#to_s]
@@ -143,7 +85,7 @@ module Accessibility::Element
143
85
  unless AX.const_defined? superklass, false
144
86
  create_class superklass
145
87
  end
146
- CREATE_QUEUE.sync do
88
+ MUTEX.synchronize do
147
89
  # re-check now that we are in the critical section
148
90
  @klass = if AX.const_defined? name, false
149
91
  AX.const_get name
@@ -156,3 +98,117 @@ module Accessibility::Element
156
98
  end
157
99
 
158
100
  end
101
+
102
+
103
+ if on_macruby?
104
+
105
+ ##
106
+ # Extensions to {Accessibility::Element} for the higher level abstractions
107
+ #
108
+ # These extensions only make sense in the context of the high level API
109
+ # but needs to be applied on the lower level class, so the code has been
110
+ # placed in its own file.
111
+ module Accessibility::Element
112
+
113
+ ##
114
+ # @todo Should we handle cases where a subrole has a value of
115
+ # 'Unknown'? What is the performance impact?
116
+ #
117
+ # Wrap the low level wrapper with the appropriate high level wrapper.
118
+ # This involves determining the proper class in the {AX} namespace,
119
+ # possibly creating it on demand, and then instantiating the class to
120
+ # wrap the low level object.
121
+ #
122
+ # Some code paths have been unrolled for efficiency. Don't hate player,
123
+ # hate the game.
124
+ #
125
+ # @return [AX::Element]
126
+ def to_ruby
127
+ type = AXValueGetType(self)
128
+ if type.zero?
129
+ to_element
130
+ else
131
+ to_box type
132
+ end
133
+ end
134
+
135
+
136
+ private
137
+
138
+ ##
139
+ # @private
140
+ #
141
+ # Reference to the singleton instance of the translator.
142
+ #
143
+ # @return [Accessibility::Translator]
144
+ TRANSLATOR = Accessibility::Translator.instance
145
+
146
+ def to_box type
147
+ ptr = Pointer.new ValueWrapper::BOX_TYPES[type]
148
+ AXValueGetValue(self, type, ptr)
149
+ ptr.value.to_ruby
150
+ end
151
+
152
+ def to_element
153
+ if roll = self.role
154
+ roll = TRANSLATOR.unprefix roll
155
+ if attributes.include? KAXSubroleAttribute
156
+ subroll = self.subrole
157
+ # Some objects claim to have a subrole but return nil
158
+ if subroll
159
+ AX.class_for2(TRANSLATOR.unprefix(subroll), roll).new self
160
+ else
161
+ AX.class_for(roll).new self
162
+ end
163
+ else
164
+ AX.class_for(roll).new self
165
+ end
166
+ else # failsafe in case object dies before we get the role
167
+ AX::Element.new self
168
+ end
169
+ end
170
+
171
+ end
172
+
173
+
174
+ else
175
+
176
+
177
+ ##
178
+ # `AXElements` extensions to the `Accessibility::Element` class
179
+ class Accessibility::Element
180
+
181
+ ##
182
+ # Override the default `#to_ruby` so that proper classes are
183
+ # chosen for each object.
184
+ #
185
+ # @return [AX::Element]
186
+ def to_ruby
187
+ if roll = self.role
188
+ roll = TRANSLATOR.unprefix roll
189
+ if attributes.include? KAXSubroleAttribute
190
+ subroll = self.subrole
191
+ # Some objects claim to have a subrole but return nil
192
+ if subroll
193
+ AX.class_for2(TRANSLATOR.unprefix(subroll), roll).new self
194
+ else
195
+ AX.class_for(roll).new self
196
+ end
197
+ else
198
+ AX.class_for(roll).new self
199
+ end
200
+ else # failsafe in case object dies before we get the role
201
+ AX::Element.new self
202
+ end
203
+ end
204
+
205
+ ##
206
+ # @private
207
+ #
208
+ # Reference to the singleton instance of the translator.
209
+ #
210
+ # @return [Accessibility::Translator]
211
+ TRANSLATOR = Accessibility::Translator.instance
212
+ end
213
+
214
+ end
@@ -1,4 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
+
3
+ require 'active_support/core_ext/object/blank'
2
4
  require 'accessibility/translator'
3
5
 
4
6
  ##
@@ -1,4 +1,5 @@
1
1
  require 'accessibility/version'
2
+ require 'accessibility/extras'
2
3
 
3
4
  ##
4
5
  # Interface for collecting some simple information about the system.
@@ -11,17 +12,30 @@ require 'accessibility/version'
11
12
  module Accessibility::SystemInfo
12
13
  extend self
13
14
 
15
+ ##
16
+ # The name the machine uses for Bonjour
17
+ #
18
+ # @example
19
+ #
20
+ # Accessibility::SystemInfo.name
21
+ # # => "ferrous"
22
+ #
23
+ # @return [String]
24
+ def name
25
+ NSHost.currentHost.localizedName
26
+ end
27
+
14
28
  ##
15
29
  # All hostnames that the system responds to
16
30
  #
17
31
  # @example
18
32
  #
19
- # Accessibility::SystemInfo.hostnames
33
+ # Accessibility::SystemInfo.hostnames
20
34
  # # => ["ferrous.local", "localhost"]
21
35
  #
22
36
  # @return [Array<String>]
23
37
  def hostnames
24
- host.names
38
+ NSHost.currentHost.names
25
39
  end
26
40
 
27
41
  ##
@@ -46,7 +60,7 @@ module Accessibility::SystemInfo
46
60
  #
47
61
  # @return [Array<String>]
48
62
  def addresses
49
- host.addresses
63
+ NSHost.currentHost.addresses
50
64
  end
51
65
 
52
66
  ##
@@ -67,7 +81,7 @@ module Accessibility::SystemInfo
67
81
  #
68
82
  # @example
69
83
  #
70
- # Accessibility::SystemInfo.ipv6_addresses
84
+ # Accessibility::SystemInfo.ipv6_addresses
71
85
  # # => ["fe80::6aa8:6dff:fe20:822%en1", "fe80::1%lo0", "::1"]
72
86
  #
73
87
  # @return [Array<String>]
@@ -86,7 +100,7 @@ module Accessibility::SystemInfo
86
100
  def model
87
101
  @model ||= `sysctl hw.model`.split.last.chomp
88
102
  end
89
-
103
+
90
104
  ##
91
105
  # OS X version string
92
106
  #
@@ -96,7 +110,7 @@ module Accessibility::SystemInfo
96
110
  #
97
111
  # @return [String]
98
112
  def osx_version
99
- pinfo.operatingSystemVersionString
113
+ NSProcessInfo.processInfo.operatingSystemVersionString
100
114
  end
101
115
 
102
116
  ##
@@ -108,7 +122,7 @@ module Accessibility::SystemInfo
108
122
  #
109
123
  # @return [Float]
110
124
  def uptime
111
- pinfo.systemUptime
125
+ NSProcessInfo.processInfo.systemUptime
112
126
  end
113
127
 
114
128
  ##
@@ -122,7 +136,7 @@ module Accessibility::SystemInfo
122
136
  #
123
137
  # @return [Fixnum]
124
138
  def num_processors
125
- pinfo.processorCount
139
+ NSProcessInfo.processInfo.processorCount
126
140
  end
127
141
 
128
142
  ##
@@ -134,7 +148,7 @@ module Accessibility::SystemInfo
134
148
  #
135
149
  # @return [Fixnum]
136
150
  def num_active_processors
137
- pinfo.activeProcessorCount
151
+ NSProcessInfo.processInfo.activeProcessorCount
138
152
  end
139
153
 
140
154
  ##
@@ -146,20 +160,71 @@ module Accessibility::SystemInfo
146
160
  #
147
161
  # @return [Fixnum]
148
162
  def total_ram
149
- pinfo.physicalMemory
163
+ NSProcessInfo.processInfo.physicalMemory
150
164
  end
151
165
  alias_method :ram, :total_ram
152
166
 
167
+ ##
168
+ # Return the current state of the battery
169
+ #
170
+ # @example
171
+ #
172
+ # battery_state # => :charged
173
+ # # unplug AC cord
174
+ # battery_state # => :discharging
175
+ # # plug AC cord back in after several minutes
176
+ # battery_state # => :charging
177
+ #
178
+ # # try this method when you have no battery
179
+ # battery_state # => :not_installed
180
+ #
181
+ # @return [Symbol]
182
+ def battery_state
183
+ Battery.state
184
+ end
153
185
 
154
- private
155
-
156
- def host
157
- NSHost.currentHost
186
+ ##
187
+ # Returns the charge percentage of the battery (if present)
188
+ #
189
+ # A special value of `-1.0` is returned if you have no battery.
190
+ #
191
+ # @example
192
+ #
193
+ # battery_charge_level # => 1.0
194
+ # # unplug AC cord and wait a couple of minutes
195
+ # battery_charge_level # => 0.99
196
+ #
197
+ # # if you have no battery
198
+ # battery_charge_level # => -1.0
199
+ #
200
+ # @return [Float]
201
+ def battery_charge_level
202
+ Battery.level
158
203
  end
204
+ alias_method :battery_level, :battery_charge_level
159
205
 
160
- def pinfo
161
- NSProcessInfo.processInfo
206
+ ##
207
+ # Return an estimate on the number of minutes until the battery is drained
208
+ #
209
+ # A special value of `0` indicates that the battery is not discharging.
210
+ # You should really only call this after you know that the battery is
211
+ # discharging by calling {#battery_state} and having `:discharging` returned.
212
+ #
213
+ # A special value of `-1` is returned when the estimate is in flux and
214
+ # cannot be accurately estimated.
215
+ #
216
+ # @example
217
+ #
218
+ # # AC cord plugged in
219
+ # battery_life_estimate # => 0
220
+ # # unplug AC cord
221
+ # battery_life_estimate # => -1
222
+ # # wait a few minutes
223
+ # battery_life_estimate # => 423
224
+ #
225
+ # @return [Fixnum]
226
+ def battery_life_estimate
227
+ Battery.time_to_empty
162
228
  end
163
229
 
164
230
  end
165
-