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:

Version:

  • 0.1

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Hash

Returns a new instance of Hash.

See Also:

  • Database::Base#initialize


41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/arachni/support/database/hash.rb', line 41

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) ⇒ Object Also known as: eql?

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

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.



352
353
354
355
356
357
358
359
360
361
362
363
# File 'lib/arachni/support/database/hash.rb', line 352

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

Retrieves the value object corresponding to the key object, nil otherwise.

Parameters:

  • k (Obj)

    key

Returns:



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

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:



63
64
65
66
67
68
# File 'lib/arachni/support/database/hash.rb', line 63

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

#_eql_hObject



381
382
383
# File 'lib/arachni/support/database/hash.rb', line 381

def _eql_h
    @eql_h.dup
end

#_internalHash

Returns the internal representation of self.

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:



377
378
379
# File 'lib/arachni/support/database/hash.rb', line 377

def _internal
    @h.dup
end

#assoc(k) ⇒ Array

Returns an array containing the given key and its value.

Parameters:

Returns:



90
91
92
93
# File 'lib/arachni/support/database/hash.rb', line 90

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

#clearObject

Removes all objects from the Queue.



340
341
342
343
# File 'lib/arachni/support/database/hash.rb', line 340

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:



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

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.<br/> If no block has been given it returns an enumerator.

Parameters:

  • block (Proc)


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

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.<br/> If no block has been given it returns an enumerator.

Parameters:

  • block (Proc)


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

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 retuns self.<br/> If no block has been given it returns an enumerator.

Parameters:

  • block (Proc)


184
185
186
187
188
189
190
191
192
193
194
# File 'lib/arachni/support/database/hash.rb', line 184

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

True if the Queue if empty, false otherwise.

Returns:

  • (Bool)


333
334
335
# File 'lib/arachni/support/database/hash.rb', line 333

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)


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

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

#key(val) ⇒ Object

Returns the key for the given value.

Parameters:

Returns:



212
213
214
215
216
217
218
219
# File 'lib/arachni/support/database/hash.rb', line 212

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

#keysArray

Returns all keys as an array.

Returns:



201
202
203
# File 'lib/arachni/support/database/hash.rb', line 201

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)


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

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:



278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/arachni/support/database/hash.rb', line 278

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

#rassoc(v) ⇒ Array

Returns an array containing the key for the given value and that value.

Parameters:

Returns:



102
103
104
105
# File 'lib/arachni/support/database/hash.rb', line 102

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:



133
134
135
136
# File 'lib/arachni/support/database/hash.rb', line 133

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

#sizeInteger Also known as: length

Size of the Queue, the number of objects it currently holds.

Returns:

  • (Integer)


323
324
325
# File 'lib/arachni/support/database/hash.rb', line 323

def size
    @h.size
end

#to_aArray

Converts self to a Ruby Array

Returns:



314
315
316
# File 'lib/arachni/support/database/hash.rb', line 314

def to_a
    to_hash.to_a
end

#to_hashHash Also known as: to_h

Converts self to a Ruby Hash

Returns:



302
303
304
305
306
# File 'lib/arachni/support/database/hash.rb', line 302

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

#value?(v) ⇒ Bool

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

Returns:

  • (Bool)


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

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

#valuesArray

Returns all values as an array.

Returns:



226
227
228
# File 'lib/arachni/support/database/hash.rb', line 226

def values
    each_value.to_a
end