Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Liquid Markup
Search
Jon Daniel
October 04, 2012
Programming
210
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Liquid Markup
Talk I gave October 4, 2012 at Pittsburgh Ruby Brigade.
Jon Daniel
October 04, 2012
More Decks by Jon Daniel
See All by Jon Daniel
Growth and Mentorship: Working with Junior Developers
binarycleric
0
100
Smart Software Design (SOA Edition)
binarycleric
0
170
Ethical and Sustainable On-Call
binarycleric
6
18k
Other Decks in Programming
See All in Programming
iOSDC Japan 2026 - Swiftで作って学ぼう!データベース自作入門
kaseken
2
170
更なる可用性を求めて、5年間運用したKotlinのアプリケーションをGoでリプレイスする話
ken_tunc
0
290
GraphRAGのKnowledge Graphを 直接!見る/View-GraphRAG's-KnowledgeGraph-directly!
tyumugi1113
1
340
アクセシビリティから考える情報設計
high_g_engineer
0
380
Kiroで創り、AgentCoreで繋ぐ!AWSで実践する「AI-DLC」から「AIエージェント統合」までの最新地図
licux
4
700
XP祭りでしか伝わらないフリップネタ #xpjug
murabayashi
0
150
速習iPhone Duo対応
yuukiw00w
1
620
市販E-Readerを乗っ取れ 〜Embedded Swiftで電子ペーパーガジェットを制御する〜
trickart
0
190
AI × TiDD / 2026.09.05 Redmine 大阪
tokudiro
1
170
動作中のプログラムの中身をリアルタイムに覗く / Realtime Debugger for CSharp with Roslyn
prota
1
450
[GoCon2026] When Goroutines Are Not Enough: Runtime Locality in High-Throughput Go
takehaya
6
2.3k
Webの地図
yosuke_furukawa
PRO
6
4.6k
Featured
See All Featured
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
370
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
3.1k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.6k
The SEO Collaboration Effect
kristinabergwall1
1
570
Optimising Largest Contentful Paint
csswizardry
37
4k
Keith and Marios Guide to Fast Websites
keithpitt
413
23k
Code Review Best Practice
trishagee
74
20k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
580
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
430
Navigating Weather and Climate Data
rabernat
0
520
Into the Great Unknown - MozCon
thekraken
41
2.7k
Claude Code のすすめ
schroneko
67
230k
Transcript
Liquid Markup
Jon Daniel @binarycleric github.com/binarycleric
Obligatory Promotion We’re Hiring Smart People. Ruby experience NOT required.
What Is Liquid?
None
github.com/Shopify/liquid
lets clients design their own sites...
safely and securely
logic and variable manipulation
None
yay!
None
$ gem install liquid require 'liquid'
markup = "Hello, {{ thing }}!" t = Liquid::Template.parse(markup) t.render("thing"
=> "world")
Hello, world!
markup = "Welcome, {{ user.name }}" user = User.find(1337) t
= Liquid::Template.parse(markup) t.render('user' => user)
Welcome, !
Liquid Has Trust Issues
Deny By Default
class Person < ActiveRecord::Base end # denied! "{{ person.name }}"
=> "" class Person < ActiveRecord::Base liquid_methods :name end # okay! "{{ person.name }}" => "Cmdr Shepard"
markup = "Welcome, {{ user.name }}" user = User.find(1337) t
= Liquid::Template.parse(markup) t.render('user' => user)
Welcome, Jon ‘maddog’ Hall! * If you don’t know who
he is, check Wikipedia.
Live Free Or Die.
Actually Rendering Templates
# load the user from somewhere. t = Liquid::Template.parse(markup) t.render("user"
=> user)
t = Liquid::Template.parse(markup) context = Liquid::Context.new(*args) t.render(context)
The Magic Context
Liquid::Context.new local_assigns, global_assigns, registers
Liquid::Context.new local_assigns, global_assigns, registers
registers[:domain] = domain registers[:whatever] = whatever registers[:your] = your registers[:app]
= app registers[:needs] = needs registers[:file_system] = FileSystem.new
registers[:domain] = domain registers[:whatever] = whatever registers[:your] = your registers[:app]
= app registers[:needs] = needs registers[:file_system] = FileSystem.new
Some Liquid Syntax
class FileSystem def initialize(*args) # whatever end def read_template_file(name, context)
# fetches partials from wherever end end {% include 'some-partial' %}
# a block {% if liquid == 'awesome' %} You
should try Liquid! {% endif %} # a tag {% assign liquid = 'awesome' %}
class ExampleTag < Liquid::Tag def initialize(name, markup, tokens) # setup
the tag, parse stuff, ya know... # expensive stuff. end def render(context) # drop in the assigns and go! # should be cheap. end end
class ExampleTag < Liquid::Tag def initialize(name, markup, tokens) # setup
the tag, parse stuff, ya know... # expensive stuff. end def render(context) # drop in the assigns and go! # should be cheap. end end
class PersonDrop < Liquid::Drop def addresses # stupid slow operation
Address::find_by_person(@person) end end {{ user.addresses }}
{{ “hello world” | capitalize }} # shamelessly stolen from
# liquid's source. use your # imagination people! def capitalize(input) input.to_s.capitalize end
Liquid Philosophies
•assume hostile environment •white list what you need •deny everything
else
•can edit markup •is probably non-technical Assume the client
•ignore errors by default •don’t let the client break too
much
It May Not Be For You
•partial branding •full white-label •per-install customization
Views As Data
Contribute!
Questions?