Class: Arachni::Support::Database::Hash

Inherits:
Base show all
Defined in:
lib/arachni/support/database/hash.rb

Overview

Flat-file Hash implementation

Behaves pretty much like a Ruby Hash however it transparently serializes and saves its values to the file-system under the OS's temp directory.

It's not interchangeable with Ruby's Hash as it lacks a lot of the stdlib methods.

Author:

  • Tasos “Zapotek” Laskos <tasos.laskos@arachni-scanner.com>

Version:

  • 0.1

Instance Method Summary collapse

Methods inherited from Base

#serialize, #unserialize

Constructor Details

#initialize(*args) ⇒ Hash

Returns a new instance of Hash.

See Also:

  • Database::Base#initialize


27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/arachni/support/database/hash.rb', line 27

def initialize( *args )
    super( *args )

    # holds the internal representation of the Hash
    # same keys as self but the values are actually pointing to filepaths
    # where the real values are being stores
    @h = ::Hash.new

    # holds a key-value pair of self with digests as values
    # in order to allow comparisons without requiring to load
    # the actual values from their files.
    @eql_h = ::Hash.new
end

Instance Method Details

#==(h) ⇒ Bool Also known as: eql?

Note:

If the given hash is not of the same type as self it will be coerced to a Ruby Hash by calling 'to_hash' on it.

Returns `true` if self and the given hash contain the same key-pair values.

Returns:

  • (Bool)

    `true` if self and the given hash contain the same key-pair values.



272
273
274
275
276
277
278
279
280
# File 'lib/arachni/support/database/hash.rb', line 272

def ==( h )
    if !h.is_a?( self.class )
        eql = {}
        h.to_hash.each { |k, v| eql[k] = eql_hash( serialize( v ) ) }
        @eql_h == eql
    else
        @eql_h == h._eql_h
    end
end

#[](k) ⇒ Object

Returns Object corresponding to the key object, `nil` otherwise.

Parameters:

  • k (Obj)

    key

Returns:

  • (Object)

    Object corresponding to the key object, `nil` otherwise.



61
62
63
# File 'lib/arachni/support/database/hash.rb', line 61

def []( k )
    load( @h[k] ) if @h[k]
end

#[]=(k, v) ⇒ Object Also known as: store

Associates the given value with the given key.

Parameters:

Returns:



50
51
52
53
54
# File 'lib/arachni/support/database/hash.rb', line 50

def []=( k, v )
    @h[k] = dump( v ) do |serialized|
        @eql_h[k] = eql_hash( serialized )
    end
end

#_eql_hObject



295
296
297
# File 'lib/arachni/support/database/hash.rb', line 295

def _eql_h
    @eql_h.dup
end

#_internalHash

It will return a Ruby Hash with the same values as self but with filepaths as values (pointing to the files that store them).

This is used for efficient merging, i.e. without requiring to load the actual values when merging 2 objects.

Returns:

  • (Hash)

    Internal representation of `self`.



291
292
293
# File 'lib/arachni/support/database/hash.rb', line 291

def _internal
    @h.dup
end

#assoc(k) ⇒ Array

Returns Array containing the given key and its value.

Parameters:

Returns:

  • (Array)

    Array containing the given key and its value.



70
71
72
73
# File 'lib/arachni/support/database/hash.rb', line 70

def assoc( k )
    return if !@h[k]
    [ k, self[k] ]
end

#clearObject

Removes all objects.



262
263
264
265
# File 'lib/arachni/support/database/hash.rb', line 262

def clear
    @h.values.each { |filepath| delete_file( filepath ) }
    @h.clear
end

#delete(k, &block) ⇒ Object

Removes an entry by key and returns its value.

If the key doesn't exist and a block has been provided it's passed the key and the method returns the result of that block.

Parameters:

Returns:



94
95
96
97
98
99
100
101
102
103
# File 'lib/arachni/support/database/hash.rb', line 94

def delete( k, &block )
    if @h[k]
        obj = load_and_delete_file( @h[k] )
        @h.delete( k )
        @eql_h.delete( k )
        return obj
    else
        block.call( k ) if block_given?
    end
end

#each(&block) ⇒ Object Also known as: each_pair

Calls block with each key-value pair.

If a block has been given it retuns self. If no block has been given it returns an enumerator.

Parameters:

  • block (Proc)


119
120
121
122
123
124
125
126
# File 'lib/arachni/support/database/hash.rb', line 119

def each( &block )
    if block_given?
        @h.each { |k, v| block.call( [ k, self[k] ] ) }
        self
    else
        enum_for( :each )
    end
end

#each_key(&block) ⇒ Object

Calls block with each key.

If a block has been given it returns self. If no block has been given it returns an enumerator.

Parameters:

  • block (Proc)


135
136
137
138
139
140
141
142
# File 'lib/arachni/support/database/hash.rb', line 135

def each_key( &block )
    if block_given?
        @h.each_key( &block )
        self
    else
        enum_for( :each_key )
    end
end

#each_value(&block) ⇒ Object

Calls block with each value.

If a block has been given it returns `self`. If no block has been given it returns an enumerator.

Parameters:

  • block (Proc)


150
151
152
153
154
155
156
157
# File 'lib/arachni/support/database/hash.rb', line 150

def each_value( &block )
    if block_given?
        @h.keys.each { |k| block.call( self[k] ) }
        self
    else
        enum_for( :each_value )
    end
end

#empty?Bool

Returns `true` if the Hash if empty, `false` otherwise.

Returns:

  • (Bool)

    `true` if the Hash if empty, `false` otherwise.



257
258
259
# File 'lib/arachni/support/database/hash.rb', line 257

def empty?
    @h.empty?
end

#include?(k) ⇒ Bool Also known as: member?, key?, has_key?

Returns `true` if the given key exists in the hash, `false` otherwise.

Returns:

  • (Bool)

    `true` if the given key exists in the hash, `false` otherwise.



183
184
185
# File 'lib/arachni/support/database/hash.rb', line 183

def include?( k )
    @h.include?( k )
end

#key(val) ⇒ Object

Returns key key for the given value.

Parameters:

Returns:

  • (Object)

    key key for the given value.



169
170
171
172
173
# File 'lib/arachni/support/database/hash.rb', line 169

def key( val )
    return if !value?( val )
    each { |k, v| return k if val == self[k] }
    nil
end

#keysArray

Returns Keys.

Returns:



161
162
163
# File 'lib/arachni/support/database/hash.rb', line 161

def keys
    @h.keys
end

#merge(h) ⇒ Arachni::Database::Hash

Merges the contents of self with the contents of the given hash and returns them in a new object.

Parameters:

Returns:

  • (Arachni::Database::Hash)


203
204
205
# File 'lib/arachni/support/database/hash.rb', line 203

def merge( h )
    self.class.new( serializer ).merge!( self ).merge!( h )
end

#merge!(h) ⇒ Object Also known as: update

Merges self with the contents of the given hash and returns self.

If the given Hash is of the same type as self then the values will not be loaded during the merge in order to keep memory usage down.

If the given Hash is any other kind of object it will be coerced to a Hash by calling 'to_hash' on it and the merging it with self.

Parameters:



216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/arachni/support/database/hash.rb', line 216

def merge!( h )
    if !h.is_a?( self.class )
        h.to_hash.each do |k, v|
            delete( k ) if @h.include?( k )
            self[k] = v
        end
    else
        h._internal.each do |k, v|
            delete( k ) if @h.include?( k )
            @h[k] = v
        end
        @eql_h.merge!( h._eql_h )
    end
    self
end

#rassoc(v) ⇒ Array

Returns Array containing the key for the given value and that value.

Parameters:

Returns:

  • (Array)

    Array containing the key for the given value and that value.



80
81
82
83
# File 'lib/arachni/support/database/hash.rb', line 80

def rassoc( v )
    return if !value?( v )
    [ key( v ), v ]
end

#shiftArray

Removes the first key-value pair from the hash and returns it as a array,

Returns:



108
109
110
111
# File 'lib/arachni/support/database/hash.rb', line 108

def shift
    k, v = @h.first
    [ k, delete( k ) ]
end

#sizeInteger Also known as: length

Returns Number of objects.

Returns:

  • (Integer)

    Number of objects.



250
251
252
# File 'lib/arachni/support/database/hash.rb', line 250

def size
    @h.size
end

#to_aArray

Returns `self` as a Ruby Array.

Returns:

  • (Array)

    `self` as a Ruby Array.



244
245
246
# File 'lib/arachni/support/database/hash.rb', line 244

def to_a
    to_hash.to_a
end

#to_hashHash Also known as: to_h

Returns `self` as Ruby Hash.

Returns:

  • (Hash)

    `self` as Ruby Hash



235
236
237
238
239
# File 'lib/arachni/support/database/hash.rb', line 235

def to_hash
    h = {}
    each { |k, v| h[k] = v }
    h
end

#value?(v) ⇒ Bool

Returns `true` if the given value exists in the hash, `false` otherwise.

Returns:

  • (Bool)

    `true` if the given value exists in the hash, `false` otherwise.



192
193
194
195
# File 'lib/arachni/support/database/hash.rb', line 192

def value?( v )
    each_value { |val| return true if val == v }
    false
end

#valuesArray

Returns Values.

Returns:



177
178
179
# File 'lib/arachni/support/database/hash.rb', line 177

def values
    each_value.to_a
end