AXElements 0.8.1 → 0.9.0

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 (62) hide show
  1. data/.yardopts +4 -0
  2. data/History.markdown +41 -0
  3. data/README.markdown +59 -62
  4. data/Rakefile +1 -1
  5. data/ext/accessibility/key_coder/extconf.rb +1 -1
  6. data/ext/accessibility/key_coder/key_coder.c +8 -5
  7. data/lib/accessibility/dsl.rb +261 -87
  8. data/lib/accessibility/enumerators.rb +14 -11
  9. data/lib/accessibility/errors.rb +4 -3
  10. data/lib/accessibility/factory.rb +159 -108
  11. data/lib/accessibility/graph.rb +13 -9
  12. data/lib/accessibility/{pp_inspector.rb → pretty_printer.rb} +4 -5
  13. data/lib/accessibility/qualifier.rb +23 -13
  14. data/lib/accessibility/string.rb +4 -4
  15. data/lib/accessibility/system_info.rb +230 -0
  16. data/lib/accessibility/translator.rb +38 -28
  17. data/lib/accessibility/version.rb +24 -2
  18. data/lib/accessibility.rb +25 -8
  19. data/lib/ax/application.rb +207 -77
  20. data/lib/ax/element.rb +62 -65
  21. data/lib/ax/menu.rb +5 -1
  22. data/lib/ax/row.rb +1 -1
  23. data/lib/ax/scroll_area.rb +7 -6
  24. data/lib/ax/systemwide.rb +38 -5
  25. data/lib/ax_elements/active_support_selections.rb +10 -0
  26. data/lib/ax_elements/mri.rb +57 -0
  27. data/lib/ax_elements/nsarray_compat.rb +97 -17
  28. data/lib/ax_elements.rb +9 -1
  29. data/rakelib/gem.rake +11 -11
  30. data/rakelib/test.rake +0 -9
  31. data/test/helper.rb +10 -18
  32. data/test/integration/accessibility/test_dsl.rb +52 -42
  33. data/test/integration/accessibility/test_enumerators.rb +0 -1
  34. data/test/integration/accessibility/test_graph.rb +1 -0
  35. data/test/integration/accessibility/test_qualifier.rb +2 -2
  36. data/test/integration/ax/test_application.rb +9 -2
  37. data/test/integration/ax/test_element.rb +41 -1
  38. data/test/sanity/accessibility/test_factory.rb +23 -56
  39. data/test/sanity/accessibility/{test_pp_inspector.rb → test_pretty_printer.rb} +9 -9
  40. data/test/sanity/accessibility/test_translator.rb +2 -5
  41. data/test/sanity/accessibility/test_version.rb +15 -0
  42. data/test/sanity/ax/test_application.rb +17 -2
  43. data/test/sanity/ax/test_element.rb +2 -2
  44. data/test/sanity/ax_elements/test_nsobject_inspect.rb +4 -2
  45. data/test/sanity/test_ax_elements.rb +1 -0
  46. metadata +69 -39
  47. data/lib/accessibility/core.rb +0 -973
  48. data/lib/accessibility/highlighter.rb +0 -86
  49. data/lib/ax_elements/vendor/inflection_data.rb +0 -66
  50. data/lib/ax_elements/vendor/inflections.rb +0 -172
  51. data/lib/ax_elements/vendor/inflector.rb +0 -306
  52. data/lib/minitest/ax_elements.rb +0 -175
  53. data/lib/mouse.rb +0 -223
  54. data/lib/rspec/expectations/ax_elements.rb +0 -234
  55. data/test/integration/accessibility/test_core.rb +0 -18
  56. data/test/integration/minitest/test_ax_elements.rb +0 -89
  57. data/test/integration/rspec/expectations/test_ax_elements.rb +0 -102
  58. data/test/sanity/accessibility/test_core.rb +0 -561
  59. data/test/sanity/accessibility/test_highlighter.rb +0 -56
  60. data/test/sanity/minitest/test_ax_elements.rb +0 -17
  61. data/test/sanity/rspec/expectations/test_ax_elements.rb +0 -15
  62. data/test/sanity/test_mouse.rb +0 -19
@@ -0,0 +1,230 @@
1
+ require 'accessibility/version'
2
+ require 'accessibility/extras'
3
+
4
+ ##
5
+ # Interface for collecting some simple information about the system.
6
+ # This information may be useful as diagnostic output when running
7
+ # tests, or if you simply need to find the hostname of the machine so
8
+ # it can be passed to another process to initiate a connection.
9
+ #
10
+ # This module extends itself, so all methods are available on the module
11
+ # and you will want to use the module as a utility module.
12
+ module Accessibility::SystemInfo
13
+ extend self
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
+
28
+ ##
29
+ # All hostnames that the system responds to
30
+ #
31
+ # @example
32
+ #
33
+ # Accessibility::SystemInfo.hostnames
34
+ # # => ["ferrous.local", "localhost"]
35
+ #
36
+ # @return [Array<String>]
37
+ def hostnames
38
+ NSHost.currentHost.names
39
+ end
40
+
41
+ ##
42
+ # The first, and likely common, name the system responds to
43
+ #
44
+ # @example
45
+ #
46
+ # Accessibility::SystemInfo.hostname # => "ferrous.local"
47
+ #
48
+ # @return [Array<String>]
49
+ def hostname
50
+ hostnames.first
51
+ end
52
+
53
+ ##
54
+ # All IP addresses the system has interfaces for
55
+ #
56
+ # @example
57
+ #
58
+ # Accessibility::SystemInfo.addresses
59
+ # # => ["fe80::6aa8:6dff:fe20:822%en1", "192.168.0.17", "fe80::1%lo0", "127.0.0.1", "::1"]
60
+ #
61
+ # @return [Array<String>]
62
+ def addresses
63
+ NSHost.currentHost.addresses
64
+ end
65
+
66
+ ##
67
+ # All IPv4 addresses the system has interfaces for
68
+ #
69
+ # @example
70
+ #
71
+ # Accessibility::SystemInfo.ipv4_addresses
72
+ # # => ["192.168.0.17", "127.0.0.1"]
73
+ #
74
+ # @return [Array<String>]
75
+ def ipv4_addresses
76
+ addresses.select { |address| address.match /\./ }
77
+ end
78
+
79
+ ##
80
+ # All IPv6 addresses the system has interfaces for
81
+ #
82
+ # @example
83
+ #
84
+ # Accessibility::SystemInfo.ipv6_addresses
85
+ # # => ["fe80::6aa8:6dff:fe20:822%en1", "fe80::1%lo0", "::1"]
86
+ #
87
+ # @return [Array<String>]
88
+ def ipv6_addresses
89
+ addresses.select { |address| address.match /:/ }
90
+ end
91
+
92
+ ##
93
+ # System model string
94
+ #
95
+ # @example
96
+ #
97
+ # Accessibility::SystemInfo.model # => "MacBookPro8,2"
98
+ #
99
+ # @return [String]
100
+ def model
101
+ @model ||= `sysctl hw.model`.split.last.chomp
102
+ end
103
+
104
+ ##
105
+ # OS X version string
106
+ #
107
+ # @example
108
+ #
109
+ # Accessibility::SystemInfo.osx_version # => "Version 10.8.2 (Build 12C60)"
110
+ #
111
+ # @return [String]
112
+ def osx_version
113
+ NSProcessInfo.processInfo.operatingSystemVersionString
114
+ end
115
+
116
+ ##
117
+ # System uptime, in seconds
118
+ #
119
+ # @example
120
+ #
121
+ # Accessibility::SystemInfo.uptime # => 22999.76858776
122
+ #
123
+ # @return [Float]
124
+ def uptime
125
+ NSProcessInfo.processInfo.systemUptime
126
+ end
127
+
128
+ ##
129
+ # Total number of CPUs the system could use
130
+ #
131
+ # May not be the same as {#num_active_processors}.
132
+ #
133
+ # @example
134
+ #
135
+ # Accessibility::SystemInfo.num_processors # => 8
136
+ #
137
+ # @return [Fixnum]
138
+ def num_processors
139
+ NSProcessInfo.processInfo.processorCount
140
+ end
141
+
142
+ ##
143
+ # Number of CPUs the system current has enabled
144
+ #
145
+ # @example
146
+ #
147
+ # Accessibility::SystemInfo.num_active_processors # => 8
148
+ #
149
+ # @return [Fixnum]
150
+ def num_active_processors
151
+ NSProcessInfo.processInfo.activeProcessorCount
152
+ end
153
+
154
+ ##
155
+ # Total amount of memory for the system, in bytes
156
+ #
157
+ # @example
158
+ #
159
+ # Accessibility::SystemInfo.total_ram # => 17179869184
160
+ #
161
+ # @return [Fixnum]
162
+ def total_ram
163
+ NSProcessInfo.processInfo.physicalMemory
164
+ end
165
+ alias_method :ram, :total_ram
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
185
+
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
203
+ end
204
+ alias_method :battery_level, :battery_charge_level
205
+
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
228
+ end
229
+
230
+ end
@@ -1,18 +1,16 @@
1
1
  require 'accessibility/version'
2
- require 'ax_elements/vendor/inflector'
3
-
4
- framework 'ApplicationServices'
5
-
6
- unless Object.const_defined? :KAXIdentifierAttribute
7
- ##
8
- # Added for backwards compatability with Snow Leopard.
9
- # This attribute is standard with Lion and newer. AXElements depends
10
- # on it being defined.
11
- #
12
- # @return [String]
13
- KAXIdentifierAttribute = 'AXIdentifier'
2
+ require 'active_support/inflector'
3
+ require 'ax_elements/mri'
4
+
5
+ ActiveSupport::Inflector.inflections do |inflect|
6
+ # Related to accessibility
7
+ inflect.acronym('UI')
8
+ inflect.acronym('RTF')
9
+ inflect.acronym('URL')
14
10
  end
15
11
 
12
+ framework 'ApplicationServices' if on_macruby?
13
+
16
14
 
17
15
  ##
18
16
  # Maintain all the rules for transforming Cocoa constants into something
@@ -55,7 +53,7 @@ class Accessibility::Translator
55
53
  # unprefix KAXWindowCreatedNotification # => 'WindowCreated'
56
54
  # unprefix NSAccessibilityButtonRole # => 'Button'
57
55
  #
58
- # @param [String]
56
+ # @param key [String]
59
57
  # @return [String]
60
58
  def unprefix key
61
59
  @unprefixes[key]
@@ -69,15 +67,18 @@ class Accessibility::Translator
69
67
  #
70
68
  # rubyize ["AXRole", "AXTitleUIElement"] # => [:role, :title_ui_element]
71
69
  #
70
+ # @param keys [Array<String>]
72
71
  # @return [Array<Symbol>]
73
72
  def rubyize keys
74
- keys.map { |x| @rubyisms[x] }
73
+ keys = keys.map { |x| @rubyisms[x] }
74
+ keys.flatten!
75
+ keys
75
76
  end
76
77
 
77
78
  ##
78
79
  # Given a symbol, return the equivalent accessibility constant.
79
80
  #
80
- # @param [#to_sym]
81
+ # @param key [#to_sym]
81
82
  # @return [String]
82
83
  def cocoaify key
83
84
  @cocoaifications[key.to_sym]
@@ -93,7 +94,7 @@ class Accessibility::Translator
93
94
  # classify 'text_field' # => "TextField"
94
95
  # classify 'buttons' # => "Button"
95
96
  #
96
- # @param [String]
97
+ # @param klass [String]
97
98
  # @return [String]
98
99
  def classify klass
99
100
  @classifications[klass]
@@ -109,7 +110,7 @@ class Accessibility::Translator
109
110
  # singularize 'buttons' # => 'button'
110
111
  # singularize 'check_boxes' # => 'check_box'
111
112
  #
112
- # @param [String]
113
+ # @param klass [String]
113
114
  # @return [String]
114
115
  def singularize klass
115
116
  @singularizations[klass]
@@ -121,7 +122,7 @@ class Accessibility::Translator
121
122
  # a notification constant then the original string parameter will
122
123
  # be returned.
123
124
  #
124
- # @param [#to_s]
125
+ # @param name [#to_s]
125
126
  # @return [String]
126
127
  def guess_notification name
127
128
  name = name.to_s.gsub /(?:^|_)(.)/ do $1.upcase! || $1 end
@@ -132,6 +133,17 @@ class Accessibility::Translator
132
133
 
133
134
  private
134
135
 
136
+ def preloads
137
+ {
138
+ # basic preloads
139
+ id: KAXIdentifierAttribute,
140
+ placeholder: KAXPlaceholderValueAttribute,
141
+ # workarounds for known case where AX uses "Is" for a boolean attribute
142
+ application_running: KAXIsApplicationRunningAttribute,
143
+ application_running?: KAXIsApplicationRunningAttribute,
144
+ }
145
+ end
146
+
135
147
  # @return [Hash{String=>String}]
136
148
  def init_unprefixes
137
149
  @unprefixes = Hash.new do |hash, key|
@@ -142,34 +154,32 @@ class Accessibility::Translator
142
154
  # @return [Hash{String=>Symbol}]
143
155
  def init_rubyisms
144
156
  @rubyisms = Hash.new do |hash, key|
145
- hash[key] = Accessibility::Inflector.underscore(@unprefixes[key]).to_sym
157
+ hash[key] = [ActiveSupport::Inflector.underscore(@unprefixes[key]).to_sym]
146
158
  end
159
+ preloads.each_pair do |k,v| @rubyisms[v] << k end
147
160
  end
148
161
 
149
162
  # @return [Hash{Symbol=>String}]
150
163
  def init_cocoaifications
151
164
  @cocoaifications = Hash.new do |hash, key|
152
- hash[key] = "AX#{Accessibility::Inflector.camelize(key.chomp QUESTION_MARK)}"
165
+ str_key = key.to_s
166
+ str_key.chomp! QUESTION_MARK
167
+ hash[key] = "AX#{ActiveSupport::Inflector.camelize(str_key)}"
153
168
  end
154
- # preload the table
155
- @cocoaifications[:id] = KAXIdentifierAttribute
156
- @cocoaifications[:placeholder] = KAXPlaceholderValueAttribute
157
- # workaround the one known case where AX uses "Is" for a boolean attribute
158
- @cocoaifications[:application_running] = # let the value all fall through
159
- @cocoaifications[:application_running?] = KAXIsApplicationRunningAttribute
169
+ preloads.each_pair do |k, v| @cocoaifications[k] = v end
160
170
  end
161
171
 
162
172
  # @return [Hash{String=>String}]
163
173
  def init_classifications
164
174
  @classifications = Hash.new do |hash, key|
165
- hash[key] = Accessibility::Inflector.classify(key)
175
+ hash[key] = ActiveSupport::Inflector.classify(key)
166
176
  end
167
177
  end
168
178
 
169
179
  # @return [Hash{String=>String}]
170
180
  def init_singularizations
171
181
  @singularizations = Hash.new do |hash, key|
172
- hash[key] = Accessibility::Inflector.singularize(key)
182
+ hash[key] = ActiveSupport::Inflector.singularize(key)
173
183
  end
174
184
  end
175
185
 
@@ -1,9 +1,31 @@
1
+ # -*- coding: utf-8 -*-
2
+
1
3
  ##
2
4
  # The main AXElements namespace.
3
5
  module Accessibility
4
6
  # @return [String]
5
- VERSION = '0.8.1'
7
+ VERSION = '0.9.0'
8
+
9
+ # @return [String]
10
+ CODE_NAME = 'エネコロロ'
6
11
 
7
12
  # @return [String]
8
- CODE_NAME = 'Clefable'
13
+ ENGINE = case RUBY_ENGINE
14
+ when 'macruby' then 'サンダース'
15
+ when 'ruby' then 'ブースター'
16
+ when 'rbx' then 'ブラッキー' # for when rbx has good cext support
17
+ else 'シャワーズ' # vapor(ware)eon
18
+ end
19
+
20
+ ##
21
+ # The complete version string for AXElements
22
+ #
23
+ # This differs from {Accessibility::VERSION} in that it also
24
+ # includes `RUBY_ENGINE` information.
25
+ #
26
+ # @return [String]
27
+ def self.version
28
+ "#{VERSION}-#{ENGINE}"
29
+ end
30
+
9
31
  end
data/lib/accessibility.rb CHANGED
@@ -20,10 +20,11 @@ class << Accessibility
20
20
  # @group Finding an application object
21
21
 
22
22
  ##
23
- # @todo Move to {AX::Aplication#initialize} eventually.
23
+ # @note Bundle identifiers are case-sensitive.
24
+ # @deprecated Use {AX::Aplication#initialize} instead.
24
25
  #
25
26
  # This is the standard way of creating an application object. It will
26
- # launch the app if it is not already running and then create the
27
+ # launch the app if it is not already running and create the
27
28
  # accessibility object.
28
29
  #
29
30
  # However, this method is a bit of a hack in cases where the app is not
@@ -40,15 +41,19 @@ class << Accessibility
40
41
  # @example
41
42
  #
42
43
  # application_with_bundle_identifier 'com.apple.mail' # wait a few seconds
43
- # application_with_bundle_identifier 'com.marketcircle.Daylite'
44
+ # application_with_bundle_identifier 'com.marketcircle.Daylite4'
44
45
  #
45
- # @param [String] bundle a bundle identifier
46
+ # @param bundle [String] a bundle identifier
46
47
  # @return [AX::Application,nil]
47
48
  def application_with_bundle_identifier bundle
49
+ $stderr.puts "#{__method__} is DEPRECATED: Use AX::Application.new instead"
48
50
  if app_running?(bundle) || launch_application(bundle)
49
51
  10.times do
50
- return AX::Application.new(bundle) if app_running? bundle
51
- sleep 1
52
+ if app_running?(bundle) && (app = try_wrapping(bundle))
53
+ return app
54
+ else
55
+ sleep 1
56
+ end
52
57
  end
53
58
  else
54
59
  raise ArgumentError, "Could not launch app matching bundle id `#{bundle}'"
@@ -70,7 +75,7 @@ class << Accessibility
70
75
  # @param [String] name name of the application to launch
71
76
  # @return [AX::Application,nil]
72
77
  def application_with_name name
73
- $stderr.puts 'DEPRECATED: Use AX::Application.new instead'
78
+ $stderr.puts "#{__method__} is DEPRECATED: Use AX::Application.new instead"
74
79
  AX::Application.new name
75
80
  end
76
81
 
@@ -83,12 +88,24 @@ class << Accessibility
83
88
  # Find out if the app is running and if so, return the running application
84
89
  # for that bundle.
85
90
  #
86
- # @param [String]
91
+ # @param bundle [String]
87
92
  # @return [NSRunningApplication,nil]
88
93
  def app_running? bundle
89
94
  NSRunningApplication.runningApplicationsWithBundleIdentifier(bundle).first
90
95
  end
91
96
 
97
+ ##
98
+ # Try to wrap an application object, just in case it is not quite ready
99
+ # for accessibility yet.
100
+ #
101
+ # @param [String]
102
+ # @return [AX::Application]
103
+ def try_wrapping bundle
104
+ AX::Application.new bundle
105
+ rescue RuntimeError
106
+ nil
107
+ end
108
+
92
109
  ##
93
110
  # Asynchronously launch an application given the bundle identifier.
94
111
  #