AXElements 1.0.0.alpha11 → 1.0.0.beta

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