renderful 0.2.0 → 0.3.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/.circleci/config.yml +4 -1
- data/.gitignore +1 -0
- data/.rubocop-https---relaxed-ruby-style-rubocop-yml +3 -24
- data/CHANGELOG.md +36 -12
- data/README.md +99 -158
- data/lib/renderful.rb +10 -7
- data/lib/renderful/cache/base.rb +31 -0
- data/lib/renderful/cache/null.rb +31 -0
- data/lib/renderful/cache/redis.rb +17 -4
- data/lib/renderful/client.rb +30 -19
- data/lib/renderful/component/base.rb +18 -0
- data/lib/renderful/content_entry.rb +24 -0
- data/lib/renderful/error/base.rb +7 -0
- data/lib/renderful/error/entry_not_found_error.rb +15 -0
- data/lib/renderful/error/no_component_error.rb +15 -0
- data/lib/renderful/provider/base.rb +25 -0
- data/lib/renderful/provider/contentful.rb +55 -0
- data/lib/renderful/provider/prismic.rb +46 -0
- data/lib/renderful/version.rb +1 -1
- data/renderful.gemspec +9 -3
- metadata +131 -28
- data/lib/renderful/cache.rb +0 -21
- data/lib/renderful/cache_invalidator.rb +0 -26
- data/lib/renderful/no_renderer_error.rb +0 -13
- data/lib/renderful/renderer.rb +0 -36
- data/lib/renderful/renderer/rails.rb +0 -29
data/lib/renderful.rb
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
4
|
-
|
5
|
-
require 'renderful/
|
6
|
-
require 'renderful/cache'
|
3
|
+
require 'renderful/error/base'
|
4
|
+
require 'renderful/error/entry_not_found_error'
|
5
|
+
require 'renderful/error/no_component_error'
|
6
|
+
require 'renderful/cache/base'
|
7
7
|
require 'renderful/cache/redis'
|
8
|
-
require 'renderful/
|
8
|
+
require 'renderful/cache/null'
|
9
|
+
require 'renderful/content_entry'
|
10
|
+
require 'renderful/provider/base'
|
11
|
+
require 'renderful/provider/contentful'
|
12
|
+
require 'renderful/provider/prismic'
|
9
13
|
require 'renderful/client'
|
10
|
-
require 'renderful/
|
11
|
-
require 'renderful/renderer/rails'
|
14
|
+
require 'renderful/component/base'
|
12
15
|
require 'renderful/version'
|
13
16
|
|
14
17
|
module Renderful
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Renderful
|
4
|
+
module Cache
|
5
|
+
class Base
|
6
|
+
def exist?(_key)
|
7
|
+
raise NotImplementedError
|
8
|
+
end
|
9
|
+
|
10
|
+
def read(_key)
|
11
|
+
raise NotImplementedError
|
12
|
+
end
|
13
|
+
|
14
|
+
def write(_key, _value)
|
15
|
+
raise NotImplementedError
|
16
|
+
end
|
17
|
+
|
18
|
+
def delete(*_keys)
|
19
|
+
raise NotImplementedError
|
20
|
+
end
|
21
|
+
|
22
|
+
def delete_matched(_pattern)
|
23
|
+
raise NotImplementedError
|
24
|
+
end
|
25
|
+
|
26
|
+
def fetch(_key)
|
27
|
+
raise NotImplementedError
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Renderful
|
4
|
+
module Cache
|
5
|
+
class Null < Base
|
6
|
+
def exist?(_key)
|
7
|
+
false
|
8
|
+
end
|
9
|
+
|
10
|
+
def read(_key)
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def write(key, value)
|
15
|
+
# noop
|
16
|
+
end
|
17
|
+
|
18
|
+
def delete(*keys)
|
19
|
+
# noop
|
20
|
+
end
|
21
|
+
|
22
|
+
def delete_matched(pattern)
|
23
|
+
# noop
|
24
|
+
end
|
25
|
+
|
26
|
+
def fetch(_key)
|
27
|
+
yield
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Renderful
|
4
|
-
|
5
|
-
class Redis <
|
4
|
+
module Cache
|
5
|
+
class Redis < Base
|
6
6
|
attr_reader :redis
|
7
7
|
|
8
8
|
def initialize(redis)
|
@@ -21,8 +21,21 @@ module Renderful
|
|
21
21
|
redis.set(key, value)
|
22
22
|
end
|
23
23
|
|
24
|
-
def delete(
|
25
|
-
redis.del(
|
24
|
+
def delete(*keys)
|
25
|
+
redis.del(*keys)
|
26
|
+
end
|
27
|
+
|
28
|
+
def delete_matched(pattern)
|
29
|
+
keys = redis.scan_each(match: pattern).to_a
|
30
|
+
delete(*keys)
|
31
|
+
end
|
32
|
+
|
33
|
+
def fetch(key)
|
34
|
+
return read(key) if exist?(key)
|
35
|
+
|
36
|
+
yield.tap do |value|
|
37
|
+
write(key, value)
|
38
|
+
end
|
26
39
|
end
|
27
40
|
end
|
28
41
|
end
|
data/lib/renderful/client.rb
CHANGED
@@ -2,34 +2,45 @@
|
|
2
2
|
|
3
3
|
module Renderful
|
4
4
|
class Client
|
5
|
-
attr_reader :
|
5
|
+
attr_reader :provider, :components, :cache
|
6
6
|
|
7
|
-
def initialize(
|
8
|
-
@
|
9
|
-
@
|
7
|
+
def initialize(provider:, components:, cache: Cache::Null.new)
|
8
|
+
@provider = provider
|
9
|
+
@components = components
|
10
10
|
@cache = cache
|
11
11
|
end
|
12
12
|
|
13
|
-
def render(
|
14
|
-
|
15
|
-
|
13
|
+
def render(entry_id, options = {})
|
14
|
+
cache.fetch(ContentEntry.build_cache_key(provider, id: entry_id)) do
|
15
|
+
content_entry = provider.find_entry(entry_id)
|
16
|
+
component = component_for_entry(content_entry)
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
if component.respond_to?(:render_in)
|
19
|
+
component.render_in(options.fetch(:view_context))
|
20
|
+
else
|
21
|
+
component.render
|
22
|
+
end
|
21
23
|
end
|
22
24
|
end
|
23
25
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
"contentful/#{entry.fetch(:content_type_id)}/#{entry.fetch(:entry_id)}"
|
26
|
+
def invalidate_cache_from_webhook(body)
|
27
|
+
result = provider.cache_keys_to_invalidate(body)
|
28
|
+
|
29
|
+
cache.delete(*result[:keys])
|
30
|
+
|
31
|
+
result[:patterns].each do |pattern|
|
32
|
+
cache.delete_matched(pattern)
|
32
33
|
end
|
33
34
|
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def component_klass_for_entry(content_entry)
|
39
|
+
components[content_entry.content_type] || fail(Error::NoComponentError, content_entry)
|
40
|
+
end
|
41
|
+
|
42
|
+
def component_for_entry(content_entry)
|
43
|
+
component_klass_for_entry(content_entry).new(entry: content_entry, client: self)
|
44
|
+
end
|
34
45
|
end
|
35
46
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Renderful
|
4
|
+
module Component
|
5
|
+
class Base
|
6
|
+
attr_reader :entry, :client
|
7
|
+
|
8
|
+
def initialize(entry:, client:)
|
9
|
+
@entry = entry
|
10
|
+
@client = client
|
11
|
+
end
|
12
|
+
|
13
|
+
def render
|
14
|
+
fail NotImplementedError
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Renderful
|
4
|
+
class ContentEntry
|
5
|
+
attr_reader :provider, :id, :content_type, :fields
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def build_cache_key(provider, id: nil)
|
9
|
+
['renderful', provider.cache_prefix, id || '*'].join('/')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(provider:, id:, content_type: nil, fields: {})
|
14
|
+
@provider = provider
|
15
|
+
@id = id
|
16
|
+
@content_type = content_type
|
17
|
+
@fields = fields
|
18
|
+
end
|
19
|
+
|
20
|
+
def cache_key
|
21
|
+
self.class.build_cache_key(provider, id: id)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Renderful
|
4
|
+
module Error
|
5
|
+
class EntryNotFoundError < Base
|
6
|
+
attr_reader :entry_id
|
7
|
+
|
8
|
+
def initialize(entry_id, *args)
|
9
|
+
@entry_id = entry_id
|
10
|
+
|
11
|
+
super "Cannot find entry #{@entry_id}", *args
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Renderful
|
4
|
+
module Error
|
5
|
+
class NoComponentError < Base
|
6
|
+
attr_reader :entry
|
7
|
+
|
8
|
+
def initialize(entry, *args)
|
9
|
+
@entry = entry
|
10
|
+
|
11
|
+
super "Cannot find component for content type #{entry.content_type}", *args
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Renderful
|
4
|
+
module Provider
|
5
|
+
class Base
|
6
|
+
attr_reader :options
|
7
|
+
|
8
|
+
def initialize(options)
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def cache_prefix
|
13
|
+
fail NotImplementedError
|
14
|
+
end
|
15
|
+
|
16
|
+
def find_entry(_entry_id)
|
17
|
+
fail NotImplementedError
|
18
|
+
end
|
19
|
+
|
20
|
+
def cache_keys_to_invalidate(_webhook_body)
|
21
|
+
fail NotImplementedError
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Renderful
|
4
|
+
module Provider
|
5
|
+
class Contentful < Base
|
6
|
+
def initialize(options)
|
7
|
+
super
|
8
|
+
|
9
|
+
fail ArgumentError, 'contentful option is required!' unless contentful
|
10
|
+
end
|
11
|
+
|
12
|
+
def cache_prefix
|
13
|
+
:contentful
|
14
|
+
end
|
15
|
+
|
16
|
+
def find_entry(entry_id)
|
17
|
+
entry = contentful.entry(entry_id)
|
18
|
+
raise Error::EntryNotFoundError, entry_id unless entry
|
19
|
+
|
20
|
+
wrap_entry(entry)
|
21
|
+
end
|
22
|
+
|
23
|
+
def cache_keys_to_invalidate(webhook_body)
|
24
|
+
params = webhook_body.is_a?(String) ? JSON.parse(webhook_body) : webhook_body
|
25
|
+
|
26
|
+
keys_to_invalidate = [ContentEntry.build_cache_key(self, id: params['sys']['id'])]
|
27
|
+
keys_to_invalidate += contentful.entries(links_to_entry: params['sys']['id']).map do |entry|
|
28
|
+
ContentEntry.build_cache_key(self, id: entry.id)
|
29
|
+
end
|
30
|
+
|
31
|
+
{
|
32
|
+
keys: keys_to_invalidate,
|
33
|
+
patterns: [],
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def wrap_entry(entry)
|
40
|
+
ContentEntry.new(
|
41
|
+
provider: self,
|
42
|
+
id: entry.id,
|
43
|
+
content_type: entry.content_type.id,
|
44
|
+
fields: entry.fields,
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
def entries_linking_to(entry_id); end
|
49
|
+
|
50
|
+
def contentful
|
51
|
+
options[:contentful]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Renderful
|
4
|
+
module Provider
|
5
|
+
class Prismic < Base
|
6
|
+
def initialize(options)
|
7
|
+
super
|
8
|
+
|
9
|
+
fail ArgumentError, 'prismic option is required!' unless prismic
|
10
|
+
end
|
11
|
+
|
12
|
+
def cache_prefix
|
13
|
+
:prismic
|
14
|
+
end
|
15
|
+
|
16
|
+
def find_entry(entry_id)
|
17
|
+
entry = prismic.getByID(entry_id)
|
18
|
+
raise Error::EntryNotFoundError, entry_id unless entry
|
19
|
+
|
20
|
+
wrap_entry(entry)
|
21
|
+
end
|
22
|
+
|
23
|
+
def cache_keys_to_invalidate(_webhook_body)
|
24
|
+
{
|
25
|
+
keys: [],
|
26
|
+
patterns: ['renderful/prismic/*'],
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def wrap_entry(entry)
|
33
|
+
ContentEntry.new(
|
34
|
+
provider: self,
|
35
|
+
id: entry.id,
|
36
|
+
content_type: entry.type,
|
37
|
+
fields: entry.fragments,
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
def prismic
|
42
|
+
options[:prismic]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/renderful/version.rb
CHANGED
data/renderful.gemspec
CHANGED
@@ -27,16 +27,22 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
28
|
spec.require_paths = ['lib']
|
29
29
|
|
30
|
-
spec.add_dependency 'contentful', '~> 2.11'
|
31
|
-
spec.add_dependency 'rails', ['>= 5.0.0', '< 7']
|
32
|
-
|
33
30
|
spec.add_development_dependency 'appraisal', '~> 2.2'
|
34
31
|
spec.add_development_dependency 'bundler', '~> 2.1'
|
32
|
+
spec.add_development_dependency 'capybara', '~> 3.32'
|
35
33
|
spec.add_development_dependency 'combustion', '~> 1.1'
|
34
|
+
spec.add_development_dependency 'contentful', '~> 2.11'
|
35
|
+
spec.add_development_dependency 'gem-release', '~> 2.1'
|
36
|
+
spec.add_development_dependency 'github_changelog_generator', '~> 1.15'
|
37
|
+
spec.add_development_dependency 'prismic.io', '~> 1.7'
|
38
|
+
spec.add_development_dependency 'rails', ['>= 5.0.0', '< 7']
|
36
39
|
spec.add_development_dependency 'rake', '~> 10.0'
|
37
40
|
spec.add_development_dependency 'redis', '~> 4.1'
|
38
41
|
spec.add_development_dependency 'rspec-rails', '~> 4.0.0.beta4'
|
39
42
|
spec.add_development_dependency 'rspec_junit_formatter', '~> 0.4.1'
|
40
43
|
spec.add_development_dependency 'rubocop', '~> 0.79.0'
|
41
44
|
spec.add_development_dependency 'rubocop-rspec', '~> 1.37'
|
45
|
+
spec.add_development_dependency 'vcr', '~> 5.1'
|
46
|
+
spec.add_development_dependency 'view_component', '~> 2.2'
|
47
|
+
spec.add_development_dependency 'webmock', '~> 3.8'
|
42
48
|
end
|