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.
- data/.yardopts +4 -0
- data/History.markdown +41 -0
- data/README.markdown +59 -62
- data/Rakefile +1 -1
- data/ext/accessibility/key_coder/extconf.rb +1 -1
- data/ext/accessibility/key_coder/key_coder.c +8 -5
- data/lib/accessibility/dsl.rb +261 -87
- data/lib/accessibility/enumerators.rb +14 -11
- data/lib/accessibility/errors.rb +4 -3
- data/lib/accessibility/factory.rb +159 -108
- data/lib/accessibility/graph.rb +13 -9
- data/lib/accessibility/{pp_inspector.rb → pretty_printer.rb} +4 -5
- data/lib/accessibility/qualifier.rb +23 -13
- data/lib/accessibility/string.rb +4 -4
- data/lib/accessibility/system_info.rb +230 -0
- data/lib/accessibility/translator.rb +38 -28
- data/lib/accessibility/version.rb +24 -2
- data/lib/accessibility.rb +25 -8
- data/lib/ax/application.rb +207 -77
- data/lib/ax/element.rb +62 -65
- data/lib/ax/menu.rb +5 -1
- data/lib/ax/row.rb +1 -1
- data/lib/ax/scroll_area.rb +7 -6
- data/lib/ax/systemwide.rb +38 -5
- data/lib/ax_elements/active_support_selections.rb +10 -0
- data/lib/ax_elements/mri.rb +57 -0
- data/lib/ax_elements/nsarray_compat.rb +97 -17
- data/lib/ax_elements.rb +9 -1
- data/rakelib/gem.rake +11 -11
- data/rakelib/test.rake +0 -9
- data/test/helper.rb +10 -18
- data/test/integration/accessibility/test_dsl.rb +52 -42
- data/test/integration/accessibility/test_enumerators.rb +0 -1
- data/test/integration/accessibility/test_graph.rb +1 -0
- data/test/integration/accessibility/test_qualifier.rb +2 -2
- data/test/integration/ax/test_application.rb +9 -2
- data/test/integration/ax/test_element.rb +41 -1
- data/test/sanity/accessibility/test_factory.rb +23 -56
- data/test/sanity/accessibility/{test_pp_inspector.rb → test_pretty_printer.rb} +9 -9
- data/test/sanity/accessibility/test_translator.rb +2 -5
- data/test/sanity/accessibility/test_version.rb +15 -0
- data/test/sanity/ax/test_application.rb +17 -2
- data/test/sanity/ax/test_element.rb +2 -2
- data/test/sanity/ax_elements/test_nsobject_inspect.rb +4 -2
- data/test/sanity/test_ax_elements.rb +1 -0
- metadata +69 -39
- data/lib/accessibility/core.rb +0 -973
- data/lib/accessibility/highlighter.rb +0 -86
- data/lib/ax_elements/vendor/inflection_data.rb +0 -66
- data/lib/ax_elements/vendor/inflections.rb +0 -172
- data/lib/ax_elements/vendor/inflector.rb +0 -306
- data/lib/minitest/ax_elements.rb +0 -175
- data/lib/mouse.rb +0 -223
- data/lib/rspec/expectations/ax_elements.rb +0 -234
- data/test/integration/accessibility/test_core.rb +0 -18
- data/test/integration/minitest/test_ax_elements.rb +0 -89
- data/test/integration/rspec/expectations/test_ax_elements.rb +0 -102
- data/test/sanity/accessibility/test_core.rb +0 -561
- data/test/sanity/accessibility/test_highlighter.rb +0 -56
- data/test/sanity/minitest/test_ax_elements.rb +0 -17
- data/test/sanity/rspec/expectations/test_ax_elements.rb +0 -15
- 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 '
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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] =
|
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
|
-
|
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
|
-
|
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] =
|
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] =
|
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.
|
7
|
+
VERSION = '0.9.0'
|
8
|
+
|
9
|
+
# @return [String]
|
10
|
+
CODE_NAME = 'エネコロロ'
|
6
11
|
|
7
12
|
# @return [String]
|
8
|
-
|
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
|
-
# @
|
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
|
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.
|
44
|
+
# application_with_bundle_identifier 'com.marketcircle.Daylite4'
|
44
45
|
#
|
45
|
-
# @param [String]
|
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
|
-
|
51
|
-
|
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
|
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
|
#
|