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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d329e99f05c6d46b176299ca0c2feac75ae3e5aeeb4b8bea0eb472b8cc6c6390
4
- data.tar.gz: b48bbd71720359afc2124fad497a4c73b3a51ec823e245cce996d733f941e511
3
+ metadata.gz: 7a3613df0269cd879899d9d22b5caaac10d81ed99b7cae5817111eabba181aff
4
+ data.tar.gz: c003a28fc817883048a004a20bc9d074543542dc2de4eeffd6f8a126452baf4c
5
5
  SHA512:
6
- metadata.gz: 57b9531c2f52655fd04cf0432b3e87375facd2dab8f79d8c1d9c480f4a946d54ecf85175319b2f1433050ac85a8bb3a4d596143f9ce7cdc063fc9f60cc249c5c
7
- data.tar.gz: b50bbe44304824e22b1cbc0e5bb92ffcbcfec7c2676c2b3caa5d335a3d99e9957663f3f1c58c65e3377b2ad3d40b8f0cd3e32110c2997430106131d04118d2e4
6
+ metadata.gz: 4631f8504116bb3c067832673e5b817ee6dd537c5a0438d360e16774023575a2a3309485560dd2825d48a2bb2dc2cdae50326aa4784dc62a9ae7594149f11bad
7
+ data.tar.gz: 87e44b29a116546be43cbf8b45bf65b23d6dae489e2b37dd602b50dcd4b588f845230e577a2de83f378261f99ed4ce71d7bf33f7da0ded698301d055954354f0
@@ -0,0 +1,34 @@
1
+ {
2
+ "features": {
3
+ "ghcr.io/devcontainers/features/common-utils:2.7.1": {
4
+ "version": "2.7.1",
5
+ "resolved": "ghcr.io/devcontainers/features/common-utils@sha256:e76a6a8a35d1ad824daad1540725e0ec9f8ed2dc00d2850e990a9830013c7d08",
6
+ "integrity": "sha256:e76a6a8a35d1ad824daad1540725e0ec9f8ed2dc00d2850e990a9830013c7d08"
7
+ },
8
+ "ghcr.io/devcontainers/features/docker-in-docker:2": {
9
+ "version": "2.17.0",
10
+ "resolved": "ghcr.io/devcontainers/features/docker-in-docker@sha256:25b9f05705ffba7dbe503230ac76081419306f8c8bc88e0ce78c4ecd99a0c78c",
11
+ "integrity": "sha256:25b9f05705ffba7dbe503230ac76081419306f8c8bc88e0ce78c4ecd99a0c78c"
12
+ },
13
+ "ghcr.io/devcontainers/features/github-cli:1": {
14
+ "version": "1.1.3",
15
+ "resolved": "ghcr.io/devcontainers/features/github-cli@sha256:bd7ab48a832228f633239277552c30b353867fef2e5b037e064b4e64f0b843f2",
16
+ "integrity": "sha256:bd7ab48a832228f633239277552c30b353867fef2e5b037e064b4e64f0b843f2"
17
+ },
18
+ "ghcr.io/devcontainers/features/node:2": {
19
+ "version": "2.1.1",
20
+ "resolved": "ghcr.io/devcontainers/features/node@sha256:2a19d3b0b3879437637cfd292eb29fee0afcfbe6364e33db9afc4f80c5c1f956",
21
+ "integrity": "sha256:2a19d3b0b3879437637cfd292eb29fee0afcfbe6364e33db9afc4f80c5c1f956"
22
+ },
23
+ "ghcr.io/rails/devcontainer/features/activestorage": {
24
+ "version": "1.1.1",
25
+ "resolved": "ghcr.io/rails/devcontainer/features/activestorage@sha256:7fa8fff898ac33076ebf65631d3c6c902dc9bad87de3e5dfa645f3e2d7a35c07",
26
+ "integrity": "sha256:7fa8fff898ac33076ebf65631d3c6c902dc9bad87de3e5dfa645f3e2d7a35c07"
27
+ },
28
+ "ghcr.io/rails/devcontainer/features/postgres-client": {
29
+ "version": "1.2.0",
30
+ "resolved": "ghcr.io/rails/devcontainer/features/postgres-client@sha256:7e6b118646d6e0d82a9ec06e81ad1b5406f7042f0279d35fff3a7a612be7a050",
31
+ "integrity": "sha256:7e6b118646d6e0d82a9ec06e81ad1b5406f7042f0279d35fff3a7a612be7a050"
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,46 @@
1
+ // For format details, see https://aka.ms/devcontainer.json. For config options, see the
2
+ // README at: https://github.com/devcontainers/templates/tree/main/src/ruby-rails-postgres
3
+ {
4
+ "name": "liquidum",
5
+ "dockerComposeFile": "docker-compose.yml",
6
+ "service": "app",
7
+ "features": {
8
+ "ghcr.io/devcontainers/features/node:2": {},
9
+ "ghcr.io/devcontainers/features/common-utils:2.7.1": {
10
+ "configureZshAsDefaultShell": true,
11
+ "installOhMyZsh": false,
12
+ "installOhMyZshConfig": false
13
+ },
14
+ "ghcr.io/rails/devcontainer/features/activestorage": {},
15
+ "ghcr.io/rails/devcontainer/features/postgres-client": {
16
+ "version": "18"
17
+ },
18
+ "ghcr.io/devcontainers/features/github-cli:1": {},
19
+ "ghcr.io/devcontainers/features/docker-in-docker:2": {
20
+ "moby": false
21
+ },
22
+ // Your own tools from ~/.config/de/config.json, written by bin/de
23
+ // initialize, see https://github.com/tdegrunt/de#your-own-tools
24
+ "./de-host": {}
25
+ },
26
+ "mounts": [
27
+ "source=/run/host-services/ssh-auth.sock,target=/ssh-agent,type=bind,consistency=cached",
28
+ "source=${localEnv:HOME}/.gitconfig,target=/home/vscode/.gitconfig,type=bind,consistency=cached"
29
+ ],
30
+ "initializeCommand": "bin/de initialize",
31
+ // Closing the editor leaves the environment running, bin/de down stops it
32
+ "shutdownAction": "none",
33
+ "postStartCommand": ".devcontainer/postStart.sh",
34
+ "containerEnv": {
35
+ "VISUAL": "vi",
36
+ "SSH_AUTH_SOCK": "/ssh-agent"
37
+ },
38
+ "remoteEnv": {
39
+ // The repository's bin/, so `rails test` works in terminals
40
+ "PATH": "${containerWorkspaceFolder}/bin:${containerEnv:PATH}"
41
+ },
42
+ "customizations": {},
43
+ // Where docker-compose.yml mounts this checkout, see env_init in bin/de.
44
+ // /workspaces/liquidum links here too, but only once the container runs.
45
+ "workspaceFolder": "/workspaces${localWorkspaceFolder}"
46
+ }
@@ -0,0 +1,102 @@
1
+ # One compose project per checkout. The variables come from .devcontainer/.env,
2
+ # written by bin/de up (or bin/de initialize when opened from an editor).
3
+ name: ${COMPOSE_PROJECT_NAME:?run bin/de up to write .devcontainer/.env}
4
+
5
+ x-env-labels: &env-labels
6
+ dev.env.name: ${ENV_NAME}
7
+ dev.env.kind: ${ENV_KIND}
8
+ dev.env.branch: ${ENV_BRANCH}
9
+ dev.env.path: ${ENV_PATH}
10
+ dev.env.gitdir: ${ENV_GIT_COMMON_DIR}
11
+
12
+ services:
13
+ app:
14
+ image: ghcr.io/rails/devcontainer/images/ruby:4.0.5
15
+ labels: *env-labels
16
+
17
+ volumes:
18
+ # The checkout and the common .git directory sit at the same place
19
+ # relative to each other as on the host (under /workspaces), so a
20
+ # worktree's relative .git link resolves. /workspaces/<repo> links to
21
+ # the checkout.
22
+ - ${ENV_PATH}:${ENV_PATH_IN_CONTAINER}
23
+ - ${ENV_GIT_COMMON_DIR}:${ENV_GIT_COMMON_DIR_IN_CONTAINER}
24
+ # The global gitignore. Here, not in devcontainer.json, which drops
25
+ # readonly from its mounts.
26
+ - ${ENV_GIT_CONFIG_DIR}:/home/vscode/.config/git:ro
27
+
28
+ environment:
29
+ DEV_ENV_NAME: ${ENV_NAME}
30
+ DEV_ENV_KIND: ${ENV_KIND}
31
+ DB_HOST: postgres
32
+ REDIS_URL: redis://redis:6379/1
33
+ # See SELENIUM_URL in env.conf
34
+ SELENIUM_URL: ${SELENIUM_URL}
35
+ CAPYBARA_APP_HOST: ${CAPYBARA_APP_HOST}
36
+ # Other worktrees aren't mounted here, keep git gc from pruning them
37
+ GIT_CONFIG_COUNT: 1
38
+ GIT_CONFIG_KEY_0: gc.worktreePruneExpire
39
+ GIT_CONFIG_VALUE_0: never
40
+
41
+ expose:
42
+ - "3000"
43
+
44
+ # Keeps the container running after the process ends
45
+ command: ["sh", "-c", "sudo ln -sfn \"$$0\" \"$$1\" && exec sleep infinity", "${ENV_PATH_IN_CONTAINER}", "${ENV_WORKSPACE_LINK}"]
46
+ restart: ${ENV_RESTART:-no}
47
+
48
+ depends_on:
49
+ postgres:
50
+ condition: service_healthy
51
+ redis:
52
+ condition: service_healthy
53
+ selenium:
54
+ condition: service_healthy
55
+
56
+ postgres:
57
+ image: postgres:18
58
+ labels: *env-labels
59
+ restart: ${ENV_RESTART:-no}
60
+ volumes:
61
+ - postgres-data:/var/lib/postgresql/18/docker
62
+ environment:
63
+ POSTGRES_USER: postgres
64
+ POSTGRES_PASSWORD: postgres
65
+ healthcheck:
66
+ test: ["CMD", "pg_isready", "-U", "postgres"]
67
+ interval: 2s
68
+ timeout: 5s
69
+ retries: 30
70
+
71
+ redis:
72
+ image: valkey/valkey:8
73
+ labels: *env-labels
74
+ restart: ${ENV_RESTART:-no}
75
+ volumes:
76
+ - redis-data:/data
77
+ healthcheck:
78
+ test: ["CMD", "valkey-cli", "ping"]
79
+ interval: 2s
80
+ timeout: 5s
81
+ retries: 30
82
+
83
+ selenium:
84
+ image: selenium/standalone-firefox
85
+ labels: *env-labels
86
+ restart: ${ENV_RESTART:-no}
87
+ shm_size: 2gb
88
+ healthcheck:
89
+ test: ["CMD", "/opt/bin/check-grid.sh", "--host", "localhost", "--port", "4444"]
90
+ interval: 2s
91
+ timeout: 5s
92
+ retries: 60
93
+
94
+ volumes:
95
+ postgres-data:
96
+ labels: *env-labels
97
+ redis-data:
98
+ labels: *env-labels
99
+
100
+ networks:
101
+ default:
102
+ labels: *env-labels
@@ -0,0 +1,31 @@
1
+ # Per-repository settings for bin/de, which comes from the de repository and
2
+ # is the same everywhere.
3
+
4
+ # Prefix of every environment name, and the folder the checkout appears at
5
+ # inside the container (/workspaces/<ENV_REPO>, see devcontainer.json). Unique
6
+ # per repository: de init --name sets it, default the repository's folder name.
7
+ ENV_REPO=liquidum
8
+
9
+ # Branches whose environments are persistent: they keep their volumes and are
10
+ # never removed by bin/de prune. Every other branch gets an ephemeral one.
11
+ PERSISTENT_BRANCHES=(staging develop)
12
+
13
+ # Branches whose environment is named just ENV_REPO, e.g. reachable as
14
+ # app.liquidum.orb.local. Always persistent.
15
+ PRIMARY_BRANCHES=(main master)
16
+
17
+ # Selenium the system tests drive: the environment's own container. To watch
18
+ # a test in a browser on the Mac instead, override it for one command:
19
+ #
20
+ # SELENIUM_URL=http://host.docker.internal:4444/ HEADLESS=0 bin/de exec bin/rails test:system
21
+ SELENIUM_URL="http://selenium:4444/"
22
+
23
+ # Run in the container at the end of bin/de up, from the checkout root, e.g.
24
+ # to prepare the test database (postStart.sh prepares the development one).
25
+ # A Rails engine runs it from the engine root, so its own migrations are
26
+ # included.
27
+ UP_COMMAND=(env RAILS_ENV=test bin/rails app:db:prepare)
28
+
29
+ # Version of @devcontainers/cli to run through npx when `devcontainer` isn't
30
+ # installed.
31
+ DEVCONTAINER_CLI_VERSION=0.90.0
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env bash
2
+ set -e
3
+
4
+ MISE="$HOME/.local/bin/mise"
5
+ # Trust first, activating reads mise.local.toml too
6
+ "$MISE" trust
7
+ eval "$("$MISE" activate bash)"
8
+ "$MISE" install
9
+ sudo chmod 666 /ssh-agent
10
+ # So git over SSH, e.g. a git source in the Gemfile, doesn't stop to ask
11
+ mkdir -p ~/.ssh
12
+ ssh-keygen -F github.com >/dev/null 2>&1 || ssh-keyscan -t ed25519 github.com 2>/dev/null >> ~/.ssh/known_hosts
13
+
14
+ [ ! -f package.json ] || "$MISE" exec -- npm install
15
+ "$MISE" exec -- bundle install
16
+ "$MISE" exec -- bin/rails db:prepare
data/.gitignore CHANGED
@@ -9,3 +9,5 @@ test/dummy/yarn-error.log
9
9
  test/dummy/storage/
10
10
  test/dummy/tmp/
11
11
  Gemfile.lock
12
+ .devcontainer/.env
13
+ .devcontainer/de-host/
data/.shipkit.yml ADDED
@@ -0,0 +1,2 @@
1
+ ---
2
+ previous_version: 1.2.1
data/.worktreeinclude ADDED
@@ -0,0 +1,2 @@
1
+ .envrc
2
+ mise.local.toml
data/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ - Allow Liquid 5.4 and later (up to 6).
6
+ - Drops describe their variables for editors: `Drop.variables`, the
7
+ `describe` DSL, and `GET /liquidum/variables` with signed roots
8
+ (`Liquidum::Variables`). See "Variables for editors" in the README.
9
+ - `config.parent_controller` chooses the controller Liquidum's controllers
10
+ inherit from.
11
+ - Removed `GET /liquidum/completions`; `/liquidum/variables` replaces it.
data/Gemfile CHANGED
@@ -1,7 +1,11 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
  git_source(:github) { |repo| "https://github.com/#{repo}.git" }
3
3
 
4
4
  # Declare your gem's dependencies in liquidum.gemspec.
5
5
  # Bundler will treat runtime dependencies like base dependencies, and
6
6
  # development dependencies will be added by default to the :development group.
7
7
  gemspec
8
+
9
+ source "https://rubygems.pkg.github.com/entdec" do
10
+ gem "shipkit"
11
+ end
data/README.md CHANGED
@@ -10,6 +10,63 @@ Basically it's as easy as:
10
10
  Liquidum.render("{{payload.test}}", assigns: { 'payload' => { 'test' => 'blah' } })
11
11
  ```
12
12
 
13
+ ## Variables for editors
14
+
15
+ Editors can offer the variables a template can use, as a picker or as
16
+ suggestions after `{{`. Liquidum works them out from your drops: what Liquid
17
+ can call on a drop, labelled with `human_attribute_name` in the current
18
+ locale, typed from the model's columns, and followed through `association`
19
+ to other drops.
20
+
21
+ ```ruby
22
+ class OrderDrop < Liquidum::Drop
23
+ association :customer, :order_lines
24
+ delegate :number, :total, to: :@object
25
+
26
+ # Only for what Liquidum can't work out
27
+ describe :total, type: :money, hint: "Including VAT"
28
+ describe :portal_url, label: -> { I18n.t("orders.portal_url") }
29
+
30
+ def portal_url = …
31
+ end
32
+
33
+ OrderDrop.variables # => [#<data Liquidum::Variable name="customer", label="Customer", type="object", …>, …]
34
+ ```
35
+
36
+ `describe` takes `label:`, `type:`, `hint:` (a string, or a proc to translate
37
+ it), and `drop:` and `collection:` for a method that returns other drops. A
38
+ drop is for the model with its name (`OrderDrop` is for `Order`); override
39
+ `self.model` when that's not so.
40
+
41
+ Mount the engine and give the editor a URL with the template's roots, signed,
42
+ so a browser can't ask about other classes:
43
+
44
+ ```ruby
45
+ mount Liquidum::Engine => "/liquidum"
46
+ ```
47
+
48
+ ```ruby
49
+ variables = Liquidum::Variables.new(order: OrderDrop, portal_url: :string)
50
+ liquidum.variables_path(roots: variables.token)
51
+ ```
52
+
53
+ The editor asks for one level at a time:
54
+
55
+ ```
56
+ GET /liquidum/variables?roots=…&path=order.customer
57
+ {"path": "order.customer", "variables": [{"name": "email", "label": "Email", "type": "string", "collection": false, "children": false}, …]}
58
+ ```
59
+
60
+ In a collection the path goes into its elements (`order.order_lines.product`).
61
+ The endpoint only describes variables and never reads a record. Its
62
+ controllers inherit from `::ApplicationController`; to choose another one:
63
+
64
+ ```ruby
65
+ Liquidum.configure do |config|
66
+ config.parent_controller = "Admin::BaseController"
67
+ end
68
+ ```
69
+
13
70
  ## Installation
14
71
 
15
72
  Add this line to your application's Gemfile:
@@ -1,5 +1,5 @@
1
1
  module Liquidum
2
- class ApplicationController < ::ApplicationController
2
+ class ApplicationController < Liquidum.config.parent_controller.constantize
3
3
  protect_from_forgery with: :exception
4
4
  end
5
5
  end
@@ -0,0 +1,17 @@
1
+ require_dependency "liquidum/application_controller"
2
+
3
+ module Liquidum
4
+ # The variables at a path, for an editor's variable picker:
5
+ #
6
+ # GET /liquidum/variables?roots=<Liquidum::Variables#token>&path=order.customer
7
+ #
8
+ # Only describes the variables; it never reads a record.
9
+ class VariablesController < ApplicationController
10
+ def index
11
+ variables = Variables.from_token(params[:roots]) or return head(:bad_request)
12
+ found = variables.at(params[:path]) or return head(:not_found)
13
+
14
+ render json: {path: params[:path].to_s, variables: found}
15
+ end
16
+ end
17
+ end