gir_ffi 0.5.1 → 0.5.2

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 (54) hide show
  1. data/History.txt +8 -0
  2. data/lib/ffi-glib/array.rb +1 -1
  3. data/lib/ffi-glib.rb +7 -12
  4. data/lib/ffi-gobject/closure.rb +1 -4
  5. data/lib/ffi-gobject/object.rb +2 -2
  6. data/lib/ffi-gobject/ruby_style.rb +2 -0
  7. data/lib/ffi-gobject/value.rb +19 -1
  8. data/lib/ffi-gobject.rb +14 -9
  9. data/lib/ffi-gobject_introspection/i_base_info.rb +5 -5
  10. data/lib/ffi-gobject_introspection/i_repository.rb +1 -1
  11. data/lib/ffi-gobject_introspection/lib.rb +1 -1
  12. data/lib/gir_ffi/arg_helper.rb +3 -3
  13. data/lib/gir_ffi/argument_builder.rb +21 -17
  14. data/lib/gir_ffi/base_argument_builder.rb +5 -3
  15. data/lib/gir_ffi/builder/type/object.rb +1 -0
  16. data/lib/gir_ffi/builder/type/user_defined.rb +2 -3
  17. data/lib/gir_ffi/builder.rb +2 -2
  18. data/lib/gir_ffi/builder_helper.rb +2 -2
  19. data/lib/gir_ffi/callback_helper.rb +9 -9
  20. data/lib/gir_ffi/function_builder.rb +2 -2
  21. data/lib/gir_ffi/in_out_pointer.rb +1 -3
  22. data/lib/gir_ffi/in_pointer.rb +15 -2
  23. data/lib/gir_ffi/info_ext/i_arg_info.rb +27 -0
  24. data/lib/gir_ffi/info_ext/i_field_info.rb +1 -0
  25. data/lib/gir_ffi/info_ext/i_property_info.rb +1 -0
  26. data/lib/gir_ffi/info_ext/i_registered_type_info.rb +1 -1
  27. data/lib/gir_ffi/info_ext/i_signal_info.rb +65 -0
  28. data/lib/gir_ffi/info_ext/i_type_info.rb +15 -0
  29. data/lib/gir_ffi/info_ext/safe_constant_name.rb +1 -0
  30. data/lib/gir_ffi/info_ext/safe_function_name.rb +1 -0
  31. data/lib/gir_ffi/info_ext.rb +2 -0
  32. data/lib/gir_ffi/module_base.rb +1 -3
  33. data/lib/gir_ffi/return_value_builder.rb +1 -4
  34. data/lib/gir_ffi/version.rb +1 -2
  35. data/lib/gir_ffi/zero_terminated.rb +42 -0
  36. data/lib/gir_ffi.rb +1 -0
  37. data/test/ffi-gobject/value_test.rb +30 -1
  38. data/test/ffi-gobject_introspection/i_object_info_test.rb +4 -4
  39. data/test/ffi-gobject_test.rb +20 -0
  40. data/test/gir_ffi/arg_helper_test.rb +4 -4
  41. data/test/gir_ffi/argument_builder_test.rb +16 -0
  42. data/test/gir_ffi/builder_test.rb +0 -5
  43. data/test/gir_ffi/in_pointer_test.rb +20 -1
  44. data/test/gir_ffi/info_ext/i_arg_info_test.rb +39 -0
  45. data/test/gir_ffi/info_ext/i_signal_info_test.rb +51 -0
  46. data/test/gir_ffi/info_ext/i_type_info_test.rb +20 -20
  47. data/test/gir_ffi/return_value_builder_test.rb +2 -2
  48. data/test/gir_ffi/zero_terminated_test.rb +48 -0
  49. data/test/gir_ffi_test_helper.rb +3 -3
  50. data/test/integration/generated_gimarshallingtests_test.rb +38 -28
  51. data/test/integration/generated_regress_test.rb +2 -5
  52. metadata +11 -5
  53. data/lib/ffi-gobject/helper.rb +0 -114
  54. data/test/ffi-gobject/helper_test.rb +0 -103
@@ -7,9 +7,7 @@ module GirFFI
7
7
  end
8
8
 
9
9
  def const_missing classname
10
- klass = load_class classname
11
- return super if klass.nil?
12
- klass
10
+ load_class(classname) || super
13
11
  end
14
12
 
15
13
  def load_class classname
@@ -10,10 +10,7 @@ module GirFFI
10
10
 
11
11
  def post
12
12
  if needs_wrapping?
13
- if specialized_type_tag == :zero_terminated
14
- # FIXME: This is almost certainly wrong.
15
- [ "#{retname} = #{argument_class_name}.wrap(#{cvar})" ]
16
- elsif [ :interface, :object ].include?(specialized_type_tag) && @is_constructor
13
+ if [ :interface, :object ].include?(specialized_type_tag) && @is_constructor
17
14
  [ "#{retname} = self.constructor_wrap(#{cvar})" ]
18
15
  else
19
16
  [ "#{retname} = #{argument_class_name}.wrap(#{return_value_conversion_arguments})" ]
@@ -1,4 +1,3 @@
1
1
  module GirFFI
2
- VERSION = "0.5.1"
2
+ VERSION = "0.5.2"
3
3
  end
4
-
@@ -0,0 +1,42 @@
1
+ module GirFFI
2
+ # Represents a null-terminated array.
3
+ class ZeroTerminated
4
+ include Enumerable
5
+
6
+ attr_reader :element_type
7
+
8
+ def initialize elm_t, ptr
9
+ @element_type = elm_t
10
+ @ptr = ptr
11
+ end
12
+
13
+ def to_ptr
14
+ @ptr
15
+ end
16
+
17
+ def self.from type, arg
18
+ self.new type, InPointer.from_array(type, arg)
19
+ end
20
+
21
+ def self.wrap type, arg
22
+ self.new type, arg
23
+ end
24
+
25
+ def each
26
+ return if @ptr.null?
27
+ offset = 0
28
+ while val = read_value(offset)
29
+ offset += FFI.type_size(:int32)
30
+ yield val
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def read_value offset
37
+ val = @ptr.get_int32(offset)
38
+ return val unless val == 0
39
+ end
40
+ end
41
+ end
42
+
data/lib/gir_ffi.rb CHANGED
@@ -8,6 +8,7 @@ require 'gir_ffi/info_ext'
8
8
 
9
9
  require 'gir_ffi/in_pointer'
10
10
  require 'gir_ffi/in_out_pointer'
11
+ require 'gir_ffi/zero_terminated'
11
12
  require 'gir_ffi/arg_helper'
12
13
  require 'gir_ffi/callback'
13
14
  require 'gir_ffi/callback_helper'
@@ -54,6 +54,17 @@ describe GObject::Value do
54
54
  result = gv.ruby_value
55
55
  assert_equal true, result
56
56
  end
57
+
58
+ it "works with a ByteArray" do
59
+ ba = GLib::ByteArray.new.append("some bytes")
60
+ v = GObject::Value.new.init(GObject.type_from_name("GByteArray"))
61
+ v.set_boxed ba
62
+
63
+ result = v.ruby_value
64
+
65
+ result.to_string.must_equal "some bytes"
66
+ result.must_be_kind_of GLib::ByteArray
67
+ end
57
68
  end
58
69
 
59
70
  describe "::from" do
@@ -70,5 +81,23 @@ describe GObject::Value do
70
81
  gv2.ruby_value.must_equal 21
71
82
  end
72
83
  end
73
- end
74
84
 
85
+ describe "#set_value" do
86
+ before do
87
+ GirFFI.setup :GIMarshallingTests
88
+ end
89
+
90
+ it "raises an error when setting an incompatible object type" do
91
+ o = GIMarshallingTests::Object.new 1
92
+ v = GObject::Value.new.init(GIMarshallingTests::OverridesObject.get_gtype)
93
+ proc { v.set_value o }.must_raise ArgumentError
94
+ end
95
+
96
+ it "works with a ByteArray" do
97
+ ba = GLib::ByteArray.new.append("some bytes")
98
+ v = GObject::Value.new.init(GObject.type_from_name("GByteArray"))
99
+ v.set_value ba
100
+ v.ruby_value.to_string.must_equal "some bytes"
101
+ end
102
+ end
103
+ end
@@ -5,13 +5,13 @@ module GirFFI
5
5
  context "An IObjectInfo object" do
6
6
 
7
7
  setup do
8
- gir = GObjectIntrospection::IRepository.default
9
- gir.require 'GObject', nil
10
- @info = gir.find_by_name 'GObject', 'Object'
8
+ gir = GObjectIntrospection::IRepository.default
9
+ gir.require 'GObject', nil
10
+ @info = gir.find_by_name 'GObject', 'Object'
11
11
  end
12
12
 
13
13
  should "find a vfunc by name" do
14
- assert_not_nil @info.find_vfunc("finalize")
14
+ assert_not_nil @info.find_vfunc("finalize")
15
15
  end
16
16
  end
17
17
 
@@ -43,6 +43,18 @@ describe GObject do
43
43
  sb2 = Regress::TestSimpleBoxedA.wrap b2
44
44
  assert sb.equals(sb2)
45
45
  end
46
+
47
+ should "allow specifying signal detail" do
48
+ a = 1
49
+ o = Regress::TestSubObj.new
50
+
51
+ callback = FFI::Function.new(:void, [:pointer, :pointer, :pointer]) { a = 2 }
52
+ ::GObject::Lib.g_signal_connect_data o, "notify::detail", callback, nil, nil, 0
53
+
54
+ GObject.signal_emit o, "notify::detail"
55
+
56
+ a.must_equal 2
57
+ end
46
58
  end
47
59
 
48
60
  describe "::signal_connect" do
@@ -92,6 +104,14 @@ describe GObject do
92
104
  end
93
105
  end
94
106
 
107
+ should "allow specifying signal detail" do
108
+ a = 1
109
+ o = Regress::TestSubObj.new
110
+ GObject.signal_connect(o, "notify::detail", 2) { |i, _, d| a = d }
111
+ GObject.signal_emit o, "notify::detail"
112
+ assert_equal 2, a
113
+ end
114
+
95
115
  describe "connecting a signal with extra arguments" do
96
116
  setup do
97
117
  @a = nil
@@ -67,15 +67,15 @@ describe GirFFI::ArgHelper do
67
67
  describe "#object_to_inptr" do
68
68
  describe "when called with an object implementing to_ptr" do
69
69
  it "returns the result of to_ptr" do
70
- obj = Object.new
71
- def obj.to_ptr; :test_value; end
72
- assert_equal :test_value, GirFFI::ArgHelper.object_to_inptr(obj)
70
+ obj = Object.new
71
+ def obj.to_ptr; :test_value; end
72
+ assert_equal :test_value, GirFFI::ArgHelper.object_to_inptr(obj)
73
73
  end
74
74
  end
75
75
 
76
76
  describe "when called with nil" do
77
77
  it "returns nil" do
78
- assert_equal nil, GirFFI::ArgHelper.object_to_inptr(nil)
78
+ assert_equal nil, GirFFI::ArgHelper.object_to_inptr(nil)
79
79
  end
80
80
  end
81
81
 
@@ -35,6 +35,22 @@ describe GirFFI::ArgumentBuilder do
35
35
  builder.post.must_equal [ ]
36
36
  end
37
37
  end
38
+
39
+ describe "for :zero_terminated" do
40
+ before do
41
+ stub(type_info).tag { :array }
42
+ stub(type_info).flattened_tag { :zero_terminated }
43
+ stub(type_info).element_type { :foo }
44
+ end
45
+
46
+ it "has the correct value for #pre" do
47
+ builder.pre.must_equal [ "_v1 = GirFFI::ZeroTerminated.from(:foo, foo)" ]
48
+ end
49
+
50
+ it "has the correct value for #post" do
51
+ builder.post.must_equal [ ]
52
+ end
53
+ end
38
54
  end
39
55
 
40
56
  describe "for an argument with direction :out" do
@@ -80,11 +80,6 @@ describe GirFFI::Builder do
80
80
  assert_equal [FFI.find_type(:pointer)], dn.param_types
81
81
  end
82
82
 
83
- # FIXME: Test passes but does not test what it claims to test.
84
- should "define ffi enum type ConnectFlags" do
85
- assert_equal({:after => 1, :swapped => 2}, GObject::ConnectFlags.to_h)
86
- end
87
-
88
83
  after do
89
84
  restore_module :Regress
90
85
  restore_module :GObject
@@ -16,9 +16,24 @@ describe GirFFI::InPointer do
16
16
  it "handles type tag :interface_pointer" do
17
17
  GirFFI::InPointer.from_array :interface_pointer, []
18
18
  end
19
+
20
+ it "handles enum types" do
21
+ e = FFI::Enum.new [:foo, :bar, :baz]
22
+ ptr = GirFFI::InPointer.from_array e, [:bar, :foo, :baz]
23
+ ptr.read_array_of_int32(3).must_equal [1, 0, 2]
24
+ end
25
+
26
+ it "handles typed pointers" do
27
+ p1 = GirFFI::InPointer.from :gint32, 42
28
+ p2 = GirFFI::InPointer.from :gint32, 24
29
+
30
+ ptr = GirFFI::InPointer.from_array [:pointer, :uint32], [p1, p2]
31
+
32
+ ptr.read_array_of_pointer(2).must_equal [p1, p2]
33
+ end
19
34
  end
20
35
 
21
- describe "an instance created with .from_array" do
36
+ describe "an instance created with .from_array :gint32" do
22
37
  before do
23
38
  @result = GirFFI::InPointer.from_array :gint32, [24, 13]
24
39
  end
@@ -31,6 +46,10 @@ describe GirFFI::InPointer do
31
46
  it "is an instance of GirFFI::InPointer" do
32
47
  assert_instance_of GirFFI::InPointer, @result
33
48
  end
49
+
50
+ it "is zero-terminated" do
51
+ assert_equal 0, @result.get_int(8)
52
+ end
34
53
  end
35
54
 
36
55
  describe "an instance created with .from_array :utf8" do
@@ -0,0 +1,39 @@
1
+ require 'gir_ffi_test_helper'
2
+
3
+ describe GirFFI::InfoExt::IArgInfo do
4
+ let(:testclass) { Class.new do
5
+ include GirFFI::InfoExt::IArgInfo
6
+ end }
7
+ let(:arg_info) { testclass.new }
8
+
9
+ describe "#cast_signal_argument" do
10
+ describe "with info for an enum" do
11
+ before do
12
+ enuminfo = get_introspection_data 'GLib', 'DateMonth'
13
+ stub(type_info = Object.new).interface { enuminfo }
14
+ stub(type_info).tag { :interface }
15
+ stub(arg_info).argument_type { type_info }
16
+ end
17
+
18
+ it "casts an integer to its enum symbol" do
19
+ res = arg_info.cast_signal_argument 7
20
+ assert_equal :july, res
21
+ end
22
+ end
23
+
24
+ describe "with info for an interface" do
25
+ before do
26
+ ifaceinfo = get_introspection_data 'Regress', 'TestInterface'
27
+ stub(type_info = Object.new).interface { ifaceinfo }
28
+ stub(type_info).tag { :interface }
29
+ stub(arg_info).argument_type { type_info }
30
+ end
31
+
32
+ it "casts the argument by calling #to_object on it" do
33
+ mock(ptr = Object.new).to_object { "good-result" }
34
+ res = arg_info.cast_signal_argument ptr
35
+ res.must_equal "good-result"
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,51 @@
1
+ require 'gir_ffi_test_helper'
2
+
3
+ describe GirFFI::InfoExt::ISignalInfo do
4
+ describe "#cast_back_signal_arguments" do
5
+ it "correctly casts back pointers for the test-with-static-scope-arg signal" do
6
+ o = Regress::TestSubObj.new
7
+ b = Regress::TestSimpleBoxedA.new
8
+ ud = GirFFI::ArgHelper.object_to_inptr "Hello!"
9
+
10
+ assert_equal "Hello!", GirFFI::ArgHelper::OBJECT_STORE[ud.address]
11
+
12
+ sig = o.class.find_signal "test-with-static-scope-arg"
13
+
14
+ gva = sig.cast_back_signal_arguments(o.to_ptr, b.to_ptr, ud)
15
+
16
+ klasses = gva.map {|it| it.class}
17
+ klasses.must_equal [ Regress::TestSubObj,
18
+ Regress::TestSimpleBoxedA,
19
+ String ]
20
+ gva[2].must_equal "Hello!"
21
+ end
22
+ end
23
+
24
+ describe "#signal_arguments_to_gvalue_array" do
25
+ describe "the result of wrapping test-with-static-scope-arg" do
26
+ setup do
27
+ o = Regress::TestSubObj.new
28
+ b = Regress::TestSimpleBoxedA.new
29
+ sig = o.class.find_signal "test-with-static-scope-arg"
30
+
31
+ @gva = sig.signal_arguments_to_gvalue_array(o, b)
32
+ end
33
+
34
+ should "be a GObject::ValueArray" do
35
+ assert_instance_of GObject::ValueArray, @gva
36
+ end
37
+
38
+ should "contain two values" do
39
+ assert_equal 2, @gva.n_values
40
+ end
41
+
42
+ should "have a first value with GType for TestSubObj" do
43
+ assert_equal Regress::TestSubObj.get_gtype, (@gva.get_nth 0).current_gtype
44
+ end
45
+
46
+ should "have a second value with GType for TestSimpleBoxedA" do
47
+ assert_equal Regress::TestSimpleBoxedA.get_gtype, (@gva.get_nth 1).current_gtype
48
+ end
49
+ end
50
+ end
51
+ end
@@ -67,9 +67,9 @@ describe GirFFI::InfoExt::ITypeInfo do
67
67
  describe "#type_specification" do
68
68
  describe "for a simple type" do
69
69
  it "returns the type tag" do
70
- stub(type_info).tag { :uint32 }
70
+ stub(type_info).tag { :uint32 }
71
71
 
72
- type_info.type_specification.must_equal ":uint32"
72
+ type_info.type_specification.must_equal ":uint32"
73
73
  end
74
74
  end
75
75
 
@@ -78,12 +78,12 @@ describe GirFFI::InfoExt::ITypeInfo do
78
78
  stub(elmtype_info).tag { :utf8 }
79
79
  stub(elmtype_info).pointer? { true }
80
80
 
81
- stub(type_info).tag { :array }
82
- stub(type_info).param_type(0) { elmtype_info }
83
- stub(type_info).zero_terminated? { true }
84
- stub(type_info).array_type { :c }
81
+ stub(type_info).tag { :array }
82
+ stub(type_info).param_type(0) { elmtype_info }
83
+ stub(type_info).zero_terminated? { true }
84
+ stub(type_info).array_type { :c }
85
85
 
86
- type_info.type_specification.must_equal "[:strv, :utf8]"
86
+ type_info.type_specification.must_equal "[:strv, :utf8]"
87
87
  end
88
88
  end
89
89
 
@@ -92,12 +92,12 @@ describe GirFFI::InfoExt::ITypeInfo do
92
92
  stub(elmtype_info).tag { :filename }
93
93
  stub(elmtype_info).pointer? { true }
94
94
 
95
- stub(type_info).tag { :array }
96
- stub(type_info).param_type(0) { elmtype_info }
97
- stub(type_info).zero_terminated? { true }
98
- stub(type_info).array_type { :c }
95
+ stub(type_info).tag { :array }
96
+ stub(type_info).param_type(0) { elmtype_info }
97
+ stub(type_info).zero_terminated? { true }
98
+ stub(type_info).array_type { :c }
99
99
 
100
- type_info.type_specification.must_equal "[:strv, :filename]"
100
+ type_info.type_specification.must_equal "[:strv, :filename]"
101
101
  end
102
102
  end
103
103
 
@@ -106,12 +106,12 @@ describe GirFFI::InfoExt::ITypeInfo do
106
106
  stub(elmtype_info).tag { :foo }
107
107
  stub(elmtype_info).pointer? { false }
108
108
 
109
- stub(type_info).tag { :array }
109
+ stub(type_info).tag { :array }
110
110
  stub(type_info).param_type(0) { elmtype_info }
111
- stub(type_info).zero_terminated? { true }
112
- stub(type_info).array_type { :c }
111
+ stub(type_info).zero_terminated? { true }
112
+ stub(type_info).array_type { :c }
113
113
 
114
- type_info.type_specification.must_equal "[:zero_terminated, :foo]"
114
+ type_info.type_specification.must_equal "[:zero_terminated, :foo]"
115
115
  end
116
116
  end
117
117
 
@@ -120,12 +120,12 @@ describe GirFFI::InfoExt::ITypeInfo do
120
120
  mock(elmtype_info).tag { :foo }
121
121
  mock(elmtype_info).pointer? { false }
122
122
 
123
- mock(type_info).tag { :array }
123
+ mock(type_info).tag { :array }
124
124
  stub(type_info).param_type(0) { elmtype_info }
125
- stub(type_info).zero_terminated? { false }
126
- stub(type_info).array_type { :c }
125
+ stub(type_info).zero_terminated? { false }
126
+ stub(type_info).array_type { :c }
127
127
 
128
- type_info.type_specification.must_equal "[:c, :foo]"
128
+ type_info.type_specification.must_equal "[:c, :foo]"
129
129
  end
130
130
  end
131
131
 
@@ -146,12 +146,12 @@ describe GirFFI::ReturnValueBuilder do
146
146
  describe "for :zero_terminated" do
147
147
  before do
148
148
  stub(type_info).flattened_tag { :zero_terminated }
149
+ stub(type_info).element_type { :foo }
149
150
  end
150
151
 
151
152
  it "wraps the result in #post" do
152
153
  builder.callarg.must_equal "_v1"
153
- # FIXME: This is almost certainly wrong, but matches original behavior.
154
- builder.post.must_equal [ "_v2 = GirFFI::InPointer.wrap(_v1)" ]
154
+ builder.post.must_equal [ "_v2 = GirFFI::ZeroTerminated.wrap(:foo, _v1)" ]
155
155
  end
156
156
 
157
157
  it "returns the wrapped result" do
@@ -0,0 +1,48 @@
1
+ require 'gir_ffi_test_helper'
2
+
3
+ describe GirFFI::ZeroTerminated do
4
+ describe ".from" do
5
+ let(:result) { GirFFI::ZeroTerminated.from :int32, [1, 2, 3] }
6
+
7
+ it "converts the passed array into a zero-terminated c array" do
8
+ ptr = result.to_ptr
9
+ ptr.read_array_of_int32(4).must_equal [1, 2, 3, 0]
10
+ end
11
+
12
+ it "returns a GirFFI::ZeroTerminated object" do
13
+ result.must_be_instance_of GirFFI::ZeroTerminated
14
+ end
15
+ end
16
+
17
+ describe ".wrap" do
18
+ it "wraps the given type and pointer" do
19
+ ptr = GirFFI::InPointer.from_array :int32, [1, 2, 3, 0]
20
+ zt = GirFFI::ZeroTerminated.wrap :foo, ptr
21
+ zt.element_type.must_equal :foo
22
+ zt.to_ptr.must_equal ptr
23
+ end
24
+ end
25
+
26
+ describe "#each" do
27
+ it "yields each element" do
28
+ zt = GirFFI::ZeroTerminated.from :int32, [1, 2, 3]
29
+ arr = []
30
+ zt.each do |int|
31
+ arr << int
32
+ end
33
+ arr.must_equal [1, 2, 3]
34
+ end
35
+
36
+ it "yields zero times for a ZeroTerminated wrapping a null pointer" do
37
+ zt = GirFFI::ZeroTerminated.wrap :int32, FFI::Pointer.new(0)
38
+ zt.each do |str|
39
+ flunk
40
+ end
41
+ end
42
+ end
43
+
44
+ it "includes Enumerable" do
45
+ GirFFI::ZeroTerminated.must_include Enumerable
46
+ end
47
+ end
48
+
@@ -8,11 +8,11 @@ module GObjectIntrospection
8
8
  def shared_library_with_regress namespace
9
9
  case namespace
10
10
  when "Regress"
11
- return File.join(File.dirname(__FILE__), 'lib', 'libregress.so')
11
+ return File.join(File.dirname(__FILE__), 'lib', 'libregress.so')
12
12
  when "GIMarshallingTests"
13
- return File.join(File.dirname(__FILE__), 'lib', 'libgimarshallingtests.so')
13
+ return File.join(File.dirname(__FILE__), 'lib', 'libgimarshallingtests.so')
14
14
  else
15
- return shared_library_without_regress namespace
15
+ return shared_library_without_regress namespace
16
16
  end
17
17
  end
18
18