redis_snippets 0.0.10 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +4 -2
- data/.rspec +2 -0
- data/.travis.yml +19 -0
- data/Gemfile +12 -0
- data/README.md +84 -18
- data/Rakefile +5 -0
- data/app/controllers/redis_snippets/snippets_controller.rb +5 -6
- data/app/helpers/redis_snippets/snippets_helper.rb +5 -23
- data/app/presenters/snippet_presenter.rb +67 -0
- data/app/{models/redis_snippets/snippets.rb → services/snippet_store_service.rb} +9 -1
- data/app/views/redis_snippets/snippets/show.html.erb +11 -15
- data/config/routes.rb +1 -1
- data/lib/redis_snippets/engine.rb +3 -1
- data/lib/redis_snippets/redis.rb +10 -5
- data/lib/redis_snippets/{help.rb → util.rb} +2 -2
- data/lib/redis_snippets/version.rb +1 -1
- data/lib/redis_snippets.rb +4 -2
- data/redis_snippets.gemspec +5 -4
- data/spec/app/helpers/redis_snippets/snippets_helper_spec.rb +38 -0
- data/spec/app/presenters/snippet_presenter_spec.rb +53 -0
- data/spec/app/presenters/snippet_presenter_transform_spec.rb +45 -0
- data/spec/app/services/snippet_store_service_spec.rb +44 -0
- data/spec/dummy/.ruby-version +1 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/config/manifest.js +3 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +33 -0
- data/spec/dummy/config/application.rb +29 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +62 -0
- data/spec/dummy/config/environments/test.rb +48 -0
- data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -0
- data/spec/dummy/config/initializers/assets.rb +12 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/content_security_policy.rb +28 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/puma.rb +38 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/config.ru +5 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/tmp/.keep +0 -0
- data/spec/dummy/tmp/development_secret.txt +1 -0
- data/spec/rails_helper.rb +54 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/support/simplecov_setup.rb +5 -0
- metadata +105 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1157b175b0ce0c3c72be376383f9da2d522999f69304c093cd3ddbc22eb0d25d
|
4
|
+
data.tar.gz: 7673c2ffe8fd7b0134847e1de912dd94aadf900a267c937625e3ace993f106ee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fc847d478f9c40aef9fe2ecb067eee24c700d23b1053bcb09280db46c5025b09a94e6363ecdb2f0d70e567a606b75cb53d0771e16844b3a934b6eb815c4bb44f
|
7
|
+
data.tar.gz: fbfc1e84fc0c9794221880574abde61e7d3e2c11720c0c92062be5592c0f15d599f428b556abe777156fc2662790b4386c60cd553720d9567a3664337761602d
|
data/.gitignore
CHANGED
data/.rspec
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
language: ruby
|
2
|
+
cache: bundler
|
3
|
+
sudo: false
|
4
|
+
env:
|
5
|
+
global:
|
6
|
+
- CC_TEST_REPORTER_ID=aa59e066b7cd7b5477aecc5c17004d78d35012420e791d23b17c0ea705ef9cd7
|
7
|
+
before_script:
|
8
|
+
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
9
|
+
- chmod +x ./cc-test-reporter
|
10
|
+
- ./cc-test-reporter before-build
|
11
|
+
before_install:
|
12
|
+
- gem update --system
|
13
|
+
- gem install bundler --version 2.0.2
|
14
|
+
rvm:
|
15
|
+
- 2.6.5
|
16
|
+
script:
|
17
|
+
- bundle exec rake
|
18
|
+
after_script:
|
19
|
+
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
data/Gemfile
ADDED
data/README.md
CHANGED
@@ -1,20 +1,48 @@
|
|
1
1
|
# Redis Snippets
|
2
2
|
|
3
|
+
[![Version](https://img.shields.io/gem/v/redis_snippets.svg?style=flat-square)](https://rubygems.org/gems/redis_snippets)
|
4
|
+
[![Build](https://img.shields.io/travis/wulffeld/redis_snippets.svg?style=flat-square)](https://travis-ci.org/wulffeld/redis_snippets)
|
5
|
+
[![Maintainability](https://img.shields.io/codeclimate/maintainability/wulffeld/redis_snippets?style=flat-square)](https://codeclimate.com/github/wulffeld/redis_snippets)
|
6
|
+
[![Coverage](https://img.shields.io/codeclimate/coverage/wulffeld/redis_snippets?style=flat-square)](https://codeclimate.com/github/wulffeld/redis_snippets)
|
7
|
+
|
3
8
|
## Background
|
4
9
|
|
5
|
-
Easily store snippets of content in Redis.
|
10
|
+
Easily store snippets of content in Redis. Inspired by plugin for Wordpress
|
11
|
+
named Snippets.
|
12
|
+
|
13
|
+
With redis_snippets you could for instance store AdSense code snippets or
|
14
|
+
other HTML/JS content.
|
15
|
+
|
16
|
+
## Requirements
|
17
|
+
|
18
|
+
Gems:
|
19
|
+
|
20
|
+
* rails 5.x or higher
|
21
|
+
* redis
|
22
|
+
* redis-namespace
|
23
|
+
|
24
|
+
## Installation
|
25
|
+
|
26
|
+
Add to your Rails projects Gemfile and bundle install:
|
27
|
+
|
28
|
+
```
|
29
|
+
gem "redis_snippets"
|
30
|
+
```
|
6
31
|
|
7
|
-
##
|
32
|
+
## Usage
|
8
33
|
|
9
|
-
It's a Rails engine so add redis-snippets to your Gemfile and put this in an
|
34
|
+
It's a Rails engine so add redis-snippets to your Gemfile and put this in an
|
35
|
+
initializer:
|
10
36
|
|
11
37
|
``` ruby
|
12
|
-
|
13
|
-
:
|
14
|
-
:
|
38
|
+
Rails.application.config.redis_snippets = {
|
39
|
+
connection: ::Redis::Namespace.new("my_namespace", redis: ::Redis.new),
|
40
|
+
keys: [:key1, :key2]
|
15
41
|
}
|
16
42
|
```
|
17
43
|
|
44
|
+
The names of the keys are entirely up to you.
|
45
|
+
|
18
46
|
You should then be able to access /admin/snippets/.
|
19
47
|
|
20
48
|
In your views use helper snippet().
|
@@ -28,20 +56,63 @@ In your views use helper snippet().
|
|
28
56
|
One snippet area can include multiple snippets if you separate them with a
|
29
57
|
|
30
58
|
```
|
31
|
-
[
|
59
|
+
[section]
|
32
60
|
```
|
33
61
|
|
34
|
-
The snippet helper will randomly select the snippet. This is convenient for ad
|
62
|
+
The snippet helper will randomly select the snippet. This is convenient for ad
|
63
|
+
delivery or perhaps A/B testing 🤷♂.
|
35
64
|
|
36
65
|
## Multi Site
|
37
66
|
|
38
|
-
If you're using one app to serve multiple sites a little more configuration is
|
67
|
+
If you're using one app to serve multiple sites a little more configuration is
|
68
|
+
necessary.
|
39
69
|
|
40
70
|
``` ruby
|
41
|
-
|
42
|
-
:
|
43
|
-
:
|
44
|
-
:
|
71
|
+
Rails.application.config.redis_snippets = {
|
72
|
+
connection: ::Redis::Namespace.new("my_namespace", redis: ::Redis.new),
|
73
|
+
multi_site: true,
|
74
|
+
keys: [:key1, :key2],
|
75
|
+
transform: "MySnippetTransform"
|
76
|
+
}
|
77
|
+
```
|
78
|
+
|
79
|
+
## Transforming Snippets
|
80
|
+
|
81
|
+
Sometimes you might want to transform snippets. This happens after
|
82
|
+
randomization so you get the actual snippet content to be rendered passed to
|
83
|
+
your transform class.
|
84
|
+
|
85
|
+
The transform class must respond to .transforms? and #transform. Example:
|
86
|
+
|
87
|
+
``` ruby
|
88
|
+
class MySnippetTransform
|
89
|
+
def initialize(content:, key:)
|
90
|
+
@content = content
|
91
|
+
@key = key
|
92
|
+
end
|
93
|
+
|
94
|
+
# Must return content.
|
95
|
+
def transform
|
96
|
+
@content.gsub("Amazon", "Etsy")
|
97
|
+
end
|
98
|
+
|
99
|
+
class << self
|
100
|
+
def transforms?(key:)
|
101
|
+
key == :advert_header
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
```
|
106
|
+
|
107
|
+
I personally use this to insert special CSS code for AdSense. This saves me
|
108
|
+
from having to do this manually whenever I update it or add it.
|
109
|
+
|
110
|
+
``` ruby
|
111
|
+
Rails.application.config.redis_snippets = {
|
112
|
+
connection: ::Redis::Namespace.new("my_namespace", redis: ::Redis.new),
|
113
|
+
multi_site: true,
|
114
|
+
keys: [:key1, :key2],
|
115
|
+
transform: "MySnippetTransform"
|
45
116
|
}
|
46
117
|
```
|
47
118
|
|
@@ -53,8 +124,3 @@ def redis_snippet_site_key
|
|
53
124
|
request.host
|
54
125
|
end
|
55
126
|
```
|
56
|
-
|
57
|
-
## Requirements
|
58
|
-
|
59
|
-
* redis
|
60
|
-
* redis-namespace
|
data/Rakefile
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class RedisSnippets::SnippetsController < ApplicationController
|
2
|
-
include RedisSnippets::
|
3
|
-
|
4
|
-
|
2
|
+
include RedisSnippets::Util
|
3
|
+
|
4
|
+
before_action :redis_snippets_authenticate_admin_user!
|
5
5
|
|
6
6
|
layout 'admin'
|
7
7
|
|
@@ -10,10 +10,9 @@ class RedisSnippets::SnippetsController < ApplicationController
|
|
10
10
|
|
11
11
|
def update
|
12
12
|
params[:snippets].each do |key, content|
|
13
|
-
|
14
|
-
RedisSnippets::Snippets.update(snippet_key(key), params[:snippets][key])
|
13
|
+
SnippetStoreService.update(snippet_key(key), params[:snippets][key])
|
15
14
|
end
|
16
|
-
|
15
|
+
|
17
16
|
flash[:notice] = 'Snippets updated.'
|
18
17
|
redirect_to redis_snippets.snippets_path
|
19
18
|
end
|
@@ -1,32 +1,14 @@
|
|
1
1
|
module RedisSnippets
|
2
2
|
module SnippetsHelper
|
3
|
-
include RedisSnippets::
|
4
|
-
|
5
|
-
def snippet_content(snippet_name)
|
6
|
-
RedisSnippets::Snippets.send(snippet_key(snippet_name))
|
7
|
-
end
|
3
|
+
include RedisSnippets::Util
|
8
4
|
|
9
5
|
# Return true if snippet has content.
|
10
|
-
def snippet_has_content?(
|
11
|
-
!
|
12
|
-
end
|
13
|
-
|
14
|
-
def snippet(snippet_name, classes=nil)
|
15
|
-
return '' if controller.status == 404
|
16
|
-
snippet = snippet_content(snippet_name)
|
17
|
-
return '' if snippet.blank?
|
18
|
-
snippets = snippet.split("[section]")
|
19
|
-
build_snippet(snippets[rand(snippets.length)], snippet_class_list(snippet_name, classes))
|
20
|
-
end
|
21
|
-
|
22
|
-
def snippet_class_list(snippet_name, classes)
|
23
|
-
['snippet', classes || snippet_name.to_s].compact.join(' ').html_safe
|
6
|
+
def snippet_has_content?(key)
|
7
|
+
!SnippetStoreService.send(snippet_key(key)).blank?
|
24
8
|
end
|
25
9
|
|
26
|
-
def
|
27
|
-
|
28
|
-
content.html_safe,
|
29
|
-
:class => classes)
|
10
|
+
def snippet(key, classes = nil)
|
11
|
+
SnippetPresenter.new(view: self, key: key, classes: classes).call
|
30
12
|
end
|
31
13
|
end
|
32
14
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
|
2
|
+
class SnippetPresenter
|
3
|
+
include RedisSnippets::Util
|
4
|
+
|
5
|
+
SECTION_DELIMITER = "[section]"
|
6
|
+
|
7
|
+
delegate :random_snippet, to: "self.class"
|
8
|
+
|
9
|
+
def initialize(view:, key:, classes: nil)
|
10
|
+
@view = view
|
11
|
+
@key = key
|
12
|
+
@classes = classes
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
prepare_snippet
|
17
|
+
render
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
def prepare_snippet
|
23
|
+
@snippet = ""
|
24
|
+
|
25
|
+
return unless content = SnippetStoreService.send(snippet_key(@key))
|
26
|
+
|
27
|
+
snippets = content.split("#{SECTION_DELIMITER}")
|
28
|
+
@snippet = random_snippet(content)
|
29
|
+
|
30
|
+
if transform_class && transform_class.transforms?(key: @key)
|
31
|
+
@snippet = transform_class.new(content: @snippet, key: @key).transform
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def snippet_class_list
|
36
|
+
[
|
37
|
+
"snippet",
|
38
|
+
@key.to_s,
|
39
|
+
*@classes
|
40
|
+
].reject(&:blank?).join(" ").html_safe
|
41
|
+
end
|
42
|
+
|
43
|
+
def render
|
44
|
+
# If snippet is empty we avoid wrapping it in the div.
|
45
|
+
if @snippet.blank?
|
46
|
+
""
|
47
|
+
else
|
48
|
+
@view.content_tag(:div, @snippet.html_safe, class: snippet_class_list)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def transform_class
|
53
|
+
@klass ||=
|
54
|
+
if RedisSnippets::Engine.config.redis_snippets[:transform].is_a?(Proc)
|
55
|
+
klass = RedisSnippets::Engine.config.redis_snippets[:transform].call and klass.constantize
|
56
|
+
else
|
57
|
+
RedisSnippets::Engine.config.redis_snippets[:transform] and RedisSnippets::Engine.config.redis_snippets[:transform].constantize
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class << self
|
62
|
+
def random_snippet(content)
|
63
|
+
snippets = content.split("#{SECTION_DELIMITER}").map { |section| section.gsub(/^\n/, "") }
|
64
|
+
snippets[rand(snippets.length)]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -1,10 +1,12 @@
|
|
1
|
-
class
|
1
|
+
class SnippetStoreService
|
2
2
|
class << self
|
3
3
|
def update(key, content)
|
4
|
+
ensure_key_is_defined!(key)
|
4
5
|
RedisSnippets::Redis.set("snippets:#{key}", content)
|
5
6
|
end
|
6
7
|
|
7
8
|
def del(key)
|
9
|
+
ensure_key_is_defined!(key)
|
8
10
|
RedisSnippets::Redis.del("snippets:#{key}")
|
9
11
|
end
|
10
12
|
|
@@ -12,5 +14,11 @@ class RedisSnippets::Snippets
|
|
12
14
|
def method_missing(method, *args)
|
13
15
|
RedisSnippets::Redis.get("snippets:#{method}")
|
14
16
|
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
def ensure_key_is_defined!(key)
|
21
|
+
raise UndefinedSnippetsKey.new("#{key} not in the specified keys.") unless RedisSnippets::Engine.config.redis_snippets[:keys].include?(key.to_sym)
|
22
|
+
end
|
15
23
|
end
|
16
24
|
end
|
@@ -1,23 +1,19 @@
|
|
1
|
-
<div class="
|
2
|
-
<h1>Snippets</h1>
|
1
|
+
<div class="redis-snippets">
|
2
|
+
<h1 class="h1">Snippets</h1>
|
3
3
|
|
4
|
-
<%= form_tag
|
5
|
-
<fieldset class="
|
6
|
-
<ol>
|
4
|
+
<%= form_tag "", method: :put, class: "redis-snippets__form" do |f| %>
|
5
|
+
<fieldset class="redis-snippets__fieldset">
|
6
|
+
<ol class="redis-snippets__list">
|
7
7
|
<% RedisSnippets::Engine.config.redis_snippets[:keys].each do |key| %>
|
8
|
-
<li class="
|
9
|
-
<%= label_tag key.to_s, key.to_s, class: "
|
10
|
-
<%= text_area_tag "snippets[#{key}]",
|
8
|
+
<li class="redis-snippets__snippet">
|
9
|
+
<%= label_tag key.to_s, key.to_s, class: "redis-snippets__snippet-label" %>
|
10
|
+
<%= text_area_tag "snippets[#{key}]", SnippetStoreService.send(snippet_key(key)), cols: 120, rows: 10 %>
|
11
11
|
</li>
|
12
12
|
<% end -%>
|
13
13
|
</ol>
|
14
14
|
</fieldset>
|
15
|
-
<fieldset class="
|
16
|
-
|
17
|
-
|
18
|
-
<%= button_tag 'Submit' %>
|
19
|
-
</li>
|
20
|
-
</ol>
|
21
|
-
</field>
|
15
|
+
<fieldset class="redis-snippets__actions">
|
16
|
+
<%= button_tag "Submit", class: "redis-snippets__submit" %>
|
17
|
+
</fieldset>
|
22
18
|
<% end -%>
|
23
19
|
</div>
|
data/config/routes.rb
CHANGED
data/lib/redis_snippets/redis.rb
CHANGED
@@ -1,17 +1,22 @@
|
|
1
1
|
module RedisSnippets
|
2
2
|
class Redis
|
3
3
|
class << self
|
4
|
-
# Can't do method_missing on get/set as they're defined somewhere by Ruby.
|
5
4
|
def get(key)
|
6
|
-
|
5
|
+
connection.get(key)
|
7
6
|
end
|
8
7
|
|
9
8
|
def set(key, value)
|
10
|
-
|
9
|
+
connection.set(key, value)
|
11
10
|
end
|
12
11
|
|
13
|
-
def
|
14
|
-
|
12
|
+
def del(key)
|
13
|
+
connection.del(key)
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def connection
|
19
|
+
RedisSnippets::Engine.config.redis_snippets[:connection]
|
15
20
|
end
|
16
21
|
end
|
17
22
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module RedisSnippets
|
2
|
-
module
|
3
|
-
# If multi_site
|
2
|
+
module Util
|
3
|
+
# If multi_site is true the symbol returned will have the key returned with a prefix.
|
4
4
|
# This prefix is defined in your application using the redis_snippet_site_key method.
|
5
5
|
# redis_snippet_site_key should simply return a unique string per site. For instance
|
6
6
|
# it could be the domain of the site.
|