diff options
| -rw-r--r-- | lib/efl/eina/eina_hash.rb | 81 | ||||
| -rw-r--r-- | spec/eina/eina_hash_spec.rb | 186 | 
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 | 
