summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJérémy Zurcher <jeremy@asynk.ch>2011-04-28 15:16:11 +0200
committerJérémy Zurcher <jeremy@asynk.ch>2011-04-28 15:16:11 +0200
commita057edb6142441a9341dee805ef66288cf402423 (patch)
tree77474f1066c58c7c02a0b609decddc4d625de15d
parentdb43d493bb7a9179d5c109cf315c9c0db132c6ec (diff)
downloadffi-efl-a057edb6142441a9341dee805ef66288cf402423.zip
ffi-efl-a057edb6142441a9341dee805ef66288cf402423.tar.gz
add eina_hash + specs
-rw-r--r--lib/efl/eina/eina_hash.rb81
-rw-r--r--spec/eina/eina_hash_spec.rb186
2 files changed, 267 insertions, 0 deletions
diff --git a/lib/efl/eina/eina_hash.rb b/lib/efl/eina/eina_hash.rb
new file mode 100644
index 0000000..76cd5d2
--- /dev/null
+++ b/lib/efl/eina/eina_hash.rb
@@ -0,0 +1,81 @@
+#! /usr/bin/env ruby
+# -*- coding: UTF-8 -*-
+#
+require 'efl/eina'
+require 'efl/ffi/eina/eina_hash'
+#
+class Hash
+ def self.from_eina_hash o
+ if o.is_a? Efl::Eina::EinaHash
+ o.to_h
+ elsif o.is_a? ::FFI::Pointer
+ Efl::Eina::EinaHash.new(o).to_h
+ else
+ raise ArgumentError.new " wrong argument #{o.class.name}"
+ end
+ end
+end
+module Efl
+ module Eina
+ #
+ class EinaHash
+ include Efl::Helper
+ include Enumerable
+ @func_prefixes = [ 'eina_hash_' ].freeze
+ def initialize o=nil, &block
+ cstr = ( block_given? ? block : Proc.new { Efl::FFI.eina_hash_string_djb2_new ::FFI::Pointer::NULL } )
+ @ptr = (
+ case o
+ when ::FFI::Pointer
+ ( o==::FFI::Pointer::NULL ? cstr.call : o )
+ when NilClass
+ cstr.call
+ when self.class
+ o.ptr
+ when Hash
+ ptr = cstr.call
+ o.each do |k,v| Efl::FFI.eina_hash_add ptr, k, v end
+ ptr
+ else
+ raise ArgumentError.new "#{ptr.class} valid argument"
+ end
+ )
+ end
+ def free
+ return if @ptr==::FFI::Pointer::NULL
+ @ptr = Efl::FFI.eina_hash_free @ptr
+ end
+ def each data=::FFI::Pointer::NULL, &block
+ return if not block_given?
+ Efl::FFI::eina_hash_foreach @ptr, Proc.new{|h,k,v,d| block.call(k,v) }, data
+ end
+ def to_h
+ rh = {}
+ each { |k,v| rh[k]=v; true }
+ rh
+ end
+ def to_h_conv &block
+ rh = {}
+ if block_given?
+ each { |k,v| rh[block.call(k)]=v; true }
+ else
+ each { |k,v| rh[k.read_string]=v; true }
+ end
+ rh
+ end
+ # for fun and tests
+ def add k, v
+ Efl::FFI.eina_hash_add @ptr, k, v
+ v
+ end
+ alias :[]= :add
+ def find k
+ r = Efl::FFI.eina_hash_find @ptr, k
+ return ( r==::FFI::Pointer::NULL ? nil : r )
+ end
+ alias :[] :find
+ end
+ end
+end
+#
+# EOF
diff --git a/spec/eina/eina_hash_spec.rb b/spec/eina/eina_hash_spec.rb
new file mode 100644
index 0000000..3cd5504
--- /dev/null
+++ b/spec/eina/eina_hash_spec.rb
@@ -0,0 +1,186 @@
+#! /usr/bin/env ruby
+# -*- coding: UTF-8 -*-
+#
+require 'efl/eina/eina_hash'
+#
+describe Efl::Eina::EinaHash do
+ #
+ before(:all) {
+ EinaHash = Efl::Eina::EinaHash
+ Efl::Eina.init.should eql 1
+ @d0 = ::FFI::MemoryPointer.from_string "D0"
+ @d1 = ::FFI::MemoryPointer.from_string "D1"
+ @d2 = ::FFI::MemoryPointer.from_string "D2"
+ @d3 = ::FFI::MemoryPointer.from_string "D3"
+ }
+ after(:all) {
+ Efl::Eina.shutdown.should eql 0
+ }
+ #
+ it "should append prepend and fetch" do
+ h = EinaHash.new
+ h.add 'k2', @d2
+ h.add 'k1', @d1
+ h['k3']=@d3
+ h['k0']=@d0
+ h['k0'].read_string.should eql "D0"
+ h['k1'].read_string.should eql "D1"
+ h['k2'].read_string.should eql "D2"
+ h['k3'].read_string.should eql "D3"
+ cpt=0
+ h.each { |k,v|
+ cpt+=1
+ v.read_string.empty?.should be_false
+ }
+ cpt.should eql 4
+ h.free
+ end
+ #
+ it "should be able to convert into ruby Hash from NULL pointer" do
+ h = Hash.from_eina_hash ::FFI::Pointer::NULL
+ h.empty?.should be_true
+ h.is_a?(Hash).should be_true
+ end
+ #
+ it "should be able to convert into ruby Hash from empty EinaHash" do
+ h = Hash.from_eina_hash EinaHash.new
+ h.empty?.should be_true
+ h.is_a?(Hash).should be_true
+ end
+ #
+ it "should be able to convert into ruby Hash from empty EinaHash pointer" do
+ h = Hash.from_eina_hash EinaHash.new.ptr
+ h.empty?.should be_true
+ h.is_a?(Hash).should be_true
+ end
+ #
+ it "should be able to convert into ruby Hash from non empty EinaHash" do
+ h = EinaHash.new
+ d0 = ::FFI::MemoryPointer.from_string "D0"
+ d1 = ::FFI::MemoryPointer.from_string "D1"
+ d2 = ::FFI::MemoryPointer.from_string "D2"
+ d3 = ::FFI::MemoryPointer.from_string "D3"
+ h.add 'k2', d2
+ h.add 'k1', d1
+ h['k3']=d3
+ h["k0"]=d0
+ h["k0"].read_string.should eql "D0"
+ h['k1'].read_string.should eql "D1"
+ h['k2'].read_string.should eql "D2"
+ h['k3'].read_string.should eql "D3"
+ cpt=0
+ h.each { |k,v|
+ cpt+=1
+ v.read_string.empty?.should be_false
+ true
+ }
+ cpt.should eql 4
+ rh = Hash.from_eina_hash h
+ rh.length.should eql 4
+ rh2 = {}
+ rh.each { |k,v|
+ rh2[k.read_string]=v.read_string
+ true
+ }
+ rh2['k0'].should eql 'D0'
+ rh2['k1'].should eql 'D1'
+ rh2['k2'].should eql 'D2'
+ rh2['k3'].should eql 'D3'
+ h.free
+ end
+ #
+ it "should be able to convert into ruby Hash from non empty EinaHash pointer" do
+ h = EinaHash.new
+ d0 = ::FFI::MemoryPointer.from_string "D0"
+ d1 = ::FFI::MemoryPointer.from_string "D1"
+ d2 = ::FFI::MemoryPointer.from_string "D2"
+ d3 = ::FFI::MemoryPointer.from_string "D3"
+ h.add 'k2', d2
+ h.add 'k1', d1
+ h['k3']=d3
+ h['k0']=d0
+ h['k0'].read_string.should eql "D0"
+ h['k1'].read_string.should eql "D1"
+ h['k2'].read_string.should eql "D2"
+ h['k3'].read_string.should eql "D3"
+ rh = Hash.from_eina_hash h.ptr
+ rh.length.should eql 4
+ h.free
+ end
+ #
+ it "should be able to convert into ruby Hash from non empty EinaHash pointer, with key from string" do
+ h = EinaHash.new
+ d0 = ::FFI::MemoryPointer.from_string "D0"
+ d1 = ::FFI::MemoryPointer.from_string "D1"
+ d2 = ::FFI::MemoryPointer.from_string "D2"
+ d3 = ::FFI::MemoryPointer.from_string "D3"
+ h.add 'k2', d2
+ h.add 'k1', d1
+ h['k3']=d3
+ h['k0']=d0
+ h['k0'].read_string.should eql "D0"
+ h['k1'].read_string.should eql "D1"
+ h['k2'].read_string.should eql "D2"
+ h['k3'].read_string.should eql "D3"
+ rh = h.to_h_conv
+ rh.length.should eql 4
+ rh['k0'].read_string.should eql "D0"
+ rh['k1'].read_string.should eql "D1"
+ rh['k2'].read_string.should eql "D2"
+ rh['k3'].read_string.should eql "D3"
+ h.free
+ end
+ #
+ it "should be able to convert into ruby Hash from non empty EinaHash pointer, with key from string block" do
+ h = EinaHash.new
+ d0 = ::FFI::MemoryPointer.from_string "D0"
+ d1 = ::FFI::MemoryPointer.from_string "D1"
+ d2 = ::FFI::MemoryPointer.from_string "D2"
+ d3 = ::FFI::MemoryPointer.from_string "D3"
+ h.add 'k2', d2
+ h.add 'k1', d1
+ h['k3']=d3
+ h['k0']=d0
+ h['k0'].read_string.should eql "D0"
+ h['k1'].read_string.should eql "D1"
+ h['k2'].read_string.should eql "D2"
+ h['k3'].read_string.should eql "D3"
+ cpt=0
+ rh = h.to_h_conv { |k| cpt+=1; k.read_string }
+ cpt.should eql 4
+ rh.length.should eql 4
+ rh['k0'].read_string.should eql "D0"
+ rh['k1'].read_string.should eql "D1"
+ rh['k2'].read_string.should eql "D2"
+ rh['k3'].read_string.should eql "D3"
+ h.free
+ end
+ #
+ it "should be able to build from ruby Hash" do
+ rh = {}
+ k0 = ::FFI::MemoryPointer.from_string "0"
+ k1 = ::FFI::MemoryPointer.from_string "1"
+ k2 = ::FFI::MemoryPointer.from_string "2"
+ k3 = ::FFI::MemoryPointer.from_string "3"
+ d0 = ::FFI::MemoryPointer.from_string "D0"
+ d1 = ::FFI::MemoryPointer.from_string "D1"
+ d2 = ::FFI::MemoryPointer.from_string "D2"
+ d3 = ::FFI::MemoryPointer.from_string "D3"
+ rh[k0]=d0
+ rh[k1]=d1
+ rh[k2]=d2
+ rh[k3]=d3
+ h = EinaHash.new rh
+ h[k0].read_string.should eql "D0"
+ h[k1].read_string.should eql "D1"
+ h[k2].read_string.should eql "D2"
+ h[k3].read_string.should eql "D3"
+ h.free
+ end
+ #
+ it "alternate constructor should work" do
+ cstr_cnt = 0
+ h = EinaHash.new { cstr_cnt+=1; Efl::FFI.eina_hash_string_superfast_new ::FFI::Pointer::NULL }
+ cstr_cnt.should eql 1
+ end
+end