cocoa 0.1.5 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +5 -1
- data/VERSION +1 -1
- data/cocoa.gemspec +4 -3
- data/lib/cocoa/extensions.rb +7 -1
- data/lib/cocoa/helpers.rb +56 -11
- data/lib/cocoa/objc.rb +15 -11
- data/lib/cocoa/objc/method_def.rb +5 -4
- data/spec/cocoa/cocoa_spec.rb +15 -2
- data/spec/cocoa/cocoa_spec_r2.rb +18 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f71aa43ea295a1886c05be665d147e1312fb09a
|
4
|
+
data.tar.gz: c33bb6813e008b446256ceec2592d4b1dd897bcc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e655407c657e9e8b7a7bfbdf65fa7cd1f27cdbbaa050183e283c03a6308041abb71f678914e974d7f2a5caf6b8454cf808ce8269bf99b16612b657c3f401fb32
|
7
|
+
data.tar.gz: 4eddefb01fbb2b0bef984084a2adcb0ff50c144614887cf3591a29211cad5ca3fbe4d53471661446b5da273e3edf48c6dded60b20b89f2a50468eb4f089d787b
|
data/Rakefile
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
PROJECT_SPECS =
|
3
|
+
PROJECT_SPECS = if RUBY_VERSION.split.first.to_i >= 2
|
4
|
+
FileList['spec/**/*_spec.rb'] + FileList['spec/**/*_spec_r2.rb']
|
5
|
+
else
|
6
|
+
FileList['spec/**/*_spec.rb']
|
7
|
+
end
|
4
8
|
|
5
9
|
require 'jeweler'
|
6
10
|
Jeweler::Tasks.new do |gem|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.6
|
data/cocoa.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: cocoa 0.1.
|
5
|
+
# stub: cocoa 0.1.6 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "cocoa"
|
9
|
-
s.version = "0.1.
|
9
|
+
s.version = "0.1.6"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib"]
|
13
13
|
s.authors = ["Patrick Hanevold"]
|
14
|
-
s.date = "2014-04-
|
14
|
+
s.date = "2014-04-13"
|
15
15
|
s.description = "Ruby FFI bindings for the OSX Cocoa API"
|
16
16
|
s.email = "patrick.hanevold@gmail.com"
|
17
17
|
s.extra_rdoc_files = [
|
@@ -425,6 +425,7 @@ Gem::Specification.new do |s|
|
|
425
425
|
"lib/cocoa/structs/NSRect.rb",
|
426
426
|
"lib/cocoa/structs/NSSize.rb",
|
427
427
|
"spec/cocoa/cocoa_spec.rb",
|
428
|
+
"spec/cocoa/cocoa_spec_r2.rb",
|
428
429
|
"spec/spec_helper.rb",
|
429
430
|
"tasks/bacon.rake",
|
430
431
|
"tasks/generate.rake",
|
data/lib/cocoa/extensions.rb
CHANGED
data/lib/cocoa/helpers.rb
CHANGED
@@ -123,24 +123,27 @@ module Cocoa
|
|
123
123
|
|
124
124
|
def self.attach_method method,*_params
|
125
125
|
return if method==:class
|
126
|
-
|
127
|
-
|
126
|
+
@method_specs ||= {}
|
127
|
+
@method_specs[method] = []
|
128
128
|
[_params].flatten.each do |spec|
|
129
|
-
|
129
|
+
@method_specs[method] << ObjC::MethodDef.new(method,spec)
|
130
130
|
end
|
131
131
|
define_method method do |*args|
|
132
|
+
klass = self.class; klass = klass.superclass while !klass.instance_methods(false).include?(method)
|
133
|
+
spec = klass.instance_variable_get(:@method_specs)[method]
|
134
|
+
|
132
135
|
matching = if args.size <= 1
|
133
|
-
matching =
|
136
|
+
matching = spec.select do |m|
|
134
137
|
m.types.size == args.size
|
135
138
|
end
|
136
139
|
else
|
137
140
|
matching = if args.last.is_a? Hash
|
138
|
-
|
141
|
+
spec.select do |m|
|
139
142
|
args.last.keys == m.names
|
140
143
|
end
|
141
144
|
else
|
142
145
|
raise "hell" unless args.size == 1
|
143
|
-
|
146
|
+
spec.select do |m|
|
144
147
|
m.types.size == 1
|
145
148
|
end
|
146
149
|
end
|
@@ -157,18 +160,26 @@ module Cocoa
|
|
157
160
|
end
|
158
161
|
|
159
162
|
def self.method_defs method
|
160
|
-
|
163
|
+
klass = self
|
164
|
+
method_specs = klass.instance_variable_get(:@method_specs)
|
165
|
+
while klass && (!method_specs || !method_specs[method])
|
166
|
+
klass = klass.superclass
|
167
|
+
method_specs = klass.instance_variable_get(:@method_specs)
|
168
|
+
end
|
169
|
+
return nil unless method_specs
|
170
|
+
|
171
|
+
spec = method_specs[method]
|
161
172
|
params = instance_method(method).parameters
|
162
173
|
keys = params.select{ |param| param.first == :key }.map{ |param| param.last }
|
163
174
|
if params.size > 0 && params.last.first == :rest
|
164
|
-
filtered =
|
175
|
+
filtered = spec.select do |m|
|
165
176
|
((m.types.size == 0 && keys.size == 0) || (m.types.size > keys.size)) &&
|
166
177
|
(m.names[0,keys.size-1] || []) == keys
|
167
178
|
end
|
168
179
|
return nil if filtered.size == 0
|
169
180
|
filtered
|
170
181
|
else
|
171
|
-
filtered =
|
182
|
+
filtered = spec.select do |m|
|
172
183
|
((m.types.size == 0 && keys.size == 0) || (m.types.size == keys.size+1)) &&
|
173
184
|
m.names == keys
|
174
185
|
end
|
@@ -181,18 +192,42 @@ module Cocoa
|
|
181
192
|
def self.method_added(name)
|
182
193
|
return if name == :== # TODO: define as equals or something?
|
183
194
|
return if name.to_s[-1] == '='
|
195
|
+
return if caller[1].split('`').last[0..-2] == 'method_added' # self
|
184
196
|
return if caller.first.split('`').last[0..-2] == 'define_method' # MRI
|
185
197
|
return if caller.first.split('`').last[0..-2] == 'attach_method' # Rubinius
|
186
198
|
|
199
|
+
# define an alias for keyword argument methods such that:
|
200
|
+
# class Foo
|
201
|
+
# def bar whatever, alpha: nil
|
202
|
+
# puts "alpha is: #{alpha}"
|
203
|
+
# end
|
204
|
+
# def bar whatever, omega: nil
|
205
|
+
# puts "omega is: #{omega}"
|
206
|
+
# end
|
207
|
+
# end
|
208
|
+
# Foo.new.bar "hello", omega: "is omega"
|
209
|
+
# Foo.new.bar "hello", alpha: "is alpha"
|
210
|
+
#=>
|
211
|
+
# omega is: is omega
|
212
|
+
# alpha is: is alpha
|
213
|
+
keys = instance_method(name).parameters.select{ |param| param.first == :key }.map{ |param| param.last }
|
214
|
+
ruby_name = name
|
215
|
+
if keys.size > 0
|
216
|
+
ruby_name = "_#{name}_with_#{keys.join('_and_')}".to_sym
|
217
|
+
alias_method ruby_name, name
|
218
|
+
end
|
219
|
+
|
220
|
+
|
187
221
|
defs = method_defs name
|
188
222
|
defs ||= ObjC::MethodDef.new(name, :names => [], :types => ['@'], :retval => 'v') # TODO: generate from method arguments!
|
189
223
|
|
190
224
|
[defs].flatten.each do |m|
|
191
225
|
@callbacks ||= []
|
192
226
|
@callbacks << Proc.new do |this,cmd,*args|
|
227
|
+
m.ruby_name = ruby_name
|
193
228
|
begin
|
194
229
|
instance = Cocoa.instances[this.address]
|
195
|
-
params = instance_method(
|
230
|
+
params = instance_method(ruby_name).parameters
|
196
231
|
m.callback(instance,params,args)
|
197
232
|
rescue => e
|
198
233
|
puts e.message
|
@@ -203,10 +238,20 @@ module Cocoa
|
|
203
238
|
callback_name = "#{self.name.gsub('::','__')}_#{m.selector.gsub(/:/,'_')}".to_sym
|
204
239
|
add_method = "add_#{callback_name}".to_sym
|
205
240
|
|
241
|
+
native_name = begin
|
242
|
+
arr = self.name.split('::')
|
243
|
+
native = if arr.first == 'Cocoa'
|
244
|
+
arr.last
|
245
|
+
else
|
246
|
+
self.name.gsub(/::/,'__')
|
247
|
+
end
|
248
|
+
native
|
249
|
+
end
|
250
|
+
|
206
251
|
ObjC.callback callback_name, [:pointer, :pointer]+m.ffi_types, m.ffi_return_type
|
207
252
|
ObjC.attach_function add_method, :class_addMethod, [:pointer,:pointer,callback_name,:string], :void
|
208
253
|
|
209
|
-
ObjC.send(add_method,ObjC.objc_getClass(
|
254
|
+
ObjC.send(add_method,ObjC.objc_getClass(native_name),ObjC.sel_registerName(m.selector),@callbacks.last,m.objc_types)
|
210
255
|
end
|
211
256
|
end
|
212
257
|
end
|
data/lib/cocoa/objc.rb
CHANGED
@@ -75,19 +75,23 @@ module ObjC
|
|
75
75
|
instance = begin
|
76
76
|
Cocoa::const_get(klass_name).new(true)
|
77
77
|
rescue
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
if
|
82
|
-
|
78
|
+
begin
|
79
|
+
Object.const_get(klass_name.gsub(/__/,'::')).new(true)
|
80
|
+
rescue
|
81
|
+
klass_name = if klass_name =~ /^__NSCF/
|
82
|
+
"NS#{klass_name[6..-1]}"
|
83
|
+
elsif klass_name[0]=='_'
|
84
|
+
if superklass = Cocoa::const_get(NSString_to_String(Cocoa::NSStringFromClass(ObjC.msgSend_pointer(ret,"superclass"))))
|
85
|
+
superklass.name.split('::').last
|
86
|
+
else
|
87
|
+
"FIX_#{klass_name}"
|
88
|
+
end
|
83
89
|
else
|
84
|
-
|
90
|
+
klass_name
|
85
91
|
end
|
86
|
-
|
87
|
-
|
92
|
+
klass = smart_constantize(ret,klass_name)
|
93
|
+
klass.new(true)
|
88
94
|
end
|
89
|
-
klass = smart_constantize(ret,klass_name)
|
90
|
-
klass.new(true)
|
91
95
|
end
|
92
96
|
instance.object = ret
|
93
97
|
instance
|
@@ -119,7 +123,7 @@ module ObjC
|
|
119
123
|
case type
|
120
124
|
when nil
|
121
125
|
default
|
122
|
-
when '@', 'v', 'q', 'Q', '^v'
|
126
|
+
when '@', 'v', 'q', 'Q', '^v', 'B'
|
123
127
|
type
|
124
128
|
when /^{([^=]*)=.*}$/
|
125
129
|
type
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module ObjC
|
2
2
|
class MethodDef
|
3
|
-
attr_accessor :name,:names,:types,:return_type
|
3
|
+
attr_accessor :name,:names,:types,:return_type,:ruby_name
|
4
4
|
|
5
5
|
TYPES = {
|
6
6
|
'c' => :char,
|
@@ -31,6 +31,7 @@ module ObjC
|
|
31
31
|
|
32
32
|
def initialize name,options
|
33
33
|
@name = name.to_sym
|
34
|
+
@ruby_name = name.to_sym
|
34
35
|
@names = options[:names].map(&:to_sym)
|
35
36
|
@types = options[:types]
|
36
37
|
@return_type = options[:retval]
|
@@ -280,12 +281,12 @@ module ObjC
|
|
280
281
|
|
281
282
|
ret = if params.size > 0 && params.last.first == :rest
|
282
283
|
args = args.map{ |arg| Cocoa::instance_for(arg) }
|
283
|
-
instance.send(
|
284
|
+
instance.send(ruby_name, args.first, Hash[*names.zip(args[1..-1]).flatten])
|
284
285
|
elsif keys.size > 0
|
285
286
|
args = args.map{ |arg| Cocoa::instance_for(arg) }
|
286
|
-
instance.send(
|
287
|
+
instance.send(ruby_name, args.first, Hash[*keys.zip(args[1..-1]).flatten])
|
287
288
|
else
|
288
|
-
instance.send(
|
289
|
+
instance.send(ruby_name, *args.map{ |arg| Cocoa::instance_for(arg) })
|
289
290
|
end
|
290
291
|
ffi_return_value(ret)
|
291
292
|
end
|
data/spec/cocoa/cocoa_spec.rb
CHANGED
@@ -17,6 +17,17 @@ describe 'Cocoa' do
|
|
17
17
|
Derived.superclass.name.should == 'Cocoa::NSObject'
|
18
18
|
end
|
19
19
|
|
20
|
+
it 'should provide native names' do
|
21
|
+
class Derived < Cocoa::NSObject
|
22
|
+
end
|
23
|
+
module Scoped; end
|
24
|
+
class Scoped::Derived < Cocoa::NSObject
|
25
|
+
end
|
26
|
+
Cocoa::NSObject.native_name.should == 'NSObject'
|
27
|
+
Derived.native_name.should == 'Derived'
|
28
|
+
Scoped::Derived.native_name.should == 'Scoped__Derived'
|
29
|
+
end
|
30
|
+
|
20
31
|
it 'should provide correct return types for class methods' do
|
21
32
|
Cocoa::NSMutableArray.array.class.name.should == 'Cocoa::NSMutableArray'
|
22
33
|
end
|
@@ -115,6 +126,7 @@ describe 'Cocoa' do
|
|
115
126
|
# fake ruby 2
|
116
127
|
unbound_method = mock('UnboundMethod')
|
117
128
|
Cocoa::NSObject.expects(:instance_method).with(:tableView).at_least_once.returns(unbound_method)
|
129
|
+
Cocoa::NSObject.expects(:instance_method).with(:_tableView_with_objectValueForTableColumn_and_row).at_least_once.returns(unbound_method)
|
118
130
|
unbound_method.expects(:parameters).at_least_once.returns([[:req, :table_view], [:key, :objectValueForTableColumn], [:key, :row]])
|
119
131
|
class Derived < Cocoa::NSObject
|
120
132
|
#def tableView(table_view, objectValueForTableColumn: column, row: i); end
|
@@ -122,7 +134,7 @@ describe 'Cocoa' do
|
|
122
134
|
end
|
123
135
|
|
124
136
|
derived = Derived.new
|
125
|
-
derived.expects(:
|
137
|
+
derived.expects(:_tableView_with_objectValueForTableColumn_and_row).with(
|
126
138
|
Cocoa::NSString.stringWithString("arg1"),
|
127
139
|
objectValueForTableColumn: Cocoa::NSString.stringWithString("arg2"),
|
128
140
|
row: 123
|
@@ -137,6 +149,7 @@ describe 'Cocoa' do
|
|
137
149
|
# fake ruby 2
|
138
150
|
unbound_method = mock('UnboundMethod')
|
139
151
|
Cocoa::NSObject.expects(:instance_method).with(:tableView).at_least_once.returns(unbound_method)
|
152
|
+
Cocoa::NSObject.expects(:instance_method).with(:_tableView_with_objectValueForTableColumn_and_row).at_least_once.returns(unbound_method)
|
140
153
|
unbound_method.expects(:parameters).at_least_once.returns([[:req, :table_view], [:key, :objectValueForTableColumn], [:key, :row]])
|
141
154
|
class Derived < Cocoa::NSObject
|
142
155
|
#def tableView(table_view, objectValueForTableColumn: column, row: i); end
|
@@ -157,7 +170,7 @@ describe 'Cocoa' do
|
|
157
170
|
end
|
158
171
|
|
159
172
|
derived = Derived.new
|
160
|
-
derived.expects(:
|
173
|
+
derived.expects(:_tableView_with_objectValueForTableColumn_and_row).with(
|
161
174
|
Cocoa::NSString.stringWithString("arg1"),
|
162
175
|
objectValueForTableColumn: Cocoa::NSString.stringWithString("arg2"),
|
163
176
|
row: 123
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
require 'cocoa'
|
3
|
+
|
4
|
+
describe 'Cocoa' do
|
5
|
+
# context 'callbacks' do
|
6
|
+
it 'should be able to call overridden methods with keword arguments and return a value' do
|
7
|
+
class Derived < Cocoa::NSObject
|
8
|
+
def tableView(table_view, objectValueForTableColumn: column, row: i)
|
9
|
+
"returned value"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
derived = Derived.new
|
14
|
+
ret = derived.tableView("arg1", objectValueForTableColumn: "arg2", row: 123)
|
15
|
+
ret.to_s.should == "returned value"
|
16
|
+
end
|
17
|
+
# end
|
18
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cocoa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Patrick Hanevold
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-04-
|
11
|
+
date: 2014-04-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -550,6 +550,7 @@ files:
|
|
550
550
|
- lib/cocoa/structs/NSRect.rb
|
551
551
|
- lib/cocoa/structs/NSSize.rb
|
552
552
|
- spec/cocoa/cocoa_spec.rb
|
553
|
+
- spec/cocoa/cocoa_spec_r2.rb
|
553
554
|
- spec/spec_helper.rb
|
554
555
|
- tasks/bacon.rake
|
555
556
|
- tasks/generate.rake
|