juno 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -24,6 +24,7 @@ gem 'couchrest'
24
24
  gem 'sequel'
25
25
  gem 'dalli'
26
26
  gem 'riak-client'
27
+ gem 'hashery'
27
28
 
28
29
  if defined?(JRUBY_VERSION)
29
30
  gem 'jdbc-sqlite3'
data/README.md CHANGED
@@ -11,6 +11,7 @@ Out of the box, it supports:
11
11
 
12
12
  * Memory:
13
13
  * In-memory store (:Memory)
14
+ * LRU hash (:LRUHash)
14
15
  * LocalMemCache (:LocalMemCache)
15
16
  * Memcached store (:Memcached, :MemcachedNative and :MemcachedDalli)
16
17
  * Relational Databases:
@@ -38,10 +39,12 @@ Out of the box, it supports:
38
39
  * Fog cloud storage which supports Amazon S3, Rackspace, etc. (:Fog)
39
40
  * Storage which doesn't store anything (:Null)
40
41
 
41
- Special proxies:
42
- * Juno::Expires to add expiration support to stores
43
- * Juno::Stack to stack multiple stores
44
- * Juno::Proxy basic proxy class
42
+ In addition it supports proxies (Similar to [Rack middlewares](http://rack.rubyforge.org/)) which
43
+ add additional features to storage backends:
44
+
45
+ * Juno::Proxy proxy base class
46
+ * Juno::Expires to add expiration support to stores which don't support it natively
47
+ * Juno::Stack to stack multiple stores (Read returns result from first where the key is found, writes go to all stores)
45
48
  * Juno::Transformer transforms keys and values (Marshal, YAML, JSON, Base64, MD5, ...)
46
49
  * Juno::Cache combine two stores, one as backend and one as cache (e.g. Juno::Adapters::File + Juno::Adapters::Memory)
47
50
 
@@ -115,13 +118,14 @@ The Cassandra, Memcached and Redis backends supports expires values directly:
115
118
 
116
119
  ~~~ ruby
117
120
  cache = Juno::Adapters::Memcached.new
118
- # Expires in 10 seconds
119
- cache.store(key, value, :expires => 10)
120
121
 
121
122
  # Or using the builder...
122
123
  cache = Juno.build do
123
124
  adapter :Memcached
124
125
  end
126
+
127
+ # Expires in 60 seconds
128
+ cache.store(key, value, :expires => 60)
125
129
  ~~~
126
130
 
127
131
  You can add the expires feature to other backends using the Expires proxy:
@@ -130,9 +134,8 @@ You can add the expires feature to other backends using the Expires proxy:
130
134
  # Using the :expires option
131
135
  cache = Juno.new(:File, :dir => '...', :expires => true)
132
136
 
133
- # or using the proxy...
137
+ # or manually by using the proxy...
134
138
  cache = Juno::Expires.new(Juno::Adapters::File.new(:dir => '...'))
135
- cache.store(key, value, :expires => 10)
136
139
 
137
140
  # or using the builder...
138
141
  cache = Juno.build do
@@ -144,5 +147,5 @@ end
144
147
  Authors
145
148
  -------
146
149
 
147
- * Moneta originally by wycats
148
150
  * Juno by Daniel Mendler
151
+ * Moneta originally by wycats
data/SPEC.md CHANGED
@@ -6,10 +6,6 @@ The purpose of the juno specification is to create a general-purpose API for int
6
6
 
7
7
  Juno ships with a set of executable specs which you can use to verify spec-compliance with your juno adapter.
8
8
 
9
- # Juno Library
10
-
11
- Juno ships with proof-of-concept adapters for over a dozen key-value stores, including in-memory, memcache, database-backed and S3. These adapters are meant as proofs-of-concept, and while the juno project intends to maintain them (and will accept patches to improve them), you should not consider them the core of the project.
12
-
13
9
  # Requirements for a Juno Adapter
14
10
 
15
11
  (See RFC 2119 for use of MUST, SHOULD, MAY, MUST NOT, and SHOULD NOT)
@@ -32,10 +28,6 @@ Return the value stored in the key-value-store under the provided key. Adapters
32
28
 
33
29
  Store the value in the key-value-store under the provided key. Adapters MAY serialize the value using Ruby's Marshal system, and MUST NOT store a reference to the original value in the store, unless Ruby disallows duplication of the original value. Adapters SHOULD NOT simply call <code>dup</code> on the value, unless the value stores no references to other Object. For example, an adapter MAY store a <code>dup</code> of a String, but SHOULD NOT store a <code>dup</code> of <code>["hello", "world"]</code>.
34
30
 
35
- ### <code>fetch(key[Object]) => Object</code>
36
-
37
- Return the value stored in the key-value-store under the provided key. If no value is stored under the provided key, the adapter MUST raise an IndexError.
38
-
39
31
  ### <code>fetch(key[Object], &block) => Object</code>
40
32
 
41
33
  Return the value stored in the key-value-store under the provided key. If no value is stored under the provided key, the adapter MUST yield to the block, and return the value. The adapter MUST NOT store the value returned from the block in the key-value-store.
@@ -65,16 +57,13 @@ Completely empty all keys and values from the key-value-store. Adapters MAY allo
65
57
  The following methods may all take an additional Hash as a final argument. This allows the client to send additional options which can be specified by the adapter (and which may be specified by extensions to this specification).
66
58
 
67
59
  * fetch
60
+ * load
68
61
  * store
69
62
  * delete
70
63
  * key?
71
64
  * clear
72
65
 
73
- In the case of methods with optional arguments, the Hash MUST be provided as the final argument, and all optional arguments MUST be specified.
74
-
75
- Keys in this Hash MUST be Strings or Symbols. If they are Strings, they MUST be prefixed with a unique namespace. Namespaces MUST be separated from the name of the key with a single ".". The namespace SHOULD be the name of the gem that exposes the key.
76
-
77
- Keys in this Hash MUST NOT be Symbols unless this specification or an official extension to this specification defines a Symbol key.
66
+ In the case of methods with optional arguments, the Hash MUST be provided as the final argument. Keys in this Hash MUST be Symbols.
78
67
 
79
68
  # Key Equality
80
69
 
@@ -17,6 +17,7 @@ module Juno
17
17
  autoload :Fog, 'juno/adapters/fog'
18
18
  autoload :GDBM, 'juno/adapters/gdbm'
19
19
  autoload :LocalMemCache, 'juno/adapters/localmemcache'
20
+ autoload :LRUHash, 'juno/adapters/lruhash'
20
21
  autoload :Memcached, 'juno/adapters/memcached'
21
22
  autoload :MemcachedDalli, 'juno/adapters/memcached_dalli'
22
23
  autoload :MemcachedNative, 'juno/adapters/memcached_native'
@@ -38,11 +39,10 @@ module Juno
38
39
  transformer = {:key => :marshal, :value => :marshal}
39
40
  raise 'Name must be Symbol' unless Symbol === name
40
41
  case name
41
- when :Sequel, :ActiveRecord, :Couch, :Mongo
42
+ when :Sequel, :ActiveRecord, :Couch
42
43
  # Sequel accept only base64 keys and values
43
44
  # FIXME: ActiveRecord and Couch should work only with :marshal but this
44
45
  # raises an error on 1.9
45
- # Mongo accepts only valid UTF-8 strings
46
46
  transformer = {:key => [:marshal, :base64], :value => [:marshal, :base64]}
47
47
  when :Memcached, :MemcachedDalli, :MemcachedNative
48
48
  # Memcached accept only base64 keys, expires already supported
@@ -0,0 +1,12 @@
1
+ require 'hashery/lru_hash'
2
+
3
+ module Juno
4
+ module Adapters
5
+ class LRUHash < Memory
6
+ def initialize(options = {})
7
+ raise 'No option :max_size specified' unless options[:max_size]
8
+ @memory = Hashery::LRUHash.new(options[:max_size])
9
+ end
10
+ end
11
+ end
12
+ end
@@ -18,7 +18,7 @@ module Juno
18
18
 
19
19
  def load(key, options = {})
20
20
  value = @collection.find_one('_id' => key)
21
- value ? value['data'] : nil
21
+ value ? value['data'].to_s : nil
22
22
  end
23
23
 
24
24
  def delete(key, options = {})
@@ -29,8 +29,8 @@ module Juno
29
29
 
30
30
  def store(key, value, options = {})
31
31
  @collection.update({ '_id' => key },
32
- { '_id' => key, 'data' => value },
33
- { :upsert => true })
32
+ { '_id' => key, 'data' => ::BSON::Binary.new(value) },
33
+ { :upsert => true })
34
34
  value
35
35
  end
36
36
 
@@ -1,4 +1,14 @@
1
1
  module Juno
2
+ # Combines two stores. One is used as cache, the other as backend.
3
+ #
4
+ # Example:
5
+ #
6
+ # Juno.build do
7
+ # use(:Cache) do
8
+ # backend { adapter :File, :dir => 'data' }
9
+ # cache { adapter :Memory }
10
+ # end
11
+ # end
2
12
  class Cache < Base
3
13
  class DSL
4
14
  def initialize(options, &block)
@@ -1,4 +1,5 @@
1
1
  module Juno
2
+ # Adds expiration support to the underlying store
2
3
  class Expires < Proxy
3
4
  def key?(key, options = {})
4
5
  !!load(key, options)
@@ -1,4 +1,5 @@
1
1
  module Juno
2
+ # Proxy base class
2
3
  class Proxy < Base
3
4
  attr_reader :adapter
4
5
 
@@ -1,4 +1,16 @@
1
1
  module Juno
2
+ # Combines multiple stores. Reads return the result from the first store,
3
+ # writes go to all stores.
4
+ #
5
+ # Example:
6
+ #
7
+ # Juno.build do
8
+ # use(:Stack) do
9
+ # add { adapter :Redis }
10
+ # add { adapter :File, :dir => 'data' }
11
+ # add { adapter :File, :dir => 'replicate' }
12
+ # end
13
+ # end
2
14
  class Stack < Base
3
15
  class DSL
4
16
  attr_reader :stack
@@ -1,4 +1,12 @@
1
1
  module Juno
2
+ # Transforms keys and values (Marshal, YAML, JSON, Base64, MD5, ...).
3
+ #
4
+ # Example:
5
+ #
6
+ # Juno.build do
7
+ # transformer :key => [:marshal, :escape], :value => [:marshal]
8
+ # adapter :File, :dir => 'data'
9
+ # end
2
10
  class Transformer < Proxy
3
11
  VALUE_TRANSFORMER = {
4
12
  :marshal => { :load => '::Marshal.load(VALUE)', :dump => '::Marshal.dump(VALUE)' },
@@ -1,3 +1,3 @@
1
1
  module Juno
2
- VERSION = '0.2.1'
2
+ VERSION = '0.2.2'
3
3
  end
@@ -0,0 +1,42 @@
1
+ # Generated file
2
+ require 'helper'
3
+
4
+ begin
5
+ Juno::Adapters::LRUHash.new(:max_size => 10).close
6
+
7
+ describe "adapter_lruhash" do
8
+ before do
9
+ @store = Juno::Adapters::LRUHash.new(:max_size => 10)
10
+ @store.clear
11
+ end
12
+
13
+ after do
14
+ @store.close.should == nil if @store
15
+ end
16
+
17
+ it_should_behave_like 'null_objectkey_objectvalue'
18
+ it_should_behave_like 'null_objectkey_stringvalue'
19
+ it_should_behave_like 'null_objectkey_hashvalue'
20
+ it_should_behave_like 'null_stringkey_objectvalue'
21
+ it_should_behave_like 'null_stringkey_stringvalue'
22
+ it_should_behave_like 'null_stringkey_hashvalue'
23
+ it_should_behave_like 'null_hashkey_objectvalue'
24
+ it_should_behave_like 'null_hashkey_stringvalue'
25
+ it_should_behave_like 'null_hashkey_hashvalue'
26
+ it_should_behave_like 'store_objectkey_objectvalue'
27
+ it_should_behave_like 'store_objectkey_stringvalue'
28
+ it_should_behave_like 'store_objectkey_hashvalue'
29
+ it_should_behave_like 'store_stringkey_objectvalue'
30
+ it_should_behave_like 'store_stringkey_stringvalue'
31
+ it_should_behave_like 'store_stringkey_hashvalue'
32
+ it_should_behave_like 'store_hashkey_objectvalue'
33
+ it_should_behave_like 'store_hashkey_stringvalue'
34
+ it_should_behave_like 'store_hashkey_hashvalue'
35
+
36
+ end
37
+ rescue LoadError => ex
38
+ puts "Test adapter_lruhash not executed: #{ex.message}"
39
+ rescue Exception => ex
40
+ puts "Test adapter_lruhash not executed: #{ex.message}"
41
+ #puts "#{ex.backtrace.join("\n")}"
42
+ end
@@ -11,6 +11,15 @@ TESTS = {
11
11
  :options => ':expires => true',
12
12
  :specs => EXPIRES_SPECS,
13
13
  },
14
+ 'simple_lruhash' => {
15
+ :store => :LRUHash,
16
+ :options => ':max_size => 10',
17
+ },
18
+ 'simple_lruhash_with_expires' => {
19
+ :store => :LRUHash,
20
+ :options => ':expires => true, :max_size => 10',
21
+ :specs => EXPIRES_SPECS,
22
+ },
14
23
  'simple_file' => {
15
24
  :store => :File,
16
25
  :options => ':dir => File.join(make_tempdir, "simple_file")'
@@ -510,6 +519,10 @@ end
510
519
  :build => 'Juno::Adapters::Memory.new',
511
520
  :specs => [:null, :store]
512
521
  },
522
+ 'adapter_lruhash' => {
523
+ :build => 'Juno::Adapters::LRUHash.new(:max_size => 10)',
524
+ :specs => [:null, :store]
525
+ },
513
526
  'adapter_mongo' => {
514
527
  :build => 'Juno::Adapters::Mongo.new(:db => "adapter_mongo")',
515
528
  :specs => ADAPTER_SPECS
@@ -0,0 +1,52 @@
1
+ # Generated file
2
+ require 'helper'
3
+
4
+ begin
5
+ Juno.new(:LRUHash, :max_size => 10).close
6
+
7
+ describe "simple_lruhash" do
8
+ before do
9
+ @store = Juno.new(:LRUHash, :max_size => 10)
10
+ @store.clear
11
+ end
12
+
13
+ after do
14
+ @store.close.should == nil if @store
15
+ end
16
+
17
+ it_should_behave_like 'null_objectkey_objectvalue'
18
+ it_should_behave_like 'null_objectkey_stringvalue'
19
+ it_should_behave_like 'null_objectkey_hashvalue'
20
+ it_should_behave_like 'null_stringkey_objectvalue'
21
+ it_should_behave_like 'null_stringkey_stringvalue'
22
+ it_should_behave_like 'null_stringkey_hashvalue'
23
+ it_should_behave_like 'null_hashkey_objectvalue'
24
+ it_should_behave_like 'null_hashkey_stringvalue'
25
+ it_should_behave_like 'null_hashkey_hashvalue'
26
+ it_should_behave_like 'store_objectkey_objectvalue'
27
+ it_should_behave_like 'store_objectkey_stringvalue'
28
+ it_should_behave_like 'store_objectkey_hashvalue'
29
+ it_should_behave_like 'store_stringkey_objectvalue'
30
+ it_should_behave_like 'store_stringkey_stringvalue'
31
+ it_should_behave_like 'store_stringkey_hashvalue'
32
+ it_should_behave_like 'store_hashkey_objectvalue'
33
+ it_should_behave_like 'store_hashkey_stringvalue'
34
+ it_should_behave_like 'store_hashkey_hashvalue'
35
+ it_should_behave_like 'returndifferent_objectkey_objectvalue'
36
+ it_should_behave_like 'returndifferent_objectkey_stringvalue'
37
+ it_should_behave_like 'returndifferent_objectkey_hashvalue'
38
+ it_should_behave_like 'returndifferent_stringkey_objectvalue'
39
+ it_should_behave_like 'returndifferent_stringkey_stringvalue'
40
+ it_should_behave_like 'returndifferent_stringkey_hashvalue'
41
+ it_should_behave_like 'returndifferent_hashkey_objectvalue'
42
+ it_should_behave_like 'returndifferent_hashkey_stringvalue'
43
+ it_should_behave_like 'returndifferent_hashkey_hashvalue'
44
+ it_should_behave_like 'marshallable_key'
45
+
46
+ end
47
+ rescue LoadError => ex
48
+ puts "Test simple_lruhash not executed: #{ex.message}"
49
+ rescue Exception => ex
50
+ puts "Test simple_lruhash not executed: #{ex.message}"
51
+ #puts "#{ex.backtrace.join("\n")}"
52
+ end
@@ -0,0 +1,53 @@
1
+ # Generated file
2
+ require 'helper'
3
+
4
+ begin
5
+ Juno.new(:LRUHash, :expires => true, :max_size => 10).close
6
+
7
+ describe "simple_lruhash_with_expires" do
8
+ before do
9
+ @store = Juno.new(:LRUHash, :expires => true, :max_size => 10)
10
+ @store.clear
11
+ end
12
+
13
+ after do
14
+ @store.close.should == nil if @store
15
+ end
16
+
17
+ it_should_behave_like 'null_objectkey_objectvalue'
18
+ it_should_behave_like 'null_objectkey_stringvalue'
19
+ it_should_behave_like 'null_objectkey_hashvalue'
20
+ it_should_behave_like 'null_stringkey_objectvalue'
21
+ it_should_behave_like 'null_stringkey_stringvalue'
22
+ it_should_behave_like 'null_stringkey_hashvalue'
23
+ it_should_behave_like 'null_hashkey_objectvalue'
24
+ it_should_behave_like 'null_hashkey_stringvalue'
25
+ it_should_behave_like 'null_hashkey_hashvalue'
26
+ it_should_behave_like 'store_objectkey_objectvalue'
27
+ it_should_behave_like 'store_objectkey_stringvalue'
28
+ it_should_behave_like 'store_objectkey_hashvalue'
29
+ it_should_behave_like 'store_stringkey_objectvalue'
30
+ it_should_behave_like 'store_stringkey_stringvalue'
31
+ it_should_behave_like 'store_stringkey_hashvalue'
32
+ it_should_behave_like 'store_hashkey_objectvalue'
33
+ it_should_behave_like 'store_hashkey_stringvalue'
34
+ it_should_behave_like 'store_hashkey_hashvalue'
35
+ it_should_behave_like 'returndifferent_objectkey_objectvalue'
36
+ it_should_behave_like 'returndifferent_objectkey_stringvalue'
37
+ it_should_behave_like 'returndifferent_objectkey_hashvalue'
38
+ it_should_behave_like 'returndifferent_stringkey_objectvalue'
39
+ it_should_behave_like 'returndifferent_stringkey_stringvalue'
40
+ it_should_behave_like 'returndifferent_stringkey_hashvalue'
41
+ it_should_behave_like 'returndifferent_hashkey_objectvalue'
42
+ it_should_behave_like 'returndifferent_hashkey_stringvalue'
43
+ it_should_behave_like 'returndifferent_hashkey_hashvalue'
44
+ it_should_behave_like 'marshallable_key'
45
+ it_should_behave_like 'expires_stringkey_stringvalue'
46
+
47
+ end
48
+ rescue LoadError => ex
49
+ puts "Test simple_lruhash_with_expires not executed: #{ex.message}"
50
+ rescue Exception => ex
51
+ puts "Test simple_lruhash_with_expires not executed: #{ex.message}"
52
+ #puts "#{ex.backtrace.join("\n")}"
53
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: juno
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2012-11-24 00:00:00.000000000 Z
14
+ date: 2012-11-26 00:00:00.000000000 Z
15
15
  dependencies: []
16
16
  description: A unified interface to key/value stores (moneta replacement)
17
17
  email:
@@ -44,6 +44,7 @@ files:
44
44
  - lib/juno/adapters/fog.rb
45
45
  - lib/juno/adapters/gdbm.rb
46
46
  - lib/juno/adapters/localmemcache.rb
47
+ - lib/juno/adapters/lruhash.rb
47
48
  - lib/juno/adapters/memcached.rb
48
49
  - lib/juno/adapters/memcached_dalli.rb
49
50
  - lib/juno/adapters/memcached_native.rb
@@ -75,6 +76,7 @@ files:
75
76
  - spec/adapter_fog_spec.rb
76
77
  - spec/adapter_gdbm_spec.rb
77
78
  - spec/adapter_localmemcache_spec.rb
79
+ - spec/adapter_lruhash_spec.rb
78
80
  - spec/adapter_memcached_dalli_spec.rb
79
81
  - spec/adapter_memcached_native_spec.rb
80
82
  - spec/adapter_memcached_spec.rb
@@ -119,6 +121,8 @@ files:
119
121
  - spec/simple_hashfile_with_expires_spec.rb
120
122
  - spec/simple_localmemcache_spec.rb
121
123
  - spec/simple_localmemcache_with_expires_spec.rb
124
+ - spec/simple_lruhash_spec.rb
125
+ - spec/simple_lruhash_with_expires_spec.rb
122
126
  - spec/simple_memcached_dalli_spec.rb
123
127
  - spec/simple_memcached_native_spec.rb
124
128
  - spec/simple_memcached_spec.rb
@@ -187,6 +191,7 @@ test_files:
187
191
  - spec/adapter_fog_spec.rb
188
192
  - spec/adapter_gdbm_spec.rb
189
193
  - spec/adapter_localmemcache_spec.rb
194
+ - spec/adapter_lruhash_spec.rb
190
195
  - spec/adapter_memcached_dalli_spec.rb
191
196
  - spec/adapter_memcached_native_spec.rb
192
197
  - spec/adapter_memcached_spec.rb
@@ -231,6 +236,8 @@ test_files:
231
236
  - spec/simple_hashfile_with_expires_spec.rb
232
237
  - spec/simple_localmemcache_spec.rb
233
238
  - spec/simple_localmemcache_with_expires_spec.rb
239
+ - spec/simple_lruhash_spec.rb
240
+ - spec/simple_lruhash_with_expires_spec.rb
234
241
  - spec/simple_memcached_dalli_spec.rb
235
242
  - spec/simple_memcached_native_spec.rb
236
243
  - spec/simple_memcached_spec.rb