gir_ffi 0.8.1 → 0.8.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 (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