AXElements 0.6.0beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/.yardopts +20 -0
  2. data/LICENSE.txt +25 -0
  3. data/README.markdown +150 -0
  4. data/Rakefile +109 -0
  5. data/docs/AccessibilityTips.markdown +119 -0
  6. data/docs/Acting.markdown +340 -0
  7. data/docs/Debugging.markdown +326 -0
  8. data/docs/Inspecting.markdown +255 -0
  9. data/docs/KeyboardEvents.markdown +57 -0
  10. data/docs/NewBehaviour.markdown +151 -0
  11. data/docs/Notifications.markdown +271 -0
  12. data/docs/Searching.markdown +250 -0
  13. data/docs/TestingExtensions.markdown +52 -0
  14. data/docs/images/AX.png +0 -0
  15. data/docs/images/all_the_buttons.jpg +0 -0
  16. data/docs/images/ui_hierarchy.dot +34 -0
  17. data/docs/images/ui_hierarchy.png +0 -0
  18. data/ext/key_coder/extconf.rb +6 -0
  19. data/ext/key_coder/key_coder.m +77 -0
  20. data/lib/ax_elements/accessibility/enumerators.rb +104 -0
  21. data/lib/ax_elements/accessibility/language.rb +347 -0
  22. data/lib/ax_elements/accessibility/qualifier.rb +73 -0
  23. data/lib/ax_elements/accessibility.rb +164 -0
  24. data/lib/ax_elements/core.rb +541 -0
  25. data/lib/ax_elements/element.rb +593 -0
  26. data/lib/ax_elements/elements/application.rb +88 -0
  27. data/lib/ax_elements/elements/button.rb +18 -0
  28. data/lib/ax_elements/elements/radio_button.rb +18 -0
  29. data/lib/ax_elements/elements/row.rb +30 -0
  30. data/lib/ax_elements/elements/static_text.rb +17 -0
  31. data/lib/ax_elements/elements/systemwide.rb +46 -0
  32. data/lib/ax_elements/inspector.rb +116 -0
  33. data/lib/ax_elements/macruby_extensions.rb +255 -0
  34. data/lib/ax_elements/notification.rb +37 -0
  35. data/lib/ax_elements/version.rb +9 -0
  36. data/lib/ax_elements.rb +30 -0
  37. data/lib/minitest/ax_elements.rb +19 -0
  38. data/lib/mouse.rb +185 -0
  39. data/lib/rspec/expectations/ax_elements.rb +15 -0
  40. data/test/elements/test_application.rb +72 -0
  41. data/test/elements/test_row.rb +27 -0
  42. data/test/elements/test_systemwide.rb +38 -0
  43. data/test/helper.rb +119 -0
  44. data/test/test_accessibility.rb +127 -0
  45. data/test/test_blankness.rb +26 -0
  46. data/test/test_core.rb +448 -0
  47. data/test/test_element.rb +939 -0
  48. data/test/test_enumerators.rb +81 -0
  49. data/test/test_inspector.rb +121 -0
  50. data/test/test_language.rb +157 -0
  51. data/test/test_macruby_extensions.rb +303 -0
  52. data/test/test_mouse.rb +5 -0
  53. data/test/test_search_semantics.rb +143 -0
  54. metadata +219 -0
data/.yardopts ADDED
@@ -0,0 +1,20 @@
1
+ --no-cache
2
+ --no-output
3
+ --verbose
4
+ --markup markdown
5
+ --markup-provider redcarpet
6
+ --asset docs/images:images
7
+ --readme README.markdown
8
+ lib/**/*.rb
9
+ ext/**/*.m
10
+ -
11
+ docs/Inspecting.markdown
12
+ docs/Acting.markdown
13
+ docs/Searching.markdown
14
+ docs/Notifications.markdown
15
+ docs/KeyboardEvents.markdown
16
+ docs/Debugging.markdown
17
+ docs/NewBehaviour.markdown
18
+ docs/AccessibilityTips.markdown
19
+ docs/TestingExtensions.markdown
20
+ LICENSE.txt
data/LICENSE.txt ADDED
@@ -0,0 +1,25 @@
1
+ Copyright (c) 2010-2011, Marketcircle Inc.
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+ * Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ * Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+ * Neither the name of Marketcircle Inc. nor the names of its
12
+ contributors may be used to endorse or promote products derived
13
+ from this software without specific prior written permission.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL Marketcircle Inc. BE LIABLE FOR ANY
19
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23
+ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.markdown ADDED
@@ -0,0 +1,150 @@
1
+ # AXElements
2
+
3
+ AXElements is a DSL abstraction built on top of the Mac OS X
4
+ Accessibility and CGEvent APIs that allows code to be written in a
5
+ very natural and declarative style that describes user interactions.
6
+
7
+ The framework is optimized for writing tests that require automatic
8
+ GUI manipulation, whether it be finding controls on the screen,
9
+ typing, clicking, or other ways in which a user can interact with the
10
+ computer.
11
+
12
+ ## Getting Setup
13
+
14
+ You need to have the OS X developer tools installed in build and
15
+ install AXElements (sorry). Go ahead and install the tools now if you
16
+ haven't done that yet, I'll wait.
17
+
18
+ Once, you have the developer tools, you should install MacRuby, the
19
+ latest release should be sufficient, but nightly builds are usually
20
+ safe as well. If you are on Snow Leopard, you will also need to
21
+ install the
22
+ [Bridge Support Preview](http://www.macruby.org/blog/2010/10/08/bridgesupport-preview.html).
23
+
24
+ At this point you should install development dependencies. You can do
25
+ so with `bundler` if you have it, but it will be faster to use the
26
+ `setup_dev` task that has been provided. Simply type the following in
27
+ terminal:
28
+
29
+ rake setup_dev
30
+
31
+ __NOTE__: if you are not using RVM, then you should use `macrake`
32
+ instead of `rake` for this command and anywhere else that you see
33
+ `rake` in the documentation. Also, remember that if you are not using
34
+ RVM with MacRuby but still have RVM installed then you will need to
35
+ disable RVM like so:
36
+
37
+ rvm use system
38
+
39
+ Once you are setup, you can start looking through the tutorial
40
+ documentation to show you how to use AXElements. The first tutorial is
41
+ the {file:docs/Inspecting.markdown Inspecting tutorial}. The full list
42
+ of topics include:
43
+
44
+ * {file:docs/Inspecting.markdown Inspecting}
45
+ * {file:docs/Acting.markdown Acting}
46
+ * {file:docs/Searching.markdown Searching}
47
+ * {file:docs/Notifications.markdown Notifications}
48
+ * {file:docs/KeyboardEvents.markdown Keyboard}
49
+ * {file:docs/Debugging.markdown Debugging}
50
+ * {file:docs/NewBehaviour.markdown Adding Behaviour To AXElements}
51
+ * {file:docs/AccessibilityTips.markdown Making Your Apps More Accessibile}
52
+ * {file:docs/TestingExtensions.markdown Test Suite Extensions for RSpec, Minitest, etc.}
53
+
54
+ ## Documentation
55
+
56
+ AXElements is documented using YARD, and includes a few tutorials in
57
+ the `docs/` directory. If you do not want to generate the
58
+ documentation yourself then you can go to
59
+ [rdoc.info](http://rdoc.info/gems/AXElements/frames).
60
+
61
+ Though it is not required, you may want to read Apple's
62
+ [Accessibility Overview](http://developer.apple.com/library/mac/#documentation/Accessibility/Conceptual/AccessibilityMacOSX/OSXAXModel/OSXAXmodel.html)
63
+ as a primer on some the technical underpinnings of AXElements.
64
+
65
+ ## Test Suite
66
+
67
+ Before starting development on your machine, you should run the test
68
+ suite and make sure things are kosher. The nature of this library
69
+ requires that the tests take over your computer while they run. The
70
+ tests aren't programmed to do anything destructive, but if you
71
+ interfere with them then something could go wrong.
72
+
73
+ To run the tests you simply need to run the `test` task:
74
+
75
+ rake test
76
+
77
+ __NOTE__: there may be some tests are dependent on Accessibility
78
+ features that are new in OS X Lion which will cause test failures on
79
+ OS X Snow Leopard. If you have any issues then you should look at the
80
+ output to find hints at what went wrong and/or log a bug. I will still
81
+ support Snow Leopard as long as MacRuby does, but I do not have easy
82
+ access to a Snow Leopard machine to verify that things still work.
83
+
84
+ ### Benchmarks
85
+
86
+ Benchmarks are also included as part of the test suite, but they are
87
+ disabled by default. In order to enable them you need to set the
88
+ `BENCH` environment variable:
89
+
90
+ BENCH=1 rake test
91
+
92
+ Benchmarks only exist for code that is known to be slow. I'm keeping
93
+ tabs on slow code so that I be confident about getting depressed when
94
+ it gets slower. Though, there is still room for improved performance
95
+ as well.
96
+
97
+ ## Road Map
98
+
99
+ There are still a bunch of things that could be done to improve
100
+ AXElements. The README only contains an idealized outline of some of
101
+ the high-level items that should get done in the next couple of
102
+ releases. Smaller items are peppered through the code base and marked
103
+ with `@todo` tags.
104
+
105
+ ### 0.7 (or maybe 1.0)
106
+
107
+ - Pre-loading AX hierarchy and attribute cache from
108
+ `/System/Library/Accessibility/AccessibilityDefinitions.plist`
109
+ + Not available on Snow Leopard, so it will have to wait anyways
110
+ + Probably inccurs too much overhead at boot time right now
111
+ - Make a decision about NSArray#method_missing
112
+ - Merge notifications with actions as they are commonly combined
113
+ + But how?
114
+ - Rewrite core module to handle errors more gracefully
115
+ - Mouse module cleanup and regression testing
116
+ - Test suite deduplication cleanup and better isolation
117
+ - Performance tweaks
118
+ - The OO abstraction leaks in a few places, code needs to be
119
+ refactored without hurting performance too much
120
+ - Test framework helpers
121
+ + Minitest
122
+ + RSpec
123
+ - Thread Safety
124
+ + Only if it becomes an issue, otherwise it might be better to
125
+ forget thread safey to simplify and optimize existing code
126
+
127
+ ### Future
128
+
129
+ - Screenshot taking and diff'ing abilities for those rare cases when
130
+ you need it
131
+ - Address Book helpers, and other friends
132
+
133
+ ## Contributing to AXElements
134
+
135
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
136
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
137
+ * Fork the project
138
+ * Start a feature/bugfix branch
139
+ * Commit and push until you are happy with your contribution
140
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
141
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
142
+
143
+ ## Copyright
144
+
145
+ Copyright (c) 2010-2011 Marketcircle Incorporated. All rights
146
+ reserved.
147
+
148
+ AXElements is available under the standard 3-clause BSD license. See
149
+ {file:LICENSE.txt LICENSE.txt} for further details.
150
+
data/Rakefile ADDED
@@ -0,0 +1,109 @@
1
+ require 'rubygems'
2
+
3
+ task :default => :gem
4
+ task :clean => :clobber
5
+
6
+ def safe_require path, name
7
+ require path
8
+ yield
9
+ rescue LoadError => e
10
+ $stderr.puts "It seems as though you do not have #{name} installed."
11
+ command = ENV['RUBY_VERSION'] ? 'gem' : 'sudo macgem'
12
+ $stderr.puts "You can install it by running `#{command} install #{name}`."
13
+ end
14
+
15
+
16
+ ## Documentation
17
+
18
+ safe_require 'yard', 'yard' do
19
+ YARD::Rake::YardocTask.new
20
+ end
21
+
22
+ desc 'Generate Graphviz object graph'
23
+ task :garden => :yard do
24
+ sh 'yard graph --full --dependencies --dot="-Tpng:quartz" -f docs/images/AX.dot'
25
+ end
26
+
27
+ ## Console
28
+
29
+ desc 'Start up irb with AXElements loaded'
30
+ task :console => :ext do
31
+ irb = ENV['RUBY_VERSION'] ? 'irb' : 'macirb'
32
+ sh "#{irb} -Ilib -Iext/key_coder -rubygems -rax_elements"
33
+ end
34
+
35
+ ## Compilation
36
+
37
+ require 'rake/compiletask'
38
+ Rake::CompileTask.new
39
+
40
+ desc 'Compile C extensions'
41
+ task :ext do
42
+ Dir.chdir 'ext/key_coder' do
43
+ break if File.exists?('key_coder.bundle') && File.mtime('key_coder.bundle') > File.mtime('key_coder.m')
44
+ ruby 'extconf.rb'
45
+ sh 'make'
46
+ end
47
+ end
48
+
49
+ desc 'Clean temporary files created by the C extension'
50
+ task :clobber_ext do
51
+ Dir.chdir 'ext/key_coder' do
52
+ ['Makefile', 'key_coder.o', 'key_coder.bundle'].each do |file|
53
+ $stdout.puts "rm ext/key_coder/#{file}"
54
+ rm file
55
+ end
56
+ end
57
+ end
58
+ task :clobber => :clobber_ext
59
+
60
+ ## Testing
61
+
62
+ desc 'Open the fixture app'
63
+ task :run_fixture => :fixture do
64
+ sh 'open test/fixture/Release/AXElementsTester.app'
65
+ end
66
+
67
+ desc 'Build the test fixture'
68
+ task :fixture do
69
+ sh 'cd test/AXElementsTester && xcodebuild'
70
+ end
71
+
72
+ require 'rake/testtask'
73
+ Rake::TestTask.new(:test) do |t|
74
+ t.libs << 'test' << 'ext/key_coder'
75
+ t.pattern = 'test/**/test_*.rb'
76
+ t.ruby_opts = ['-rhelper']
77
+ t.verbose = true
78
+ end
79
+ task :test => [:ext, :fixture]
80
+
81
+ ## Gem Packaging
82
+ require 'rubygems/dependency_installer'
83
+ require 'rake/gempackagetask'
84
+
85
+ spec = Gem::Specification.load('AXElements.gemspec')
86
+
87
+ Rake::GemPackageTask.new(spec) { }
88
+
89
+ # This only installs this gem, it does not take deps into consideration
90
+ desc 'Build gem and install it'
91
+ task :install => :gem do
92
+ Gem::Installer.new("pkg/#{spec.file_name}").install
93
+ end
94
+
95
+ desc 'Install dependencies for a test node'
96
+ task :setup_node do
97
+ spec.runtime_dependencies.each do |dep|
98
+ puts "Installing #{dep.name}"
99
+ Gem::DependencyInstaller.new.install(dep.name, dep.requirement)
100
+ end
101
+ end
102
+
103
+ desc 'Install dependencies for development'
104
+ task :setup_dev => :setup_node do
105
+ spec.development_dependencies.each do |dep|
106
+ puts "Installing #{dep.name}"
107
+ Gem::DependencyInstaller.new.install(dep.name, dep.requirement)
108
+ end
109
+ end
@@ -0,0 +1,119 @@
1
+ # Accessibility Tips
2
+
3
+ This document includes tips for customizing accessibility in your own
4
+ applications. The goal is to inform you of pitfalls that are not
5
+ mentioned in Apple's documentation. It also includes notes on how to
6
+ avoid making decsions that will make an application incompatible with
7
+ AXElements.
8
+
9
+ @todo This document is under construction and is currently just a set
10
+ of notes and unorganized sections ripped from other documents.
11
+
12
+ ## Guidelines
13
+
14
+ When implementing custom accessibility roles, you should never use a
15
+ pluralized name for the role. A role that is already pluralized will
16
+ break search.
17
+
18
+
19
+ ## Adding new stuff
20
+
21
+ Adding new attributes to an object is very simple...usually. Most of
22
+ the time it is as simple as overriding two methods:
23
+
24
+ - `accessibilityAttributeNames`
25
+ - `accessibilityAttributeValue:`
26
+
27
+ `accessibilityAttributeNames` needs to return an array with the names
28
+ of available attributes. You should call `super` to get the existing
29
+ array first, and then append any custom attributes you want to
30
+ provide.
31
+
32
+ An attribute name must follow the convention of being a camel cased
33
+ string with the "AX" prefix, such as `AXTitle`. You can optionally
34
+ include an additional prefix before "AX", such as "MCAX" for
35
+ Marketcircle custom attributes. If you do not follow these rules then
36
+ attribute names will not be translated properly by AXElements.
37
+
38
+ `accessibilityAttributeValue:` is how you actually provide the value
39
+ for the attribute; the parameter for this method is the name of the
40
+ attribute fetched from calling `accessibilityAttributeNames`. You
41
+ should return the value without doing any extra work to the data; the
42
+ Accessibility interface will do any wrapping or translating for
43
+ you (e.g. CGPoint objects will have co-ordinates flipped). In the case
44
+ of a C structs you should leave them wrapped in an NSValue object.
45
+
46
+ Similarly, parameterized attributes are added using methods with
47
+ `Parameter` in the name. The method for getting the value of a
48
+ parameterized attribute will of course take an extra parameter for the
49
+ parameterized attributes parameter.
50
+
51
+ ### Where To Implement The Methods
52
+
53
+ The difficulty in adding attributes lies in finding out where you need
54
+ to add the accessibility methods. Often, the class that implements
55
+ accessibility is the class that draws the user interface element. For
56
+ example, the accessibility information for a button is implemented on
57
+ the button cell and not the button itself. Since Apple is under the
58
+ delusion that you will never need to add any custom accessibility
59
+ information, they really don't document these customizations enough,
60
+ and so this document only includes caveats that have been discovered
61
+ so far.
62
+
63
+ It is often inconvenient to subclass the cell for an object just for
64
+ accessibility. In these cases Apple has provided something similar to
65
+ singleton methods, but less useful, with the
66
+ `accessibilitySetOverrideValue:forAttribute:` method. You can use the
67
+ method to override an attribute or even add a new one. The main issue
68
+ with this method is that any attribute that is overridden, or added,
69
+ will not be writable using the accessibility APIs. Another issue is
70
+ that you have to calculate the value when you override instead of when
71
+ the attribute value is queried by the client.
72
+
73
+ ### Writability
74
+
75
+ In the case where it is convenient to be able to change an attribute's
76
+ value through accessibility, like the size of a window, you will also
77
+ need to implement two more methods for the attribute:
78
+
79
+ - `accessibilityIsAttributeSettable:`
80
+ - `accessibilitySetValue:forAttribute:`
81
+
82
+ `accessibilityIsAttributeSettable:` simply responds with whether or
83
+ not the attribute is writable, and
84
+ `accessibilitySetValue:forAttribute:` will be called to actually write
85
+ to the attribute.
86
+
87
+ ### Remember `super`
88
+
89
+ It is important to remember that these methods are already implemented
90
+ for the built in features. When overriding, you should only implement
91
+ the custom behaviour and call `super` to handle everything else.
92
+
93
+ ### Existing Definitions
94
+
95
+ When implementing custom behaviour, you should try and use
96
+ pseudoclasses that have already been defined by Apple, as well as
97
+ attributes, parameterized attributes, and other features that have
98
+ already been defined. Apple maintains the documentation for all their
99
+ definitions on
100
+ [here](http://developer.apple.com/library/mac/#documentation/UserExperience/Reference/Accessibility_RoleAttribute_Ref/Introduction.html#//apple_ref/doc/uid/TP40007870).
101
+ The documentation is fairly detailed now (moreso than before), but
102
+ still misses a few things.
103
+
104
+
105
+ ## Adding Accessibility Actions
106
+
107
+ If you have access to the source code for an app, you can add more
108
+ accessibility actions. You need to override two methods, just like
109
+ with adding attributes:
110
+
111
+ – `accessibilityActionNames`
112
+ – `accessibilityPerformAction:`
113
+
114
+ These methods should be implemented in the same way that you would
115
+ implement new attributes, just as detailed in the
116
+ {file:docs/Inspecting.markdown Inspecting tutorial}. The one
117
+ difference is that `accessibilityPerformAction:` should not return
118
+ anything after it performs the action.
119
+