SlideShare a Scribd company logo
1 of 49
Parsing and Rewriting
Ruby Templates
Parsing and Rewriting Ruby
Templates
John Hawthorn
@jhawthorn
Rails committer
Ruby Architecture @ GitHub
Ruby Templates
Rails 6.0 - ActionView
• Template de-duplication
• Faster dev-mode
• Faster template resolution
Problem:
Loading templates
at boot
unicorn/puma
Parent
WorkerWorkerWorkerWorkerWorkerWorkerWorkerWorkerWorker
fork()
Lazy loaded views
Parent
Worker
fork()
WorkerWorkerWorkerWorkerWorkerWorkerWorker
viewsviewsviewsviewsviewsviewsviewsviews
Eager loading views
Parent
Worker
fork()
WorkerWorkerWorkerWorkerWorkerWorkerWorker
views
Ruby Templates
Never declared
local or method?
locals hash
Plan
Scan all views for render calls
Parsing render calls
Rails already does this!
Running Ruby
Ruby Process
Running Ruby
Parse Compile Run
Ruby AST
YARV
Bytecode Process
Running Ruby
Parse Compile Run
Ruby AST
YARV
Bytecode
RubyVM::AbstractSyntaxTree (new in Ruby 2.6)
Process
Ruby Parsers
• RubyVM::AbstractSyntaxTree (Ruby 2.6+)
• Ripper
• jruby
• parser (gem)
• ruby_parser (gem)
❤️
Ruby Templating
Ruby
ERB
HAML slim
jbuilder
ERB templates are Ruby
ERB templates are Ruby
Compiled to methods
Template parsing
Ruby ASTERB
ERB
Parsing render calls
FCALL
:render ARRAY
STR
"hello"
Parsing render calls
Parsing render calls
FCALL
:render ARRAY
STR
"hello"
HASH
LIT STR
:name "..."
Parsing render calls
FCALL
:render ARRAY
STR
"hello"
HASH
LIT STR
:name "..."
Parsing render calls
keys must be literals!
Eager loading views
Testing a real application
First request
without precompilation
~100ms
First request
with precompilation
~60ms
Initial request timing
Measured over 100 requests
40% faster!
• 💎 actionview_precompiler
• ✅ It works
• ✅ Any templating language (ERB/HAML/slim)
• ✅ Fast!
• ⚠️ RubyVM::AST is Ruby 2.6+
A different idea...
Local assignment
Can we avoid this?
Local assignment
Local assignment
VCALLLVAR
What if we could rewrite
local variable usage?
(known local)
(unknown if local or method)
Local assignment
A ruby to ruby
transpiler
with dynamic locals
github.com/jhawthorn/dynamic_locals
Rewriting locals: ERB
Rewriting locals: ERB
Rewriting locals: ERB
Rewriting locals: ERB
Rewriting locals!!!
Rewriting locals!!!
Rewriting locals!!!
• 💎 dynamic_locals
• ✅ It works!
• ✅ Passes Rails ActionView test suite 100%
• ⚠️ Slower?
• ⚠️ Errors and warnings might be different
• ⚠️ It's complicated!
¡Gracias!
Thank you

More Related Content

What's hot

Survive JavaScript - Strategies and Tricks
Survive JavaScript - Strategies and TricksSurvive JavaScript - Strategies and Tricks
Survive JavaScript - Strategies and TricksJuho Vepsäläinen
 
Getting Started with Apache Camel at DevNation 2014
Getting Started with Apache Camel at DevNation 2014Getting Started with Apache Camel at DevNation 2014
Getting Started with Apache Camel at DevNation 2014Claus Ibsen
 
Why and how Pricing Assistant migrated from Celery to RQ - Paris.py #2
Why and how Pricing Assistant migrated from Celery to RQ - Paris.py #2Why and how Pricing Assistant migrated from Celery to RQ - Paris.py #2
Why and how Pricing Assistant migrated from Celery to RQ - Paris.py #2Sylvain Zimmer
 
Wellington meetup SilverStripe 4 upgrading presentation (Feb 2017)
Wellington meetup SilverStripe 4 upgrading presentation (Feb 2017)Wellington meetup SilverStripe 4 upgrading presentation (Feb 2017)
Wellington meetup SilverStripe 4 upgrading presentation (Feb 2017)Robbie Averill
 
Developing, Testing and Scaling with Apache Camel - UberConf 2015
Developing, Testing and Scaling with Apache Camel - UberConf 2015Developing, Testing and Scaling with Apache Camel - UberConf 2015
Developing, Testing and Scaling with Apache Camel - UberConf 2015Matt Raible
 
The Many Ways to Test Your React App
The Many Ways to Test Your React AppThe Many Ways to Test Your React App
The Many Ways to Test Your React AppAll Things Open
 
Developer-friendly taskqueues: What you should ask yourself before choosing one
Developer-friendly taskqueues: What you should ask yourself before choosing oneDeveloper-friendly taskqueues: What you should ask yourself before choosing one
Developer-friendly taskqueues: What you should ask yourself before choosing oneSylvain Zimmer
 
Ruby On Rails Presentation
Ruby On Rails PresentationRuby On Rails Presentation
Ruby On Rails PresentationChanHan Hy
 
Avoiding Common Pitfalls in Ember.js
Avoiding Common Pitfalls in Ember.jsAvoiding Common Pitfalls in Ember.js
Avoiding Common Pitfalls in Ember.jsAlex Speller
 
Integration using Apache Camel and Groovy
Integration using Apache Camel and GroovyIntegration using Apache Camel and Groovy
Integration using Apache Camel and GroovyClaus Ibsen
 
Engage 2014 OpenNTF Domino API Slides
Engage 2014 OpenNTF Domino API SlidesEngage 2014 OpenNTF Domino API Slides
Engage 2014 OpenNTF Domino API SlidesPaul Withers
 
Clojure Conj 2014 - Paradigms of core.async - Julian Gamble
Clojure Conj 2014 - Paradigms of core.async - Julian GambleClojure Conj 2014 - Paradigms of core.async - Julian Gamble
Clojure Conj 2014 - Paradigms of core.async - Julian GambleJulian Gamble
 
Camel Day Italy 2021 - What's new in Camel 3
Camel Day Italy 2021 - What's new in Camel 3Camel Day Italy 2021 - What's new in Camel 3
Camel Day Italy 2021 - What's new in Camel 3Claus Ibsen
 
DanNotes 2013: OpenNTF Domino API
DanNotes 2013: OpenNTF Domino APIDanNotes 2013: OpenNTF Domino API
DanNotes 2013: OpenNTF Domino APIPaul Withers
 

What's hot (20)

Survive JavaScript - Strategies and Tricks
Survive JavaScript - Strategies and TricksSurvive JavaScript - Strategies and Tricks
Survive JavaScript - Strategies and Tricks
 
Wider than rails
Wider than railsWider than rails
Wider than rails
 
Getting Started with Apache Camel at DevNation 2014
Getting Started with Apache Camel at DevNation 2014Getting Started with Apache Camel at DevNation 2014
Getting Started with Apache Camel at DevNation 2014
 
Perl in Teh Cloud
Perl in Teh CloudPerl in Teh Cloud
Perl in Teh Cloud
 
Why and how Pricing Assistant migrated from Celery to RQ - Paris.py #2
Why and how Pricing Assistant migrated from Celery to RQ - Paris.py #2Why and how Pricing Assistant migrated from Celery to RQ - Paris.py #2
Why and how Pricing Assistant migrated from Celery to RQ - Paris.py #2
 
Wellington meetup SilverStripe 4 upgrading presentation (Feb 2017)
Wellington meetup SilverStripe 4 upgrading presentation (Feb 2017)Wellington meetup SilverStripe 4 upgrading presentation (Feb 2017)
Wellington meetup SilverStripe 4 upgrading presentation (Feb 2017)
 
Rango
RangoRango
Rango
 
About Clack
About ClackAbout Clack
About Clack
 
Developing, Testing and Scaling with Apache Camel - UberConf 2015
Developing, Testing and Scaling with Apache Camel - UberConf 2015Developing, Testing and Scaling with Apache Camel - UberConf 2015
Developing, Testing and Scaling with Apache Camel - UberConf 2015
 
The Many Ways to Test Your React App
The Many Ways to Test Your React AppThe Many Ways to Test Your React App
The Many Ways to Test Your React App
 
Developer-friendly taskqueues: What you should ask yourself before choosing one
Developer-friendly taskqueues: What you should ask yourself before choosing oneDeveloper-friendly taskqueues: What you should ask yourself before choosing one
Developer-friendly taskqueues: What you should ask yourself before choosing one
 
Ruby On Rails Presentation
Ruby On Rails PresentationRuby On Rails Presentation
Ruby On Rails Presentation
 
Azkaban
AzkabanAzkaban
Azkaban
 
Avoiding Common Pitfalls in Ember.js
Avoiding Common Pitfalls in Ember.jsAvoiding Common Pitfalls in Ember.js
Avoiding Common Pitfalls in Ember.js
 
Integration using Apache Camel and Groovy
Integration using Apache Camel and GroovyIntegration using Apache Camel and Groovy
Integration using Apache Camel and Groovy
 
Engage 2014 OpenNTF Domino API Slides
Engage 2014 OpenNTF Domino API SlidesEngage 2014 OpenNTF Domino API Slides
Engage 2014 OpenNTF Domino API Slides
 
Clojure Conj 2014 - Paradigms of core.async - Julian Gamble
Clojure Conj 2014 - Paradigms of core.async - Julian GambleClojure Conj 2014 - Paradigms of core.async - Julian Gamble
Clojure Conj 2014 - Paradigms of core.async - Julian Gamble
 
Camel Day Italy 2021 - What's new in Camel 3
Camel Day Italy 2021 - What's new in Camel 3Camel Day Italy 2021 - What's new in Camel 3
Camel Day Italy 2021 - What's new in Camel 3
 
Day 8 - jRuby
Day 8 - jRubyDay 8 - jRuby
Day 8 - jRuby
 
DanNotes 2013: OpenNTF Domino API
DanNotes 2013: OpenNTF Domino APIDanNotes 2013: OpenNTF Domino API
DanNotes 2013: OpenNTF Domino API
 

Similar to Parsing and Rewriting Ruby Templates

Gemification for Ruby 2.5/3.0
Gemification for Ruby 2.5/3.0Gemification for Ruby 2.5/3.0
Gemification for Ruby 2.5/3.0Hiroshi SHIBATA
 
Ruby on Rails : 簡介與入門
Ruby on Rails : 簡介與入門Ruby on Rails : 簡介與入門
Ruby on Rails : 簡介與入門Wen-Tien Chang
 
JBoss, Rails and the cloud
JBoss, Rails and the cloudJBoss, Rails and the cloud
JBoss, Rails and the cloudelliando dias
 
Ruby on Rails : First Mile
Ruby on Rails : First MileRuby on Rails : First Mile
Ruby on Rails : First MileGourab Mitra
 
Ruby on Rails survival guide of an aged Java developer
Ruby on Rails survival guide of an aged Java developerRuby on Rails survival guide of an aged Java developer
Ruby on Rails survival guide of an aged Java developergicappa
 
Getting Started with Rails on GlassFish (Hands-on Lab) - Spark IT 2010
Getting Started with Rails on GlassFish (Hands-on Lab) - Spark IT 2010Getting Started with Rails on GlassFish (Hands-on Lab) - Spark IT 2010
Getting Started with Rails on GlassFish (Hands-on Lab) - Spark IT 2010Arun Gupta
 
Ruby on-rails-101-presentation-slides-for-a-five-day-introductory-course-1194...
Ruby on-rails-101-presentation-slides-for-a-five-day-introductory-course-1194...Ruby on-rails-101-presentation-slides-for-a-five-day-introductory-course-1194...
Ruby on-rails-101-presentation-slides-for-a-five-day-introductory-course-1194...Nilesh Panchal
 
Lessons Learnt in 2009
Lessons Learnt in 2009Lessons Learnt in 2009
Lessons Learnt in 2009pratiknaik
 
Практики применения JRuby
Практики применения JRubyПрактики применения JRuby
Практики применения JRuby.toster
 
JRuby - Enterprise 2.0
JRuby - Enterprise 2.0JRuby - Enterprise 2.0
JRuby - Enterprise 2.0Jan Sifra
 
The Enterprise Strikes Back
The Enterprise Strikes BackThe Enterprise Strikes Back
The Enterprise Strikes BackBurke Libbey
 
JRuby - Programmer's Best Friend on JVM
JRuby - Programmer's Best Friend on JVMJRuby - Programmer's Best Friend on JVM
JRuby - Programmer's Best Friend on JVMRaimonds Simanovskis
 
Jaoo Michael Neale 09
Jaoo Michael Neale 09Jaoo Michael Neale 09
Jaoo Michael Neale 09Michael Neale
 
Exploring Ruby on Rails and PostgreSQL
Exploring Ruby on Rails and PostgreSQLExploring Ruby on Rails and PostgreSQL
Exploring Ruby on Rails and PostgreSQLBarry Jones
 
Rails On Spring
Rails On SpringRails On Spring
Rails On Springswamy g
 

Similar to Parsing and Rewriting Ruby Templates (20)

Gemification for Ruby 2.5/3.0
Gemification for Ruby 2.5/3.0Gemification for Ruby 2.5/3.0
Gemification for Ruby 2.5/3.0
 
Ruby on Rails : 簡介與入門
Ruby on Rails : 簡介與入門Ruby on Rails : 簡介與入門
Ruby on Rails : 簡介與入門
 
JBoss, Rails and the cloud
JBoss, Rails and the cloudJBoss, Rails and the cloud
JBoss, Rails and the cloud
 
Ruby on Rails : First Mile
Ruby on Rails : First MileRuby on Rails : First Mile
Ruby on Rails : First Mile
 
Ruby on Rails survival guide of an aged Java developer
Ruby on Rails survival guide of an aged Java developerRuby on Rails survival guide of an aged Java developer
Ruby on Rails survival guide of an aged Java developer
 
Getting Started with Rails on GlassFish (Hands-on Lab) - Spark IT 2010
Getting Started with Rails on GlassFish (Hands-on Lab) - Spark IT 2010Getting Started with Rails on GlassFish (Hands-on Lab) - Spark IT 2010
Getting Started with Rails on GlassFish (Hands-on Lab) - Spark IT 2010
 
How DSL works on Ruby
How DSL works on RubyHow DSL works on Ruby
How DSL works on Ruby
 
Ruby on-rails-101-presentation-slides-for-a-five-day-introductory-course-1194...
Ruby on-rails-101-presentation-slides-for-a-five-day-introductory-course-1194...Ruby on-rails-101-presentation-slides-for-a-five-day-introductory-course-1194...
Ruby on-rails-101-presentation-slides-for-a-five-day-introductory-course-1194...
 
Lessons Learnt in 2009
Lessons Learnt in 2009Lessons Learnt in 2009
Lessons Learnt in 2009
 
Практики применения JRuby
Практики применения JRubyПрактики применения JRuby
Практики применения JRuby
 
Ruby On Rails
Ruby On RailsRuby On Rails
Ruby On Rails
 
JRuby - Enterprise 2.0
JRuby - Enterprise 2.0JRuby - Enterprise 2.0
JRuby - Enterprise 2.0
 
Php resque
Php resquePhp resque
Php resque
 
The Enterprise Strikes Back
The Enterprise Strikes BackThe Enterprise Strikes Back
The Enterprise Strikes Back
 
Ruby on the JVM
Ruby on the JVMRuby on the JVM
Ruby on the JVM
 
Bhavesh ro r
Bhavesh ro rBhavesh ro r
Bhavesh ro r
 
JRuby - Programmer's Best Friend on JVM
JRuby - Programmer's Best Friend on JVMJRuby - Programmer's Best Friend on JVM
JRuby - Programmer's Best Friend on JVM
 
Jaoo Michael Neale 09
Jaoo Michael Neale 09Jaoo Michael Neale 09
Jaoo Michael Neale 09
 
Exploring Ruby on Rails and PostgreSQL
Exploring Ruby on Rails and PostgreSQLExploring Ruby on Rails and PostgreSQL
Exploring Ruby on Rails and PostgreSQL
 
Rails On Spring
Rails On SpringRails On Spring
Rails On Spring
 

Recently uploaded

(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyFrank van der Linden
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfPower Karaoke
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWave PLM
 
cybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningcybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningVitsRangannavar
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...aditisharan08
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
XpertSolvers: Your Partner in Building Innovative Software Solutions
XpertSolvers: Your Partner in Building Innovative Software SolutionsXpertSolvers: Your Partner in Building Innovative Software Solutions
XpertSolvers: Your Partner in Building Innovative Software SolutionsMehedi Hasan Shohan
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataBradBedford3
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptkotipi9215
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 

Recently uploaded (20)

(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The Ugly
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdf
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need It
 
cybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningcybersecurity notes for mca students for learning
cybersecurity notes for mca students for learning
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
XpertSolvers: Your Partner in Building Innovative Software Solutions
XpertSolvers: Your Partner in Building Innovative Software SolutionsXpertSolvers: Your Partner in Building Innovative Software Solutions
XpertSolvers: Your Partner in Building Innovative Software Solutions
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.ppt
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 

Parsing and Rewriting Ruby Templates

Editor's Notes

  1. Hi I'm John Hawthorn. I'm a Rails committer and I work on the Ruby Architecture team at GitHub.
  2. This talk is about Ruby templates. Here is an example. We have a file named "_hello.html.erb", with the contents Buenos dias, and then we an ERB tag with with ruby code inside, which will interpolate a name. We have another file named "home.html.erb". This renders the original file Most of the techniques in this talk would apply to all Ruby code, but I'm interested in templates.
  3. Among the many improvements in Rails 6.0 were several performance optimizations in ActionView. We now allocate fewer template objects, templates in development mode should now be as fast as production, and template resolution (which is how we map template names to files) is now much faster.
  4. Another performance improvement we've wanted to be able to make for a long time is being able to load the templates at boot. So why do we want this...
  5. Unicorn, puma, and similar web servers for MRI Ruby, spawn workers using forking. After fully loading the application they make a fork: a full copy of the process. This is relatively fast, we only need to load the application once, and usually the workers can share most of the memory from the parent process. This also means we want to boot the application fully and load as much as possible in the parent process.
  6. With the current system where we lazy load views, we have to load them once for each worker. We end up repeating work, and worst of all that work is done while a user is waiting for a response.
  7. If we could instead load views in the parent we wouldn't need to repeat work in the worker and we could use less memory. In general, for production, we always want to load as much as possible in the parent process. This way we do no extra work, use no extra memory, and avoid wasting time when serving user requests. So why has it been hard for us to introduce this change...
  8. The big challenge we've always had is when looking at this template, we don't know if "name" is a local variable passed in, or a method. Unlike a normal ruby method, name is never declared. It's actually pretty unusual to reference a variable which is never declared, you can't write a method that works this way. We only know what locals are defined when we look at the keys of the hash passed to render.
  9. I want to share two ways I've tried to solve this. The first is to scan all views, to find all the render calls, and to find what keys the view is being passed for locals.
  10. I was surprised to learn that Rails already does this! Kind of. We have a feature called "Russian Doll Caching" which invalidates cache keys when a template's content changes. To do this it has a dependency tracker which determines which other templates a view might render. Unfortunately it does it with this very large regular expression. Regular expressions aren't great for parsing code, it does work well for caching, but for our needs it isn't able to parse out the locals hash, and I think it would be too challenging to do so. We need a different solution.
  11. When we run Ruby we normally only interact with it as a file, like we would with our text editor, or a process as we would with a console session or running web server.
  12. To run code Ruby actually goes through a series of steps, which are usually hidden from us.
  13. When we run Ruby code we're actually going through a series of steps, which are usually hidden from us. Most of the time when writing ruby we're only looking at the first and last of these steps. The first is where I open my editor and the last is where I have pry.
  14. We don't want to run this code. We're probably not able to.
  15. This isn't the first time we've had a parser available in Ruby and it's not the only option. I've tried all of these and they're all good. I really like the Ruby 2.6 parser because it's built-in, and we can expect it to keep up with any new ruby syntaxes. One problem is that it's only in Ruby 2.6+ and it's marked experimental.
  16. It's likely you already use some sort of static analysis, like RuboCop in your projects.
  17. What we get from the parser is an abstract syntax tree.
  18. So we know we can parse ruby, what about templates? There are many templating languages and they all compile into ruby. Let's take a look
  19. Ruby templates _are_ ruby. This is most apparent when looking at a template language like jbuilder
  20. When you use jbuilder inside Rails, the template handler really just takes the template and adds one line of setup, and one line at the end to make sure we return the output.
  21. To "compile" jbuilder, we add a little bit of code around the handler to initialize the json local variable, and to get the output at the end of the template.
  22. ERB templates are ruby code. I think we recognize that from looking at them that they have ruby in them, but when we run them Rails will first turn them into Ruby.
  23. ERB templates are ruby code. I think we recognize that from looking at them that they have ruby in them, but when we run them Rails will first turn them into Ruby. We can do this manually with ERB.new(src).src, this is essentially what Rails action_view will do internally. It's not pretty ruby, but it is plain Ruby.
  24. And this is what it would look like as Rails finally renders the template. It's compiled into a method and this is what Rails will call. The local variable name is assigned here, we need to compile a different method depending on while locals are passed in.
  25. So our plan is to take our template language, compile it into ruby, and then parse it into an AST. Because we can compile ERB to ruby and then parse that, we should be able to use any static analysis tool with ruby views. The Brakeman security scanner does this already, and there are tools which will let you use rubocop this way. We're still looking for render calls. Let's try it out...
  26. ...
  27. Let's look at just that render call to keep it simple. We have our source code as a string. We pass it to the parser, and we get this node object out. This object is a lisp-like definition, so I can be helpful to look at it as a tree.
  28. To parse the render we need to check every aspect of the call. We check that it's a function, that the function name is render, that it has arguments, and that the first argument is a string. Then after that we can get the name of the template we're rendering. Around here I gain more appreciation for the large regular expression solution. This is kind of like writing a method_missing, but a little more detailed. This code isn't hard, it's just tedious. I find it necessary to write a lot of tests.
  29. So we can parse the basic render call, same as the regex did, now we need to pick up on the keys of the hash.
  30. So we can parse the basic render call, same as the regex did, now we need to pick up on the keys of the hash.
  31. We need to make sure the keys are literals: either strings or symbols. If they're dynamic or use a variable we just have to skip this render. That's fine. Ruby is a very dynamic language, any time we are doing static analysis we need to accept that it might not work.
  32. This technique is now a gem: actionview_precompiler. If we ran it on the example we'd been using it it does find the render of hello with name. For the top level "home" template it assumes it gets rendered with no arguments.
  33. That's great for our small example. I wanted to verify this technique on a Real application. I used exercism.io, a very cool code practice tool. It's a real application with a few hundred views.
  34. This is the tree of all the views in exercism and how they render each other.
  35. To test this I booted the web server and then measured the very first request it served. This is without precompilation. This is a flamegraph which shows where the application spent time in the first request. The horizontal x axis is time. I've highlighted where the view compilation occurs. There are 8 views which are compiled and rendered in this request.
  36. The only modification made to exercism.io is to add one initializer, which runs Actionview::Precompiler on boot.
  37. And this is with eager loaded views. It was able to eager load all but one template render, which was inside a helper.
  38. Profiling isn't benchmarking, so I re-ran the test 100 times with and without precompilation and found again that we are went from an average 100ms to 60ms.
  39. So this worked great. I'm hoping someday soon we can add this to Rails, and we can give every Rails app this benefit. For today it's a gem actionview_precompiler, it's available on my github.
  40. So we've seen the benefits from parsing. We can analyze code and use those results at runtime. We can do more by actually rewriting the code we've parsed.
  41. Both of the existing popular parsing gems allow modifying the AST and then have a matching library to allow converting it back to ruby.
  42. Unfortunately the new ruby parser doesn't support converting back to Ruby. Existing tools had ruby2ruby and unparser.
  43. Each node comes with a start and end line and column.
  44. So that's I think the the good solution, from what I learned implementing that I also came up with a strange solution.
  45. I learned a lot about parsing from the previous work and began to wonder if there was another solution. The fundamental problem seemed to be that we needed to compile assignment of the keys passed in as locals.
  46. It would be nice if there was another way to do this, but we can't do it dynamically. You can try with eval or binding.local_variable_set, it won't work.
  47. The reason we can't do this is that name is compiled differently depending on if there has been an assignment before or not. This is done at parse time. If we know it's a local it gets compiled to LVAR otherwise it gets compiled to VCALL. I think VCALL means variable call but I'm not sure.
  48. If we can parse this code, maybe we can parse the code and then rewrite it so that it does support dynamically assigning locals.
  49. We can tell these are parsed differently because
  50. I think VCALL means variable-call.
  51. Here's the idea: ... Every time we assign to a local variable, we can instead write to a locals hash. Every time we read from a local, we can read from a locals hash. No big change here. Here's the big one, we can change those ambiguous calls or variables accesses to check if the key is in the hash and otherwise call the method.
  52. What this is is a ruby-to-ruby transpiler with dynamic locals
  53. We take our original source code.
  54. Compile the ERB into plain Ruby.
  55. Then we can run dynamic locals translate to convert it to use the locals hash.
  56. And finally we can put it inside our method. We don't need to know what locals this template is rendered with. There are a few problems with this...
  57. The defined keyword can be used to check if something is a local or not. If we didn't change it it would no longer work. We can use the same trick as before, return "local-variable" if it's in our fake locals hash, otherwise we can call the original.
  58. binding has a similar problem. If a user calls binding.pry they probably want their locals to be available. Any time we see `binding`, we can add our dynamic variables onto it and then start pry on that.
  59. Somehow this actually works, and it passes Rails' test suite 100%. I don't think that means this is going to production or should ship with rails. It's still very strange and probably has some issues, but I found this a very fun experiment. These techniques don't have to be about views. I hope this might make you think of some interesting ways you might use parsing or static analysis to find ways to use Ruby in completely new ways.