class Arachni::Support::Database::Hash
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
Public Class Methods
@see Arachni::Database::Base#initialize
Arachni::Support::Database::Base::new
# 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
Public Instance Methods
@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.
@return [Bool]
`true` if self and the given hash contain the same key-pair values.
# 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
@param [Obj] k key
@return [Object]
Object corresponding to the key object, `nil` otherwise.
# File lib/arachni/support/database/hash.rb, line 61 def []( k ) load( @h[k] ) if @h[k] end
Associates the given value with the given key.
@param [Object] k
Key.
@param [Object] v
Value.
@return [Object]
`v`.
# 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
# File lib/arachni/support/database/hash.rb, line 295 def _eql_h @eql_h.dup end
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.
@return [Hash]
Internal representation of `self`.
# File lib/arachni/support/database/hash.rb, line 291 def _internal @h.dup end
@param [Object] k
Key.
@return [Array]
Array containing the given key and its value.
# File lib/arachni/support/database/hash.rb, line 70 def assoc( k ) return if !@h[k] [ k, self[k] ] end
Removes all objects.
# File lib/arachni/support/database/hash.rb, line 262 def clear @h.values.each { |filepath| delete_file( filepath ) } @h.clear end
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.
@param [Object] k
Key.
@return [Object]
# 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
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.
@param [Proc] block
# 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
Calls block with each key.
If a block has been given it returns self. If no block has been given it returns an enumerator.
@param [Proc] block
# 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
Calls block with each value.
If a block has been given it returns ‘self`. If no block has been given it returns an enumerator.
@param [Proc] block
# 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
@return [Bool]
`true` if the Hash if empty, `false` otherwise.
# File lib/arachni/support/database/hash.rb, line 257 def empty? @h.empty? end
@return [Bool]
`true` if the given key exists in the hash, `false` otherwise.
# File lib/arachni/support/database/hash.rb, line 183 def include?( k ) @h.include?( k ) end
@param [Object] val
@return [Object] key
key for the given value.
# 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
@return [Array]
Keys.
# File lib/arachni/support/database/hash.rb, line 161 def keys @h.keys end
Merges the contents of self with the contents of the given hash and returns them in a new object.
@param [Hash] h
@return [Arachni::Database::Hash]
# File lib/arachni/support/database/hash.rb, line 203 def merge( h ) self.class.new( serializer ).merge!( self ).merge!( h ) end
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.
@param [Hash] h
# 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
@param [Object] v
Value.
@return [Array]
Array containing the key for the given value and that value.
# File lib/arachni/support/database/hash.rb, line 80 def rassoc( v ) return if !value?( v ) [ key( v ), v ] end
Removes the first key-value pair from the hash and returns it as a array,
@return [Array]
# File lib/arachni/support/database/hash.rb, line 108 def shift k, v = @h.first [ k, delete( k ) ] end
@return [Integer]
Number of objects.
# File lib/arachni/support/database/hash.rb, line 250 def size @h.size end
@return [Array]
`self` as a Ruby Array.
# File lib/arachni/support/database/hash.rb, line 244 def to_a to_hash.to_a end
@return [Hash]
`self` as Ruby Hash
# File lib/arachni/support/database/hash.rb, line 235 def to_hash h = {} each { |k, v| h[k] = v } h end
@return [Bool]
`true` if the given value exists in the hash, `false` otherwise.
# File lib/arachni/support/database/hash.rb, line 192 def value?( v ) each_value { |val| return true if val == v } false end
@return [Array]
Values.
# File lib/arachni/support/database/hash.rb, line 177 def values each_value.to_a end
Private Instance Methods
# File lib/arachni/support/database/hash.rb, line 301 def eql_hash( str ) Digest::SHA1.hexdigest( str ) end