moneta 0.7.2 → 0.7.3

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,4 +1,10 @@
1
- master
1
+ 0.7.3
2
+
3
+ * Added Adapters::RestClient
4
+ * Added Rack::MonetaRest
5
+ * Added Rack::MonetaStore
6
+
7
+ 0.7.2
2
8
 
3
9
  * Renamed WithOptions to OptionSupport
4
10
  * Refactored Base in Defaults mixin
data/Gemfile CHANGED
@@ -44,6 +44,7 @@ gem 'sequel'
44
44
  gem 'dalli'
45
45
  gem 'riak-client'
46
46
  gem 'cassandra'
47
+ gem 'httpi'
47
48
  #gem 'hbaserb'
48
49
  #gem 'localmemcache'
49
50
  alternatives :mri => 'leveldb-ruby'
data/README.md CHANGED
@@ -12,7 +12,7 @@ Moneta provides a standard interface for interacting with various kinds of key/v
12
12
  * Expiration for all stores (Added via proxy `Moneta::Expires` if not supported natively)
13
13
  * Atomic incrementation and decrementation for most stores (Method `#increment` and `#decrement`)
14
14
  * Includes a very simple key/value server (`Moneta::Server`) and client (`Moneta::Adapters::Client`)
15
- * Integration with [Rails](http://rubyonrails.org/), [Rack](http://rack.github.com/) as cookie and session store and [Rack-Cache](https://github.com/rtomayko/rack-cache)
15
+ * Integration with [Rails](http://rubyonrails.org/), [Rack](http://rack.github.com/), [Sinatra](http://sinatrarb.com/) and [Rack-Cache](https://github.com/rtomayko/rack-cache)
16
16
 
17
17
  Moneta is tested thoroughly using [Travis-CI](http://travis-ci.org/minad/moneta).
18
18
 
@@ -56,8 +56,10 @@ Out of the box, it supports the following backends:
56
56
  * Document databases:
57
57
  * CouchDB (`:Couch`)
58
58
  * MongoDB (`:Mongo`)
59
+ * Moneta network protocols:
60
+ * Moneta key/value client (`:Client` works with `Moneta::Server`)
61
+ * Moneta HTTP/REST client (`:RestClient` works with `Rack::MonetaRest`)
59
62
  * Other
60
- * Moneta key/value server client (`:Client` works with `Moneta::Server`)
61
63
  * Fog cloud storage which supports Amazon S3, Rackspace, etc. (`:Fog`)
62
64
  * Storage which doesn't store anything (`:Null`)
63
65
 
@@ -309,11 +311,21 @@ short_lived_store['key'] = 'value'
309
311
 
310
312
  ## Framework Integration
311
313
 
312
- Inspired by [redis-store](https://github.com/jodosha/redis-store) there exist integration classes for [Rails](http://rubyonrails.org/), [Rack](http://rack.github.com/) and [Rack-Cache](https://github.com/rtomayko/rack-cache).
314
+ Inspired by [redis-store](https://github.com/jodosha/redis-store) there exist integration classes for [Rails](http://rubyonrails.org/), [Rack](http://rack.github.com/) and [Rack-Cache](https://github.com/rtomayko/rack-cache). You can also use all the Rack middlewares together with the [Sinatra](http://sinatrarb.com/) framework. There exist the following integration classes:
315
+
316
+ * Rack and Sinatra
317
+ * `Rack::Session::Moneta` is a Rack middleware to use Moneta for storing sessions
318
+ * `Rack::MonetaStore` is a Rack middleware which places a Moneta store in the environment and enables per-request caching
319
+ * `Rack::MonetaCookies` is a Rack middleware which uses Moneta to store cookies
320
+ * `Rack::MonetaRest` is a Rack application which exposes a Moneta store via REST/HTTP
321
+ * `Rack::Cache::Moneta` provides meta and entity stores for Rack-Cache
322
+ * Rails
323
+ * `ActionDispatch::Session::MonetaStore` is a Rails middleware to use Moneta for storing sessions
324
+ * `ActiveSupport::Cache::MonetaStore` is a Rails cache implementation which uses a Moneta store as backend
313
325
 
314
326
  ### Rack session store
315
327
 
316
- Use Moneta as a [Rack](http://rack.github.com/) session store:
328
+ You can use Moneta as a [Rack](http://rack.github.com/) session store. Use it in your `config.ru` like this:
317
329
 
318
330
  ~~~ ruby
319
331
  require 'rack/session/moneta'
@@ -331,9 +343,51 @@ use Rack::Session::Moneta do
331
343
  end
332
344
  ~~~
333
345
 
346
+ ### Rack Moneta middleware
347
+
348
+ There is a simple middleware which places a Moneta store in the Rack environment at `env['rack.moneta_store']`. It supports per-request
349
+ caching if you add the option `:cache => true`. Use it in your `config.ru` like this:
350
+
351
+ ~~~ ruby
352
+ # Add Rack::MonetaStore somewhere in your rack stack
353
+ use Rack::MonetaStore, :Memory, :cache => true
354
+
355
+ run lambda do |env|
356
+ env['rack.moneta_store'] # is a Moneta store with per-request caching
357
+ end
358
+
359
+ # Pass it a block like the one passed to Moneta.build
360
+ use Rack::MonetaStore do
361
+ use :Transformer, :value => :zlib
362
+ adapter :Cookie
363
+ end
364
+
365
+ run lambda do |env|
366
+ env['rack.moneta_store'] # is a Moneta store without caching
367
+ end
368
+ ~~~
369
+
370
+ ### Rack REST server
371
+
372
+ If you want to expose your Moneta key/value store via HTTP, you can use the Rack/Moneta REST service. Use it in your `config.ru` like this:
373
+
374
+ ~~~ ruby
375
+ require 'rack/moneta_rest'
376
+
377
+ map '/moneta' do
378
+ run Rack::MonetaRest.new(:Memory)
379
+ end
380
+
381
+ # Or pass it a block like the one passed to Moneta.build
382
+ run Rack::MonetaRest.new do
383
+ use :Transformer, :value => :zlib
384
+ adapter :Memory
385
+ end
386
+ ~~~
387
+
334
388
  ### Rack cache
335
389
 
336
- Use Moneta as a [Rack-Cache](https://github.com/rtomayko/rack-cache) store:
390
+ You can use Moneta as a [Rack-Cache](https://github.com/rtomayko/rack-cache) store. Use it in your `config.ru` like this:
337
391
 
338
392
  ~~~ ruby
339
393
  require 'rack/cache/moneta'
data/lib/moneta.rb CHANGED
@@ -40,6 +40,7 @@ module Moneta
40
40
  autoload :Null, 'moneta/adapters/null'
41
41
  autoload :PStore, 'moneta/adapters/pstore'
42
42
  autoload :Redis, 'moneta/adapters/redis'
43
+ autoload :RestClient, 'moneta/adapters/restclient'
43
44
  autoload :Riak, 'moneta/adapters/riak'
44
45
  autoload :SDBM, 'moneta/adapters/sdbm'
45
46
  autoload :Sequel, 'moneta/adapters/sequel'
@@ -93,7 +94,7 @@ module Moneta
93
94
  # FIXME: Couch should work only with :marshal but this raises an error on 1.9
94
95
  transformer[:key] << :base64
95
96
  transformer[:value] << :base64
96
- when :Riak
97
+ when :Riak, :RestClient
97
98
  # Riak accepts only utf-8 keys over the http interface
98
99
  # We use base64 encoding therefore.
99
100
  transformer[:key] << :base64
@@ -125,8 +126,9 @@ module Moneta
125
126
  end
126
127
  end
127
128
 
128
- # Configure your own Moneta proxy stack!
129
+ # Configure your own Moneta proxy stack
129
130
  #
131
+ # @yieldparam Builder block
130
132
  # @return [Moneta store] newly created Moneta store
131
133
  #
132
134
  # @example Moneta builder
@@ -1,6 +1,6 @@
1
1
  module Moneta
2
2
  module Adapters
3
- # Cookie backend used by `Rack::MonetaCookies`
3
+ # Cookie backend used by the middleware `Rack::MonetaCookies`
4
4
  # @api public
5
5
  class Cookie < Memory
6
6
  attr_reader :cookies
@@ -32,6 +32,8 @@ module Moneta
32
32
  self
33
33
  end
34
34
 
35
+ # Reset the cookie store
36
+ # This method is used by the middleware.
35
37
  def reset(cookies)
36
38
  @cookies, @hash = {}, cookies
37
39
  end
@@ -17,14 +17,14 @@ module Moneta
17
17
  # (see Proxy#key?)
18
18
  def key?(key, options = {})
19
19
  @db.get(key) != nil
20
- rescue RestClient::ResourceNotFound
20
+ rescue ::RestClient::ResourceNotFound
21
21
  false
22
22
  end
23
23
 
24
24
  # (see Proxy#load)
25
25
  def load(key, options = {})
26
26
  @db.get(key)['value']
27
- rescue RestClient::ResourceNotFound
27
+ rescue ::RestClient::ResourceNotFound
28
28
  nil
29
29
  end
30
30
 
@@ -33,11 +33,11 @@ module Moneta
33
33
  doc = {'_id' => key, 'value' => value}
34
34
  begin
35
35
  doc['_rev'] = @db.get(key)['_rev']
36
- rescue RestClient::ResourceNotFound
36
+ rescue ::RestClient::ResourceNotFound
37
37
  end
38
38
  @db.save_doc(doc)
39
39
  value
40
- rescue RestClient::RequestFailed
40
+ rescue ::RestClient::RequestFailed
41
41
  value
42
42
  end
43
43
 
@@ -46,7 +46,7 @@ module Moneta
46
46
  value = @db.get(key)
47
47
  @db.delete_doc('_id' => value['_id'], '_rev' => value['_rev'])
48
48
  value['value']
49
- rescue RestClient::ResourceNotFound
49
+ rescue ::RestClient::ResourceNotFound
50
50
  nil
51
51
  end
52
52
 
@@ -7,6 +7,7 @@ module Moneta
7
7
  include HashAdapter
8
8
  include IncrementSupport
9
9
 
10
+ # @param [Hash] options Options hash
10
11
  def initialize(options = {})
11
12
  @hash = {}
12
13
  end
@@ -5,6 +5,7 @@ module Moneta
5
5
  class Null
6
6
  include Defaults
7
7
 
8
+ # @param [Hash] options Options hash
8
9
  def initialize(options = {})
9
10
  end
10
11
 
@@ -0,0 +1,47 @@
1
+ require 'httpi'
2
+
3
+ module Moneta
4
+ module Adapters
5
+ # Moneta rest client backend which works together with `Rack::MonetaRest`
6
+ # @api public
7
+ class RestClient
8
+ include Defaults
9
+
10
+ # @param [Hash] options
11
+ # @option options [String] :url URL
12
+ def initialize(options = {})
13
+ raise ArgumentError, 'Option :url is required' unless @url = options[:url]
14
+ end
15
+
16
+ # (see Proxy#key?)
17
+ def key?(key, options = {})
18
+ response = HTTPI.head(@url + key)
19
+ response.code == 200
20
+ end
21
+
22
+ # (see Proxy#load)
23
+ def load(key, options = {})
24
+ response = HTTPI.get(@url + key)
25
+ response.code == 200 ? response.body : nil
26
+ end
27
+
28
+ # (see Proxy#store)
29
+ def store(key, value, options = {})
30
+ HTTPI.post(@url + key, value)
31
+ value
32
+ end
33
+
34
+ # (see Proxy#delete)
35
+ def delete(key, options = {})
36
+ response = HTTPI.delete(@url + key)
37
+ response.code == 200 ? response.body : nil
38
+ end
39
+
40
+ # (see Proxy#clear)
41
+ def clear(options = {})
42
+ HTTPI.delete(@url)
43
+ self
44
+ end
45
+ end
46
+ end
47
+ end
@@ -2,6 +2,7 @@ module Moneta
2
2
  # Builder implements the DSL to build a stack of Moneta store proxies
3
3
  # @api private
4
4
  class Builder
5
+ # @yieldparam Builder dsl code block
5
6
  def initialize(&block)
6
7
  raise ArgumentError, 'No block given' unless block_given?
7
8
  @proxies = []
@@ -9,6 +10,7 @@ module Moneta
9
10
  end
10
11
 
11
12
  # Build proxy stack
13
+ #
12
14
  # @return [Object] Generated Moneta proxy stack
13
15
  # @api public
14
16
  def build
data/lib/moneta/cache.rb CHANGED
@@ -15,34 +15,35 @@ module Moneta
15
15
 
16
16
  # @api private
17
17
  class DSL
18
- def initialize(options, &block)
19
- @cache, @backend = options[:cache], options[:backend]
18
+ def initialize(store, &block)
19
+ @store = store
20
20
  instance_eval(&block)
21
21
  end
22
22
 
23
23
  # @api public
24
24
  def backend(store = nil, &block)
25
- raise 'Backend already set' if @backend
25
+ raise 'Backend already set' if @store.backend
26
26
  raise ArgumentError, 'Only argument or block allowed' if store && block
27
- @backend = store || Moneta.build(&block)
27
+ @store.backend = store || Moneta.build(&block)
28
28
  end
29
29
 
30
30
  # @api public
31
31
  def cache(store = nil, &block)
32
- raise 'Cache already set' if @cache
32
+ raise 'Cache already set' if @store.cache
33
33
  raise ArgumentError, 'Only argument or block allowed' if store && block
34
- @cache = store || Moneta.build(&block)
35
- end
36
-
37
- def result
38
- [@cache, @backend]
34
+ @store.cache = store || Moneta.build(&block)
39
35
  end
40
36
  end
41
37
 
42
- attr_reader :cache, :backend
38
+ attr_accessor :cache, :backend
43
39
 
40
+ # @param [Hash] options Options hash
41
+ # @option options [Moneta store] :cache Moneta store used as cache
42
+ # @option options [Moneta store] :backend Moneta store used as backend
43
+ # @yieldparam Builder block
44
44
  def initialize(options = {}, &block)
45
- @cache, @backend = DSL.new(options, &block).result
45
+ @cache, @backend = options[:cache], options[:backend]
46
+ DSL.new(self, &block) if block_given?
46
47
  end
47
48
 
48
49
  # (see Proxy#key?)
@@ -14,6 +14,7 @@ module Moneta
14
14
  @expires = options[:expires]
15
15
  end
16
16
 
17
+ # (see Proxy#key?)
17
18
  def key?(key, options = {})
18
19
  # Transformer might raise exception
19
20
  load_entry(key, options) != nil
@@ -22,12 +23,14 @@ module Moneta
22
23
  super(key, options)
23
24
  end
24
25
 
26
+ # (see Proxy#load)
25
27
  def load(key, options = {})
26
28
  return super if options.include?(:raw)
27
29
  value, expires = load_entry(key, options)
28
30
  value
29
31
  end
30
32
 
33
+ # (see Proxy#store)
31
34
  def store(key, value, options = {})
32
35
  return super if options.include?(:raw)
33
36
  expires = options.include?(:expires) && (options = options.dup; options.delete(:expires))
@@ -41,6 +44,7 @@ module Moneta
41
44
  value
42
45
  end
43
46
 
47
+ # (see Proxy#delete)
44
48
  def delete(key, options = {})
45
49
  return super if options.include?(:raw)
46
50
  value, expires = super
data/lib/moneta/mixins.rb CHANGED
@@ -1,11 +1,18 @@
1
1
  module Moneta
2
2
  # @api private
3
3
  module OptionSupport
4
+ # Return Moneta store with default options
5
+ #
6
+ # @param [Hash] options Options to merge
7
+ # @return [OptionMerger]
4
8
  # @api public
5
9
  def with(options)
6
10
  OptionMerger.new(self, options)
7
11
  end
8
12
 
13
+ # Return Moneta store with default option :raw => true
14
+ #
15
+ # @return [OptionMerger]
9
16
  # @api public
10
17
  def raw
11
18
  @raw_store ||=
@@ -16,11 +23,19 @@ module Moneta
16
23
  end
17
24
  end
18
25
 
26
+ # Return Moneta store with default prefix option
27
+ #
28
+ # @param [String] prefix Key prefix
29
+ # @return [OptionMerger]
19
30
  # @api public
20
31
  def prefix(prefix)
21
32
  with(:prefix => prefix, :except => :clear)
22
33
  end
23
34
 
35
+ # Return Moneta store with default expiration time
36
+ #
37
+ # @param [Integer] expires Default expiration time
38
+ # @return [OptionMerger]
24
39
  # @api public
25
40
  def expires(expires)
26
41
  with(:expires => expires, :only => [:store, :increment])
@@ -35,8 +50,8 @@ module Moneta
35
50
  # Exists the value with key
36
51
  #
37
52
  # @param [Object] key
38
- # @return [Boolean]
39
53
  # @param [Hash] options
54
+ # @return [Boolean]
40
55
  # @api public
41
56
  def key?(key, options = {})
42
57
  load(key, options) != nil
@@ -44,11 +59,10 @@ module Moneta
44
59
 
45
60
  # Atomically increment integer value with key
46
61
  #
47
- # Not every Moneta store implements this method,
48
- # a NotImplementedError if it is not supported.
49
- #
50
62
  # This method also accepts negative amounts.
51
63
  #
64
+ # @note Not every Moneta store implements this method,
65
+ # a NotImplementedError is raised if it is not supported.
52
66
  # @param [Object] key
53
67
  # @param [Integer] amount
54
68
  # @param [Hash] options
@@ -5,6 +5,8 @@ module Moneta
5
5
 
6
6
  attr_reader :default_options
7
7
 
8
+ # @param [Moneta store] adapter underlying adapter
9
+ # @param [Hash] options
8
10
  def initialize(adapter, options = {})
9
11
  super(adapter, options)
10
12
 
data/lib/moneta/server.rb CHANGED
@@ -19,10 +19,16 @@ module Moneta
19
19
  @running = false
20
20
  end
21
21
 
22
+ # Is the server running
23
+ #
24
+ # @return [Boolean] true if the server is running
22
25
  def running?
23
26
  @running
24
27
  end
25
28
 
29
+ # Run the server
30
+ #
31
+ # @note This method blocks!
26
32
  def run
27
33
  raise 'Already running' if @running
28
34
  @stop = false
@@ -36,6 +42,7 @@ module Moneta
36
42
  end
37
43
  end
38
44
 
45
+ # Stop the server
39
46
  def stop
40
47
  raise 'Not running' unless @running
41
48
  @stop = true
data/lib/moneta/shared.rb CHANGED
@@ -20,6 +20,7 @@ module Moneta
20
20
  @builder = Builder.new(&block)
21
21
  end
22
22
 
23
+ # (see Proxy#close)
23
24
  def close
24
25
  if @server
25
26
  @server.stop
data/lib/moneta/stack.rb CHANGED
@@ -17,10 +17,8 @@ module Moneta
17
17
 
18
18
  # @api private
19
19
  class DSL
20
- attr_reader :stack
21
-
22
- def initialize(options, &block)
23
- @stack = options[:stack].to_a
20
+ def initialize(stack, &block)
21
+ @stack = stack
24
22
  instance_eval(&block)
25
23
  end
26
24
 
@@ -34,8 +32,12 @@ module Moneta
34
32
 
35
33
  attr_reader :stack
36
34
 
35
+ # @param [Hash] options Options hash
36
+ # @option options [Array] :stack Array of Moneta stores
37
+ # @yieldparam Builder block
37
38
  def initialize(options = {}, &block)
38
- @stack = DSL.new(options, &block).stack
39
+ @stack = options[:stack].to_a
40
+ DSL.new(@stack, &block) if block_given?
39
41
  end
40
42
 
41
43
  # (see Proxy#key?)
@@ -1,5 +1,5 @@
1
1
  module Moneta
2
2
  # Moneta version number
3
3
  # @api public
4
- VERSION = '0.7.2'
4
+ VERSION = '0.7.3'
5
5
  end
@@ -2,30 +2,37 @@ module Moneta
2
2
  # Wraps the calls to the adapter
3
3
  # @api public
4
4
  class Wrapper < Proxy
5
+ # (see Proxy#key?)
5
6
  def key?(key, options = {})
6
7
  wrap(:key?, key, options) { super }
7
8
  end
8
9
 
10
+ # (see Proxy#load)
9
11
  def load(key, options = {})
10
12
  wrap(:load, key, options) { super }
11
13
  end
12
14
 
15
+ # (see Proxy#store)
13
16
  def store(key, value, options = {})
14
17
  wrap(:store, key, value, options) { super }
15
18
  end
16
19
 
20
+ # (see Proxy#delete)
17
21
  def delete(key, options = {})
18
22
  wrap(:delete, key, options) { super }
19
23
  end
20
24
 
25
+ # (see Proxy#increment)
21
26
  def increment(key, amount = 1, options = {})
22
27
  wrap(:increment, key, amount, options) { super }
23
28
  end
24
29
 
30
+ # (see Proxy#clear)
25
31
  def clear(options = {})
26
32
  wrap(:clear, options) { super }
27
33
  end
28
34
 
35
+ # (see Proxy#close)
29
36
  def close
30
37
  wrap(:close) { super }
31
38
  end
@@ -47,7 +47,7 @@ module Rack
47
47
 
48
48
  def call(env)
49
49
  stores = @pool.pop || @builder.build
50
- env['rack.request.cookie_hash'] = stores.last
50
+ env['rack.moneta_cookies'] = env['rack.request.cookie_hash'] = stores.last
51
51
  env['rack.request.cookie_string'] = env['HTTP_COOKIE']
52
52
  stores.first.reset(Rack::Utils.parse_query(env['HTTP_COOKIE']))
53
53
  status, headers, body = @app.call(env)
@@ -1,13 +1,28 @@
1
1
  require 'moneta'
2
2
 
3
3
  module Rack
4
+ # A Rack application which provides a REST interface to a Moneta store.
5
+ #
6
+ # @example config.ru
7
+ # map '/moneta' do
8
+ # run Rack::MonetaRest.new(:Memory)
9
+ # end
10
+ #
11
+ # @example config.ru
12
+ # # Pass it a block like the one passed to Moneta.build
13
+ # run Rack::MonetaRest.new do
14
+ # use :Transformer, :value => :zlib
15
+ # adapter :Memory
16
+ # end
17
+ #
18
+ # @api public
4
19
  class MonetaRest
5
20
  def initialize(store = nil, options = {}, &block)
6
21
  if block
7
- raise ArgumentError, 'Use either block or options' unless options.emtpy?
22
+ raise ArgumentError, 'Use either block or options' unless options.empty?
8
23
  @store = ::Moneta.build(&block)
9
24
  else
10
- raise ArgumentError, 'Option :store is required' unless @store = store
25
+ raise ArgumentError, 'Block or argument store is required' unless @store = store
11
26
  @store = ::Moneta.new(@store, options) if Symbol === @store
12
27
  end
13
28
  end
@@ -16,19 +31,27 @@ module Rack
16
31
  key = env['PATH_INFO'][1..-1]
17
32
  case env['REQUEST_METHOD']
18
33
  when 'HEAD'
19
- if @store.key?(key)
20
- respond(200)
34
+ if key.empty?
35
+ respond(400, 'Empty key')
36
+ elsif @store.key?(key)
37
+ empty(200)
21
38
  else
22
39
  empty(404)
23
40
  end
24
41
  when 'GET'
25
- if value = @store[key]
42
+ if key.empty?
43
+ respond(400, 'Empty key')
44
+ elsif value = @store[key]
26
45
  respond(200, value)
27
46
  else
28
47
  empty(404)
29
48
  end
30
49
  when 'POST', 'PUT'
31
- respond(200, @store[key] = env['rack.input'].read)
50
+ if key.empty?
51
+ respond(400, 'Empty key')
52
+ else
53
+ respond(200, @store[key] = env['rack.input'].read)
54
+ end
32
55
  when 'DELETE'
33
56
  if key.empty?
34
57
  @store.clear
@@ -37,10 +60,10 @@ module Rack
37
60
  respond(200, @store.delete(key))
38
61
  end
39
62
  else
40
- empty(400)
63
+ respond(400, 'Bad method')
41
64
  end
42
65
  rescue => ex
43
- respond(500, ex.message)
66
+ respond(500, "Exception: #{ex.message}")
44
67
  end
45
68
 
46
69
  private
@@ -0,0 +1,45 @@
1
+ require 'moneta'
2
+
3
+ module Rack
4
+ # A Rack middleware that inserts a Moneta store in the environment
5
+ # and supports per-request caching via the the option `:cache => true`.
6
+ #
7
+ # @example config.ru
8
+ # # Add Rack::MonetaStore somewhere in your rack stack
9
+ # use Rack::MonetaStore, :Memory, :cache => true
10
+ #
11
+ # run lambda do |env|
12
+ # env['rack.moneta_store'] # is a Moneta store with per-request caching
13
+ # end
14
+ #
15
+ # @example config.ru
16
+ # # Pass it a block like the one passed to Moneta.build
17
+ # use Rack::MonetaStore do
18
+ # use :Transformer, :value => :zlib
19
+ # adapter :Cookie
20
+ # end
21
+ #
22
+ # run lambda do |env|
23
+ # env['rack.moneta_store'] # is a Moneta store without caching
24
+ # end
25
+ #
26
+ # @api public
27
+ class MonetaStore
28
+ def initialize(app, store = nil, options = {}, &block)
29
+ @app = app
30
+ @cache = options.delete(:cache)
31
+ if block
32
+ raise ArgumentError, 'Use either block or options' unless options.empty?
33
+ @store = ::Moneta.build(&block)
34
+ else
35
+ raise ArgumentError, 'Block or argument store is required' unless @store = store
36
+ @store = ::Moneta.new(@store, options) if Symbol === @store
37
+ end
38
+ end
39
+
40
+ def call(env)
41
+ env['rack.moneta_store'] = @cache ? ::Moneta::Cache.new(:cache => ::Moneta::Adapters::Memory.new, :backend => @store) : @store
42
+ @app.call(env)
43
+ end
44
+ end
45
+ end
@@ -14,7 +14,7 @@ module Rack
14
14
  raise ArgumentError, 'Use either block or option :store' if options[:store]
15
15
  @pool = ::Moneta.build(&block)
16
16
  else
17
- raise ArgumentError, 'Option :store is required' unless @pool = options[:store]
17
+ raise ArgumentError, 'Block or option :store is required' unless @pool = options[:store]
18
18
  @pool = ::Moneta.new(@pool, :expires => true) if Symbol === @pool
19
19
  end
20
20
  @mutex = Mutex.new
data/spec/generate.rb CHANGED
@@ -129,6 +129,12 @@ end
129
129
  :options => ":file => File.join(make_tempdir, 'simple_client_unix')",
130
130
  :specs => STANDARD_SPECS
131
131
  },
132
+ 'simple_restclient' => {
133
+ :preamble => "start_restserver\n",
134
+ :store => :RestClient,
135
+ :options => ":url => 'http://localhost:8808/moneta/'",
136
+ :specs => STANDARD_SPECS.without_increment
137
+ },
132
138
  'simple_memory' => {
133
139
  :store => :Memory,
134
140
  :specs => STANDARD_SPECS.without_persist
@@ -844,6 +850,11 @@ end
844
850
  :build => "Moneta::Adapters::Client.new",
845
851
  :specs => ADAPTER_SPECS
846
852
  },
853
+ 'adapter_restclient' => {
854
+ :preamble => "start_restserver\n",
855
+ :build => "Moneta::Adapters::RestClient.new(:url => 'http://localhost:8808/moneta/')",
856
+ :specs => ADAPTER_SPECS.without_increment
857
+ },
847
858
  'adapter_cassandra' => {
848
859
  :build => "Moneta::Adapters::Cassandra.new(:keyspace => 'adapter_cassandra')",
849
860
  :specs => ADAPTER_SPECS.without_increment.with_expires,
data/spec/helper.rb CHANGED
@@ -9,19 +9,6 @@ RSpec::Core::Formatters::ProgressFormatter.class_eval do
9
9
  end
10
10
  end
11
11
 
12
- module Moneta
13
- class Transformer < Proxy
14
- class << self
15
- alias_method :verbose_new, :new
16
-
17
- def new(adapter, options = {})
18
- options[:quiet] = true
19
- verbose_new(adapter, options)
20
- end
21
- end
22
- end
23
- end
24
-
25
12
  class Value
26
13
  attr_accessor :x
27
14
  def initialize(x)
@@ -41,6 +28,36 @@ class Value
41
28
  end
42
29
  end
43
30
 
31
+ def start_restserver
32
+ require 'rack'
33
+ require 'webrick'
34
+ require 'httpi'
35
+ require 'rack/moneta_rest'
36
+
37
+ HTTPI.log = false
38
+
39
+ # Keep webrick quiet
40
+ ::WEBrick::HTTPServer.class_eval do
41
+ def access_log(config, req, res); end
42
+ end
43
+ ::WEBrick::BasicLog.class_eval do
44
+ def log(level, data); end
45
+ end
46
+
47
+ Thread.start do
48
+ Rack::Server.start(:app => Rack::Builder.app do
49
+ use Rack::Lint
50
+ map '/moneta' do
51
+ run Rack::MonetaRest.new(:store => :Memory)
52
+ end
53
+ end,
54
+ :environment => :none,
55
+ :server => :webrick,
56
+ :Port => 8808)
57
+ end
58
+ sleep 1
59
+ end
60
+
44
61
  def start_server(*args)
45
62
  server = Moneta::Server.new(*args)
46
63
  Thread.new { server.run }
@@ -0,0 +1,20 @@
1
+ # Generated by generate.rb
2
+ require 'helper'
3
+
4
+ describe_moneta "adapter_restclient" do
5
+ start_restserver
6
+ def new_store
7
+ Moneta::Adapters::RestClient.new(:url => 'http://localhost:8808/moneta/')
8
+ end
9
+
10
+ def load_value(value)
11
+ Marshal.load(value)
12
+ end
13
+
14
+ include_context 'setup_store'
15
+ it_should_behave_like 'not_increment'
16
+ it_should_behave_like 'null_stringkey_stringvalue'
17
+ it_should_behave_like 'persist_stringkey_stringvalue'
18
+ it_should_behave_like 'returndifferent_stringkey_stringvalue'
19
+ it_should_behave_like 'store_stringkey_stringvalue'
20
+ end
@@ -0,0 +1,145 @@
1
+ # Generated by generate.rb
2
+ require 'helper'
3
+
4
+ describe_moneta "simple_restclient" do
5
+ start_restserver
6
+ def new_store
7
+ Moneta.new(:RestClient, :url => 'http://localhost:8808/moneta/', :logger => {:out => File.open(File.join(make_tempdir, 'simple_restclient.log'), 'a')})
8
+ end
9
+
10
+ def load_value(value)
11
+ Marshal.load(value)
12
+ end
13
+
14
+ include_context 'setup_store'
15
+ it_should_behave_like 'marshallable_key'
16
+ it_should_behave_like 'marshallable_value'
17
+ it_should_behave_like 'not_increment'
18
+ it_should_behave_like 'null_objectkey_objectvalue'
19
+ it_should_behave_like 'null_objectkey_stringvalue'
20
+ it_should_behave_like 'null_objectkey_hashvalue'
21
+ it_should_behave_like 'null_objectkey_booleanvalue'
22
+ it_should_behave_like 'null_objectkey_nilvalue'
23
+ it_should_behave_like 'null_objectkey_integervalue'
24
+ it_should_behave_like 'null_stringkey_objectvalue'
25
+ it_should_behave_like 'null_stringkey_stringvalue'
26
+ it_should_behave_like 'null_stringkey_hashvalue'
27
+ it_should_behave_like 'null_stringkey_booleanvalue'
28
+ it_should_behave_like 'null_stringkey_nilvalue'
29
+ it_should_behave_like 'null_stringkey_integervalue'
30
+ it_should_behave_like 'null_hashkey_objectvalue'
31
+ it_should_behave_like 'null_hashkey_stringvalue'
32
+ it_should_behave_like 'null_hashkey_hashvalue'
33
+ it_should_behave_like 'null_hashkey_booleanvalue'
34
+ it_should_behave_like 'null_hashkey_nilvalue'
35
+ it_should_behave_like 'null_hashkey_integervalue'
36
+ it_should_behave_like 'null_booleankey_objectvalue'
37
+ it_should_behave_like 'null_booleankey_stringvalue'
38
+ it_should_behave_like 'null_booleankey_hashvalue'
39
+ it_should_behave_like 'null_booleankey_booleanvalue'
40
+ it_should_behave_like 'null_booleankey_nilvalue'
41
+ it_should_behave_like 'null_booleankey_integervalue'
42
+ it_should_behave_like 'null_nilkey_objectvalue'
43
+ it_should_behave_like 'null_nilkey_stringvalue'
44
+ it_should_behave_like 'null_nilkey_hashvalue'
45
+ it_should_behave_like 'null_nilkey_booleanvalue'
46
+ it_should_behave_like 'null_nilkey_nilvalue'
47
+ it_should_behave_like 'null_nilkey_integervalue'
48
+ it_should_behave_like 'null_integerkey_objectvalue'
49
+ it_should_behave_like 'null_integerkey_stringvalue'
50
+ it_should_behave_like 'null_integerkey_hashvalue'
51
+ it_should_behave_like 'null_integerkey_booleanvalue'
52
+ it_should_behave_like 'null_integerkey_nilvalue'
53
+ it_should_behave_like 'null_integerkey_integervalue'
54
+ it_should_behave_like 'persist_objectkey_objectvalue'
55
+ it_should_behave_like 'persist_objectkey_stringvalue'
56
+ it_should_behave_like 'persist_objectkey_hashvalue'
57
+ it_should_behave_like 'persist_objectkey_booleanvalue'
58
+ it_should_behave_like 'persist_objectkey_nilvalue'
59
+ it_should_behave_like 'persist_objectkey_integervalue'
60
+ it_should_behave_like 'persist_stringkey_objectvalue'
61
+ it_should_behave_like 'persist_stringkey_stringvalue'
62
+ it_should_behave_like 'persist_stringkey_hashvalue'
63
+ it_should_behave_like 'persist_stringkey_booleanvalue'
64
+ it_should_behave_like 'persist_stringkey_nilvalue'
65
+ it_should_behave_like 'persist_stringkey_integervalue'
66
+ it_should_behave_like 'persist_hashkey_objectvalue'
67
+ it_should_behave_like 'persist_hashkey_stringvalue'
68
+ it_should_behave_like 'persist_hashkey_hashvalue'
69
+ it_should_behave_like 'persist_hashkey_booleanvalue'
70
+ it_should_behave_like 'persist_hashkey_nilvalue'
71
+ it_should_behave_like 'persist_hashkey_integervalue'
72
+ it_should_behave_like 'persist_booleankey_objectvalue'
73
+ it_should_behave_like 'persist_booleankey_stringvalue'
74
+ it_should_behave_like 'persist_booleankey_hashvalue'
75
+ it_should_behave_like 'persist_booleankey_booleanvalue'
76
+ it_should_behave_like 'persist_booleankey_nilvalue'
77
+ it_should_behave_like 'persist_booleankey_integervalue'
78
+ it_should_behave_like 'persist_nilkey_objectvalue'
79
+ it_should_behave_like 'persist_nilkey_stringvalue'
80
+ it_should_behave_like 'persist_nilkey_hashvalue'
81
+ it_should_behave_like 'persist_nilkey_booleanvalue'
82
+ it_should_behave_like 'persist_nilkey_nilvalue'
83
+ it_should_behave_like 'persist_nilkey_integervalue'
84
+ it_should_behave_like 'persist_integerkey_objectvalue'
85
+ it_should_behave_like 'persist_integerkey_stringvalue'
86
+ it_should_behave_like 'persist_integerkey_hashvalue'
87
+ it_should_behave_like 'persist_integerkey_booleanvalue'
88
+ it_should_behave_like 'persist_integerkey_nilvalue'
89
+ it_should_behave_like 'persist_integerkey_integervalue'
90
+ it_should_behave_like 'returndifferent_objectkey_objectvalue'
91
+ it_should_behave_like 'returndifferent_objectkey_stringvalue'
92
+ it_should_behave_like 'returndifferent_objectkey_hashvalue'
93
+ it_should_behave_like 'returndifferent_stringkey_objectvalue'
94
+ it_should_behave_like 'returndifferent_stringkey_stringvalue'
95
+ it_should_behave_like 'returndifferent_stringkey_hashvalue'
96
+ it_should_behave_like 'returndifferent_hashkey_objectvalue'
97
+ it_should_behave_like 'returndifferent_hashkey_stringvalue'
98
+ it_should_behave_like 'returndifferent_hashkey_hashvalue'
99
+ it_should_behave_like 'returndifferent_booleankey_objectvalue'
100
+ it_should_behave_like 'returndifferent_booleankey_stringvalue'
101
+ it_should_behave_like 'returndifferent_booleankey_hashvalue'
102
+ it_should_behave_like 'returndifferent_nilkey_objectvalue'
103
+ it_should_behave_like 'returndifferent_nilkey_stringvalue'
104
+ it_should_behave_like 'returndifferent_nilkey_hashvalue'
105
+ it_should_behave_like 'returndifferent_integerkey_objectvalue'
106
+ it_should_behave_like 'returndifferent_integerkey_stringvalue'
107
+ it_should_behave_like 'returndifferent_integerkey_hashvalue'
108
+ it_should_behave_like 'store_objectkey_objectvalue'
109
+ it_should_behave_like 'store_objectkey_stringvalue'
110
+ it_should_behave_like 'store_objectkey_hashvalue'
111
+ it_should_behave_like 'store_objectkey_booleanvalue'
112
+ it_should_behave_like 'store_objectkey_nilvalue'
113
+ it_should_behave_like 'store_objectkey_integervalue'
114
+ it_should_behave_like 'store_stringkey_objectvalue'
115
+ it_should_behave_like 'store_stringkey_stringvalue'
116
+ it_should_behave_like 'store_stringkey_hashvalue'
117
+ it_should_behave_like 'store_stringkey_booleanvalue'
118
+ it_should_behave_like 'store_stringkey_nilvalue'
119
+ it_should_behave_like 'store_stringkey_integervalue'
120
+ it_should_behave_like 'store_hashkey_objectvalue'
121
+ it_should_behave_like 'store_hashkey_stringvalue'
122
+ it_should_behave_like 'store_hashkey_hashvalue'
123
+ it_should_behave_like 'store_hashkey_booleanvalue'
124
+ it_should_behave_like 'store_hashkey_nilvalue'
125
+ it_should_behave_like 'store_hashkey_integervalue'
126
+ it_should_behave_like 'store_booleankey_objectvalue'
127
+ it_should_behave_like 'store_booleankey_stringvalue'
128
+ it_should_behave_like 'store_booleankey_hashvalue'
129
+ it_should_behave_like 'store_booleankey_booleanvalue'
130
+ it_should_behave_like 'store_booleankey_nilvalue'
131
+ it_should_behave_like 'store_booleankey_integervalue'
132
+ it_should_behave_like 'store_nilkey_objectvalue'
133
+ it_should_behave_like 'store_nilkey_stringvalue'
134
+ it_should_behave_like 'store_nilkey_hashvalue'
135
+ it_should_behave_like 'store_nilkey_booleanvalue'
136
+ it_should_behave_like 'store_nilkey_nilvalue'
137
+ it_should_behave_like 'store_nilkey_integervalue'
138
+ it_should_behave_like 'store_integerkey_objectvalue'
139
+ it_should_behave_like 'store_integerkey_stringvalue'
140
+ it_should_behave_like 'store_integerkey_hashvalue'
141
+ it_should_behave_like 'store_integerkey_booleanvalue'
142
+ it_should_behave_like 'store_integerkey_nilvalue'
143
+ it_should_behave_like 'store_integerkey_integervalue'
144
+ it_should_behave_like 'transform_value'
145
+ end
@@ -13,11 +13,12 @@ describe Rack::MonetaCookies do
13
13
  end
14
14
 
15
15
  def backend
16
- Rack::MockRequest.new(Rack::MonetaCookies.new(lambda{|env|
16
+ Rack::MockRequest.new(Rack::MonetaCookies.new(lambda do |env|
17
17
  @store = env['rack.request.cookie_hash']
18
+ expect(@store).to equal(env['rack.moneta_cookies'])
18
19
  app.call(env) if app
19
20
  [200,{},[]]
20
- }, @options || {}, &@block))
21
+ end, @options || {}, &@block))
21
22
  end
22
23
 
23
24
  def get(cookies = {}, &block)
@@ -25,20 +26,20 @@ describe Rack::MonetaCookies do
25
26
  @response = backend.get('/','HTTP_COOKIE' => Rack::Utils.build_query(cookies))
26
27
  end
27
28
 
28
- it 'should be able to read a simple key' do
29
+ it 'should be able to read a key' do
29
30
  get 'key' => 'value' do
30
31
  expect( @store['key'] ).to eql('value')
31
32
  end
32
33
  end
33
34
 
34
- it 'should be able to set a simple key' do
35
+ it 'should be able to set a key' do
35
36
  get do
36
37
  @store['key'] = 'value'
37
38
  end
38
39
  expect( @response['Set-Cookie'] ).to eql('key=value')
39
40
  end
40
41
 
41
- it 'should be able to remove a simple key' do
42
+ it 'should be able to remove a key' do
42
43
  get 'key' => 'value' do
43
44
  @store.delete('key')
44
45
  end
@@ -0,0 +1,83 @@
1
+ require 'helper'
2
+ require 'rack/mock'
3
+ require 'rack/moneta_store'
4
+
5
+ describe Rack::MonetaStore do
6
+ def config(store_arg = nil, options = nil, &block)
7
+ @store_arg = store_arg
8
+ @options = options
9
+ @block = block
10
+ end
11
+
12
+ def app(&block)
13
+ @app_block ||= block
14
+ end
15
+
16
+ def middleware
17
+ @middleware ||= Rack::MonetaStore.new(lambda do |env|
18
+ @store = env['rack.moneta_store']
19
+ app.call(env) if app
20
+ [200,{},[]]
21
+ end, @store_arg, @options || {}, &@block)
22
+ end
23
+
24
+ def backend
25
+ @backend ||= Rack::MockRequest.new(middleware)
26
+ end
27
+
28
+ def get(&block)
29
+ app(&block)
30
+ @response = backend.get('/')
31
+ end
32
+
33
+ def uncached_store
34
+ middleware.instance_variable_get(:@store)
35
+ end
36
+
37
+ it 'should be able to get a key without caching' do
38
+ config :Memory
39
+ uncached_store['key'] = 'value'
40
+ get do
41
+ expect(@store['key']).to eql('value')
42
+ end
43
+ end
44
+
45
+ it 'should be able to get a key with caching' do
46
+ config :Memory, :cache => true
47
+ uncached_store['key'] = 'value'
48
+ get do
49
+ expect(@store['key']).to eql('value')
50
+ expect(@store.backend).to equal(uncached_store)
51
+ expect(@store.cache['key']).to eql('value')
52
+ end
53
+ end
54
+
55
+ it 'should be able to set a key' do
56
+ config :Memory
57
+ get do
58
+ @store['key'] = 'value'
59
+ end
60
+ expect( @store['key'] ).to eql('value')
61
+ expect(uncached_store['key']).to eql('value')
62
+ end
63
+
64
+ it 'should be able to get a remove a key' do
65
+ config :Memory
66
+ uncached_store['key'] = 'value'
67
+ get do
68
+ expect(@store.delete('key')).to eql('value')
69
+ end
70
+ expect(uncached_store.key?('key')).to be_false
71
+ end
72
+
73
+ it 'should accept a config block' do
74
+ config do
75
+ use :Transformer, :key => :prefix, :prefix => 'moneta.'
76
+ adapter :Memory
77
+ end
78
+ uncached_store['key'] = 'value'
79
+ get do
80
+ expect(@store['key']).to eql('value')
81
+ end
82
+ end
83
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: moneta
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 0.7.3
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-12-28 00:00:00.000000000 Z
14
+ date: 2012-12-31 00:00:00.000000000 Z
15
15
  dependencies: []
16
16
  description: A unified interface to key/value stores
17
17
  email:
@@ -60,6 +60,7 @@ files:
60
60
  - lib/moneta/adapters/null.rb
61
61
  - lib/moneta/adapters/pstore.rb
62
62
  - lib/moneta/adapters/redis.rb
63
+ - lib/moneta/adapters/restclient.rb
63
64
  - lib/moneta/adapters/riak.rb
64
65
  - lib/moneta/adapters/sdbm.rb
65
66
  - lib/moneta/adapters/sequel.rb
@@ -85,6 +86,7 @@ files:
85
86
  - lib/rack/cache/moneta.rb
86
87
  - lib/rack/moneta_cookies.rb
87
88
  - lib/rack/moneta_rest.rb
89
+ - lib/rack/moneta_store.rb
88
90
  - lib/rack/session/moneta.rb
89
91
  - moneta.gemspec
90
92
  - spec/action_dispatch/fixtures/session_autoload_test/foo.rb
@@ -113,6 +115,7 @@ files:
113
115
  - spec/moneta/adapter_mongo_spec.rb
114
116
  - spec/moneta/adapter_pstore_spec.rb
115
117
  - spec/moneta/adapter_redis_spec.rb
118
+ - spec/moneta/adapter_restclient_spec.rb
116
119
  - spec/moneta/adapter_riak_spec.rb
117
120
  - spec/moneta/adapter_sdbm_spec.rb
118
121
  - spec/moneta/adapter_sequel_spec.rb
@@ -175,6 +178,7 @@ files:
175
178
  - spec/moneta/simple_pstore_spec.rb
176
179
  - spec/moneta/simple_pstore_with_expires_spec.rb
177
180
  - spec/moneta/simple_redis_spec.rb
181
+ - spec/moneta/simple_restclient_spec.rb
178
182
  - spec/moneta/simple_riak_spec.rb
179
183
  - spec/moneta/simple_riak_with_expires_spec.rb
180
184
  - spec/moneta/simple_sdbm_spec.rb
@@ -224,6 +228,7 @@ files:
224
228
  - spec/monetaspecs.rb
225
229
  - spec/rack/cache_moneta_spec.rb
226
230
  - spec/rack/moneta_cookies_spec.rb
231
+ - spec/rack/moneta_store_spec.rb
227
232
  - spec/rack/session_moneta_spec.rb
228
233
  homepage: http://github.com/minad/moneta
229
234
  licenses: []
@@ -277,6 +282,7 @@ test_files:
277
282
  - spec/moneta/adapter_mongo_spec.rb
278
283
  - spec/moneta/adapter_pstore_spec.rb
279
284
  - spec/moneta/adapter_redis_spec.rb
285
+ - spec/moneta/adapter_restclient_spec.rb
280
286
  - spec/moneta/adapter_riak_spec.rb
281
287
  - spec/moneta/adapter_sdbm_spec.rb
282
288
  - spec/moneta/adapter_sequel_spec.rb
@@ -339,6 +345,7 @@ test_files:
339
345
  - spec/moneta/simple_pstore_spec.rb
340
346
  - spec/moneta/simple_pstore_with_expires_spec.rb
341
347
  - spec/moneta/simple_redis_spec.rb
348
+ - spec/moneta/simple_restclient_spec.rb
342
349
  - spec/moneta/simple_riak_spec.rb
343
350
  - spec/moneta/simple_riak_with_expires_spec.rb
344
351
  - spec/moneta/simple_sdbm_spec.rb
@@ -388,5 +395,6 @@ test_files:
388
395
  - spec/monetaspecs.rb
389
396
  - spec/rack/cache_moneta_spec.rb
390
397
  - spec/rack/moneta_cookies_spec.rb
398
+ - spec/rack/moneta_store_spec.rb
391
399
  - spec/rack/session_moneta_spec.rb
392
400
  has_rdoc: