Class: Arachni::Database::Hash

Inherits:
Base show all
Defined in:
lib/arachni/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

<[email protected]>
<[email protected]>

@version: 0.1

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Hash

Returns a new instance of Hash.

See Also:



35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/arachni/database/hash.rb', line 35

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.



343
344
345
346
347
348
349
350
351
352
353
354
# File 'lib/arachni/database/hash.rb', line 343

def ==( h )
    if !h.is_a?( self.class )
        eql = {}
        h.to_hash.each {
            |k, v|
            eql[k] = eql_hash( v.to_yaml )
        }
        @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:



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

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:



55
56
57
58
59
60
# File 'lib/arachni/database/hash.rb', line 55

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

#_eql_hObject



372
373
374
# File 'lib/arachni/database/hash.rb', line 372

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:



368
369
370
# File 'lib/arachni/database/hash.rb', line 368

def _internal
    @h.dup
end

#assoc(k) ⇒ Array

Returns an array containing the given key and its value.

Parameters:

Returns:



82
83
84
85
# File 'lib/arachni/database/hash.rb', line 82

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

#clearObject

Removes all objects from the Queue.



331
332
333
334
# File 'lib/arachni/database/hash.rb', line 331

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:



109
110
111
112
113
114
115
116
117
118
# File 'lib/arachni/database/hash.rb', line 109

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)


138
139
140
141
142
143
144
145
146
147
148
# File 'lib/arachni/database/hash.rb', line 138

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)


159
160
161
162
163
164
165
166
# File 'lib/arachni/database/hash.rb', line 159

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)


176
177
178
179
180
181
182
183
184
185
186
# File 'lib/arachni/database/hash.rb', line 176

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)


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

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)


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

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

#key(val) ⇒ Object

Returns the key for the given value.

Parameters:

Returns:



204
205
206
207
208
209
210
# File 'lib/arachni/database/hash.rb', line 204

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

#keysArray

Returns all keys as an array.

Returns:



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

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:



254
255
256
# File 'lib/arachni/database/hash.rb', line 254

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:



269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# File 'lib/arachni/database/hash.rb', line 269

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:



94
95
96
97
# File 'lib/arachni/database/hash.rb', line 94

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:



125
126
127
128
# File 'lib/arachni/database/hash.rb', line 125

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

#sizeInteger Also known as: length

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

Returns:

  • (Integer)


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

def size
    @h.size
end

#to_aArray

Converts self to a Ruby Array

Returns:



305
306
307
# File 'lib/arachni/database/hash.rb', line 305

def to_a
    to_hash.to_a
end

#to_hashHash Also known as: to_h

Converts self to a Ruby Hash

Returns:



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

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)


238
239
240
241
242
243
244
# File 'lib/arachni/database/hash.rb', line 238

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

#valuesArray

Returns all values as an array.

Returns:



217
218
219
# File 'lib/arachni/database/hash.rb', line 217

def values
    each_value.to_a
end