stash 1.0.0 → 2.0.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.
@@ -1,92 +0,0 @@
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 DELETED
@@ -1,46 +0,0 @@
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.2.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(:rcov) 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 DELETED
@@ -1 +0,0 @@
1
- 1.0.0
@@ -1,59 +0,0 @@
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
-
45
- # Obtain the class for a given adapter name
46
- def adapter_class(name)
47
- adapter_name = name.to_s.split('_').map { |s| s.capitalize }.join
48
- adapter_name << "Adapter"
49
-
50
- begin
51
- Stash.const_get adapter_name
52
- rescue NameError
53
- raise ArgumentError, "unknown adapter: #{name}"
54
- end
55
- end
56
- end
57
-
58
- extend ClassMethods
59
- end
@@ -1,62 +0,0 @@
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
- self
53
- end
54
-
55
- # Inspect a hash
56
- def inspect
57
- "#<Stash::Hash[:#{@name}]: #{to_hash.inspect}>"
58
- end
59
-
60
- # Create a string representation of a hash
61
- alias_method :to_s, :inspect
62
- end
@@ -1,91 +0,0 @@
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
- self
77
- end
78
-
79
- # Obtain the last element in a list
80
- def last
81
- to_ary[-1]
82
- end
83
-
84
- # Inspect a list
85
- def inspect
86
- "#<Stash::List[:#{@key}]: #{to_ary.inspect}>"
87
- end
88
-
89
- # Create a string representation of a list
90
- alias_method :to_s, :inspect
91
- end
@@ -1,152 +0,0 @@
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
- def initialize(config)
9
- # Convert config keys to symbols
10
- config = symbolize_config(config)
11
-
12
- raise ArgumentError, "missing 'host' key" unless config[:host]
13
- config[:port] ||= 6379 # Default Redis port
14
-
15
- @config = config
16
- end
17
-
18
- # Obtain a connection to Redis
19
- def connection
20
- redis = Redis.new @config
21
- redis = Redis::Namespace.new @config[:namespace], :redis => redis if @config[:namespace]
22
-
23
- begin
24
- yield redis
25
- ensure
26
- redis.quit
27
- end
28
- end
29
-
30
- # Set a given key within Redis
31
- def []=(key, value)
32
- connection { |redis| redis.set key.to_s, value.to_s }
33
- end
34
-
35
- # Retrieve a given key from Redis
36
- def [](key)
37
- case type(key)
38
- when "none" then nil
39
- when "string" then Stash::String.new key, self
40
- when "list" then Stash::List.new key, self
41
- else raise "unknown Redis key type: #{key}"
42
- end
43
- end
44
-
45
- # Retrieve the type for a given key
46
- def type(key)
47
- connection { |redis| redis.type key.to_s }
48
- end
49
-
50
- # Retrieve a key as a string
51
- def get(key)
52
- connection { |redis| redis.get key.to_s }
53
- end
54
-
55
- # Delete a key
56
- def delete(key)
57
- connection { |redis| redis.del key.to_s }
58
- end
59
-
60
- # Push an element onto a list
61
- def list_push(name, value, side)
62
- connection do |redis|
63
- case side
64
- when :right
65
- redis.rpush name.to_s, value.to_s
66
- when :left
67
- redis.lpush name.to_s, value.to_s
68
- else raise ArgumentError, "left or right plztks"
69
- end
70
- end
71
- end
72
-
73
- # Pop from a list
74
- def list_pop(name, side)
75
- connection do |redis|
76
- case side
77
- when :right
78
- redis.rpop name.to_s
79
- when :left
80
- redis.lpop name.to_s
81
- else raise ArgumentError, "left or right plztks"
82
- end
83
- end
84
- end
85
-
86
- # Blocking pop from a list
87
- def list_blocking_pop(name, side, timeout = nil)
88
- connection do |redis|
89
- timeout ||= 0
90
- res = case side
91
- when :left
92
- redis.blpop name, timeout
93
- when :right
94
- redis.brpop name, timeout
95
- else raise ArgumentError, "left or right plztks"
96
- end
97
-
98
- return res[1] if res
99
- raise Stash::TimeoutError, "request timed out"
100
- end
101
- end
102
-
103
- # Retrieve the length of a list
104
- def list_length(name)
105
- connection { |redis| redis.llen name.to_s }
106
- end
107
-
108
- # Retrieve the given range from a list
109
- def list_range(name, from, to)
110
- connection { |redis| redis.lrange name.to_s, from, to }
111
- end
112
-
113
- # Retrieve a value from a hash
114
- def hash_get(name, key)
115
- res = connection { |redis| redis.hget name.to_s, key.to_s }
116
- return if res == ""
117
- res
118
- end
119
-
120
- # Store a value in a hash
121
- def hash_set(name, key, value)
122
- connection { |redis| redis.hset name.to_s, key.to_s, value.to_s }
123
- end
124
-
125
- # Retrieve the contents of a hash as a Ruby hash
126
- def hash_value(name)
127
- connection { |redis| redis.hgetall name.to_s }
128
- end
129
-
130
- # Delete an entry from a hash
131
- def hash_delete(name, key)
132
- connection { |redis| redis.hdel name.to_s, key.to_s }
133
- end
134
-
135
- # Return the length of a hash
136
- def hash_length(name)
137
- connection { |redis| redis.hlen name.to_s }
138
- end
139
-
140
- #######
141
- private
142
- #######
143
-
144
- def symbolize_config(config)
145
- new_config = {}
146
- config.each do |k, v|
147
- new_config[k.to_sym] = v
148
- end
149
- new_config
150
- end
151
- end
152
- end