From f0dbb9e39f5a420ca6f5bb9ac992b05fccf3027e Mon Sep 17 00:00:00 2001 From: Gibheer Date: Thu, 16 Jun 2011 13:15:56 +0200 Subject: [PATCH] built a simple storage engine based on a hash and an abstract class to have an interface for the next one --- lib/polecat.rb | 1 + lib/polecat/storage/hash_storage.rb | 54 +++++++++++++++++ lib/polecat/storage/storage.rb | 69 ++++++++++++++++++++++ spec/storage/hash_storage/add_spec.rb | 23 ++++++++ spec/storage/hash_storage/delete_spec.rb | 27 +++++++++ spec/storage/hash_storage/find_spec.rb | 24 ++++++++ spec/storage/hash_storage/interval_spec.rb | 27 +++++++++ spec/storage/hash_storage/new_spec.rb | 10 ++++ spec/storage/hash_storage/select_spec.rb | 24 ++++++++ spec/storage/storage/add_spec.rb | 13 ++++ spec/storage/storage/count_spec.rb | 13 ++++ spec/storage/storage/delete_spec.rb | 13 ++++ spec/storage/storage/find_spec.rb | 13 ++++ spec/storage/storage/interval_spec.rb | 13 ++++ spec/storage/storage/new_spec.rb | 8 +++ spec/storage/storage/select_spec.rb | 13 ++++ 16 files changed, 345 insertions(+) create mode 100644 lib/polecat/storage/hash_storage.rb create mode 100644 lib/polecat/storage/storage.rb create mode 100644 spec/storage/hash_storage/add_spec.rb create mode 100644 spec/storage/hash_storage/delete_spec.rb create mode 100644 spec/storage/hash_storage/find_spec.rb create mode 100644 spec/storage/hash_storage/interval_spec.rb create mode 100644 spec/storage/hash_storage/new_spec.rb create mode 100644 spec/storage/hash_storage/select_spec.rb create mode 100644 spec/storage/storage/add_spec.rb create mode 100644 spec/storage/storage/count_spec.rb create mode 100644 spec/storage/storage/delete_spec.rb create mode 100644 spec/storage/storage/find_spec.rb create mode 100644 spec/storage/storage/interval_spec.rb create mode 100644 spec/storage/storage/new_spec.rb create mode 100644 spec/storage/storage/select_spec.rb diff --git a/lib/polecat.rb b/lib/polecat.rb index 2204385..0a35e99 100644 --- a/lib/polecat.rb +++ b/lib/polecat.rb @@ -8,4 +8,5 @@ module Polecat require 'polecat/index_searcher' require 'polecat/query' require 'polecat/term' + require 'polecat/storage/storage' end diff --git a/lib/polecat/storage/hash_storage.rb b/lib/polecat/storage/hash_storage.rb new file mode 100644 index 0000000..75be644 --- /dev/null +++ b/lib/polecat/storage/hash_storage.rb @@ -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 diff --git a/lib/polecat/storage/storage.rb b/lib/polecat/storage/storage.rb new file mode 100644 index 0000000..429e6ec --- /dev/null +++ b/lib/polecat/storage/storage.rb @@ -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 diff --git a/spec/storage/hash_storage/add_spec.rb b/spec/storage/hash_storage/add_spec.rb new file mode 100644 index 0000000..4285435 --- /dev/null +++ b/spec/storage/hash_storage/add_spec.rb @@ -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 diff --git a/spec/storage/hash_storage/delete_spec.rb b/spec/storage/hash_storage/delete_spec.rb new file mode 100644 index 0000000..0f4a90e --- /dev/null +++ b/spec/storage/hash_storage/delete_spec.rb @@ -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 diff --git a/spec/storage/hash_storage/find_spec.rb b/spec/storage/hash_storage/find_spec.rb new file mode 100644 index 0000000..a19553b --- /dev/null +++ b/spec/storage/hash_storage/find_spec.rb @@ -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 diff --git a/spec/storage/hash_storage/interval_spec.rb b/spec/storage/hash_storage/interval_spec.rb new file mode 100644 index 0000000..c4cd12c --- /dev/null +++ b/spec/storage/hash_storage/interval_spec.rb @@ -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 diff --git a/spec/storage/hash_storage/new_spec.rb b/spec/storage/hash_storage/new_spec.rb new file mode 100644 index 0000000..a0df23c --- /dev/null +++ b/spec/storage/hash_storage/new_spec.rb @@ -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 diff --git a/spec/storage/hash_storage/select_spec.rb b/spec/storage/hash_storage/select_spec.rb new file mode 100644 index 0000000..f86aba2 --- /dev/null +++ b/spec/storage/hash_storage/select_spec.rb @@ -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 diff --git a/spec/storage/storage/add_spec.rb b/spec/storage/storage/add_spec.rb new file mode 100644 index 0000000..f94aff0 --- /dev/null +++ b/spec/storage/storage/add_spec.rb @@ -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 diff --git a/spec/storage/storage/count_spec.rb b/spec/storage/storage/count_spec.rb new file mode 100644 index 0000000..bec1645 --- /dev/null +++ b/spec/storage/storage/count_spec.rb @@ -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 diff --git a/spec/storage/storage/delete_spec.rb b/spec/storage/storage/delete_spec.rb new file mode 100644 index 0000000..be9709a --- /dev/null +++ b/spec/storage/storage/delete_spec.rb @@ -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 diff --git a/spec/storage/storage/find_spec.rb b/spec/storage/storage/find_spec.rb new file mode 100644 index 0000000..8a0aa70 --- /dev/null +++ b/spec/storage/storage/find_spec.rb @@ -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 diff --git a/spec/storage/storage/interval_spec.rb b/spec/storage/storage/interval_spec.rb new file mode 100644 index 0000000..4e949e8 --- /dev/null +++ b/spec/storage/storage/interval_spec.rb @@ -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 diff --git a/spec/storage/storage/new_spec.rb b/spec/storage/storage/new_spec.rb new file mode 100644 index 0000000..f92b0e9 --- /dev/null +++ b/spec/storage/storage/new_spec.rb @@ -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 diff --git a/spec/storage/storage/select_spec.rb b/spec/storage/storage/select_spec.rb new file mode 100644 index 0000000..8f0cc48 --- /dev/null +++ b/spec/storage/storage/select_spec.rb @@ -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