oria 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Flip Sasser
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,133 @@
1
+ Oria
2
+ ===
3
+
4
+ Oria (oh-rye-uh) is an in-memory, Ruby-based Key-Value Store. It's designed to handle moderate amounts of data quickly
5
+ and easily without causing deployment issues or server headaches. It uses EventMachine to provide a networked interface
6
+ to a semi-persistent KVS and asynchronously writes the in-memory data to YAML files.
7
+
8
+ Installation
9
+ -
10
+
11
+ Oria is a provided as a Gem. Use the following command to install it:
12
+
13
+ gem install oria --source http://gemcutter.org
14
+
15
+ That's it! You're ready to start storing basic data in memory. Now add
16
+
17
+ require "oria"
18
+
19
+ so's you can access Oria.
20
+
21
+ Command Line
22
+ -
23
+
24
+ The recommended pattern for starting and stopping Oria is using the Oria command line application, like so:
25
+
26
+ $ oria start|stop|restart
27
+
28
+ That's it! Oria will run in-memory, and you can always shut it down using `oria stop`.
29
+
30
+ Auto-Start and Daeomonizing
31
+ -
32
+
33
+ Yes, I recommend you use the command line. But on _[certain platforms](http://heroku.com)_, you don't have access to the
34
+ command line. And since Oria was built to be simple to use and to deploy, it also supports auto-starting and stopping. It
35
+ will detect a downed server and boot itself up in a separate thread. I should warn you, however: this functionality means
36
+ Oria requires a *nix environment - sorry, IronRuby users!
37
+
38
+ Oria auto-starts transparently, so just use it normally to take advantage of this feature. **Note:** this feature is currently
39
+ untested, so please test it heavily before deploying, and _report any issues you may have!_
40
+
41
+ Usage
42
+ -
43
+
44
+ Okay, now for the fun part. Oria behaves (mostly) like a Hash - you could say that it responds to 2/3 of @wycats' Moneta
45
+ plugin. Specifically, it responds to the following Hash methods:
46
+
47
+ []=(value) Set a key to ... something.
48
+
49
+ [] Retrieve a key
50
+
51
+ delete(key) Delete and return a key's value
52
+
53
+ key?(key) Returns a boolean value for whether or not that key exists
54
+
55
+ has_key?(key) Same as key
56
+
57
+ clear Clears all keys and values from Oria
58
+
59
+ In addition to those methods, Oria also supports a cool option inspired by some other KVS's:
60
+
61
+ stash(value) Stash a value in Oria. Returns the randomly generated key it stored the value under. This
62
+ is useful for when you need to store something temporarily, e.g. stash it, pass the key
63
+ in a URL, and retrieve / delete it.
64
+
65
+ So let's play:
66
+
67
+ Oria[:foo] = 'bar' #=> "bar"
68
+ Oria[:foo] #=> "bar"
69
+ Oria.key?(:foo) #=> true
70
+ Oria.delete(:foo) #=> foo
71
+ Oria[:foo] #=> nil
72
+ Oria.stash("baz") #=> "wZ"
73
+
74
+ Nothing exciting? Try shutting your app down and booting it back up.
75
+
76
+ Oria[:wZ] #=> "baz"
77
+
78
+ Bam. A relatively fast KVS with no configuration or special server setup.
79
+
80
+ But wait, I stored a <Ruby-specific object>! WTF?
81
+ -
82
+
83
+ Ah yes. You've found Oria's Achilles heel. Oria speaks JSON, so everything you give it must be capable of JSON'ing.
84
+ That means `Oria[:user] = User.find(1)` ain't working any time soon. Likewise, and perhaps more unfortunately, things like
85
+ `Oria[:my_cool_hash] = {:key => "Key!!!!!1", :value => "valyooooo"}` are going to return `{"key" => "Key", etc...}` so
86
+ your hashes are going to respond to string keys and not symbols once they've been through Oria.
87
+
88
+ It's a bummer, I know. But this is an in-memory KVS, and not Rails sessions where we're marshaling and un-marshaling everything
89
+ every request. I realize that it'll most likely only ever speak to Ruby clients (specifically this one), but this is where
90
+ it is. Sorry.
91
+
92
+ Configuration
93
+ -
94
+
95
+ Oria is built the be configuration-less out of the box, but if you really need to, you can tell it to do lots of
96
+ things. It's built on top of EventMachine, so networking is an option - but if you're networking your KVS, you should
97
+ think about upgrading to something like Redis or Memcached. Oria is meant to be used in situations where a database OR
98
+ a high-powered KVS would be overkill. But then again, you can use Oria to decentralize some of your tasks over a network,
99
+ which is fun. Observe:
100
+
101
+ Oria.connect(server, port) Connect to a server / port. Defaults to localhost and 6851
102
+
103
+ Oria.disconnect Kills the running server... maybe (see command line vs auto-start above)
104
+
105
+ Oria.app_key = value Oria supports "splitting" your apps, much like how Resque supports named queues. Specifying an
106
+ app key will effectively change the hash you are working with. It defaults to "default," cause
107
+ I'm original like that.
108
+
109
+ Let's try it out:
110
+
111
+ Oria.app_key = "my_app_1"
112
+ Oria[:foo] = "bar"
113
+ Oria[:foo] #=> "bar"
114
+
115
+ Oria.app_key = "my_app_2"
116
+ Oria[:foo] #=> nil
117
+ Oria.app_key = "my_app_1"
118
+ Oria[:foo] #=> "bar"
119
+
120
+ Dependencies
121
+ -
122
+
123
+ Oria speaks JSON, so it relies on the JSON gem. It depends on the newest stable version (1.2.0), so be sure to add the right version
124
+ checking code to your legacy apps before using Oria!
125
+
126
+ It also needs [EventMachine](http://github.com/eventmachine/eventmachine) to do everything. Yes, I could have used Drb or straight
127
+ UDP sockets, and spent a lifetime on this. But EventMachine is seriously, seriously, seriously awesome, and works very well
128
+ without me writing an insane amount of code I couldn't write very well anyway. Check it out and see for yourself.
129
+
130
+ That's it! I hope you enjoy Oria, and please let me know if you find any issues or have any trouble. As you will no doubt see from
131
+ the current version information, it's a very young project, and any contribution is welcome.
132
+
133
+ Copyright (c) 2009 Flip Sasser, released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ require 'rake'
2
+
3
+ begin
4
+ require 'spec/rake/spectask'
5
+
6
+ desc "Run all examples"
7
+ Spec::Rake::SpecTask.new('spec') do |t|
8
+ t.spec_files = FileList['spec/**/*.rb']
9
+ end
10
+
11
+ desc "Run all examples with RCov"
12
+ Spec::Rake::SpecTask.new('spec:rcov') do |t|
13
+ t.spec_files = FileList['spec/**/*.rb']
14
+ t.rcov = true
15
+ t.rcov_opts = ['--exclude', 'spec,gem']
16
+ end
17
+ rescue LoadError
18
+ puts "Could not load Rspec. To run tests, use `gem install rspec`"
19
+ end
20
+
21
+ begin
22
+ require 'jeweler'
23
+ Jeweler::Tasks.new do |gemspec|
24
+ gemspec.name = "oria"
25
+ gemspec.summary = "A Ruby-based, in-memory KVS with one half of the peristence you want"
26
+ gemspec.description = %{
27
+ Oria (oh-rye-uh) is an in-memory, Ruby-based Key-Value store. It's designed to handle moderate amounts of data quickly
28
+ and easily without causing deployment issues or server headaches. It uses EventMachine to provide a networked interface
29
+ to a semi-persistent KVS and asynchronously writes the in-memory data to YAML files.
30
+ }
31
+ gemspec.email = "flip@x451.com"
32
+ gemspec.homepage = "http://github.com/flipsasser/oria"
33
+ gemspec.authors = ["Flip Sasser"]
34
+ gemspec.add_dependency('eventmachine', '>= 0.12.10')
35
+ gemspec.add_dependency('json', '>= 1.2.0')
36
+ end
37
+ rescue LoadError
38
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
data/bin/oria ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ # require 'oria'
3
+
4
+ # Oria.run!
@@ -0,0 +1,19 @@
1
+ module Oria
2
+ class Client < EventMachine::Connection
3
+ attr_reader :response
4
+
5
+ def connection_completed
6
+ @connected = true
7
+ end
8
+
9
+ def receive_data(data)
10
+ @response = JSON.parse(data)
11
+ close_connection
12
+ end
13
+
14
+ def unbind
15
+ raise Oria::ConnectionError.new("Could not connect to the Oria server") unless @connected
16
+ EventMachine.stop_event_loop
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,4 @@
1
+ module Oria
2
+ class ConnectionError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,111 @@
1
+ require 'yaml'
2
+ require 'tmpdir'
3
+ module Oria
4
+ class Server < EventMachine::Connection
5
+ class << self
6
+ def debug?
7
+ @@debug
8
+ end
9
+
10
+ def logger
11
+ require 'logger'
12
+ @@logger ||= Logger.new(log_file, 0, 100 * 1024 * 1024)
13
+ end
14
+
15
+ def start(server, port, app_key = nil, debug = false)
16
+ @@pid = Process.pid
17
+ app_key ||= 'default'
18
+ @@servers ||= if File.exists?(yaml_store)
19
+ YAML.load_file(yaml_store)
20
+ else
21
+ {}
22
+ end
23
+ @@debug = !!debug
24
+ @@servers[app_key] ||= {}
25
+ EventMachine.run do
26
+ EventMachine.start_server server, port, Oria::Server
27
+ end
28
+ end
29
+
30
+ def stop
31
+ Process.kill('HUP', @@pid) if defined?(@@pid)
32
+ end
33
+
34
+ def write_hash
35
+ @@write_hash ||= proc do
36
+ File.open(yaml_store, 'w') do |store|
37
+ store.puts YAML.dump(@@servers)
38
+ end
39
+ end
40
+ end
41
+
42
+ protected
43
+ def log_file
44
+ @@log_file ||= File.join(Dir.tmpdir, 'oria.log')
45
+ end
46
+
47
+ def yaml_store
48
+ @@yaml_store ||= File.join(Dir.tmpdir, 'oria.yml')
49
+ end
50
+ end
51
+
52
+ def post_init
53
+ log "Client connected"
54
+ end
55
+
56
+ def receive_data(data)
57
+ log "Responding to #{data}"
58
+ data = data.split(' ')
59
+ method = data.shift
60
+ data = JSON.parse(data.join(' '))
61
+ @app_key = data.delete('app_key')
62
+ case method
63
+ when 'GET'
64
+ response = hash[data['key']]
65
+ when 'DELETE'
66
+ if data.empty?
67
+ hash.clear
68
+ else
69
+ response = hash.delete(data['key'])
70
+ end
71
+ when 'PUT'
72
+ if data.key?('key')
73
+ hash[data['key']] = data['value']
74
+ response = data['value']
75
+ elsif data.key?('value')
76
+ response = random_key
77
+ hash[response] = data['value']
78
+ end
79
+ end
80
+ if defined?(response)
81
+ response = JSON.generate({:response => response})
82
+ log "Sending response: #{response}"
83
+ send_data response
84
+ end
85
+ EventMachine.defer(Oria::Server.write_hash)
86
+ end
87
+
88
+ def unbind
89
+ end
90
+
91
+ private
92
+ def hash
93
+ @hash ||= @@servers[@app_key || 'default'] ||= {}
94
+ end
95
+
96
+ def log(value)
97
+ if Oria::Server.debug?
98
+ Oria::Server.logger.debug(value)
99
+ end
100
+ end
101
+
102
+ def random_key
103
+ chars = ['a'..'z', 'A'..'Z', 0..9].map(&:to_a).flatten
104
+ max = [hash.length, 2].max
105
+ while hash.key?(key = (1..max).map{|i| chars[rand(chars.length)]}.join)
106
+ key = (1..max).map{|i| chars[rand(chars.length)]}.join
107
+ end
108
+ key
109
+ end
110
+ end
111
+ end
data/lib/oria.rb ADDED
@@ -0,0 +1,96 @@
1
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__))
2
+ require 'rubygems'
3
+ require 'eventmachine'
4
+ require 'json'
5
+ require 'oria/errors'
6
+
7
+ module Oria
8
+ autoload(:Client, 'oria/client')
9
+ autoload(:Server, 'oria/server')
10
+
11
+ def self.[](key)
12
+ store(:get, :key => key)
13
+ end
14
+
15
+ def self.[]=(key, value)
16
+ store(:put, :key => key, :value => value)
17
+ value
18
+ end
19
+
20
+ def self.app_key
21
+ @@app_key ||= nil
22
+ end
23
+
24
+ def self.app_key=(key)
25
+ @@app_key = key.to_s
26
+ end
27
+
28
+ def self.auto_start
29
+ @@pid = fork do
30
+ Oria::Server.start(Oria.server, Oria.port, Oria.app_key)
31
+ end
32
+ Process.detach(@@pid)
33
+ at_exit {
34
+ Process.kill("HUP", @@pid)
35
+ }
36
+ sleep 1
37
+ end
38
+
39
+ def self.clear
40
+ store(:delete)
41
+ end
42
+
43
+ def self.connect(server, port = nil, options = {})
44
+ @@server = server
45
+ @@port = port.to_i unless port.to_i == 0
46
+ end
47
+
48
+ def self.delete(key)
49
+ store(:delete, :key => key)
50
+ end
51
+
52
+ def self.disconnect
53
+ Oria::Server.stop
54
+ end
55
+
56
+ def self.has_key?(key)
57
+ key?(key)
58
+ end
59
+
60
+ def self.key?(key)
61
+ !self.[](key).nil?
62
+ end
63
+
64
+ def self.port
65
+ @@port ||= "Oria is easily the coolest in-memory, super-simple KVS. Cool people use it.".split("").inject(0) {|total, char| total += char[0]}
66
+ end
67
+
68
+ def self.server
69
+ @@server ||= '0.0.0.0'
70
+ end
71
+
72
+ def self.stash(value)
73
+ store(:put, :value => value)
74
+ end
75
+
76
+ private
77
+ def self.do_store(method, args)
78
+ client = nil
79
+ EventMachine.run do
80
+ client = EventMachine.connect(Oria.server, Oria.port, Oria::Client)
81
+ client.send_data("#{method.to_s.upcase}#{" #{args}" if args}")
82
+ end
83
+ if client.response
84
+ client.response['response']
85
+ end
86
+ end
87
+
88
+ def self.store(method, args = {})
89
+ args.merge!(:app_key => Oria.app_key)
90
+ args = JSON.generate(args)
91
+ do_store(method, args)
92
+ rescue Oria::ConnectionError
93
+ auto_start
94
+ do_store(method, args)
95
+ end
96
+ end
data/spec/oria_spec.rb ADDED
@@ -0,0 +1,155 @@
1
+ require "spec_helper"
2
+ require "oria"
3
+
4
+ describe Oria do
5
+ describe "Moneta methods" do
6
+ it "should include []" do
7
+ Oria.should respond_to(:[])
8
+ end
9
+
10
+ it "should include []=" do
11
+ Oria.should respond_to(:[]=)
12
+ end
13
+
14
+ it "should include clear" do
15
+ Oria.should respond_to(:clear)
16
+ end
17
+
18
+ it "should include delete" do
19
+ Oria.should respond_to(:delete)
20
+ end
21
+
22
+ it "should include has_key?" do
23
+ Oria.should respond_to(:has_key?)
24
+ end
25
+
26
+ it "should include key?" do
27
+ Oria.should respond_to(:key?)
28
+ end
29
+ end
30
+
31
+ it "should provide a connect method" do
32
+ Oria.should respond_to(:connect)
33
+ end
34
+
35
+ it "should support per-app keys" do
36
+ Oria.should respond_to(:app_key)
37
+ Oria.should respond_to(:app_key=)
38
+ end
39
+
40
+ it "should support custom connections" do
41
+ Oria.connect("127.0.0.1", 4567)
42
+ Oria.server.should == "127.0.0.1"
43
+ Oria.port.should == 4567
44
+ end
45
+
46
+ it "should automatically boot a server" do
47
+ # Oria.should_receive(:auto_start)
48
+ # Oria["foo"] = "bar"
49
+ # Oria.disconnect
50
+ end
51
+
52
+ describe "app_key" do
53
+ # it "should default to nil" do
54
+ # # This is bleeding over from the last example below. Frankly,
55
+ # # I don't know how to fix it.
56
+ # Oria.app_key.should be_nil
57
+ # end
58
+
59
+ it "should be configurable" do
60
+ Oria.app_key = "test_app"
61
+ Oria.app_key.should == "test_app"
62
+ end
63
+ end
64
+
65
+ it "should be possible to disconnect" do
66
+ Oria::Server.should_receive(:stop)
67
+ Oria["foo"] = "bar"
68
+ Oria.disconnect
69
+ end
70
+
71
+ describe "setting values" do
72
+ describe "with a booted server" do
73
+ before :all do
74
+ @pid = fork do
75
+ Oria::Server.start(Oria.server, Oria.port, nil, true)
76
+ end
77
+ Process.detach(@pid)
78
+ sleep 0.5
79
+ end
80
+
81
+ after :all do
82
+ Oria.clear
83
+ Oria::Server.stop
84
+ Process.kill("HUP", @pid)
85
+ end
86
+
87
+ it "should set string values" do
88
+ Oria["foo"] = "bar"
89
+ Oria["foo"].should == "bar"
90
+ end
91
+
92
+ it "should set integer values" do
93
+ Oria["foo"] = 12
94
+ Oria["foo"].should == 12
95
+ end
96
+
97
+ it "should support Hashes" do
98
+ Oria["foo"] = {"Flip" => "Sasser"}
99
+ Oria["foo"].should == {"Flip" => "Sasser"}
100
+ end
101
+
102
+ it "should support Arrays" do
103
+ Oria["foo"] = ["Foo", "Bar", "Baz"]
104
+ Oria["foo"].should == ["Foo", "Bar", "Baz"]
105
+ end
106
+
107
+ it "should support Booleans" do
108
+ Oria["true"] = false
109
+ Oria["true"].should == false
110
+ end
111
+
112
+ it "should support deleting values" do
113
+ Oria["memoria"] = "foobar"
114
+ Oria["dont_delete"] = "please"
115
+ Oria.delete("memoria").should == "foobar"
116
+ Oria["memora"].should be_nil
117
+ Oria["dont_delete"].should == "please"
118
+ end
119
+
120
+ it "should support complete clearing" do
121
+ Oria["a"] = "c"
122
+ Oria["b"] = "d"
123
+ Oria["a"].should == "c"
124
+ Oria["b"].should == "d"
125
+ Oria.clear
126
+ Oria["a"].should be_nil
127
+ Oria["b"].should be_nil
128
+ end
129
+
130
+ it "should support key-checking" do
131
+ Oria["key_check"] = "check-a-key"
132
+ Oria.key?("key_check").should be_true
133
+ Oria.key?("key_check_broken").should be_false
134
+ Oria.has_key?("key_check").should be_true
135
+ Oria.has_key?("key_check_broken").should be_false
136
+ end
137
+
138
+ it "should support stashing" do
139
+ key = Oria.stash("foobar")
140
+ key.should_not be_nil
141
+ Oria[key].should == "foobar"
142
+ end
143
+
144
+ it "should support different app_keys" do
145
+ Oria.app_key = "test_app_1"
146
+ Oria["test_app_1"] = "bar"
147
+ Oria["test_app_1"].should == "bar"
148
+ Oria.app_key = "test_app_2"
149
+ Oria["test_app_2"] = "baz"
150
+ Oria["test_app_1"].should be_nil
151
+ Oria["test_app_2"].should == "baz"
152
+ end
153
+ end
154
+ end
155
+ end
data/spec/rcov.opts ADDED
@@ -0,0 +1 @@
1
+ --exclude "spec/*,gems/*"
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format progress
3
+ --loadby mtime
4
+ --reverse
@@ -0,0 +1,2 @@
1
+ $LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oria
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Flip Sasser
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-22 00:00:00 -05:00
13
+ default_executable: oria
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: eventmachine
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.12.10
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: json
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.2.0
34
+ version:
35
+ description: "\n Oria (oh-rye-uh) is an in-memory, Ruby-based Key-Value store. It's designed to handle moderate amounts of data quickly\n and easily without causing deployment issues or server headaches. It uses EventMachine to provide a networked interface\n to a semi-persistent KVS and asynchronously writes the in-memory data to YAML files.\n "
36
+ email: flip@x451.com
37
+ executables:
38
+ - oria
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - LICENSE
43
+ - README.markdown
44
+ files:
45
+ - LICENSE
46
+ - README.markdown
47
+ - Rakefile
48
+ - VERSION
49
+ - bin/oria
50
+ - lib/oria.rb
51
+ - lib/oria/client.rb
52
+ - lib/oria/errors.rb
53
+ - lib/oria/server.rb
54
+ - spec/oria_spec.rb
55
+ - spec/rcov.opts
56
+ - spec/spec.opts
57
+ - spec/spec_helper.rb
58
+ has_rdoc: true
59
+ homepage: http://github.com/flipsasser/oria
60
+ licenses: []
61
+
62
+ post_install_message:
63
+ rdoc_options:
64
+ - --charset=UTF-8
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ version:
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: "0"
78
+ version:
79
+ requirements: []
80
+
81
+ rubyforge_project:
82
+ rubygems_version: 1.3.5
83
+ signing_key:
84
+ specification_version: 3
85
+ summary: A Ruby-based, in-memory KVS with one half of the peristence you want
86
+ test_files:
87
+ - spec/oria_spec.rb
88
+ - spec/spec_helper.rb