jahuty 3.1.1 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +64 -8
- data/lib/jahuty.rb +5 -2
- data/lib/jahuty/action/index.rb +9 -0
- data/lib/jahuty/client.rb +14 -19
- data/lib/jahuty/request/factory.rb +15 -3
- data/lib/jahuty/resource/factory.rb +5 -28
- data/lib/jahuty/resource/render.rb +5 -3
- data/lib/jahuty/response/handler.rb +60 -0
- data/lib/jahuty/service/snippet.rb +85 -4
- data/lib/jahuty/util.rb +25 -0
- data/lib/jahuty/version.rb +1 -1
- metadata +5 -4
- data/lib/jahuty/cache/manager.rb +0 -47
- data/lib/jahuty/service/factory.rb +0 -46
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 42d427523be1564e07087d282367b7c13b9e80ac7219522a26a86a04f6fd23e7
|
4
|
+
data.tar.gz: 5f164380a18fda536c08c918dbfaaba6aaffc02183cfb2e74c6944b3e0bc42c3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f5b8c35c587b3f26a7fce8830963c98c859307e444edf5a0b058695e954fc5ce1dd0220b25f99d874ed983f1c72474546b51a2294f718bbea0358198d01ce6f6
|
7
|
+
data.tar.gz: 6f037d7ee49936532c2bd2ed5ed6f91942352f95082da4af28bd390afd3bc0d0dfdcda847f2c4e4ad742e4b1702562c9c6cba6c0fd5df4c923756c4113aa3d6a
|
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.2.0 - 2020-03-08
|
9
|
+
|
10
|
+
* Added collections to the library with `all_renders` method. This was a rather large change and required adding new objects like `Action::Show`, refactoring old ones like `Resource::Factory`, and removing some objects like `Cache::Manager` and `Service::Factory` which added unnecessary complexity.
|
11
|
+
* Added `snippet_id` to `Resource::Render` to help keep track of a render's parent snippet.
|
12
|
+
|
8
13
|
## 3.1.1 - 2020-02-26
|
9
14
|
|
10
15
|
- Add support for extra, unused attributes returned by the API to support evolution.
|
data/README.md
CHANGED
@@ -26,7 +26,7 @@ jahuty = Jahuty::Client.new(api_key: 'YOUR_API_KEY')
|
|
26
26
|
puts jahuty.snippets.render YOUR_SNIPPET_ID
|
27
27
|
```
|
28
28
|
|
29
|
-
You can
|
29
|
+
You can access the render's content with `to_s` or `content`:
|
30
30
|
|
31
31
|
```ruby
|
32
32
|
jahuty = Jahuty::Client.new(api_key: 'YOUR_API_KEY')
|
@@ -54,9 +54,19 @@ In an HTML view:
|
|
54
54
|
</body>
|
55
55
|
```
|
56
56
|
|
57
|
+
You can also use tags to render a collection of snippets with the `snippets.all_renders` method:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
jahuty = Jahuty::Client.new(api_key: 'YOUR_API_KEY')
|
61
|
+
|
62
|
+
renders = jahuty.snippets.all_renders 'YOUR_TAG'
|
63
|
+
|
64
|
+
renders.each { |render| puts render }
|
65
|
+
```
|
66
|
+
|
57
67
|
## Parameters
|
58
68
|
|
59
|
-
You can [pass parameters](https://docs.jahuty.com/liquid/parameters) into your
|
69
|
+
You can [pass parameters](https://docs.jahuty.com/liquid/parameters) into your renders using the `params` option:
|
60
70
|
|
61
71
|
```ruby
|
62
72
|
jahuty = Jahuty::Client.new(api_key: 'YOUR_API_KEY')
|
@@ -70,6 +80,30 @@ The parameters above would be equivalent to [assigning the variable](https://doc
|
|
70
80
|
{% assign foo = "bar" %}
|
71
81
|
```
|
72
82
|
|
83
|
+
If you're rendering a collection, the first dimension of the `params` key determines the parameters' scope. Use an asterisk key (`*`) to pass the same parameters to all snippets, or use a snippet id as key to pass parameters to a specific snippet.
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
jahuty = Jahuty::Client.new(api_key: 'YOUR_API_KEY')
|
87
|
+
|
88
|
+
jahuty.snippets.all_renders 'YOUR_TAG', params: {
|
89
|
+
'*' => { foo: 'bar' },
|
90
|
+
'1' => { baz: 'qux' }
|
91
|
+
}
|
92
|
+
```
|
93
|
+
|
94
|
+
This will pass the params `{ foo: 'bar' }` to all snippets, except for snippet `1`, which will be passed `{ foo: 'bar', baz: 'qux' }`.
|
95
|
+
|
96
|
+
The two parameter lists will be merged recursively, and parameters for a specific snippet will take precedence over parameters for all snippets. For example, the parameter `foo` will be assigned the value `"bar"` for all snippets, except for snippet `1`, where it will be assigned the value `"qux"`:
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
jahuty = Jahuty::Client.new(api_key: 'YOUR_API_KEY')
|
100
|
+
|
101
|
+
jahuty.snippets.all_renders 'YOUR_TAG', params: {
|
102
|
+
'*' => { foo: 'bar' },
|
103
|
+
'1' => { foo: 'qux' }
|
104
|
+
}
|
105
|
+
```
|
106
|
+
|
73
107
|
## Caching
|
74
108
|
|
75
109
|
You can use caching to control how frequently this library requests the latest content from Jahuty's API.
|
@@ -133,22 +167,44 @@ jahuty = Jahuty::Client.new(
|
|
133
167
|
)
|
134
168
|
```
|
135
169
|
|
136
|
-
If this library's default `:expires_in` is set, it will take precedence over the default `:
|
170
|
+
If this library's default `:expires_in` is set, it will take precedence over the default `:expires_in` of the caching implementation.
|
137
171
|
|
138
172
|
#### Configuring a render's `:expires_in`
|
139
173
|
|
140
|
-
You can configure
|
174
|
+
You can configure `:expires_in` for individual renders by passing an integer number of seconds via the render method's `:expires_in` configuration option:
|
141
175
|
|
142
176
|
```ruby
|
143
|
-
#
|
144
|
-
jahuty = Jahuty::Client.new(api_key: 'YOUR_API_KEY', cache: cache)
|
177
|
+
# Cache all renders 300 seconds (five minutes).
|
178
|
+
jahuty = Jahuty::Client.new(api_key: 'YOUR_API_KEY', cache: cache, expires_in: 300)
|
145
179
|
|
146
180
|
# Except, cache this render for 60 seconds.
|
147
|
-
render = jahuty.snippets.render
|
181
|
+
render = jahuty.snippets.render YOUR_SNIPPET_ID, expires_in: 60
|
182
|
+
|
183
|
+
# Except, cache the renders in this collection for 120 seconds.
|
184
|
+
render = jahuty.snippets.all_renders 'YOUR_TAG', expires_in: 120
|
148
185
|
```
|
149
186
|
|
150
187
|
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
188
|
|
189
|
+
### Caching collections
|
190
|
+
|
191
|
+
By default, this library will cache each render returned by `all_renders`:
|
192
|
+
|
193
|
+
```ruby
|
194
|
+
jahuty = Jahuty::Client.new(api_key: 'YOUR_API_KEY', cache: cache)
|
195
|
+
|
196
|
+
# Sends a network request, caches each render, and returns the collection.
|
197
|
+
jahuty.snippets.all_renders 'YOUR_TAG';
|
198
|
+
|
199
|
+
# If this reder exists in the collection, the cached value will be used instead
|
200
|
+
# of sending a network request for the latest version.
|
201
|
+
jahuty.snippets.render YOUR_SNIPPET_ID;
|
202
|
+
```
|
203
|
+
|
204
|
+
This is a powerful feature, especially when combined with a persistent cache. Using the `all_renders` method, you can render and cache an arbitrarily large chunk of content with a single network request. Because any subsequent call to `render` a snippet in the collection will use its cached version, you can reduce the number of network requests to load your content.
|
205
|
+
|
206
|
+
This method is even more powerful when combined with an asynchronous background job. When `all_renders` can be called outside your request cycle periodically, you can turn your cache into your content storage mechanism. You can render and cache dynamic content as frequently as you like without any hit to your application's response time.
|
207
|
+
|
152
208
|
### Disabling caching
|
153
209
|
|
154
210
|
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:
|
@@ -159,7 +215,7 @@ jahuty1 = Jahuty::Client.new(api_key: 'YOUR_API_KEY', expires_in: 0)
|
|
159
215
|
|
160
216
|
# Disable caching for this render.
|
161
217
|
jahuty2 = Jahuty::Client.new(api_key: 'YOUR_API_KEY', expires_in: 60)
|
162
|
-
jahuty2.snippets.render
|
218
|
+
jahuty2.snippets.render 1, expires_in: 0
|
163
219
|
```
|
164
220
|
|
165
221
|
## Errors
|
data/lib/jahuty.rb
CHANGED
@@ -3,12 +3,12 @@
|
|
3
3
|
require 'jahuty/version'
|
4
4
|
|
5
5
|
require 'jahuty/action/base'
|
6
|
+
require 'jahuty/action/index'
|
6
7
|
require 'jahuty/action/show'
|
7
8
|
|
8
9
|
require 'jahuty/api/client'
|
9
10
|
|
10
11
|
require 'jahuty/cache/facade'
|
11
|
-
require 'jahuty/cache/manager'
|
12
12
|
|
13
13
|
require 'jahuty/exception/error'
|
14
14
|
|
@@ -19,12 +19,15 @@ require 'jahuty/resource/problem'
|
|
19
19
|
require 'jahuty/resource/render'
|
20
20
|
require 'jahuty/resource/factory'
|
21
21
|
|
22
|
+
require 'jahuty/response/handler'
|
23
|
+
|
22
24
|
require 'jahuty/service/base'
|
23
25
|
require 'jahuty/service/snippet'
|
24
|
-
require 'jahuty/service/factory'
|
25
26
|
|
26
27
|
require 'jahuty/client'
|
27
28
|
|
29
|
+
require 'jahuty/util'
|
30
|
+
|
28
31
|
module Jahuty
|
29
32
|
BASE_URI = 'https://api.jahuty.com'
|
30
33
|
end
|
data/lib/jahuty/client.rb
CHANGED
@@ -7,30 +7,25 @@ module Jahuty
|
|
7
7
|
class Client
|
8
8
|
def initialize(api_key:, cache: nil, expires_in: nil)
|
9
9
|
@api_key = api_key
|
10
|
-
@cache = cache || ::MiniCache::Store.new
|
10
|
+
@cache = Cache::Facade.new(cache || ::MiniCache::Store.new)
|
11
11
|
@expires_in = expires_in
|
12
|
-
@services =
|
12
|
+
@services = {}
|
13
13
|
end
|
14
14
|
|
15
15
|
# Allows services to be accessed as properties (e.g., jahuty.snippets).
|
16
16
|
def method_missing(name, *args, &block)
|
17
|
-
if args.empty? &&
|
18
|
-
@services.
|
17
|
+
if args.empty? && name == :snippets
|
18
|
+
unless @services.key?(name)
|
19
|
+
@services[name] = Service::Snippet.new(
|
20
|
+
client: self, cache: @cache, expires_in: @expires_in
|
21
|
+
)
|
22
|
+
end
|
23
|
+
@services[name]
|
19
24
|
else
|
20
25
|
super
|
21
26
|
end
|
22
27
|
end
|
23
28
|
|
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
|
-
|
34
29
|
def request(action)
|
35
30
|
@requests ||= Request::Factory.new
|
36
31
|
|
@@ -40,17 +35,17 @@ module Jahuty
|
|
40
35
|
|
41
36
|
response = @client.send(request)
|
42
37
|
|
43
|
-
@
|
38
|
+
@responses ||= Response::Handler.new
|
44
39
|
|
45
|
-
|
40
|
+
result = @responses.call(action, response)
|
46
41
|
|
47
|
-
raise Exception::Error.new(
|
42
|
+
raise Exception::Error.new(result), 'API problem' if result.is_a?(Resource::Problem)
|
48
43
|
|
49
|
-
|
44
|
+
result
|
50
45
|
end
|
51
46
|
|
52
47
|
def respond_to_missing?(name, include_private = false)
|
53
|
-
|
48
|
+
name == :snippets || super
|
54
49
|
end
|
55
50
|
end
|
56
51
|
end
|
@@ -2,16 +2,28 @@
|
|
2
2
|
|
3
3
|
module Jahuty
|
4
4
|
module Request
|
5
|
-
# Instantiates a request from an action.
|
6
|
-
# we add actions, it will become more complicated.
|
5
|
+
# Instantiates a request from an action.
|
7
6
|
class Factory
|
8
7
|
def call(action)
|
9
8
|
Base.new(
|
10
9
|
method: 'get',
|
11
|
-
path:
|
10
|
+
path: path(action),
|
12
11
|
params: action.params
|
13
12
|
)
|
14
13
|
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def path(action)
|
18
|
+
case action
|
19
|
+
when ::Jahuty::Action::Show
|
20
|
+
"snippets/#{action.id}/render"
|
21
|
+
when ::Jahuty::Action::Index
|
22
|
+
'snippets/render'
|
23
|
+
else
|
24
|
+
raise ArgumentError, 'Action is not supported'
|
25
|
+
end
|
26
|
+
end
|
15
27
|
end
|
16
28
|
end
|
17
29
|
end
|
@@ -1,31 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'json'
|
4
|
-
|
5
3
|
module Jahuty
|
6
4
|
module Resource
|
7
|
-
#
|
8
|
-
# server's response.
|
5
|
+
# Instantiates and returns a resource.
|
9
6
|
class Factory
|
10
7
|
CLASSES = {
|
11
8
|
problem: Problem.name,
|
12
9
|
render: Render.name
|
13
10
|
}.freeze
|
14
11
|
|
15
|
-
def call(
|
16
|
-
|
17
|
-
resource_name = action.resource
|
18
|
-
elsif problem? response
|
19
|
-
resource_name = 'problem'
|
20
|
-
else
|
21
|
-
raise ArgumentError, 'Unexpected response'
|
22
|
-
end
|
23
|
-
|
24
|
-
resource_class = class_name(resource_name.to_sym)
|
12
|
+
def call(resource_name, payload)
|
13
|
+
klass = class_name(resource_name.to_sym)
|
25
14
|
|
26
|
-
|
15
|
+
raise ArgumentError, "#{resource_name} missing" if klass.nil?
|
27
16
|
|
28
|
-
Object.const_get(
|
17
|
+
Object.const_get(klass).send(:from, **payload)
|
29
18
|
end
|
30
19
|
|
31
20
|
private
|
@@ -33,18 +22,6 @@ module Jahuty
|
|
33
22
|
def class_name(resource_name)
|
34
23
|
CLASSES[resource_name.to_sym]
|
35
24
|
end
|
36
|
-
|
37
|
-
def problem?(response)
|
38
|
-
response.headers['Content-Type'] == 'application/problem+json'
|
39
|
-
end
|
40
|
-
|
41
|
-
def parse(response)
|
42
|
-
JSON.parse(response.body, symbolize_names: true)
|
43
|
-
end
|
44
|
-
|
45
|
-
def success?(response)
|
46
|
-
response.status.between?(200, 299)
|
47
|
-
end
|
48
25
|
end
|
49
26
|
end
|
50
27
|
end
|
@@ -4,16 +4,18 @@ module Jahuty
|
|
4
4
|
module Resource
|
5
5
|
# A snippet's rendered content.
|
6
6
|
class Render
|
7
|
-
attr_accessor :content
|
7
|
+
attr_accessor :content, :snippet_id
|
8
8
|
|
9
|
-
def initialize(content:)
|
9
|
+
def initialize(content:, snippet_id:)
|
10
10
|
@content = content
|
11
|
+
@snippet_id = snippet_id
|
11
12
|
end
|
12
13
|
|
13
14
|
def self.from(data)
|
14
15
|
raise ArgumentError.new, 'Key :content missing' unless data.key?(:content)
|
16
|
+
raise ArgumentError.new, 'Key :snippet_id missing' unless data.key?(:snippet_id)
|
15
17
|
|
16
|
-
Render.new(data.slice(:content))
|
18
|
+
Render.new(data.slice(:content, :snippet_id))
|
17
19
|
end
|
18
20
|
|
19
21
|
def to_s
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Jahuty
|
6
|
+
module Response
|
7
|
+
# Inspects the response and returns the appropriate resource or collection.
|
8
|
+
class Handler
|
9
|
+
def call(action, response)
|
10
|
+
resource_name = name_resource action, response
|
11
|
+
|
12
|
+
payload = parse response
|
13
|
+
|
14
|
+
@resources ||= ::Jahuty::Resource::Factory.new
|
15
|
+
|
16
|
+
if collection?(action, payload)
|
17
|
+
payload.map { |data| @resources.call resource_name, data }
|
18
|
+
elsif resource?(action, payload)
|
19
|
+
@resources.call resource_name, payload
|
20
|
+
else
|
21
|
+
raise ArgumentError, 'Action and payload mismatch'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def collection?(action, payload)
|
28
|
+
action.is_a?(Action::Index) && payload.is_a?(::Array)
|
29
|
+
end
|
30
|
+
|
31
|
+
def name_resource(action, response)
|
32
|
+
if success? response
|
33
|
+
action.resource
|
34
|
+
elsif problem? response
|
35
|
+
'problem'
|
36
|
+
else
|
37
|
+
raise ArgumentError, 'Unexpected response'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def parse(response)
|
42
|
+
JSON.parse(response.body, symbolize_names: true)
|
43
|
+
end
|
44
|
+
|
45
|
+
def problem?(response)
|
46
|
+
response.headers['Content-Type'].include?('application/problem+json') &&
|
47
|
+
(response.status < 200 || response.status >= 300)
|
48
|
+
end
|
49
|
+
|
50
|
+
def resource?(action, payload)
|
51
|
+
!action.is_a?(Action::Index) && payload.is_a?(::Object)
|
52
|
+
end
|
53
|
+
|
54
|
+
def success?(response)
|
55
|
+
response.headers['Content-Type'].include?('application/json') &&
|
56
|
+
response.status.between?(200, 299)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -4,12 +4,93 @@ module Jahuty
|
|
4
4
|
module Service
|
5
5
|
# A service for interacting with snippets.
|
6
6
|
class Snippet < Base
|
7
|
-
def
|
8
|
-
|
7
|
+
def initialize(client:, cache:, expires_in: nil)
|
8
|
+
super(client: client)
|
9
9
|
|
10
|
-
|
10
|
+
@cache = cache
|
11
|
+
@expires_in = expires_in
|
12
|
+
end
|
13
|
+
|
14
|
+
def all_renders(tag, params: {}, expires_in: nil)
|
15
|
+
renders = index_renders tag: tag, params: params
|
16
|
+
|
17
|
+
cache_renders renders: renders, params: params, expires_in: expires_in
|
18
|
+
|
19
|
+
renders
|
20
|
+
end
|
21
|
+
|
22
|
+
def render(snippet_id, params: {}, expires_in: nil)
|
23
|
+
expires_in ||= @expires_in
|
24
|
+
|
25
|
+
key = cache_key snippet_id: snippet_id, params: params
|
26
|
+
|
27
|
+
render = @cache.read(key)
|
28
|
+
|
29
|
+
@cache.delete key unless render.nil? || cacheable?(expires_in)
|
30
|
+
|
31
|
+
if render.nil?
|
32
|
+
render = show_render snippet_id: snippet_id, params: params
|
33
|
+
|
34
|
+
@cache.write key, render, expires_in: expires_in if cacheable?(expires_in)
|
35
|
+
end
|
36
|
+
|
37
|
+
render
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def cache_key(snippet_id:, params: {})
|
43
|
+
fingerprint = Digest::MD5.new
|
44
|
+
fingerprint << "snippets/#{snippet_id}/render/"
|
45
|
+
fingerprint << params.to_json
|
46
|
+
|
47
|
+
"jahuty_#{fingerprint.hexdigest}"
|
48
|
+
end
|
49
|
+
|
50
|
+
def cache_renders(renders:, params:, expires_in: nil)
|
51
|
+
expires_in ||= @expires_in
|
52
|
+
|
53
|
+
return unless cacheable?(expires_in)
|
54
|
+
|
55
|
+
global_params = params['*'] || {}
|
56
|
+
|
57
|
+
renders.each do |render|
|
58
|
+
local_params = params[render.snippet_id.to_s] || {}
|
59
|
+
render_params = ::Jahuty::Util.deep_merge global_params, local_params
|
60
|
+
|
61
|
+
key = cache_key snippet_id: render.snippet_id, params: render_params
|
62
|
+
|
63
|
+
@cache.write key, render, expires_in: expires_in
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def cacheable?(expires_in)
|
68
|
+
expires_in.nil? || expires_in.positive?
|
69
|
+
end
|
70
|
+
|
71
|
+
def index_renders(tag:, params: {})
|
72
|
+
request_params = { tag: tag }
|
73
|
+
request_params[:params] = params.to_json unless params.empty?
|
74
|
+
|
75
|
+
action = ::Jahuty::Action::Index.new(
|
76
|
+
resource: 'render',
|
77
|
+
params: request_params
|
78
|
+
)
|
79
|
+
|
80
|
+
@client.request action
|
81
|
+
end
|
82
|
+
|
83
|
+
def show_render(snippet_id:, params: {})
|
84
|
+
request_params = {}
|
85
|
+
request_params[:params] = params.to_json unless params.empty?
|
86
|
+
|
87
|
+
action = ::Jahuty::Action::Show.new(
|
88
|
+
id: snippet_id,
|
89
|
+
resource: 'render',
|
90
|
+
params: request_params
|
91
|
+
)
|
11
92
|
|
12
|
-
@client.
|
93
|
+
@client.request action
|
13
94
|
end
|
14
95
|
end
|
15
96
|
end
|
data/lib/jahuty/util.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jahuty
|
4
|
+
# Utility methods.
|
5
|
+
class Util
|
6
|
+
# Deeply merges two hashes like Rails.
|
7
|
+
#
|
8
|
+
# Ideally, the API and this library could use the same method to merge
|
9
|
+
# parameters. This library's method just needs to be deterministic and not
|
10
|
+
# collide distinct combinations.
|
11
|
+
#
|
12
|
+
# @see https://github.com/rails/rails/blob/main/activesupport/lib/active_support/core_ext/hash/deep_merge.rb
|
13
|
+
def self.deep_merge(first_hash, other_hash, &block)
|
14
|
+
first_hash.merge!(other_hash) do |key, first_val, other_val|
|
15
|
+
if first_val.is_a?(Hash) && other_val.is_a?(Hash)
|
16
|
+
deep_merge(first_val, other_val, &block)
|
17
|
+
elsif block
|
18
|
+
yield(key, first_val, other_val)
|
19
|
+
else
|
20
|
+
other_val
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
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.2.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: 2021-
|
11
|
+
date: 2021-03-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -199,10 +199,10 @@ files:
|
|
199
199
|
- jahuty.gemspec
|
200
200
|
- lib/jahuty.rb
|
201
201
|
- lib/jahuty/action/base.rb
|
202
|
+
- lib/jahuty/action/index.rb
|
202
203
|
- lib/jahuty/action/show.rb
|
203
204
|
- lib/jahuty/api/client.rb
|
204
205
|
- lib/jahuty/cache/facade.rb
|
205
|
-
- lib/jahuty/cache/manager.rb
|
206
206
|
- lib/jahuty/client.rb
|
207
207
|
- lib/jahuty/exception/error.rb
|
208
208
|
- lib/jahuty/request/base.rb
|
@@ -210,9 +210,10 @@ files:
|
|
210
210
|
- lib/jahuty/resource/factory.rb
|
211
211
|
- lib/jahuty/resource/problem.rb
|
212
212
|
- lib/jahuty/resource/render.rb
|
213
|
+
- lib/jahuty/response/handler.rb
|
213
214
|
- lib/jahuty/service/base.rb
|
214
|
-
- lib/jahuty/service/factory.rb
|
215
215
|
- lib/jahuty/service/snippet.rb
|
216
|
+
- lib/jahuty/util.rb
|
216
217
|
- lib/jahuty/version.rb
|
217
218
|
homepage: https://www.jahuty.com
|
218
219
|
licenses:
|
data/lib/jahuty/cache/manager.rb
DELETED
@@ -1,47 +0,0 @@
|
|
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
|
@@ -1,46 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Jahuty
|
4
|
-
module Service
|
5
|
-
# Instantiates the requested service and memoizes it for subsequent
|
6
|
-
# requests.
|
7
|
-
class Factory
|
8
|
-
CLASSES = {
|
9
|
-
snippets: Snippet.name
|
10
|
-
}.freeze
|
11
|
-
|
12
|
-
def initialize(client:)
|
13
|
-
@client = client
|
14
|
-
@services = {}
|
15
|
-
end
|
16
|
-
|
17
|
-
def method_missing(name, *args, &block)
|
18
|
-
if args.empty? && class_name?(name)
|
19
|
-
unless @services.key?(name)
|
20
|
-
klass = class_name(name)
|
21
|
-
service = Object.const_get(klass).send(:new, client: @client)
|
22
|
-
@services[name] = service
|
23
|
-
end
|
24
|
-
|
25
|
-
@services[name]
|
26
|
-
else
|
27
|
-
super
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def respond_to_missing?(name, include_private = false)
|
32
|
-
class_name(name) || super
|
33
|
-
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def class_name(service_name)
|
38
|
-
CLASSES[service_name]
|
39
|
-
end
|
40
|
-
|
41
|
-
def class_name?(service_name)
|
42
|
-
CLASSES.key?(service_name)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|