AXElements 1.0.0.beta4 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/History.markdown +7 -0
  3. data/README.markdown +41 -29
  4. data/Rakefile +1 -6
  5. data/lib/accessibility/dsl.rb +17 -15
  6. data/lib/accessibility/pretty_printer.rb +40 -12
  7. data/lib/accessibility/system_info.rb +2 -0
  8. data/lib/accessibility/text_highlighter.rb +73 -0
  9. data/lib/accessibility/translator.rb +1 -0
  10. data/lib/accessibility/version.rb +1 -1
  11. data/lib/accessibility.rb +13 -114
  12. data/lib/ax/application.rb +54 -42
  13. data/lib/ax/element.rb +27 -7
  14. data/lib/ax/scroll_area.rb +1 -0
  15. data/lib/ax/systemwide.rb +5 -4
  16. data/lib/ax/text_area.rb +16 -0
  17. data/lib/ax/text_field.rb +10 -0
  18. data/lib/ax_elements/mri.rb +36 -1
  19. data/rakelib/ci.rake +9 -0
  20. data/rakelib/doc.rake +4 -13
  21. data/rakelib/ext.rake +1 -57
  22. data/rakelib/gem.rake +7 -23
  23. data/rakelib/test.rake +10 -17
  24. data/test/helper.rb +15 -18
  25. data/test/integration/accessibility/test_dsl.rb +9 -3
  26. data/test/integration/ax/test_application.rb +1 -1
  27. data/test/integration/ax/test_text_area.rb +62 -0
  28. data/test/integration/ax/test_text_field.rb +49 -0
  29. data/test/sanity/accessibility/test_dsl.rb +1 -0
  30. data/test/sanity/accessibility/test_errors.rb +1 -1
  31. data/test/sanity/accessibility/test_pretty_printer.rb +6 -1
  32. data/test/sanity/accessibility/test_qualifier.rb +1 -1
  33. data/test/sanity/accessibility/test_system_info.rb +109 -0
  34. data/test/sanity/accessibility/test_translator.rb +1 -1
  35. data/test/sanity/accessibility/test_version.rb +2 -2
  36. data/test/sanity/ax_elements/test_nsarray_compat.rb +1 -1
  37. data/test/sanity/ax_elements/test_nsobject_inspect.rb +1 -1
  38. data/test/sanity/test_ax_elements.rb +1 -1
  39. metadata +34 -59
  40. data/ext/accessibility/key_coder/extconf.rb +0 -22
  41. data/ext/accessibility/key_coder/key_coder.c +0 -123
  42. data/lib/accessibility/string.rb +0 -502
  43. data/test/sanity/accessibility/test_string.rb +0 -238
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0b61857f042227f18716780302b724e51803461f
4
+ data.tar.gz: 24308e7efc98e7ad11047e4a68099303a556c095
5
+ SHA512:
6
+ metadata.gz: 38c616f7f1d5ad7982ba5fc836dc803fdab4cf70d378d1c4898755a6f69f5344af71043f8b082a84c437545cc3eb978850a5a1b60646933fb3051484cd860a2f
7
+ data.tar.gz: 023fa8b38c431e9d9a2ac335a6e07ae111eb27f33819b6dcd0595196c30205b34fa98a2d98141565773ea9973b5a33184b348ed8bd81af284c0b7b53d3b87abc
data/History.markdown CHANGED
@@ -1,3 +1,10 @@
1
+ # 6.0.0
2
+
3
+ * Compatability with Sea Lion (OS X 10.9)
4
+ - You can no longer send simulated input directly to an object,
5
+ we now approximate the old behaviour by trying to set focus
6
+ to the element before simulating system wide input
7
+
1
8
  # 0.9.0
2
9
 
3
10
  * AXElements can now run on MRI as well as MacRuby
data/README.markdown CHANGED
@@ -24,12 +24,12 @@ The code from the demo video is right here:
24
24
  Accessibility.debug = true
25
25
 
26
26
  # Get a reference to the Finder and bring it to the front
27
- finder = app_with_bundle_identifier 'com.apple.finder'
27
+ finder = AX::Application.new 'com.apple.finder'
28
28
  set_focus_to finder
29
29
 
30
30
  # Open a new window
31
31
  type "\\COMMAND+n"
32
- sleep 1 # pause for "slow motion"
32
+ sleep 1 # pause for "slow motion" effect
33
33
 
34
34
  # Find and click the "Applications" item in the sidebar
35
35
  window = finder.main_window
@@ -64,12 +64,31 @@ The code from the demo video is right here:
64
64
 
65
65
  ## Getting Setup
66
66
 
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
71
- [Setup MacRuby](https://github.com/MacRuby/MacRuby/wiki/Setting-up-MacRuby)
72
- guide on Github.
67
+ If you are running OS X 10.9 (Sea Lion) or newer, all you need are the
68
+ command line tools, and then you can install AXElements:
69
+
70
+ ```bash
71
+ xcode-select --install # if you need to install the command line tools
72
+
73
+ sudo gem install AXElements
74
+ ```
75
+
76
+ Alternatively, if you know how to change your `$GEM_HOME`, then you can
77
+ install AXElements without using `sudo`.
78
+
79
+ You will be asked to "Grant access" for Accessibility to Terminal.app
80
+ when you first try using AXElements. Make sure you select Terminal in
81
+ the list on the right, and then AXElements should work without requiring
82
+ you to grant further permissions:
83
+
84
+ ![Grant Access](http://axelements.com/images/access.png)
85
+
86
+ ![How To Grant Access](http://axelements.com/images/privacy_prefs.png)
87
+
88
+ For older versions of OS X, you will need to install a compatible version
89
+ of Ruby along with the Developer tools. Supported Rubies are:
90
+
91
+ - [Ruby 1.9.4+](http://www.ruby-lang.org/)
73
92
 
74
93
  You will also need to make sure you "enable access for assistive devices".
75
94
  This can be done in System Preferences in the Universal Access section:
@@ -80,15 +99,20 @@ Then you can install AXElements either from RubyGems or from source. The
80
99
  RubyGems install is as usual, but you may need `sudo` power:
81
100
 
82
101
  ```bash
83
- gem install AXElements --pre
102
+ gem install AXElements
84
103
  ```
85
104
 
86
- Or you can install from source:
105
+
106
+ ### Install From Source
107
+
108
+ If the gem install processes are not working for you, you can build
109
+ AXElements from source, but you will need to be familiar with tools
110
+ like `bundler` and `rake`.
87
111
 
88
112
  ```bash
89
113
  cd ~/Documents # or where you want to put the AXElements code
90
- git clone git://github.com/Marketcircle/AXElements
91
- cd AXElements && rake install
114
+ git clone git://github.com/AXElements/AXElements
115
+ cd AXElements && bundle install && rake install
92
116
  ```
93
117
 
94
118
  Once all the setup is finished, you can start up AXElements in IRB:
@@ -97,20 +121,10 @@ Once all the setup is finished, you can start up AXElements in IRB:
97
121
  irb -rubygems -rax_elements
98
122
  ```
99
123
 
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:
105
-
106
- ```bash
107
- rvm use system
108
- ```
109
-
110
124
 
111
125
  ## Getting Started
112
126
 
113
- The [wiki](http://github.com/Marketcircle/AXElements/wiki)
127
+ The [wiki](http://github.com/AXElements/AXElements/wiki)
114
128
  is the best place to get started, it includes tutorials to help you get
115
129
  started. API documentation is also available on
116
130
  [rdoc.info](http://rdoc.info/gems/AXElements/frames).
@@ -123,13 +137,14 @@ as some of the technical the technical underpinnings of AXElements.
123
137
 
124
138
  ## Development
125
139
 
126
- [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/Marketcircle/AXElements)
140
+ [![Dependency Status](https://gemnasium.com/AXElements/AXElements.png)](https://gemnasium.com/AXElements/AXElements)
141
+ [![Code Climate](https://codeclimate.com/github/AXElements/AXElements.png)](https://codeclimate.com/github/AXElements/AXElements)
127
142
 
128
143
  AXElements has reached a point where the main focus is stability,
129
144
  documentation, and additional conveniences. It will be out of this
130
145
  world, so we're code naming the next version "Lunatone".
131
146
 
132
- ![The Moon](https://github.com/Marketcircle/AXElements/raw/gh-pages/images/next_version.png)
147
+ ![The Moon](https://raw.github.com/AXElements/axelements.github.com/master/images/next_version.png)
133
148
 
134
149
  Proper releases to rubygems will be made as milestones are reached.
135
150
 
@@ -137,7 +152,7 @@ Proper releases to rubygems will be made as milestones are reached.
137
152
 
138
153
  There are still a bunch of things that could be done to improve
139
154
  AXElements. Some of the higher level tasks are outlined in various
140
- [Github Issues](http://github.com/Marketcircle/AXElements/issues).
155
+ [Github Issues](http://github.com/AXElements/AXElements/issues).
141
156
  Smaller items are peppered through the code base and marked with `@todo`
142
157
  tags.
143
158
 
@@ -155,9 +170,6 @@ you simply need to run the `test` task:
155
170
  rake test
156
171
  ```
157
172
 
158
- If there is a test that crashes MacRuby then you will need to run tests
159
- in verbose mode.
160
-
161
173
  __NOTE__: There may be some tests are dependent on Accessibility
162
174
  features that are new in OS X Lion which will cause test failures on
163
175
  OS X Snow Leopard. If you have any issues then you should look at the
data/Rakefile CHANGED
@@ -3,12 +3,7 @@ require 'rubygems'
3
3
  task :default => :test
4
4
 
5
5
  desc 'Remove all generated files'
6
- task :clean => :clobber
7
- desc 'Remove all generated files'
8
- task :clobber => :clobber_ext
9
-
10
- desc 'Compile C extensions'
11
- task :ext => 'ext:key_coder'
6
+ task :clean => :clobber
12
7
 
13
8
  desc 'Run all tests'
14
9
  task :test => ['test:sanity', 'test:integration']
@@ -165,6 +165,9 @@ module Accessibility::DSL
165
165
  end
166
166
 
167
167
  ##
168
+ # @todo Introduce a method to set focus to closest ancestor that
169
+ # supports focus.
170
+ #
168
171
  # Focus an element on the screen, but only if it can be directly
169
172
  # focused. It is safe to pass any element into this method as nothing
170
173
  # will happen if it does not have a writable focused state attribute.
@@ -448,26 +451,25 @@ module Accessibility::DSL
448
451
  # all search results have been returned.
449
452
  #
450
453
  # @overload wait_for_invalidation_of element
451
- # @param element [AX::Element]
452
- # @param filters [Hash]
453
- # @option filters [Number] :timeout (5) in seconds
454
- # @return [Boolean]
454
+ # @param element [AX::Element]
455
+ # @param filters [Hash]
456
+ # @option filters [Number] :timeout (5) in seconds
457
+ # @return [Boolean]
455
458
  #
456
- # @example
459
+ # @example
457
460
  #
458
- # wait_for_invalidation_of table.row(static_text: { value: 'Cake' })
461
+ # wait_for_invalidation_of table.row(static_text: { value: 'Cake' })
459
462
  #
460
463
  # @overload wait_for_invalidation_of kind, filters = {}, &block
461
- # @param element [#to_s]
462
- # @param filters [Hash]
463
- # @option filters [Number] :timeout (5) in seconds
464
- # @return [Boolean]
464
+ # @param element [#to_s]
465
+ # @param filters [Hash]
466
+ # @option filters [Number] :timeout (5) in seconds
467
+ # @return [Boolean]
465
468
  #
466
- # @example
469
+ # @example
467
470
  #
468
- # wait_for_invalidation_of :row, parent: table, static_text: { value: 'Cake' }
471
+ # wait_for_invalidation_of :row, parent: table, static_text: { value: 'Cake' }
469
472
  #
470
- # @return [Boolean]
471
473
  def wait_for_invalidation_of element, filters = {}, &block
472
474
  timeout = filters[:timeout] || 5
473
475
  start = Time.now
@@ -769,13 +771,13 @@ module Accessibility::DSL
769
771
  # # highlighter automatically turns off after 5 seconds
770
772
  # highlight window.outline.row, colour: NSColor.greenColor, timeout: 5
771
773
  #
772
- # @param obj [#bounds]
774
+ # @param obj [#to_rect]
773
775
  # @param opts [Hash]
774
776
  # @option opts [Number] :timeout
775
777
  # @option opts [NSColor] :colour (NSColor.magentaColor)
776
778
  # @return [Accessibility::Highlighter]
777
779
  def highlight obj, opts = {}
778
- Accessibility::Highlighter.new obj.bounds, opts
780
+ Accessibility::Highlighter.new obj, opts
779
781
  end
780
782
 
781
783
  ##
@@ -58,12 +58,11 @@ module Accessibility::PrettyPrinter
58
58
  #
59
59
  # @return [String]
60
60
  def pp_position
61
- position = attribute :position
62
- if position
63
- " (#{position.x}, #{position.y})"
64
- else
65
- EMPTY_STRING
61
+ if attributes.include? :position
62
+ position = attribute :position
63
+ return " (#{position.x}, #{position.y})" if position
66
64
  end
65
+ EMPTY_STRING
67
66
  end
68
67
 
69
68
  ##
@@ -72,14 +71,13 @@ module Accessibility::PrettyPrinter
72
71
  #
73
72
  # @return [String]
74
73
  def pp_children
75
- child_count = size_of :children
76
- if child_count > 1
77
- " #{child_count} children"
78
- elsif child_count == 1
79
- ONE_CHILD
80
- else # there are some odd edge cases
81
- EMPTY_STRING
74
+ if attributes.include? :children
75
+ child_count = size_of :children
76
+ return " #{child_count} children" if child_count > 1
77
+ return ONE_CHILD if child_count == 1
78
+ # there are some odd edge cases where 0 children are reported
82
79
  end
80
+ EMPTY_STRING
83
81
  end
84
82
 
85
83
  ##
@@ -93,6 +91,36 @@ module Accessibility::PrettyPrinter
93
91
  " #{attr}[#{attribute(attr) ? CHECKMARK : CROSS }]"
94
92
  end
95
93
 
94
+ ##
95
+ # Safely create a {pp_checkbox} for the `KAXEnabledAttribute`
96
+ #
97
+ # If the receiver does not have the attribute then an empty
98
+ # string will be returned.
99
+ #
100
+ # @return [String]
101
+ def pp_enabled
102
+ if attributes.include? :enabled
103
+ pp_checkbox(:enabled)
104
+ else
105
+ EMPTY_STRING
106
+ end
107
+ end
108
+
109
+ ##
110
+ # Safely create a {pp_checkbox} for the `KAXFocusedAttribute`
111
+ #
112
+ # If the receiver does not have the attribute then an empty
113
+ # string will be returned.
114
+ #
115
+ # @return [String]
116
+ def pp_focused
117
+ if attributes.include? :focused
118
+ pp_checkbox(:focused)
119
+ else
120
+ EMPTY_STRING
121
+ end
122
+ end
123
+
96
124
 
97
125
  private
98
126
 
@@ -138,6 +138,7 @@ module Accessibility::SystemInfo
138
138
  def num_processors
139
139
  NSProcessInfo.processInfo.processorCount
140
140
  end
141
+ alias_method :number_of_processors, :num_processors
141
142
 
142
143
  ##
143
144
  # Number of CPUs the system current has enabled
@@ -150,6 +151,7 @@ module Accessibility::SystemInfo
150
151
  def num_active_processors
151
152
  NSProcessInfo.processInfo.activeProcessorCount
152
153
  end
154
+ alias_method :number_of_active_processors, :num_active_processors
153
155
 
154
156
  ##
155
157
  # Total amount of memory for the system, in bytes
@@ -0,0 +1,73 @@
1
+ require 'accessibility/version'
2
+ require 'mouse'
3
+
4
+ ##
5
+ # Mix-in module
6
+ module Accessibility::TextHighlighter
7
+
8
+ ##
9
+ # @note The implementation of this code makes assumptions about the
10
+ # minimum size of text and may not work with very small fonts.
11
+ #
12
+ # Highlights text in the field/area that matches the given `text`
13
+ #
14
+ # The given `text` can be a `String`, `Range`, or `Regexp` that
15
+ # matches some range of text in the receiver. An exception will
16
+ # be raised if the `text` is not valid for any reason.
17
+ #
18
+ # @example
19
+ #
20
+ # text_field.highlight_text(0..5); type "\\DELETE"
21
+ # text_area.highligtht_text("W"); type "W"
22
+ # text_field.highlight_text(/is a lie?/i); type "is delicious and moist"
23
+ #
24
+ # @param text [String,Regexp,Range]
25
+ def highlight_text text
26
+ text = highlighter_range_for(text).to_a
27
+
28
+ head = parameterized_attribute(:bounds_for_range, text.first..text.first)
29
+ tail = parameterized_attribute(:bounds_for_range, text.last..text.last)
30
+
31
+ if Accessibility.debug?
32
+ highlight head, timeout: 5, colour: NSColor.yellowColor
33
+ highlight tail, timeout: 5, colour: NSColor.brownColor
34
+ end
35
+
36
+ head_point = head.origin
37
+ head_point.x += 1
38
+ head_point.y += 1
39
+ click
40
+
41
+ tail_point = tail.origin
42
+ tail_point.x += tail.size.width - 1
43
+ tail_point.y += tail.size.height - 1
44
+ drag_mouse_to tail_point
45
+ end
46
+
47
+
48
+ private
49
+
50
+ def highlighter_range_for text
51
+ value = @ref.value
52
+
53
+ case text
54
+ when Regexp
55
+ match = value.match text
56
+ if match
57
+ pair = match.offset(0)
58
+ pair[1] -= 1
59
+ pair
60
+ end
61
+ when String
62
+ start = value.index text
63
+ [start, start.to_i + text.length - 1]
64
+ when Range
65
+ text
66
+ else
67
+ raise ArgumentError,
68
+ "Cannot figure out what to highlight given #{text.inspect}"
69
+ end
70
+ end
71
+
72
+
73
+ end
@@ -7,6 +7,7 @@ ActiveSupport::Inflector.inflections do |inflect|
7
7
  inflect.acronym('UI')
8
8
  inflect.acronym('RTF')
9
9
  inflect.acronym('URL')
10
+ inflect.acronym('AMPM')
10
11
  end
11
12
 
12
13
  framework 'ApplicationServices' if on_macruby?
@@ -4,7 +4,7 @@
4
4
  # The main AXElements namespace.
5
5
  module Accessibility
6
6
  # @return [String]
7
- VERSION = '1.0.0.beta4'
7
+ VERSION = '6.0.0'
8
8
 
9
9
  # @return [String]
10
10
  CODE_NAME = case RUBY_ENGINE
data/lib/accessibility.rb CHANGED
@@ -1,121 +1,20 @@
1
1
  require 'accessibility/version'
2
- require 'ax/application'
3
2
 
4
- class << Accessibility
3
+ module Accessibility
4
+
5
+ class << self
6
+ ##
7
+ # Whether or not to turn on DEBUG features in AXElements. The
8
+ # value is initially inherited from `$DEBUG` but can be overridden
9
+ # by an environment variable named `AXDEBUG` or changed dynamically
10
+ # at runtime.
11
+ #
12
+ # @return [Boolean]
13
+ attr_accessor :debug
14
+ alias_method :debug?, :debug
15
+ end
5
16
 
6
17
  # Initialize the DEBUG value
7
18
  @debug = ENV.fetch 'AXDEBUG', $DEBUG
8
19
 
9
- ##
10
- # Whether or not to turn on DEBUG features in AXElements. The
11
- # value is initially inherited from `$DEBUG` but can be overridden
12
- # by an environment variable named `AXDEBUG` or changed dynamically
13
- # at runtime.
14
- #
15
- # @return [Boolean]
16
- attr_accessor :debug
17
- alias_method :debug?, :debug
18
-
19
-
20
- # @group Finding an application object
21
-
22
- ##
23
- # @note Bundle identifiers are case-sensitive.
24
- # @deprecated Use {AX::Aplication#initialize} instead.
25
- #
26
- # This is the standard way of creating an application object. It will
27
- # launch the app if it is not already running and create the
28
- # accessibility object.
29
- #
30
- # However, this method is a bit of a hack in cases where the app is not
31
- # already running; I've tried to register for notifications, launch
32
- # synchronously, etc., but there is always a problem with accessibility
33
- # not being ready right away.
34
- #
35
- # If this method fails to find an app with the appropriate bundle
36
- # identifier then it will raise an exception. If the problem was not a
37
- # typo, then it might mean that the bundle identifier has not been
38
- # registered with the system yet and you should launch the app once
39
- # manually.
40
- #
41
- # @example
42
- #
43
- # application_with_bundle_identifier 'com.apple.mail' # wait a few seconds
44
- # application_with_bundle_identifier 'com.marketcircle.Daylite4'
45
- #
46
- # @param bundle [String] a bundle identifier
47
- # @return [AX::Application,nil]
48
- def application_with_bundle_identifier bundle
49
- $stderr.puts "#{__method__} is DEPRECATED: Use AX::Application.new instead"
50
- if app_running?(bundle) || launch_application(bundle)
51
- 10.times do
52
- if app_running?(bundle) && (app = try_wrapping(bundle))
53
- return app
54
- else
55
- sleep 1
56
- end
57
- end
58
- else
59
- raise ArgumentError, "Could not launch app matching bundle id `#{bundle}'"
60
- end
61
- nil
62
- end
63
-
64
- ##
65
- # @deprecated Directly initialize an {AX::Application} instance instead
66
- # (e.g. `AX::Application.new('Terminal')`).
67
- #
68
- # Get the accessibility object for an application given its localized
69
- # name. This will only work if the application is already running.
70
- #
71
- # @example
72
- #
73
- # application_with_name 'Mail'
74
- #
75
- # @param [String] name name of the application to launch
76
- # @return [AX::Application,nil]
77
- def application_with_name name
78
- $stderr.puts "#{__method__} is DEPRECATED: Use AX::Application.new instead"
79
- AX::Application.new name
80
- end
81
-
82
- # @endgroup
83
-
84
-
85
- private
86
-
87
- ##
88
- # Find out if the app is running and if so, return the running application
89
- # for that bundle.
90
- #
91
- # @param bundle [String]
92
- # @return [NSRunningApplication,nil]
93
- def app_running? bundle
94
- NSRunningApplication.runningApplicationsWithBundleIdentifier(bundle).first
95
- end
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
-
109
- ##
110
- # Asynchronously launch an application given the bundle identifier.
111
- #
112
- # @param [String] bundle the bundle identifier for the app
113
- # @return [Boolean]
114
- def launch_application bundle
115
- NSWorkspace.sharedWorkspace.launchAppWithBundleIdentifier bundle,
116
- options: NSWorkspaceLaunchAsync,
117
- additionalEventParamDescriptor: nil,
118
- launchIdentifier: nil
119
- end
120
-
121
20
  end