stash 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/LICENSE +20 -0
- data/README.markdown +92 -0
- data/Rakefile +46 -0
- data/VERSION +1 -0
- data/lib/stash/class_methods.rb +47 -0
- data/lib/stash/hash.rb +61 -0
- data/lib/stash/list.rb +90 -0
- data/lib/stash/redis_adapter.rb +132 -0
- data/lib/stash/string.rb +16 -0
- data/lib/stash.rb +43 -0
- data/spec/hash_spec.rb +29 -0
- data/spec/list_spec.rb +65 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/string_spec.rb +9 -0
- metadata +133 -0
data/.document
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Tony Arcieri
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
Stash
|
2
|
+
=====
|
3
|
+
|
4
|
+
*"The sloping companion I cast down the ash, yanked on my tunic and dangled my stash"*
|
5
|
+
|
6
|
+
Stash provides Ruby-like classes for interacting with data structures servers.
|
7
|
+
Presently the only such server supported is Redis, however support is planned
|
8
|
+
for Membase, Memcache, and possibly Kestrel.
|
9
|
+
|
10
|
+
Initializing Stash
|
11
|
+
------------------
|
12
|
+
|
13
|
+
Stash supports multiple connections which are initialized through the
|
14
|
+
stash Stash.setup command. Stash operates primarily through the default
|
15
|
+
connection:
|
16
|
+
|
17
|
+
Stash.setup :default, :adapter => :redis, :host => 'localhost'
|
18
|
+
|
19
|
+
This will connect to the Redis server listening on localhost. Stash.setup
|
20
|
+
takes an options hash with the following parameters:
|
21
|
+
|
22
|
+
- **adapter**: must be "redis" (*mandatory*)
|
23
|
+
- **host**: hostname or IP address of the Redis server (*mandatory*)
|
24
|
+
- **port**: port of the Redis server (*optional, default 6379*)
|
25
|
+
- **namespace**: Redis namspace to use (*optional, default global namespace*)
|
26
|
+
- **password**: password to the Redis server (*optional*)
|
27
|
+
|
28
|
+
Strings
|
29
|
+
-------
|
30
|
+
|
31
|
+
The core type exposed by Stash is a string. You can store a string in the
|
32
|
+
default Stash using:
|
33
|
+
|
34
|
+
Stash[:foobar] = "mystring"
|
35
|
+
|
36
|
+
This string can be retrieved as easily as:
|
37
|
+
|
38
|
+
Stash[:foobar]
|
39
|
+
|
40
|
+
And deleted with:
|
41
|
+
|
42
|
+
Stash.delete :foobar
|
43
|
+
|
44
|
+
Lists
|
45
|
+
-----
|
46
|
+
|
47
|
+
Stash supports a mostly ordered list type. You can retrieve a list with:
|
48
|
+
|
49
|
+
Stash::List[:baz]
|
50
|
+
|
51
|
+
Stash Lists support most of the methods you'd expect on the Ruby Array type.
|
52
|
+
They are enumerable and support all of Ruby's Enumerable methods.
|
53
|
+
|
54
|
+
You can push elements onto the list with:
|
55
|
+
|
56
|
+
Stash::List[:baz] << 'asdf'
|
57
|
+
|
58
|
+
And pop them with:
|
59
|
+
|
60
|
+
Stash::List[:baz].pop
|
61
|
+
|
62
|
+
Lists can be converted to arrays with:
|
63
|
+
|
64
|
+
Stash::List[:baz].to_a
|
65
|
+
|
66
|
+
Or iterated with:
|
67
|
+
|
68
|
+
Stash::List[:baz].each { |elem| ... }
|
69
|
+
|
70
|
+
Stash asks you to think of lists as being somewhat loosely ordered. This
|
71
|
+
means that Stash will make its best effort to give you a list in order,
|
72
|
+
however that order may shift around depending on how the backend storage
|
73
|
+
system is implemented. Distributed systems may be interesting properties.
|
74
|
+
|
75
|
+
Hashes
|
76
|
+
------
|
77
|
+
|
78
|
+
Stash hashes work like Ruby hashes. You can retrieve a Stash::Hash with:
|
79
|
+
|
80
|
+
Stash::Hash[:qux]
|
81
|
+
|
82
|
+
You can set members of a Stash::Hash with:
|
83
|
+
|
84
|
+
Stash::Hash[:qux][:omgwtf] == "bbq"
|
85
|
+
|
86
|
+
or retrieve them with:
|
87
|
+
|
88
|
+
Stash::Hash[:qux][:omgwtf]
|
89
|
+
|
90
|
+
You can convert a Stash::Hash to a Ruby hash with:
|
91
|
+
|
92
|
+
Stash::Hash[:qux].to_hash
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "stash"
|
8
|
+
gem.summary = "Abstract interface to data structures servers"
|
9
|
+
gem.description = "Stash maps the facilities provided by data structures servers onto classes which mimic Ruby's built-in types"
|
10
|
+
gem.email = "tony@medioh.com"
|
11
|
+
gem.homepage = "http://github.com/tarcieri/stash"
|
12
|
+
gem.authors = ["Tony Arcieri"]
|
13
|
+
gem.add_dependency "redis", "~> 2.1.0"
|
14
|
+
gem.add_dependency "redis-namespace", "~> 0.10.0"
|
15
|
+
gem.add_development_dependency "rspec", "~> 2.1.0"
|
16
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
17
|
+
end
|
18
|
+
Jeweler::GemcutterTasks.new
|
19
|
+
rescue LoadError
|
20
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'rspec/core/rake_task'
|
24
|
+
RSpec::Core::RakeTask.new(:rspec) do |rspec|
|
25
|
+
rspec.rspec_opts = %w[-fs -c -b]
|
26
|
+
end
|
27
|
+
|
28
|
+
RSpec::Core::RakeTask.new(:rspec) do |rspec|
|
29
|
+
rspec.rspec_opts = %w[-fs -c -b]
|
30
|
+
rspec.rcov = true
|
31
|
+
end
|
32
|
+
|
33
|
+
task :rspec => :check_dependencies
|
34
|
+
task :spec => :rspec
|
35
|
+
|
36
|
+
task :default => :rspec
|
37
|
+
|
38
|
+
require 'rake/rdoctask'
|
39
|
+
Rake::RDocTask.new do |rdoc|
|
40
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
41
|
+
|
42
|
+
rdoc.rdoc_dir = 'rdoc'
|
43
|
+
rdoc.title = "stash #{version}"
|
44
|
+
rdoc.rdoc_files.include('README*')
|
45
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
46
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class Stash
|
2
|
+
# Configuration error
|
3
|
+
class ConfigError < StandardError; end
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
def [](key)
|
7
|
+
default[key]
|
8
|
+
end
|
9
|
+
|
10
|
+
def []=(key, value)
|
11
|
+
default[key] = value
|
12
|
+
end
|
13
|
+
|
14
|
+
# Add a configuration entry to Stash
|
15
|
+
def setup(label, configuration)
|
16
|
+
@configurations ||= {}
|
17
|
+
@configurations[label.to_sym] = configuration
|
18
|
+
|
19
|
+
if label == :default
|
20
|
+
@default = nil
|
21
|
+
default
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Retrieve the default Stash configuration
|
26
|
+
def default
|
27
|
+
@default ||= begin
|
28
|
+
raise ConfigError, "please configure me with Stash.setup" unless @configurations
|
29
|
+
raise ConfigError, "no default configuration" unless @configurations[:default]
|
30
|
+
new(@configurations[:default])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Retrieve a particular Stash configuration
|
35
|
+
def configuration(key)
|
36
|
+
@configurations[key.to_sym]
|
37
|
+
end
|
38
|
+
|
39
|
+
# Delete a key from the Stash
|
40
|
+
def delete(key)
|
41
|
+
default.delete(key)
|
42
|
+
true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
extend ClassMethods
|
47
|
+
end
|
data/lib/stash/hash.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# Stash::Hashes are remotely located lookup tables
|
2
|
+
class Stash::Hash
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
def self.[](key)
|
6
|
+
new(key)
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(key, adapter = Stash.default.adapter)
|
10
|
+
@name, @adapter = key.to_s, adapter
|
11
|
+
end
|
12
|
+
|
13
|
+
# Retrieve the value associated with a given key
|
14
|
+
def [](key)
|
15
|
+
@adapter.hash_get @name, key.to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
# Set a value in the hash
|
19
|
+
def []=(key, value)
|
20
|
+
@adapter.hash_set @name, key.to_s, value.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
# Clear all elements from the hash
|
24
|
+
def clear
|
25
|
+
@adapter.delete @name
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
# Delete a value from the hash
|
30
|
+
def delete(key)
|
31
|
+
@adapter.hash_delete @name, key.to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
# Return the length of a hash
|
35
|
+
def length
|
36
|
+
@adapter.hash_length @name
|
37
|
+
end
|
38
|
+
|
39
|
+
# Is this hash empty?
|
40
|
+
def empty?
|
41
|
+
length == 0
|
42
|
+
end
|
43
|
+
|
44
|
+
# Cast to a Ruby hash
|
45
|
+
def to_hash
|
46
|
+
@adapter.hash_value @name
|
47
|
+
end
|
48
|
+
|
49
|
+
# Enumerate hashes
|
50
|
+
def each(&block)
|
51
|
+
to_hash.each(&block)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Inspect a hash
|
55
|
+
def inspect
|
56
|
+
"#<Stash::Hash[:#{@name}]: #{to_hash.inspect}>"
|
57
|
+
end
|
58
|
+
|
59
|
+
# Create a string representation of a hash
|
60
|
+
alias_method :to_s, :inspect
|
61
|
+
end
|
data/lib/stash/list.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# Stash::Lists are (mostly) ordered lists stored remotely on the server
|
2
|
+
class Stash::List
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
def self.[](key)
|
6
|
+
new(key)
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(key, adapter = Stash.default.adapter)
|
10
|
+
@key, @adapter = key.to_s, adapter
|
11
|
+
end
|
12
|
+
|
13
|
+
# Cast to an array
|
14
|
+
def to_ary
|
15
|
+
@adapter.list_range @key, 0, length
|
16
|
+
end
|
17
|
+
alias_method :to_a, :to_ary
|
18
|
+
|
19
|
+
# Get the length of a list
|
20
|
+
def length
|
21
|
+
@adapter.list_length(@key)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Is this list empty?
|
25
|
+
def empty?
|
26
|
+
length == 0
|
27
|
+
end
|
28
|
+
|
29
|
+
# Clear all elements from the list
|
30
|
+
def clear
|
31
|
+
@adapter.delete @key
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
# Push an element onto the list (i.e. right push)
|
36
|
+
def push(elem)
|
37
|
+
@adapter.list_push @key, elem.to_s, :right
|
38
|
+
self
|
39
|
+
end
|
40
|
+
alias_method :<<, :push
|
41
|
+
alias_method :rpush, :push
|
42
|
+
|
43
|
+
# Unshift an element onto the list (i.e. left push)
|
44
|
+
def unshift(elem)
|
45
|
+
@adapter.list_push @key, elem.to_s, :left
|
46
|
+
end
|
47
|
+
alias_method :lpush, :unshift
|
48
|
+
|
49
|
+
# Pop from a list (i.e. right pop)
|
50
|
+
def pop
|
51
|
+
@adapter.list_pop @key, :right
|
52
|
+
end
|
53
|
+
alias_method :rpop, :pop
|
54
|
+
|
55
|
+
# Shift from a list (i.e. left pop)
|
56
|
+
def shift
|
57
|
+
@adapter.list_pop @key, :left
|
58
|
+
end
|
59
|
+
alias_method :lpop, :shift
|
60
|
+
|
61
|
+
# Blocking shift: wait for a message to be pushed (with an optional timeout)
|
62
|
+
def bshift(timeout = nil)
|
63
|
+
@adapter.list_blocking_pop @key, :left, timeout
|
64
|
+
end
|
65
|
+
alias_method :blpop, :bshift
|
66
|
+
|
67
|
+
# Blocking pop: wait for a message to be unshifted (with an optional timeout)
|
68
|
+
def bpop(timeout = nil)
|
69
|
+
@adapter.list_blocking_pop @key, :right, timeout
|
70
|
+
end
|
71
|
+
alias_method :brpop, :bpop
|
72
|
+
|
73
|
+
# Iterate the list
|
74
|
+
def each(&block)
|
75
|
+
to_ary.each(&block)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Obtain the last element in a list
|
79
|
+
def last
|
80
|
+
to_ary[-1]
|
81
|
+
end
|
82
|
+
|
83
|
+
# Inspect a list
|
84
|
+
def inspect
|
85
|
+
"#<Stash::List[:#{@key}]: #{to_ary.inspect}>"
|
86
|
+
end
|
87
|
+
|
88
|
+
# Create a string representation of a list
|
89
|
+
alias_method :to_s, :inspect
|
90
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'redis'
|
2
|
+
require 'redis-namespace'
|
3
|
+
|
4
|
+
class Stash
|
5
|
+
# Adapter for the Redis data structures server.
|
6
|
+
# See http://code.google.com/p/redis/
|
7
|
+
class RedisAdapter
|
8
|
+
attr_reader :capabilities
|
9
|
+
|
10
|
+
def initialize(config)
|
11
|
+
# Symbolize keys in config
|
12
|
+
config = config.inject({}) { |h, (k, v)| h[k.to_sym] = v; h }
|
13
|
+
|
14
|
+
raise ArgumentError, "missing 'host' key" unless config[:host]
|
15
|
+
config[:port] ||= 6379 # Default Redis port
|
16
|
+
|
17
|
+
redis = Redis.new config
|
18
|
+
redis = Redis::Namespace.new config[:namespace], :redis => redis if config[:namespace]
|
19
|
+
|
20
|
+
@capabilities = [:string, :list, :hash]
|
21
|
+
|
22
|
+
# Redis 2.0RC+ supports blocking pop
|
23
|
+
@capabilities << :bpop if redis.info['redis_version'] >= "1.3.0"
|
24
|
+
|
25
|
+
@redis = redis
|
26
|
+
end
|
27
|
+
|
28
|
+
# Set a given key within Redis
|
29
|
+
def []=(key, value)
|
30
|
+
@redis.set key.to_s, value.to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
# Retrieve a given key from Redis
|
34
|
+
def [](key)
|
35
|
+
case type(key)
|
36
|
+
when "none" then nil
|
37
|
+
when "string" then Stash::String.new key, self
|
38
|
+
when "list" then Stash::List.new key, self
|
39
|
+
else raise "unknown Redis key type: #{key}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Retrieve the type for a given key
|
44
|
+
def type(key)
|
45
|
+
@redis.type key.to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
# Retrieve a key as a string
|
49
|
+
def get(key)
|
50
|
+
@redis.get key.to_s
|
51
|
+
end
|
52
|
+
|
53
|
+
# Delete a key
|
54
|
+
def delete(key)
|
55
|
+
@redis.del key.to_s
|
56
|
+
end
|
57
|
+
|
58
|
+
# Push an element onto a list
|
59
|
+
def list_push(name, value, side)
|
60
|
+
case side
|
61
|
+
when :right
|
62
|
+
@redis.rpush name.to_s, value.to_s
|
63
|
+
when :left
|
64
|
+
@redis.lpush name.to_s, value.to_s
|
65
|
+
else raise ArgumentError, "left or right plztks"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Pop from a list
|
70
|
+
def list_pop(name, side)
|
71
|
+
case side
|
72
|
+
when :right
|
73
|
+
@redis.rpop name.to_s
|
74
|
+
when :left
|
75
|
+
@redis.lpop name.to_s
|
76
|
+
else raise ArgumentError, "left or right plztks"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Blocking pop from a list
|
81
|
+
def list_blocking_pop(name, side, timeout = nil)
|
82
|
+
timeout ||= 0
|
83
|
+
res = case side
|
84
|
+
when :left
|
85
|
+
@redis.blpop name, timeout
|
86
|
+
when :right
|
87
|
+
@redis.brpop name, timeout
|
88
|
+
else raise ArgumentError, "left or right plztks"
|
89
|
+
end
|
90
|
+
|
91
|
+
return res[1] if res
|
92
|
+
raise Stash::TimeoutError, "request timed out"
|
93
|
+
end
|
94
|
+
|
95
|
+
# Retrieve the length of a list
|
96
|
+
def list_length(name)
|
97
|
+
@redis.llen name.to_s
|
98
|
+
end
|
99
|
+
|
100
|
+
# Retrieve the given range from a list
|
101
|
+
def list_range(name, from, to)
|
102
|
+
@redis.lrange name.to_s, from, to
|
103
|
+
end
|
104
|
+
|
105
|
+
# Retrieve a value from a hash
|
106
|
+
def hash_get(name, key)
|
107
|
+
res = @redis.hget name.to_s, key.to_s
|
108
|
+
return if res == ""
|
109
|
+
res
|
110
|
+
end
|
111
|
+
|
112
|
+
# Store a value in a hash
|
113
|
+
def hash_set(name, key, value)
|
114
|
+
@redis.hset name.to_s, key.to_s, value.to_s
|
115
|
+
end
|
116
|
+
|
117
|
+
# Retrieve the contents of a hash as a Ruby hash
|
118
|
+
def hash_value(name)
|
119
|
+
@redis.hgetall name.to_s
|
120
|
+
end
|
121
|
+
|
122
|
+
# Delete an entry from a hash
|
123
|
+
def hash_delete(name, key)
|
124
|
+
@redis.hdel name.to_s, key.to_s
|
125
|
+
end
|
126
|
+
|
127
|
+
# Return the length of a hash
|
128
|
+
def hash_length(name)
|
129
|
+
@redis.hlen name.to_s
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
data/lib/stash/string.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# Strings are Stash's most basic type, and the only non-collection type
|
2
|
+
# They store exactly that, a string, and nothing more
|
3
|
+
class Stash::String
|
4
|
+
def initialize(key, adapter = Stash.default.adapter)
|
5
|
+
@adapter, @key = adapter, key.to_s
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_string
|
9
|
+
@adapter.get @key
|
10
|
+
end
|
11
|
+
alias_method :to_s, :to_string
|
12
|
+
|
13
|
+
def inspect
|
14
|
+
"#<Stash::String[:#{key}]: #{to_s}>"
|
15
|
+
end
|
16
|
+
end
|
data/lib/stash.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# Stash is an abstract interface to data structures servers
|
2
|
+
class Stash
|
3
|
+
attr_reader :adapter
|
4
|
+
|
5
|
+
# Timeout when performing a blocking action, such as blocking pop
|
6
|
+
class TimeoutError < StandardError; end
|
7
|
+
|
8
|
+
def initialize(config)
|
9
|
+
raise ArgumentError, "no adapter specified" unless config[:adapter]
|
10
|
+
adapter_name = config[:adapter].to_s.split('_').map { |s| s.capitalize }.join
|
11
|
+
adapter_name += "Adapter"
|
12
|
+
|
13
|
+
begin
|
14
|
+
adapter_class = Stash.const_get adapter_name
|
15
|
+
rescue NameError
|
16
|
+
raise ArgumentError, "unknown adapter: #{config[:adapter]}"
|
17
|
+
end
|
18
|
+
|
19
|
+
@adapter = adapter_class.new config
|
20
|
+
end
|
21
|
+
|
22
|
+
# Store an object in the Stash
|
23
|
+
def []=(key, value)
|
24
|
+
@adapter[key.to_s] = value
|
25
|
+
end
|
26
|
+
|
27
|
+
# Retrieve an object from the Stash
|
28
|
+
def [](key)
|
29
|
+
@adapter[key.to_s]
|
30
|
+
end
|
31
|
+
|
32
|
+
# Remove a key from the Stash
|
33
|
+
def delete(key)
|
34
|
+
@adapter.delete(key.to_s)
|
35
|
+
true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
require 'stash/class_methods'
|
40
|
+
require 'stash/redis_adapter'
|
41
|
+
require 'stash/string'
|
42
|
+
require 'stash/list'
|
43
|
+
require 'stash/hash'
|
data/spec/hash_spec.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Stash::Hash do
|
4
|
+
before :each do
|
5
|
+
@hash = Stash::Hash[:foobar]
|
6
|
+
@hash.clear
|
7
|
+
end
|
8
|
+
|
9
|
+
it "clears hashes" do
|
10
|
+
@hash[:foo] = "a"
|
11
|
+
@hash[:bar] = "b"
|
12
|
+
@hash.clear
|
13
|
+
@hash.to_hash.should == {}
|
14
|
+
end
|
15
|
+
|
16
|
+
it "sets and gets strings from hashes" do
|
17
|
+
@hash[:foo].should be_nil
|
18
|
+
@hash[:foo] = "42"
|
19
|
+
@hash[:foo].should == "42"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "casts to a Ruby hash" do
|
23
|
+
@hash.should be_empty
|
24
|
+
@hash['foo'] = 'a'
|
25
|
+
@hash['bar'] = 'b'
|
26
|
+
|
27
|
+
@hash.to_hash.should == {'foo'=>'a', 'bar'=>'b'}
|
28
|
+
end
|
29
|
+
end
|
data/spec/list_spec.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Stash::List do
|
4
|
+
before :each do
|
5
|
+
@list = Stash::List[:foobar]
|
6
|
+
@list.clear
|
7
|
+
end
|
8
|
+
|
9
|
+
it "clears lists" do
|
10
|
+
@list << "x"
|
11
|
+
@list << "y"
|
12
|
+
@list << "z"
|
13
|
+
@list.clear
|
14
|
+
@list.to_a.should == []
|
15
|
+
end
|
16
|
+
|
17
|
+
it "pushes to lists" do
|
18
|
+
# Normal syntax
|
19
|
+
@list.push "zomg"
|
20
|
+
|
21
|
+
# Cool syntax
|
22
|
+
@list << "wtf"
|
23
|
+
|
24
|
+
@list.to_a.should == ["zomg", "wtf"]
|
25
|
+
end
|
26
|
+
|
27
|
+
it "unshifts to lists" do
|
28
|
+
@list.unshift "omfg"
|
29
|
+
@list.unshift "lulz"
|
30
|
+
|
31
|
+
@list.to_a.should == ["lulz", "omfg"]
|
32
|
+
end
|
33
|
+
|
34
|
+
it "pops from lists" do
|
35
|
+
@list << "x"
|
36
|
+
@list << "y"
|
37
|
+
@list << "z"
|
38
|
+
@list.pop.should == "z"
|
39
|
+
@list.to_a.should == ["x", "y"]
|
40
|
+
end
|
41
|
+
|
42
|
+
it "shifts from lists" do
|
43
|
+
@list << "x"
|
44
|
+
@list << "y"
|
45
|
+
@list << "z"
|
46
|
+
@list.shift.should == "x"
|
47
|
+
@list.to_a.should == ["y", "z"]
|
48
|
+
end
|
49
|
+
|
50
|
+
it "knows its length" do
|
51
|
+
@list.length.should == 0
|
52
|
+
|
53
|
+
@list << "x"
|
54
|
+
@list << "y"
|
55
|
+
@list << "z"
|
56
|
+
@list.length.should == 3
|
57
|
+
end
|
58
|
+
|
59
|
+
it "knows if it's empty" do
|
60
|
+
@list.should be_empty
|
61
|
+
|
62
|
+
@list << "something"
|
63
|
+
@list.should_not be_empty
|
64
|
+
end
|
65
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
$LOAD_PATH.unshift File.dirname(__FILE__)
|
2
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
3
|
+
|
4
|
+
require 'stash'
|
5
|
+
require 'rspec'
|
6
|
+
require 'rspec/autorun'
|
7
|
+
|
8
|
+
# Connect to Redis
|
9
|
+
Stash.setup :default, :adapter => :redis,
|
10
|
+
:namespace => 'stash_test',
|
11
|
+
:host => '127.0.0.1',
|
12
|
+
:port => 6379
|
data/spec/string_spec.rb
ADDED
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: stash
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Tony Arcieri
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-11-30 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: redis
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 11
|
30
|
+
segments:
|
31
|
+
- 2
|
32
|
+
- 1
|
33
|
+
- 0
|
34
|
+
version: 2.1.0
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: redis-namespace
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 55
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
- 10
|
49
|
+
- 0
|
50
|
+
version: 0.10.0
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: rspec
|
55
|
+
prerelease: false
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 11
|
62
|
+
segments:
|
63
|
+
- 2
|
64
|
+
- 1
|
65
|
+
- 0
|
66
|
+
version: 2.1.0
|
67
|
+
type: :development
|
68
|
+
version_requirements: *id003
|
69
|
+
description: Stash maps the facilities provided by data structures servers onto classes which mimic Ruby's built-in types
|
70
|
+
email: tony@medioh.com
|
71
|
+
executables: []
|
72
|
+
|
73
|
+
extensions: []
|
74
|
+
|
75
|
+
extra_rdoc_files:
|
76
|
+
- LICENSE
|
77
|
+
- README.markdown
|
78
|
+
files:
|
79
|
+
- .document
|
80
|
+
- LICENSE
|
81
|
+
- README.markdown
|
82
|
+
- Rakefile
|
83
|
+
- VERSION
|
84
|
+
- lib/stash.rb
|
85
|
+
- lib/stash/class_methods.rb
|
86
|
+
- lib/stash/hash.rb
|
87
|
+
- lib/stash/list.rb
|
88
|
+
- lib/stash/redis_adapter.rb
|
89
|
+
- lib/stash/string.rb
|
90
|
+
- spec/hash_spec.rb
|
91
|
+
- spec/list_spec.rb
|
92
|
+
- spec/spec.opts
|
93
|
+
- spec/spec_helper.rb
|
94
|
+
- spec/string_spec.rb
|
95
|
+
has_rdoc: true
|
96
|
+
homepage: http://github.com/tarcieri/stash
|
97
|
+
licenses: []
|
98
|
+
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options: []
|
101
|
+
|
102
|
+
require_paths:
|
103
|
+
- lib
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
hash: 3
|
110
|
+
segments:
|
111
|
+
- 0
|
112
|
+
version: "0"
|
113
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
hash: 3
|
119
|
+
segments:
|
120
|
+
- 0
|
121
|
+
version: "0"
|
122
|
+
requirements: []
|
123
|
+
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 1.3.7
|
126
|
+
signing_key:
|
127
|
+
specification_version: 3
|
128
|
+
summary: Abstract interface to data structures servers
|
129
|
+
test_files:
|
130
|
+
- spec/hash_spec.rb
|
131
|
+
- spec/list_spec.rb
|
132
|
+
- spec/spec_helper.rb
|
133
|
+
- spec/string_spec.rb
|