rabl 0.17.0 → 0.19.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/CHANGELOG.md +70 -0
- data/README.md +105 -23
- data/SECURITY.md +14 -0
- data/lib/rabl/builder.rb +19 -1
- data/lib/rabl/cache_engine.rb +21 -20
- data/lib/rabl/configuration.rb +71 -4
- data/lib/rabl/digestor.rb +4 -22
- data/lib/rabl/engine.rb +342 -36
- data/lib/rabl/helpers.rb +37 -10
- data/lib/rabl/multi_builder.rb +8 -2
- data/lib/rabl/partials.rb +2 -0
- data/lib/rabl/railtie.rb +12 -14
- data/lib/rabl/renderer.rb +14 -6
- data/lib/rabl/sources.rb +264 -25
- data/lib/rabl/template.rb +7 -47
- data/lib/rabl/template_cache_key.rb +93 -0
- data/lib/rabl/tracker.rb +2 -0
- data/lib/rabl/version.rb +3 -1
- data/lib/rabl.rb +25 -11
- metadata +12 -9
- data/lib/rabl/digestor/rails3.rb +0 -12
- data/lib/rabl/digestor/rails41.rb +0 -12
- data/lib/rabl/digestor/rails5.rb +0 -6
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'digest/sha1'
|
|
4
|
+
|
|
5
|
+
module Rabl
|
|
6
|
+
# Marks every cache key rabl reads or writes. Bump it when a release changes rendered output so
|
|
7
|
+
# that entries cached by earlier versions would be wrong: the keys change once, so no entry
|
|
8
|
+
# cached by an earlier version, which lacks that release's output fixes, is served.
|
|
9
|
+
# Keys before 0.18.0 had no marker ("rabl/", and "rabl_build/" in old releases); 2 is 0.18.0.
|
|
10
|
+
# The README's caching example shows the resulting prefix: update it when this changes.
|
|
11
|
+
CACHE_KEY_VERSION = 2
|
|
12
|
+
|
|
13
|
+
# Builds the parts of template cache keys. These are module functions rather than
|
|
14
|
+
# Engine methods so that they never shadow helpers a template calls.
|
|
15
|
+
module TemplateCacheKey
|
|
16
|
+
module_function
|
|
17
|
+
|
|
18
|
+
# Returns the key rabl reads and writes in the cache engine for the given parts. Earlier
|
|
19
|
+
# versions put their keys under "rabl/", so no key built here can be one of theirs.
|
|
20
|
+
# TemplateCacheKey.expand([user, "json"]) => "rabl-v2/users/1/json"
|
|
21
|
+
def expand(parts)
|
|
22
|
+
ActiveSupport::Cache.expand_cache_key(parts, "rabl-v#{CACHE_KEY_VERSION}")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Returns a digest of the given parts
|
|
26
|
+
# TemplateCacheKey.digest(["app/views/show.rabl", "object @user"]) => "4a1b..."
|
|
27
|
+
def digest(parts)
|
|
28
|
+
digest = Digest::SHA1.new
|
|
29
|
+
Array(parts).flatten.each { |part| digest << part.to_s << "\0" }
|
|
30
|
+
digest.hexdigest
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Returns a path that stays the same when the application moves: relative to the
|
|
34
|
+
# working directory when inside it, and nil for "(eval)" locations (the identity of
|
|
35
|
+
# the parent template tells evaluated sources apart).
|
|
36
|
+
# ceiling: paths outside the working directory stay absolute, so moving them changes
|
|
37
|
+
# the keys; a configurable root would let those move too.
|
|
38
|
+
# TemplateCacheKey.path("/app/views/show.rabl", "/app/") => "views/show.rabl"
|
|
39
|
+
def path(path, root = self.root)
|
|
40
|
+
path = path.to_s.dup.force_encoding(Encoding::BINARY) # paths may differ in encoding
|
|
41
|
+
return if path.empty? || path.start_with?("(eval")
|
|
42
|
+
|
|
43
|
+
root && path.start_with?(root) ? path.byteslice(root.bytesize..-1) : path
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Returns the column a block starts at, which tells apart blocks on one line, or nil when
|
|
47
|
+
# the runtime doesn't expose it.
|
|
48
|
+
# ceiling: without RubyVM::InstructionSequence (e.g. on JRuby), blocks that start on the
|
|
49
|
+
# same line of a template share an identity; put them on separate lines, or give them
|
|
50
|
+
# distinct cache keys.
|
|
51
|
+
def column(block)
|
|
52
|
+
return unless defined?(RubyVM::InstructionSequence)
|
|
53
|
+
|
|
54
|
+
iseq = RubyVM::InstructionSequence.of(block)
|
|
55
|
+
iseq && iseq.to_a[4][:code_location][1]
|
|
56
|
+
rescue StandardError
|
|
57
|
+
nil
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Returns the working directory with a trailing separator, as bytes, or nil if it is gone
|
|
61
|
+
def root
|
|
62
|
+
File.join(Dir.pwd, "").force_encoding(Encoding::BINARY)
|
|
63
|
+
rescue SystemCallError
|
|
64
|
+
nil
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Returns the options that change the shape of a rendering. A nested (hash format)
|
|
68
|
+
# rendering gets its root options from its parent; for other formats only root
|
|
69
|
+
# options given explicitly are added, so default keys have none. The format `extends`
|
|
70
|
+
# and `partial` look templates up in (lookup_format) is added when it isn't the one
|
|
71
|
+
# rendered, a hash counting as JSON: a nested rendering is a hash for every format.
|
|
72
|
+
# TemplateCacheKey.shape({ :format => "hash", :root => true }, "json") => ["root", "no_child_root"]
|
|
73
|
+
# TemplateCacheKey.shape({ :format => "hash", :child_root => true }, "xml") => ["lookup_format=xml"]
|
|
74
|
+
# TemplateCacheKey.shape({ :format => "json", :except => :b }, "json") => ["except=:b"]
|
|
75
|
+
def shape(options, lookup_format)
|
|
76
|
+
shape = []
|
|
77
|
+
format = options[:format].to_s
|
|
78
|
+
|
|
79
|
+
if format == "hash"
|
|
80
|
+
shape << "root" if options[:root]
|
|
81
|
+
shape << "no_child_root" unless options[:child_root]
|
|
82
|
+
shape << "object_root=#{options[:object_root_name].inspect}" if options[:object_root_name]
|
|
83
|
+
else
|
|
84
|
+
shape << "root=#{options[:root].inspect}" if options.key?(:root)
|
|
85
|
+
shape << "child_root=#{options[:child_root].inspect}" if options.key?(:child_root)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
shape << "except=#{Array(options[:except]).map { |name| name.inspect }.join(',')}" if options[:except]
|
|
89
|
+
shape << "lookup_format=#{lookup_format}" unless lookup_format == (format == "hash" ? "json" : format)
|
|
90
|
+
shape
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
data/lib/rabl/tracker.rb
CHANGED
data/lib/rabl/version.rb
CHANGED
data/lib/rabl.rb
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'active_support'
|
|
4
|
+
require 'active_support/core_ext/array/extract_options'
|
|
2
5
|
require 'active_support/core_ext/string/inflections'
|
|
3
6
|
require 'active_support/core_ext/object/blank'
|
|
4
7
|
require 'active_support/core_ext/hash/reverse_merge'
|
|
@@ -15,11 +18,12 @@ require 'rabl/multi_builder'
|
|
|
15
18
|
require 'rabl/configuration'
|
|
16
19
|
require 'rabl/renderer'
|
|
17
20
|
require 'rabl/cache_engine'
|
|
21
|
+
require 'rabl/template_cache_key'
|
|
18
22
|
|
|
19
23
|
if defined?(Rails) && Rails.respond_to?(:version)
|
|
20
|
-
require 'rabl/tracker'
|
|
21
|
-
require 'rabl/digestor'
|
|
22
|
-
require 'rabl/railtie'
|
|
24
|
+
require 'rabl/tracker'
|
|
25
|
+
require 'rabl/digestor'
|
|
26
|
+
require 'rabl/railtie'
|
|
23
27
|
end
|
|
24
28
|
|
|
25
29
|
# Rabl.register!
|
|
@@ -54,16 +58,18 @@ module Rabl
|
|
|
54
58
|
end
|
|
55
59
|
|
|
56
60
|
# Fetches from the source_cache, stores block result in cache if nil
|
|
57
|
-
# Used to cache the contents and paths to various rabl templates
|
|
58
|
-
#
|
|
59
|
-
|
|
61
|
+
# Used to cache the contents and paths to various rabl templates, keyed by
|
|
62
|
+
# everything the lookup depends on (the file, the view path and the lookup details)
|
|
63
|
+
# source_cache("users/index", ["path/to/view"], [:json]) { "/full/path/to/template/users/index" }
|
|
64
|
+
def source_cache(file, view_path, lookup = nil)
|
|
60
65
|
return yield unless Rabl.configuration.cache_sources
|
|
61
66
|
|
|
62
|
-
cache_key = [file, view_path].compact.join(":")
|
|
63
|
-
|
|
64
67
|
@_source_cache ||= {}
|
|
65
68
|
|
|
66
|
-
|
|
69
|
+
# stores a frozen copy of the key, so later changes to the caller's strings don't reach it
|
|
70
|
+
@_source_cache.fetch([file, view_path, lookup]) do
|
|
71
|
+
@_source_cache[frozen_copy([file, view_path, lookup])] = yield
|
|
72
|
+
end
|
|
67
73
|
end
|
|
68
74
|
|
|
69
75
|
# Resets the RABL source cache
|
|
@@ -71,6 +77,16 @@ module Rabl
|
|
|
71
77
|
@_source_cache = {}
|
|
72
78
|
end
|
|
73
79
|
|
|
80
|
+
# Returns a copy of value whose Strings and Arrays are frozen, for cache keys that
|
|
81
|
+
# must not change when the caller's objects do
|
|
82
|
+
def frozen_copy(value)
|
|
83
|
+
case value
|
|
84
|
+
when Array then value.map { |item| frozen_copy(item) }.freeze
|
|
85
|
+
when String then value.frozen? ? value : value.dup.freeze
|
|
86
|
+
else value
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
74
90
|
# Renders an object using a specified template within an application.
|
|
75
91
|
# render(@post, 'posts/show', :view_path => "/path/to/app/views")
|
|
76
92
|
def render(object, source, options = {})
|
|
@@ -83,6 +99,4 @@ end
|
|
|
83
99
|
if defined?(Padrino)
|
|
84
100
|
require 'padrino-core'
|
|
85
101
|
Padrino.after_load { Rabl.register! }
|
|
86
|
-
elsif defined?(Rails.version) && Rails.version =~ /^2/
|
|
87
|
-
Rabl.register!
|
|
88
102
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rabl
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.19.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nathan Esquenazi
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-11-01 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -16,14 +16,14 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
19
|
+
version: '6.1'
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
26
|
+
version: '6.1'
|
|
27
27
|
description: General ruby templating with json, bson, xml and msgpack support
|
|
28
28
|
email:
|
|
29
29
|
- nesquena@gmail.com
|
|
@@ -35,14 +35,12 @@ files:
|
|
|
35
35
|
- CONTRIBUTING.md
|
|
36
36
|
- MIT-LICENSE
|
|
37
37
|
- README.md
|
|
38
|
+
- SECURITY.md
|
|
38
39
|
- lib/rabl.rb
|
|
39
40
|
- lib/rabl/builder.rb
|
|
40
41
|
- lib/rabl/cache_engine.rb
|
|
41
42
|
- lib/rabl/configuration.rb
|
|
42
43
|
- lib/rabl/digestor.rb
|
|
43
|
-
- lib/rabl/digestor/rails3.rb
|
|
44
|
-
- lib/rabl/digestor/rails41.rb
|
|
45
|
-
- lib/rabl/digestor/rails5.rb
|
|
46
44
|
- lib/rabl/engine.rb
|
|
47
45
|
- lib/rabl/helpers.rb
|
|
48
46
|
- lib/rabl/multi_builder.rb
|
|
@@ -51,12 +49,17 @@ files:
|
|
|
51
49
|
- lib/rabl/renderer.rb
|
|
52
50
|
- lib/rabl/sources.rb
|
|
53
51
|
- lib/rabl/template.rb
|
|
52
|
+
- lib/rabl/template_cache_key.rb
|
|
54
53
|
- lib/rabl/tracker.rb
|
|
55
54
|
- lib/rabl/version.rb
|
|
56
55
|
homepage: https://github.com/nesquena/rabl
|
|
57
56
|
licenses:
|
|
58
57
|
- MIT
|
|
59
|
-
metadata:
|
|
58
|
+
metadata:
|
|
59
|
+
changelog_uri: https://github.com/nesquena/rabl/blob/master/CHANGELOG.md
|
|
60
|
+
source_code_uri: https://github.com/nesquena/rabl
|
|
61
|
+
bug_tracker_uri: https://github.com/nesquena/rabl/issues
|
|
62
|
+
rubygems_mfa_required: 'true'
|
|
60
63
|
post_install_message:
|
|
61
64
|
rdoc_options: []
|
|
62
65
|
require_paths:
|
|
@@ -65,7 +68,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
65
68
|
requirements:
|
|
66
69
|
- - ">="
|
|
67
70
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '
|
|
71
|
+
version: '2.7'
|
|
69
72
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
70
73
|
requirements:
|
|
71
74
|
- - ">="
|
data/lib/rabl/digestor/rails3.rb
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
require 'action_view'
|
|
2
|
-
|
|
3
|
-
module Rabl
|
|
4
|
-
class Digestor < ActionView::Digestor
|
|
5
|
-
def self.digest(name, format, finder, options = {})
|
|
6
|
-
cache_key = [name, format] + Array.wrap(options[:dependencies])
|
|
7
|
-
@@cache[cache_key.join('.')] ||= begin
|
|
8
|
-
Digestor.new(name, format, finder, options).digest
|
|
9
|
-
end
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
end
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
require 'action_view'
|
|
2
|
-
|
|
3
|
-
module Rabl
|
|
4
|
-
class Digestor < ActionView::Digestor
|
|
5
|
-
def self.digest(options = {})
|
|
6
|
-
cache_key = [options[:name]] + Array.wrap(options[:dependencies])
|
|
7
|
-
@@cache[cache_key.join('.')] ||= begin
|
|
8
|
-
Digestor.new({ :name => options[:name], :finder => options[:finder] }.merge!(options)).digest
|
|
9
|
-
end
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
end
|