0
0
Fork 0

built a simple storage engine based on a hash and an abstract class to

have an interface for the next one
This commit is contained in:
Gibheer 2011-06-16 13:15:56 +02:00
parent febf0a7a2e
commit f0dbb9e39f
16 changed files with 345 additions and 0 deletions

View File

@ -8,4 +8,5 @@ module Polecat
require 'polecat/index_searcher'
require 'polecat/query'
require 'polecat/term'
require 'polecat/storage/storage'
end

View File

@ -0,0 +1,54 @@
module Polecat
module Storage
# This class is a storage engine based on a simple hash.
class HashStorage < Storage
def initialize
@storage = {}
end
def add key, value
check_key key
@storage[key] = value
end
def delete key
check_key key
@storage.delete key
end
def interval lower, upper
check_key lower
check_key upper
select do |key|
lower <= key && key <= upper
end
end
def find key
check_key key
if @storage.has_key? key
@storage[key]
else
nil
end
end
def select &block
out = []
@storage.keys.each do |key|
out << @storage[key] if block.call(key)
end
out
end
def count
@storage.count
end
def check_key key
raise ArgumentError, 'key does not support #<=>' unless key.respond_to?(:<=>)
end
private :check_key
end
end
end

View File

@ -0,0 +1,69 @@
module Polecat
module Storage
# This class is a schema for building storage engines which then can be used
# in the index.
class Storage
# creates a new storage
def initialize
end
# add a new value with the key
#
# Add a new key with a value attached to this key. The key has to
# have an implementation of the method #<=> as it is used for comparing
# all values.
# @param [#<=>] key a key for searching
# @param [Object] value the coresponding value
def add key, value
raise NotImplementedError
end
# delete the element with this key
#
# This deletes the given key. The class of key must have an implementation
# of #<=>.
# @param [#<=>] key the key for values to be deleted
def delete key
raise NotImplementedError
end
# counts the number of elements
def count
raise NotImplementedError
end
# returns the value for this key or nil
#
# Finds the key and returns the first value or nil. The key must have an
# implementation of #<=>.
# @param [#<=>] key the key to look for
# @return [Object] the value of the key
def find key
raise NotImplementedError
end
# return all values where the block is true
#
# This methods evaluates the block and stores all values in an array when
# the block evaluates to true for the given key.
# A list with all values is returnd.
# @yield [key] the block which gets yield with the key
# @return [Array] all found values
def select &block
raise NotImplementedError
end
# search in an interval
#
# Search for values where the key is between the lower and the upper
# limit. Both lower and upper must implement the method #<=>.
# All values are returned as a list.
# @param [#<=>] lower the lower limit
# @param [#<=>] upper the upper limit
# @return [Array] a list of all found values
def interval lower, upper
raise NotImplementedError
end
end
end
end

View File

@ -0,0 +1,23 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require 'polecat/storage/hash_storage'
describe "HashStorage#add" do
let (:s) { Polecat::Storage::HashStorage.new }
it "raises the element count" do
s.add('foo', 'bar')
s.count.should == 1
end
it "raises the element count with every add" do
s.add('foo', 1)
s.add('bar', 2)
s.add('baz', 3)
s.count.should == 3
end
it "raises an error when the attribute does not support #<=>" do
s.add('foo', 'bar')
lambda { s.add(:foo, 'baz') }.should raise_error(ArgumentError)
end
end

View File

@ -0,0 +1,27 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
describe "HashStorage#delete" do
let (:s) { Polecat::Storage::HashStorage.new }
before do
s.add 'foo', 'bar'
s.add 'bar', 'baz'
s.add 'baz', 'foo'
end
it "decrements the element count" do
s.delete('foo')
s.count.should == 2
end
it "returns the value of the deleted key" do
s.delete('foo').should == 'bar'
end
it "returns nil when the element was not found" do
s.delete('foobar').should be(nil)
end
it "raises an error when the argument does not support #<=>" do
lambda { s.delete(:foo) }.should raise_error(ArgumentError)
end
end

View File

@ -0,0 +1,24 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require 'polecat/storage/hash_storage'
describe "HashStorage#find" do
let (:s) { Polecat::Storage::HashStorage.new }
before do
s.add 'foo', 'bar'
s.add 'bar', 'baz'
s.add 'baz', 'foobar'
s.add 'zum', 'zum'
end
it "returns nil when the element was not found" do
s.find('baba').should be(nil)
end
it "returns the value of the key" do
s.find('foo').should == 'bar'
end
it "raises an error when the type does not know #<=>" do
lambda { s.find(:foo) }.should raise_error(ArgumentError)
end
end

View File

@ -0,0 +1,27 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
describe "HashStorage#interval" do
let (:s) { Polecat::Storage::HashStorage.new }
before do
s.add 'foo', 'bar'
s.add 'bar', 'baz'
s.add 'baz', 'foobar'
s.add 'zum', 'zum'
end
it "returns an empty array when no element was found" do
s.interval('a', 'b').should == []
end
it "returns an array of found elements" do
s.interval('ba', 'bb').sort.should == ['baz', 'foobar']
end
it "includes the search values" do
s.interval('bar', 'baz').sort.should == ['baz', 'foobar']
end
it "raises an error when one of the arguments type does not match" do
lambda { s.interval(1, 2) }.should raise_error(ArgumentError)
end
end

View File

@ -0,0 +1,10 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require 'polecat/storage/hash_storage'
describe "HashStorage#new" do
it "creates a new storage object" do
s = Polecat::Storage::HashStorage.new
s.kind_of?(Polecat::Storage::Storage).should == true
s.class.should be(Polecat::Storage::HashStorage)
end
end

View File

@ -0,0 +1,24 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
describe "HashStorage#select" do
let (:s) { Polecat::Storage::HashStorage.new }
before do
s.add 'key', 'value'
s.add 'foo', 'bar'
s.add 'bar', 'baz'
s.add 'baz', 'foobar'
end
it "returns an empty array, when no element was selected" do
(s.select {|element| false }).should == []
end
it "takes a block as an argument" do
(s.select {|element| element.match /ba*/ }).sort.should == ['baz', 'foobar']
end
it "does not handle errors" do
lambda { s.select {|element| raise ArgumentError }}.should(
raise_error(ArgumentError))
end
end

View File

@ -0,0 +1,13 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
describe "Storage#add" do
let (:s) { Polecat::Storage::Storage.new }
it "takes two parameters" do
s.method(:add).arity.should == 2
end
it "raises an error because it is not implemented" do
lambda { s.add 1, 2 }.should raise_error(NotImplementedError)
end
end

View File

@ -0,0 +1,13 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
describe "Storage#count" do
let (:s) { Polecat::Storage::Storage.new }
it "takes no argument" do
s.method(:count).arity.should == 0
end
it "raises an error as it is not implemented" do
lambda { s.count }.should raise_error(NotImplementedError)
end
end

View File

@ -0,0 +1,13 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
describe "Storage#delete" do
let (:s) { Polecat::Storage::Storage.new }
it "takes one argument" do
s.method(:delete).arity.should == 1
end
it "raises an error as it is not implemented" do
lambda { s.delete 1 }.should raise_error(NotImplementedError)
end
end

View File

@ -0,0 +1,13 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
describe "Storage#find" do
let (:s) { Polecat::Storage::Storage.new }
it "takes one argument" do
s.method(:find).arity.should == 1
end
it "raises an error as this method is not implemented" do
lambda { s.find(23) }.should raise_error(NotImplementedError)
end
end

View File

@ -0,0 +1,13 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
describe "Storage#interval" do
let (:s) { Polecat::Storage::Storage.new }
it "takes two arguments" do
s.method(:interval).arity.should == 2
end
it "raises an error when one of the arguments type does not match" do
lambda { s.interval(1, 2) }.should raise_error(NotImplementedError)
end
end

View File

@ -0,0 +1,8 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
describe "Storage#new" do
it "creates a new storage object" do
s = Polecat::Storage::Storage.new
s.class.should be(Polecat::Storage::Storage)
end
end

View File

@ -0,0 +1,13 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
describe "Storage#select" do
let (:s) { Polecat::Storage::Storage.new }
it "takes a block as an argument" do
s.method(:select).arity.should == 0
end
it "raises an error as it is not implemented" do
lambda { s.select }.should raise_error(NotImplementedError)
end
end