grape-shaman_cache 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in grape-shaman_cache.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Victor Wang
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # Grape::ShamanCache
2
+
3
+ ## Features
4
+
5
+ HTTP and server side cache integration for Grape and Jbuilder without Rails application.
6
+
7
+ If you're not familiar with HTTP caching, ETags and If-Modified-Since, here are some resources.
8
+
9
+ * [From Zero to API Cache w/ Grape & MongoDB in 10 Minutes](http://www.confreaks.com/videos/986-goruco2012-from-zero-to-api-cache-w-grape-mongodb-in-10-minutes)
10
+ * [Doing HTTP Caching Right: Introducing httplib2](http://www.xml.com/lpt/a/1642)
11
+ * [Introducing Rack::Cache](http://tomayko.com/writings/rack-cache-announce)
12
+
13
+
14
+ ## Installation
15
+
16
+ Add this line to your application's Gemfile:
17
+
18
+ gem 'grape-shaman_cache'
19
+
20
+ And then execute:
21
+
22
+ $ bundle
23
+
24
+ Or install it yourself as:
25
+
26
+ $ gem install grape-shaman_cache
27
+
28
+ remember to modify your config.ru file:
29
+
30
+ ```
31
+ use Rack::ConditionalGet
32
+ use Rack::ETag
33
+ ```
34
+
35
+ ## Usage
36
+
37
+ ```
38
+ class Welcome < Grape::API
39
+
40
+ include Grape::ShamanCache
41
+
42
+ format :json
43
+ formatter :json, Grape::Formatter::Jbuilder
44
+
45
+ get :home, jbuilder: 'welcome/home' do
46
+ @banners = Article.banner.without_gifts
47
+ cache(key: [:v2, :home, @banners.last], expires_in: 2.hours) do
48
+ @banners
49
+ end
50
+ end
51
+
52
+ end
53
+ ```
54
+
55
+ ## Configuration
56
+
57
+ By default `Grape::ShamanCache` will use an instance of `ActiveSupport::Cache::MemoryStore` in a non-Rails application. You can configure it to use any other cache store.
58
+
59
+ ```
60
+ Grape::ShamanCache.configure do |config|
61
+ config.cache = ActiveSupport::Cache::FileStore.new("tmp/cache")
62
+ end
63
+ ```
64
+
65
+ ## Contributing
66
+
67
+ 1. Fork it
68
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
69
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
70
+ 4. Push to the branch (`git push origin my-new-feature`)
71
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'grape-shaman_cache/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.authors = ["Victor Wang"]
8
+ gem.email = ["wjp2013@gmail.com"]
9
+ gem.description = %q{HTTP and server side cache integration for Grape and Rack applications}
10
+ gem.summary = %q{HTTP and server side cache integration for Grape and Rack applications}
11
+ gem.homepage = ""
12
+
13
+ gem.files = `git ls-files`.split($\)
14
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
15
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
16
+ gem.name = "grape-shaman_cache"
17
+ gem.require_paths = ["lib"]
18
+ gem.version = Grape::ShamanCache::VERSION
19
+
20
+ gem.add_dependency "grape", ">= 0.6.1"
21
+ gem.add_dependency "jbuilder"
22
+ gem.add_dependency "activesupport"
23
+
24
+ gem.add_development_dependency "bundler", "~> 1.3"
25
+ gem.add_development_dependency "rake"
26
+ end
@@ -0,0 +1,4 @@
1
+ require "grape-shaman_cache/version"
2
+ require "grape-shaman_cache/config"
3
+ require "grape-shaman_cache/formatter"
4
+ require "grape-shaman_cache/shaman_cache"
@@ -0,0 +1,103 @@
1
+ module Grape
2
+ module ShamanCache
3
+
4
+ class << self
5
+ # Set the configuration options. Best used by passing a block.
6
+ #
7
+ # @example Set up configuration options.
8
+ # ShamanCache.configure do |config|
9
+ # config.cache = Rails.cache
10
+ # end
11
+ #
12
+ # @return [Config] The configuration object.
13
+ def configure
14
+ block_given? ? yield(ShamanCache::Config) : ShamanCache::Config
15
+ end
16
+ alias :config :configure
17
+ end
18
+
19
+ module Config
20
+ extend self
21
+
22
+ # Current configuration settings.
23
+ attr_accessor :settings
24
+
25
+ # Default configuration settings.
26
+ attr_accessor :defaults
27
+
28
+ @settings = {}
29
+ @defaults = {}
30
+
31
+ # Define a configuration option with a default.
32
+ #
33
+ # @example Define the option.
34
+ # Config.option(:cache, :default => nil)
35
+ #
36
+ # @param [Symbol] name The name of the configuration option.
37
+ # @param [Hash] options Extras for the option.
38
+ #
39
+ # @option options [Object] :default The default value.
40
+ def option(name, options = {})
41
+ defaults[name] = settings[name] = options[:default]
42
+
43
+ class_eval <<-RUBY
44
+ def #{name}
45
+ settings[#{name.inspect}]
46
+ end
47
+
48
+ def #{name}=(value)
49
+ settings[#{name.inspect}] = value
50
+ end
51
+
52
+ def #{name}?
53
+ #{name}
54
+ end
55
+ RUBY
56
+ end
57
+
58
+ # Returns the default cache store, either Rails.cache or an instance
59
+ # of ActiveSupport::Cache::MemoryStore.
60
+ #
61
+ # @example Get the default cache store
62
+ # config.default_cache
63
+ #
64
+ # @return [Cache] The default cache store instance.
65
+ def default_cache
66
+ if defined?(Rails) && Rails.respond_to?(:cache)
67
+ Rails.cache
68
+ else
69
+ ::ActiveSupport::Cache::MemoryStore.new
70
+ end
71
+ end
72
+
73
+ # Returns the cache, or defaults to Rails cache when running in Rails
74
+ # or an instance of ActiveSupport::Cache::MemoryStore otherwise.
75
+ #
76
+ # @example Get the cache.
77
+ # config.cache
78
+ #
79
+ # @return [Cache] The configured cache or a default cache instance.
80
+ def cache
81
+ settings[:cache] = default_cache unless settings.has_key?(:cache)
82
+ settings[:cache]
83
+ end
84
+
85
+ # Sets the cache to use.
86
+ #
87
+ # @example Set the cache.
88
+ # config.cache = Rails.cache
89
+ #
90
+ # @return [Cache] The newly set cache.
91
+ def cache=(cache)
92
+ settings[:cache] = cache
93
+ end
94
+
95
+ # Default cache options
96
+ option(:global_cache_options, :default => {})
97
+
98
+ # Default cache expiration time.
99
+ option(:expires_in, :default => nil)
100
+ end
101
+
102
+ end
103
+ end
@@ -0,0 +1,23 @@
1
+ # Rewrite Grape::Formatter::Jbuilder.call defined by 'grape-jbuilder' gem.
2
+ module Grape
3
+ module Formatter
4
+ # For maximum performance we are fetching string from redis and return them with no parsing at all
5
+ module Jbuilder
6
+ def self.call(object, env)
7
+ @env = env
8
+ @endpoint = env['api.endpoint']
9
+ # object is string means that we need to use cache
10
+ return object if object.is_a?(String)
11
+
12
+ if jbuilderable?
13
+ jbuilder do |template|
14
+ engine = ::Tilt.new(view_path(template), nil, view_path: env['api.tilt.root'])
15
+ engine.render(endpoint, {})
16
+ end
17
+ else
18
+ Grape::Formatter::Json.call object, env
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,56 @@
1
+ module Grape
2
+ module ShamanCache
3
+
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ helpers do
8
+
9
+ # Based on actionpack/lib/action_controller/base.rb, line 1216
10
+ def expires_in(seconds, options = {})
11
+ cache_control = []
12
+ cache_control << "max-age=#{seconds}"
13
+ cache_control.delete("no-cache")
14
+ if options[:public]
15
+ cache_control.delete("private")
16
+ cache_control << "public"
17
+ else
18
+ cache_control << "private"
19
+ end
20
+
21
+ # This allows for additional headers to be passed through like 'max-stale' => 5.hours
22
+ cache_control += options.symbolize_keys.reject{|k,v| k == :public || k == :private }.map{ |k,v| v == true ? k.to_s : "#{k.to_s}=#{v.to_s}"}
23
+
24
+ header "Cache-Control", cache_control.join(', ')
25
+ end
26
+
27
+ def default_expire_time
28
+ 2.hours
29
+ end
30
+
31
+ def cache(opts = {}, &block)
32
+ # HTTP Cache
33
+ cache_key = ActiveSupport::Cache.expand_cache_key(opts[:key])
34
+
35
+ # compare_etag(opts[:etag]) # Check if client has fresh version
36
+ # Check if client has fresh version
37
+
38
+ # Set Cache-Control
39
+ expire_time = opts[:expires_in] || default_expire_time
40
+ expires_in(expire_time, public: true)
41
+
42
+ # Try to fetch from server side cache
43
+ # MemCacheStore's write method supports the :raw option
44
+ # which tells the memcached server to store all values as strings.
45
+ cache = Grape::ShamanCache.config.cache
46
+ cache.fetch(cache_key, raw: true, expires_in: expire_time) do
47
+ Grape::Formatter::Jbuilder.call block, env
48
+ end
49
+ end
50
+
51
+ end
52
+ end
53
+
54
+
55
+ end
56
+ end
@@ -0,0 +1,5 @@
1
+ module Grape
2
+ module ShamanCache
3
+ VERSION = "0.1.1"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: grape-shaman_cache
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Victor Wang
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-12-19 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: grape
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.6.1
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 0.6.1
30
+ - !ruby/object:Gem::Dependency
31
+ name: jbuilder
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: activesupport
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: bundler
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '1.3'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '1.3'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rake
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ description: HTTP and server side cache integration for Grape and Rack applications
95
+ email:
96
+ - wjp2013@gmail.com
97
+ executables: []
98
+ extensions: []
99
+ extra_rdoc_files: []
100
+ files:
101
+ - .gitignore
102
+ - Gemfile
103
+ - LICENSE
104
+ - README.md
105
+ - Rakefile
106
+ - grape-shaman_cache.gemspec
107
+ - lib/grape-shaman_cache.rb
108
+ - lib/grape-shaman_cache/config.rb
109
+ - lib/grape-shaman_cache/formatter.rb
110
+ - lib/grape-shaman_cache/shaman_cache.rb
111
+ - lib/grape-shaman_cache/version.rb
112
+ homepage: ''
113
+ licenses: []
114
+ post_install_message:
115
+ rdoc_options: []
116
+ require_paths:
117
+ - lib
118
+ required_ruby_version: !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ! '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ! '>='
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ requirements: []
131
+ rubyforge_project:
132
+ rubygems_version: 1.8.24
133
+ signing_key:
134
+ specification_version: 3
135
+ summary: HTTP and server side cache integration for Grape and Rack applications
136
+ test_files: []