jahuty 3.0.0 → 3.1.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 +4 -4
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +5 -0
- data/README.md +100 -12
- data/jahuty.gemspec +1 -0
- data/lib/jahuty.rb +3 -0
- data/lib/jahuty/cache/facade.rb +46 -0
- data/lib/jahuty/cache/manager.rb +47 -0
- data/lib/jahuty/client.rb +18 -4
- data/lib/jahuty/resource/render.rb +1 -3
- data/lib/jahuty/service/snippet.rb +4 -8
- data/lib/jahuty/version.rb +1 -1
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 88cfffd7646bfc5849b4f45076f7dba175a65b8a5a89734e00db137dc49ee6e4
|
4
|
+
data.tar.gz: 85d9a607c72e94f041adc4fe22da7309f6228f6c07b50b49a1ad3f6c768be67c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d0292d5ee64c8d715a9506ef3586c0bcacddacf9c5b97a384b6bc608b119152220f3eda45f6a4b35792a7aab0bfa6895db0ed747b842ab4d45d561d0bdd7a271
|
7
|
+
data.tar.gz: dba24f33415884a663f959c9a8ebf7b443773b88ade368d46a2c7026c8cc1ead6b60c481b4d5fb9f4e956ba6ef2d41dbdf12b20fb9a333a4e75544cdd9c00759
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
+
## 3.1.0 - 2020-01-04
|
9
|
+
|
10
|
+
- Add caching support for any cache implementation that supports `get/set` or `read/write` methods.
|
11
|
+
- Default to using in-memory [mini-cache](https://github.com/derrickreimer/mini_cache) storage.
|
12
|
+
|
8
13
|
## 3.0.0 - 2020-12-30
|
9
14
|
|
10
15
|
- Change from a static-based architecture (e.g., `Jahuty::Snippet.render(1)`) to an instance-based one (e.g., `jahuty.snippets.render(1)`) to make the library easier to develop, test, and use.
|
data/README.md
CHANGED
@@ -10,20 +10,20 @@ This library requires [Ruby 2.6+](https://www.ruby-lang.org/en/downloads/release
|
|
10
10
|
|
11
11
|
It is multi-platform, and we strive to make it run equally well on Windows, Linux, and OSX.
|
12
12
|
|
13
|
-
|
13
|
+
To install, add this line to your application's `Gemfile` and run `bundle install`:
|
14
14
|
|
15
15
|
```ruby
|
16
|
-
gem 'jahuty', '~> 3.
|
16
|
+
gem 'jahuty', '~> 3.1'
|
17
17
|
```
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
-
Instantiate the client with your [API key](https://docs.jahuty.com/api#authentication) and use `snippets.render
|
21
|
+
Instantiate the client with your [API key](https://docs.jahuty.com/api#authentication) and use `snippets.render` to render your snippet:
|
22
22
|
|
23
23
|
```ruby
|
24
24
|
jahuty = Jahuty::Client.new(api_key: 'YOUR_API_KEY')
|
25
25
|
|
26
|
-
puts jahuty.snippets.render
|
26
|
+
puts jahuty.snippets.render YOUR_SNIPPET_ID
|
27
27
|
```
|
28
28
|
|
29
29
|
You can also access the render's content with `to_s` or `content`:
|
@@ -31,7 +31,7 @@ You can also access the render's content with `to_s` or `content`:
|
|
31
31
|
```ruby
|
32
32
|
jahuty = Jahuty::Client.new(api_key: 'YOUR_API_KEY')
|
33
33
|
|
34
|
-
render = jahuty.snippets.render
|
34
|
+
render = jahuty.snippets.render YOUR_SNIPPET_ID
|
35
35
|
|
36
36
|
a = render.to_s
|
37
37
|
|
@@ -43,16 +43,14 @@ a == b # returns true
|
|
43
43
|
In an HTML view:
|
44
44
|
|
45
45
|
```html+erb
|
46
|
-
<%-
|
47
|
-
jahuty = Jahuty::Client.new(api_key: 'YOUR_API_KEY')
|
48
|
-
%>
|
46
|
+
<%- jahuty = Jahuty::Client.new(api_key: 'YOUR_API_KEY') -%>
|
49
47
|
<!doctype html>
|
50
48
|
<html>
|
51
49
|
<head>
|
52
50
|
<title>Awesome example</title>
|
53
51
|
</head>
|
54
52
|
<body>
|
55
|
-
|
53
|
+
<%== jahuty.snippets.render YOUR_SNIPPET_ID %>
|
56
54
|
</body>
|
57
55
|
```
|
58
56
|
|
@@ -63,7 +61,7 @@ You can [pass parameters](https://docs.jahuty.com/liquid/parameters) into your s
|
|
63
61
|
```ruby
|
64
62
|
jahuty = Jahuty::Client.new(api_key: 'YOUR_API_KEY')
|
65
63
|
|
66
|
-
jahuty.snippets.render
|
64
|
+
jahuty.snippets.render YOUR_SNIPPET_ID, params: { foo: 'bar' }
|
67
65
|
```
|
68
66
|
|
69
67
|
The parameters above would be equivalent to [assigning the variable](https://docs.jahuty.com/liquid/variables) below in your snippet:
|
@@ -72,13 +70,103 @@ The parameters above would be equivalent to [assigning the variable](https://doc
|
|
72
70
|
{% assign foo = "bar" %}
|
73
71
|
```
|
74
72
|
|
73
|
+
## Caching
|
74
|
+
|
75
|
+
You can use caching to control how frequently this library requests the latest content from Jahuty's API.
|
76
|
+
|
77
|
+
* When content is in _development_ (i.e., frequently changing and low traffic), you can use the default in-memory store to view content changes instantaneously with slower response times.
|
78
|
+
* When content is in _production_ (i.e., more stable and high traffic), you can use persistent caching to update content less frequently and improve your application's response time.
|
79
|
+
|
80
|
+
### Caching in memory (default)
|
81
|
+
|
82
|
+
By default, this library uses an in-memory cache to avoid requesting the same render more than once during the same request lifecycle. For example:
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
jahuty = Jahuty::Client.new(api_key: 'YOUR_API_KEY')
|
86
|
+
|
87
|
+
# This call will send a synchronous API request; cache the result in memory;
|
88
|
+
# and, return the result to the caller.
|
89
|
+
render1 = jahuty.snippets.render YOUR_SNIPPET_ID
|
90
|
+
|
91
|
+
# This call skips sending an API request and uses the cached value instead.
|
92
|
+
render2 = jahuty.snippets.render YOUR_SNIPPET_ID
|
93
|
+
```
|
94
|
+
|
95
|
+
The in-memory cache only persists for the duration of the original request, however. At the end of the request's lifecycle, the cache will be discarded. To store renders across requests, you need a persistent cache.
|
96
|
+
|
97
|
+
### Caching persistently
|
98
|
+
|
99
|
+
A persistent cache allows renders to be cached across multiple requests. This reduces the number of synchronous network requests to Jahuty's API and improves your application's average response time.
|
100
|
+
|
101
|
+
To configure Jahuty to use your persistent cache, pass a cache implementation to the client via the `cache` configuration option:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
jahuty = new Jahuty::Client.new(
|
105
|
+
api_key: 'YOUR_API_KEY',
|
106
|
+
cache: cache
|
107
|
+
)
|
108
|
+
```
|
109
|
+
|
110
|
+
The persistent cache implementation you choose and configure is up to you. There are many libraries available, and most frameworks provide their own. At this time, we support any object which responds to `get(key)`/`set(key, value, expires_in:)` or `read(key)`/`write(key, value, expires_in:)` including [ActiveSupport::Cache::Store](https://api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html#method-i-fetch).
|
111
|
+
|
112
|
+
### Expiring
|
113
|
+
|
114
|
+
There are three methods for configuring this library's `:expires_in`, the amount of time between when a render is stored and when it's considered stale. From lowest-to-highest precedence, the methods are:
|
115
|
+
|
116
|
+
1. configuring your caching implementation,
|
117
|
+
1. configuring this library's default `:expires_in`, and
|
118
|
+
1. configuring a render's `:expires_in`.
|
119
|
+
|
120
|
+
#### Configuring your caching implementation
|
121
|
+
|
122
|
+
You can usually configure your caching implementation with a default `:expires_in`. If no other `:expires_in` is configured, this library will defer to the caching implementation's default `:expires_in`.
|
123
|
+
|
124
|
+
#### Configuring this library's default `:expires_in`
|
125
|
+
|
126
|
+
You can configure a default `:expires_in` for all of this library's renders by passing an integer number of seconds via the client's `:expires_in` configuration option:
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
jahuty = Jahuty::Client.new(
|
130
|
+
api_key: 'YOUR_API_KEY',
|
131
|
+
cache: cache,
|
132
|
+
expires_in: 60 # <- Cache all renders for sixty seconds
|
133
|
+
)
|
134
|
+
```
|
135
|
+
|
136
|
+
If this library's default `:expires_in` is set, it will take precedence over the default `:expires_is` of the caching implementation.
|
137
|
+
|
138
|
+
#### Configuring a render's `:expires_in`
|
139
|
+
|
140
|
+
You can configure a single render's `:expires_in` by passing an integer number of seconds via its `:expires_in` configuration option:
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
# Default to the caching implementation's :expires_in for all renders.
|
144
|
+
jahuty = Jahuty::Client.new(api_key: 'YOUR_API_KEY', cache: cache)
|
145
|
+
|
146
|
+
# Except, cache this render for 60 seconds.
|
147
|
+
render = jahuty.snippets.render(1, expires_in: 60)
|
148
|
+
```
|
149
|
+
|
150
|
+
If a render's `:expires_in` is set, it will take precedence over the library's default `:expires_in` and the caching implementation's `:expires_in`.
|
151
|
+
|
152
|
+
### Disabling caching
|
153
|
+
|
154
|
+
You can disable caching, even the default in-memory caching, by passing an `:expires_in` of zero (`0`) or a negative integer (e.g., `-1`) via any of the methods described above. For example:
|
155
|
+
|
156
|
+
```ruby
|
157
|
+
# Disable all caching.
|
158
|
+
jahuty1 = Jahuty::Client.new(api_key: 'YOUR_API_KEY', expires_in: 0)
|
159
|
+
|
160
|
+
# Disable caching for this render.
|
161
|
+
jahuty2 = Jahuty::Client.new(api_key: 'YOUR_API_KEY', expires_in: 60)
|
162
|
+
jahuty2.snippets.render(1, expires_in: 0)
|
163
|
+
```
|
164
|
+
|
75
165
|
## Errors
|
76
166
|
|
77
167
|
If an error occurs with [Jahuty's API](https://docs.jahuty.com/api#errors), a `Jahuty::Exception::Error` will be raised:
|
78
168
|
|
79
169
|
```ruby
|
80
|
-
require 'jahuty'
|
81
|
-
|
82
170
|
begin
|
83
171
|
jahuty = Jahuty::Client.new(api_key: 'YOUR_API_KEY')
|
84
172
|
jahuty.snippets.render YOUR_SNIPPET_ID
|
data/jahuty.gemspec
CHANGED
@@ -32,6 +32,7 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.required_ruby_version = '~> 2.6'
|
33
33
|
|
34
34
|
spec.add_dependency 'faraday', '~> 1.0'
|
35
|
+
spec.add_dependency 'mini_cache', '~> 1.1'
|
35
36
|
|
36
37
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
37
38
|
spec.add_development_dependency 'rake', '~> 12.3'
|
data/lib/jahuty.rb
CHANGED
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jahuty
|
4
|
+
module Cache
|
5
|
+
# Abstracts away the differences in cache implementation methods and
|
6
|
+
# argument lists.
|
7
|
+
class Facade
|
8
|
+
def initialize(cache)
|
9
|
+
@cache = cache
|
10
|
+
end
|
11
|
+
|
12
|
+
def delete(key)
|
13
|
+
if @cache.respond_to? :delete
|
14
|
+
@cache.delete key
|
15
|
+
elsif @cache.respond_to? :unset
|
16
|
+
@cache.unset key
|
17
|
+
else
|
18
|
+
raise NoMethodError, 'Cache must respond to :delete or :unset'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def read(key)
|
23
|
+
if @cache.respond_to? :read
|
24
|
+
@cache.read key
|
25
|
+
elsif @cache.respond_to? :get
|
26
|
+
@cache.get key
|
27
|
+
else
|
28
|
+
raise NoMethodError, 'Cache must respond to :read or :get'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def write(key, value, expires_in: nil)
|
33
|
+
if Object.const_defined?('::ActiveSupport::Cache::Store') &&
|
34
|
+
@cache.is_a?(::ActiveSupport::Cache::Store)
|
35
|
+
@cache.write key, value, expires_in: expires_in, race_condition_ttl: 10
|
36
|
+
elsif @cache.respond_to? :write
|
37
|
+
@cache.write key, value, expires_in: expires_in
|
38
|
+
elsif @cache.respond_to? :set
|
39
|
+
@cache.set key, value, expires_in: expires_in
|
40
|
+
else
|
41
|
+
raise NoMethodError, 'Cache must respond to :write or :set'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jahuty
|
4
|
+
module Cache
|
5
|
+
# Fetches the requested action from the cache or API.
|
6
|
+
class Manager
|
7
|
+
def initialize(cache:, client:, expires_in: nil)
|
8
|
+
@client = client
|
9
|
+
@cache = Facade.new(cache)
|
10
|
+
@expires_in = expires_in
|
11
|
+
end
|
12
|
+
|
13
|
+
def fetch(action, expires_in: nil)
|
14
|
+
key = key action
|
15
|
+
value = @cache.read key
|
16
|
+
|
17
|
+
@cache.delete key unless value.nil? || cacheable(expires_in)
|
18
|
+
|
19
|
+
if value.nil?
|
20
|
+
value = @client.request action
|
21
|
+
@cache.write key, value, expires_in: expires_in || @expires_in if cacheable(expires_in)
|
22
|
+
end
|
23
|
+
|
24
|
+
value
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def cacheable(expires_in)
|
30
|
+
expires_in.nil? || expires_in.positive?
|
31
|
+
end
|
32
|
+
|
33
|
+
def key(action)
|
34
|
+
# We only build cache keys for show-render actions at this time.
|
35
|
+
unless action.is_a?(::Jahuty::Action::Show) && action.resource == 'render'
|
36
|
+
raise ArgumentError, 'Action must be show render'
|
37
|
+
end
|
38
|
+
|
39
|
+
fingerprint = Digest::MD5.new
|
40
|
+
fingerprint << "snippets/#{action.id}/render/"
|
41
|
+
fingerprint << action.params.to_json
|
42
|
+
|
43
|
+
"jahuty_#{fingerprint.hexdigest}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/jahuty/client.rb
CHANGED
@@ -1,14 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'mini_cache'
|
4
|
+
|
3
5
|
module Jahuty
|
4
6
|
# Executes requests against Jahuty's API and returns resources.
|
5
7
|
class Client
|
6
|
-
def initialize(api_key:)
|
7
|
-
@api_key
|
8
|
-
@
|
8
|
+
def initialize(api_key:, cache: nil, expires_in: nil)
|
9
|
+
@api_key = api_key
|
10
|
+
@cache = cache || ::MiniCache::Store.new
|
11
|
+
@expires_in = expires_in
|
12
|
+
@services = Service::Factory.new(client: self)
|
9
13
|
end
|
10
14
|
|
11
|
-
# Allows services to
|
15
|
+
# Allows services to be accessed as properties (e.g., jahuty.snippets).
|
12
16
|
def method_missing(name, *args, &block)
|
13
17
|
if args.empty? && @services.respond_to?(name)
|
14
18
|
@services.send(name)
|
@@ -17,6 +21,16 @@ module Jahuty
|
|
17
21
|
end
|
18
22
|
end
|
19
23
|
|
24
|
+
def fetch(action, expires_in: nil)
|
25
|
+
@manager ||= Cache::Manager.new(
|
26
|
+
client: self,
|
27
|
+
cache: @cache,
|
28
|
+
expires_in: expires_in || @expires_in
|
29
|
+
)
|
30
|
+
|
31
|
+
@manager.fetch(action)
|
32
|
+
end
|
33
|
+
|
20
34
|
def request(action)
|
21
35
|
@requests ||= Request::Factory.new
|
22
36
|
|
@@ -2,9 +2,7 @@
|
|
2
2
|
|
3
3
|
module Jahuty
|
4
4
|
module Resource
|
5
|
-
# A snippet's rendered content.
|
6
|
-
# combination of id and params (i.e., the same id can produce different
|
7
|
-
# renders with different params).
|
5
|
+
# A snippet's rendered content.
|
8
6
|
class Render
|
9
7
|
attr_accessor :content
|
10
8
|
|
@@ -4,16 +4,12 @@ module Jahuty
|
|
4
4
|
module Service
|
5
5
|
# A service for interacting with snippets.
|
6
6
|
class Snippet < Base
|
7
|
-
def render(id,
|
8
|
-
params = { params:
|
7
|
+
def render(id, params: {}, expires_in: nil)
|
8
|
+
params = { params: params.to_json } unless params.empty?
|
9
9
|
|
10
|
-
action = ::Jahuty::Action::Show.new(
|
11
|
-
id: id,
|
12
|
-
resource: 'render',
|
13
|
-
params: params || {}
|
14
|
-
)
|
10
|
+
action = ::Jahuty::Action::Show.new(id: id, resource: 'render', params: params)
|
15
11
|
|
16
|
-
@client.
|
12
|
+
@client.fetch action, expires_in: expires_in
|
17
13
|
end
|
18
14
|
end
|
19
15
|
end
|
data/lib/jahuty/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jahuty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jack Clayton
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mini_cache
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.1'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.1'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: bundler
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -187,6 +201,8 @@ files:
|
|
187
201
|
- lib/jahuty/action/base.rb
|
188
202
|
- lib/jahuty/action/show.rb
|
189
203
|
- lib/jahuty/api/client.rb
|
204
|
+
- lib/jahuty/cache/facade.rb
|
205
|
+
- lib/jahuty/cache/manager.rb
|
190
206
|
- lib/jahuty/client.rb
|
191
207
|
- lib/jahuty/exception/error.rb
|
192
208
|
- lib/jahuty/request/base.rb
|