moneta 0.7.2 → 0.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: