gir_ffi 0.5.2 → 0.6.0

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 (78) hide show
  1. data/History.txt +5 -0
  2. data/lib/ffi-glib/array.rb +2 -3
  3. data/lib/ffi-glib/container_class_methods.rb +3 -4
  4. data/lib/ffi-glib/hash_table.rb +7 -3
  5. data/lib/ffi-glib/list_methods.rb +1 -1
  6. data/lib/ffi-glib/sized_array.rb +66 -0
  7. data/lib/ffi-glib/strv.rb +1 -1
  8. data/lib/ffi-glib.rb +5 -4
  9. data/lib/ffi-gobject/object.rb +2 -3
  10. data/lib/ffi-gobject/ruby_closure.rb +3 -2
  11. data/lib/ffi-gobject/value.rb +26 -14
  12. data/lib/ffi-gobject.rb +8 -5
  13. data/lib/ffi-gobject_introspection/g_error.rb +1 -0
  14. data/lib/ffi-gobject_introspection/i_base_info.rb +3 -2
  15. data/lib/ffi-gobject_introspection/i_union_info.rb +21 -8
  16. data/lib/ffi-gobject_introspection/lib.rb +1 -0
  17. data/lib/gir_ffi/argument_builder.rb +8 -20
  18. data/lib/gir_ffi/base_argument_builder.rb +13 -30
  19. data/lib/gir_ffi/builder/module.rb +3 -9
  20. data/lib/gir_ffi/builder/type/base.rb +2 -0
  21. data/lib/gir_ffi/builder/type/callback.rb +2 -2
  22. data/lib/gir_ffi/builder/type/enum.rb +1 -0
  23. data/lib/gir_ffi/builder/type/object.rb +13 -3
  24. data/lib/gir_ffi/builder/type/registered_type.rb +1 -1
  25. data/lib/gir_ffi/builder/type/struct.rb +18 -3
  26. data/lib/gir_ffi/builder/type/unintrospectable.rb +5 -45
  27. data/lib/gir_ffi/builder/type/user_defined.rb +3 -15
  28. data/lib/gir_ffi/builder/type.rb +5 -5
  29. data/lib/gir_ffi/builder.rb +5 -80
  30. data/lib/gir_ffi/callback.rb +65 -2
  31. data/lib/gir_ffi/callback_helper.rb +0 -56
  32. data/lib/gir_ffi/class_base.rb +2 -2
  33. data/lib/gir_ffi/in_out_pointer.rb +7 -28
  34. data/lib/gir_ffi/in_pointer.rb +12 -19
  35. data/lib/gir_ffi/info_ext/i_arg_info.rb +5 -0
  36. data/lib/gir_ffi/info_ext/i_callable_info.rb +16 -0
  37. data/lib/gir_ffi/info_ext/i_function_info.rb +15 -0
  38. data/lib/gir_ffi/info_ext/i_signal_info.rb +17 -10
  39. data/lib/gir_ffi/info_ext/i_type_info.rb +63 -39
  40. data/lib/gir_ffi/info_ext.rb +5 -3
  41. data/lib/gir_ffi/null_argument_builder.rb +1 -1
  42. data/lib/gir_ffi/return_value_builder.rb +24 -16
  43. data/lib/gir_ffi/unintrospectable_type_info.rb +41 -0
  44. data/lib/gir_ffi/user_defined_property_info.rb +15 -0
  45. data/lib/gir_ffi/user_defined_type_info.rb +25 -0
  46. data/lib/gir_ffi/version.rb +1 -1
  47. data/lib/gir_ffi-base.rb +3 -0
  48. data/lib/gir_ffi.rb +2 -1
  49. data/test/ffi-glib/sized_array_test.rb +87 -0
  50. data/test/ffi-gobject_introspection/i_base_info_test.rb +4 -5
  51. data/test/gir_ffi/argument_builder_test.rb +26 -55
  52. data/test/gir_ffi/builder/type/unintrospectable_test.rb +3 -19
  53. data/test/gir_ffi/builder/type/user_defined_test.rb +16 -21
  54. data/test/gir_ffi/builder_test.rb +31 -53
  55. data/test/gir_ffi/callback_helper_test.rb +0 -47
  56. data/test/gir_ffi/callback_test.rb +49 -0
  57. data/test/gir_ffi/function_builder_test.rb +8 -8
  58. data/test/gir_ffi/in_out_pointer_test.rb +2 -53
  59. data/test/gir_ffi/in_pointer_test.rb +0 -13
  60. data/test/gir_ffi/info_ext/i_callable_info_test.rb +32 -0
  61. data/test/gir_ffi/info_ext/i_function_info_test.rb +61 -0
  62. data/test/gir_ffi/info_ext/i_signal_info_test.rb +7 -0
  63. data/test/gir_ffi/info_ext/i_type_info_test.rb +158 -77
  64. data/test/gir_ffi/return_value_builder_test.rb +2 -2
  65. data/test/gir_ffi/unintrospectable_type_info_test.rb +95 -0
  66. data/test/gir_ffi/user_defined_property_info_test.rb +19 -0
  67. data/test/gir_ffi/user_defined_type_info_test.rb +34 -0
  68. data/test/integration/generated_gimarshallingtests_test.rb +10 -10
  69. data/test/integration/generated_regress_test.rb +10 -10
  70. metadata +24 -15
  71. data/lib/gir_ffi/builder/type/struct_based.rb +0 -31
  72. data/lib/gir_ffi/user_defined/i_base_info.rb +0 -7
  73. data/lib/gir_ffi/user_defined/i_object_info.rb +0 -13
  74. data/lib/gir_ffi/user_defined/i_property_info.rb +0 -9
  75. data/lib/gir_ffi/user_defined/i_registered_type_info.rb +0 -10
  76. data/test/gir_ffi/user_defined/i_object_info_test.rb +0 -18
  77. data/test/gir_ffi/user_defined/i_property_info_test.rb +0 -14
  78. data/test/gir_ffi/user_defined/i_registered_type_info_test.rb +0 -10
@@ -1,6 +1,7 @@
1
1
  module GirFFI
2
2
  module InfoExt
3
3
  # Extensions for GObjectIntrospection::ISignalInfo needed by GirFFI
4
+ # TODO: Rename methods to not include 'signal' everywhere.
4
5
  module ISignalInfo
5
6
  # Create a signal hander callback. Wraps the given block in such a way that
6
7
  # arguments and return value are cast correctly to the ruby world and back.
@@ -10,7 +11,11 @@ module GirFFI
10
11
  # @return [FFI::Function] The signal handler, ready to be passed as a
11
12
  # callback to C.
12
13
  def signal_callback &block
13
- GirFFI::Builder.build_callback self, &signal_callback_args(&block)
14
+ rettype = self.return_ffi_type
15
+ argtypes = self.ffi_callback_argument_types
16
+
17
+ # TODO: Create signal handler type?
18
+ FFI::Function.new rettype, argtypes, &signal_callback_args(&block)
14
19
  end
15
20
 
16
21
  # TODO: Generate cast back methods using existing Argument builders.
@@ -36,7 +41,7 @@ module GirFFI
36
41
  def signal_arguments_to_gvalue_array instance, *rest
37
42
  arr = ::GObject::ValueArray.new self.n_args + 1
38
43
 
39
- arr.append signal_reciever_to_gvalue instance
44
+ arr.append GObject::Value.wrap_instance(instance)
40
45
 
41
46
  self.args.zip(rest).each do |info, arg|
42
47
  arr.append info.argument_type.make_g_value.set_value(arg)
@@ -49,15 +54,17 @@ module GirFFI
49
54
  GObject::Value.for_g_type return_type.g_type
50
55
  end
51
56
 
52
- private
53
-
54
- def signal_reciever_to_gvalue instance
55
- val = ::GObject::Value.new
56
- val.init ::GObject.type_from_instance instance
57
- val.set_instance instance
58
- return val
57
+ # TODO: Rename and clarify relation to argument_ffi_types:
58
+ # The types returned by ffi_callback_argument_types are more basic than
59
+ # those returned by argument_ffi_types. Is there a way to make these
60
+ # methods more related? Perhaps argument_ffi_types can return more basic
61
+ # types as well?
62
+ def ffi_callback_argument_types
63
+ types = args.map do |arg|
64
+ arg.argument_type.to_callback_ffitype
65
+ end
66
+ types.unshift(:pointer).push(:pointer)
59
67
  end
60
-
61
68
  end
62
69
  end
63
70
  end
@@ -21,12 +21,10 @@ module GirFFI
21
21
  end
22
22
 
23
23
  def layout_specification_type
24
- ffitype = GirFFI::Builder.itypeinfo_to_ffitype self
24
+ ffitype = self.to_ffitype
25
25
  case ffitype
26
26
  when Class
27
27
  ffitype.const_get :Struct
28
- when :bool
29
- :int
30
28
  when :array
31
29
  subtype = param_type(0).layout_specification_type
32
30
  # XXX Don't use pointer directly to appease JRuby.
@@ -42,9 +40,9 @@ module GirFFI
42
40
  def element_type
43
41
  case tag
44
42
  when :glist, :gslist, :array
45
- subtype_tag 0
43
+ subtype_tag_or_class 0
46
44
  when :ghash
47
- [subtype_tag(0), subtype_tag(1)]
45
+ [subtype_tag_or_class(0), subtype_tag_or_class(1)]
48
46
  else
49
47
  nil
50
48
  end
@@ -54,24 +52,15 @@ module GirFFI
54
52
  interface.full_type_name
55
53
  end
56
54
 
57
- def type_specification
58
- tag = self.flattened_tag
59
- case tag
60
- when :strv, :zero_terminated, :c
61
- "[#{tag.inspect}, #{subtype_tag_or_class_name}]"
62
- else
63
- tag.inspect
64
- end
65
- end
66
-
67
55
  def flattened_tag
68
- case tag
56
+ type_tag = self.tag
57
+ case type_tag
69
58
  when :interface
70
59
  interface_type
71
60
  when :array
72
61
  flattened_array_type
73
62
  else
74
- tag
63
+ type_tag
75
64
  end
76
65
  end
77
66
 
@@ -87,21 +76,71 @@ module GirFFI
87
76
  end
88
77
  end
89
78
 
90
- def subtype_tag_or_class_name
91
- type = self.param_type 0
92
- tag = type.tag
93
- base = if tag == :interface
94
- type.interface_type_name
79
+ def subtype_tag_or_class_name index = 0
80
+ param_type(index).tag_or_class_name
81
+ end
82
+
83
+ def subtype_tag_or_class index = 0
84
+ param_type(index).tag_or_class
85
+ end
86
+
87
+ # TODO: Merge with tag_or_class
88
+ def tag_or_class_name
89
+ type_tag = self.tag
90
+ base = if type_tag == :interface
91
+ interface_type_name
95
92
  else
96
- tag.inspect
93
+ type_tag.inspect
97
94
  end
98
- if type.pointer? && tag != :utf8 && tag != :filename
95
+ if pointer? && type_tag != :utf8 && type_tag != :filename
99
96
  "[:pointer, #{base}]"
100
97
  else
101
98
  base
102
99
  end
103
100
  end
104
101
 
102
+ def tag_or_class
103
+ type_tag = self.tag
104
+ base = if type_tag == :interface
105
+ Builder.build_class interface
106
+ else
107
+ type_tag
108
+ end
109
+ if pointer? && type_tag != :utf8 && type_tag != :filename
110
+ [:pointer, base]
111
+ else
112
+ base
113
+ end
114
+ end
115
+
116
+ def to_ffitype
117
+ return :pointer if pointer?
118
+
119
+ type_tag = tag
120
+ if type_tag == :interface
121
+ Builder.build_class interface
122
+ else
123
+ TypeMap.map_basic_type type_tag
124
+ end
125
+ end
126
+
127
+ def to_callback_ffitype
128
+ type_tag = tag
129
+
130
+ return :string if type_tag == :utf8
131
+ return :pointer if pointer?
132
+
133
+ if type_tag == :interface
134
+ case interface.info_type
135
+ when :enum, :flags
136
+ :int32
137
+ else
138
+ :pointer
139
+ end
140
+ else
141
+ return TypeMap.map_basic_type type_tag
142
+ end
143
+ end
105
144
  private
106
145
 
107
146
  def zero_terminated_array_type
@@ -113,21 +152,6 @@ module GirFFI
113
152
  :zero_terminated
114
153
  end
115
154
  end
116
-
117
- def subtype_tag index
118
- st = param_type(index)
119
- tag = st.tag
120
- case tag
121
- when :interface
122
- return :interface_pointer if st.pointer?
123
- return :interface
124
- when :void
125
- return :gpointer if st.pointer?
126
- return :void
127
- else
128
- return tag
129
- end
130
- end
131
155
  end
132
156
  end
133
157
  end
@@ -1,8 +1,10 @@
1
- require 'gir_ffi/info_ext/safe_constant_name'
2
- require 'gir_ffi/info_ext/safe_function_name'
3
1
  require 'gir_ffi/info_ext/i_arg_info'
2
+ require 'gir_ffi/info_ext/i_callable_info'
4
3
  require 'gir_ffi/info_ext/i_field_info'
4
+ require 'gir_ffi/info_ext/i_function_info'
5
5
  require 'gir_ffi/info_ext/i_property_info'
6
- require 'gir_ffi/info_ext/i_signal_info'
7
6
  require 'gir_ffi/info_ext/i_registered_type_info'
7
+ require 'gir_ffi/info_ext/i_signal_info'
8
8
  require 'gir_ffi/info_ext/i_type_info'
9
+ require 'gir_ffi/info_ext/safe_constant_name'
10
+ require 'gir_ffi/info_ext/safe_function_name'
@@ -1,7 +1,7 @@
1
1
  module GirFFI
2
2
  # Argument builder that does nothing. Implements the Null Object pattern.
3
3
  class NullArgumentBuilder
4
- def initialize *args; end
4
+ def initialize *; end
5
5
  def pre; []; end
6
6
  def post; []; end
7
7
  def callarg; end
@@ -9,18 +9,8 @@ module GirFFI
9
9
  end
10
10
 
11
11
  def post
12
- if needs_wrapping?
13
- if [ :interface, :object ].include?(specialized_type_tag) && @is_constructor
14
- [ "#{retname} = self.constructor_wrap(#{cvar})" ]
15
- else
16
- [ "#{retname} = #{argument_class_name}.wrap(#{return_value_conversion_arguments})" ]
17
- end
18
- elsif specialized_type_tag == :utf8
19
- # TODO: Re-use methods in InOutPointer for this conversion
20
- [ "#{retname} = GirFFI::ArgHelper.ptr_to_utf8(#{cvar})" ]
21
- elsif specialized_type_tag == :c
22
- size = array_size
23
- [ "#{retname} = GirFFI::ArgHelper.ptr_to_typed_array #{subtype_tag_or_class_name}, #{cvar}, #{size}" ]
12
+ if has_conversion?
13
+ [ "#{retname} = #{post_conversion}" ]
24
14
  else
25
15
  []
26
16
  end
@@ -47,6 +37,24 @@ module GirFFI
47
37
 
48
38
  private
49
39
 
40
+ def post_conversion
41
+ raw = cvar
42
+
43
+ if needs_constructor_wrap?
44
+ "self.constructor_wrap(#{raw})"
45
+ elsif needs_wrapping?
46
+ "#{argument_class_name}.wrap(#{conversion_arguments raw})"
47
+ else
48
+ case specialized_type_tag
49
+ when :utf8
50
+ # TODO: Re-use methods in InOutPointer for this conversion
51
+ "GirFFI::ArgHelper.ptr_to_utf8(#{raw})"
52
+ when :c
53
+ "GLib::SizedArray.wrap(#{subtype_tag_or_class_name}, #{array_size}, #{raw})"
54
+ end
55
+ end
56
+ end
57
+
50
58
  def retname
51
59
  @retname ||= @var_gen.new_var
52
60
  end
@@ -61,12 +69,12 @@ module GirFFI
61
69
  ].include?(specialized_type_tag)
62
70
  end
63
71
 
64
- def is_void_return_value?
65
- specialized_type_tag == :void && !type_info.pointer?
72
+ def needs_constructor_wrap?
73
+ @is_constructor && [ :interface, :object ].include?(specialized_type_tag)
66
74
  end
67
75
 
68
- def return_value_conversion_arguments
69
- conversion_arguments cvar
76
+ def is_void_return_value?
77
+ specialized_type_tag == :void && !type_info.pointer?
70
78
  end
71
79
  end
72
80
  end
@@ -0,0 +1,41 @@
1
+ module GirFFI
2
+ # Represents a type not found in the GIR, conforming, as needed, to the
3
+ # interface of GObjectIntrospection::IObjectInfo.
4
+ class UnintrospectableTypeInfo
5
+ attr_reader :g_type
6
+
7
+ def initialize(gtype,
8
+ gir = GObjectIntrospection::IRepository.default,
9
+ gobject = ::GObject)
10
+ @g_type = gtype
11
+ @gir = gir
12
+ @gobject = gobject
13
+ end
14
+
15
+ def info_type
16
+ :unintrospectable
17
+ end
18
+
19
+ def safe_name
20
+ @gobject.type_name @g_type
21
+ end
22
+
23
+ def parent
24
+ @gir.find_by_gtype @gobject.type_parent(@g_type)
25
+ end
26
+
27
+ def namespace
28
+ parent.namespace
29
+ end
30
+
31
+ def interfaces
32
+ @gobject.type_interfaces(@g_type).map do |gtype|
33
+ @gir.find_by_gtype gtype
34
+ end.compact
35
+ end
36
+
37
+ def fields
38
+ []
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,15 @@
1
+ module GirFFI
2
+ # Represents a property of a user defined type, conforming, as needed, to the
3
+ # interface of GObjectIntrospection::IPropertyInfo.
4
+ class UserDefinedPropertyInfo
5
+ def initialize param_spec
6
+ @param_spec = param_spec
7
+ end
8
+
9
+ attr_reader :param_spec
10
+
11
+ def name
12
+ @param_spec.get_name
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ require 'gir_ffi/user_defined_property_info'
2
+
3
+ module GirFFI
4
+ # Represents a user defined type, conforming, as needed, to the interface of
5
+ # GObjectIntrospection::IObjectInfo.
6
+ class UserDefinedTypeInfo
7
+ def initialize klass, &block
8
+ @klass = klass
9
+ @properties = []
10
+ self.instance_eval(&block) if block
11
+ end
12
+
13
+ def described_class
14
+ @klass
15
+ end
16
+
17
+ def install_property property
18
+ @properties << UserDefinedPropertyInfo.new(property)
19
+ end
20
+
21
+ def properties
22
+ @properties
23
+ end
24
+ end
25
+ end
@@ -1,3 +1,3 @@
1
1
  module GirFFI
2
- VERSION = "0.5.2"
2
+ VERSION = "0.6.0"
3
3
  end
data/lib/gir_ffi-base.rb CHANGED
@@ -1,2 +1,5 @@
1
+ # This section contains code that is needed by GObjectIntrospection, but
2
+ # belongs in modules that can only be created fully once GObjectIntrospection
3
+ # is fully loaded.
1
4
  require 'gir_ffi-base/glib/strv'
2
5
  require 'gir_ffi-base/gobject/lib'
data/lib/gir_ffi.rb CHANGED
@@ -21,7 +21,8 @@ module GirFFI
21
21
  end
22
22
 
23
23
  def self.define_type klass, &block
24
- Builder::Type::UserDefined.new(klass, &block).build_class
24
+ info = UserDefinedTypeInfo.new(klass, &block)
25
+ Builder::Type::UserDefined.new(info).build_class
25
26
 
26
27
  klass.get_gtype
27
28
  end
@@ -0,0 +1,87 @@
1
+ require 'base_test_helper'
2
+
3
+ describe GLib::SizedArray do
4
+ describe "::wrap" do
5
+ it "takes a type, size and pointer and returns a GLib::SizedArray wrapping them" do
6
+ mock(ptr = Object.new).null? { false }
7
+ sarr = GLib::SizedArray.wrap :gint32, 3, ptr
8
+ assert_instance_of GLib::SizedArray, sarr
9
+ assert_equal ptr, sarr.to_ptr
10
+ assert_equal 3, sarr.size
11
+ assert_equal :gint32, sarr.element_type
12
+ end
13
+
14
+ it "returns nil if the wrapped pointer is null" do
15
+ mock(ptr = Object.new).null? { true }
16
+ sarr = GLib::SizedArray.wrap :gint32, 3, ptr
17
+ sarr.must_be_nil
18
+ end
19
+ end
20
+
21
+ describe "#each" do
22
+ it "yields each element" do
23
+ ary = ["one", "two", "three"]
24
+ ptrs = ary.map {|a| FFI::MemoryPointer.from_string(a)}
25
+ ptrs << nil
26
+ block = FFI::MemoryPointer.new(:pointer, ptrs.length)
27
+ block.write_array_of_pointer ptrs
28
+
29
+ sarr = GLib::SizedArray.new :utf8, 3, block
30
+ arr = []
31
+ sarr.each do |str|
32
+ arr << str
33
+ end
34
+ assert_equal ["one", "two", "three"], arr
35
+ end
36
+ end
37
+
38
+ describe "::from" do
39
+ context "from a Ruby array" do
40
+ it "creates a GLib::SizedArray with the same elements" do
41
+ arr = GLib::SizedArray.from :gint32, 3, [3, 2, 1]
42
+ arr.must_be_instance_of GLib::SizedArray
43
+ assert_equal [3, 2, 1], arr.to_a
44
+ end
45
+
46
+ it "raises an error if the array has the wrong number of elements" do
47
+ lambda { GLib::SizedArray.from :gint32, 4, [3, 2, 1] }.must_raise ArgumentError
48
+ end
49
+
50
+ it "uses the array's size if passed -1 as the size" do
51
+ arr = GLib::SizedArray.from :gint32, -1, [3, 2, 1]
52
+ arr.size.must_equal 3
53
+ end
54
+ end
55
+
56
+ context "from a GLib::SizedArray" do
57
+ it "return its argument" do
58
+ arr = GLib::SizedArray.from :gint32, 3, [3, 2, 1]
59
+ arr2 = GLib::SizedArray.from :gint32, 3, arr
60
+ assert_equal arr, arr2
61
+ end
62
+
63
+ it "raises an error if the argument has the wrong number of elements" do
64
+ arr = GLib::SizedArray.from :gint32, 3, [3, 2, 1]
65
+ lambda { GLib::SizedArray.from :gint32, 4, arr }.must_raise ArgumentError
66
+ end
67
+ end
68
+
69
+ it "returns nil when passed nil" do
70
+ arr = GLib::SizedArray.from :gint32, 0, nil
71
+ arr.must_be_nil
72
+ end
73
+
74
+ it "wraps its argument if given a pointer" do
75
+ arr = GLib::SizedArray.from :gint32, 3, [3, 2, 1]
76
+ arr2 = GLib::SizedArray.from :gint32, 3, arr.to_ptr
77
+ assert_instance_of GLib::SizedArray, arr2
78
+ refute_equal arr, arr2
79
+ assert_equal arr.to_a, arr2.to_a
80
+ end
81
+ end
82
+
83
+ it "includes Enumerable" do
84
+ GLib::SizedArray.must_include Enumerable
85
+ end
86
+ end
87
+
@@ -3,10 +3,6 @@ require 'introspection_test_helper'
3
3
  describe GObjectIntrospection::IBaseInfo do
4
4
  let(:described_class) { GObjectIntrospection::IBaseInfo }
5
5
  describe "#initialize" do
6
- it "raises an error if nil is passed" do
7
- proc { described_class.new nil }.must_raise ArgumentError
8
- end
9
-
10
6
  it "raises an error if a null pointer is passed" do
11
7
  mock(ptr = Object.new).null? { true }
12
8
  proc { described_class.new ptr }.must_raise ArgumentError
@@ -21,7 +17,10 @@ describe GObjectIntrospection::IBaseInfo do
21
17
 
22
18
  describe "upon garbage collection" do
23
19
  it "calls g_base_info_unref" do
24
- skip "cannot be reliably tested on JRuby" if RUBY_PLATFORM == 'java'
20
+ if defined?(RUBY_ENGINE) && ['jruby', 'rbx'].include?(RUBY_ENGINE)
21
+ skip "cannot be reliably tested on JRuby and Rubinius"
22
+ end
23
+
25
24
  mock(ptr = Object.new).null? { false }
26
25
  mock(lib = Object.new).g_base_info_unref(ptr) { nil }
27
26
  described_class.new ptr, lib