gir_ffi 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
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