gir_ffi 0.0.3 → 0.0.4
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/DESIGN.rdoc +9 -0
- data/History.txt +11 -0
- data/TODO.rdoc +6 -9
- data/examples/01_empty_window.rb +1 -1
- data/examples/02_hello_world.rb +4 -4
- data/examples/03_upgraded_hello_world.rb +7 -8
- data/lib/gir_ffi.rb +0 -4
- data/lib/gir_ffi/arg_helper.rb +27 -2
- data/lib/gir_ffi/builder.rb +13 -86
- data/lib/gir_ffi/builder_helper.rb +2 -15
- data/lib/gir_ffi/class_base.rb +51 -0
- data/lib/gir_ffi/class_builder.rb +178 -52
- data/lib/gir_ffi/function_definition_builder.rb +46 -9
- data/lib/gir_ffi/g_object.rb +37 -0
- data/lib/gir_ffi/i_arg_info.rb +27 -9
- data/lib/gir_ffi/i_base_info.rb +12 -4
- data/lib/gir_ffi/i_callable_info.rb +15 -5
- data/lib/gir_ffi/i_enum_info.rb +9 -3
- data/lib/gir_ffi/i_field_info.rb +12 -4
- data/lib/gir_ffi/i_function_info.rb +24 -8
- data/lib/gir_ffi/i_object_info.rb +63 -21
- data/lib/gir_ffi/i_registered_type_info.rb +11 -0
- data/lib/gir_ffi/i_repository.rb +2 -2
- data/lib/gir_ffi/i_signal_info.rb +1 -1
- data/lib/gir_ffi/i_struct_info.rb +24 -8
- data/lib/gir_ffi/i_type_info.rb +24 -8
- data/lib/gir_ffi/i_union_info.rb +15 -0
- data/lib/gir_ffi/i_value_info.rb +3 -1
- data/lib/gir_ffi/i_vfunc_info.rb +12 -1
- data/lib/gir_ffi/lib.rb +23 -1
- data/lib/gir_ffi/lib_c.rb +1 -1
- data/lib/gir_ffi/module_base.rb +19 -0
- data/lib/gir_ffi/module_builder.rb +67 -20
- data/lib/gir_ffi/overrides/gobject.rb +174 -0
- data/lib/gir_ffi/overrides/gtk.rb +26 -9
- data/test/builder_test.rb +57 -37
- data/test/{base_test.rb → class_base_test.rb} +3 -3
- data/test/class_builder_test.rb +48 -6
- data/test/everything_test.rb +285 -36
- data/test/function_definition_builder_test.rb +11 -9
- data/test/g_object_test.rb +22 -0
- data/test/gobject_overrides_test.rb +216 -0
- data/test/i_object_info_test.rb +21 -0
- data/test/module_builder_test.rb +54 -0
- data/test/test_helper.rb +6 -4
- metadata +18 -14
- data/lib/gir_ffi/base.rb +0 -25
- data/lib/gir_ffi/constructor_definition_builder.rb +0 -20
- data/lib/gir_ffi/g_type.rb +0 -14
- data/lib/gir_ffi/method_missing_definition_builder.rb +0 -59
- data/test/constructor_definition_builder_test.rb +0 -19
- data/test/g_type_test.rb +0 -22
@@ -1,7 +1,9 @@
|
|
1
|
+
require 'gir_ffi/builder_helper'
|
1
2
|
module GirFFI
|
2
3
|
# Builds a class based on information found in the introspection
|
3
4
|
# repository.
|
4
5
|
class ClassBuilder
|
6
|
+
include BuilderHelper
|
5
7
|
def initialize namespace, classname
|
6
8
|
@namespace = namespace
|
7
9
|
@classname = classname
|
@@ -11,61 +13,120 @@ module GirFFI
|
|
11
13
|
build_class
|
12
14
|
end
|
13
15
|
|
16
|
+
def setup_method method
|
17
|
+
definition = prepare_method method.to_s
|
18
|
+
|
19
|
+
return false if definition.nil?
|
20
|
+
|
21
|
+
klass = build_class
|
22
|
+
meta = (class << klass; self; end)
|
23
|
+
meta.class_eval definition
|
24
|
+
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
def setup_instance_method method
|
29
|
+
definition = prepare_method method.to_s
|
30
|
+
|
31
|
+
if definition.nil?
|
32
|
+
if parent
|
33
|
+
return superclass.gir_ffi_builder.setup_instance_method method
|
34
|
+
else
|
35
|
+
return false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
klass = build_class
|
40
|
+
klass.class_eval "undef #{method}"
|
41
|
+
klass.class_eval definition
|
42
|
+
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
def find_signal signal_name
|
47
|
+
info.signals.each do |s|
|
48
|
+
return s if s.name == signal_name
|
49
|
+
end
|
50
|
+
if info.parent
|
51
|
+
return superclass.gir_ffi_builder.find_signal signal_name
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
14
55
|
private
|
15
56
|
|
16
57
|
def build_class
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
@
|
27
|
-
|
58
|
+
unless defined? @klass
|
59
|
+
case info.type
|
60
|
+
when :object, :struct
|
61
|
+
instantiate_class
|
62
|
+
setup_class unless already_set_up
|
63
|
+
when :union
|
64
|
+
instantiate_union_class
|
65
|
+
setup_class unless already_set_up
|
66
|
+
when :enum, :flags
|
67
|
+
@klass = optionally_define_constant namespace_module, @classname do
|
68
|
+
vals = info.values.map {|v| [v.name.to_sym, v.value]}.flatten
|
69
|
+
lib.enum(@classname.to_sym, vals)
|
70
|
+
end
|
71
|
+
else
|
72
|
+
raise NotImplementedError, "Cannot build classes of type #{info.type}"
|
73
|
+
end
|
28
74
|
end
|
29
75
|
@klass
|
30
76
|
end
|
31
77
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
78
|
+
def info
|
79
|
+
unless defined? @info
|
80
|
+
@info = gir.find_by_name @namespace, @classname
|
81
|
+
raise "Class #{@classname} not found in namespace #{@namespace}" if @info.nil?
|
82
|
+
end
|
83
|
+
@info
|
84
|
+
end
|
35
85
|
|
36
|
-
|
37
|
-
|
86
|
+
def parent
|
87
|
+
unless defined? @parent
|
88
|
+
@parent = info.type == :object ? info.parent : nil
|
89
|
+
end
|
90
|
+
@parent
|
38
91
|
end
|
39
92
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
93
|
+
def superclass
|
94
|
+
unless defined? @superclass
|
95
|
+
if parent
|
96
|
+
@superclass = Builder.build_class parent.namespace, parent.name
|
97
|
+
else
|
98
|
+
@superclass = GirFFI::ClassBase
|
99
|
+
end
|
46
100
|
end
|
101
|
+
@superclass
|
102
|
+
end
|
103
|
+
|
104
|
+
def namespace_module
|
105
|
+
@namespace_module ||= Builder.build_module @namespace
|
47
106
|
end
|
48
107
|
|
49
|
-
def
|
50
|
-
@
|
51
|
-
@lib = @module.const_get :Lib
|
108
|
+
def lib
|
109
|
+
@lib ||= namespace_module.const_get :Lib
|
52
110
|
end
|
53
111
|
|
54
112
|
def instantiate_class
|
55
|
-
|
56
|
-
@
|
57
|
-
|
113
|
+
@klass = get_or_define_class namespace_module, @classname, superclass
|
114
|
+
@structklass = get_or_define_class @klass, :Struct, FFI::Struct
|
115
|
+
end
|
116
|
+
|
117
|
+
def instantiate_union_class
|
118
|
+
@klass = get_or_define_class namespace_module, @classname, superclass
|
119
|
+
@structklass = get_or_define_class @klass, :Struct, FFI::Union
|
58
120
|
end
|
59
121
|
|
60
122
|
def setup_class
|
61
|
-
setup_method_missing
|
62
123
|
setup_layout
|
63
|
-
|
64
|
-
|
124
|
+
setup_constants
|
125
|
+
setup_instance_methods
|
126
|
+
setup_gtype_getter
|
65
127
|
|
66
|
-
|
67
|
-
|
68
|
-
@klass.class_eval class_method_missing_definition
|
128
|
+
setup_vfunc_invokers if info.type == :object
|
129
|
+
provide_struct_constructor if info.type == :struct
|
69
130
|
end
|
70
131
|
|
71
132
|
def setup_layout
|
@@ -74,30 +135,34 @@ module GirFFI
|
|
74
135
|
end
|
75
136
|
|
76
137
|
def layout_specification
|
77
|
-
|
78
|
-
|
79
|
-
|
138
|
+
fields = info.fields
|
139
|
+
|
140
|
+
if fields.empty?
|
141
|
+
if parent
|
142
|
+
return [:parent, superclass.const_get(:Struct), 0]
|
80
143
|
end
|
81
144
|
end
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
end
|
88
|
-
spec
|
145
|
+
|
146
|
+
fields.map do |f|
|
147
|
+
[ f.name.to_sym,
|
148
|
+
itypeinfo_to_ffitype_for_struct(f.type),
|
149
|
+
f.offset ]
|
150
|
+
end.flatten
|
89
151
|
end
|
90
152
|
|
91
153
|
def itypeinfo_to_ffitype_for_struct typeinfo
|
92
154
|
ffitype = Builder.itypeinfo_to_ffitype typeinfo
|
93
|
-
if ffitype.kind_of?(Class) and
|
155
|
+
if ffitype.kind_of?(Class) and const_defined_for ffitype, :Struct
|
94
156
|
ffitype = ffitype.const_get :Struct
|
95
157
|
end
|
158
|
+
if ffitype == :bool
|
159
|
+
ffitype = :int
|
160
|
+
end
|
96
161
|
ffitype
|
97
162
|
end
|
98
163
|
|
99
|
-
def
|
100
|
-
|
164
|
+
def setup_instance_methods
|
165
|
+
info.methods.each do |m|
|
101
166
|
@klass.class_eval "
|
102
167
|
def #{m.name} *args, &block
|
103
168
|
method_missing :#{m.name}, *args, &block
|
@@ -106,16 +171,77 @@ module GirFFI
|
|
106
171
|
end
|
107
172
|
end
|
108
173
|
|
109
|
-
def
|
110
|
-
|
174
|
+
def setup_gtype_getter
|
175
|
+
getter = info.type_init
|
176
|
+
return if getter.nil? or getter == "intern"
|
177
|
+
lib.attach_function getter.to_sym, [], :int
|
178
|
+
@klass.class_eval "
|
179
|
+
def self.get_gtype
|
180
|
+
::#{lib}.#{getter}
|
181
|
+
end
|
182
|
+
"
|
183
|
+
end
|
184
|
+
|
185
|
+
def setup_vfunc_invokers
|
186
|
+
info.vfuncs.each do |v|
|
187
|
+
invoker = v.invoker
|
188
|
+
next if invoker.nil?
|
189
|
+
next if invoker.name == v.name
|
190
|
+
|
191
|
+
@klass.class_eval "
|
192
|
+
def #{v.name} *args, &block
|
193
|
+
#{invoker.name}(*args, &block)
|
194
|
+
end
|
195
|
+
"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def provide_struct_constructor
|
200
|
+
return if info.find_method 'new'
|
201
|
+
|
202
|
+
(class << @klass; self; end).class_eval {
|
203
|
+
alias_method :new, :_real_new
|
204
|
+
}
|
111
205
|
end
|
112
206
|
|
113
|
-
def
|
114
|
-
|
207
|
+
def setup_constants
|
208
|
+
@klass.const_set :GIR_INFO, info
|
209
|
+
@klass.const_set :GIR_FFI_BUILDER, self
|
115
210
|
end
|
116
211
|
|
117
212
|
def already_set_up
|
118
|
-
@klass
|
213
|
+
const_defined_for @klass, :GIR_FFI_BUILDER
|
214
|
+
end
|
215
|
+
|
216
|
+
def method_introspection_data method
|
217
|
+
info.find_method method
|
218
|
+
end
|
219
|
+
|
220
|
+
def function_definition go
|
221
|
+
FunctionDefinitionBuilder.new(go, lib).generate
|
222
|
+
end
|
223
|
+
|
224
|
+
def prepare_method method
|
225
|
+
go = method_introspection_data method
|
226
|
+
|
227
|
+
return nil if go.nil?
|
228
|
+
|
229
|
+
Builder.attach_ffi_function lib, go
|
230
|
+
function_definition go
|
231
|
+
end
|
232
|
+
|
233
|
+
def gir
|
234
|
+
unless defined? @gir
|
235
|
+
@gir = IRepository.default
|
236
|
+
@gir.require @namespace, nil
|
237
|
+
end
|
238
|
+
@gir
|
239
|
+
end
|
240
|
+
|
241
|
+
def get_or_define_class namespace, name, parent
|
242
|
+
optionally_define_constant(namespace, name) {
|
243
|
+
Class.new parent
|
244
|
+
}
|
119
245
|
end
|
120
246
|
end
|
121
247
|
end
|
@@ -44,8 +44,10 @@ module GirFFI
|
|
44
44
|
process_inout_arg arg
|
45
45
|
when :in
|
46
46
|
process_in_arg arg
|
47
|
+
when :out
|
48
|
+
process_out_arg arg
|
47
49
|
else
|
48
|
-
raise
|
50
|
+
raise ArgumentError
|
49
51
|
end
|
50
52
|
end
|
51
53
|
|
@@ -76,6 +78,34 @@ module GirFFI
|
|
76
78
|
@retvals << postvar
|
77
79
|
end
|
78
80
|
|
81
|
+
def process_out_arg arg
|
82
|
+
prevar = new_var
|
83
|
+
postvar = new_var
|
84
|
+
|
85
|
+
case arg.type.tag
|
86
|
+
when :int, :int32
|
87
|
+
@pre << "#{prevar} = GirFFI::ArgHelper.int_to_inoutptr 0"
|
88
|
+
@post << "#{postvar} = GirFFI::ArgHelper.outptr_to_int #{prevar}"
|
89
|
+
when :double
|
90
|
+
@pre << "#{prevar} = GirFFI::ArgHelper.double_to_inoutptr 0"
|
91
|
+
@post << "#{postvar} = GirFFI::ArgHelper.outptr_to_double #{prevar}"
|
92
|
+
when :interface
|
93
|
+
iface = arg.type.interface
|
94
|
+
if iface.type == :struct
|
95
|
+
@pre << "#{prevar} = #{iface.namespace}::#{iface.name}.new"
|
96
|
+
@post << "#{postvar} = #{prevar}"
|
97
|
+
else
|
98
|
+
raise NotImplementedError,
|
99
|
+
"Don't know what to do with interface type #{iface.type}"
|
100
|
+
end
|
101
|
+
else
|
102
|
+
raise NotImplementedError,
|
103
|
+
"Don't know what to do with argument type #{arg.type.tag}"
|
104
|
+
end
|
105
|
+
@callargs << prevar
|
106
|
+
@retvals << postvar
|
107
|
+
end
|
108
|
+
|
79
109
|
def process_in_arg arg
|
80
110
|
name = safe arg.name
|
81
111
|
type = arg.type
|
@@ -87,7 +117,7 @@ module GirFFI
|
|
87
117
|
# TODO: Use arg.scope to decide if this is needed.
|
88
118
|
procvar = new_var
|
89
119
|
@pre << "#{procvar} = GirFFI::ArgHelper.mapped_callback_args #{name}"
|
90
|
-
@pre << "
|
120
|
+
@pre << "::#{@libmodule}::CALLBACKS << #{procvar}"
|
91
121
|
@callargs << procvar
|
92
122
|
elsif tag == :void
|
93
123
|
raise NotImplementedError unless arg.type.pointer?
|
@@ -103,15 +133,22 @@ module GirFFI
|
|
103
133
|
type = @info.return_type
|
104
134
|
tag = type.tag
|
105
135
|
return if tag == :void
|
106
|
-
|
107
|
-
@capture = "#{
|
136
|
+
cvar = new_var
|
137
|
+
@capture = "#{cvar} = "
|
108
138
|
|
109
139
|
if tag == :interface
|
110
140
|
interface = type.interface
|
111
|
-
|
112
|
-
|
113
|
-
|
141
|
+
namespace = interface.namespace
|
142
|
+
name = interface.name
|
143
|
+
GirFFI::Builder.build_class namespace, name
|
144
|
+
retval = new_var
|
145
|
+
@post << "#{retval} = ::#{namespace}::#{name}._real_new(#{cvar})"
|
146
|
+
if interface.type == :object
|
147
|
+
@post << "GirFFI::ArgHelper.sink_if_floating(#{retval})"
|
148
|
+
end
|
114
149
|
@retvals << retval
|
150
|
+
else
|
151
|
+
@retvals << cvar
|
115
152
|
end
|
116
153
|
end
|
117
154
|
|
@@ -119,7 +156,7 @@ module GirFFI
|
|
119
156
|
if @info.throws?
|
120
157
|
errvar = new_var
|
121
158
|
@pre << "#{errvar} = FFI::MemoryPointer.new(:pointer).write_pointer nil"
|
122
|
-
@post
|
159
|
+
@post.unshift "GirFFI::ArgHelper.check_error(#{errvar})"
|
123
160
|
@callargs << errvar
|
124
161
|
end
|
125
162
|
|
@@ -134,7 +171,7 @@ module GirFFI
|
|
134
171
|
return <<-CODE
|
135
172
|
def #{@info.name} #{@inargs.join(', ')}
|
136
173
|
#{@pre.join("\n")}
|
137
|
-
#{@capture}
|
174
|
+
#{@capture}::#{@libmodule}.#{@info.symbol} #{@callargs.join(', ')}
|
138
175
|
#{@post.join("\n")}
|
139
176
|
end
|
140
177
|
CODE
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module GirFFI
|
4
|
+
module GObject
|
5
|
+
def self.type_init
|
6
|
+
Lib::g_type_init
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.object_ref o
|
10
|
+
Lib::g_object_ref o.to_ptr
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.object_ref_sink o
|
14
|
+
Lib::g_object_ref_sink o.to_ptr
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.object_unref o
|
18
|
+
Lib::g_object_unref o.to_ptr
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.object_is_floating o
|
22
|
+
Lib::g_object_is_floating o.to_ptr
|
23
|
+
end
|
24
|
+
|
25
|
+
module Lib
|
26
|
+
extend FFI::Library
|
27
|
+
ffi_lib "gobject-2.0"
|
28
|
+
attach_function :g_type_init, [], :void
|
29
|
+
attach_function :g_object_ref, [:pointer], :void
|
30
|
+
attach_function :g_object_ref_sink, [:pointer], :void
|
31
|
+
attach_function :g_object_unref, [:pointer], :void
|
32
|
+
attach_function :g_object_is_floating, [:pointer], :bool
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
data/lib/gir_ffi/i_arg_info.rb
CHANGED
@@ -3,14 +3,32 @@ module GirFFI
|
|
3
3
|
# Wraps a GIArgInfo struct.
|
4
4
|
# Represents an argument.
|
5
5
|
class IArgInfo < IBaseInfo
|
6
|
-
def direction
|
7
|
-
|
8
|
-
|
9
|
-
def
|
10
|
-
|
11
|
-
|
12
|
-
def
|
13
|
-
|
14
|
-
|
6
|
+
def direction
|
7
|
+
Lib.g_arg_info_get_direction @gobj
|
8
|
+
end
|
9
|
+
def return_value?
|
10
|
+
Lib.g_arg_info_is_return_value @gobj
|
11
|
+
end
|
12
|
+
def optional?
|
13
|
+
Lib.g_arg_info_is_optional @gobj
|
14
|
+
end
|
15
|
+
def may_be_null?
|
16
|
+
Lib.g_arg_info_may_be_null @gobj
|
17
|
+
end
|
18
|
+
def ownership_transfer
|
19
|
+
Lib.g_arg_info_get_ownership_transfer @gobj
|
20
|
+
end
|
21
|
+
def scope
|
22
|
+
Lib.g_arg_info_get_scope @gobj
|
23
|
+
end
|
24
|
+
def closure
|
25
|
+
Lib.g_arg_info_get_closure @gobj
|
26
|
+
end
|
27
|
+
def destroy
|
28
|
+
Lib.g_arg_info_get_destroy @gobj
|
29
|
+
end
|
30
|
+
def type
|
31
|
+
ITypeInfo.wrap(Lib.g_arg_info_get_type @gobj)
|
32
|
+
end
|
15
33
|
end
|
16
34
|
end
|