gir_ffi 0.9.4 → 0.9.5

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