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.
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