gir_ffi 0.9.4 → 0.9.5

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +11 -0
  3. data/README.md +8 -6
  4. data/TODO.md +3 -0
  5. data/lib/ffi-glib.rb +2 -1
  6. data/lib/ffi-gobject.rb +2 -1
  7. data/lib/ffi-gobject/object.rb +19 -9
  8. data/lib/ffi-gobject/value.rb +15 -3
  9. data/lib/gir_ffi-base.rb +9 -4
  10. data/lib/gir_ffi-base/glib.rb +8 -0
  11. data/lib/gir_ffi-base/glib/boolean.rb +1 -0
  12. data/lib/gir_ffi-base/glib/strv.rb +1 -0
  13. data/lib/gir_ffi-base/gobject.rb +5 -1
  14. data/lib/gir_ffi/boxed_base.rb +12 -0
  15. data/lib/gir_ffi/builder.rb +10 -1
  16. data/lib/gir_ffi/builders/argument_builder.rb +8 -4
  17. data/lib/gir_ffi/builders/base_return_value_builder.rb +38 -0
  18. data/lib/gir_ffi/builders/callback_return_value_builder.rb +2 -30
  19. data/lib/gir_ffi/builders/initializer_return_value_builder.rb +2 -6
  20. data/lib/gir_ffi/builders/module_builder.rb +2 -3
  21. data/lib/gir_ffi/builders/property_argument_builder.rb +23 -0
  22. data/lib/gir_ffi/builders/property_builder.rb +65 -46
  23. data/lib/gir_ffi/builders/property_return_value_builder.rb +14 -0
  24. data/lib/gir_ffi/builders/return_value_builder.rb +9 -33
  25. data/lib/gir_ffi/callback_base.rb +5 -0
  26. data/lib/gir_ffi/core.rb +3 -3
  27. data/lib/gir_ffi/in_pointer.rb +1 -1
  28. data/lib/gir_ffi/info_ext/i_signal_info.rb +2 -3
  29. data/lib/gir_ffi/info_ext/i_type_info.rb +22 -14
  30. data/lib/gir_ffi/interface_base.rb +12 -0
  31. data/lib/gir_ffi/user_defined_type_info.rb +8 -0
  32. data/lib/gir_ffi/version.rb +1 -1
  33. data/test/gir_ffi/builders/function_builder_test.rb +19 -0
  34. data/test/gir_ffi/builders/object_builder_test.rb +5 -11
  35. data/test/gir_ffi/builders/property_builder_test.rb +37 -5
  36. data/test/gir_ffi/builders/signal_closure_builder_test.rb +21 -0
  37. data/test/gir_ffi/builders/vfunc_builder_test.rb +20 -0
  38. data/test/gir_ffi/info_ext/i_type_info_test.rb +18 -0
  39. data/test/gir_ffi/user_defined_type_info_test.rb +25 -0
  40. data/test/gir_ffi_test_helper.rb +2 -6
  41. data/test/integration/generated_gimarshallingtests_test.rb +5 -5
  42. data/test/integration/generated_gio_test.rb +2 -3
  43. data/test/integration/generated_gst_test.rb +1 -0
  44. data/test/integration/generated_regress_test.rb +630 -189
  45. data/test/integration/generated_utility_test.rb +173 -0
  46. data/test/lib/Makefile.am +3 -5
  47. metadata +7 -2
@@ -1,6 +1,63 @@
1
1
  # frozen_string_literal: true
2
+ require 'gir_ffi/builders/method_template'
3
+ require 'gir_ffi/builders/argument_builder_collection'
4
+ require 'gir_ffi/builders/property_argument_builder'
5
+ require 'gir_ffi/builders/property_return_value_builder'
6
+ require 'gir_ffi/variable_name_generator'
7
+ require 'gir_ffi/field_argument_info'
8
+
2
9
  module GirFFI
3
10
  module Builders
11
+ # Method builder used for the creation of property getter methods.
12
+ class PropertyGetterBuilder
13
+ attr_reader :info
14
+ attr_reader :return_value_builder
15
+
16
+ def initialize(info, return_value_builder)
17
+ @return_value_builder = return_value_builder
18
+ @info = info
19
+ end
20
+
21
+ def method_definition
22
+ template.method_definition
23
+ end
24
+
25
+ def template
26
+ @template ||= MethodTemplate.new(self, argument_builder_collection)
27
+ end
28
+
29
+ def singleton_method?
30
+ false
31
+ end
32
+
33
+ def method_name
34
+ info.getter_name
35
+ end
36
+
37
+ def method_arguments
38
+ []
39
+ end
40
+
41
+ def preparation
42
+ []
43
+ end
44
+
45
+ def invocation
46
+ "get_property('#{info.name}')"
47
+ end
48
+
49
+ def result
50
+ [return_value_builder.return_value_name]
51
+ end
52
+
53
+ private
54
+
55
+ def argument_builder_collection
56
+ @argument_builder_collection ||=
57
+ ArgumentBuilderCollection.new(return_value_builder, [])
58
+ end
59
+ end
60
+
4
61
  # Creates property getter and setter code for a given IPropertyInfo.
5
62
  class PropertyBuilder
6
63
  def initialize(property_info)
@@ -24,51 +81,20 @@ module GirFFI
24
81
  container_class.class_eval setter_def
25
82
  end
26
83
 
27
- # TODO: Fix argument builders so converting_getter_def can always be used.
28
84
  def getter_def
29
- case type_info.tag
30
- when :glist, :ghash
31
- converting_getter_def
32
- else
33
- simple_getter_def
34
- end
85
+ PropertyGetterBuilder.new(@info, getter_builder).method_definition
35
86
  end
36
87
 
37
- # TODO: Fix argument builders so converting_setter_def can always be used.
38
88
  def setter_def
39
- case type_info.flattened_tag
40
- when :glist, :ghash, :strv
41
- converting_setter_def
42
- else
43
- simple_setter_def
44
- end
89
+ converting_setter_def
45
90
  end
46
91
 
47
92
  private
48
93
 
49
- # TODO: Use a builder like MarshallingMethodBuilder
50
- def converting_getter_def
51
- capture = getter_builder.capture_variable_name
52
- <<-CODE.reset_indentation
53
- def #{getter_name}
54
- #{capture} = get_property("#{property_name}")
55
- #{getter_builder.post_conversion.join("\n")}
56
- #{getter_builder.return_value_name}
57
- end
58
- CODE
59
- end
60
-
61
- def simple_getter_def
62
- <<-CODE.reset_indentation
63
- def #{getter_name}
64
- get_property("#{property_name}")
65
- end
66
- CODE
67
- end
68
-
69
94
  def getter_builder
70
- @getter_builder ||= ReturnValueBuilder.new(VariableNameGenerator.new,
71
- argument_info)
95
+ @getter_builder ||=
96
+ PropertyReturnValueBuilder.new(VariableNameGenerator.new,
97
+ argument_info)
72
98
  end
73
99
 
74
100
  def converting_setter_def
@@ -80,17 +106,10 @@ module GirFFI
80
106
  CODE
81
107
  end
82
108
 
83
- def simple_setter_def
84
- <<-CODE.reset_indentation
85
- def #{setter_name} value
86
- set_property("#{property_name}", value)
87
- end
88
- CODE
89
- end
90
-
91
109
  def setter_builder
92
- @setter_builder ||= ArgumentBuilder.new(VariableNameGenerator.new,
93
- argument_info)
110
+ @setter_builder ||=
111
+ PropertyArgumentBuilder.new(VariableNameGenerator.new,
112
+ argument_info)
94
113
  end
95
114
 
96
115
  def property_name
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ require 'gir_ffi/builders/return_value_builder'
3
+
4
+ module GirFFI
5
+ module Builders
6
+ # Implements building post-processing statements for return values of
7
+ # property getters.
8
+ class PropertyReturnValueBuilder < ReturnValueBuilder
9
+ def needs_c_to_ruby_conversion?
10
+ type_info.needs_c_to_ruby_conversion_for_properties?
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,32 +1,12 @@
1
1
  # frozen_string_literal: true
2
- require 'gir_ffi/builders/base_argument_builder'
2
+ require 'gir_ffi/builders/base_return_value_builder'
3
3
  require 'gir_ffi/builders/full_c_to_ruby_convertor'
4
4
  require 'gir_ffi/builders/closure_convertor'
5
5
 
6
6
  module GirFFI
7
7
  module Builders
8
8
  # Implements building post-processing statements for return values.
9
- class ReturnValueBuilder < BaseArgumentBuilder
10
- def relevant?
11
- !void_return_value? && !arginfo.skip?
12
- end
13
-
14
- def capture_variable_name
15
- @capture_variable_name ||= new_variable if relevant?
16
- end
17
-
18
- def post_converted_name
19
- @post_converted_name ||= if has_post_conversion?
20
- new_variable
21
- else
22
- capture_variable_name
23
- end
24
- end
25
-
26
- def return_value_name
27
- post_converted_name if has_return_value_name?
28
- end
29
-
9
+ class ReturnValueBuilder < BaseReturnValueBuilder
30
10
  def post_conversion
31
11
  if has_post_conversion?
32
12
  ["#{post_converted_name} = #{post_convertor.conversion}"]
@@ -35,12 +15,16 @@ module GirFFI
35
15
  end
36
16
  end
37
17
 
38
- private
39
-
40
18
  def has_post_conversion?
41
- closure? || type_info.needs_c_to_ruby_conversion_for_functions?
19
+ closure? || needs_c_to_ruby_conversion?
20
+ end
21
+
22
+ def needs_c_to_ruby_conversion?
23
+ type_info.needs_c_to_ruby_conversion_for_functions?
42
24
  end
43
25
 
26
+ private
27
+
44
28
  def post_convertor
45
29
  @post_convertor ||= if closure?
46
30
  ClosureConvertor.new(capture_variable_name)
@@ -54,14 +38,6 @@ module GirFFI
54
38
  def length_argument_name
55
39
  length_arg && length_arg.post_converted_name
56
40
  end
57
-
58
- def void_return_value?
59
- specialized_type_tag == :void && !type_info.pointer?
60
- end
61
-
62
- def has_return_value_name?
63
- relevant? && !array_arg
64
- end
65
41
  end
66
42
  end
67
43
  end
@@ -13,6 +13,7 @@ module GirFFI
13
13
  FFI::Type::POINTER
14
14
  end
15
15
 
16
+ # TODO: Return instance of this class
16
17
  def self.from_native(value, _context)
17
18
  return nil if !value || value.null?
18
19
  FFI::Function.new(gir_ffi_builder.return_ffi_type,
@@ -74,6 +75,10 @@ module GirFFI
74
75
  end
75
76
  end
76
77
 
78
+ def to_ptr
79
+ to_native.to_ptr
80
+ end
81
+
77
82
  def self.copy_value_to_pointer(value, pointer)
78
83
  pointer.put_pointer 0, to_native(value, nil)
79
84
  end
@@ -23,9 +23,9 @@ require 'gir_ffi/version'
23
23
  # Main module containing classes and modules needed for generating GLib and
24
24
  # GObject bindings.
25
25
  module GirFFI
26
- def self.setup(module_name, version = nil)
27
- module_name = module_name.to_s
28
- GirFFI::Builder.build_module module_name, version
26
+ def self.setup(namespace, version = nil)
27
+ namespace = namespace.to_s
28
+ GirFFI::Builder.build_module namespace, version
29
29
  end
30
30
 
31
31
  def self.define_type(klass, &block)
@@ -35,7 +35,7 @@ module GirFFI
35
35
  case type
36
36
  when :utf8, :filename
37
37
  from_utf8 val
38
- when :gint32, :guint32, :gint8
38
+ when :gint32, :guint32, :gint8, :GType
39
39
  new val
40
40
  when Class, :void
41
41
  val.to_ptr
@@ -16,9 +16,8 @@ module GirFFI
16
16
  end
17
17
 
18
18
  def arguments_to_gvalues(instance, arguments)
19
- arg_g_values = args.map { |info| info.argument_type.make_g_value }
20
- arg_g_values.zip(arguments).each do |g_value, arg|
21
- g_value.set_value arg
19
+ arg_g_values = args.zip(arguments).map do |info, arg|
20
+ info.argument_type.make_g_value.tap { |it| it.set_value arg }
22
21
  end
23
22
 
24
23
  arg_g_values.unshift GObject::Value.wrap_instance(instance)
@@ -7,24 +7,24 @@ module GirFFI
7
7
  module ITypeInfo
8
8
  def self.flattened_tag_to_gtype_map
9
9
  @flattened_tag_to_gtype_map ||= {
10
- array: GObject::TYPE_ARRAY,
11
- c: GObject::TYPE_POINTER,
12
- gboolean: GObject::TYPE_BOOLEAN,
13
- ghash: GObject::TYPE_HASH_TABLE,
14
- gint32: GObject::TYPE_INT,
15
- gint64: GObject::TYPE_INT64,
16
- guint64: GObject::TYPE_UINT64,
17
- strv: GObject::TYPE_STRV,
18
- utf8: GObject::TYPE_STRING,
19
- void: GObject::TYPE_NONE
10
+ [:array, true] => GObject::TYPE_ARRAY,
11
+ [:c, true] => GObject::TYPE_POINTER,
12
+ [:gboolean, false] => GObject::TYPE_BOOLEAN,
13
+ [:ghash, true] => GObject::TYPE_HASH_TABLE,
14
+ [:glist, true] => GObject::TYPE_POINTER,
15
+ [:gint32, false] => GObject::TYPE_INT,
16
+ [:gint64, false] => GObject::TYPE_INT64,
17
+ [:guint64, false] => GObject::TYPE_UINT64,
18
+ [:strv, true] => GObject::TYPE_STRV,
19
+ [:utf8, true] => GObject::TYPE_STRING,
20
+ [:void, true] => GObject::TYPE_POINTER,
21
+ [:void, false] => GObject::TYPE_NONE
20
22
  }.freeze
21
23
  end
22
24
 
23
25
  def gtype
24
26
  return interface.gtype if tag == :interface
25
- type = ITypeInfo.flattened_tag_to_gtype_map[flattened_tag]
26
- return type if type
27
- raise "Can't find GType for #{flattened_tag} pointer? = #{pointer?}"
27
+ ITypeInfo.flattened_tag_to_gtype_map.fetch [flattened_tag, pointer?]
28
28
  end
29
29
 
30
30
  def make_g_value
@@ -158,13 +158,21 @@ module GirFFI
158
158
  end
159
159
 
160
160
  def needs_c_to_ruby_conversion_for_closures?
161
- [:array, :c, :ghash, :struct, :strv].include?(flattened_tag)
161
+ [:array, :c, :ghash, :glist, :struct, :strv].include?(flattened_tag)
162
162
  end
163
163
 
164
164
  def needs_ruby_to_c_conversion_for_closures?
165
165
  [:array].include?(flattened_tag)
166
166
  end
167
167
 
168
+ def needs_ruby_to_c_conversion_for_properties?
169
+ [:glist, :ghash, :strv, :callback].include?(flattened_tag)
170
+ end
171
+
172
+ def needs_c_to_ruby_conversion_for_properties?
173
+ [:glist, :ghash, :callback].include?(flattened_tag)
174
+ end
175
+
168
176
  def extra_conversion_arguments
169
177
  case flattened_tag
170
178
  when :utf8, :void
@@ -6,10 +6,22 @@ module GirFFI
6
6
  module InterfaceBase
7
7
  include RegisteredTypeBase
8
8
 
9
+ def setup_and_call(method, arguments, &block)
10
+ method_name = setup_method method.to_s
11
+ unless method_name
12
+ raise NoMethodError, "undefined method `#{method}' for #{self}"
13
+ end
14
+ send method_name, *arguments, &block
15
+ end
16
+
9
17
  def setup_instance_method(name)
10
18
  gir_ffi_builder.setup_instance_method name
11
19
  end
12
20
 
21
+ def setup_method(name)
22
+ gir_ffi_builder.setup_method name
23
+ end
24
+
13
25
  def wrap(ptr)
14
26
  ptr.to_object
15
27
  end
@@ -49,6 +49,14 @@ module GirFFI
49
49
  parent.class_struct
50
50
  end
51
51
 
52
+ def interfaces
53
+ (@klass.included_modules - @klass.superclass.included_modules).map(&:gir_info)
54
+ end
55
+
56
+ def find_signal(_signal_name)
57
+ nil
58
+ end
59
+
52
60
  attr_writer :g_name
53
61
 
54
62
  def g_name
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
  # Current GirFFI version
3
3
  module GirFFI
4
- VERSION = '0.9.4'.freeze
4
+ VERSION = '0.9.5'.freeze
5
5
  end
@@ -36,6 +36,25 @@ describe GirFFI::Builders::FunctionBuilder do
36
36
  end
37
37
  end
38
38
 
39
+ describe 'for methods taking a zero-terminated array with length argument' do
40
+ let(:function_info) { get_method_introspection_data 'Regress', 'AnnotationObject', 'parse_args' }
41
+ it 'builds a correct definition' do
42
+ skip unless function_info
43
+ code.must_equal <<-CODE.reset_indentation
44
+ def parse_args(argv)
45
+ argc = argv.nil? ? 0 : argv.length
46
+ _v1 = GirFFI::InOutPointer.for :gint32
47
+ _v1.set_value argc
48
+ _v2 = GirFFI::InOutPointer.for [:pointer, :strv]
49
+ _v2.set_value GLib::Strv.from(argv)
50
+ Regress::Lib.regress_annotation_object_parse_args self, _v1, _v2
51
+ _v3 = GLib::Strv.wrap(_v2.to_value)
52
+ return _v3
53
+ end
54
+ CODE
55
+ end
56
+ end
57
+
39
58
  describe 'for functions with callbacks' do
40
59
  let(:function_info) { get_introspection_data 'Regress', 'test_callback_destroy_notify' }
41
60
  it 'builds a correct definition' do
@@ -65,21 +65,15 @@ describe GirFFI::Builders::ObjectBuilder do
65
65
  end
66
66
  end
67
67
 
68
- # TODO: Improve this spec to use less mocking
69
68
  describe 'for a struct without defined fields' do
70
- it 'uses a single field of the parent struct type as the default layout' do
71
- @gir = GObjectIntrospection::IRepository.default
72
- @gir.require 'GObject', nil
69
+ let(:info) { get_introspection_data 'GObject', 'Binding' }
73
70
 
74
- allow(info = Object.new).to receive(:parent).and_return @gir.find_by_name 'GObject', 'Object'
75
- allow(info).to receive(:fields).and_return []
76
- allow(info).to receive(:info_type).and_return :object
77
- allow(info).to receive(:safe_name).and_return 'Bar'
78
- allow(info).to receive(:namespace).and_return 'Foo'
71
+ it 'uses a single field of the parent struct type as the default layout' do
72
+ info.n_fields.must_equal 0
79
73
 
80
- @classbuilder = GirFFI::Builders::ObjectBuilder.new info
74
+ builder = GirFFI::Builders::ObjectBuilder.new info
81
75
 
82
- spec = @classbuilder.send :layout_specification
76
+ spec = builder.send :layout_specification
83
77
  assert_equal [:parent, GObject::Object::Struct, 0], spec
84
78
  end
85
79
  end
@@ -9,7 +9,7 @@ describe GirFFI::Builders::PropertyBuilder do
9
9
  it 'generates the correct getter definition' do
10
10
  expected = <<-CODE.reset_indentation
11
11
  def list
12
- _v1 = get_property("list")
12
+ _v1 = get_property('list')
13
13
  _v2 = GLib::List.wrap(:utf8, _v1)
14
14
  _v2
15
15
  end
@@ -35,7 +35,7 @@ describe GirFFI::Builders::PropertyBuilder do
35
35
  it 'generates the correct getter definition' do
36
36
  expected = <<-CODE.reset_indentation
37
37
  def hash_table
38
- _v1 = get_property("hash-table")
38
+ _v1 = get_property('hash-table')
39
39
  _v2 = GLib::HashTable.wrap([:utf8, :gint8], _v1)
40
40
  _v2
41
41
  end
@@ -69,7 +69,8 @@ describe GirFFI::Builders::PropertyBuilder do
69
69
  it 'generates the correct getter definition' do
70
70
  expected = <<-CODE.reset_indentation
71
71
  def some_strv
72
- get_property("some-strv")
72
+ _v1 = get_property('some-strv')
73
+ _v1
73
74
  end
74
75
  CODE
75
76
 
@@ -93,7 +94,8 @@ describe GirFFI::Builders::PropertyBuilder do
93
94
  it 'generates the correct getter definition' do
94
95
  expected = <<-CODE.reset_indentation
95
96
  def string
96
- get_property("string")
97
+ _v1 = get_property('string')
98
+ _v1
97
99
  end
98
100
  CODE
99
101
 
@@ -103,7 +105,37 @@ describe GirFFI::Builders::PropertyBuilder do
103
105
  it 'generates the correct setter definition' do
104
106
  expected = <<-CODE.reset_indentation
105
107
  def string= value
106
- set_property("string", value)
108
+ _v1 = value
109
+ set_property("string", _v1)
110
+ end
111
+ CODE
112
+
113
+ builder.setter_def.must_equal expected
114
+ end
115
+ end
116
+
117
+ describe 'for a property of a callback type' do
118
+ let(:property_info) do
119
+ get_property_introspection_data('Regress', 'AnnotationObject', 'function-property')
120
+ end
121
+
122
+ it 'generates the correct getter definition' do
123
+ expected = <<-CODE.reset_indentation
124
+ def function_property
125
+ _v1 = get_property('function-property')
126
+ _v2 = Regress::AnnotationCallback.wrap(_v1)
127
+ _v2
128
+ end
129
+ CODE
130
+
131
+ builder.getter_def.must_equal expected
132
+ end
133
+
134
+ it 'generates the correct setter definition' do
135
+ expected = <<-CODE.reset_indentation
136
+ def function_property= value
137
+ _v1 = Regress::AnnotationCallback.from(value)
138
+ set_property("function-property", _v1)
107
139
  end
108
140
  CODE
109
141