gir_ffi 0.6.3 → 0.6.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/History.txt +11 -0
  2. data/README.md +24 -6
  3. data/lib/ffi-glib/ptr_array.rb +17 -1
  4. data/lib/ffi-glib/variant.rb +15 -0
  5. data/lib/ffi-glib.rb +1 -0
  6. data/lib/ffi-gobject/object.rb +1 -1
  7. data/lib/ffi-gobject/ruby_closure.rb +1 -1
  8. data/lib/ffi-gobject/value.rb +13 -3
  9. data/lib/ffi-gobject.rb +1 -2
  10. data/lib/ffi-gobject_introspection/i_enum_info.rb +14 -0
  11. data/lib/ffi-gobject_introspection/lib.rb +2 -0
  12. data/lib/gir_ffi/arg_helper.rb +2 -0
  13. data/lib/gir_ffi/argument_builder.rb +22 -21
  14. data/lib/gir_ffi/base_argument_builder.rb +2 -1
  15. data/lib/gir_ffi/builder/module.rb +2 -3
  16. data/lib/gir_ffi/builder/type/enum.rb +18 -1
  17. data/lib/gir_ffi/builder/type/object.rb +20 -18
  18. data/lib/gir_ffi/class_base.rb +0 -1
  19. data/lib/gir_ffi/enum_base.rb +25 -0
  20. data/lib/gir_ffi/ffi_ext.rb +1 -0
  21. data/lib/gir_ffi/function_builder.rb +50 -33
  22. data/lib/gir_ffi/in_out_pointer.rb +0 -5
  23. data/lib/gir_ffi/in_pointer.rb +7 -5
  24. data/lib/gir_ffi/info_ext/i_callable_info.rb +4 -0
  25. data/lib/gir_ffi/info_ext/i_enum_info.rb +13 -0
  26. data/lib/gir_ffi/info_ext/i_field_info.rb +1 -1
  27. data/lib/gir_ffi/info_ext/i_object_info.rb +11 -0
  28. data/lib/gir_ffi/info_ext/i_registered_type_info.rb +11 -0
  29. data/lib/gir_ffi/info_ext/i_struct_info.rb +11 -0
  30. data/lib/gir_ffi/info_ext/i_type_info.rb +10 -19
  31. data/lib/gir_ffi/info_ext/i_union_info.rb +12 -0
  32. data/lib/gir_ffi/info_ext/safe_constant_name.rb +0 -2
  33. data/lib/gir_ffi/info_ext.rb +4 -0
  34. data/lib/gir_ffi/interface_base.rb +0 -1
  35. data/lib/gir_ffi/return_value_builder.rb +3 -2
  36. data/lib/gir_ffi/type_map.rb +3 -0
  37. data/lib/gir_ffi/version.rb +1 -1
  38. data/lib/gir_ffi/zero_terminated.rb +36 -3
  39. data/lib/gir_ffi-base/gir_ffi/library.rb +17 -0
  40. data/lib/gir_ffi-base/gobject/lib.rb +2 -2
  41. data/lib/gir_ffi.rb +1 -0
  42. data/tasks/test.rake +1 -0
  43. data/test/base_test_helper.rb +22 -2
  44. data/test/ffi-glib/ruby_closure_test.rb +1 -1
  45. data/test/ffi-glib/variant_test.rb +10 -0
  46. data/test/ffi-gobject/value_test.rb +24 -8
  47. data/test/ffi-gobject_introspection/i_enum_info_test.rb +17 -0
  48. data/test/gir_ffi/argument_builder_test.rb +66 -24
  49. data/test/gir_ffi/builder_test.rb +1 -1
  50. data/test/gir_ffi/function_builder_test.rb +1 -3
  51. data/test/gir_ffi/in_out_pointer_test.rb +5 -3
  52. data/test/gir_ffi/in_pointer_test.rb +32 -2
  53. data/test/gir_ffi/info_ext/i_arg_info_test.rb +2 -2
  54. data/test/gir_ffi/info_ext/i_callable_info_test.rb +2 -2
  55. data/test/gir_ffi/info_ext/i_field_info_test.rb +14 -20
  56. data/test/gir_ffi/info_ext/i_function_info_test.rb +2 -2
  57. data/test/gir_ffi/info_ext/i_signal_info_test.rb +2 -2
  58. data/test/gir_ffi/info_ext/i_type_info_test.rb +8 -8
  59. data/test/gir_ffi/info_ext/safe_constant_name_test.rb +2 -2
  60. data/test/gir_ffi/info_ext/safe_function_name_test.rb +2 -2
  61. data/test/gir_ffi/return_value_builder_test.rb +18 -1
  62. data/test/gir_ffi/zero_terminated_test.rb +10 -0
  63. data/test/gir_ffi_test_helper.rb +0 -19
  64. data/test/integration/generated_gimarshallingtests_test.rb +291 -99
  65. data/test/integration/generated_regress_test.rb +138 -14
  66. data/test/lib/autogen.sh +6 -2
  67. metadata +14 -2
data/History.txt CHANGED
@@ -1,3 +1,14 @@
1
+ == 0.6.4 / 2013-06-30
2
+
3
+ * Represent enum types by modules wrapping FFI::Enum
4
+ * Support functions on enums
5
+ * Handle zero-terminated arrays of types other than int32
6
+ * Add override for GLib::Variant#get_string
7
+ * Handle non-throwing arguments and return values of type GError
8
+ * Handle arguments and return values of type GPtrArray
9
+ * Handle caller-allocated arguments of type GArray
10
+ * Deprecate GObject::Value#ruby_value, replacing it with #get_value
11
+
1
12
  == 0.6.3 / 2013-06-15
2
13
 
3
14
  * Make use of enums as element type for GHashTable and other containers
data/README.md CHANGED
@@ -20,12 +20,18 @@ Ruby bindings for GNOME using the GObject Introspection Repository.
20
20
 
21
21
  require 'gir_ffi'
22
22
 
23
- GirFFI.setup :TheNamespace
23
+ # Set up the namespace you wish to use
24
+ GirFFI.setup :Gio
24
25
 
25
- TheNamespace.some_function
26
+ # Create an object
27
+ inet_address = Gio::InetAddress.new_from_string "127.0.0.1"
26
28
 
27
- obj = TheNamespace::SomeClass.new
28
- obj.some_method with, some, args
29
+ # Call some methods on the object
30
+ inet_address.is_loopback # => true
31
+ inet_address.is_multicast # => false
32
+
33
+ # Call a function in the namespace
34
+ Gio.dbus_is_name "foo" # => false
29
35
 
30
36
  ## Install
31
37
 
@@ -33,8 +39,8 @@ Ruby bindings for GNOME using the GObject Introspection Repository.
33
39
 
34
40
  ## Requirements
35
41
 
36
- GirFFI should work on MRI 1.8 and 1.9, and JRuby in both 1.8 and 1.9
37
- modes. It does not work on Rubinius yet.
42
+ GirFFI should work on MRI 1.8, 1.9 and 2.0, JRuby in both 1.8 and 1.9
43
+ modes, and on Rubinius in both 1.8 and 1.9 modes.
38
44
 
39
45
  You will also need gobject-introspection installed with some
40
46
  introspection data.
@@ -53,6 +59,18 @@ On Debian and Ubuntu, installing `libgirepository1.0-dev` and
53
59
 
54
60
  GirFFI has not been tested on Mac OS X or Microsoft Windows. YMMV.
55
61
 
62
+ ## Overrides
63
+
64
+ Sometimes, the GIR data is incorrect, or not detailed enough, and a
65
+ reasonable binding cannot be created automatically. For these cases,
66
+ overrides can be defined. The following gems with overrides
67
+ already exist:
68
+
69
+ * `gir_ffi-gtk`: overrides for Gtk+ 2 and 3.
70
+ * `gir_ffi-cairo`: overrides for Cairo
71
+ * `gir_ffi-pango`: overrides for Pango
72
+ * `gir_ffi-tracker`: overrides for Tracker
73
+
56
74
  ## Hacking and contributing
57
75
 
58
76
  If you want to help out, have a look at TODO.rdoc, and check the notes
@@ -15,10 +15,22 @@ module GLib
15
15
  end
16
16
 
17
17
  def self.new type
18
- wrap(Lib.g_ptr_array_new).tap {|it|
18
+ wrap(type, Lib.g_ptr_array_new)
19
+ end
20
+
21
+ def self.wrap type, ptr
22
+ super(ptr).tap {|it|
19
23
  it.element_type = type}
20
24
  end
21
25
 
26
+ def self.from type, it
27
+ case it
28
+ when self then it
29
+ when FFI::Pointer then wrap type, it
30
+ else self.new(type).tap {|arr| arr.add_array it}
31
+ end
32
+ end
33
+
22
34
  def self.add array, data
23
35
  array.add data
24
36
  end
@@ -28,6 +40,10 @@ module GLib
28
40
  Lib.g_ptr_array_add self, ptr
29
41
  end
30
42
 
43
+ def add_array ary
44
+ ary.each {|item| add item}
45
+ end
46
+
31
47
  # Re-implementation of the g_ptr_array_index macro
32
48
  def index idx
33
49
  sz = FFI.type_size :pointer
@@ -0,0 +1,15 @@
1
+ module GLib
2
+ load_class :Variant
3
+
4
+ # Overrides for GVariant, GLib's variant data type.
5
+ class Variant
6
+ setup_instance_method "get_string"
7
+
8
+ def get_string_with_override
9
+ get_string_without_override.first
10
+ end
11
+
12
+ alias get_string_without_override get_string
13
+ alias get_string get_string_with_override
14
+ end
15
+ end
data/lib/ffi-glib.rb CHANGED
@@ -11,6 +11,7 @@ require 'ffi-glib/ptr_array'
11
11
  require 'ffi-glib/s_list'
12
12
  require 'ffi-glib/sized_array'
13
13
  require 'ffi-glib/strv'
14
+ require 'ffi-glib/variant'
14
15
 
15
16
  module GLib
16
17
  load_class :HFunc
@@ -18,7 +18,7 @@ module GObject
18
18
 
19
19
  get_property_without_override property_name, gvalue
20
20
 
21
- adjust_value_to_type gvalue.ruby_value, type
21
+ adjust_value_to_type gvalue.get_value, type
22
22
  end
23
23
 
24
24
  def set_property_with_override property_name, value
@@ -43,7 +43,7 @@ module GObject
43
43
  rclosure = wrap(closure.to_ptr)
44
44
 
45
45
  args = n_param_values.times.map {|idx|
46
- Value.wrap(param_values.to_ptr + idx * Value::Struct.size).ruby_value
46
+ Value.wrap(param_values.to_ptr + idx * Value::Struct.size).get_value
47
47
  }
48
48
 
49
49
  result = rclosure.invoke_block(*args)
@@ -15,6 +15,7 @@ module GObject
15
15
  TYPE_TO_SET_METHOD_MAP = {
16
16
  TYPE_BOOLEAN => :set_boolean,
17
17
  TYPE_INT => :set_int,
18
+ TYPE_INT64 => :set_int64,
18
19
  TYPE_STRING => :set_string,
19
20
  TYPE_FLOAT => :set_float,
20
21
  TYPE_DOUBLE => :set_double,
@@ -25,6 +26,10 @@ module GObject
25
26
  TYPE_ENUM => :set_enum
26
27
  }
27
28
 
29
+ def value= val
30
+ set_value val
31
+ end
32
+
28
33
  def set_value val
29
34
  send set_method, val
30
35
  self
@@ -62,6 +67,7 @@ module GObject
62
67
  TYPE_TO_GET_METHOD_MAP = {
63
68
  TYPE_BOOLEAN => :get_boolean,
64
69
  TYPE_INT => :get_int,
70
+ TYPE_INT64 => :get_int64,
65
71
  TYPE_STRING => :get_string,
66
72
  TYPE_FLOAT => :get_float,
67
73
  TYPE_DOUBLE => :get_double,
@@ -70,11 +76,15 @@ module GObject
70
76
  TYPE_POINTER => :get_pointer
71
77
  }
72
78
 
73
- # TODO: Rename to get_value
74
- def ruby_value
79
+ def get_value
75
80
  send get_method
76
81
  end
77
82
 
83
+ # @deprecated Compatibility function. Remove in 0.7.0.
84
+ def ruby_value
85
+ get_value
86
+ end
87
+
78
88
  class << self
79
89
  # TODO: Give more generic name
80
90
  def wrap_ruby_value val
@@ -94,7 +104,7 @@ module GObject
94
104
 
95
105
  def for_g_type g_type
96
106
  return nil if g_type == TYPE_NONE
97
- self.new.tap {|it| it.init g_type }
107
+ self.new.init g_type
98
108
  end
99
109
  end
100
110
 
data/lib/ffi-gobject.rb CHANGED
@@ -109,8 +109,7 @@ module GObject
109
109
  attach_function :g_hash_table_get_type, [], :size_t
110
110
 
111
111
  attach_function :g_signal_connect_data,
112
- [:pointer, :string, Callback, :pointer, ClosureNotify,
113
- ConnectFlags],
112
+ [:pointer, :string, Callback, :pointer, ClosureNotify, ConnectFlags],
114
113
  :ulong
115
114
  attach_function :g_closure_set_marshal,
116
115
  [:pointer, ClosureMarshal], :void
@@ -11,6 +11,20 @@ module GObjectIntrospection
11
11
  ##
12
12
  build_array_method :values
13
13
 
14
+ def get_n_methods
15
+ Lib.g_enum_info_get_n_methods @gobj
16
+ end
17
+ def get_method(index)
18
+ IFunctionInfo.wrap(Lib.g_enum_info_get_method @gobj, index)
19
+ end
20
+
21
+ ##
22
+ build_array_method :get_methods
23
+
24
+ def find_method name
25
+ get_methods.find {|m| m.name == name}
26
+ end
27
+
14
28
  def storage_type
15
29
  Lib.g_enum_info_get_storage_type @gobj
16
30
  end
@@ -178,6 +178,8 @@ module GObjectIntrospection
178
178
  attach_function :g_enum_info_get_storage_type, [:pointer], :ITypeTag
179
179
  attach_function :g_enum_info_get_n_values, [:pointer], :int
180
180
  attach_function :g_enum_info_get_value, [:pointer, :int], :pointer
181
+ attach_function :g_enum_info_get_n_methods, [:pointer], :int
182
+ attach_function :g_enum_info_get_method, [:pointer, :int], :pointer
181
183
 
182
184
  # IObjectInfo
183
185
  attach_function :g_object_info_get_type_name, [:pointer], :string
@@ -29,6 +29,8 @@ module GirFFI
29
29
  case type
30
30
  when Class
31
31
  ptr_to_interface_array type, ptr, size
32
+ when Module
33
+ ptr_to_enum_array type, ptr, size
32
34
  when Array
33
35
  ptr_to_interface_pointer_array type[1], ptr, size
34
36
  when FFI::Enum
@@ -53,8 +53,6 @@ module GirFFI
53
53
  else
54
54
  "#{argument_class_name}.wrap(#{output_conversion_arguments})"
55
55
  end
56
- elsif is_fixed_length_array?
57
- "GLib::SizedArray.wrap(#{subtype_tag_or_class_name}, #{array_size}, #{callarg}.to_value)"
58
56
  else
59
57
  "#{callarg}.to_value"
60
58
  end
@@ -68,10 +66,6 @@ module GirFFI
68
66
  specialized_type_tag == :c && type_info.array_fixed_size > -1
69
67
  end
70
68
 
71
- def is_fixed_length_array?
72
- specialized_type_tag == :c
73
- end
74
-
75
69
  def fixed_array_size_check
76
70
  size = type_info.array_fixed_size
77
71
  "GirFFI::ArgHelper.check_fixed_array_size #{size}, #{@name}, \"#{@name}\""
@@ -93,7 +87,11 @@ module GirFFI
93
87
  def set_function_call_argument
94
88
  value = if @direction == :out
95
89
  if is_caller_allocated_object?
96
- "#{argument_class_name}._allocate"
90
+ if specialized_type_tag == :array
91
+ "#{argument_class_name}.new #{elm_t}"
92
+ else
93
+ "#{argument_class_name}.new"
94
+ end
97
95
  else
98
96
  "GirFFI::InOutPointer.for #{specialized_type_tag.inspect}"
99
97
  end
@@ -108,42 +106,45 @@ module GirFFI
108
106
  end
109
107
 
110
108
  def is_caller_allocated_object?
111
- [:object, :struct].include?(specialized_type_tag) &&
109
+ [ :struct, :array ].include?(specialized_type_tag) &&
112
110
  @arginfo.caller_allocates?
113
111
  end
114
112
 
115
113
  def needs_outgoing_parameter_conversion?
116
- [ :array, :enum, :flags, :ghash, :glist, :gslist, :object, :struct,
117
- :strv, :utf8 ].include?(specialized_type_tag)
114
+ [ :array, :c, :enum, :error, :flags, :ghash, :glist, :gslist, :object,
115
+ :ptr_array, :struct, :strv, :utf8 ].include?(specialized_type_tag)
118
116
  end
119
117
 
120
118
  def needs_ingoing_parameter_conversion?
121
119
  @direction == :inout ||
122
- [ :object, :struct, :callback, :utf8, :void, :glist, :gslist, :ghash,
123
- :array, :c, :zero_terminated, :strv ].include?(specialized_type_tag)
120
+ [ :array, :c, :callback, :ghash, :glist, :gslist, :object, :ptr_array,
121
+ :struct, :strv, :utf8, :void, :zero_terminated ].include?(specialized_type_tag)
124
122
  end
125
123
 
126
124
  def ingoing_parameter_conversion
127
125
  case specialized_type_tag
128
126
  when :enum, :flags
129
127
  base = "#{argument_class_name}[#{parameter_conversion_arguments}]"
130
- "GirFFI::InOutPointer.from #{specialized_type_tag.inspect}, #{base}"
131
- when :object, :struct, :void, :glist, :gslist, :ghash, :array,
132
- :zero_terminated, :strv, :callback, :utf8, :c
128
+ when :array, :c, :callback, :ghash, :glist, :gslist, :object, :ptr_array,
129
+ :struct, :strv, :utf8, :void, :zero_terminated
133
130
  base = "#{argument_class_name}.from(#{parameter_conversion_arguments})"
134
- if has_output_value?
135
- "GirFFI::InOutPointer.from :pointer, #{base}"
136
- else
137
- base
138
- end
139
131
  else
140
132
  base = "#{parameter_conversion_arguments}"
133
+ end
134
+
135
+ if has_output_value?
141
136
  "GirFFI::InOutPointer.from #{specialized_type_tag.inspect}, #{base}"
137
+ else
138
+ base
142
139
  end
143
140
  end
144
141
 
145
142
  def output_conversion_arguments
146
- conversion_arguments "#{callarg}.to_value"
143
+ if specialized_type_tag == :c
144
+ "#{subtype_tag_or_class_name}, #{array_size}, #{callarg}.to_value"
145
+ else
146
+ conversion_arguments "#{callarg}.to_value"
147
+ end
147
148
  end
148
149
 
149
150
  def parameter_conversion_arguments
@@ -42,6 +42,7 @@ module GirFFI
42
42
  :byte_array => 'GLib::ByteArray',
43
43
  :c => 'GLib::SizedArray',
44
44
  :callback => 'GirFFI::Callback',
45
+ :error => 'GLib::Error',
45
46
  :ghash => 'GLib::HashTable',
46
47
  :glist => 'GLib::List',
47
48
  :gslist => 'GLib::SList',
@@ -118,7 +119,7 @@ module GirFFI
118
119
  "#{specialized_type_tag.inspect}, #{name}"
119
120
  when :c
120
121
  "#{subtype_tag_or_class_name}, #{type_info.array_fixed_size}, #{name}"
121
- when :glist, :gslist, :ghash, :array, :zero_terminated
122
+ when :array, :ghash, :glist, :gslist, :ptr_array, :zero_terminated
122
123
  "#{elm_t}, #{name}"
123
124
  when :callback
124
125
  iface = type_info.interface
@@ -80,8 +80,8 @@ module GirFFI
80
80
  def setup_lib_for_ffi
81
81
  @lib = get_or_define_module @module, :Lib
82
82
 
83
- unless (class << @lib; self.include? FFI::Library; end)
84
- @lib.extend FFI::Library
83
+ unless (class << @lib; self.include? GirFFI::Library; end)
84
+ @lib.extend GirFFI::Library
85
85
  @lib.ffi_lib_flags :global, :lazy
86
86
  libspec = gir.shared_library(@namespace)
87
87
  unless libspec.nil?
@@ -123,6 +123,5 @@ module GirFFI
123
123
  def get_or_define_module parent, name
124
124
  optionally_define_constant(parent, name) { Module.new }
125
125
  end
126
-
127
126
  end
128
127
  end
@@ -1,4 +1,6 @@
1
1
  require 'gir_ffi/builder/type/registered_type'
2
+ require 'gir_ffi/builder/type/with_methods'
3
+ require 'gir_ffi/enum_base'
2
4
 
3
5
  module GirFFI
4
6
  module Builder
@@ -8,6 +10,8 @@ module GirFFI
8
10
  # attached to the appropriate namespace module, and will be defined
9
11
  # as an enum for FFI.
10
12
  class Enum < RegisteredType
13
+ include WithMethods
14
+
11
15
  private
12
16
 
13
17
  def enum_sym
@@ -22,11 +26,15 @@ module GirFFI
22
26
  end
23
27
 
24
28
  def instantiate_class
25
- @klass = optionally_define_constant namespace_module, @classname do
29
+ @klass = get_or_define_module namespace_module, @classname
30
+ @enum = optionally_define_constant @klass, :Enum do
26
31
  lib.enum(enum_sym, value_spec)
27
32
  end
28
33
  unless already_set_up
34
+ @klass.extend superclass
35
+ setup_constants
29
36
  setup_gtype_getter
37
+ stub_methods
30
38
  setup_inspect
31
39
  end
32
40
  end
@@ -42,6 +50,15 @@ module GirFFI
42
50
  def already_set_up
43
51
  @klass.respond_to? :get_gtype
44
52
  end
53
+
54
+ def superclass
55
+ @superclass ||= EnumBase
56
+ end
57
+
58
+ # FIXME: Remove duplication with Builder::Module
59
+ def get_or_define_module parent, name
60
+ optionally_define_constant(parent, name) { ::Module.new }
61
+ end
45
62
  end
46
63
  end
47
64
  end
@@ -51,7 +51,7 @@ module GirFFI
51
51
  setup_interfaces
52
52
  end
53
53
 
54
- # FIXME: Private method only in subclass
54
+ # FIXME: Private method only used in subclass
55
55
  def layout_superclass
56
56
  FFI::Struct
57
57
  end
@@ -69,16 +69,14 @@ module GirFFI
69
69
  end
70
70
 
71
71
  def superclass
72
- unless defined? @superclass
73
- if parent
74
- @superclass = Builder.build_class parent
75
- else
76
- @superclass = ObjectBase
77
- end
78
- end
79
- @superclass
72
+ @superclass ||= if parent
73
+ Builder.build_class parent
74
+ else
75
+ ObjectBase
76
+ end
80
77
  end
81
78
 
79
+ # TODO: Unify with field accessor setup.
82
80
  def setup_property_accessors
83
81
  info.properties.each do |prop|
84
82
  setup_accessors_for_property_info prop
@@ -94,20 +92,24 @@ module GirFFI
94
92
  end
95
93
 
96
94
  # TODO: Guard agains accidental invocation of undefined vfuncs.
95
+ # TODO: Create object responsible for creating these invokers
97
96
  def setup_vfunc_invokers
98
97
  info.vfuncs.each do |vfinfo|
99
- invoker = vfinfo.invoker
100
- next if invoker.nil?
101
- next if invoker.name == vfinfo.name
102
-
103
- @klass.class_eval "
104
- def #{vfinfo.name} *args, &block
105
- #{invoker.name}(*args, &block)
106
- end
107
- "
98
+ if (invoker = vfinfo.invoker)
99
+ define_vfunc_invoker vfinfo.name, invoker.name
100
+ end
108
101
  end
109
102
  end
110
103
 
104
+ def define_vfunc_invoker vfunc_name, invoker_name
105
+ return if vfunc_name == invoker_name
106
+ @klass.class_eval "
107
+ def #{vfunc_name} *args, &block
108
+ #{invoker_name}(*args, &block)
109
+ end
110
+ "
111
+ end
112
+
111
113
  def setup_interfaces
112
114
  interfaces.each do |iface|
113
115
  @klass.class_eval do
@@ -1,5 +1,4 @@
1
1
  require 'forwardable'
2
- require 'gir_ffi/ffi_ext/pointer'
3
2
 
4
3
  module GirFFI
5
4
  # Base class for all generated classes. Contains code for dealing with
@@ -0,0 +1,25 @@
1
+ module GirFFI
2
+ module EnumBase
3
+ def [](arg)
4
+ self::Enum[arg]
5
+ end
6
+
7
+ def setup_and_call method, *arguments, &block
8
+ result = setup_method method.to_s
9
+
10
+ unless result
11
+ raise RuntimeError, "Unable to set up method #{method} in #{self}"
12
+ end
13
+
14
+ self.send method, *arguments, &block
15
+ end
16
+
17
+ def gir_ffi_builder
18
+ self.const_get :GIR_FFI_BUILDER
19
+ end
20
+
21
+ def setup_method name
22
+ gir_ffi_builder.setup_method name
23
+ end
24
+ end
25
+ end
@@ -0,0 +1 @@
1
+ require 'gir_ffi/ffi_ext/pointer'
@@ -15,81 +15,98 @@ module GirFFI
15
15
 
16
16
  def generate
17
17
  vargen = GirFFI::VariableNameGenerator.new
18
- @data = @info.args.map {|arg| ArgumentBuilder.new vargen, arg }
19
- @rvdata = ReturnValueBuilder.new(vargen, @info.return_type,
20
- @info.constructor?)
18
+ @argument_builders = @info.args.map {|arg| ArgumentBuilder.new vargen, arg }
19
+ @return_value_builder = ReturnValueBuilder.new(vargen, @info.return_type,
20
+ @info.constructor?)
21
21
 
22
- alldata = @data.dup << @rvdata
22
+ link_array_length_arguments
23
+ setup_error_argument vargen
24
+ return filled_out_template
25
+ end
26
+
27
+ private
28
+
29
+ def link_array_length_arguments
30
+ alldata = @argument_builders.dup << @return_value_builder
23
31
 
24
32
  alldata.each {|data|
25
33
  idx = data.type_info.array_length
26
34
  if idx > -1
27
- data.length_arg = @data[idx]
28
- @data[idx].array_arg = data
35
+ other_data = @argument_builders[idx]
36
+ data.length_arg = other_data
37
+ other_data.array_arg = data
29
38
  end
30
39
  }
31
-
32
- setup_error_argument vargen
33
- return filled_out_template
34
40
  end
35
41
 
36
- private
37
-
38
42
  def setup_error_argument vargen
39
43
  klass = @info.throws? ? ErrorArgumentBuilder : NullArgumentBuilder
40
44
  @errarg = klass.new vargen, nil, nil, :error
41
45
  end
42
46
 
43
47
  def filled_out_template
44
- lines = pre
45
- lines << "#{capture}#{@libmodule}.#{@info.symbol} #{callargs.join(', ')}"
46
- lines << post
47
-
48
48
  meta = @info.method? ? '' : "self."
49
49
 
50
- code = "def #{meta}#{@info.safe_name} #{inargs.join(', ')}\n"
51
- code << lines.join("\n").indent
50
+ code = "def #{meta}#{@info.safe_name} #{method_arguments.join(', ')}\n"
51
+ code << method_body
52
52
  code << "\nend\n"
53
53
  end
54
54
 
55
- def inargs
56
- @data.map(&:inarg).compact
55
+ def method_body
56
+ lines = preparation << function_call << post_processing << cleanup
57
+ lines << "return #{return_values.join(', ')}" if has_return_values?
58
+ lines.flatten.join("\n").indent
57
59
  end
58
60
 
59
- def callargs
60
- ca = @data.map(&:callarg)
61
+ def function_call
62
+ "#{capture}#{@libmodule}.#{@info.symbol} #{function_call_arguments.join(', ')}"
63
+ end
64
+
65
+ def method_arguments
66
+ @argument_builders.map(&:inarg).compact
67
+ end
68
+
69
+ def function_call_arguments
70
+ ca = @argument_builders.map(&:callarg)
61
71
  ca << @errarg.callarg
62
72
  ca.unshift "self" if @info.method?
63
73
  ca.compact
64
74
  end
65
75
 
66
- def pre
67
- pr = @data.map(&:pre)
76
+ def preparation
77
+ pr = @argument_builders.map(&:pre)
68
78
  pr << @errarg.pre
69
79
  pr.flatten
70
80
  end
71
81
 
72
82
  def capture
73
- if (cv = @rvdata.cvar)
83
+ if (cv = @return_value_builder.cvar)
74
84
  "#{cv} = "
75
85
  else
76
86
  ""
77
87
  end
78
88
  end
79
89
 
80
- def post
81
- args = @data.sort_by {|arg| arg.type_info.array_length}
90
+ def post_processing
91
+ # FIXME: Sorting knows too much about internals of ArgumentBuilder.
92
+ args = @argument_builders.sort_by {|arg| arg.type_info.array_length}
93
+ args << @return_value_builder
94
+ args.unshift @errarg
82
95
 
83
- po = args.map {|arg|arg.post} +
84
- @rvdata.post
85
- po.unshift @errarg.post
96
+ args.map {|arg| arg.post}
97
+ end
86
98
 
87
- po += @data.map {|item| item.cleanup}
99
+ def cleanup
100
+ @argument_builders.map {|item| item.cleanup}
101
+ end
88
102
 
89
- retvals = ([@rvdata.retval] + @data.map(&:retval)).compact
90
- po << "return #{retvals.join(', ')}" unless retvals.empty?
103
+ def return_values
104
+ @return_values ||= ([@return_value_builder.retval] +
105
+ @argument_builders.map(&:retval)).compact
106
+ end
91
107
 
92
- po.flatten
108
+ def has_return_values?
109
+ !return_values.empty?
93
110
  end
94
111
  end
95
112
  end