cache_rocket 0.2.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 864c56c4f67471c61a8bb9dbea603410616d3fb6
4
+ data.tar.gz: f39b92cc8432727cf11e305e87c9820885472491
5
+ SHA512:
6
+ metadata.gz: 8ef3d5ebf32c1010b0c928c7b1daf55ded395ca1c6a0bd6a378bc790c4760ac7380ec6d52baf07348f251ee380420e91a028fb4e70071f1fb1996d1a77081065
7
+ data.tar.gz: 105657511b52018069395a9fe968e1f7202280b6fbe95301350ebebe03e297f29a3bb270d7565dbc6a89f881c7b5e09ffd599c94be8624d24ea544d17a45ee99
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ Gemfile.lock
6
+ coverage
7
+ doc/
8
+ lib/bundler/man
9
+ pkg
10
+ rdoc
11
+ spec/reports
12
+ test/tmp
13
+ test/version_tmp
14
+ tmp
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.0.0
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ group :test do
4
+ gem 'coveralls', require: false
5
+ end
6
+
7
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Tee Parham
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,118 @@
1
+ [![Gem Version](https://badge.fury.io/rb/cache_rocket.png)][gem]
2
+ [![Build Status](https://api.travis-ci.org/teeparham/cache_rocket.png)][build]
3
+ [![Coverage Status](https://coveralls.io/repos/teeparham/cache_rocket.badge.png)][coverage]
4
+ [![Code Climate](https://codeclimate.com/github/teeparham/cache_rocket.png)][climate]
5
+
6
+ [gem]: http://badge.fury.io/rb/cache_rocket
7
+ [build]: https://travis-ci.org/teeparham/cache_rocket
8
+ [coverage]: https://coveralls.io/r/teeparham/cache_rocket
9
+ [climate]: https://codeclimate.com/github/teeparham/cache_rocket
10
+
11
+ # Rails rendering extension for server-side html caching
12
+
13
+ ## Why do I need this?
14
+
15
+ To improve fragment caching efficiency in Rails by only caching the things that change.
16
+ CacheRocket may be used in with other Rails caching strategies such as Russian Doll caching.
17
+
18
+ ## Install
19
+
20
+ Add this line to your Gemfile:
21
+
22
+ ```ruby
23
+ gem 'cache_rocket'
24
+ ```
25
+
26
+ Add this line to a helper file, likely your ApplicationHelper:
27
+
28
+ ```ruby
29
+ include CacheRocket
30
+ ```
31
+
32
+ ## Use
33
+
34
+ This gem allows you to easily cache a partial of static html and replace inner dynamic html. Here is an example
35
+ scenario:
36
+
37
+ You have some html that would be cached, except for some uncacheable code nested in the DOM. For example:
38
+
39
+ ##### file.html.haml:
40
+ ```haml
41
+ = render 'container'
42
+ ```
43
+
44
+ ##### _container.html.haml:
45
+ ```haml
46
+ .lots
47
+ .of
48
+ .htmls
49
+ = render 'dynamic'
50
+ ```
51
+
52
+ ##### _dynamic.html.haml:
53
+ ```haml
54
+ = complicated_uncacheable_stuff
55
+ ```
56
+
57
+ In the scenario above, you can't cache anything. With `cache_rocket`, you can:
58
+
59
+ ##### file.html.haml:
60
+ ```haml
61
+ = render_cached 'container', replace: 'dynamic'
62
+ ```
63
+
64
+ ##### _container.html.haml:
65
+ ```haml
66
+ - cache "container" do
67
+ .lots
68
+ .of
69
+ .htmls
70
+ = cache_replace_key 'dynamic'
71
+ ```
72
+
73
+ ##### _dynamic.html.haml:
74
+ ``` haml
75
+ = complicated_uncacheable_stuff
76
+ ```
77
+
78
+ In the above example, you could also remove the `_dynamic.html.haml` file like so:
79
+
80
+ ##### file.html.haml:
81
+ ```haml
82
+ = render_cached 'container', replace: {dynamic: complicated_uncacheable_stuff}
83
+ ```
84
+
85
+ ## Options
86
+
87
+ `render_cached` provides 4 calling styles:
88
+
89
+ #### Single partial to replace
90
+
91
+ ```ruby
92
+ render_cached "container", replace: "inner"
93
+ ```
94
+
95
+ #### Array of partials to replace
96
+ ```ruby
97
+ render_cached "container", replace: ["inner"]
98
+ ```
99
+
100
+ #### Map of keys to replace with values
101
+ ```ruby
102
+ render_cached "container", replace: {key_name: a_helper_method(object)}
103
+ ```
104
+
105
+ #### Yield to a hash of keys to replace with values
106
+ ```ruby
107
+ render_cached "container" do
108
+ {key_name: a_helper_method(object)}
109
+ end
110
+ ```
111
+
112
+ ## Contribute
113
+
114
+ 1. Fork it
115
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
116
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
117
+ 4. Push to the branch (`git push origin my-new-feature`)
118
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/gem_tasks'
3
+ require 'rake/testtask'
4
+
5
+ desc 'Run tests'
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << 'test'
8
+ t.pattern = 'test/**/*_test.rb'
9
+ t.verbose = false
10
+ end
11
+
12
+ task default: :test
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cache_rocket/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "cache_rocket"
8
+ spec.version = CacheRocket::VERSION
9
+ spec.authors = ["Tee Parham"]
10
+ spec.email = ["tee@neighborland.com"]
11
+ spec.description = %q{Rails rendering extension for server-side html caching}
12
+ spec.summary = %q{Rails rendering extension for server-side html caching}
13
+ spec.homepage = "https://github.com/teeparham/cache_rocket"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.test_files = `git ls-files -- {test}/*`.split("\n")
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_dependency "actionpack", ">= 3.2"
21
+
22
+ spec.add_development_dependency "rake", ">= 10.0"
23
+ spec.add_development_dependency "test-unit", ">= 2.5"
24
+ spec.add_development_dependency "mocha", ">= 0.13"
25
+ spec.add_development_dependency "shoulda-context"
26
+ spec.add_development_dependency "pry", ">= 0.9"
27
+ end
@@ -0,0 +1,62 @@
1
+ require 'active_support/core_ext/string'
2
+ require 'cache_rocket/key'
3
+ require 'cache_rocket/fragment'
4
+ require 'cache_rocket/version'
5
+
6
+ module CacheRocket
7
+ include Key
8
+
9
+ ERROR_MISSING_KEY_OR_BLOCK = "You must either pass a `replace` key or a block to render_cached."
10
+
11
+ # Supports 5 options:
12
+ #
13
+ # 1. Single partial to replace.
14
+ # "inner" is the key name and "_inner.*" is the partial file name.
15
+ #
16
+ # render_cached "container", replace: "inner"
17
+ #
18
+ # 2. Array of partials to replace
19
+ #
20
+ # render_cached "container", replace: ["inner"]
21
+ #
22
+ # 3. Map of keys to replace with values
23
+ #
24
+ # render_cached "container", replace: {key_name: a_helper_method(object)}
25
+ #
26
+ # 4. Yield to a hash of keys to replace with values
27
+ #
28
+ # render_cached "container" do
29
+ # {key_name: a_helper_method(object)}
30
+ # end
31
+ #
32
+ # 5. Render a collection with Procs for replace values.
33
+ #
34
+ # render_cached "partial", collection: objects, replace: { key_name: ->(object){a_method(object)} }
35
+ #
36
+ def render_cached(partial, options={})
37
+ replace = options.delete(:replace)
38
+ collection = options.delete(:collection)
39
+
40
+ fragment = Fragment.new(render(partial, options))
41
+
42
+ case replace
43
+ when Hash
44
+ if collection
45
+ fragment.replace_collection collection, replace
46
+ else
47
+ fragment.replace_from_hash replace
48
+ end
49
+ when NilClass
50
+ raise ArgumentError.new(ERROR_MISSING_KEY_OR_BLOCK) unless block_given?
51
+ fragment.replace_from_hash yield
52
+ else
53
+ replace = *replace
54
+ replace.each do |key|
55
+ fragment.gsub! cache_replace_key(key), render(key, options)
56
+ end
57
+ end
58
+
59
+ fragment.to_s.html_safe
60
+ end
61
+
62
+ end
@@ -0,0 +1,48 @@
1
+ module CacheRocket
2
+ class Fragment
3
+ include Key
4
+
5
+ attr_accessor :value
6
+
7
+ def initialize(value)
8
+ self.value = value
9
+ end
10
+
11
+ def to_s
12
+ value
13
+ end
14
+
15
+ def gsub!(key, value)
16
+ self.value.gsub! key, value
17
+ end
18
+
19
+ def replace_from_hash(hash)
20
+ hash.each do |key, value|
21
+ gsub! cache_replace_key(key), value.to_s
22
+ end
23
+ end
24
+
25
+ def replace_collection(collection, replace_hash)
26
+ html = ""
27
+
28
+ collection.each do |item|
29
+ html << replace_item_hash(item, replace_hash)
30
+ end
31
+
32
+ self.value = html
33
+ end
34
+
35
+ private
36
+
37
+ def replace_item_hash(item, hash)
38
+ item_fragment = self.value.dup
39
+
40
+ hash.each do |key, value|
41
+ item_fragment.gsub! cache_replace_key(key), value.call(item)
42
+ end
43
+
44
+ item_fragment
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,13 @@
1
+ module CacheRocket
2
+ module Key
3
+ CACHE_REPLACE_KEY_OPEN = '<cr '
4
+
5
+ # string key containing the partial file name or placeholder key.
6
+ # It is a tag that should never be returned to be rendered by the
7
+ # client, but if so, it will be hidden since CR is not a valid html tag.
8
+ def cache_replace_key(key)
9
+ "#{CACHE_REPLACE_KEY_OPEN}#{key.to_s}>".html_safe
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ module CacheRocket
2
+ VERSION = "0.2.0"
3
+ end
@@ -0,0 +1,90 @@
1
+ require 'test_helper'
2
+
3
+ class CacheRocketTest < Test::Unit::TestCase
4
+ class FakeRenderer
5
+ include CacheRocket
6
+ end
7
+
8
+ setup do
9
+ @renderer = FakeRenderer.new
10
+ end
11
+
12
+ context "#cache_replace_key" do
13
+ should "return key with prefix" do
14
+ assert_equal CacheRocket::CACHE_REPLACE_KEY_OPEN + "some/thing>", @renderer.cache_replace_key("some/thing")
15
+ end
16
+ end
17
+
18
+ context "#render_cached" do
19
+ setup do
20
+ @renderer.stubs(:render).with("container", {}).returns "Fanny pack #{@renderer.cache_replace_key('inner')} viral mustache."
21
+ @renderer.stubs(:render).with("inner", {}).returns "quinoa hoodie"
22
+ end
23
+
24
+ should "render with single partial" do
25
+ assert_equal "Fanny pack quinoa hoodie viral mustache.", @renderer.render_cached("container", replace: "inner")
26
+ end
27
+
28
+ should "pass options to inner render" do
29
+ @renderer.expects(:render).with("container", variable: "x").returns ""
30
+ @renderer.expects(:render).with("inner", variable: "x").returns ""
31
+ @renderer.render_cached("container", variable: "x", replace: "inner")
32
+ end
33
+
34
+ should "render with array of partials" do
35
+ @renderer.stubs(:render).with("container", {}).
36
+ returns "#{@renderer.cache_replace_key('inner')} #{@renderer.cache_replace_key('other')} viral mustache."
37
+ @renderer.stubs(:render).with("other", {}).returns "high life"
38
+
39
+ assert_equal "quinoa hoodie high life viral mustache.",
40
+ @renderer.render_cached("container", replace: ["inner", "other"])
41
+ end
42
+
43
+ should "render with map of keys" do
44
+ assert_equal "Fanny pack keytar viral mustache.", @renderer.render_cached("container", replace: {inner: "keytar"})
45
+ end
46
+
47
+ should "render with map of keys with a nil value" do
48
+ assert_equal "Fanny pack viral mustache.", @renderer.render_cached("container", replace: {inner: nil})
49
+ end
50
+
51
+ should "render with hash block" do
52
+ output = @renderer.render_cached("container") do
53
+ {inner: "keytar"}
54
+ end
55
+ assert_equal "Fanny pack keytar viral mustache.", output
56
+ end
57
+
58
+ should "replace every instance of key in inner partial" do
59
+ @renderer.stubs(:render).with("container", {}).
60
+ returns "#{@renderer.cache_replace_key('inner')} #{@renderer.cache_replace_key('inner')} viral mustache."
61
+
62
+ assert_equal "quinoa hoodie quinoa hoodie viral mustache.",
63
+ @renderer.render_cached("container", replace: "inner")
64
+ end
65
+
66
+ should "replace every instance of the keys with hash values" do
67
+ @renderer.stubs(:render).with("container", {}).
68
+ returns "I like #{@renderer.cache_replace_key('beer')}, #{@renderer.cache_replace_key('beer')} and #{@renderer.cache_replace_key('food')}."
69
+
70
+ assert_equal "I like stout, stout and chips.",
71
+ @renderer.render_cached("container", replace: {food: "chips", beer: 'stout'})
72
+ end
73
+
74
+ should "replace collection with Proc in replace key" do
75
+ def dog_name(dog) dog end
76
+ @renderer.stubs(:render).with("partial", {}).returns "Hi #{@renderer.cache_replace_key(:dog)}."
77
+ dogs = %w[Snoop Boo]
78
+
79
+ assert_equal "Hi Snoop.Hi Boo.",
80
+ @renderer.render_cached("partial", collection: dogs, replace: {dog: ->(dog){dog_name(dog)} })
81
+ end
82
+
83
+ should "raise ArgumentError with invalid syntax" do
84
+ @renderer.stubs(:render).with("container").returns("")
85
+ assert_raise(ArgumentError) do
86
+ @renderer.render_cached("container")
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,42 @@
1
+ require 'test_helper'
2
+
3
+ module CacheRocket
4
+ class FragmentTest < Test::Unit::TestCase
5
+ context "#to_s" do
6
+ should "equal value" do
7
+ assert_equal "yo", Fragment.new("yo").to_s
8
+ end
9
+ end
10
+
11
+ context "#gsub!" do
12
+ should "gsub value" do
13
+ fragment = Fragment.new("hello there, hello.")
14
+ assert_equal "yo there, yo.", fragment.gsub!("hello", "yo")
15
+ end
16
+ end
17
+
18
+ context "#replace_from_hash" do
19
+ should "replace cache keys" do
20
+ cr_key = Fragment.new(nil).cache_replace_key(:xx)
21
+ fragment = Fragment.new("hey #{cr_key} hey.")
22
+ fragment.replace_from_hash(xx: "yo")
23
+ assert_equal "hey yo hey.", fragment.value
24
+ end
25
+ end
26
+
27
+ context "#replace_collection" do
28
+ should "replace with Proc" do
29
+ def last5(object)
30
+ object.last(5)
31
+ end
32
+ replace_hash = { something: ->(obj){ last5(obj)} }
33
+ collection = %w[xxTiger xxSkunk]
34
+ cr_key = Fragment.new(nil).cache_replace_key(:something)
35
+ fragment = Fragment.new("hey #{cr_key} hey.")
36
+ assert_equal "hey Tiger hey.hey Skunk hey.",
37
+ fragment.replace_collection(collection, replace_hash)
38
+ end
39
+ end
40
+
41
+ end
42
+ end
data/test/key_test.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'test_helper'
2
+
3
+ module CacheRocket
4
+ class KeyTest < Test::Unit::TestCase
5
+
6
+ context "#cache_replace_key" do
7
+ should "return key with prefix" do
8
+ class KeyFake
9
+ include Key
10
+ end
11
+
12
+ key = KeyFake.new
13
+ assert_equal CacheRocket::Key::CACHE_REPLACE_KEY_OPEN + "some/thing>", key.cache_replace_key("some/thing")
14
+ end
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,8 @@
1
+ require 'coveralls'
2
+ Coveralls.wear!
3
+
4
+ require 'test/unit'
5
+ require 'shoulda-context'
6
+ require 'mocha/setup'
7
+ require 'cache_rocket'
8
+ require 'pry'
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cache_rocket
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Tee Parham
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: actionpack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '3.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '3.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: test-unit
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '2.5'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '2.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: mocha
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0.13'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0.13'
69
+ - !ruby/object:Gem::Dependency
70
+ name: shoulda-context
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0.9'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0.9'
97
+ description: Rails rendering extension for server-side html caching
98
+ email:
99
+ - tee@neighborland.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - .gitignore
105
+ - .ruby-version
106
+ - .travis.yml
107
+ - Gemfile
108
+ - LICENSE.txt
109
+ - README.md
110
+ - Rakefile
111
+ - cache_rocket.gemspec
112
+ - lib/cache_rocket.rb
113
+ - lib/cache_rocket/fragment.rb
114
+ - lib/cache_rocket/key.rb
115
+ - lib/cache_rocket/version.rb
116
+ - test/cache_rocket_test.rb
117
+ - test/fragment_test.rb
118
+ - test/key_test.rb
119
+ - test/test_helper.rb
120
+ homepage: https://github.com/teeparham/cache_rocket
121
+ licenses:
122
+ - MIT
123
+ metadata: {}
124
+ post_install_message:
125
+ rdoc_options: []
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - '>='
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ requirements: []
139
+ rubyforge_project:
140
+ rubygems_version: 2.0.7
141
+ signing_key:
142
+ specification_version: 4
143
+ summary: Rails rendering extension for server-side html caching
144
+ test_files: []