From 6e2123c3f53f5e5e18e90b935fd36fe23afcd3a5 Mon Sep 17 00:00:00 2001 From: River Date: Tue, 14 Jul 2026 16:35:28 +0000 Subject: [PATCH 1/5] Add liquid-il benchmark: rendering LiquidIL-generated Ruby LiquidIL (https://github.com/tobi/liquid-il) compiles Liquid templates to standalone Ruby that runs without an interpreter loop. This benchmark renders that generated Ruby for a set of Liquid templates (a one-line output up to full storefront product/cart/collection pages), exercising the machine-generated code a JIT actually compiles: heavy runtime-helper dispatch, partial lambdas, string-buffer building, hash lookups, and loops. The exact generated Ruby is committed under generated/ (produced from templates.yml by extract.rb and validated against each template's expected output), so what the JIT compiles lives in the repo and does not drift with the LiquidIL compiler. benchmark.rb requires the pinned liquid-il gem for its runtime helpers and renders the committed modules. Co-authored-by: Max Bernstein --- benchmarks.yml | 3 + benchmarks/liquid-il/Gemfile | 13 + benchmarks/liquid-il/Gemfile.lock | 29 + benchmarks/liquid-il/benchmark.rb | 31 + benchmarks/liquid-il/extract.rb | 78 + .../bench_ecommerce_product_page.json | 59 + .../fixtures/bench_notification_center.json | 112 ++ .../fixtures/bench_render_for_loop.json | 24 + .../fixtures/bench_render_with_params.json | 29 + .../bench_simple_product_listing.json | 16 + .../fixtures/bench_theme_cart_page.json | 140 ++ .../fixtures/bench_theme_collection_page.json | 329 ++++ .../fixtures/bench_theme_product_page.json | 207 ++ .../generated/bench_ecommerce_product_page.rb | 136 ++ .../generated/bench_notification_center.rb | 163 ++ .../generated/bench_render_for_loop.rb | 55 + .../generated/bench_render_with_params.rb | 63 + .../generated/bench_simple_product_listing.rb | 77 + .../generated/bench_theme_cart_page.rb | 204 ++ .../generated/bench_theme_collection_page.rb | 223 +++ .../generated/bench_theme_product_page.rb | 272 +++ benchmarks/liquid-il/manifest.json | 42 + benchmarks/liquid-il/templates.yml | 1723 +++++++++++++++++ 23 files changed, 4028 insertions(+) create mode 100644 benchmarks/liquid-il/Gemfile create mode 100644 benchmarks/liquid-il/Gemfile.lock create mode 100644 benchmarks/liquid-il/benchmark.rb create mode 100644 benchmarks/liquid-il/extract.rb create mode 100644 benchmarks/liquid-il/fixtures/bench_ecommerce_product_page.json create mode 100644 benchmarks/liquid-il/fixtures/bench_notification_center.json create mode 100644 benchmarks/liquid-il/fixtures/bench_render_for_loop.json create mode 100644 benchmarks/liquid-il/fixtures/bench_render_with_params.json create mode 100644 benchmarks/liquid-il/fixtures/bench_simple_product_listing.json create mode 100644 benchmarks/liquid-il/fixtures/bench_theme_cart_page.json create mode 100644 benchmarks/liquid-il/fixtures/bench_theme_collection_page.json create mode 100644 benchmarks/liquid-il/fixtures/bench_theme_product_page.json create mode 100644 benchmarks/liquid-il/generated/bench_ecommerce_product_page.rb create mode 100644 benchmarks/liquid-il/generated/bench_notification_center.rb create mode 100644 benchmarks/liquid-il/generated/bench_render_for_loop.rb create mode 100644 benchmarks/liquid-il/generated/bench_render_with_params.rb create mode 100644 benchmarks/liquid-il/generated/bench_simple_product_listing.rb create mode 100644 benchmarks/liquid-il/generated/bench_theme_cart_page.rb create mode 100644 benchmarks/liquid-il/generated/bench_theme_collection_page.rb create mode 100644 benchmarks/liquid-il/generated/bench_theme_product_page.rb create mode 100644 benchmarks/liquid-il/manifest.json create mode 100644 benchmarks/liquid-il/templates.yml diff --git a/benchmarks.yml b/benchmarks.yml index 78ba26bf..18d7133b 100644 --- a/benchmarks.yml +++ b/benchmarks.yml @@ -19,6 +19,9 @@ liquid-c: liquid-compile: desc: compiles a chosen-for-profiling Liquid theme repeatedly. category: headline +liquid-il: + desc: renders LiquidIL-generated Ruby for a set of Liquid templates repeatedly (Liquid compiled to standalone Ruby). + category: headline liquid-render: desc: renders a chosen-for-profiling Liquid theme repeatedly. category: headline diff --git a/benchmarks/liquid-il/Gemfile b/benchmarks/liquid-il/Gemfile new file mode 100644 index 00000000..ae519d38 --- /dev/null +++ b/benchmarks/liquid-il/Gemfile @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +source "https://rubygems.org" +git_source(:github) do |repo_name| + "https://github.com/#{repo_name}.git" +end + +# LiquidIL compiles Liquid to Ruby; this benchmark renders its generated Ruby. +# See extract.rb for how generated/ is produced from templates.yml. +gem "liquid-il", github: "tobi/liquid-il", ref: "1b07d162068f1ed2becec1bafd29f36f52dbbd5b" + +gem "base64" +gem "bigdecimal" diff --git a/benchmarks/liquid-il/Gemfile.lock b/benchmarks/liquid-il/Gemfile.lock new file mode 100644 index 00000000..8efe0c60 --- /dev/null +++ b/benchmarks/liquid-il/Gemfile.lock @@ -0,0 +1,29 @@ +GIT + remote: https://github.com/tobi/liquid-il.git + revision: 1b07d162068f1ed2becec1bafd29f36f52dbbd5b + ref: 1b07d162068f1ed2becec1bafd29f36f52dbbd5b + specs: + liquid-il (0.1.0) + +GEM + remote: https://rubygems.org/ + specs: + base64 (0.3.0) + bigdecimal (4.1.2) + +PLATFORMS + ruby + x86_64-linux + +DEPENDENCIES + base64 + bigdecimal + liquid-il! + +CHECKSUMS + base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b + bigdecimal (4.1.2) sha256=53d217666027eab4280346fba98e7d5b66baaae1b9c3c1c0ffe89d48188a3fbd + liquid-il (0.1.0) + +BUNDLED WITH + 4.0.10 diff --git a/benchmarks/liquid-il/benchmark.rb b/benchmarks/liquid-il/benchmark.rb new file mode 100644 index 00000000..ae15226b --- /dev/null +++ b/benchmarks/liquid-il/benchmark.rb @@ -0,0 +1,31 @@ +require_relative '../../harness/loader' + +Dir.chdir __dir__ +use_gemfile + +require 'liquid_il' +require 'json' + +# LiquidIL compiles Liquid templates to standalone Ruby (see extract.rb). We +# render that committed generated Ruby here, so this benchmark exercises the +# machine-generated code a JIT actually compiles: heavy runtime-helper dispatch, +# partial lambdas, string-buffer building, hash lookups, and loops. The exact +# Ruby lives in generated/ and does not drift with the LiquidIL compiler. +manifest = JSON.parse(File.read(File.join(__dir__, 'manifest.json'))) +CASES = manifest.map do |m| + require File.join(__dir__, 'generated', "#{m['spec']}.rb") + mod = Object.const_get(m['module']) + assigns = JSON.parse(File.read(File.join(__dir__, 'fixtures', "#{m['spec']}.json"))) + [mod, assigns] +end + +# Sanity: every generated module must produce output, or the timing is empty. +CASES.each { |mod, assigns| raise "empty render for #{mod}" if mod.render(assigns).to_s.empty? } + +run_benchmark(150) do + # Each render is quick; render the whole template set several times per + # iteration to reduce time-measurement noise (mirrors liquid-render). + 10.times do + CASES.each { |mod, assigns| mod.render(assigns) } + end +end diff --git a/benchmarks/liquid-il/extract.rb b/benchmarks/liquid-il/extract.rb new file mode 100644 index 00000000..03f0e7f2 --- /dev/null +++ b/benchmarks/liquid-il/extract.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +# Regenerate the committed LiquidIL-generated Ruby sample from templates.yml. +# +# LiquidIL (https://github.com/tobi/liquid-il) compiles a Liquid template to +# standalone Ruby (Template#to_ruby), inlining static partials so the result +# renders with no file_system. This script compiles each template in +# templates.yml to a module under generated/, writes its render assigns to +# fixtures/, and validates the standalone module reproduces the template's +# expected output. benchmark.rb then renders those committed modules in a hot +# loop, so the exact Ruby the JIT compiles lives in the repo and does not drift +# with the compiler. +# +# BUNDLE_GEMFILE=$PWD/Gemfile bundle exec ruby extract.rb +# +# The generated/ and fixtures/ output is committed; you only need to re-run +# this when templates.yml or the pinned LiquidIL version changes. + +require "json" +require "yaml" +require "liquid_il" + +HERE = __dir__ +GEN_DIR = File.join(HERE, "generated") +FIX_DIR = File.join(HERE, "fixtures") + +# Compile-time file system for the templates' inline partials. Static partials +# are inlined into the caller, so the generated Ruby holds no reference to it. +class SpecFileSystem + def initialize(files) = @files = files || {} + def read_template_file(name, _context = nil) + @files.fetch(name.to_s) { raise LiquidIL::FileSystemError, "no such partial: #{name}" } + end +end + +def module_name_for(name) + "LiquidILBench" + name.split(/[^a-zA-Z0-9]/).reject(&:empty?).map(&:capitalize).join +end + +def deep_dup(obj) + case obj + when Hash then obj.each_with_object({}) { |(k, v), h| h[k] = deep_dup(v) } + when Array then obj.map { |v| deep_dup(v) } + else obj + end +end + +Dir.mkdir(GEN_DIR) unless Dir.exist?(GEN_DIR) +Dir.mkdir(FIX_DIR) unless Dir.exist?(FIX_DIR) + +specs = YAML.safe_load(File.read(File.join(HERE, "templates.yml")), aliases: true).fetch("specs") +manifest = [] + +specs.each do |spec| + name = spec.fetch("name") + mod = module_name_for(name) + + ctx = LiquidIL::Context.new(file_system: SpecFileSystem.new(spec["filesystem"])) + template = ctx.parse(spec.fetch("template")) + ruby = template.to_ruby(mod) + + # Validate the standalone module in an isolated namespace, no file_system. + probe = Module.new + probe.module_eval(ruby, "generated/#{name}.rb") + produced = probe.const_get(mod).render(deep_dup(spec["environment"] || {})) + expected = spec["expected"] + if expected && produced != expected + raise "#{name}: generated Ruby output does not match expected" + end + + File.write(File.join(GEN_DIR, "#{name}.rb"), ruby) + File.write(File.join(FIX_DIR, "#{name}.json"), JSON.pretty_generate(spec["environment"] || {}) + "\n") + manifest << { "spec" => name, "module" => mod, "ruby_bytes" => ruby.bytesize } + printf(" ok %-32s %6d B\n", name, ruby.bytesize) +end + +File.write(File.join(HERE, "manifest.json"), JSON.pretty_generate(manifest) + "\n") +puts "Extracted #{manifest.size} module(s); #{manifest.sum { |m| m["ruby_bytes"] }} B generated Ruby." diff --git a/benchmarks/liquid-il/fixtures/bench_ecommerce_product_page.json b/benchmarks/liquid-il/fixtures/bench_ecommerce_product_page.json new file mode 100644 index 00000000..c5e6a99b --- /dev/null +++ b/benchmarks/liquid-il/fixtures/bench_ecommerce_product_page.json @@ -0,0 +1,59 @@ +{ + "product": { + "name": "Premium Widget", + "price": 99.99, + "description": "The finest widget money can buy", + "sku": "WDG-001", + "in_stock": true, + "features": [ + "Durable", + "Lightweight", + "Eco-friendly" + ] + }, + "breadcrumbs": [ + { + "label": "Home", + "url": "/" + }, + { + "label": "Widgets", + "url": "/widgets" + }, + { + "label": "Premium Widget", + "url": null + } + ], + "reviews": [ + { + "author": "Alice", + "rating": 5, + "text": "Amazing!" + }, + { + "author": "Bob", + "rating": 4, + "text": "Very good" + }, + { + "author": "Carol", + "rating": 5, + "text": "Love it" + } + ], + "related": [ + { + "name": "Basic Widget", + "price": 29.99 + }, + { + "name": "Super Widget", + "price": 149.99 + }, + { + "name": "Widget Pro", + "price": 199.99 + } + ] +} diff --git a/benchmarks/liquid-il/fixtures/bench_notification_center.json b/benchmarks/liquid-il/fixtures/bench_notification_center.json new file mode 100644 index 00000000..004cac25 --- /dev/null +++ b/benchmarks/liquid-il/fixtures/bench_notification_center.json @@ -0,0 +1,112 @@ +{ + "notifications": [ + { + "type": "order", + "order_id": "ORD-001", + "status": "confirmed", + "total": 149.99, + "items": 3, + "date": "2024-01-15" + }, + { + "type": "shipping", + "order_id": "ORD-002", + "carrier": "FedEx", + "tracking": "1234567890", + "eta": "Jan 18" + }, + { + "type": "review", + "product": "Leather Jacket", + "customer": "Alice", + "rating": 5, + "snippet": "Amazing quality!" + }, + { + "type": "promo", + "code": "SAVE20", + "discount": "20%", + "expires": "Jan 31", + "min_purchase": 50 + }, + { + "type": "stock", + "product": "Blue Widget", + "sku": "BW-001", + "status": "back_in_stock", + "quantity": 25 + }, + { + "type": "order", + "order_id": "ORD-003", + "status": "processing", + "total": 89.5, + "items": 2, + "date": "2024-01-16" + }, + { + "type": "shipping", + "order_id": "ORD-001", + "carrier": "UPS", + "tracking": "9876543210", + "eta": "Jan 17" + }, + { + "type": "review", + "product": "Cotton T-Shirt", + "customer": "Bob", + "rating": 4, + "snippet": "Great fit" + }, + { + "type": "promo", + "code": "FREESHIP", + "discount": "Free Shipping", + "expires": "Feb 1", + "min_purchase": 75 + }, + { + "type": "stock", + "product": "Red Scarf", + "sku": "RS-002", + "status": "low_stock", + "quantity": 3 + }, + { + "type": "order", + "order_id": "ORD-004", + "status": "shipped", + "total": 299.0, + "items": 1, + "date": "2024-01-14" + }, + { + "type": "shipping", + "order_id": "ORD-004", + "carrier": "USPS", + "tracking": "5555555555", + "eta": "Jan 19" + }, + { + "type": "review", + "product": "Wool Sweater", + "customer": "Carol", + "rating": 5, + "snippet": "Perfect for winter" + }, + { + "type": "promo", + "code": "VIP25", + "discount": "25%", + "expires": "Jan 20", + "min_purchase": 100 + }, + { + "type": "stock", + "product": "Green Hat", + "sku": "GH-003", + "status": "back_in_stock", + "quantity": 50 + } + ] +} diff --git a/benchmarks/liquid-il/fixtures/bench_render_for_loop.json b/benchmarks/liquid-il/fixtures/bench_render_for_loop.json new file mode 100644 index 00000000..948ebd8f --- /dev/null +++ b/benchmarks/liquid-il/fixtures/bench_render_for_loop.json @@ -0,0 +1,24 @@ +{ + "items": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20 + ] +} diff --git a/benchmarks/liquid-il/fixtures/bench_render_with_params.json b/benchmarks/liquid-il/fixtures/bench_render_with_params.json new file mode 100644 index 00000000..4a75909f --- /dev/null +++ b/benchmarks/liquid-il/fixtures/bench_render_with_params.json @@ -0,0 +1,29 @@ +{ + "products": [ + { + "name": "Widget", + "price": 9.99, + "description": "A useful widget" + }, + { + "name": "Gadget", + "price": 19.99, + "description": "An amazing gadget" + }, + { + "name": "Gizmo", + "price": 29.99, + "description": "A fantastic gizmo" + }, + { + "name": "Doohickey", + "price": 39.99, + "description": "A wonderful doohickey" + }, + { + "name": "Thingamajig", + "price": 49.99, + "description": "A marvelous thingamajig" + } + ] +} diff --git a/benchmarks/liquid-il/fixtures/bench_simple_product_listing.json b/benchmarks/liquid-il/fixtures/bench_simple_product_listing.json new file mode 100644 index 00000000..ad4443d4 --- /dev/null +++ b/benchmarks/liquid-il/fixtures/bench_simple_product_listing.json @@ -0,0 +1,16 @@ +{ + "products": [ + { + "name": "Widget", + "price": 9.99 + }, + { + "name": "Gadget", + "price": 19.99 + }, + { + "name": "Gizmo", + "price": 29.99 + } + ] +} diff --git a/benchmarks/liquid-il/fixtures/bench_theme_cart_page.json b/benchmarks/liquid-il/fixtures/bench_theme_cart_page.json new file mode 100644 index 00000000..a985c80b --- /dev/null +++ b/benchmarks/liquid-il/fixtures/bench_theme_cart_page.json @@ -0,0 +1,140 @@ +{ + "shop": { + "name": "Acme Store", + "currency": "USD", + "email": "support@acme.test" + }, + "cart": { + "item_count": 5, + "total_price": 549.95, + "items": [ + { + "id": 1, + "title": "Classic Leather Jacket", + "variant_title": "M / Black", + "price": 299.99, + "quantity": 1, + "line_price": 299.99, + "image": "/images/jacket.jpg", + "url": "/products/jacket", + "sku": "LJ-BLK-M", + "properties": { + "gift_wrap": "Yes", + "gift_message": "Happy Birthday!" + } + }, + { + "id": 2, + "title": "Cotton T-Shirt", + "variant_title": "L / White", + "price": 29.99, + "quantity": 3, + "line_price": 89.97, + "image": "/images/tshirt.jpg", + "url": "/products/tshirt", + "sku": "TS-WHT-L", + "properties": {} + }, + { + "id": 3, + "title": "Wool Beanie", + "variant_title": "One Size / Navy", + "price": 24.99, + "quantity": 2, + "line_price": 49.98, + "image": "/images/beanie.jpg", + "url": "/products/beanie", + "sku": "BN-NVY-OS", + "properties": {} + }, + { + "id": 4, + "title": "Leather Belt", + "variant_title": "34 / Brown", + "price": 59.99, + "quantity": 1, + "line_price": 59.99, + "image": "/images/belt.jpg", + "url": "/products/belt", + "sku": "BT-BRN-34", + "properties": {} + }, + { + "id": 5, + "title": "Silk Scarf", + "variant_title": "One Size / Burgundy", + "price": 49.99, + "quantity": 1, + "line_price": 49.99, + "image": "/images/scarf.jpg", + "url": "/products/scarf", + "sku": "SC-BUR-OS", + "properties": { + "monogram": "ABC" + } + } + ], + "discounts": [ + { + "code": "SAVE10", + "amount": 54.99, + "title": "10% Off" + } + ] + }, + "shipping_rates": [ + { + "name": "Standard Shipping", + "price": 5.99, + "delivery": "5-7 business days" + }, + { + "name": "Express Shipping", + "price": 15.99, + "delivery": "2-3 business days" + }, + { + "name": "Overnight", + "price": 29.99, + "delivery": "Next business day" + } + ], + "recommendations": [ + { + "title": "Leather Gloves", + "price": 49.99, + "image": "/images/gloves.jpg", + "url": "/products/gloves" + }, + { + "title": "Wool Socks", + "price": 19.99, + "image": "/images/socks.jpg", + "url": "/products/socks" + }, + { + "title": "Sunglasses", + "price": 79.99, + "image": "/images/sunglasses.jpg", + "url": "/products/sunglasses" + } + ], + "footer_links": [ + { + "title": "About", + "url": "/about" + }, + { + "title": "Contact", + "url": "/contact" + }, + { + "title": "Shipping", + "url": "/shipping" + }, + { + "title": "Returns", + "url": "/returns" + } + ] +} diff --git a/benchmarks/liquid-il/fixtures/bench_theme_collection_page.json b/benchmarks/liquid-il/fixtures/bench_theme_collection_page.json new file mode 100644 index 00000000..61cf88fe --- /dev/null +++ b/benchmarks/liquid-il/fixtures/bench_theme_collection_page.json @@ -0,0 +1,329 @@ +{ + "shop": { + "name": "Acme Store", + "currency": "USD", + "email": "support@acme.test" + }, + "collection": { + "title": "Men's Outerwear", + "description": "Premium jackets and coats for every season", + "image": "/images/outerwear-hero.jpg", + "products_count": 48, + "products": [ + { + "id": 1, + "title": "Classic Leather Jacket", + "price": 299.99, + "compare_at_price": 399.99, + "image": "/images/leather.jpg", + "url": "/products/leather-jacket", + "vendor": "Acme Apparel", + "available": true, + "tags": [ + "leather", + "classic" + ] + }, + { + "id": 2, + "title": "Bomber Jacket", + "price": 249.99, + "compare_at_price": null, + "image": "/images/bomber.jpg", + "url": "/products/bomber", + "vendor": "Acme Apparel", + "available": true, + "tags": [ + "bomber", + "casual" + ] + }, + { + "id": 3, + "title": "Denim Jacket", + "price": 149.99, + "compare_at_price": 179.99, + "image": "/images/denim.jpg", + "url": "/products/denim-jacket", + "vendor": "Acme Apparel", + "available": true, + "tags": [ + "denim", + "casual" + ] + }, + { + "id": 4, + "title": "Wool Peacoat", + "price": 349.99, + "compare_at_price": null, + "image": "/images/peacoat.jpg", + "url": "/products/peacoat", + "vendor": "Acme Apparel", + "available": false, + "tags": [ + "wool", + "formal" + ] + }, + { + "id": 5, + "title": "Quilted Vest", + "price": 129.99, + "compare_at_price": null, + "image": "/images/vest.jpg", + "url": "/products/vest", + "vendor": "Acme Apparel", + "available": true, + "tags": [ + "vest", + "layering" + ] + }, + { + "id": 6, + "title": "Windbreaker", + "price": 99.99, + "compare_at_price": 129.99, + "image": "/images/windbreaker.jpg", + "url": "/products/windbreaker", + "vendor": "Acme Apparel", + "available": true, + "tags": [ + "light", + "athletic" + ] + }, + { + "id": 7, + "title": "Parka", + "price": 399.99, + "compare_at_price": null, + "image": "/images/parka.jpg", + "url": "/products/parka", + "vendor": "Acme Apparel", + "available": true, + "tags": [ + "winter", + "heavy" + ] + }, + { + "id": 8, + "title": "Suede Jacket", + "price": 279.99, + "compare_at_price": 329.99, + "image": "/images/suede.jpg", + "url": "/products/suede-jacket", + "vendor": "Premium Line", + "available": true, + "tags": [ + "suede", + "premium" + ] + }, + { + "id": 9, + "title": "Rain Jacket", + "price": 149.99, + "compare_at_price": null, + "image": "/images/rain.jpg", + "url": "/products/rain-jacket", + "vendor": "Acme Apparel", + "available": true, + "tags": [ + "waterproof", + "light" + ] + }, + { + "id": 10, + "title": "Down Jacket", + "price": 279.99, + "compare_at_price": null, + "image": "/images/down.jpg", + "url": "/products/down-jacket", + "vendor": "Acme Apparel", + "available": true, + "tags": [ + "winter", + "warm" + ] + }, + { + "id": 11, + "title": "Fleece Jacket", + "price": 89.99, + "compare_at_price": null, + "image": "/images/fleece.jpg", + "url": "/products/fleece", + "vendor": "Acme Apparel", + "available": true, + "tags": [ + "fleece", + "casual" + ] + }, + { + "id": 12, + "title": "Blazer", + "price": 199.99, + "compare_at_price": 249.99, + "image": "/images/blazer.jpg", + "url": "/products/blazer", + "vendor": "Premium Line", + "available": true, + "tags": [ + "formal", + "business" + ] + } + ] + }, + "filters": [ + { + "name": "Price", + "values": [ + { + "label": "Under $100", + "value": "0-100", + "count": 2 + }, + { + "label": "$100-$200", + "value": "100-200", + "count": 4 + }, + { + "label": "$200-$300", + "value": "200-300", + "count": 4 + }, + { + "label": "Over $300", + "value": "300-", + "count": 2 + } + ] + }, + { + "name": "Size", + "values": [ + { + "label": "S", + "value": "s", + "count": 10 + }, + { + "label": "M", + "value": "m", + "count": 12 + }, + { + "label": "L", + "value": "l", + "count": 11 + }, + { + "label": "XL", + "value": "xl", + "count": 9 + } + ] + }, + { + "name": "Color", + "values": [ + { + "label": "Black", + "value": "black", + "count": 6 + }, + { + "label": "Brown", + "value": "brown", + "count": 4 + }, + { + "label": "Navy", + "value": "navy", + "count": 3 + }, + { + "label": "Gray", + "value": "gray", + "count": 2 + } + ] + }, + { + "name": "Availability", + "values": [ + { + "label": "In Stock", + "value": "true", + "count": 11 + }, + { + "label": "Out of Stock", + "value": "false", + "count": 1 + } + ] + } + ], + "active_filters": [ + "100-200" + ], + "sort_options": [ + { + "label": "Featured", + "value": "featured" + }, + { + "label": "Price: Low to High", + "value": "price-asc" + }, + { + "label": "Price: High to Low", + "value": "price-desc" + }, + { + "label": "Newest", + "value": "created-desc" + }, + { + "label": "Best Selling", + "value": "best-selling" + } + ], + "current_sort": "featured", + "pagination": { + "current": 1, + "total": 4, + "pages": [ + 1, + 2, + 3, + 4 + ] + }, + "footer_links": [ + { + "title": "About", + "url": "/about" + }, + { + "title": "Contact", + "url": "/contact" + }, + { + "title": "Shipping", + "url": "/shipping" + }, + { + "title": "Returns", + "url": "/returns" + } + ] +} diff --git a/benchmarks/liquid-il/fixtures/bench_theme_product_page.json b/benchmarks/liquid-il/fixtures/bench_theme_product_page.json new file mode 100644 index 00000000..37ce5df5 --- /dev/null +++ b/benchmarks/liquid-il/fixtures/bench_theme_product_page.json @@ -0,0 +1,207 @@ +{ + "shop": { + "name": "Acme Store", + "currency": "USD", + "email": "support@acme.test" + }, + "product": { + "id": 12345, + "title": "Classic Leather Jacket", + "vendor": "Acme Apparel", + "type": "Outerwear", + "price": 299.99, + "compare_at_price": 399.99, + "description": "Premium quality genuine leather jacket with satin lining. Features two front pockets and an interior pocket.", + "sku": "LJ-BLK-M", + "available": true, + "tags": [ + "leather", + "jacket", + "outerwear", + "premium" + ], + "images": [ + { + "src": "/images/jacket-front.jpg", + "alt": "Front view" + }, + { + "src": "/images/jacket-back.jpg", + "alt": "Back view" + }, + { + "src": "/images/jacket-detail.jpg", + "alt": "Detail view" + }, + { + "src": "/images/jacket-pocket.jpg", + "alt": "Pocket detail" + } + ], + "options": [ + { + "name": "Size", + "values": [ + "S", + "M", + "L", + "XL" + ] + }, + { + "name": "Color", + "values": [ + "Black", + "Brown", + "Navy" + ] + } + ], + "features": [ + "100% genuine leather", + "Satin lining", + "YKK zippers", + "Two exterior pockets", + "One interior pocket" + ], + "care": [ + "Dry clean only", + "Store on padded hanger", + "Keep away from heat" + ] + }, + "variants": [ + { + "id": 1, + "title": "S / Black", + "price": 299.99, + "available": true, + "sku": "LJ-BLK-S" + }, + { + "id": 2, + "title": "M / Black", + "price": 299.99, + "available": true, + "sku": "LJ-BLK-M" + }, + { + "id": 3, + "title": "L / Black", + "price": 299.99, + "available": false, + "sku": "LJ-BLK-L" + }, + { + "id": 4, + "title": "XL / Black", + "price": 299.99, + "available": true, + "sku": "LJ-BLK-XL" + }, + { + "id": 5, + "title": "S / Brown", + "price": 299.99, + "available": true, + "sku": "LJ-BRN-S" + }, + { + "id": 6, + "title": "M / Brown", + "price": 299.99, + "available": true, + "sku": "LJ-BRN-M" + }, + { + "id": 7, + "title": "L / Brown", + "price": 299.99, + "available": true, + "sku": "LJ-BRN-L" + }, + { + "id": 8, + "title": "XL / Brown", + "price": 299.99, + "available": false, + "sku": "LJ-BRN-XL" + } + ], + "breadcrumbs": [ + { + "title": "Home", + "url": "/" + }, + { + "title": "Apparel", + "url": "/collections/apparel" + }, + { + "title": "Outerwear", + "url": "/collections/outerwear" + }, + { + "title": "Classic Leather Jacket", + "url": null + } + ], + "related_products": [ + { + "title": "Bomber Jacket", + "price": 249.99, + "image": "/images/bomber.jpg", + "url": "/products/bomber" + }, + { + "title": "Denim Jacket", + "price": 149.99, + "image": "/images/denim.jpg", + "url": "/products/denim" + }, + { + "title": "Suede Jacket", + "price": 279.99, + "image": "/images/suede.jpg", + "url": "/products/suede" + }, + { + "title": "Windbreaker", + "price": 99.99, + "image": "/images/wind.jpg", + "url": "/products/windbreaker" + } + ], + "recent_products": [ + { + "title": "Wool Sweater", + "price": 89.99, + "image": "/images/sweater.jpg", + "url": "/products/sweater" + }, + { + "title": "Cotton T-Shirt", + "price": 29.99, + "image": "/images/tshirt.jpg", + "url": "/products/tshirt" + } + ], + "footer_links": [ + { + "title": "About", + "url": "/about" + }, + { + "title": "Contact", + "url": "/contact" + }, + { + "title": "Shipping", + "url": "/shipping" + }, + { + "title": "Returns", + "url": "/returns" + } + ] +} diff --git a/benchmarks/liquid-il/generated/bench_ecommerce_product_page.rb b/benchmarks/liquid-il/generated/bench_ecommerce_product_page.rb new file mode 100644 index 00000000..a55795b3 --- /dev/null +++ b/benchmarks/liquid-il/generated/bench_ecommerce_product_page.rb @@ -0,0 +1,136 @@ +# frozen_string_literal: true +# +# Auto-generated by LiquidIL (ruby compiler) +# Source template: +# {% render 'page_header', page_title: product.name %} +# {% render 'breadcrumbs', items: breadcrumbs %} +# {% render 'product_detail', product: product %} +# {% render 'product_reviews', reviews: reviews %} +# {% render 'related_products', products: related %} +# {% render 'page_footer' %} +# +# Usage: +# require_relative "this_file" +# output = LiquidILBenchBenchEcommerceProductPage.render({"name" => "World"}) +# + +autoload :LiquidIL, "liquid_il" unless defined?(LiquidIL) + +module LiquidILBenchBenchEcommerceProductPage + + PARTIAL_CONSTANTS = nil.freeze + + def self.render(assigns = {}, render_errors: true) + __scope__ = LiquidIL::Scope.new(assigns) + __scope__.render_errors = render_errors + __partial_constants__ = PARTIAL_CONSTANTS + + # Match compiler-generated local names used in proc source. + _S = __scope__ + _pc = __partial_constants__ + + _H = LiquidIL::RuntimeHelpers + __p706167655f686561646572__ = nil + __p62726561646372756d6273__ = nil + __p70726f647563745f64657461696c__ = nil + __p7265766965775f63617264__ = nil + __p70726f647563745f72657669657773__ = nil + __p72656c617465645f70726f6475637473__ = nil + __p706167655f666f6f746572__ = nil + + __p70726f647563745f72657669657773__ = ->(_S, _O, isolated, caller_line: 1, parent_cycle_state: nil) { + _cs = isolated ? {} : (parent_cycle_state || {}) + _O << "
\n

Customer Reviews

\n " + _H.ei(_S.lookup("reviews")) do |_i1300__| + _O << "\n " + _pa0__ = _i1300__ + _H.rolf(_O, "
\n ", _pa0__, "author") + _H.rolf(_O, "\n ", _pa0__, "rating") + _H.rolf(_O, "/5\n

", _pa0__, "text") + _O << "

\n
\n" + _O << "\n " + end + _O << "\n
\n" + } + + _O = +"" + _cs = {} + + _pa0__ = _H.lookup(_S.lookup("product"), "name") + _H.roa(_O, "
\n

", _pa0__) + _O << "

\n
\n" + _O << "\n" + _pa1__ = _S.lookup("breadcrumbs") + _O << "\n" + _O << "\n" + _pa2__ = _S.lookup("product") + _H.rolf(_O, "
\n

", _pa2__, "name") + _H.rolf(_O, "

\n

$", _pa2__, "price") + _H.rolf(_O, "

\n

", _pa2__, "description") + _H.rolf(_O, "

\n

SKU: ", _pa2__, "sku") + _O << "

\n " + if _H.t(_H.lf(_pa2__, "in_stock")) + _O << "\n

In Stock

\n " + else + _O << "\n

Out of Stock

\n " + end + _O << "\n
    \n " + _H.ei(_H.lf(_pa2__, "features")) do |_i1200__| + _O << "\n
  • " + _H.oa(_O, _i1200__) + _O << "
  • \n " + end + _O << "\n
\n
\n" + _O << "\n" + __partial_args__ = {} + __partial_args__["reviews"] = _S.lookup("reviews") + _H.ipc(__p70726f647563745f72657669657773__, "product_reviews", __partial_args__, _O, _S, true, 4, _cs) + _O << "\n" + _pa3__ = _S.lookup("related") + _O << "
\n

Related Products

\n
    \n " + _H.ei(_pa3__) do |_i1500__| + _O << "\n
  • " + _O << (_i1500__["name"].to_s) + _O << " - $" + _O << (_i1500__["price"].to_s) + _O << "
  • \n " + end + _O << "\n
\n
\n" + _O << "\n" + _O << "
\n

Thank you for shopping with us!

\n
\n" + _O << "\n" + + _O + + + _O + rescue LiquidIL::RuntimeError => e + raise unless render_errors + output = e.partial_output || "" + location = e.file ? "#{e.file} line #{e.line}" : "line #{e.line}" + output + "Liquid error (#{location}): #{e.message}" + rescue StandardError => e + raise unless render_errors + "Liquid error (line 1): #{LiquidIL.clean_error_message(e.message)}" + end +end diff --git a/benchmarks/liquid-il/generated/bench_notification_center.rb b/benchmarks/liquid-il/generated/bench_notification_center.rb new file mode 100644 index 00000000..cb8da5bc --- /dev/null +++ b/benchmarks/liquid-il/generated/bench_notification_center.rb @@ -0,0 +1,163 @@ +# frozen_string_literal: true +# +# Auto-generated by LiquidIL (ruby compiler) +# Source template: +#
+# {% for notification in notifications %} +# {% case notification.type %} +# {% when 'order' %} +# {% render 'notif_order', notif: notification %} +# {% when 'shipping' %} +# {% render 'notif_shipping', notif: notification %} +# {% when 'review' %} +# {% render 'notif_review', notif: notification %} +# {% when 'promo' %} +# {% render 'notif_promo', notif: notification %} +# {% when 'stock' %} +# {% render 'notif_stock', notif: notification %} +# {% endcase %} +# {% endfor %} +#
+# +# Usage: +# require_relative "this_file" +# output = LiquidILBenchBenchNotificationCenter.render({"name" => "World"}) +# + +autoload :LiquidIL, "liquid_il" unless defined?(LiquidIL) + +module LiquidILBenchBenchNotificationCenter + + PARTIAL_CONSTANTS = nil.freeze + + def self.render(assigns = {}, render_errors: true) + __scope__ = LiquidIL::Scope.new(assigns) + __scope__.render_errors = render_errors + __partial_constants__ = PARTIAL_CONSTANTS + + # Match compiler-generated local names used in proc source. + _S = __scope__ + _pc = __partial_constants__ + + _H = LiquidIL::RuntimeHelpers + _U = LiquidIL::Utils + __p6e6f7469665f6f72646572__ = nil + __p6e6f7469665f7368697070696e67__ = nil + __p6e6f7469665f726576696577__ = nil + __p6e6f7469665f70726f6d6f__ = nil + __p6e6f7469665f73746f636b__ = nil + + _O = +"" + _cst = [] + + _O << "
\n " + _H.ei(_S.lookup("notifications")) do |_i0__| + _O << "\n " + __temp_0__ = _i0__["type"] + __temp_1__ = false + _cst << _O; _O = String.new + _O << "\n " + _O = _cst.pop + if (_U.ce?("order", __temp_0__)) + __temp_1__ = true + _O << "\n " + _pa0__ = _i0__ + _H.rolf(_O, "
\n
📦
\n
\n

Order ", _pa0__, "order_id") + _H.rolf(_O, " ", _pa0__, "status") + _H.rolf(_O, "

\n

", _pa0__, "items") + _H.rolf(_O, " items • $", _pa0__, "total") + _H.rolf(_O, "

\n \n " + if (_H.cmp(_H.lf(_pa0__, "status"), "confirmed", :eq, _O, "notif_order")) + _O << "\n Confirmed\n " + else + if (_H.cmp(_H.lf(_pa0__, "status"), "processing", :eq, _O, "notif_order")) + _O << "\n Processing\n " + else + if (_H.cmp(_H.lf(_pa0__, "status"), "shipped", :eq, _O, "notif_order")) + _O << "\n Shipped\n " + end + end + end + _O << "\n
\n
\n" + _O << "\n " + end + if (_U.ce?("shipping", __temp_0__)) + __temp_1__ = true + _O << "\n " + _pa1__ = _i0__ + _H.rolf(_O, "
\n
🚚
\n
\n

Shipment Update

\n

Order ", _pa1__, "order_id") + _H.rolf(_O, " via ", _pa1__, "carrier") + _H.rolf(_O, "

\n

Tracking: ", _pa1__, "tracking") + _H.rolf(_O, "

\n

Expected: ", _pa1__, "eta") + _H.rolf(_O, "

\n Track Package\n
\n
\n" + _O << "\n " + end + if (_U.ce?("review", __temp_0__)) + __temp_1__ = true + _O << "\n " + _pa2__ = _i0__ + _H.rolf(_O, "
\n
\n
\n

New Review for ", _pa2__, "product") + _H.rolf(_O, "

\n

", _pa2__, "customer") + _H.rolf(_O, " rated ", _pa2__, "rating") + _H.rolf(_O, "/5

\n
\"", _pa2__, "snippet") + _O << "\"
\n View All Reviews\n
\n
\n" + _O << "\n " + end + if (_U.ce?("promo", __temp_0__)) + __temp_1__ = true + _O << "\n " + _pa3__ = _i0__ + _H.rolf(_O, "
\n
🎁
\n
\n

", _pa3__, "discount") + _H.rolf(_O, " Off!

\n

Use code ", _pa3__, "code") + _H.rolf(_O, "

\n

Min. purchase $", _pa3__, "min_purchase") + _H.rolf(_O, " • Expires ", _pa3__, "expires") + _H.rolf(_O, "

\n \n
\n
\n" + _O << "\n " + end + if (_U.ce?("stock", __temp_0__)) + __temp_1__ = true + _O << "\n " + _pa4__ = _i0__ + _O << "
\n
" + if (_H.cmp(_H.lf(_pa4__, "status"), "back_in_stock", :eq, _O, "notif_stock")) + _O << "✅" + else + _O << "⚠️" + end + _H.rolf(_O, "
\n
\n

", _pa4__, "product") + _H.rolf(_O, "

\n

SKU: ", _pa4__, "sku") + _O << "

\n " + if (_H.cmp(_H.lf(_pa4__, "status"), "back_in_stock", :eq, _O, "notif_stock")) + _H.rolf(_O, "\n

Back in stock! ", _pa4__, "quantity") + _O << " available

\n " + else + if (_H.cmp(_H.lf(_pa4__, "status"), "low_stock", :eq, _O, "notif_stock")) + _H.rolf(_O, "\n

Low stock: only ", _pa4__, "quantity") + _O << " left

\n " + end + end + _H.rolf(_O, "\n View Product\n
\n
\n" + _O << "\n " + end + _O << "\n " + end + _O << "\n
\n" + + _O + + + _O + rescue LiquidIL::RuntimeError => e + raise unless render_errors + output = e.partial_output || "" + location = e.file ? "#{e.file} line #{e.line}" : "line #{e.line}" + output + "Liquid error (#{location}): #{e.message}" + rescue StandardError => e + raise unless render_errors + "Liquid error (line 1): #{LiquidIL.clean_error_message(e.message)}" + end +end diff --git a/benchmarks/liquid-il/generated/bench_render_for_loop.rb b/benchmarks/liquid-il/generated/bench_render_for_loop.rb new file mode 100644 index 00000000..c234020e --- /dev/null +++ b/benchmarks/liquid-il/generated/bench_render_for_loop.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true +# +# Auto-generated by LiquidIL (ruby compiler) +# Source template: +# {% render 'item' for items as item %} +# +# Usage: +# require_relative "this_file" +# output = LiquidILBenchBenchRenderForLoop.render({"name" => "World"}) +# + +autoload :LiquidIL, "liquid_il" unless defined?(LiquidIL) + +module LiquidILBenchBenchRenderForLoop + + PARTIAL_CONSTANTS = nil.freeze + + def self.render(assigns = {}, render_errors: true) + __scope__ = LiquidIL::Scope.new(assigns) + __scope__.render_errors = render_errors + __partial_constants__ = PARTIAL_CONSTANTS + + # Match compiler-generated local names used in proc source. + _S = __scope__ + _pc = __partial_constants__ + + _H = LiquidIL::RuntimeHelpers + __p6974656d__ = nil + + __p6974656d__ = ->(_S, _O, isolated, caller_line: 1, parent_cycle_state: nil) { + _H.oa(_O, _S.lookup("item")) + unless _H.t(_H.lp(_S.lookup("forloop"), "last")) + _O << ", " + end + } + + _O = +"" + + __partial_args__ = {} + _H.rpf(__p6974656d__, "item", "item", _S.lookup("items"), __partial_args__, _O, _S, 1) + + _O + + + _O + rescue LiquidIL::RuntimeError => e + raise unless render_errors + output = e.partial_output || "" + location = e.file ? "#{e.file} line #{e.line}" : "line #{e.line}" + output + "Liquid error (#{location}): #{e.message}" + rescue StandardError => e + raise unless render_errors + "Liquid error (line 1): #{LiquidIL.clean_error_message(e.message)}" + end +end diff --git a/benchmarks/liquid-il/generated/bench_render_with_params.rb b/benchmarks/liquid-il/generated/bench_render_with_params.rb new file mode 100644 index 00000000..58cba7f8 --- /dev/null +++ b/benchmarks/liquid-il/generated/bench_render_with_params.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true +# +# Auto-generated by LiquidIL (ruby compiler) +# Source template: +# {% for product in products %} +# {% render 'product_card', product: product, show_price: true %} +# {% endfor %} +# +# Usage: +# require_relative "this_file" +# output = LiquidILBenchBenchRenderWithParams.render({"name" => "World"}) +# + +autoload :LiquidIL, "liquid_il" unless defined?(LiquidIL) + +module LiquidILBenchBenchRenderWithParams + + PARTIAL_CONSTANTS = nil.freeze + + def self.render(assigns = {}, render_errors: true) + __scope__ = LiquidIL::Scope.new(assigns) + __scope__.render_errors = render_errors + __partial_constants__ = PARTIAL_CONSTANTS + + # Match compiler-generated local names used in proc source. + _S = __scope__ + _pc = __partial_constants__ + + _H = LiquidIL::RuntimeHelpers + __p70726f647563745f63617264__ = nil + + _O = +"" + + _H.ei(_S.lookup("products")) do |_i0__| + _O << "\n" + _pa0__ = _i0__ + _pa1__ = true + _H.rolf(_O, "
\n

", _pa0__, "name") + _H.rolf(_O, "

\n

", _pa0__, "description") + _O << "

\n " + if _H.t(_pa1__) + _H.rolf(_O, "$", _pa0__, "price") + _O << "" + end + _O << "\n
\n" + _O << "\n" + end + _O << "\n" + + _O + + + _O + rescue LiquidIL::RuntimeError => e + raise unless render_errors + output = e.partial_output || "" + location = e.file ? "#{e.file} line #{e.line}" : "line #{e.line}" + output + "Liquid error (#{location}): #{e.message}" + rescue StandardError => e + raise unless render_errors + "Liquid error (line 1): #{LiquidIL.clean_error_message(e.message)}" + end +end diff --git a/benchmarks/liquid-il/generated/bench_simple_product_listing.rb b/benchmarks/liquid-il/generated/bench_simple_product_listing.rb new file mode 100644 index 00000000..3c209cc1 --- /dev/null +++ b/benchmarks/liquid-il/generated/bench_simple_product_listing.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true +# +# Auto-generated by LiquidIL (ruby compiler) +# Source template: +# {% render 'header' with 'Products' as title %} +# +# +# Usage: +# require_relative "this_file" +# output = LiquidILBenchBenchSimpleProductListing.render({"name" => "World"}) +# + +autoload :LiquidIL, "liquid_il" unless defined?(LiquidIL) + +module LiquidILBenchBenchSimpleProductListing + + PARTIAL_CONSTANTS = nil.freeze + + def self.render(assigns = {}, render_errors: true) + __scope__ = LiquidIL::Scope.new(assigns) + __scope__.render_errors = render_errors + __partial_constants__ = PARTIAL_CONSTANTS + + # Match compiler-generated local names used in proc source. + _S = __scope__ + _pc = __partial_constants__ + + _H = LiquidIL::RuntimeHelpers + __p686561646572__ = nil + __p6974656d__ = nil + + __p686561646572__ = ->(_S, _O, isolated, caller_line: 1, parent_cycle_state: nil) { + _H.roa(_O, "
", _S.lookup("title")) + _O << "
" + } + + __p6974656d__ = ->(_S, _O, isolated, caller_line: 1, parent_cycle_state: nil) { + _H.rolf(_O, "
  • ", _S.lookup("item"), "name") + _H.rolf(_O, ": $", _S.lookup("item"), "price") + _O << "
  • " + } + + _O = +"" + + __partial_args__ = {} + __with_val__ = "Products" + __partial_args__["title"] = __with_val__ unless __with_val__.nil? + _H.ipc(__p686561646572__, "header", __partial_args__, _O, _S, true, 1) + _O << "\n\n" + + _O + + + _O + rescue LiquidIL::RuntimeError => e + raise unless render_errors + output = e.partial_output || "" + location = e.file ? "#{e.file} line #{e.line}" : "line #{e.line}" + output + "Liquid error (#{location}): #{e.message}" + rescue StandardError => e + raise unless render_errors + "Liquid error (line 1): #{LiquidIL.clean_error_message(e.message)}" + end +end diff --git a/benchmarks/liquid-il/generated/bench_theme_cart_page.rb b/benchmarks/liquid-il/generated/bench_theme_cart_page.rb new file mode 100644 index 00000000..7bb719b3 --- /dev/null +++ b/benchmarks/liquid-il/generated/bench_theme_cart_page.rb @@ -0,0 +1,204 @@ +# frozen_string_literal: true +# +# Auto-generated by LiquidIL (ruby compiler) +# Source template: +# {% render 'theme_header', shop: shop %} +#
    +#

    Shopping Cart

    +# {% if cart.items.size > 0 %} +# {% render 'cart_table', cart: cart %} +# {% render 'cart_totals', cart: cart %} +# {% render 'cart_actions' %} +# {% render 'shipping_calculator', rates: shipping_rates %} +# {% else %} +# {% render 'empty_cart' %} +# {% endif %} +# {% render 'cart_recommendations', products: recommendations %} +#
    +# {% render 'theme_footer', shop: shop, links: footer_links %} +# +# Usage: +# require_relative "this_file" +# output = LiquidILBenchBenchThemeCartPage.render({"name" => "World"}) +# + +autoload :LiquidIL, "liquid_il" unless defined?(LiquidIL) + +module LiquidILBenchBenchThemeCartPage + + PARTIAL_CONSTANTS = nil.freeze + + def self.render(assigns = {}, render_errors: true) + __scope__ = LiquidIL::Scope.new(assigns) + __scope__.render_errors = render_errors + __partial_constants__ = PARTIAL_CONSTANTS + + # Match compiler-generated local names used in proc source. + _S = __scope__ + _pc = __partial_constants__ + + _H = LiquidIL::RuntimeHelpers + _F = LiquidIL::Filters + __p7468656d655f686561646572__ = nil + __p636172745f6c696e655f6974656d__ = nil + __p636172745f7461626c65__ = nil + __p636172745f746f74616c73__ = nil + __p636172745f616374696f6e73__ = nil + __p7368697070696e675f63616c63756c61746f72__ = nil + __p656d7074795f63617274__ = nil + __p70726f647563745f63617264__ = nil + __p636172745f7265636f6d6d656e646174696f6e73__ = nil + __p7468656d655f666f6f746572__ = nil + + __p636172745f7461626c65__ = ->(_S, _O, isolated, caller_line: 1, parent_cycle_state: nil) { + _cs = isolated ? {} : (parent_cycle_state || {}) + _O << "\n \n \n \n \n \n \n \n \n \n \n " + _H.ei(_H.lf(_S.lookup("cart"), "items")) do |_i3100__| + _O << "\n " + _pa0__ = _i3100__ + _H.rolf(_O, "\n \n \n \n \n \n\n" + _O << "\n " + end + _O << "\n \n
    ProductPriceQuantityTotalActions
    \n \"",\n
    \n ", _pa0__, "title") + _H.rolf(_O, "\n

    ", _pa0__, "variant_title") + _H.rolf(_O, "

    \n

    SKU: ", _pa0__, "sku") + _O << "

    \n " + if (_H.cmp(_H.lp(_H.lf(_pa0__, "properties"), "size"), 0, :gt, _O, "cart_line_item")) + _O << "\n
    \n " + _H.ei(_H.lf(_pa0__, "properties")) do |_i3200__| + _O << "\n

    " + _H.oa(_O, _H.bl(_i3200__, 0)) + _O << ": " + _H.oa(_O, _H.bl(_i3200__, 1)) + _O << "

    \n " + end + _O << "\n
    \n " + end + _H.rolf(_O, "\n
    \n
    $", _pa0__, "price") + _H.rolf(_O, "\n \n $", _pa0__, "line_price") + _H.rolf(_O, "\n \n
    \n" + } + + __p636172745f7265636f6d6d656e646174696f6e73__ = ->(_S, _O, isolated, caller_line: 1, parent_cycle_state: nil) { + _cs = isolated ? {} : (parent_cycle_state || {}) + _O << "
    \n

    You might also like

    \n
    \n " + _H.ei(_S.lookup("products")) do |_i3700__| + _O << "\n " + _pa0__ = _i3700__ + _H.rolf(_O, "\n" + _O << "\n " + end + _O << "\n
    \n
    \n" + } + + _O = +"" + _cs = {} + + _pa0__ = _S.lookup("shop") + _H.rolf(_O, "\n\n\n ", _pa0__, "name") + _H.rolf(_O, " - Cart\n\n\n
    \n
    ", _pa0__, "name") + _O << "
    \n
    \n" + _O << "\n
    \n

    Shopping Cart

    \n " + if (_H.cmp(_H.lp(_H.lf(_S.lookup("cart"), "items"), "size"), 0, :gt, _O, nil)) + _O << "\n " + __partial_args__ = {} + __partial_args__["cart"] = _S.lookup("cart") + _H.ipc(__p636172745f7461626c65__, "cart_table", __partial_args__, _O, _S, true, 5, _cs) + _O << "\n " + _pa1__ = _S.lookup("cart") + __partial_args__ = {} + __partial_args__["cart"] = _pa1__ + __caller_scope_2__ = _S; _S = _S.isolated_with(__partial_args__) + _H.rolf(_O, "
    \n
    \n Subtotal (", _pa1__, "item_count") + _H.rolf(_O, " items):\n $", _pa1__, "total_price") + _O << "\n
    \n " + if (_H.cmp(_H.lp(_H.lf(_pa1__, "discounts"), "size"), 0, :gt, _O, "cart_totals")) + _O << "\n
    \n " + _H.ei(_H.lf(_pa1__, "discounts")) do |_i3300__| + _O << "\n
    \n " + _O << (_i3300__["title"].to_s) + _O << " (" + _O << (_i3300__["code"].to_s) + _O << "):\n -$" + _O << (_i3300__["amount"].to_s) + _O << "\n
    \n " + end + _O << "\n
    \n " + end + _O << "\n " + _H.af(_S, "final_total", _H.lf(_pa1__, "total_price")) + _O << "\n " + _H.ei(_H.lf(_pa1__, "discounts")) do |_i3300__| + _H.af(_S, "final_total", _F.minus(_S.lookup("final_total"), _i3300__["amount"])) + end + _H.roa(_O, "\n
    \n Total:\n $", _S.lookup("final_total")) + _O << "\n
    \n
    \n" + _S = __caller_scope_2__ + _O << "\n " + _O << "\n" + _O << "\n " + _pa2__ = _S.lookup("shipping_rates") + _O << "
    \n

    Shipping Estimates

    \n
      \n " + _H.ei(_pa2__) do |_i3500__| + _O << "\n
    • \n \n
    • \n " + end + _O << "\n
    \n
    \n" + _O << "\n " + else + _O << "\n " + _O << "
    \n

    Your cart is empty.

    \n Start Shopping\n
    \n" + _O << "\n " + end + _O << "\n " + __partial_args__ = {} + __partial_args__["products"] = _S.lookup("recommendations") + _H.ipc(__p636172745f7265636f6d6d656e646174696f6e73__, "cart_recommendations", __partial_args__, _O, _S, true, 12, _cs) + _O << "\n
    \n" + _pa3__ = _S.lookup("shop") + _pa4__ = _S.lookup("footer_links") + _O << "\n\n\n" + _O << "\n" + + _O + + + _O + rescue LiquidIL::RuntimeError => e + raise unless render_errors + output = e.partial_output || "" + location = e.file ? "#{e.file} line #{e.line}" : "line #{e.line}" + output + "Liquid error (#{location}): #{e.message}" + rescue StandardError => e + raise unless render_errors + "Liquid error (line 1): #{LiquidIL.clean_error_message(e.message)}" + end +end diff --git a/benchmarks/liquid-il/generated/bench_theme_collection_page.rb b/benchmarks/liquid-il/generated/bench_theme_collection_page.rb new file mode 100644 index 00000000..f4caecdd --- /dev/null +++ b/benchmarks/liquid-il/generated/bench_theme_collection_page.rb @@ -0,0 +1,223 @@ +# frozen_string_literal: true +# +# Auto-generated by LiquidIL (ruby compiler) +# Source template: +# {% render 'theme_header', shop: shop %} +# {% render 'collection_hero', collection: collection %} +#
    +# {% render 'filter_sidebar', filters: filters, active_filters: active_filters %} +#
    +# {% render 'sort_bar', sort_options: sort_options, current_sort: current_sort, product_count: collection.products.size %} +# {% render 'product_grid', products: collection.products %} +# {% render 'pagination', pages: pagination %} +#
    +#
    +# {% render 'theme_footer', shop: shop, links: footer_links %} +# +# Usage: +# require_relative "this_file" +# output = LiquidILBenchBenchThemeCollectionPage.render({"name" => "World"}) +# + +autoload :LiquidIL, "liquid_il" unless defined?(LiquidIL) + +module LiquidILBenchBenchThemeCollectionPage + + PARTIAL_CONSTANTS = nil.freeze + + def self.render(assigns = {}, render_errors: true) + __scope__ = LiquidIL::Scope.new(assigns) + __scope__.render_errors = render_errors + __partial_constants__ = PARTIAL_CONSTANTS + + # Match compiler-generated local names used in proc source. + _S = __scope__ + _pc = __partial_constants__ + + _H = LiquidIL::RuntimeHelpers + _F = LiquidIL::Filters + __p7468656d655f686561646572__ = nil + __p636f6c6c656374696f6e5f6865726f__ = nil + __p66696c7465725f73696465626172__ = nil + __p736f72745f626172__ = nil + __p636f6c6c656374696f6e5f70726f647563745f63617264__ = nil + __p70726f647563745f67726964__ = nil + __p706167696e6174696f6e__ = nil + __p7468656d655f666f6f746572__ = nil + + __p70726f647563745f67726964__ = ->(_S, _O, isolated, caller_line: 1, parent_cycle_state: nil) { + _cs = isolated ? {} : (parent_cycle_state || {}) + _O << "\n" + } + + _O = +"" + _cs = {} + + _pa0__ = _S.lookup("shop") + _H.rolf(_O, "\n\n\n ", _pa0__, "name") + _H.rolf(_O, "\n\n\n
    \n
    ", _pa0__, "name") + _O << "
    \n
    \n" + _O << "\n" + _pa1__ = _S.lookup("collection") + _H.rolf(_O, "
    \n
    \n

    ", _pa1__, "title") + _H.rolf(_O, "

    \n

    ", _pa1__, "description") + _H.rolf(_O, "

    \n ", _pa1__, "products_count") + _O << " products\n
    \n
    \n" + _O << "\n
    \n " + _pa2__ = _S.lookup("filters") + _pa3__ = _S.lookup("active_filters") + _O << "\n" + _O << "\n
    \n " + _pa4__ = _S.lookup("sort_options") + _pa5__ = _S.lookup("current_sort") + _pa6__ = _H.lookup(_H.lookup(_S.lookup("collection"), "products"), "size") + _H.roa(_O, "
    \n ", _pa6__) + _O << " products\n
    \n \n \n
    \n
    \n \n \n
    \n
    \n" + _O << "\n " + __partial_args__ = {} + __partial_args__["products"] = _H.lookup(_S.lookup("collection"), "products") + _H.ipc(__p70726f647563745f67726964__, "product_grid", __partial_args__, _O, _S, true, 7, _cs) + _O << "\n " + _pa7__ = _S.lookup("pagination") + __partial_args__ = {} + __partial_args__["pages"] = _pa7__ + __caller_scope_5__ = _S; _S = _S.isolated_with(__partial_args__) + _O << "\n" + _S = __caller_scope_5__ + _O << "\n
    \n
    \n" + _pa8__ = _S.lookup("shop") + _pa9__ = _S.lookup("footer_links") + _O << "\n\n\n" + _O << "\n" + + _O + + + _O + rescue LiquidIL::RuntimeError => e + raise unless render_errors + output = e.partial_output || "" + location = e.file ? "#{e.file} line #{e.line}" : "line #{e.line}" + output + "Liquid error (#{location}): #{e.message}" + rescue StandardError => e + raise unless render_errors + "Liquid error (line 1): #{LiquidIL.clean_error_message(e.message)}" + end +end diff --git a/benchmarks/liquid-il/generated/bench_theme_product_page.rb b/benchmarks/liquid-il/generated/bench_theme_product_page.rb new file mode 100644 index 00000000..7d6473aa --- /dev/null +++ b/benchmarks/liquid-il/generated/bench_theme_product_page.rb @@ -0,0 +1,272 @@ +# frozen_string_literal: true +# +# Auto-generated by LiquidIL (ruby compiler) +# Source template: +# {% render 'theme_header', shop: shop %} +# {% render 'breadcrumb_nav', crumbs: breadcrumbs %} +#
    +# {% render 'product_gallery', images: product.images %} +# {% render 'product_info', product: product, variants: variants %} +# {% render 'variant_selector', variants: variants %} +# {% render 'add_to_cart_form', product: product %} +# {% render 'product_tabs', product: product %} +# {% render 'related_grid', products: related_products, title: 'You may also like' %} +# {% render 'recently_viewed', products: recent_products %} +#
    +# {% render 'theme_footer', shop: shop, links: footer_links %} +# +# Usage: +# require_relative "this_file" +# output = LiquidILBenchBenchThemeProductPage.render({"name" => "World"}) +# + +autoload :LiquidIL, "liquid_il" unless defined?(LiquidIL) + +module LiquidILBenchBenchThemeProductPage + + PARTIAL_CONSTANTS = nil.freeze + + def self.render(assigns = {}, render_errors: true) + __scope__ = LiquidIL::Scope.new(assigns) + __scope__.render_errors = render_errors + __partial_constants__ = PARTIAL_CONSTANTS + + # Match compiler-generated local names used in proc source. + _S = __scope__ + _pc = __partial_constants__ + + _H = LiquidIL::RuntimeHelpers + _F = LiquidIL::Filters + __p6d61696e5f6e6176__ = nil + __p636172745f69636f6e__ = nil + __p7468656d655f686561646572__ = nil + __p62726561646372756d625f6e6176__ = nil + __p70726f647563745f67616c6c657279__ = nil + __p70726f647563745f696e666f__ = nil + __p76617269616e745f73656c6563746f72__ = nil + __p6164645f746f5f636172745f666f726d__ = nil + __p70726f647563745f74616273__ = nil + __p70726f647563745f63617264__ = nil + __p72656c617465645f67726964__ = nil + __p726563656e746c795f766965776564__ = nil + __p7468656d655f666f6f746572__ = nil + + __p7468656d655f686561646572__ = ->(_S, _O, isolated, caller_line: 1, parent_cycle_state: nil) { + _cs = isolated ? {} : (parent_cycle_state || {}) + _H.rolf(_O, "\n\n\n ", _S.lookup("shop"), "name") + _H.rolf(_O, "\n \n\n\n
    \n
    ", _S.lookup("shop"), "name") + _O << "
    \n " + _O << "\n" + _O << "\n " + _O << "
    \n Cart\n
    \n" + _O << "\n
    \n" + } + + __p72656c617465645f67726964__ = ->(_S, _O, isolated, caller_line: 1, parent_cycle_state: nil) { + _cs = isolated ? {} : (parent_cycle_state || {}) + _H.roa(_O, "
    \n

    ", _S.lookup("title")) + _O << "

    \n
    \n " + _H.ei(_S.lookup("products")) do |_i2600__| + _O << "\n " + _pa0__ = _i2600__ + _H.rolf(_O, "\n" + _O << "\n " + end + _O << "\n
    \n
    \n" + } + + __p726563656e746c795f766965776564__ = ->(_S, _O, isolated, caller_line: 1, parent_cycle_state: nil) { + _cs = isolated ? {} : (parent_cycle_state || {}) + _O << "
    \n

    Recently Viewed

    \n
    \n " + _H.ei(_S.lookup("products")) do |_i2800__| + _O << "\n " + _pa0__ = _i2800__ + _H.rolf(_O, "\n" + _O << "\n " + end + _O << "\n
    \n
    \n" + } + + _O = +"" + _cs = {} + + __partial_args__ = {} + __partial_args__["shop"] = _S.lookup("shop") + _H.ipc(__p7468656d655f686561646572__, "theme_header", __partial_args__, _O, _S, true, 1, _cs) + _O << "\n" + _pa0__ = _S.lookup("breadcrumbs") + _O << "\n" + _O << "\n
    \n " + _pa1__ = _H.lookup(_S.lookup("product"), "images") + _O << "
    \n " + _H.eif(_pa1__, "image-images", nil) do |_i2100__, _fl2100__| + _O << "\n
    \n \""\n
    \n " + end + _O << "\n
    \n " + _H.eif(_pa1__, "image-images", nil) do |_i2100__, _fl2100__| + _O << "\n \n " + end + _O << "\n
    \n
    \n" + _O << "\n " + _pa2__ = _S.lookup("product") + __partial_args__ = {} + __partial_args__["product"] = _pa2__ + __caller_scope_3__ = _S; _S = _S.isolated_with(__partial_args__) + _H.rolf(_O, "
    \n

    ", _pa2__, "vendor") + _H.rolf(_O, "

    \n

    ", _pa2__, "title") + _O << "

    \n
    \n " + if (_H.cmp(_H.lf(_pa2__, "compare_at_price"), _H.lf(_pa2__, "price"), :gt, _O, "product_info")) + _H.rolf(_O, "\n $", _pa2__, "compare_at_price") + _O << "\n " + end + _H.rolf(_O, "\n $", _pa2__, "price") + _O << "\n " + if (_H.cmp(_H.lf(_pa2__, "compare_at_price"), _H.lf(_pa2__, "price"), :gt, _O, "product_info")) + _O << "\n " + _H.af(_S, "savings", _F.minus(_H.lf(_pa2__, "compare_at_price"), _H.lf(_pa2__, "price"))) + _H.roa(_O, "\n Save $", _S.lookup("savings")) + _O << "\n " + end + _H.rolf(_O, "\n
    \n
    ", _pa2__, "description") + _O << "
    \n
    \n " + _H.ei(_H.lf(_pa2__, "tags")) do |_i2200__| + _O << "\n " + _H.oa(_O, _i2200__) + _O << "\n " + end + _O << "\n
    \n
    \n" + _S = __caller_scope_3__ + _O << "\n " + _pa3__ = _S.lookup("variants") + _O << "
    \n \n \n
    \n" + _O << "\n " + _pa4__ = _S.lookup("product") + _H.rolf(_O, "
    \n \n
    \n \n \n
    \n " + if _H.t(_H.lf(_pa4__, "available")) + _O << "\n \n " + else + _O << "\n \n " + end + _O << "\n
    \n" + _O << "\n " + _pa5__ = _S.lookup("product") + _O << "
    \n
    \n

    Features

    \n
      \n " + _H.ei(_H.lf(_pa5__, "features")) do |_i2500__| + _O << "\n
    • " + _H.oa(_O, _i2500__) + _O << "
    • \n " + end + _O << "\n
    \n
    \n
    \n

    Care Instructions

    \n
      \n " + _H.ei(_H.lf(_pa5__, "care")) do |_i2500__| + _O << "\n
    • " + _H.oa(_O, _i2500__) + _O << "
    • \n " + end + _O << "\n
    \n
    \n
    \n" + _O << "\n " + __partial_args__ = {} + __partial_args__["products"] = _S.lookup("related_products") + __partial_args__["title"] = "You may also like" + _H.ipc(__p72656c617465645f67726964__, "related_grid", __partial_args__, _O, _S, true, 9, _cs) + _O << "\n " + __partial_args__ = {} + __partial_args__["products"] = _S.lookup("recent_products") + _H.ipc(__p726563656e746c795f766965776564__, "recently_viewed", __partial_args__, _O, _S, true, 10, _cs) + _O << "\n
    \n" + _pa6__ = _S.lookup("shop") + _pa7__ = _S.lookup("footer_links") + _O << "\n\n\n" + _O << "\n" + + _O + + + _O + rescue LiquidIL::RuntimeError => e + raise unless render_errors + output = e.partial_output || "" + location = e.file ? "#{e.file} line #{e.line}" : "line #{e.line}" + output + "Liquid error (#{location}): #{e.message}" + rescue StandardError => e + raise unless render_errors + "Liquid error (line 1): #{LiquidIL.clean_error_message(e.message)}" + end +end diff --git a/benchmarks/liquid-il/manifest.json b/benchmarks/liquid-il/manifest.json new file mode 100644 index 00000000..2e825a12 --- /dev/null +++ b/benchmarks/liquid-il/manifest.json @@ -0,0 +1,42 @@ +[ + { + "spec": "bench_simple_product_listing", + "module": "LiquidILBenchBenchSimpleProductListing", + "ruby_bytes": 2249 + }, + { + "spec": "bench_render_with_params", + "module": "LiquidILBenchBenchRenderWithParams", + "ruby_bytes": 1684 + }, + { + "spec": "bench_render_for_loop", + "module": "LiquidILBenchBenchRenderForLoop", + "ruby_bytes": 1486 + }, + { + "spec": "bench_notification_center", + "module": "LiquidILBenchBenchNotificationCenter", + "ruby_bytes": 6449 + }, + { + "spec": "bench_ecommerce_product_page", + "module": "LiquidILBenchBenchEcommerceProductPage", + "ruby_bytes": 4510 + }, + { + "spec": "bench_theme_product_page", + "module": "LiquidILBenchBenchThemeProductPage", + "ruby_bytes": 11008 + }, + { + "spec": "bench_theme_cart_page", + "module": "LiquidILBenchBenchThemeCartPage", + "ruby_bytes": 8886 + }, + { + "spec": "bench_theme_collection_page", + "module": "LiquidILBenchBenchThemeCollectionPage", + "ruby_bytes": 9026 + } +] diff --git a/benchmarks/liquid-il/templates.yml b/benchmarks/liquid-il/templates.yml new file mode 100644 index 00000000..d208df1d --- /dev/null +++ b/benchmarks/liquid-il/templates.yml @@ -0,0 +1,1723 @@ +--- +specs: +- name: bench_simple_product_listing + template: | + {% render 'header' with 'Products' as title %} + + filesystem: + header: "
    {{ title }}
    " + item: "
  • {{ item.name }}: ${{ item.price }}
  • " + environment: + products: + - name: Widget + price: 9.99 + - name: Gadget + price: 19.99 + - name: Gizmo + price: 29.99 + expected: | +
    Products
    + +- name: bench_render_with_params + template: | + {% for product in products %} + {% render 'product_card', product: product, show_price: true %} + {% endfor %} + filesystem: + product_card: | +
    +

    {{ product.name }}

    +

    {{ product.description }}

    + {% if show_price %}${{ product.price }}{% endif %} +
    + environment: + products: + - name: Widget + price: 9.99 + description: A useful widget + - name: Gadget + price: 19.99 + description: An amazing gadget + - name: Gizmo + price: 29.99 + description: A fantastic gizmo + - name: Doohickey + price: 39.99 + description: A wonderful doohickey + - name: Thingamajig + price: 49.99 + description: A marvelous thingamajig + expected: |2+ + +
    +

    Widget

    +

    A useful widget

    + $9.99 +
    + + +
    +

    Gadget

    +

    An amazing gadget

    + $19.99 +
    + + +
    +

    Gizmo

    +

    A fantastic gizmo

    + $29.99 +
    + + +
    +

    Doohickey

    +

    A wonderful doohickey

    + $39.99 +
    + + +
    +

    Thingamajig

    +

    A marvelous thingamajig

    + $49.99 +
    + + +- name: bench_render_for_loop + template: "{% render 'item' for items as item %}" + filesystem: + item: "{{ item }}{% unless forloop.last %}, {% endunless %}" + environment: + items: + - 1 + - 2 + - 3 + - 4 + - 5 + - 6 + - 7 + - 8 + - 9 + - 10 + - 11 + - 12 + - 13 + - 14 + - 15 + - 16 + - 17 + - 18 + - 19 + - 20 + expected: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 +- name: bench_notification_center + template: | +
    + {% for notification in notifications %} + {% case notification.type %} + {% when 'order' %} + {% render 'notif_order', notif: notification %} + {% when 'shipping' %} + {% render 'notif_shipping', notif: notification %} + {% when 'review' %} + {% render 'notif_review', notif: notification %} + {% when 'promo' %} + {% render 'notif_promo', notif: notification %} + {% when 'stock' %} + {% render 'notif_stock', notif: notification %} + {% endcase %} + {% endfor %} +
    + filesystem: + notif_order: "
    \n
    \U0001F4E6
    \n + \
    \n

    Order {{ notif.order_id }} {{ notif.status + }}

    \n

    {{ notif.items }} items • ${{ notif.total }}

    \n \n {% if notif.status == 'confirmed' %}\n Confirmed\n {% elsif notif.status == + 'processing' %}\n Processing\n + \ {% elsif notif.status == 'shipped' %}\n Shipped\n + \ {% endif %}\n
    \n
    \n" + notif_shipping: "
    \n
    \U0001F69A
    \n + \
    \n

    Shipment Update

    \n

    Order + {{ notif.order_id }} via {{ notif.carrier }}

    \n

    Tracking: + {{ notif.tracking }}

    \n

    Expected: {{ notif.eta }}

    \n + \ Track Package\n + \
    \n
    \n" + notif_review: | +
    +
    +
    +

    New Review for {{ notif.product }}

    +

    {{ notif.customer }} rated {{ notif.rating }}/5

    +
    "{{ notif.snippet }}"
    + View All Reviews +
    +
    + notif_promo: "
    \n
    \U0001F381
    \n + \
    \n

    {{ notif.discount }} Off!

    \n

    Use + code {{ notif.code }}

    \n

    Min. purchase + ${{ notif.min_purchase }} • Expires {{ notif.expires }}

    \n \n
    \n
    \n" + notif_stock: | +
    +
    {% if notif.status == 'back_in_stock' %}✅{% else %}⚠️{% endif %}
    +
    +

    {{ notif.product }}

    +

    SKU: {{ notif.sku }}

    + {% if notif.status == 'back_in_stock' %} +

    Back in stock! {{ notif.quantity }} available

    + {% elsif notif.status == 'low_stock' %} +

    Low stock: only {{ notif.quantity }} left

    + {% endif %} + View Product +
    +
    + environment: + notifications: + - type: order + order_id: ORD-001 + status: confirmed + total: 149.99 + items: 3 + date: '2024-01-15' + - type: shipping + order_id: ORD-002 + carrier: FedEx + tracking: '1234567890' + eta: Jan 18 + - type: review + product: Leather Jacket + customer: Alice + rating: 5 + snippet: Amazing quality! + - type: promo + code: SAVE20 + discount: 20% + expires: Jan 31 + min_purchase: 50 + - type: stock + product: Blue Widget + sku: BW-001 + status: back_in_stock + quantity: 25 + - type: order + order_id: ORD-003 + status: processing + total: 89.5 + items: 2 + date: '2024-01-16' + - type: shipping + order_id: ORD-001 + carrier: UPS + tracking: '9876543210' + eta: Jan 17 + - type: review + product: Cotton T-Shirt + customer: Bob + rating: 4 + snippet: Great fit + - type: promo + code: FREESHIP + discount: Free Shipping + expires: Feb 1 + min_purchase: 75 + - type: stock + product: Red Scarf + sku: RS-002 + status: low_stock + quantity: 3 + - type: order + order_id: ORD-004 + status: shipped + total: 299.0 + items: 1 + date: '2024-01-14' + - type: shipping + order_id: ORD-004 + carrier: USPS + tracking: '5555555555' + eta: Jan 19 + - type: review + product: Wool Sweater + customer: Carol + rating: 5 + snippet: Perfect for winter + - type: promo + code: VIP25 + discount: 25% + expires: Jan 20 + min_purchase: 100 + - type: stock + product: Green Hat + sku: GH-003 + status: back_in_stock + quantity: 50 + expected: "
    \n \n \n
    \n
    \U0001F4E6
    \n
    \n + \

    Order ORD-001 confirmed

    \n

    3 items • $149.99

    \n \n + \ \n Confirmed\n \n
    \n
    \n\n + \ \n \n \n
    \n + \
    \U0001F69A
    \n
    \n + \

    Shipment Update

    \n

    Order ORD-002 via FedEx

    \n

    Tracking: + 1234567890

    \n

    Expected: Jan 18

    \n Track Package\n
    \n
    \n\n \n \n \n + \
    \n
    \n + \
    \n

    New Review for Leather Jacket

    \n + \

    Alice rated 5/5

    \n
    \"Amazing quality!\"
    \n + \ View All Reviews\n
    \n
    \n\n + \ \n \n \n
    \n
    \U0001F381
    \n
    \n

    20% + Off!

    \n

    Use code SAVE20

    \n

    Min. + purchase $50 • Expires Jan 31

    \n \n
    \n
    \n\n \n \n \n
    \n
    \n
    \n + \

    Blue Widget

    \n

    SKU: BW-001

    \n \n

    Back in stock! 25 available

    \n \n View Product\n
    \n
    \n\n \n \n \n
    \n
    \U0001F4E6
    \n + \
    \n

    Order ORD-003 processing

    \n

    2 + items • $89.5

    \n \n \n Processing\n \n
    \n
    \n\n \n \n \n + \
    \n
    \U0001F69A
    \n + \
    \n

    Shipment Update

    \n

    Order ORD-001 + via UPS

    \n

    Tracking: 9876543210

    \n

    Expected: + Jan 17

    \n Track Package\n + \
    \n
    \n\n \n \n \n
    \n + \
    \n
    \n

    New + Review for Cotton T-Shirt

    \n

    Bob rated 4/5

    \n + \
    \"Great fit\"
    \n View + All Reviews\n
    \n
    \n\n \n \n \n
    \n
    \U0001F381
    \n
    \n + \

    Free Shipping Off!

    \n

    Use code FREESHIP

    \n + \

    Min. purchase $75 • Expires Feb 1

    \n \n
    \n
    \n\n \n \n \n + \
    \n
    ⚠️
    \n + \
    \n

    Red Scarf

    \n

    SKU: + RS-002

    \n \n

    Low stock: only 3 left

    \n + \ \n View Product\n
    \n
    \n\n + \ \n \n \n
    \n
    \U0001F4E6
    \n
    \n

    Order + ORD-004 shipped

    \n

    1 items • $299.0

    \n \n + \ \n Shipped\n \n
    \n
    \n\n + \ \n \n \n
    \n + \
    \U0001F69A
    \n
    \n + \

    Shipment Update

    \n

    Order ORD-004 via USPS

    \n

    Tracking: + 5555555555

    \n

    Expected: Jan 19

    \n Track Package\n
    \n
    \n\n \n \n \n + \
    \n
    \n + \
    \n

    New Review for Wool Sweater

    \n

    Carol rated 5/5

    \n
    \"Perfect for winter\"
    \n + \ View All Reviews\n
    \n
    \n\n + \ \n \n \n
    \n
    \U0001F381
    \n
    \n

    25% + Off!

    \n

    Use code VIP25

    \n

    Min. + purchase $100 • Expires Jan 20

    \n \n
    \n
    \n\n \n \n \n
    \n
    \n
    \n + \

    Green Hat

    \n

    SKU: GH-003

    \n \n

    Back in stock! 50 available

    \n \n View Product\n
    \n
    \n\n \n \n
    \n" +- name: bench_ecommerce_product_page + template: | + {% render 'page_header', page_title: product.name %} + {% render 'breadcrumbs', items: breadcrumbs %} + {% render 'product_detail', product: product %} + {% render 'product_reviews', reviews: reviews %} + {% render 'related_products', products: related %} + {% render 'page_footer' %} + filesystem: + page_header: | +
    +

    {{ page_title }}

    +
    + breadcrumbs: | + + product_detail: | +
    +

    {{ product.name }}

    +

    ${{ product.price }}

    +

    {{ product.description }}

    +

    SKU: {{ product.sku }}

    + {% if product.in_stock %} +

    In Stock

    + {% else %} +

    Out of Stock

    + {% endif %} +
      + {% for feature in product.features %} +
    • {{ feature }}
    • + {% endfor %} +
    +
    + product_reviews: | +
    +

    Customer Reviews

    + {% for review in reviews %} + {% render 'review_card', review: review %} + {% endfor %} +
    + review_card: | +
    + {{ review.author }} + {{ review.rating }}/5 +

    {{ review.text }}

    +
    + related_products: | + + page_footer: | +
    +

    Thank you for shopping with us!

    +
    + environment: + product: + name: Premium Widget + price: 99.99 + description: The finest widget money can buy + sku: WDG-001 + in_stock: true + features: + - Durable + - Lightweight + - Eco-friendly + breadcrumbs: + - label: Home + url: "/" + - label: Widgets + url: "/widgets" + - label: Premium Widget + url: + reviews: + - author: Alice + rating: 5 + text: Amazing! + - author: Bob + rating: 4 + text: Very good + - author: Carol + rating: 5 + text: Love it + related: + - name: Basic Widget + price: 29.99 + - name: Super Widget + price: 149.99 + - name: Widget Pro + price: 199.99 + expected: "
    \n

    Premium Widget

    \n
    \n\n\n\n
    \n

    Premium Widget

    \n

    $99.99

    \n + \

    The finest widget money can buy

    \n

    SKU: + WDG-001

    \n \n

    In Stock

    \n \n
      \n + \ \n
    • Durable
    • \n \n
    • Lightweight
    • \n \n
    • Eco-friendly
    • \n + \ \n
    \n
    \n\n
    \n

    Customer Reviews

    \n + \ \n
    \n Alice\n 5/5\n + \

    Amazing!

    \n
    \n\n \n
    \n Bob\n + \ 4/5\n

    Very good

    \n
    \n\n \n
    \n Carol\n 5/5\n + \

    Love it

    \n
    \n\n \n
    \n\n
    \n

    Related + Products

    \n
      \n \n
    • Basic Widget - $29.99
    • \n \n
    • Super + Widget - $149.99
    • \n \n
    • Widget Pro - $199.99
    • \n \n
    \n
    \n\n
    \n + \

    Thank you for shopping with us!

    \n
    \n\n" +- name: bench_theme_product_page + template: | + {% render 'theme_header', shop: shop %} + {% render 'breadcrumb_nav', crumbs: breadcrumbs %} +
    + {% render 'product_gallery', images: product.images %} + {% render 'product_info', product: product, variants: variants %} + {% render 'variant_selector', variants: variants %} + {% render 'add_to_cart_form', product: product %} + {% render 'product_tabs', product: product %} + {% render 'related_grid', products: related_products, title: 'You may also like' %} + {% render 'recently_viewed', products: recent_products %} +
    + {% render 'theme_footer', shop: shop, links: footer_links %} + filesystem: + theme_header: | + + + + {{ shop.name }} + + + + + main_nav: | + + cart_icon: | +
    + Cart +
    + breadcrumb_nav: | + + product_gallery: | + + product_info: | +
    +

    {{ product.vendor }}

    +

    {{ product.title }}

    +
    + {% if product.compare_at_price > product.price %} + ${{ product.compare_at_price }} + {% endif %} + ${{ product.price }} + {% if product.compare_at_price > product.price %} + {% assign savings = product.compare_at_price | minus: product.price %} + Save ${{ savings }} + {% endif %} +
    +
    {{ product.description }}
    +
    + {% for tag in product.tags %} + {{ tag }} + {% endfor %} +
    +
    + variant_selector: | +
    + + +
    + add_to_cart_form: | +
    + +
    + + +
    + {% if product.available %} + + {% else %} + + {% endif %} +
    + product_tabs: | +
    +
    +

    Features

    +
      + {% for feature in product.features %} +
    • {{ feature }}
    • + {% endfor %} +
    +
    +
    +

    Care Instructions

    +
      + {% for instruction in product.care %} +
    • {{ instruction }}
    • + {% endfor %} +
    +
    +
    + related_grid: | + + product_card: | + + recently_viewed: | +
    +

    Recently Viewed

    +
    + {% for product in products %} + {% render 'product_card', product: product %} + {% endfor %} +
    +
    + theme_footer: | +
    + + +
    + + + environment: + shop: + name: Acme Store + currency: USD + email: support@acme.test + product: + id: 12345 + title: Classic Leather Jacket + vendor: Acme Apparel + type: Outerwear + price: 299.99 + compare_at_price: 399.99 + description: Premium quality genuine leather jacket with satin lining. Features + two front pockets and an interior pocket. + sku: LJ-BLK-M + available: true + tags: + - leather + - jacket + - outerwear + - premium + images: + - src: "/images/jacket-front.jpg" + alt: Front view + - src: "/images/jacket-back.jpg" + alt: Back view + - src: "/images/jacket-detail.jpg" + alt: Detail view + - src: "/images/jacket-pocket.jpg" + alt: Pocket detail + options: + - name: Size + values: + - S + - M + - L + - XL + - name: Color + values: + - Black + - Brown + - Navy + features: + - 100% genuine leather + - Satin lining + - YKK zippers + - Two exterior pockets + - One interior pocket + care: + - Dry clean only + - Store on padded hanger + - Keep away from heat + variants: + - id: 1 + title: S / Black + price: 299.99 + available: true + sku: LJ-BLK-S + - id: 2 + title: M / Black + price: 299.99 + available: true + sku: LJ-BLK-M + - id: 3 + title: L / Black + price: 299.99 + available: false + sku: LJ-BLK-L + - id: 4 + title: XL / Black + price: 299.99 + available: true + sku: LJ-BLK-XL + - id: 5 + title: S / Brown + price: 299.99 + available: true + sku: LJ-BRN-S + - id: 6 + title: M / Brown + price: 299.99 + available: true + sku: LJ-BRN-M + - id: 7 + title: L / Brown + price: 299.99 + available: true + sku: LJ-BRN-L + - id: 8 + title: XL / Brown + price: 299.99 + available: false + sku: LJ-BRN-XL + breadcrumbs: + - title: Home + url: "/" + - title: Apparel + url: "/collections/apparel" + - title: Outerwear + url: "/collections/outerwear" + - title: Classic Leather Jacket + url: + related_products: + - title: Bomber Jacket + price: 249.99 + image: "/images/bomber.jpg" + url: "/products/bomber" + - title: Denim Jacket + price: 149.99 + image: "/images/denim.jpg" + url: "/products/denim" + - title: Suede Jacket + price: 279.99 + image: "/images/suede.jpg" + url: "/products/suede" + - title: Windbreaker + price: 99.99 + image: "/images/wind.jpg" + url: "/products/windbreaker" + recent_products: + - title: Wool Sweater + price: 89.99 + image: "/images/sweater.jpg" + url: "/products/sweater" + - title: Cotton T-Shirt + price: 29.99 + image: "/images/tshirt.jpg" + url: "/products/tshirt" + footer_links: + - title: About + url: "/about" + - title: Contact + url: "/contact" + - title: Shipping + url: "/shipping" + - title: Returns + url: "/returns" + expected: "\n\n\n Acme Store\n \n\n\n
    \n
    Acme Store
    \n \n\n + \
    \n Cart\n
    \n\n
    \n\n\n\n
    \n
    \n \n
    \n \"Front\n
    \n + \ \n
    \n \"Back\n
    \n \n
    \n + \ \"Detail\n + \
    \n \n
    \n \"Pocket\n
    \n \n
    \n + \ \n \n \n \n + \ \n \n \n \n + \ \n
    \n
    \n\n
    \n

    Acme + Apparel

    \n

    Classic Leather Jacket

    \n
    \n + \ \n $399.99\n \n $299.99\n + \ \n \n Save $100.0\n \n
    \n + \
    Premium quality genuine leather jacket with satin + lining. Features two front pockets and an interior pocket.
    \n
    \n + \ \n leather\n \n jacket\n + \ \n outerwear\n \n premium\n + \ \n
    \n
    \n\n
    \n \n \n
    \n\n
    \n \n + \
    \n \n \n
    \n + \ \n \n \n
    \n\n + \
    \n
    \n + \

    Features

    \n
      \n \n
    • 100% genuine leather
    • \n + \ \n
    • Satin lining
    • \n \n
    • YKK zippers
    • \n + \ \n
    • Two exterior pockets
    • \n \n
    • One interior + pocket
    • \n \n
    \n
    \n
    \n + \

    Care Instructions

    \n
      \n \n
    • Dry clean only
    • \n + \ \n
    • Store on padded hanger
    • \n \n
    • Keep away + from heat
    • \n \n
    \n
    \n
    \n\n
    \n + \

    You may also like

    \n \n
    \n\n + \
    \n

    Recently Viewed

    \n
    \n + \ \n \n\n \n \n\n + \ \n
    \n
    \n\n
    \n\n\n\n\n" +- name: bench_theme_cart_page + template: | + {% render 'theme_header', shop: shop %} +
    +

    Shopping Cart

    + {% if cart.items.size > 0 %} + {% render 'cart_table', cart: cart %} + {% render 'cart_totals', cart: cart %} + {% render 'cart_actions' %} + {% render 'shipping_calculator', rates: shipping_rates %} + {% else %} + {% render 'empty_cart' %} + {% endif %} + {% render 'cart_recommendations', products: recommendations %} +
    + {% render 'theme_footer', shop: shop, links: footer_links %} + filesystem: + theme_header: | + + + + {{ shop.name }} - Cart + + + + cart_table: | + + + + + + + + + + + + {% for item in cart.items %} + {% render 'cart_line_item', item: item %} + {% endfor %} + +
    ProductPriceQuantityTotalActions
    + cart_line_item: | + + + {{ item.title }} +
    + {{ item.title }} +

    {{ item.variant_title }}

    +

    SKU: {{ item.sku }}

    + {% if item.properties.size > 0 %} +
    + {% for prop in item.properties %} +

    {{ prop[0] }}: {{ prop[1] }}

    + {% endfor %} +
    + {% endif %} +
    + + ${{ item.price }} + + + + ${{ item.line_price }} + + + + + cart_totals: | +
    +
    + Subtotal ({{ cart.item_count }} items): + ${{ cart.total_price }} +
    + {% if cart.discounts.size > 0 %} +
    + {% for discount in cart.discounts %} +
    + {{ discount.title }} ({{ discount.code }}): + -${{ discount.amount }} +
    + {% endfor %} +
    + {% endif %} + {% assign final_total = cart.total_price %} + {% for discount in cart.discounts %} + {% assign final_total = final_total | minus: discount.amount %} + {% endfor %} +
    + Total: + ${{ final_total }} +
    +
    + cart_actions: | + + shipping_calculator: | +
    +

    Shipping Estimates

    +
      + {% for rate in rates %} +
    • + +
    • + {% endfor %} +
    +
    + empty_cart: | +
    +

    Your cart is empty.

    + Start Shopping +
    + cart_recommendations: | +
    +

    You might also like

    +
    + {% for product in products %} + {% render 'product_card', product: product %} + {% endfor %} +
    +
    + product_card: | + + theme_footer: | +
    + +

    © {{ shop.name }}

    +
    + + + environment: + shop: + name: Acme Store + currency: USD + email: support@acme.test + cart: + item_count: 5 + total_price: 549.95 + items: + - id: 1 + title: Classic Leather Jacket + variant_title: M / Black + price: 299.99 + quantity: 1 + line_price: 299.99 + image: "/images/jacket.jpg" + url: "/products/jacket" + sku: LJ-BLK-M + properties: + gift_wrap: 'Yes' + gift_message: Happy Birthday! + - id: 2 + title: Cotton T-Shirt + variant_title: L / White + price: 29.99 + quantity: 3 + line_price: 89.97 + image: "/images/tshirt.jpg" + url: "/products/tshirt" + sku: TS-WHT-L + properties: {} + - id: 3 + title: Wool Beanie + variant_title: One Size / Navy + price: 24.99 + quantity: 2 + line_price: 49.98 + image: "/images/beanie.jpg" + url: "/products/beanie" + sku: BN-NVY-OS + properties: {} + - id: 4 + title: Leather Belt + variant_title: 34 / Brown + price: 59.99 + quantity: 1 + line_price: 59.99 + image: "/images/belt.jpg" + url: "/products/belt" + sku: BT-BRN-34 + properties: {} + - id: 5 + title: Silk Scarf + variant_title: One Size / Burgundy + price: 49.99 + quantity: 1 + line_price: 49.99 + image: "/images/scarf.jpg" + url: "/products/scarf" + sku: SC-BUR-OS + properties: + monogram: ABC + discounts: + - code: SAVE10 + amount: 54.99 + title: 10% Off + shipping_rates: + - name: Standard Shipping + price: 5.99 + delivery: 5-7 business days + - name: Express Shipping + price: 15.99 + delivery: 2-3 business days + - name: Overnight + price: 29.99 + delivery: Next business day + recommendations: + - title: Leather Gloves + price: 49.99 + image: "/images/gloves.jpg" + url: "/products/gloves" + - title: Wool Socks + price: 19.99 + image: "/images/socks.jpg" + url: "/products/socks" + - title: Sunglasses + price: 79.99 + image: "/images/sunglasses.jpg" + url: "/products/sunglasses" + footer_links: + - title: About + url: "/about" + - title: Contact + url: "/contact" + - title: Shipping + url: "/shipping" + - title: Returns + url: "/returns" + expected: "\n\n\n Acme Store - Cart\n\n\n + \
    \n
    Acme Store
    \n
    \n\n
    \n

    Shopping Cart

    \n \n \n + \ \n \n \n \n \n + \ \n \n \n \n \n + \ \n \n \n \n + \ \n \n \n\n\n \n \n \n \n + \ \n \n \n\n\n \n \n \n + \ \n \n \n + \ \n\n\n \n \n \n \n \n + \ \n \n\n\n \n \n \n \n + \ \n \n \n\n\n \n \n
    ProductPriceQuantityTotalActions
    \n + \ \"Classic\n + \
    \n Classic Leather + Jacket\n

    M / Black

    \n

    SKU: + LJ-BLK-M

    \n \n
    \n \n

    gift_wrap: Yes

    \n \n

    gift_message: Happy Birthday!

    \n \n + \
    \n \n
    \n
    $299.99\n \n + \ $299.99\n \n
    \n \"Cotton\n
    \n Cotton T-Shirt\n

    L / White

    \n + \

    SKU: TS-WHT-L

    \n \n
    \n
    $29.99\n \n + \ $89.97\n \n
    \n \"Wool\n
    \n Wool Beanie\n

    One Size + / Navy

    \n

    SKU: BN-NVY-OS

    \n \n
    \n
    $24.99\n \n $49.98\n \n + \
    \n + \ \"Leather\n + \
    \n Leather Belt\n + \

    34 / Brown

    \n

    SKU: BT-BRN-34

    \n + \ \n
    \n
    $59.99\n + \ \n $59.99\n \n
    \n \"Silk\n
    \n Silk Scarf\n

    One Size / + Burgundy

    \n

    SKU: SC-BUR-OS

    \n \n
    \n \n

    monogram: + ABC

    \n \n
    \n \n
    \n
    $49.99\n \n + \ $49.99\n \n
    \n\n + \
    \n
    \n Subtotal + (5 items):\n $549.95\n
    \n \n
    \n + \ \n
    \n 10% Off (SAVE10):\n + \ -$54.99\n
    \n \n
    \n \n \n \n + \
    \n Total:\n $494.96\n
    \n
    \n\n + \ \n\n
    \n + \

    Shipping Estimates

    \n
      \n \n
    • \n \n
    • \n \n
    • \n + \ \n
    • \n \n
    • \n + \ \n + \
    • \n \n
    \n
    \n\n \n
    \n + \

    You might also like

    \n \n
    \n\n
    \n\n\n\n\n" +- name: bench_theme_collection_page + template: | + {% render 'theme_header', shop: shop %} + {% render 'collection_hero', collection: collection %} +
    + {% render 'filter_sidebar', filters: filters, active_filters: active_filters %} +
    + {% render 'sort_bar', sort_options: sort_options, current_sort: current_sort, product_count: collection.products.size %} + {% render 'product_grid', products: collection.products %} + {% render 'pagination', pages: pagination %} +
    +
    + {% render 'theme_footer', shop: shop, links: footer_links %} + filesystem: + theme_header: | + + + + {{ shop.name }} + + + + collection_hero: | +
    +
    +

    {{ collection.title }}

    +

    {{ collection.description }}

    + {{ collection.products_count }} products +
    +
    + filter_sidebar: | + + sort_bar: | +
    + {{ product_count }} products +
    + + +
    +
    + + +
    +
    + product_grid: | +
    + {% for product in products %} + {% render 'collection_product_card', product: product %} + {% endfor %} +
    + collection_product_card: | + + pagination: | + + theme_footer: | +
    + +

    © {{ shop.name }}

    +
    + + + environment: + shop: + name: Acme Store + currency: USD + email: support@acme.test + collection: + title: Men's Outerwear + description: Premium jackets and coats for every season + image: "/images/outerwear-hero.jpg" + products_count: 48 + products: + - id: 1 + title: Classic Leather Jacket + price: 299.99 + compare_at_price: 399.99 + image: "/images/leather.jpg" + url: "/products/leather-jacket" + vendor: Acme Apparel + available: true + tags: + - leather + - classic + - id: 2 + title: Bomber Jacket + price: 249.99 + compare_at_price: + image: "/images/bomber.jpg" + url: "/products/bomber" + vendor: Acme Apparel + available: true + tags: + - bomber + - casual + - id: 3 + title: Denim Jacket + price: 149.99 + compare_at_price: 179.99 + image: "/images/denim.jpg" + url: "/products/denim-jacket" + vendor: Acme Apparel + available: true + tags: + - denim + - casual + - id: 4 + title: Wool Peacoat + price: 349.99 + compare_at_price: + image: "/images/peacoat.jpg" + url: "/products/peacoat" + vendor: Acme Apparel + available: false + tags: + - wool + - formal + - id: 5 + title: Quilted Vest + price: 129.99 + compare_at_price: + image: "/images/vest.jpg" + url: "/products/vest" + vendor: Acme Apparel + available: true + tags: + - vest + - layering + - id: 6 + title: Windbreaker + price: 99.99 + compare_at_price: 129.99 + image: "/images/windbreaker.jpg" + url: "/products/windbreaker" + vendor: Acme Apparel + available: true + tags: + - light + - athletic + - id: 7 + title: Parka + price: 399.99 + compare_at_price: + image: "/images/parka.jpg" + url: "/products/parka" + vendor: Acme Apparel + available: true + tags: + - winter + - heavy + - id: 8 + title: Suede Jacket + price: 279.99 + compare_at_price: 329.99 + image: "/images/suede.jpg" + url: "/products/suede-jacket" + vendor: Premium Line + available: true + tags: + - suede + - premium + - id: 9 + title: Rain Jacket + price: 149.99 + compare_at_price: + image: "/images/rain.jpg" + url: "/products/rain-jacket" + vendor: Acme Apparel + available: true + tags: + - waterproof + - light + - id: 10 + title: Down Jacket + price: 279.99 + compare_at_price: + image: "/images/down.jpg" + url: "/products/down-jacket" + vendor: Acme Apparel + available: true + tags: + - winter + - warm + - id: 11 + title: Fleece Jacket + price: 89.99 + compare_at_price: + image: "/images/fleece.jpg" + url: "/products/fleece" + vendor: Acme Apparel + available: true + tags: + - fleece + - casual + - id: 12 + title: Blazer + price: 199.99 + compare_at_price: 249.99 + image: "/images/blazer.jpg" + url: "/products/blazer" + vendor: Premium Line + available: true + tags: + - formal + - business + filters: + - name: Price + values: + - label: Under $100 + value: 0-100 + count: 2 + - label: "$100-$200" + value: 100-200 + count: 4 + - label: "$200-$300" + value: 200-300 + count: 4 + - label: Over $300 + value: 300- + count: 2 + - name: Size + values: + - label: S + value: s + count: 10 + - label: M + value: m + count: 12 + - label: L + value: l + count: 11 + - label: XL + value: xl + count: 9 + - name: Color + values: + - label: Black + value: black + count: 6 + - label: Brown + value: brown + count: 4 + - label: Navy + value: navy + count: 3 + - label: Gray + value: gray + count: 2 + - name: Availability + values: + - label: In Stock + value: 'true' + count: 11 + - label: Out of Stock + value: 'false' + count: 1 + active_filters: + - 100-200 + sort_options: + - label: Featured + value: featured + - label: 'Price: Low to High' + value: price-asc + - label: 'Price: High to Low' + value: price-desc + - label: Newest + value: created-desc + - label: Best Selling + value: best-selling + current_sort: featured + pagination: + current: 1 + total: 4 + pages: + - 1 + - 2 + - 3 + - 4 + footer_links: + - title: About + url: "/about" + - title: Contact + url: "/contact" + - title: Shipping + url: "/shipping" + - title: Returns + url: "/returns" + expected: "\n\n\n Acme Store\n\n\n + \
    \n
    Acme Store
    \n
    \n\n
    \n + \
    \n

    Men's Outerwear

    \n

    Premium jackets + and coats for every season

    \n 48 products\n + \
    \n
    \n\n
    \n \n\n
    \n + \
    \n 12 products\n + \
    \n \n \n
    \n
    \n \n + \ \n
    \n
    \n\n
    \n + \ \n \n\n \n \n\n \n \n\n + \ \n \n\n \n \n\n \n \n\n + \ \n \n\n \n \n\n + \ \n \n\n \n \n\n \n \n\n \n \n\n \n
    \n\n \n\n + \
    \n
    \n\n\n\n\n" From 6a6a098877a3fef6af06af7a398134cf1a4a042a Mon Sep 17 00:00:00 2001 From: Max Bernstein Date: Tue, 14 Jul 2026 12:55:15 -0400 Subject: [PATCH 2/5] Do more iterations --- benchmarks/liquid-il/benchmark.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/liquid-il/benchmark.rb b/benchmarks/liquid-il/benchmark.rb index ae15226b..1950efa4 100644 --- a/benchmarks/liquid-il/benchmark.rb +++ b/benchmarks/liquid-il/benchmark.rb @@ -25,7 +25,7 @@ run_benchmark(150) do # Each render is quick; render the whole template set several times per # iteration to reduce time-measurement noise (mirrors liquid-render). - 10.times do + 100.times do CASES.each { |mod, assigns| mod.render(assigns) } end end From 641a5301a7fb0fb533e18eccb75f37cb45f6a040 Mon Sep 17 00:00:00 2001 From: Max Bernstein Date: Tue, 14 Jul 2026 13:00:43 -0400 Subject: [PATCH 3/5] . --- benchmarks/liquid-il/templates.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/benchmarks/liquid-il/templates.yml b/benchmarks/liquid-il/templates.yml index d208df1d..2e654f31 100644 --- a/benchmarks/liquid-il/templates.yml +++ b/benchmarks/liquid-il/templates.yml @@ -1,3 +1,4 @@ +# Extracted and edited from upstream tobi/liquid-il --- specs: - name: bench_simple_product_listing From 6f86718f983fd98deafba2adae7b907a901ee3e5 Mon Sep 17 00:00:00 2001 From: Max Bernstein Date: Tue, 14 Jul 2026 13:17:26 -0400 Subject: [PATCH 4/5] Upgrade bundler --- benchmarks/liquid-il/Gemfile.lock | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/benchmarks/liquid-il/Gemfile.lock b/benchmarks/liquid-il/Gemfile.lock index 8efe0c60..41f742ce 100644 --- a/benchmarks/liquid-il/Gemfile.lock +++ b/benchmarks/liquid-il/Gemfile.lock @@ -23,7 +23,8 @@ DEPENDENCIES CHECKSUMS base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b bigdecimal (4.1.2) sha256=53d217666027eab4280346fba98e7d5b66baaae1b9c3c1c0ffe89d48188a3fbd + bundler (4.0.16) sha256=d6ca5dd440c24f9abce9844cf44cc8e18c6a553de65a47efb4544137af92c47d liquid-il (0.1.0) BUNDLED WITH - 4.0.10 + 4.0.16 From a888944bdbfbfeee48a8f06bf1cc43aeec6ccedf Mon Sep 17 00:00:00 2001 From: Max Bernstein Date: Tue, 14 Jul 2026 20:09:41 -0400 Subject: [PATCH 5/5] Increase iteration count --- benchmarks/liquid-il/benchmark.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/liquid-il/benchmark.rb b/benchmarks/liquid-il/benchmark.rb index 1950efa4..144894ca 100644 --- a/benchmarks/liquid-il/benchmark.rb +++ b/benchmarks/liquid-il/benchmark.rb @@ -25,7 +25,7 @@ run_benchmark(150) do # Each render is quick; render the whole template set several times per # iteration to reduce time-measurement noise (mirrors liquid-render). - 100.times do + 1000.times do CASES.each { |mod, assigns| mod.render(assigns) } end end