gir_ffi 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/DESIGN.rdoc +9 -0
  2. data/History.txt +11 -0
  3. data/TODO.rdoc +6 -9
  4. data/examples/01_empty_window.rb +1 -1
  5. data/examples/02_hello_world.rb +4 -4
  6. data/examples/03_upgraded_hello_world.rb +7 -8
  7. data/lib/gir_ffi.rb +0 -4
  8. data/lib/gir_ffi/arg_helper.rb +27 -2
  9. data/lib/gir_ffi/builder.rb +13 -86
  10. data/lib/gir_ffi/builder_helper.rb +2 -15
  11. data/lib/gir_ffi/class_base.rb +51 -0
  12. data/lib/gir_ffi/class_builder.rb +178 -52
  13. data/lib/gir_ffi/function_definition_builder.rb +46 -9
  14. data/lib/gir_ffi/g_object.rb +37 -0
  15. data/lib/gir_ffi/i_arg_info.rb +27 -9
  16. data/lib/gir_ffi/i_base_info.rb +12 -4
  17. data/lib/gir_ffi/i_callable_info.rb +15 -5
  18. data/lib/gir_ffi/i_enum_info.rb +9 -3
  19. data/lib/gir_ffi/i_field_info.rb +12 -4
  20. data/lib/gir_ffi/i_function_info.rb +24 -8
  21. data/lib/gir_ffi/i_object_info.rb +63 -21
  22. data/lib/gir_ffi/i_registered_type_info.rb +11 -0
  23. data/lib/gir_ffi/i_repository.rb +2 -2
  24. data/lib/gir_ffi/i_signal_info.rb +1 -1
  25. data/lib/gir_ffi/i_struct_info.rb +24 -8
  26. data/lib/gir_ffi/i_type_info.rb +24 -8
  27. data/lib/gir_ffi/i_union_info.rb +15 -0
  28. data/lib/gir_ffi/i_value_info.rb +3 -1
  29. data/lib/gir_ffi/i_vfunc_info.rb +12 -1
  30. data/lib/gir_ffi/lib.rb +23 -1
  31. data/lib/gir_ffi/lib_c.rb +1 -1
  32. data/lib/gir_ffi/module_base.rb +19 -0
  33. data/lib/gir_ffi/module_builder.rb +67 -20
  34. data/lib/gir_ffi/overrides/gobject.rb +174 -0
  35. data/lib/gir_ffi/overrides/gtk.rb +26 -9
  36. data/test/builder_test.rb +57 -37
  37. data/test/{base_test.rb → class_base_test.rb} +3 -3
  38. data/test/class_builder_test.rb +48 -6
  39. data/test/everything_test.rb +285 -36
  40. data/test/function_definition_builder_test.rb +11 -9
  41. data/test/g_object_test.rb +22 -0
  42. data/test/gobject_overrides_test.rb +216 -0
  43. data/test/i_object_info_test.rb +21 -0
  44. data/test/module_builder_test.rb +54 -0
  45. data/test/test_helper.rb +6 -4
  46. metadata +18 -14
  47. data/lib/gir_ffi/base.rb +0 -25
  48. data/lib/gir_ffi/constructor_definition_builder.rb +0 -20
  49. data/lib/gir_ffi/g_type.rb +0 -14
  50. data/lib/gir_ffi/method_missing_definition_builder.rb +0 -59
  51. data/test/constructor_definition_builder_test.rb +0 -19
  52. 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
- get_gir_info
18
- instantiate_module
19
- case @info.type
20
- when :object, :struct
21
- instantiate_class
22
- setup_class unless already_set_up
23
- when :enum, :flags
24
- @klass = BuilderHelper.optionally_define_constant @module, @classname do
25
- vals = @info.values.map {|v| [v.name.to_sym, v.value]}.flatten
26
- @lib.enum(@classname.to_sym, vals)
27
- end
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 get_gir_info
33
- gir = IRepository.default
34
- gir.require @namespace, nil
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
- @info = gir.find_by_name @namespace, @classname
37
- raise "Class #{@classname} not found in namespace #{@namespace}" if @info.nil?
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 get_superclass
41
- @parent = @info.type == :object ? @info.parent : nil
42
- if @parent
43
- @superclass = Builder.build_class @parent.namespace, @parent.name
44
- else
45
- @superclass = GirFFI::Base
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 instantiate_module
50
- @module = Builder.build_module @namespace
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
- get_superclass
56
- @klass = BuilderHelper.get_or_define_class @module, @classname, @superclass
57
- @structklass = BuilderHelper.get_or_define_class @klass, :Struct, FFI::Struct
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
- alias_instance_methods
64
- end
124
+ setup_constants
125
+ setup_instance_methods
126
+ setup_gtype_getter
65
127
 
66
- def setup_method_missing
67
- @klass.class_eval instance_method_missing_definition
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
- if @info.fields.empty?
78
- if @parent
79
- return [:parent, @superclass.const_get(:Struct), 0]
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
- spec = []
83
- @info.fields.each do |f|
84
- spec << f.name.to_sym
85
- spec << itypeinfo_to_ffitype_for_struct(f.type)
86
- spec << f.offset
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 BuilderHelper.const_defined_for ffitype, :Struct
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 alias_instance_methods
100
- @info.methods.each do |m|
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 instance_method_missing_definition
110
- InstanceMethodMissingDefinitionBuilder.new(@lib, @module, @namespace, @classname).generate
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 class_method_missing_definition
114
- ClassMethodMissingDefinitionBuilder.new(@lib, @module, @namespace, @classname).generate
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.instance_methods(false).map(&:to_sym).include? :method_missing
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 NotImplementedError
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 << "#{@libmodule}::CALLBACKS << #{procvar}"
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
- retval = new_var
107
- @capture = "#{retval} = "
136
+ cvar = new_var
137
+ @capture = "#{cvar} = "
108
138
 
109
139
  if tag == :interface
110
140
  interface = type.interface
111
- GirFFI::Builder.build_class interface.namespace, interface.name
112
- @retvals << "#{interface.namespace}::#{interface.name}._real_new(#{retval})"
113
- else
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 << "GirFFI::ArgHelper.check_error(#{errvar})"
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}#{@libmodule}.#{@info.symbol} #{@callargs.join(', ')}
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
+
@@ -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; Lib.g_arg_info_get_direction @gobj; end
7
- def return_value?; Lib.g_arg_info_is_return_value @gobj; end
8
- def optional?; Lib.g_arg_info_is_optional @gobj; end
9
- def may_be_null?; Lib.g_arg_info_may_be_null @gobj; end
10
- def ownership_transfer; Lib.g_arg_info_get_ownership_transfer @gobj; end
11
- def scope; Lib.g_arg_info_get_scope @gobj; end
12
- def closure; Lib.g_arg_info_get_closure @gobj; end
13
- def destroy; Lib.g_arg_info_get_destroy @gobj; end
14
- def type; ITypeInfo.wrap(Lib.g_arg_info_get_type @gobj); end
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