accessibility_bridge 0.1.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 ADDED
@@ -0,0 +1,9 @@
1
+ --no-cache
2
+ --no-output
3
+ --verbose
4
+ --markup markdown
5
+ --markup-provider kramdown
6
+ --readme README.markdown
7
+ --hide-void-return
8
+ lib/**/*.rb
9
+ ext/**/*{.m,.c}
data/History.markdown ADDED
@@ -0,0 +1,5 @@
1
+ # v0.1.0 - Initial release
2
+
3
+ * MRI and MacRuby compatible
4
+ * Bare minimum bridging so that accessibility-core works
5
+
data/README.markdown ADDED
@@ -0,0 +1,39 @@
1
+ # accessibility\_bridge
2
+
3
+ Bare minimum bridging for MRI to easily use Cocoa objects. The intended
4
+ use for this code is as a support for other gems that require some
5
+ bridging to Cocoa stuff.
6
+
7
+ This was extracted from the
8
+ [accessibility\_core](https://github.com/AXElements/accessibility_core)
9
+ project and is a work-in-progress.
10
+
11
+
12
+ ## Copyright
13
+
14
+ Copyright (c)2012, Mark Rada
15
+ All rights reserved.
16
+
17
+ Redistribution and use in source and binary forms, with or without
18
+ modification, are permitted provided that the following conditions are met:
19
+
20
+ * Redistributions of source code must retain the above copyright
21
+ notice, this list of conditions and the following disclaimer.
22
+ * Redistributions in binary form must reproduce the above copyright
23
+ notice, this list of conditions and the following disclaimer in the
24
+ documentation and/or other materials provided with the distribution.
25
+ * Neither the name of Mark Rada nor the names of its
26
+ contributors may be used to endorse or promote products derived
27
+ from this software without specific prior written permission.
28
+
29
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
30
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
31
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
32
+ DISCLAIMED. IN NO EVENT SHALL Mark Rada BE LIABLE FOR ANY
33
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
35
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
37
+ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
38
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
39
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/Rakefile ADDED
@@ -0,0 +1,51 @@
1
+ task :default => :test
2
+
3
+ require 'rake/clean'
4
+ CLEAN.include '*.plist', '*.gch'
5
+
6
+ desc 'Run the Clang static analyzer'
7
+ task :analyze do
8
+ sh "clang --analyze ext/accessibility/bridge/bridge.c"
9
+ end
10
+
11
+ desc 'Startup an IRb console with accessibility-core loaded'
12
+ task :console => [:compile] do
13
+ sh 'irb -Ilib -raccessibility/bridge'
14
+ end
15
+
16
+ desc 'Build the test fixture'
17
+ task :fixture do
18
+ sh 'cd test/AXElementsTester && xcodebuild'
19
+ end
20
+
21
+ require 'rake/testtask'
22
+ Rake::TestTask.new do |t|
23
+ t.libs << '.'
24
+ t.pattern = 'test/*_test.rb'
25
+ end
26
+ task :test => :compile
27
+
28
+
29
+ # Gem stuff
30
+
31
+ require 'rubygems/package_task'
32
+ SPEC = Gem::Specification.load('accessibility_bridge.gemspec')
33
+
34
+ Gem::PackageTask.new(SPEC) { }
35
+
36
+ desc 'Build and install gem (not including deps)'
37
+ task :install => :gem do
38
+ require 'rubygems/installer'
39
+ Gem::Installer.new("pkg/#{SPEC.file_name}").install
40
+ end
41
+
42
+
43
+ # C extensions!
44
+
45
+ require 'rake/extensiontask'
46
+
47
+ Rake::ExtensionTask.new('bridge', SPEC) do |ext|
48
+ ext.ext_dir = 'ext/accessibility/bridge'
49
+ ext.lib_dir = 'lib/accessibility'
50
+ end
51
+
@@ -0,0 +1,490 @@
1
+ #include "ruby.h"
2
+ #import <Cocoa/Cocoa.h>
3
+
4
+ #ifndef ACCESSIBILITY_BRIDGE
5
+ #define ACCESSIBILITY_BRIDGE 1
6
+
7
+ #ifdef NOT_MACRUBY
8
+
9
+ VALUE rb_mAccessibility;
10
+ VALUE rb_cElement;
11
+ VALUE rb_cCGPoint;
12
+ VALUE rb_cCGSize;
13
+ VALUE rb_cCGRect;
14
+ VALUE rb_mURI; // URI module
15
+ VALUE rb_cURI; // URI::Generic class
16
+
17
+ ID sel_x;
18
+ ID sel_y;
19
+ ID sel_width;
20
+ ID sel_height;
21
+ ID sel_origin;
22
+ ID sel_size;
23
+ ID sel_to_point;
24
+ ID sel_to_size;
25
+ ID sel_to_rect;
26
+ ID sel_to_s;
27
+ ID sel_parse;
28
+
29
+
30
+ #define WRAP_ARRAY(wrapper) do { \
31
+ CFIndex length = CFArrayGetCount(array); \
32
+ VALUE ary = rb_ary_new2(length); \
33
+ \
34
+ for (CFIndex idx = 0; idx < length; idx++) \
35
+ rb_ary_store( \
36
+ ary, \
37
+ idx, \
38
+ wrapper(CFArrayGetValueAtIndex(array, idx)) \
39
+ ); \
40
+ return ary; \
41
+ } while (false);
42
+
43
+
44
+ VALUE
45
+ wrap_unknown(CFTypeRef obj)
46
+ {
47
+ // TODO: this will leak, can we use something like alloca?
48
+ CFStringRef description = CFCopyDescription(obj);
49
+ rb_raise(
50
+ rb_eRuntimeError,
51
+ "accessibility-core doesn't know how to wrap `%s` objects yet",
52
+ CFStringGetCStringPtr(description, kCFStringEncodingMacRoman)
53
+ );
54
+ return Qnil; // unreachable
55
+ }
56
+
57
+ CFTypeRef
58
+ unwrap_unknown(VALUE obj)
59
+ {
60
+ obj = rb_funcall(obj, sel_to_s, 0);
61
+ rb_raise(
62
+ rb_eRuntimeError,
63
+ "accessibility-core doesn't know how to unwrap `%s'",
64
+ StringValuePtr(obj)
65
+ );
66
+ return NULL; // unreachable
67
+ }
68
+
69
+
70
+ VALUE
71
+ wrap_point(CGPoint point)
72
+ {
73
+ return rb_struct_new(rb_cCGPoint, DBL2NUM(point.x), DBL2NUM(point.y));
74
+ }
75
+
76
+ CGPoint
77
+ unwrap_point(VALUE point)
78
+ {
79
+ point = rb_funcall(point, sel_to_point, 0);
80
+ double x = NUM2DBL(rb_struct_getmember(point, sel_x));
81
+ double y = NUM2DBL(rb_struct_getmember(point, sel_y));
82
+ return CGPointMake(x, y);
83
+ }
84
+
85
+
86
+ VALUE
87
+ wrap_size(CGSize size)
88
+ {
89
+ return rb_struct_new(rb_cCGSize, DBL2NUM(size.width), DBL2NUM(size.height));
90
+ }
91
+
92
+ CGSize
93
+ unwrap_size(VALUE size)
94
+ {
95
+ size = rb_funcall(size, sel_to_size, 0);
96
+ double width = NUM2DBL(rb_struct_getmember(size, sel_width));
97
+ double height = NUM2DBL(rb_struct_getmember(size, sel_height));
98
+ return CGSizeMake(width, height);
99
+ }
100
+
101
+
102
+ VALUE
103
+ wrap_rect(CGRect rect)
104
+ {
105
+ VALUE point = wrap_point(rect.origin);
106
+ VALUE size = wrap_size(rect.size);
107
+ return rb_struct_new(rb_cCGRect, point, size);
108
+ }
109
+
110
+ CGRect
111
+ unwrap_rect(VALUE rect)
112
+ {
113
+ rect = rb_funcall(rect, sel_to_rect, 0);
114
+ CGPoint origin = unwrap_point(rb_struct_getmember(rect, sel_origin));
115
+ CGSize size = unwrap_size(rb_struct_getmember(rect, sel_size));
116
+ return CGRectMake(origin.x, origin.y, size.width, size.height);
117
+ }
118
+
119
+
120
+ VALUE
121
+ convert_cf_range(CFRange range)
122
+ {
123
+ CFIndex end_index = range.location + range.length;
124
+ if (range.length != 0)
125
+ end_index -= 1;
126
+ return rb_range_new(INT2FIX(range.location), INT2FIX(end_index), 0);
127
+ }
128
+
129
+ CFRange
130
+ convert_rb_range(VALUE range)
131
+ {
132
+ VALUE b, e;
133
+ int exclusive;
134
+
135
+ rb_range_values(range, &b, &e, &exclusive);
136
+
137
+ int begin = NUM2INT(b);
138
+ int end = NUM2INT(e);
139
+
140
+ if (begin < 0 || end < 0)
141
+ // We don't know what the max length of the range will be, so we
142
+ // can't count backwards.
143
+ rb_raise(
144
+ rb_eArgError,
145
+ "negative values are not allowed in ranges " \
146
+ "that are converted to CFRange structures."
147
+ );
148
+
149
+ int length = exclusive ? end-begin : end-begin + 1;
150
+ return CFRangeMake(begin, length);
151
+ }
152
+
153
+
154
+ #define WRAP_VALUE(type, cookie, wrapper) do { \
155
+ type st; \
156
+ AXValueGetValue(value, cookie, &st); \
157
+ return wrapper(st); \
158
+ } while (0); \
159
+
160
+ VALUE wrap_value_point(AXValueRef value) { WRAP_VALUE(CGPoint, kAXValueCGPointType, wrap_point) }
161
+ VALUE wrap_value_size(AXValueRef value) { WRAP_VALUE(CGSize, kAXValueCGSizeType, wrap_size) }
162
+ VALUE wrap_value_rect(AXValueRef value) { WRAP_VALUE(CGRect, kAXValueCGRectType, wrap_rect) }
163
+ VALUE wrap_value_range(AXValueRef value) { WRAP_VALUE(CFRange, kAXValueCFRangeType, convert_cf_range) }
164
+ VALUE wrap_value_error(AXValueRef value) { WRAP_VALUE(AXError, kAXValueAXErrorType, INT2NUM) }
165
+
166
+ #define UNWRAP_VALUE(type, value, unwrapper) do { \
167
+ type st = unwrapper(val); \
168
+ return AXValueCreate(value, &st); \
169
+ } while(0);
170
+
171
+ AXValueRef unwrap_value_point(VALUE val) { UNWRAP_VALUE(CGPoint, kAXValueCGPointType, unwrap_point) }
172
+ AXValueRef unwrap_value_size(VALUE val) { UNWRAP_VALUE(CGSize, kAXValueCGSizeType, unwrap_size) }
173
+ AXValueRef unwrap_value_rect(VALUE val) { UNWRAP_VALUE(CGRect, kAXValueCGRectType, unwrap_rect) }
174
+ AXValueRef unwrap_value_range(VALUE val) { UNWRAP_VALUE(CFRange, kAXValueCFRangeType, convert_rb_range) }
175
+
176
+
177
+ VALUE
178
+ wrap_value(AXValueRef value)
179
+ {
180
+ switch (AXValueGetType(value))
181
+ {
182
+ case kAXValueIllegalType:
183
+ // TODO better error message
184
+ rb_raise(rb_eArgError, "herped when you should have derped");
185
+ case kAXValueCGPointType:
186
+ return wrap_value_point(value);
187
+ case kAXValueCGSizeType:
188
+ return wrap_value_size(value);
189
+ case kAXValueCGRectType:
190
+ return wrap_value_rect(value);
191
+ case kAXValueCFRangeType:
192
+ return wrap_value_range(value);
193
+ case kAXValueAXErrorType:
194
+ return wrap_value_error(value);
195
+ default:
196
+ // TODO better error message
197
+ rb_raise(
198
+ rb_eRuntimeError,
199
+ "Could not wrap You've found a bug in something...not sure who to blame"
200
+ );
201
+ }
202
+
203
+ return Qnil; // unreachable
204
+ }
205
+
206
+ AXValueRef
207
+ unwrap_value(VALUE value)
208
+ {
209
+ VALUE type = CLASS_OF(value);
210
+ if (type == rb_cCGPoint)
211
+ return unwrap_value_point(value);
212
+ else if (type == rb_cCGSize)
213
+ return unwrap_value_size(value);
214
+ else if (type == rb_cCGRect)
215
+ return unwrap_value_rect(value);
216
+ else if (type == rb_cRange)
217
+ return unwrap_value_range(value);
218
+
219
+ rb_raise(rb_eArgError, "could not wrap %s", rb_class2name(type));
220
+ return NULL; // unreachable
221
+ }
222
+
223
+ VALUE wrap_array_values(CFArrayRef array) { WRAP_ARRAY(wrap_value) }
224
+
225
+
226
+ static
227
+ void
228
+ ref_finalizer(void* obj)
229
+ {
230
+ CFRelease((CFTypeRef)obj);
231
+ }
232
+
233
+ VALUE
234
+ wrap_ref(AXUIElementRef ref)
235
+ {
236
+ return Data_Wrap_Struct(rb_cElement, NULL, ref_finalizer, (void*)ref);
237
+ }
238
+
239
+ AXUIElementRef
240
+ unwrap_ref(VALUE obj)
241
+ {
242
+ AXUIElementRef* ref;
243
+ Data_Get_Struct(obj, AXUIElementRef, ref);
244
+ // TODO we should return *ref? but that seems to fuck things up...
245
+ return (AXUIElementRef)ref;
246
+ }
247
+
248
+ VALUE wrap_array_refs(CFArrayRef array) { WRAP_ARRAY(wrap_ref) }
249
+
250
+
251
+ VALUE
252
+ wrap_string(CFStringRef string)
253
+ {
254
+ // flying by the seat of our pants here, this hasn't failed yet
255
+ // but probably will one day when I'm not looking
256
+ const char* name = CFStringGetCStringPtr(string, kCFStringEncodingMacRoman);
257
+ if (name)
258
+ return rb_str_new(name, CFStringGetLength(string));
259
+ else
260
+ // use rb_external_str_new() ? assume always UTF-8?
261
+ rb_raise(rb_eRuntimeError, "NEED TO IMPLEMNET STRING COPYING");
262
+
263
+ return Qnil; // unreachable
264
+ }
265
+
266
+ CFStringRef
267
+ unwrap_string(VALUE string)
268
+ {
269
+ return CFStringCreateWithCStringNoCopy(
270
+ NULL,
271
+ StringValueCStr(string),
272
+ 0,
273
+ kCFAllocatorNull
274
+ );
275
+ /* return CFStringCreateWithCString( */
276
+ /* NULL, */
277
+ /* StringValuePtr(string), */
278
+ /* kCFStringEncodingUTF8 */
279
+ /* ); */
280
+ }
281
+
282
+ VALUE wrap_array_strings(CFArrayRef array) { WRAP_ARRAY(wrap_string) }
283
+
284
+
285
+ #define WRAP_NUM(type, cookie, macro) do { \
286
+ type value; \
287
+ if (CFNumberGetValue(num, cookie, &value)) \
288
+ return macro(value); \
289
+ rb_raise(rb_eRuntimeError, "I goofed wrapping a number"); \
290
+ return Qnil; \
291
+ } while(0);
292
+
293
+ VALUE wrap_long(CFNumberRef num) { WRAP_NUM(long, kCFNumberLongType, LONG2FIX) }
294
+ VALUE wrap_long_long(CFNumberRef num) { WRAP_NUM(long long, kCFNumberLongLongType, LL2NUM) }
295
+ VALUE wrap_float(CFNumberRef num) { WRAP_NUM(double, kCFNumberDoubleType, DBL2NUM) }
296
+
297
+ #define UNWRAP_NUM(type, cookie, macro) do { \
298
+ type base = macro(num); \
299
+ return CFNumberCreate(NULL, cookie, &base); \
300
+ } while(0);
301
+
302
+ CFNumberRef unwrap_long(VALUE num) { UNWRAP_NUM(long, kCFNumberLongType, NUM2LONG) }
303
+ CFNumberRef unwrap_long_long(VALUE num) { UNWRAP_NUM(long long, kCFNumberLongLongType, NUM2LL) }
304
+ CFNumberRef unwrap_float(VALUE num) { UNWRAP_NUM(double, kCFNumberDoubleType, NUM2DBL) }
305
+
306
+ VALUE
307
+ wrap_number(CFNumberRef number)
308
+ {
309
+ switch (CFNumberGetType(number))
310
+ {
311
+ case kCFNumberSInt8Type:
312
+ case kCFNumberSInt16Type:
313
+ case kCFNumberSInt32Type:
314
+ case kCFNumberSInt64Type:
315
+ return wrap_long(number);
316
+ case kCFNumberFloat32Type:
317
+ case kCFNumberFloat64Type:
318
+ return wrap_float(number);
319
+ case kCFNumberCharType:
320
+ case kCFNumberShortType:
321
+ case kCFNumberIntType:
322
+ case kCFNumberLongType:
323
+ return wrap_long(number);
324
+ case kCFNumberLongLongType:
325
+ return wrap_long_long(number);
326
+ case kCFNumberFloatType:
327
+ case kCFNumberDoubleType:
328
+ return wrap_float(number);
329
+ case kCFNumberCFIndexType:
330
+ case kCFNumberNSIntegerType:
331
+ return wrap_long(number);
332
+ case kCFNumberCGFloatType: // == kCFNumberMaxType
333
+ return wrap_float(number);
334
+ default:
335
+ return INT2NUM(0); // unreachable unless system goofed
336
+ }
337
+ }
338
+
339
+ CFNumberRef
340
+ unwrap_number(VALUE number)
341
+ {
342
+ switch (TYPE(number))
343
+ {
344
+ case T_FIXNUM:
345
+ return unwrap_long(number);
346
+ case T_FLOAT:
347
+ return unwrap_float(number);
348
+ default:
349
+ rb_raise(
350
+ rb_eRuntimeError,
351
+ "wrapping %s is not supported; log a bug?",
352
+ rb_string_value_cstr(&number)
353
+ );
354
+ return kCFNumberNegativeInfinity; // unreachable
355
+ }
356
+ }
357
+
358
+ VALUE wrap_array_numbers(CFArrayRef array) { WRAP_ARRAY(wrap_number) }
359
+
360
+
361
+ VALUE
362
+ wrap_url(CFURLRef url)
363
+ {
364
+ return rb_funcall(rb_mURI, sel_parse, 1, wrap_string(CFURLGetString(url)));
365
+ }
366
+
367
+ CFURLRef
368
+ unwrap_url(VALUE url)
369
+ {
370
+ url = rb_funcall(url, sel_to_s, 0);
371
+ CFStringRef string = CFStringCreateWithCString(
372
+ NULL,
373
+ StringValuePtr(url),
374
+ kCFStringEncodingUTF8
375
+ );
376
+ CFURLRef url_ref = CFURLCreateWithString(NULL, string, NULL);
377
+ CFRelease(string);
378
+ return url_ref;
379
+ }
380
+
381
+ VALUE wrap_array_urls(CFArrayRef array) { WRAP_ARRAY(wrap_url) }
382
+
383
+ VALUE
384
+ wrap_date(CFDateRef date)
385
+ {
386
+ NSTimeInterval time = [(NSDate*)date timeIntervalSince1970];
387
+ return rb_time_new((time_t)time, 0);
388
+ }
389
+
390
+ CFDateRef
391
+ unwrap_date(VALUE date)
392
+ {
393
+ struct timeval t = rb_time_timeval(date);
394
+ NSDate* ns_date = [NSDate dateWithTimeIntervalSince1970:t.tv_sec];
395
+ return (CFDateRef)ns_date;
396
+ }
397
+
398
+ VALUE wrap_array_dates(CFArrayRef array) { WRAP_ARRAY(wrap_date) }
399
+
400
+
401
+ VALUE
402
+ wrap_boolean(CFBooleanRef bool_val)
403
+ {
404
+ return (CFBooleanGetValue(bool_val) ? Qtrue : Qfalse);
405
+ }
406
+
407
+ CFBooleanRef
408
+ unwrap_boolean(VALUE bool_val)
409
+ {
410
+ return (bool_val == Qtrue ? kCFBooleanTrue : kCFBooleanFalse);
411
+ }
412
+
413
+ VALUE wrap_array_booleans(CFArrayRef array) { WRAP_ARRAY(wrap_boolean) }
414
+
415
+
416
+ VALUE
417
+ wrap_array(CFArrayRef array)
418
+ {
419
+ CFTypeRef obj = CFArrayGetValueAtIndex(array, 0);
420
+ CFTypeID di = CFGetTypeID(obj);
421
+ if (di == AXUIElementGetTypeID()) return wrap_array_refs(array);
422
+ else if (di == AXValueGetTypeID()) return wrap_array_values(array);
423
+ else if (di == CFStringGetTypeID()) return wrap_array_strings(array);
424
+ else if (di == CFNumberGetTypeID()) return wrap_array_numbers(array);
425
+ else if (di == CFBooleanGetTypeID()) return wrap_array_booleans(array);
426
+ else if (di == CFURLGetTypeID()) return wrap_array_urls(array);
427
+ else if (di == CFDateGetTypeID()) return wrap_array_dates(array);
428
+ else return wrap_unknown(obj);
429
+ }
430
+
431
+ VALUE
432
+ to_ruby(CFTypeRef obj)
433
+ {
434
+ CFTypeID di = CFGetTypeID(obj);
435
+ if (di == CFArrayGetTypeID()) return wrap_array(obj);
436
+ else if (di == AXUIElementGetTypeID()) return wrap_ref(obj);
437
+ else if (di == AXValueGetTypeID()) return wrap_value(obj);
438
+ else if (di == CFStringGetTypeID()) return wrap_string(obj);
439
+ else if (di == CFNumberGetTypeID()) return wrap_number(obj);
440
+ else if (di == CFBooleanGetTypeID()) return wrap_boolean(obj);
441
+ else if (di == CFURLGetTypeID()) return wrap_url(obj);
442
+ else if (di == CFDateGetTypeID()) return wrap_date(obj);
443
+ else return wrap_unknown(obj);
444
+ }
445
+
446
+ CFTypeRef
447
+ to_ax(VALUE obj)
448
+ {
449
+ // TODO we can better optimize this when running under MacRuby
450
+ VALUE type = CLASS_OF(obj);
451
+ if (type == rb_cElement) return unwrap_ref(obj);
452
+ else if (type == rb_cString) return unwrap_string(obj);
453
+ else if (type == rb_cStruct) return unwrap_value(obj);
454
+ else if (type == rb_cRange) return unwrap_value(obj);
455
+ else if (type == rb_cFixnum) return unwrap_number(obj);
456
+ else if (type == rb_cFloat) return unwrap_number(obj);
457
+ else if (type == rb_cTime) return unwrap_date(obj);
458
+ else if (type == rb_cURI) return unwrap_url(obj);
459
+ else if (obj == Qtrue || obj == Qfalse) return unwrap_boolean(obj);
460
+ else return unwrap_unknown(obj);
461
+ }
462
+
463
+ #endif
464
+
465
+
466
+ void
467
+ Init_bridge()
468
+ {
469
+ #ifdef NOT_MACRUBY
470
+ sel_x = rb_intern("x");
471
+ sel_y = rb_intern("y");
472
+ sel_width = rb_intern("width");
473
+ sel_height = rb_intern("height");
474
+ sel_origin = rb_intern("origin");
475
+ sel_size = rb_intern("size");
476
+ sel_to_point = rb_intern("to_point");
477
+ sel_to_size = rb_intern("to_size");
478
+ sel_to_rect = rb_intern("to_rect");
479
+ sel_to_s = rb_intern("to_s");
480
+ sel_parse = rb_intern("parse");
481
+
482
+ rb_cCGPoint = rb_const_get(rb_cObject, rb_intern("CGPoint"));
483
+ rb_cCGSize = rb_const_get(rb_cObject, rb_intern("CGSize"));
484
+ rb_cCGRect = rb_const_get(rb_cObject, rb_intern("CGRect"));
485
+ rb_mURI = rb_const_get(rb_cObject, rb_intern("URI"));
486
+ rb_cURI = rb_const_get(rb_mURI, rb_intern("Generic"));
487
+ #endif
488
+ }
489
+
490
+ #endif
@@ -0,0 +1,22 @@
1
+ require 'mkmf'
2
+
3
+ $CFLAGS << ' -std=c99 -Wall -Werror -pedantic -ObjC'
4
+ $LIBS << ' -framework CoreFoundation -framework ApplicationServices -framework Cocoa'
5
+ $LIBS << ' -framework CoreGraphics' unless `sw_vers -productVersion`.to_f == 10.7
6
+
7
+ if RUBY_ENGINE == 'macruby'
8
+ $CFLAGS << ' -fobjc-gc'
9
+ else
10
+ unless RbConfig::CONFIG["CC"].match /clang/
11
+ clang = `which clang`.chomp
12
+ if clang.empty?
13
+ raise "Clang not installed. Cannot build C extension"
14
+ else
15
+ RbConfig::MAKEFILE_CONFIG["CC"] = clang
16
+ RbConfig::MAKEFILE_CONFIG["CXX"] = clang
17
+ end
18
+ end
19
+ $CFLAGS << ' -DNOT_MACRUBY'
20
+ end
21
+
22
+ create_makefile 'accessibility/bridge'
@@ -0,0 +1,33 @@
1
+ require 'accessibility/bridge/version'
2
+
3
+ if RUBY_ENGINE == 'macruby'
4
+
5
+ ##
6
+ # Whether or not we are running on MacRuby
7
+ def on_macruby?
8
+ true
9
+ end
10
+
11
+ framework 'Cocoa'
12
+
13
+ # A workaround that guarantees that `CGPoint` is defined
14
+ unless defined? MOUNTAIN_LION_APPKIT_VERSION
15
+ MOUNTAIN_LION_APPKIT_VERSION = 1187
16
+ end
17
+
18
+ if NSAppKitVersionNumber >= MOUNTAIN_LION_APPKIT_VERSION
19
+ framework '/System/Library/Frameworks/CoreGraphics.framework'
20
+ end
21
+
22
+ require 'accessibility/bridge/macruby'
23
+
24
+ else
25
+
26
+ def on_macruby?
27
+ false
28
+ end
29
+
30
+ require 'accessibility/bridge/mri'
31
+
32
+ end
33
+
@@ -0,0 +1,57 @@
1
+ class CGPoint
2
+ ##
3
+ # Returns the receiver, since the receiver is already a {CGPoint}
4
+ #
5
+ # @return [CGPoint]
6
+ def to_point
7
+ self
8
+ end
9
+ end
10
+
11
+ class CGSize
12
+ ##
13
+ # Returns the receiver, since the receiver is already a {CGSize}
14
+ #
15
+ # @return [CGSize]
16
+ def to_size
17
+ self
18
+ end
19
+ end
20
+
21
+ class CGRect
22
+ ##
23
+ # Returns the receiver, since the receiver is already a {CGRect}
24
+ #
25
+ # @return [CGRect]
26
+ def to_rect
27
+ self
28
+ end
29
+ end
30
+
31
+ ##
32
+ # accessibility-core extensions to `Array`
33
+ class Array
34
+ ##
35
+ # Coerce the first two elements of the receiver into a {CGPoint}
36
+ #
37
+ # @return [CGPoint]
38
+ def to_point
39
+ CGPoint.new self[0], self[1]
40
+ end
41
+
42
+ ##
43
+ # Coerce the first two elements of the receiver into a {CGSize}
44
+ #
45
+ # @return [CGSize]
46
+ def to_size
47
+ CGSize.new self[0], self[1]
48
+ end
49
+
50
+ ##
51
+ # Coerce the first four elements of the receiver into a {CGRect}
52
+ #
53
+ # @return [CGRect]
54
+ def to_rect
55
+ CGRect.new CGPoint.new(self[0], self[1]), CGSize.new(self[2], self[3])
56
+ end
57
+ end
@@ -0,0 +1,185 @@
1
+ require 'accessibility/bridge/common'
2
+
3
+ ##
4
+ # accessibility-core extensions for `NSURL`
5
+ class NSURL
6
+ ##
7
+ # Return the reciver, for the receiver is already a URL object
8
+ #
9
+ # @return [NSURL]
10
+ def to_url
11
+ self
12
+ end
13
+
14
+ # because printing is easier this way
15
+ alias_method :to_s, :inspect
16
+ end
17
+
18
+ ##
19
+ # accessibility-core extensions for `NSString`
20
+ class NSString
21
+ ##
22
+ # Create an NSURL using the receiver as the initialization string
23
+ #
24
+ # If the receiver is not a valid URL then `nil` will be returned.
25
+ #
26
+ # This exists because of
27
+ # [rdar://11207662](http://openradar.appspot.com/11207662).
28
+ #
29
+ # @return [NSURL,nil]
30
+ def to_url
31
+ NSURL.URLWithString self
32
+ end
33
+ end
34
+
35
+ ##
36
+ # `accessibility-core` extensions for `NSObject`
37
+ class NSObject
38
+ ##
39
+ # Return an object safe for passing to AXAPI
40
+ def to_ax
41
+ self
42
+ end
43
+
44
+ ##
45
+ # Return a usable object from an AXAPI pointer
46
+ def to_ruby
47
+ self
48
+ end
49
+ end
50
+
51
+ ##
52
+ # `accessibility-core` extensions for `CFRange`
53
+ class CFRange
54
+ ##
55
+ # Convert the {CFRange} to a Ruby {Range} object
56
+ #
57
+ # @return [Range]
58
+ def to_ruby
59
+ Range.new location, (location + length - 1)
60
+ end
61
+ end
62
+
63
+ ##
64
+ # `accessibility-core` extensions for `Range`
65
+ class Range
66
+ # @return [AXValueRef]
67
+ def to_ax
68
+ raise ArgumentError, "can't convert negative index" if last < 0 || first < 0
69
+ length = if exclude_end?
70
+ last - first
71
+ else
72
+ last - first + 1
73
+ end
74
+ CFRange.new(first, length).to_ax
75
+ end
76
+ end
77
+
78
+ ##
79
+ # AXElements extensions to the `Boxed` class
80
+ #
81
+ # The `Boxed` class is simply an abstract base class for structs that
82
+ # MacRuby can use via bridge support.
83
+ class Boxed
84
+ ##
85
+ # Returns the number that AXAPI uses in order to know how to wrap
86
+ # a struct.
87
+ #
88
+ # @return [Number]
89
+ def self.ax_value
90
+ raise NotImplementedError, "#{inspect}:#{self.class} cannot be wrapped"
91
+ end
92
+
93
+ ##
94
+ # Create an `AXValueRef` from the `Boxed` instance. This will only
95
+ # work if for the most common boxed types, you will need to check
96
+ # the AXAPI documentation for an up to date list.
97
+ #
98
+ # @example
99
+ #
100
+ # CGPoint.new(12, 34).to_ax # => #<AXValueRef:0x455678e2>
101
+ # CGSize.new(56, 78).to_ax # => #<AXValueRef:0x555678e2>
102
+ #
103
+ # @return [AXValueRef]
104
+ def to_ax
105
+ klass = self.class
106
+ ptr = Pointer.new klass.type
107
+ ptr.assign self
108
+ AXValueCreate(klass.ax_value, ptr)
109
+ end
110
+ end
111
+
112
+ # `accessibility-core` extensions for `CFRange`'s metaclass
113
+ class << CFRange
114
+ # (see Boxed.ax_value)
115
+ def ax_value; KAXValueCFRangeType end
116
+ end
117
+ # `accessibility-core` extensions for `CGSize`'s metaclass
118
+ class << CGSize
119
+ # (see Boxed.ax_value)
120
+ def ax_value; KAXValueCGSizeType end
121
+ end
122
+ # `accessibility-core` extensions for `CGRect`'s metaclass
123
+ class << CGRect
124
+ # (see Boxed.ax_value)
125
+ def ax_value; KAXValueCGRectType end
126
+ end
127
+ # `accessibility-core` extensions for `CGPoint`'s metaclass
128
+ class << CGPoint
129
+ # (see Boxed.ax_value)
130
+ def ax_value; KAXValueCGPointType end
131
+ end
132
+
133
+ ##
134
+ # Mixin for the special hidden class in MacRuby that represents `AXValueRef`
135
+ #
136
+ # This module adds a `#to_ruby` method that actually unwraps the object from
137
+ # the `AXValueRef` to some sort of {Boxed} object, such as a {CGPoint} or a
138
+ # {Range}.
139
+ module ValueWrapper
140
+
141
+
142
+ ##
143
+ # Map of type encodings used for unwrapping structs wrapped in an `AXValueRef`
144
+ #
145
+ # The list is order sensitive, which is why we unshift nil, but
146
+ # should probably be more rigorously defined at runtime.
147
+ #
148
+ # @return [String,nil]
149
+ BOX_TYPES = [CGPoint, CGSize, CGRect, CFRange].map!(&:type).unshift(nil)
150
+
151
+ ##
152
+ # Unwrap an `AXValueRef` into the `Boxed` instance that it is supposed
153
+ # to be. This will only work for the most common boxed types, you will
154
+ # need to check the AXAPI documentation for an up to date list.
155
+ #
156
+ # @example
157
+ #
158
+ # wrapped_point.to_ruby # => #<CGPoint x=44.3 y=99.0>
159
+ # wrapped_range.to_ruby # => #<CFRange begin=7 length=100>
160
+ # wrapped_thing.to_ruby # => wrapped_thing
161
+ #
162
+ # @return [Boxed]
163
+ def to_ruby
164
+ type = AXValueGetType(self)
165
+ return self if type.zero?
166
+
167
+ ptr = Pointer.new BOX_TYPES[type]
168
+ AXValueGetValue(self, type, ptr)
169
+ ptr.value.to_ruby
170
+ end
171
+
172
+ # hack to find the __NSCFType class and mix things in
173
+ klass = AXUIElementCreateSystemWide().class
174
+ klass.send :include, self
175
+
176
+ end
177
+
178
+ ##
179
+ # `accessibility-core` extensions to `NSArray`
180
+ class NSArray
181
+ # @return [Array]
182
+ def to_ruby
183
+ map do |obj| obj.to_ruby end
184
+ end
185
+ end
@@ -0,0 +1,121 @@
1
+ ##
2
+ # A structure that contains a point in a two-dimensional coordinate system
3
+ CGPoint = Struct.new(:x, :y) do
4
+
5
+ # @param x [Number]
6
+ # @param y [Number]
7
+ def initialize x = 0.0, y = 0.0
8
+ super
9
+ end
10
+
11
+ # @!attribute [rw] x
12
+ # The `x` co-ordinate of the screen point
13
+ # @return [Number]
14
+
15
+ # @!attribute [rw] y
16
+ # The `y` co-ordinate of the screen point
17
+ # @return [Number]
18
+
19
+ ##
20
+ # Return a nice string representation of the point
21
+ #
22
+ # Overrides `Object#inspect` to more closely mimic MacRuby `Boxed#inspect`.
23
+ #
24
+ # @return [String]
25
+ def inspect
26
+ "#<CGPoint x=#{self.x.to_f} y=#{self.y.to_f}>"
27
+ end
28
+
29
+ end
30
+
31
+
32
+ ##
33
+ # A structure that contains the size of a rectangle in a 2D co-ordinate system
34
+ CGSize = Struct.new(:width, :height) do
35
+
36
+ # @param width [Number]
37
+ # @param height [Number]
38
+ def initialize width = 0.0, height = 0.0
39
+ super
40
+ end
41
+
42
+ # @!attribute [rw] width
43
+ # The `width` of the box
44
+ # @return [Number]
45
+
46
+ # @!attribute [rw] height
47
+ # The `heighth` of the box
48
+ # @return [Number]
49
+
50
+ ##
51
+ # Return a nice string representation of the size
52
+ #
53
+ # Overrides `Object#inspect` to more closely mimic MacRuby `Boxed#inspect`.
54
+ #
55
+ # @return [String]
56
+ def inspect
57
+ "#<CGSize width=#{self.width.to_f} height=#{self.height.to_f}>"
58
+ end
59
+
60
+ end
61
+
62
+
63
+ ##
64
+ # Complete definition of a rectangle in a 2D coordinate system
65
+ CGRect = Struct.new(:origin, :size) do
66
+
67
+ # @param origin [CGPoint,#to_point]
68
+ # @param size [CGSize,#to_size]
69
+ def initialize origin = CGPoint.new, size = CGSize.new
70
+ super(origin.to_point, size.to_size)
71
+ end
72
+
73
+ # @!attribute [rw] origin
74
+ # The `origin` point
75
+ # @return [CGPoint,#to_point]
76
+
77
+ # @!attribute [rw] size
78
+ # The `size` of the rectangle
79
+ # @return [CGSize,#to_size]
80
+
81
+ ##
82
+ # Return a nice string representation of the rectangle
83
+ #
84
+ # Overrides `Object#inspect` to more closely mimic MacRuby `Boxed#inspect`.
85
+ #
86
+ # @return [String]
87
+ def inspect
88
+ "#<CGRect origin=#{self.origin.inspect} size=#{self.size.inspect}>"
89
+ end
90
+
91
+ end
92
+
93
+
94
+ require 'uri'
95
+
96
+ ##
97
+ # `accessibility-core` extensions to the `URI` family of classes
98
+ class URI::Generic
99
+ ##
100
+ # Returns the receiver (since the receiver is already a `URI` object)
101
+ #
102
+ # @return [URI::Generic]
103
+ def to_url
104
+ self
105
+ end
106
+ end
107
+
108
+ ##
109
+ # `accessibility-core` extensions to the `String` class
110
+ class String
111
+ ##
112
+ # Parse the receiver into a `URI` object
113
+ #
114
+ # @return [URI::Generic]
115
+ def to_url
116
+ URI.parse self
117
+ end
118
+ end
119
+
120
+
121
+ require 'accessibility/bridge/common'
@@ -0,0 +1,6 @@
1
+ module Accessibility
2
+ module Bridge
3
+ # @return [String]
4
+ VERSION = '0.1.0'
5
+ end
6
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'minitest/autorun'
2
+ require 'minitest/pride'
3
+ require 'accessibility/bridge'
4
+
5
+ class MiniTest::Unit::TestCase
6
+
7
+ def rand_nums count, range = 1_000
8
+ Array.new count do
9
+ rand range
10
+ end
11
+ end
12
+
13
+ def rand_floats count, range = 1_000.0
14
+ Array.new count do
15
+ rand * range
16
+ end
17
+ end
18
+
19
+ end
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: accessibility_bridge
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Mark Rada
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-18 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: yard
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.8.3
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 0.8.3
30
+ - !ruby/object:Gem::Dependency
31
+ name: kramdown
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.14.1
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.14.1
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake-compiler
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 0.8.1
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.8.1
62
+ description: ! 'accessibility_bridge is a wrapper around various bits of Cocoa
63
+
64
+ so that the various accessibility projects can run on CRuby.
65
+
66
+
67
+ Originally extracted from the AXElements project.
68
+
69
+ '
70
+ email: markrada26@gmail.com
71
+ executables: []
72
+ extensions:
73
+ - ext/accessibility/bridge/extconf.rb
74
+ extra_rdoc_files: []
75
+ files:
76
+ - lib/accessibility/bridge/common.rb
77
+ - lib/accessibility/bridge/macruby.rb
78
+ - lib/accessibility/bridge/mri.rb
79
+ - lib/accessibility/bridge/version.rb
80
+ - lib/accessibility/bridge.rb
81
+ - ext/accessibility/bridge/bridge.c
82
+ - ext/accessibility/bridge/extconf.rb
83
+ - Rakefile
84
+ - README.markdown
85
+ - History.markdown
86
+ - .yardopts
87
+ - test/helper.rb
88
+ homepage: http://github.com/AXElements/accessibility_bridge
89
+ licenses:
90
+ - BSD 3-clause
91
+ post_install_message:
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ! '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ segments:
102
+ - 0
103
+ hash: -1210497514143783933
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ segments:
111
+ - 0
112
+ hash: -1210497514143783933
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 1.8.24
116
+ signing_key:
117
+ specification_version: 3
118
+ summary: A library for bridging into Cocoa on OSX
119
+ test_files:
120
+ - test/helper.rb