liquidum 1.2.1 → 1.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/.devcontainer/devcontainer-lock.json +34 -0
- data/.devcontainer/devcontainer.json +46 -0
- data/.devcontainer/docker-compose.yml +102 -0
- data/.devcontainer/env.conf +31 -0
- data/.devcontainer/postStart.sh +16 -0
- data/.gitignore +2 -0
- data/.shipkit.yml +2 -0
- data/.worktreeinclude +2 -0
- data/CHANGELOG.md +11 -0
- data/Gemfile +5 -1
- data/README.md +57 -0
- data/app/controllers/liquidum/application_controller.rb +1 -1
- data/app/controllers/liquidum/variables_controller.rb +17 -0
- data/bin/de +1112 -0
- data/config/routes.rb +1 -1
- data/lib/liquidum/configuration.rb +3 -0
- data/lib/liquidum/drop.rb +84 -7
- data/lib/liquidum/liquid/tags/render_tag.rb +1 -1
- data/lib/liquidum/variable.rb +12 -0
- data/lib/liquidum/variables.rb +61 -0
- data/lib/liquidum/version.rb +1 -1
- data/lib/liquidum.rb +10 -3
- data/liquidum.gemspec +1 -1
- data/mise.toml +4 -0
- metadata +18 -9
- data/app/controllers/liquidum/completions_controller.rb +0 -15
data/config/routes.rb
CHANGED
|
@@ -38,6 +38,9 @@ module Liquidum
|
|
|
38
38
|
|
|
39
39
|
option :logger, default: -> { Logger.new($stdout).tap { |l| l.level = Logger::INFO } }, proc: true
|
|
40
40
|
option :liquidum_file_system, default: "Liquidum::LiquidumFileSystem"
|
|
41
|
+
# The controller Liquidum's controllers inherit from, to decide who may
|
|
42
|
+
# use them, e.g. "Admin::BaseController". Set it in an initializer.
|
|
43
|
+
option :parent_controller, default: "::ApplicationController"
|
|
41
44
|
attr_writer :i18n_store
|
|
42
45
|
|
|
43
46
|
def initialize
|
data/lib/liquidum/drop.rb
CHANGED
|
@@ -29,12 +29,12 @@ module Liquidum
|
|
|
29
29
|
result = send(pm)
|
|
30
30
|
|
|
31
31
|
h[pm] = if result.is_a? ApplicationDrop
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
result.to_h(max_level, current_level: current_level + 1)
|
|
33
|
+
elsif result.is_a? Enumerator::Lazy
|
|
34
|
+
result.map { |r| r.to_h(max_level, current_level: current_level + 1) }.force
|
|
35
|
+
else
|
|
36
|
+
result
|
|
37
|
+
end
|
|
38
38
|
end
|
|
39
39
|
h
|
|
40
40
|
end
|
|
@@ -42,6 +42,8 @@ module Liquidum
|
|
|
42
42
|
class << self
|
|
43
43
|
def association(*associations)
|
|
44
44
|
associations.each do |name|
|
|
45
|
+
self.associations << name.to_s
|
|
46
|
+
|
|
45
47
|
define_method(name) do
|
|
46
48
|
if @object.class.respond_to?(:reflect_on_all_associations)
|
|
47
49
|
relation = @object.class.reflect_on_all_associations.find do |a|
|
|
@@ -50,7 +52,7 @@ module Liquidum
|
|
|
50
52
|
end
|
|
51
53
|
return unless relation
|
|
52
54
|
|
|
53
|
-
klass =
|
|
55
|
+
klass = Drop.for_relation(relation)
|
|
54
56
|
|
|
55
57
|
Rails.logger.warn "No #{klass}" and return unless klass
|
|
56
58
|
|
|
@@ -64,6 +66,81 @@ module Liquidum
|
|
|
64
66
|
end
|
|
65
67
|
end
|
|
66
68
|
end
|
|
69
|
+
|
|
70
|
+
# Adds to what Liquidum works out about a variable for the editor's
|
|
71
|
+
# variable picker (see .variables):
|
|
72
|
+
#
|
|
73
|
+
# describe :total, type: :money, hint: "Including VAT"
|
|
74
|
+
# describe :portal_url, label: -> { I18n.t("orders.portal_url") }
|
|
75
|
+
# describe :owner, drop: "UserDrop"
|
|
76
|
+
# describe :tags, drop: "TagDrop", collection: true
|
|
77
|
+
#
|
|
78
|
+
# A label or hint can be a proc, to translate it in the current locale.
|
|
79
|
+
def describe(name, label: nil, type: nil, hint: nil, drop: nil, collection: nil)
|
|
80
|
+
descriptions[name.to_s] = {label: label, type: type, hint: hint, drop: drop, collection: collection}.compact
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def descriptions
|
|
84
|
+
@descriptions ||= superclass.respond_to?(:descriptions) ? superclass.descriptions.dup : {}
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def associations
|
|
88
|
+
@associations ||= superclass.respond_to?(:associations) ? superclass.associations.dup : []
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# The model the drop is for, for labels, types and associations:
|
|
92
|
+
# OrderDrop is for Order. Override it when the names don't match.
|
|
93
|
+
def model
|
|
94
|
+
name&.delete_suffix("Drop")&.safe_constantize
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# The variables a template can use on this drop, one level deep, with
|
|
98
|
+
# labels in the current locale. Only what Liquid can call is listed, so
|
|
99
|
+
# not the helpers every Liquidum::Drop has (to_gid, to_h, …).
|
|
100
|
+
def variables
|
|
101
|
+
(invokable_methods - HELPERS).sort.filter_map do |name|
|
|
102
|
+
next if instance_method(name).parameters.any? { |kind, _| kind == :req }
|
|
103
|
+
|
|
104
|
+
variable(name)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def for_relation(relation)
|
|
109
|
+
"#{relation.class_name}Drop".classify.safe_constantize
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
private
|
|
113
|
+
|
|
114
|
+
def variable(name)
|
|
115
|
+
description = descriptions.fetch(name, {})
|
|
116
|
+
relation = model.reflect_on_association(name) if associations.include?(name) && model.respond_to?(:reflect_on_association)
|
|
117
|
+
drop = description[:drop]&.to_s&.safe_constantize || (for_relation(relation) if relation)
|
|
118
|
+
|
|
119
|
+
Variable.new(
|
|
120
|
+
name: name,
|
|
121
|
+
label: resolve(description[:label]) || label_for(name),
|
|
122
|
+
type: (description[:type] || (drop ? :object : attribute_type(name)))&.to_s,
|
|
123
|
+
hint: resolve(description[:hint]),
|
|
124
|
+
drop: drop,
|
|
125
|
+
collection: description.fetch(:collection) { relation&.collection? || false }
|
|
126
|
+
)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def label_for(name)
|
|
130
|
+
model.respond_to?(:human_attribute_name) ? model.human_attribute_name(name) : name.humanize
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def attribute_type(name)
|
|
134
|
+
return unless model.respond_to?(:attribute_types) && model.attribute_types.key?(name)
|
|
135
|
+
|
|
136
|
+
model.attribute_types[name].type
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def resolve(value)
|
|
140
|
+
value.respond_to?(:call) ? value.call : value
|
|
141
|
+
end
|
|
67
142
|
end
|
|
143
|
+
|
|
144
|
+
HELPERS = (public_instance_methods(false).map(&:to_s) - %w[id]) + %w[to_liquid]
|
|
68
145
|
end
|
|
69
146
|
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Liquidum
|
|
4
|
+
# A variable a template can use, as the editor's variable picker shows it.
|
|
5
|
+
# A variable with a drop has variables of its own; a collection is a list
|
|
6
|
+
# of them, to loop over.
|
|
7
|
+
Variable = Data.define(:name, :label, :type, :hint, :drop, :collection) do
|
|
8
|
+
def as_json(*)
|
|
9
|
+
{name: name, label: label, type: type, hint: hint, collection: collection, children: !drop.nil?}.compact
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Liquidum
|
|
4
|
+
# The variables available to a template, from its roots: the drops (or
|
|
5
|
+
# plain values) it's rendered with.
|
|
6
|
+
#
|
|
7
|
+
# variables = Liquidum::Variables.new(order: OrderDrop, portal_url: :string)
|
|
8
|
+
# variables.at("") # order, portal_url
|
|
9
|
+
# variables.at("order.customer") # the customer's variables
|
|
10
|
+
# variables.at("order.order_lines.product") # in a collection: an element's
|
|
11
|
+
#
|
|
12
|
+
# The editor asks for one level at a time (see Liquidum::VariablesController),
|
|
13
|
+
# so associations that lead back (order → customer → orders) are no problem.
|
|
14
|
+
# Hosts pass the roots signed, from .token, so a browser can't ask about
|
|
15
|
+
# other classes.
|
|
16
|
+
class Variables
|
|
17
|
+
attr_reader :roots
|
|
18
|
+
|
|
19
|
+
def initialize(roots)
|
|
20
|
+
@roots = roots.to_h { |name, root| [name.to_s, root] }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def at(path)
|
|
24
|
+
names = path.to_s.split(".")
|
|
25
|
+
return roots.map { |name, root| root_variable(name, root) } if names.empty?
|
|
26
|
+
|
|
27
|
+
first, *rest = names
|
|
28
|
+
variable = root_variable(first, roots[first]) if roots.key?(first)
|
|
29
|
+
rest.each { |name| variable = variable&.drop&.variables&.find { |v| v.name == name } }
|
|
30
|
+
variable&.drop&.variables
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def token
|
|
34
|
+
self.class.verifier.generate(roots.transform_values { |root| root.is_a?(Class) ? {"drop" => root.name} : {"type" => root.to_s} })
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class << self
|
|
38
|
+
def from_token(token)
|
|
39
|
+
roots = verifier.verified(token.to_s) or return
|
|
40
|
+
|
|
41
|
+
new(roots.transform_values { |root| root["drop"] ? root["drop"].safe_constantize : root["type"] })
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def verifier
|
|
45
|
+
Rails.application.message_verifier("liquidum/variables")
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def root_variable(name, root)
|
|
52
|
+
if root.is_a?(Class) && root < Liquid::Drop
|
|
53
|
+
model = root.model if root.respond_to?(:model)
|
|
54
|
+
label = model.respond_to?(:model_name) ? model.model_name.human : name.humanize
|
|
55
|
+
Variable.new(name: name, label: label, type: "object", hint: nil, drop: (root if root.respond_to?(:variables)), collection: false)
|
|
56
|
+
else
|
|
57
|
+
Variable.new(name: name, label: name.humanize, type: root&.to_s, hint: nil, drop: nil, collection: false)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
data/lib/liquidum/version.rb
CHANGED
data/lib/liquidum.rb
CHANGED
|
@@ -9,6 +9,8 @@ require "liquidum/version"
|
|
|
9
9
|
require "liquidum/engine"
|
|
10
10
|
require "liquidum/configuration"
|
|
11
11
|
require "liquidum/drop"
|
|
12
|
+
require "liquidum/variable"
|
|
13
|
+
require "liquidum/variables"
|
|
12
14
|
|
|
13
15
|
require "liquidum/liquid/liquid_helpers"
|
|
14
16
|
require "liquidum/liquid/liquid_template_extensions"
|
|
@@ -47,8 +49,13 @@ module Liquidum
|
|
|
47
49
|
options[:registers] ||= {}
|
|
48
50
|
options[:registers]["file_system"] =
|
|
49
51
|
Liquidum.config.liquidum_file_system.constantize.new(options[:registers])
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
# A Liquid::Context (from a tag) already carries its registers, and since
|
|
53
|
+
# Liquid 5.4 those are a Liquid::Registers, which render won't take again
|
|
54
|
+
result = if options[:context]
|
|
55
|
+
template.render(options[:context])
|
|
56
|
+
else
|
|
57
|
+
template.render(options[:assigns].stringify_keys, registers: options[:registers])
|
|
58
|
+
end
|
|
52
59
|
|
|
53
60
|
if template.errors.present?
|
|
54
61
|
Liquidum.config.logger.error "--- Template rendering errors: " + "-" * 49
|
|
@@ -63,7 +70,7 @@ module Liquidum
|
|
|
63
70
|
|
|
64
71
|
assigns = options[:assigns].deep_stringify_keys
|
|
65
72
|
assigns = assigns.merge(template.assigns.stringify_keys) if template.assigns
|
|
66
|
-
options[:registers].
|
|
73
|
+
template.registers&.each { |key, value| options[:registers][key.to_s] = value }
|
|
67
74
|
|
|
68
75
|
if options[:filter].present? && Tilt[options[:filter]]
|
|
69
76
|
result = Tilt[options[:filter]].new(options[:filter_options]) do
|
data/liquidum.gemspec
CHANGED
|
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
|
|
|
28
28
|
spec.add_runtime_dependency("i18n", ["~> 1.8"])
|
|
29
29
|
spec.add_runtime_dependency("kramdown", ["~> 2.1"])
|
|
30
30
|
spec.add_runtime_dependency("kramdown-parser-gfm", ["~> 1.0"])
|
|
31
|
-
spec.add_runtime_dependency("liquid", ["<
|
|
31
|
+
spec.add_runtime_dependency("liquid", ["< 6"])
|
|
32
32
|
spec.add_runtime_dependency("parslet", [">= 0"])
|
|
33
33
|
spec.add_runtime_dependency("pg", [">= 0"])
|
|
34
34
|
spec.add_runtime_dependency("rails", [">= 5.2"])
|
data/mise.toml
ADDED
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: liquidum
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tom de Grunt
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: addressable
|
|
@@ -86,14 +85,14 @@ dependencies:
|
|
|
86
85
|
requirements:
|
|
87
86
|
- - "<"
|
|
88
87
|
- !ruby/object:Gem::Version
|
|
89
|
-
version: '
|
|
88
|
+
version: '6'
|
|
90
89
|
type: :runtime
|
|
91
90
|
prerelease: false
|
|
92
91
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
92
|
requirements:
|
|
94
93
|
- - "<"
|
|
95
94
|
- !ruby/object:Gem::Version
|
|
96
|
-
version: '
|
|
95
|
+
version: '6'
|
|
97
96
|
- !ruby/object:Gem::Dependency
|
|
98
97
|
name: parslet
|
|
99
98
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -269,18 +268,26 @@ executables: []
|
|
|
269
268
|
extensions: []
|
|
270
269
|
extra_rdoc_files: []
|
|
271
270
|
files:
|
|
271
|
+
- ".devcontainer/devcontainer-lock.json"
|
|
272
|
+
- ".devcontainer/devcontainer.json"
|
|
273
|
+
- ".devcontainer/docker-compose.yml"
|
|
274
|
+
- ".devcontainer/env.conf"
|
|
275
|
+
- ".devcontainer/postStart.sh"
|
|
272
276
|
- ".github/workflows/gem-push.yml"
|
|
273
277
|
- ".gitignore"
|
|
274
278
|
- ".rubocop.yml"
|
|
279
|
+
- ".shipkit.yml"
|
|
280
|
+
- ".worktreeinclude"
|
|
281
|
+
- CHANGELOG.md
|
|
275
282
|
- Gemfile
|
|
276
283
|
- MIT-LICENSE
|
|
277
284
|
- README.md
|
|
278
285
|
- Rakefile
|
|
279
286
|
- TODO.md
|
|
280
287
|
- app/controllers/liquidum/application_controller.rb
|
|
281
|
-
- app/controllers/liquidum/completions_controller.rb
|
|
282
288
|
- app/controllers/liquidum/conversions_controller.rb
|
|
283
289
|
- app/controllers/liquidum/sandbox_controller.rb
|
|
290
|
+
- app/controllers/liquidum/variables_controller.rb
|
|
284
291
|
- app/helpers/liquidum/application_helper.rb
|
|
285
292
|
- app/jobs/liquidum/application_job.rb
|
|
286
293
|
- app/models/concerns/liquidum/to_liquid.rb
|
|
@@ -290,6 +297,7 @@ files:
|
|
|
290
297
|
- app/views/liquidum/conversions/index.html.slim
|
|
291
298
|
- app/views/liquidum/sandbox/edit.html.slim
|
|
292
299
|
- app/views/liquidum/sandbox/index.html.slim
|
|
300
|
+
- bin/de
|
|
293
301
|
- bin/rails
|
|
294
302
|
- bin/rubocop
|
|
295
303
|
- config/routes.rb
|
|
@@ -322,13 +330,15 @@ files:
|
|
|
322
330
|
- lib/liquidum/liquid/parser.rb
|
|
323
331
|
- lib/liquidum/liquid/tags/helper_tag.rb
|
|
324
332
|
- lib/liquidum/liquid/tags/render_tag.rb
|
|
333
|
+
- lib/liquidum/variable.rb
|
|
334
|
+
- lib/liquidum/variables.rb
|
|
325
335
|
- lib/liquidum/version.rb
|
|
326
336
|
- liquidum.gemspec
|
|
337
|
+
- mise.toml
|
|
327
338
|
homepage: https://github.com/entdec/liquidum
|
|
328
339
|
licenses:
|
|
329
340
|
- MIT
|
|
330
341
|
metadata: {}
|
|
331
|
-
post_install_message:
|
|
332
342
|
rdoc_options: []
|
|
333
343
|
require_paths:
|
|
334
344
|
- lib
|
|
@@ -343,8 +353,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
343
353
|
- !ruby/object:Gem::Version
|
|
344
354
|
version: '0'
|
|
345
355
|
requirements: []
|
|
346
|
-
rubygems_version: 3.
|
|
347
|
-
signing_key:
|
|
356
|
+
rubygems_version: 3.6.9
|
|
348
357
|
specification_version: 4
|
|
349
358
|
summary: Liquid templating - on steroids
|
|
350
359
|
test_files: []
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
require_dependency "liquidum/application_controller"
|
|
2
|
-
|
|
3
|
-
module Liquidum
|
|
4
|
-
class CompletionsController < ApplicationController
|
|
5
|
-
def index
|
|
6
|
-
q = params[:q]
|
|
7
|
-
klass = q.classify.safe_constantize
|
|
8
|
-
drop = q.classify.concat('Drop').safe_constantize
|
|
9
|
-
invokables = drop&.invokable_methods || []
|
|
10
|
-
# drop_relations = klass.reflect_on_all_associations.map(&:name).select {|n| invokables.include?(n.to_s) }
|
|
11
|
-
|
|
12
|
-
render json: { q: q, completions: invokables }
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
end
|