stash 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/stash/build.c +267 -0
- data/ext/stash/execute.c +248 -0
- data/ext/stash/extconf.rb +3 -0
- data/ext/stash/intern.h +79 -0
- data/ext/stash/lex.yy.c +2143 -0
- data/ext/stash/lex.yy.h +333 -0
- data/ext/stash/mustache.c +50 -0
- data/ext/stash/mustache.h +124 -0
- data/ext/stash/optimize.c +208 -0
- data/ext/stash/stash.c +177 -0
- data/ext/stash/stash.h +17 -0
- data/ext/stash/tokens.c +151 -0
- data/ext/stash/types.c +181 -0
- data/lib/stash.rb +2 -34
- data/lib/stash/debug.rb +46 -0
- metadata +30 -88
- data/.document +0 -5
- data/LICENSE +0 -20
- data/README.markdown +0 -92
- data/Rakefile +0 -46
- data/VERSION +0 -1
- data/lib/stash/class_methods.rb +0 -59
- data/lib/stash/hash.rb +0 -62
- data/lib/stash/list.rb +0 -91
- data/lib/stash/redis_adapter.rb +0 -152
- data/lib/stash/string.rb +0 -16
- data/spec/hash_spec.rb +0 -29
- data/spec/list_spec.rb +0 -65
- data/spec/spec.opts +0 -1
- data/spec/spec_helper.rb +0 -12
- data/spec/string_spec.rb +0 -9
- data/stash.gemspec +0 -68
data/README.markdown
DELETED
@@ -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
|
data/lib/stash/class_methods.rb
DELETED
@@ -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
|
data/lib/stash/hash.rb
DELETED
@@ -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
|
data/lib/stash/list.rb
DELETED
@@ -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
|
data/lib/stash/redis_adapter.rb
DELETED
@@ -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
|