gir_ffi 0.8.1 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +16 -0
  3. data/DESIGN.md +17 -15
  4. data/lib/ffi-glib/array.rb +4 -5
  5. data/lib/ffi-glib/byte_array.rb +2 -4
  6. data/lib/ffi-glib/bytes.rb +12 -2
  7. data/lib/ffi-glib/hash_table.rb +31 -31
  8. data/lib/ffi-glib/list_methods.rb +5 -15
  9. data/lib/ffi-glib/ptr_array.rb +3 -3
  10. data/lib/ffi-gobject/closure.rb +2 -0
  11. data/lib/ffi-gobject/ruby_closure.rb +13 -15
  12. data/lib/ffi-gobject/value.rb +33 -27
  13. data/lib/ffi-gobject.rb +5 -3
  14. data/lib/ffi-gobject_introspection/i_base_info.rb +2 -1
  15. data/lib/ffi-gobject_introspection/i_interface_info.rb +1 -1
  16. data/lib/ffi-gobject_introspection/i_object_info.rb +2 -2
  17. data/lib/ffi-gobject_introspection/i_struct_info.rb +1 -1
  18. data/lib/ffi-gobject_introspection/i_union_info.rb +1 -1
  19. data/lib/gir_ffi/boxed_base.rb +8 -6
  20. data/lib/gir_ffi/builders/boxed_builder.rb +0 -10
  21. data/lib/gir_ffi/builders/null_class_builder.rb +13 -0
  22. data/lib/gir_ffi/builders/user_defined_builder.rb +3 -3
  23. data/lib/gir_ffi/class_base.rb +10 -6
  24. data/lib/gir_ffi/in_out_pointer.rb +1 -5
  25. data/lib/gir_ffi/info_ext/i_registered_type_info.rb +4 -0
  26. data/lib/gir_ffi/user_defined_type_info.rb +4 -0
  27. data/lib/gir_ffi/version.rb +1 -1
  28. data/test/ffi-glib/ruby_closure_test.rb +1 -1
  29. data/test/ffi-gobject/value_test.rb +29 -0
  30. data/test/ffi-gobject_introspection/i_interface_info_test.rb +21 -0
  31. data/test/ffi-gobject_introspection/i_object_info_test.rb +15 -1
  32. data/test/ffi-gobject_introspection/i_struct_info_test.rb +21 -0
  33. data/test/ffi-gobject_introspection/i_union_info_test.rb +15 -0
  34. data/test/gir_ffi/class_base_test.rb +31 -6
  35. data/test/gir_ffi/in_out_pointer_test.rb +21 -2
  36. data/test/gir_ffi/user_defined_type_info_test.rb +9 -0
  37. metadata +6 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5e373464c8f376bf817deb6d9f1d82317b9d0b6a
4
- data.tar.gz: 9205d3435def6eecba27339a6bd7d0f1a114c745
3
+ metadata.gz: 6121625e854dd754146516dab64b67c650155c67
4
+ data.tar.gz: e486edea5ebffe7146c68dca786796f94ac58945
5
5
  SHA512:
6
- metadata.gz: 42daa42701febe109c324c616af3aee367be2382e6994ca7fc9b915d63ef2984daacaed84eb6e1d5dd84d125e2acc964beeacb49e465552f9b45ad57f66a676c
7
- data.tar.gz: 5f88e3c9d6e23449d0b461aab4bb320322f338e40f2938f5dd2bd9408da976b941d7661ad762c2ebd218f20521adb6c34dc27deab1316724d4bb6e3de0601bc2
6
+ metadata.gz: 170a26c6f8aecc34a77722a5525d8b1534491febdd244fff0a9c88aa298a357ee0914f1fc15393da52b306d2f295e7aaba0180f258a187e942433658e51262ae
7
+ data.tar.gz: afbed9ce4c8869f8e44b6c1bbb36d22192bf27e01720874d9e3632fd5dd4b59fcc5604e785c39ccf1c6b8e6fe084270d7efee54f992a70e36dc469fd93508031
data/Changelog.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.8.2 / 2015-10-10
4
+
5
+ * Use inherited constructor for boxed types
6
+ * Make InOutPointer work correctly for boxed types
7
+ * Make .for work with boxed types
8
+ * Make #set_value work with boxed types
9
+ * Make GObject::Value support nil type:
10
+ * Make .wrap_ruby_value(nil) work
11
+ * Make #set_value and #get_value work when the type is TYPE_INVALID
12
+ * Make .for_gtype work with TYPE_INVALID and TYPE_NONE
13
+ * Make .from(nil) return a GObject::Value instead of nil
14
+ * Make #set_ruby_value private
15
+ * Make GObject::Object.signal_emit work with gobject-introspection 1.46
16
+ * Replace or remove all custom .new methods
17
+ * Make setup_method and setup_instance_method handle symbol arguments
18
+
3
19
  ## 0.8.1 / 2015-10-04
4
20
 
5
21
  * Handle struct array fields with related length fields
data/DESIGN.md CHANGED
@@ -64,25 +64,27 @@ cannot bootstrap itself.
64
64
 
65
65
  ## Object initialization
66
66
 
67
- An attempt at making Thing.new less hacky.
67
+ Each constructor method is implemented in Ruby by a pair of new/initialize
68
+ methods. For example, a constructor `new_from_file` is implemented as a
69
+ combination of the singleton method `new_from_file` and the instance method
70
+ `initialize_from_file`. User-created subclasses override the appropriate
71
+ initializer method and must call super with the appropriate arguments.
68
72
 
69
- Goals:
70
-
71
- * No aliasing of Ruby's new. Overriding is possible with super being called.
72
- * #initialize should behave as expected. We may enforce use of super in Ruby
73
- subclasses.
74
-
75
- Schematic depiction of what happens (can happen):
73
+ Here is an example of the generated pair of methods:
76
74
 
77
75
  ```ruby
78
- class GObject::Object
79
- def self.new *args
80
- # Stage A
81
- super(*other_args)
82
- # Stage C
76
+ class Regress::TestObj
77
+ def self.new_from_file(*args)
78
+ obj = allocate
79
+ obj.__send__ :initialize_from_file, *args
80
+ obj
83
81
  end
84
82
 
85
- def initialize *other_args
86
- # Stage B
83
+ def initialize_from_file(x)
84
+ _v1 = GirFFI::InPointer.from(:utf8, x)
85
+ _v2 = FFI::MemoryPointer.new(:pointer).write_pointer nil
86
+ _v3 = Regress::Lib.regress_test_obj_new_from_file _v1, _v2
87
+ GirFFI::ArgHelper.check_error(_v2)
88
+ store_pointer(_v3)
87
89
  end
88
90
  end
@@ -13,11 +13,10 @@ module GLib
13
13
 
14
14
  attr_reader :element_type
15
15
 
16
- class << self; undef :new; end
17
-
18
- def self.new(type)
19
- ptr = Lib.g_array_new(0, 0, calculated_element_size(type))
20
- wrap type, ptr
16
+ def initialize(type)
17
+ @element_type = type
18
+ ptr = Lib.g_array_new(0, 0, calculated_element_size)
19
+ store_pointer(ptr)
21
20
  end
22
21
 
23
22
  # @api private
@@ -13,10 +13,8 @@ module GLib
13
13
  self.class.wrap(Lib.g_byte_array_append to_ptr, bytes, len)
14
14
  end
15
15
 
16
- class << self; undef :new; end
17
-
18
- def self.new
19
- wrap(Lib.g_byte_array_new)
16
+ def initialize
17
+ store_pointer(Lib.g_byte_array_new)
20
18
  end
21
19
  end
22
20
  end
@@ -32,13 +32,23 @@ module GLib
32
32
  end
33
33
  end
34
34
 
35
+ # Why redefine new here? The class builder will only define the full
36
+ # version of 'new' on first call, causing both new and initialize to be
37
+ # defined. This overwrites the custom version of initialize below.
38
+ # TODO: Improve class builder so this trick is not needed.
35
39
  class << self
36
40
  undef new
37
41
  end
38
42
 
39
- def self.new(arr)
43
+ def self.new(*args)
44
+ obj = allocate
45
+ obj.__send__ :initialize, *args
46
+ obj
47
+ end
48
+
49
+ def initialize(arr)
40
50
  data = GirFFI::SizedArray.from :guint8, arr.size, arr
41
- wrap Lib.g_bytes_new data.to_ptr, data.size
51
+ store_pointer Lib.g_bytes_new data.to_ptr, data.size
42
52
  end
43
53
 
44
54
  private
@@ -11,11 +11,11 @@ module GLib
11
11
  attr_reader :key_type
12
12
  attr_reader :value_type
13
13
 
14
- class << self; remove_method :new; end
15
-
16
- def self.new(keytype, valtype)
17
- wrap [keytype, valtype], Lib.g_hash_table_new(
18
- hash_function_for(keytype), equality_function_for(keytype))
14
+ def initialize(key_type, value_type)
15
+ @key_type = key_type
16
+ @value_type = value_type
17
+ store_pointer Lib.g_hash_table_new(
18
+ hash_function_for_key_type, equality_function_for_key_type)
19
19
  end
20
20
 
21
21
  # @api private
@@ -27,32 +27,6 @@ module GLib
27
27
  ghash
28
28
  end
29
29
 
30
- # @api private
31
- def self.hash_function_for(keytype)
32
- case keytype
33
- when :utf8
34
- FFI::Function.new(:uint,
35
- [:pointer],
36
- find_support_function('g_str_hash'))
37
- end
38
- end
39
-
40
- # @api private
41
- def self.equality_function_for(keytype)
42
- case keytype
43
- when :utf8
44
- FFI::Function.new(:int,
45
- [:pointer, :pointer],
46
- find_support_function('g_str_equal'))
47
- end
48
- end
49
-
50
- # @api private
51
- def self.find_support_function(name)
52
- lib = ::GLib::Lib.ffi_libraries.first
53
- lib.find_function(name)
54
- end
55
-
56
30
  def each
57
31
  prc = proc do|keyptr, valptr, _userdata|
58
32
  key = GirFFI::ArgHelper.cast_from_pointer key_type, keyptr
@@ -79,5 +53,31 @@ module GLib
79
53
  @key_type, @value_type = *typespec
80
54
  self
81
55
  end
56
+
57
+ private
58
+
59
+ def hash_function_for_key_type
60
+ case @key_type
61
+ when :utf8
62
+ FFI::Function.new(:uint,
63
+ [:pointer],
64
+ find_support_function('g_str_hash'))
65
+ end
66
+ end
67
+
68
+ def equality_function_for_key_type
69
+ case @key_type
70
+ when :utf8
71
+ FFI::Function.new(:int,
72
+ [:pointer, :pointer],
73
+ find_support_function('g_str_equal'))
74
+ end
75
+ end
76
+
77
+ def find_support_function(name)
78
+ lib = ::GLib::Lib.ffi_libraries.first
79
+ lib.find_function(name)
80
+ end
81
+
82
82
  end
83
83
  end
@@ -11,9 +11,6 @@ module GLib
11
11
  replace_method base, :next, :tail
12
12
  replace_method base, :data, :head
13
13
 
14
- class << base; self end.send :remove_method, :new
15
- base.extend ListClassMethods
16
-
17
14
  base.extend ContainerClassMethods
18
15
  end
19
16
 
@@ -24,6 +21,11 @@ module GLib
24
21
  end
25
22
  end
26
23
 
24
+ def initialize(type)
25
+ store_pointer(FFI::Pointer.new(0))
26
+ @element_type = type
27
+ end
28
+
27
29
  def each
28
30
  reset_iterator
29
31
  while (elem = next_element)
@@ -64,17 +66,5 @@ module GLib
64
66
  def element_ptr_for(data)
65
67
  GirFFI::InPointer.from(element_type, data)
66
68
  end
67
-
68
- # Common class methods for List and SList
69
- module ListClassMethods
70
- # TODO: Make this behave more like a real .new method
71
- def new(type)
72
- allocate.tap do |it|
73
- struct = self::Struct.new(FFI::Pointer.new(0))
74
- it.instance_variable_set :@struct, struct
75
- it.instance_variable_set :@element_type, type
76
- end
77
- end
78
- end
79
69
  end
80
70
  end
@@ -16,13 +16,13 @@ module GLib
16
16
  POINTER_SIZE = FFI.type_size(:pointer)
17
17
 
18
18
  class << self
19
- remove_method :new
20
19
  # Remove stub generated by builder.
21
20
  remove_method :add if method_defined? :add
22
21
  end
23
22
 
24
- def self.new(type)
25
- wrap(type, Lib.g_ptr_array_new)
23
+ def initialize(type)
24
+ @element_type = type
25
+ store_pointer Lib.g_ptr_array_new
26
26
  end
27
27
 
28
28
  def self.from_enumerable(type, it)
@@ -5,6 +5,8 @@ module GObject
5
5
  #
6
6
  # To create Closure objects wrapping Ruby code, use {RubyClosure}.
7
7
  class Closure
8
+ setup_method :new_simple
9
+
8
10
  # @override
9
11
  #
10
12
  # @param [Proc] marshal The marshaller to use for this closure object
@@ -15,14 +15,12 @@ module GObject
15
15
  :block_id, :int64
16
16
  end
17
17
 
18
- def self.new(&block)
18
+ def initialize(&block)
19
19
  raise ArgumentError unless block_given?
20
20
 
21
- closure = wrap(new_simple(self::Struct.size, nil).to_ptr)
22
- closure.block = block
23
- closure.set_marshal proc { |*args| marshaller(*args) }
24
-
25
- closure
21
+ initialize_simple(self.class::Struct.size, nil)
22
+ self.block = block
23
+ set_marshal proc { |*args| self.class.marshaller(*args) }
26
24
  end
27
25
 
28
26
  # @api private
@@ -36,24 +34,24 @@ module GObject
36
34
 
37
35
  result = rclosure.invoke_block(*args)
38
36
 
39
- return_value.set_ruby_value(result) if return_value
40
- end
41
-
42
- # @api private
43
- # TODO: Re-structure so block= and invoke_block can become private methods
44
- def block=(block)
45
- id = block.object_id
46
- BLOCK_STORE[id] = block
47
- @struct[:block_id] = id
37
+ return_value.set_value(result) if return_value
48
38
  end
49
39
 
50
40
  # @api private
41
+ # TODO: Re-structure so invoke_block can become a private method
51
42
  def invoke_block(*args)
52
43
  block.call(*args)
53
44
  end
54
45
 
55
46
  private
56
47
 
48
+ # @api private
49
+ def block=(block)
50
+ id = block.object_id
51
+ BLOCK_STORE[id] = block
52
+ @struct[:block_id] = id
53
+ end
54
+
57
55
  def block
58
56
  BLOCK_STORE[@struct[:block_id]]
59
57
  end
@@ -6,6 +6,7 @@ module GObject
6
6
  setup_instance_method 'init'
7
7
 
8
8
  def init_with_finalizer(type)
9
+ return self if [TYPE_NONE, TYPE_INVALID].include? type
9
10
  init_without_finalizer(type).tap do
10
11
  ObjectSpace.define_finalizer self, self.class.make_finalizer(to_ptr)
11
12
  end
@@ -20,13 +21,8 @@ module GObject
20
21
  end
21
22
  end
22
23
 
23
- # TODO: Give more generic name
24
- def set_ruby_value(val)
25
- init_for_ruby_value val if current_gtype == 0
26
- set_value val
27
- end
28
-
29
24
  METHOD_MAP = {
25
+ TYPE_INVALID => [:get_none, :set_none],
30
26
  TYPE_BOOLEAN => [:get_boolean, :set_boolean],
31
27
  TYPE_BOXED => [:get_boxed, :set_boxed],
32
28
  TYPE_CHAR => [:get_char, :set_char],
@@ -55,23 +51,6 @@ module GObject
55
51
 
56
52
  alias_method :value=, :set_value
57
53
 
58
- CLASS_TO_GTYPE_MAP = {
59
- TrueClass => TYPE_BOOLEAN,
60
- FalseClass => TYPE_BOOLEAN,
61
- Integer => TYPE_INT,
62
- String => TYPE_STRING
63
- }
64
-
65
- def init_for_ruby_value(val)
66
- CLASS_TO_GTYPE_MAP.each do |klass, type|
67
- if val.is_a? klass
68
- init type
69
- return self
70
- end
71
- end
72
- raise "Can't handle #{val.class}"
73
- end
74
-
75
54
  def current_gtype
76
55
  @struct[:g_type]
77
56
  end
@@ -99,22 +78,19 @@ module GObject
99
78
 
100
79
  # TODO: Give more generic name
101
80
  def self.wrap_ruby_value(val)
102
- new.tap { |gv| gv.set_ruby_value val }
81
+ new.tap { |gv| gv.__send__ :set_ruby_value, val }
103
82
  end
104
83
 
105
84
  def self.from(val)
106
85
  case val
107
86
  when self
108
87
  val
109
- when nil
110
- nil
111
88
  else
112
89
  wrap_ruby_value val
113
90
  end
114
91
  end
115
92
 
116
93
  def self.for_gtype(gtype)
117
- return nil if gtype == TYPE_NONE
118
94
  new.tap do |it|
119
95
  it.init gtype
120
96
  end
@@ -130,6 +106,36 @@ module GObject
130
106
 
131
107
  private
132
108
 
109
+ def set_ruby_value(val)
110
+ init_for_ruby_value val if uninitialized?
111
+ set_value val
112
+ end
113
+
114
+ CLASS_TO_GTYPE_MAP = {
115
+ NilClass => TYPE_INVALID,
116
+ TrueClass => TYPE_BOOLEAN,
117
+ FalseClass => TYPE_BOOLEAN,
118
+ Integer => TYPE_INT,
119
+ String => TYPE_STRING
120
+ }
121
+
122
+ def init_for_ruby_value(val)
123
+ CLASS_TO_GTYPE_MAP.each do |klass, type|
124
+ return init type if val.is_a? klass
125
+ end
126
+ raise "Can't handle #{val.class}"
127
+ end
128
+
129
+ def set_none(_)
130
+ end
131
+
132
+ def get_none
133
+ end
134
+
135
+ def uninitialized?
136
+ current_gtype == TYPE_INVALID
137
+ end
138
+
133
139
  def set_instance_enhanced(val)
134
140
  check_type_compatibility val if val
135
141
  set_instance val
data/lib/ffi-gobject.rb CHANGED
@@ -47,9 +47,11 @@ module GObject
47
47
  argument_gvalues = sig_info.arguments_to_gvalues object, args
48
48
  return_gvalue = sig_info.gvalue_for_return_value
49
49
 
50
- signal_emitv argument_gvalues, signal_id, detail_quark, return_gvalue
51
-
52
- return_gvalue
50
+ result = signal_emitv argument_gvalues, signal_id, detail_quark, return_gvalue
51
+ # NOTE: Depending on the version of GObjectIntrospection, the result will
52
+ # be stored in result or return_gvalue. This was changed between versions
53
+ # 1.44 and 1.46.
54
+ result || return_gvalue
53
55
  end
54
56
 
55
57
  def self.signal_connect(object, detailed_signal, data = nil, after = false, &block)
@@ -70,7 +70,8 @@ module GObjectIntrospection
70
70
  fetcher ||= "#{single}"
71
71
  class_eval <<-CODE
72
72
  def #{method}(name)
73
- (0..(#{counter} - 1)).each do |i|
73
+ name = name.to_s
74
+ #{counter}.times do |i|
74
75
  it = #{fetcher}(i)
75
76
  return it if it.name == name
76
77
  end
@@ -37,7 +37,7 @@ module GObjectIntrospection
37
37
  build_array_method :get_methods
38
38
 
39
39
  def find_method(name)
40
- IFunctionInfo.wrap(Lib.g_interface_info_find_method @gobj, name)
40
+ IFunctionInfo.wrap(Lib.g_interface_info_find_method @gobj, name.to_s)
41
41
  end
42
42
 
43
43
  def n_signals
@@ -68,7 +68,7 @@ module GObjectIntrospection
68
68
  build_array_method :get_methods
69
69
 
70
70
  def find_method(name)
71
- IFunctionInfo.wrap(Lib.g_object_info_find_method @gobj, name)
71
+ IFunctionInfo.wrap(Lib.g_object_info_find_method @gobj, name.to_s)
72
72
  end
73
73
 
74
74
  def n_signals
@@ -92,7 +92,7 @@ module GObjectIntrospection
92
92
  end
93
93
 
94
94
  def find_vfunc(name)
95
- IVFuncInfo.wrap(Lib.g_object_info_find_vfunc @gobj, name)
95
+ IVFuncInfo.wrap(Lib.g_object_info_find_vfunc @gobj, name.to_s)
96
96
  end
97
97
  ##
98
98
  build_array_method :vfuncs
@@ -24,7 +24,7 @@ module GObjectIntrospection
24
24
 
25
25
  ##
26
26
  build_array_method :get_methods
27
- # There is a function g_object_info_find_method but it causes a core dump.
27
+ # There is a function g_struct_info_find_method but it causes a core dump.
28
28
  build_finder_method :find_method, :get_n_methods, :get_method
29
29
 
30
30
  def size
@@ -25,7 +25,7 @@ module GObjectIntrospection
25
25
  build_array_method :get_methods
26
26
 
27
27
  def find_method(name)
28
- IFunctionInfo.wrap(Lib.g_union_info_find_method @gobj, name)
28
+ IFunctionInfo.wrap(Lib.g_union_info_find_method @gobj, name.to_s)
29
29
  end
30
30
 
31
31
  def size
@@ -23,14 +23,16 @@ module GirFFI
23
23
 
24
24
  def self.copy_value_to_pointer(value, pointer, offset = 0)
25
25
  size = self::Struct.size
26
- pointer.put_bytes offset, value.to_ptr.read_bytes(size), 0, size
26
+ bytes = if value
27
+ value.to_ptr.read_bytes(size)
28
+ else
29
+ "\x00" * size
30
+ end
31
+ pointer.put_bytes offset, bytes, 0, size
27
32
  end
28
33
 
29
- # TODO: Make this behave more like a real .new method
30
- def self._allocate
31
- obj = allocate
32
- obj.instance_variable_set :@struct, self::Struct.new
33
- obj
34
+ def initialize
35
+ @struct = self.class::Struct.new
34
36
  end
35
37
  end
36
38
  end
@@ -14,16 +14,6 @@ module GirFFI
14
14
  setup_constants
15
15
  stub_methods
16
16
  setup_field_accessors
17
- provide_constructor
18
- end
19
-
20
- def provide_constructor
21
- return if info.find_method 'new'
22
-
23
- # TODO: Provide both new and initialize
24
- (class << klass; self; end).class_eval do
25
- alias_method :new, :_allocate
26
- end
27
17
  end
28
18
  end
29
19
  end
@@ -0,0 +1,13 @@
1
+ module GirFFI
2
+ module Builders
3
+ class NullClassBuilder
4
+ def setup_method(_)
5
+ nil
6
+ end
7
+
8
+ def setup_instance_method(_)
9
+ nil
10
+ end
11
+ end
12
+ end
13
+ end
@@ -200,9 +200,9 @@ module GirFFI
200
200
 
201
201
  def setup_constructor
202
202
  code = <<-CODE
203
- def self.new
204
- gptr = GObject::Lib.g_object_newv #{@gtype}, 0, nil
205
- self.wrap(gptr)
203
+ def initialize
204
+ ptr = GObject::Lib.g_object_newv #{@gtype}, 0, nil
205
+ store_pointer(ptr)
206
206
  end
207
207
  CODE
208
208
  klass.class_eval code
@@ -1,5 +1,6 @@
1
1
  require 'forwardable'
2
2
  require 'gir_ffi/registered_type_base'
3
+ require 'gir_ffi/builders/null_class_builder'
3
4
 
4
5
  module GirFFI
5
6
  # Base class for all generated classes and structs. Contains code for dealing
@@ -8,6 +9,8 @@ module GirFFI
8
9
  extend RegisteredTypeBase
9
10
  extend Forwardable
10
11
 
12
+ GIR_FFI_BUILDER = Builders::NullClassBuilder.new
13
+
11
14
  attr_reader :struct
12
15
  def_delegators :@struct, :to_ptr
13
16
 
@@ -15,7 +18,7 @@ module GirFFI
15
18
  method_name = self.class.try_in_ancestors(:setup_instance_method, method.to_s)
16
19
 
17
20
  unless method_name
18
- raise "Unable to set up instance method '#{method}' in #{self}"
21
+ raise NoMethodError, "undefined method `#{method}' for #{self}"
19
22
  end
20
23
 
21
24
  send method_name, *arguments, &block
@@ -27,11 +30,15 @@ module GirFFI
27
30
  other.class == self.class && to_ptr.address == other.to_ptr.address
28
31
  end
29
32
 
33
+ def initialize
34
+ raise NoMethodError
35
+ end
36
+
30
37
  def self.setup_and_call(method, arguments, &block)
31
38
  method_name = try_in_ancestors(:setup_method, method.to_s)
32
39
 
33
40
  unless method_name
34
- raise "Unable to set up method '#{method}' in #{self}"
41
+ raise NoMethodError, "undefined method `#{method}' for #{self}"
35
42
  end
36
43
 
37
44
  send method_name, *arguments, &block
@@ -44,6 +51,7 @@ module GirFFI
44
51
  return result if result
45
52
  end
46
53
  end
54
+ nil
47
55
  end
48
56
 
49
57
  def self.to_ffi_type
@@ -58,10 +66,6 @@ module GirFFI
58
66
  gir_ffi_builder.setup_instance_method name
59
67
  end
60
68
 
61
- class << self
62
- undef new
63
- end
64
-
65
69
  # Wrap the passed pointer in an instance of the current class, or a
66
70
  # descendant type if applicable.
67
71
  def self.wrap(ptr)
@@ -52,7 +52,7 @@ module GirFFI
52
52
  end
53
53
 
54
54
  def clear
55
- set_value nil_value
55
+ put_bytes 0, "\x00" * value_type_size, 0, value_type_size
56
56
  end
57
57
 
58
58
  def self.for(type)
@@ -72,9 +72,5 @@ module GirFFI
72
72
  def value_type_size
73
73
  @value_type_size ||= FFI.type_size value_ffi_type
74
74
  end
75
-
76
- def nil_value
77
- value_ffi_type == :pointer ? nil : 0
78
- end
79
75
  end
80
76
  end
@@ -16,6 +16,10 @@ module GirFFI
16
16
  info = find_method method
17
17
  return info if info && info.method?
18
18
  end
19
+
20
+ def find_method(method)
21
+ raise 'Must be overridden in subclass'
22
+ end
19
23
  end
20
24
  end
21
25
  end
@@ -27,6 +27,10 @@ module GirFFI
27
27
  @vfunc_implementations << VFuncImplementation.new(name, implementation)
28
28
  end
29
29
 
30
+ def find_method(_method)
31
+ nil
32
+ end
33
+
30
34
  def find_instance_method(_method)
31
35
  nil
32
36
  end
@@ -1,4 +1,4 @@
1
1
  # Current GirFFI version
2
2
  module GirFFI
3
- VERSION = '0.8.1'
3
+ VERSION = '0.8.2'
4
4
  end
@@ -38,7 +38,7 @@ describe GObject::RubyClosure do
38
38
 
39
39
  it "stores the closure's return value in the proper gvalue" do
40
40
  c = GObject::RubyClosure.new { 2 }
41
- gv = GObject::Value.new
41
+ gv = GObject::Value.new.init GObject::TYPE_INT
42
42
  GObject::RubyClosure.marshaller(c, gv, nil, nil, nil)
43
43
  assert_equal 2, gv.get_value
44
44
  end
@@ -18,6 +18,23 @@ describe GObject::Value do
18
18
  end
19
19
  end
20
20
 
21
+ describe '.for_gtype' do
22
+ it 'handles char' do
23
+ gv = GObject::Value.for_gtype GObject::TYPE_CHAR
24
+ gv.current_gtype.must_equal GObject::TYPE_CHAR
25
+ end
26
+
27
+ it 'handles invalid type' do
28
+ gv = GObject::Value.for_gtype GObject::TYPE_INVALID
29
+ gv.current_gtype.must_equal GObject::TYPE_INVALID
30
+ end
31
+
32
+ it 'handles void type' do
33
+ gv = GObject::Value.for_gtype GObject::TYPE_NONE
34
+ gv.current_gtype.must_equal GObject::TYPE_INVALID
35
+ end
36
+ end
37
+
21
38
  describe '::wrap_ruby_value' do
22
39
  it 'wraps a boolean false' do
23
40
  gv = GObject::Value.wrap_ruby_value false
@@ -40,6 +57,12 @@ describe GObject::Value do
40
57
  gv = GObject::Value.wrap_ruby_value 'Some Random String'
41
58
  assert_equal 'Some Random String', gv.get_string
42
59
  end
60
+
61
+ it 'wraps nil' do
62
+ gv = GObject::Value.wrap_ruby_value nil
63
+ assert_instance_of GObject::Value, gv
64
+ assert_equal nil, gv.get_value
65
+ end
43
66
  end
44
67
 
45
68
  describe '#set_value' do
@@ -247,6 +270,12 @@ describe GObject::Value do
247
270
  gv2.current_gtype_name.must_equal 'gint'
248
271
  gv2.get_value.must_equal 21
249
272
  end
273
+
274
+ it 'creates a null GValue from a Ruby nil' do
275
+ gv = GObject::Value.from nil
276
+ gv.current_gtype.must_equal GObject::TYPE_INVALID
277
+ gv.get_value.must_equal nil
278
+ end
250
279
  end
251
280
 
252
281
  describe '#set_value' do
@@ -0,0 +1,21 @@
1
+ require 'introspection_test_helper'
2
+
3
+ describe GObjectIntrospection::IInterfaceInfo do
4
+ let(:object_info) { get_introspection_data('GObject', 'TypePlugin') }
5
+
6
+ describe '#find_method' do
7
+ it 'finds a method by name string' do
8
+ object_info.find_method('complete_interface_info').wont_be_nil
9
+ end
10
+
11
+ it 'finds a method by name symbol' do
12
+ object_info.find_method(:complete_interface_info).wont_be_nil
13
+ end
14
+ end
15
+
16
+ describe '#type_name' do
17
+ it 'returns the correct name' do
18
+ object_info.type_name.must_equal 'GTypePlugin'
19
+ end
20
+ end
21
+ end
@@ -4,9 +4,23 @@ describe GObjectIntrospection::IObjectInfo do
4
4
  let(:object_info) { get_introspection_data('GObject', 'Object') }
5
5
 
6
6
  describe '#find_vfunc' do
7
- it 'finds a vfunc by name' do
7
+ it 'finds a vfunc by name string' do
8
8
  object_info.find_vfunc('finalize').wont_be_nil
9
9
  end
10
+
11
+ it 'finds a vfunc by name symbol' do
12
+ object_info.find_vfunc(:finalize).wont_be_nil
13
+ end
14
+ end
15
+
16
+ describe '#find_method' do
17
+ it 'finds a method by name string' do
18
+ object_info.find_method('bind_property').wont_be_nil
19
+ end
20
+
21
+ it 'finds a method by name symbol' do
22
+ object_info.find_method(:bind_property).wont_be_nil
23
+ end
10
24
  end
11
25
 
12
26
  describe '#type_name' do
@@ -0,0 +1,21 @@
1
+ require 'introspection_test_helper'
2
+
3
+ describe GObjectIntrospection::IStructInfo do
4
+ let(:object_info) { get_introspection_data('GObject', 'Closure') }
5
+
6
+ describe '#find_method' do
7
+ it 'finds a method by name string' do
8
+ object_info.find_method('new_simple').wont_be_nil
9
+ end
10
+
11
+ it 'finds a method by name symbol' do
12
+ object_info.find_method(:new_simple).wont_be_nil
13
+ end
14
+ end
15
+
16
+ describe '#type_name' do
17
+ it 'returns the correct name' do
18
+ object_info.type_name.must_equal 'GClosure'
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ require 'introspection_test_helper'
2
+
3
+ describe GObjectIntrospection::IUnionInfo do
4
+ let(:object_info) { get_introspection_data('GLib', 'Mutex') }
5
+
6
+ describe '#find_method' do
7
+ it 'finds a method by name string' do
8
+ object_info.find_method('clear').wont_be_nil
9
+ end
10
+
11
+ it 'finds a method by name symbol' do
12
+ object_info.find_method(:clear).wont_be_nil
13
+ end
14
+ end
15
+ end
@@ -92,8 +92,7 @@ describe GirFFI::ClassBase do
92
92
  'correct-result'
93
93
  end
94
94
 
95
- def self.new
96
- allocate
95
+ def initialize
97
96
  end
98
97
  end
99
98
  klass.const_set :GIR_FFI_BUILDER, builder
@@ -101,6 +100,19 @@ describe GirFFI::ClassBase do
101
100
  result = klass.setup_and_call :foo, []
102
101
  result.must_equal 'correct-result'
103
102
  end
103
+
104
+ it 'raises a sensible error if the method is not found' do
105
+ expect(builder = Object.new).to receive(:setup_method).with('foo').and_return nil
106
+ klass = Class.new GirFFI::ClassBase do
107
+ def initialize
108
+ end
109
+ end
110
+ klass.const_set :GIR_FFI_BUILDER, builder
111
+
112
+ proc { klass.setup_and_call :foo, [] }.
113
+ must_raise(NoMethodError).message.
114
+ must_match(/^undefined method `foo' for/)
115
+ end
104
116
  end
105
117
 
106
118
  describe '#setup_and_call' do
@@ -114,8 +126,7 @@ describe GirFFI::ClassBase do
114
126
  def foo
115
127
  end
116
128
 
117
- def self.new
118
- allocate
129
+ def initialize
119
130
  end
120
131
  end
121
132
  sub_klass.const_set :GIR_FFI_BUILDER, sub_builder
@@ -132,8 +143,7 @@ describe GirFFI::ClassBase do
132
143
  'correct-result'
133
144
  end
134
145
 
135
- def self.new
136
- allocate
146
+ def initialize
137
147
  end
138
148
  end
139
149
  klass.const_set :GIR_FFI_BUILDER, builder
@@ -143,5 +153,20 @@ describe GirFFI::ClassBase do
143
153
  result = obj.setup_and_call :foo, []
144
154
  result.must_equal 'correct-result'
145
155
  end
156
+
157
+ it 'raises a sensible error if the method is not found' do
158
+ expect(builder = Object.new).to receive(:setup_instance_method).with('foo').and_return nil
159
+ klass = Class.new GirFFI::ClassBase do
160
+ def initialize
161
+ end
162
+ end
163
+ klass.const_set :GIR_FFI_BUILDER, builder
164
+
165
+ obj = klass.new
166
+
167
+ proc { obj.setup_and_call :foo, [] }.
168
+ must_raise(NoMethodError).message.
169
+ must_match(/^undefined method `foo' for/)
170
+ end
146
171
  end
147
172
  end
@@ -57,11 +57,30 @@ describe GirFFI::InOutPointer do
57
57
 
58
58
  describe '.for' do
59
59
  it 'handles :gboolean' do
60
- GirFFI::InOutPointer.for :gboolean
60
+ result = GirFFI::InOutPointer.for :gboolean
61
+ result.to_value.must_equal false
61
62
  end
62
63
 
63
64
  it 'handles :utf8' do
64
- GirFFI::InOutPointer.for :utf8
65
+ result = GirFFI::InOutPointer.for :utf8
66
+ result.to_value.must_be :null?
67
+ end
68
+
69
+ it 'handles GObject::Value' do
70
+ result = GirFFI::InOutPointer.for GObject::Value
71
+ type_size = FFI.type_size GObject::Value
72
+ expected = "\x00" * type_size
73
+ result.to_value.read_bytes(type_size).must_equal expected
74
+ end
75
+ end
76
+
77
+ describe '#set_value' do
78
+ it 'works setting the value to nil for GObject::Value' do
79
+ pointer = GirFFI::InOutPointer.from GObject::Value, GObject::Value.from(3)
80
+ pointer.set_value nil
81
+ type_size = FFI.type_size GObject::Value
82
+ expected = "\x00" * type_size
83
+ pointer.to_value.read_bytes(type_size).must_equal expected
65
84
  end
66
85
  end
67
86
 
@@ -76,4 +76,13 @@ describe GirFFI::UserDefinedTypeInfo do
76
76
  info.g_name.must_equal 'bar'
77
77
  end
78
78
  end
79
+
80
+ describe '#find_method' do
81
+ let(:klass) { Object.new }
82
+ let(:info) { GirFFI::UserDefinedTypeInfo.new klass }
83
+
84
+ it 'finds no methods' do
85
+ info.find_method('foo').must_equal nil
86
+ end
87
+ end
79
88
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gir_ffi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matijs van Zuijlen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-04 00:00:00.000000000 Z
11
+ date: 2015-10-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -189,6 +189,7 @@ files:
189
189
  - lib/gir_ffi/builders/method_template.rb
190
190
  - lib/gir_ffi/builders/module_builder.rb
191
191
  - lib/gir_ffi/builders/null_argument_builder.rb
192
+ - lib/gir_ffi/builders/null_class_builder.rb
192
193
  - lib/gir_ffi/builders/null_convertor.rb
193
194
  - lib/gir_ffi/builders/null_return_value_builder.rb
194
195
  - lib/gir_ffi/builders/object_builder.rb
@@ -278,10 +279,13 @@ files:
278
279
  - test/ffi-gobject_introspection/i_constant_info_test.rb
279
280
  - test/ffi-gobject_introspection/i_enum_info_test.rb
280
281
  - test/ffi-gobject_introspection/i_function_info_test.rb
282
+ - test/ffi-gobject_introspection/i_interface_info_test.rb
281
283
  - test/ffi-gobject_introspection/i_object_info_test.rb
282
284
  - test/ffi-gobject_introspection/i_registered_type_info_test.rb
283
285
  - test/ffi-gobject_introspection/i_repository_test.rb
286
+ - test/ffi-gobject_introspection/i_struct_info_test.rb
284
287
  - test/ffi-gobject_introspection/i_type_info_test.rb
288
+ - test/ffi-gobject_introspection/i_union_info_test.rb
285
289
  - test/ffi-gobject_introspection/lib_test.rb
286
290
  - test/ffi-gobject_test.rb
287
291
  - test/gir_ffi-base/glib/boolean_test.rb