liquidum 1.2.0 → 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/sandbox_controller.rb +11 -10
- data/app/controllers/liquidum/variables_controller.rb +17 -0
- data/app/tables/liquidum/application_table.rb +4 -0
- data/app/views/liquidum/conversions/index.html.slim +2 -2
- data/app/views/liquidum/sandbox/edit.html.slim +3 -3
- data/app/views/liquidum/sandbox/index.html.slim +1 -1
- 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 +19 -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,26 +268,36 @@ 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
|
|
287
294
|
- app/models/liquidum/sandbox.rb
|
|
295
|
+
- app/tables/liquidum/application_table.rb
|
|
288
296
|
- app/tables/liquidum/sandboxes_table.rb
|
|
289
297
|
- app/views/liquidum/conversions/index.html.slim
|
|
290
298
|
- app/views/liquidum/sandbox/edit.html.slim
|
|
291
299
|
- app/views/liquidum/sandbox/index.html.slim
|
|
300
|
+
- bin/de
|
|
292
301
|
- bin/rails
|
|
293
302
|
- bin/rubocop
|
|
294
303
|
- config/routes.rb
|
|
@@ -321,13 +330,15 @@ files:
|
|
|
321
330
|
- lib/liquidum/liquid/parser.rb
|
|
322
331
|
- lib/liquidum/liquid/tags/helper_tag.rb
|
|
323
332
|
- lib/liquidum/liquid/tags/render_tag.rb
|
|
333
|
+
- lib/liquidum/variable.rb
|
|
334
|
+
- lib/liquidum/variables.rb
|
|
324
335
|
- lib/liquidum/version.rb
|
|
325
336
|
- liquidum.gemspec
|
|
337
|
+
- mise.toml
|
|
326
338
|
homepage: https://github.com/entdec/liquidum
|
|
327
339
|
licenses:
|
|
328
340
|
- MIT
|
|
329
341
|
metadata: {}
|
|
330
|
-
post_install_message:
|
|
331
342
|
rdoc_options: []
|
|
332
343
|
require_paths:
|
|
333
344
|
- lib
|
|
@@ -342,8 +353,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
342
353
|
- !ruby/object:Gem::Version
|
|
343
354
|
version: '0'
|
|
344
355
|
requirements: []
|
|
345
|
-
rubygems_version: 3.
|
|
346
|
-
signing_key:
|
|
356
|
+
rubygems_version: 3.6.9
|
|
347
357
|
specification_version: 4
|
|
348
358
|
summary: Liquid templating - on steroids
|
|
349
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
|