SlideShare a Scribd company logo
1 of 34
Download to read offline
WEWLJCIO - WORKING
EFFECTIVELY WITH LEGACY
JAVASCRIPT CODE IN OPAL
FORREST CHANG
FKCHANG2000@YAHOO.COM
BACKGOUND - OPAL-HOT-RELOADER
Hot reloader for
Hot loaded code
I merged a pull request that added hot css reloading
Opal
THE NEW CODE
Worked
But in Javascript
No tests
:(
Want to extend code
Want it to be easier to maintain
REAL LIFE REFACTORING
Real life better than canned examples
Need tests
Want to be in Ruby/Opal
BY MICHAEL
FEATHERS
WORKING EFFECTIVELY WITH LEGACY CODE
Similar situation
"Legacy code" == code w/o tests
How to put tests on something w/o tests
But also a little different
Want to convert languages
Subject to the predefined browser API and a particular way of
interacting with it
THE SUBMITTED CODE
Added a new if clause to OpalHotReloader#reload() to handle
CSS hot reloading
Implemented in Javascript via Opal x-string.
ORIGINAL RELOAD() METHOD
def reload(e)
# original code
reload_request = JSON.parse(`e.data`)
if reload_request[:type] == "ruby"
puts "Reloading ruby #{reload_request[:filename]}"
eval reload_request[:source_code]
if @reload_post_callback
@reload_post_callback.call
else
puts "not reloading code"
end
end
ADDED IF CODE TO RELOAD() METHOD
# the new css hot reloading code
if reload_request[:type] == "css"
url = reload_request[:url]
puts "Reloading CSS: #{url}"
# Work outsources Javascript via x-string
%x{
var toAppend = "t_hot_reload=" + (new Date()).getTime();
var links = document.getElementsByTagName("link");
for (var i = 0; i < links.length; i++) {
var link = links[i];
if (link.rel === "stylesheet" && link.href.indexOf(#{url}) >= 0) {
if (link.href.indexOf("?") === -1) {
link.href += "?" + toAppend;
} else {
if (link.href.indexOf("t_hot_reload") === -1) {
link.href += "&" + toAppend;
} else {
link.href = link.href.replace(/t_hot_reload=d{13}/, toAppend)
}
}
}
}
}
end
end
OBSERVATIONS
reload() used to be small
Now 3x the size
Has an additional responsiblity
REFACTORING
Extract Method to handle new responsibilty
Extract class to hold that responsibilty (SRP)
Delegate to instance new class
New instance @css_reloader to be created in initialize method
REFACTORED RELOAD()
def reload(e)
reload_request = JSON.parse(`e.data`)
if reload_request[:type] == "ruby"
puts "Reloading ruby #{reload_request[:filename]}"
eval reload_request[:source_code]
if @reload_post_callback
@reload_post_callback.call
else
puts "not reloading code"
end
end
if reload_request[:type] == "css"
@css_reloader.reload(reload_request) # extracted method called here
end
end
THE NEW CSSRELOADER CLASS
class OpalHotReloader
class CssReloader
def reload(reload_request)
url = reload_request[:url]
%x{
var toAppend = "t_hot_reload=" + (new Date()).getTime();
var links = document.getElementsByTagName("link");
for (var i = 0; i < links.length; i++) {
var link = links[i];
if (link.rel === "stylesheet" && link.href.indexOf(#{url}) >= 0) {
if (link.href.indexOf("?") === -1) {
link.href += "?" + toAppend;
} else {
if (link.href.indexOf("t_hot_reload") === -1) {
link.href += "&" + toAppend;
} else {
link.href = link.href.replace(/t_hot_reload=d{13}/, toAppend)
}
}
}
}
}
end
end
end
TESTING THE SOLUTION
No automated tests yet.
Test manually
PITA
New code works!
WRITING AUTOMATED TESTS
Refactored works, we can now add automated tests
Using - minitest also available for those who don't like rspecopal-rspec
A PROBLEM
Technique to update css involves manipulating style links in the global
document object
Could
Create links in the actual DOM of the spec runner (not hard)
But don't like the non transparency of this
Don't like code that calls out directly to global document
Would be nice to be able to inject a test document
DEPENDENCY INJECTION
Desired outcome: Inject test doc for test, inject the real document for
application
Don't need standard dependency injection methods (constructor, setter,
interface)
Able to just pass document as a parameter
MORE ISSUES FOR DOCUMENT TEST DOUBLE
Limited options for hot reloading of CSS - have to do it a certain way
document interface not under my control - must match it
Stubbing Javascript objects in Opal
Opal/JS interface a problem here - Opal objects different
Opal-rspec has powerful mock/stub capability, but only Opal objects
Need to create own method
2 CONVENIENCE METHODS
Creates javascript objects directly via x-strings
create_link() to create the link DOM object that will get altered to
facillitate the css hot reloading and
fake_links_document() a convenience method which returns both a
test double for global document object, which responds to the
getElementsByTagName('link') call and a test double for the link
itself, that I will inspect to see whether it has been correctly altered.
CODE
def create_link( href)
%x|
var ss = document.createElement("link");
ss.type = "text/css";
ss.rel = "stylesheet";
ss.href = #{href};
return ss;
|
end
def fake_links_document(href)
link = create_link(href)
doc = `{ getElementsByTagName: function(name) { links = [ #{link}]; return links;}}`
{ link: link, document: doc}
end
ADD DOCUMENT TO RELOAD() SIGNATURE
# change from
def reload(reload_request)
# to
def reload(reload_request, document)
CALL WITH THE NEW SIGNATURE
# in OpalHotReloader#reload()
# instead of calling it this way
@css_reloader.reload(reload_request)
# we pass in the real browser document
@css_reloader.reload(reload_request, `document`)
MODIFY CSSRELOADER TO TAKE
DOCUMENT
class OpalHotReloader
class CssReloader
def reload(reload_request, document) # pass in the "document"
url = reload_request[:url]
%x{
var toAppend = "t_hot_reload=" + (new Date()).getTime();
// invoke it here
var links = #{document}.getElementsByTagName("link");
for (var i = 0; i < links.length; i++) {
var link = links[i];
if (link.rel === "stylesheet" && link.href.indexOf(#{url}) >= 0) {
if (link.href.indexOf("?") === -1) {
link.href += "?" + toAppend;
} else {
if (link.href.indexOf("t_hot_reload") === -1) {
link.href += "&" + toAppend;
} else {
link.href = link.href.replace(/t_hot_reload=d{13}/, toAppend)
}
}
}
}
}
end
end
end
TESTING SIGNATURE CHANGE
Must hand test again
Works!
REQUIRED TEST CASES
A plain stylesheet link where we add the hot reload argument for the first
time.
Updating a link that has already been updated with a hot reload argument.
Appending an additional hot reload argument parameter to a stylesheet
link that already has a parameter.
WRITING SPECS FOR THESE CASES
require 'native'
require 'opal_hot_reloader'
require 'opal_hot_reloader/css_reloader'
describe OpalHotReloader::CssReloader do
def create_link( href)
%x|
var ss = document.createElement("link");
ss.type = "text/css";
ss.rel = "stylesheet";
ss.href = #{href};
return ss;
|
end
def fake_links_document(href)
link = create_link(href)
doc = `{ getElementsByTagName: function(name) { links = [ #{link}]; return links;}}`
{ link: link, document: doc}
end
context 'Rack::Sass::Plugin' do
it 'should add t_hot_reload to a css path' do
css_path = 'stylesheets/base.css'
doubles = fake_links_document(css_path)
link = Native(doubles[:link])
expect(link[:href]).to match /#{Regexp.escape(css_path)}$/
subject.reload({ url: css_path}, doubles[:document])
expect(link[:href]).to match /#{Regexp.escape(css_path)}?t_hot_reload=d+/
end
PAGE 2
it 'should update t_hot_reload argument if there is one already' do
css_path = 'stylesheets/base.css?t_hot_reload=1111111111111'
doubles = fake_links_document(css_path)
link = Native(doubles[:link])
expect(link[:href]).to match /#{Regexp.escape(css_path)}$/
subject.reload({ url: css_path}, doubles[:document])
expect(link[:href]).to match /#{Regexp.escape('stylesheets/base.css?t_hot_reload=')
}(d)+/
expect($1).to_not eq '1111111111111'
end
it 'should append t_hot_reload if there are existing arguments' do
css_path = 'stylesheets/base.css?some-arg=1'
doubles = fake_links_document(css_path)
link = Native(doubles[:link])
expect(link[:href]).to match /#{Regexp.escape(css_path)}$/
subject.reload({ url: css_path}, doubles[:document])
expect(link[:href]).to match /#{Regexp.escape(css_path)}&t_hot_reload=(d)+/
end
end
end
SPECS PASS - SAFE TO REFACTOR
Added automated test coverage for the 3 cases
Now safe to rewrite the reload() method in Ruby/Opal
Spec provide safety net to prove we don't break the desired functionality
A trick - have reload() delegate to reload_ruby() reload_js() to
have both code side by side - handy for development and debugging
THE TRICK
require 'native'
class OpalHotReloader
class CssReloader
def reload(reload_request, document)
# currently using the Ruby version
reload_ruby(reload_request, document)
# reload_js(reload_request, document)
end
def reload_ruby(reload_request, document)
url = reload_request[:url]
puts "Reloading CSS: #{url}"
to_append = "t_hot_reload=#{Time.now.to_i}"
links = Native(`document.getElementsByTagName("link")`)
(0..links.length-1).each { |i|
link = links[i]
if link.rel == 'stylesheet' && link.href.index(url)
if link.href !~ /?/
link.href += "?#{to_append}"
else
if link.href !~ /t_hot_reload/
link.href += "&#{to_append}"
else
link.href = link.href.sub(/t_hot_reload=d{13}/, to_append)
end
end
end
}
end
PAGE 2
def reload_js(reload_request, document)
url = reload_request[:url]
%x{
var toAppend = "t_hot_reload=" + (new Date()).getTime();
var links = #{document}.getElementsByTagName("link");
for (var i = 0; i < links.length; i++) {
var link = links[i];
if (link.rel === "stylesheet" && link.href.indexOf(#{url}) >= 0) {
if (link.href.indexOf("?") === -1) {
link.href += "?" + toAppend;
} else {
if (link.href.indexOf("t_hot_reload") === -1) {
link.href += "&" + toAppend;
} else {
link.href = link.href.replace(/t_hot_reload=d{13}/, toAppend)
}
}
}
}
}
end
end
end
IMPLEMENTATION
Ruby version - a line by line translation
Specs passed
Can remove Javascript version
OPAL ONLY CSSRELOADER
require 'native'
class OpalHotReloader
class CssReloader
def reload(reload_request, document)
url = reload_request[:url]
puts "Reloading CSS: #{url}"
to_append = "t_hot_reload=#{Time.now.to_i}"
links = Native(`document.getElementsByTagName("link")`)
(0..links.length-1).each { |i|
link = links[i]
if link.rel == 'stylesheet' && link.href.index(url)
if link.href !~ /?/
link.href += "?#{to_append}"
else
if link.href !~ /t_hot_reload/
link.href += "&#{to_append}"
else
link.href = link.href.sub(/t_hot_reload=d{13}/, to_append)
end
end
end
}
end
end
end
ONWARD
Now have specs
Converted code to Ruby
Much easier to implment hot reloading of Rails CSS/SASS
Already did it, it was easy, used TDD for that
LINKS TO BLOG POST
Blogger - code syntax highlighted
Medium - prettier but no syntax highlighting
http://funkworks.blogspot.com/2016/06/wewljcio-working-effectively-
with.html
https://medium.com/@fkchang2000/wewljcio-working-effectively-with-
legacy-javascript-code-in-opal-4fd624693de4
FIN
Questions?

More Related Content

What's hot

Introduction to Angular js
Introduction to Angular jsIntroduction to Angular js
Introduction to Angular jsMustafa Gamal
 
JavaScript Testing for Rubyists
JavaScript Testing for RubyistsJavaScript Testing for Rubyists
JavaScript Testing for RubyistsJamie Dyer
 
Going Beyond LAMP Again - Manchester WordPress User Group
Going Beyond LAMP Again - Manchester WordPress User GroupGoing Beyond LAMP Again - Manchester WordPress User Group
Going Beyond LAMP Again - Manchester WordPress User GroupTim Nash
 
How to perform debounce in react
How to perform debounce in reactHow to perform debounce in react
How to perform debounce in reactBOSC Tech Labs
 
Hidden Treasures in Project Wonder
Hidden Treasures in Project WonderHidden Treasures in Project Wonder
Hidden Treasures in Project WonderWO Community
 
Operacion Guinda 2
Operacion Guinda 2Operacion Guinda 2
Operacion Guinda 2Red RADAR
 
Demo how to create visualforce and apex controller to update, delete custom o...
Demo how to create visualforce and apex controller to update, delete custom o...Demo how to create visualforce and apex controller to update, delete custom o...
Demo how to create visualforce and apex controller to update, delete custom o...tuan vo
 
Python and EM CLI: The Enterprise Management Super Tools
Python and EM CLI: The Enterprise Management Super ToolsPython and EM CLI: The Enterprise Management Super Tools
Python and EM CLI: The Enterprise Management Super ToolsSeth Miller
 
Merrill's Journey to CI-CD and Continuous Testing by Ashish Mukherjee
Merrill's Journey to CI-CD and Continuous Testing by Ashish MukherjeeMerrill's Journey to CI-CD and Continuous Testing by Ashish Mukherjee
Merrill's Journey to CI-CD and Continuous Testing by Ashish MukherjeeSauce Labs
 
Adapters db-104-informixstoredprocedure
Adapters db-104-informixstoredprocedureAdapters db-104-informixstoredprocedure
Adapters db-104-informixstoredprocedureprathap kumar
 
Cis407 a ilab 5 web application development devry university
Cis407 a ilab 5 web application development devry universityCis407 a ilab 5 web application development devry university
Cis407 a ilab 5 web application development devry universitylhkslkdh89009
 
4 introduction-php-mvc-cakephp-m4-controllers-slides
4 introduction-php-mvc-cakephp-m4-controllers-slides4 introduction-php-mvc-cakephp-m4-controllers-slides
4 introduction-php-mvc-cakephp-m4-controllers-slidesMasterCode.vn
 
Introduction to windows power shell in sharepoint 2010
Introduction to windows power shell in sharepoint 2010Introduction to windows power shell in sharepoint 2010
Introduction to windows power shell in sharepoint 2010Binh Nguyen
 
Build Lightweight Web Module
Build Lightweight Web ModuleBuild Lightweight Web Module
Build Lightweight Web ModuleMorgan Cheng
 
Knowledge is Power: Getting out of trouble by understanding Git - Steve Smith...
Knowledge is Power: Getting out of trouble by understanding Git - Steve Smith...Knowledge is Power: Getting out of trouble by understanding Git - Steve Smith...
Knowledge is Power: Getting out of trouble by understanding Git - Steve Smith...Codemotion
 
Me and my importers
Me and my importersMe and my importers
Me and my importersDonny Wals
 
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014Hardcore URL Routing for WordPress - WordCamp Atlanta 2014
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014Mike Schinkel
 
Node.js: scalability tips - Azure Dev Community Vijayawada
Node.js: scalability tips - Azure Dev Community VijayawadaNode.js: scalability tips - Azure Dev Community Vijayawada
Node.js: scalability tips - Azure Dev Community VijayawadaLuciano Mammino
 
PowerShell Tips & Tricks for Exchange
PowerShell Tips & Tricks for ExchangePowerShell Tips & Tricks for Exchange
PowerShell Tips & Tricks for ExchangeMichel de Rooij
 

What's hot (20)

Introduction to Angular js
Introduction to Angular jsIntroduction to Angular js
Introduction to Angular js
 
JavaScript Testing for Rubyists
JavaScript Testing for RubyistsJavaScript Testing for Rubyists
JavaScript Testing for Rubyists
 
Going Beyond LAMP Again - Manchester WordPress User Group
Going Beyond LAMP Again - Manchester WordPress User GroupGoing Beyond LAMP Again - Manchester WordPress User Group
Going Beyond LAMP Again - Manchester WordPress User Group
 
How to perform debounce in react
How to perform debounce in reactHow to perform debounce in react
How to perform debounce in react
 
Hidden Treasures in Project Wonder
Hidden Treasures in Project WonderHidden Treasures in Project Wonder
Hidden Treasures in Project Wonder
 
Operacion Guinda 2
Operacion Guinda 2Operacion Guinda 2
Operacion Guinda 2
 
Demo how to create visualforce and apex controller to update, delete custom o...
Demo how to create visualforce and apex controller to update, delete custom o...Demo how to create visualforce and apex controller to update, delete custom o...
Demo how to create visualforce and apex controller to update, delete custom o...
 
Python and EM CLI: The Enterprise Management Super Tools
Python and EM CLI: The Enterprise Management Super ToolsPython and EM CLI: The Enterprise Management Super Tools
Python and EM CLI: The Enterprise Management Super Tools
 
Merrill's Journey to CI-CD and Continuous Testing by Ashish Mukherjee
Merrill's Journey to CI-CD and Continuous Testing by Ashish MukherjeeMerrill's Journey to CI-CD and Continuous Testing by Ashish Mukherjee
Merrill's Journey to CI-CD and Continuous Testing by Ashish Mukherjee
 
Adapters db-104-informixstoredprocedure
Adapters db-104-informixstoredprocedureAdapters db-104-informixstoredprocedure
Adapters db-104-informixstoredprocedure
 
Cis407 a ilab 5 web application development devry university
Cis407 a ilab 5 web application development devry universityCis407 a ilab 5 web application development devry university
Cis407 a ilab 5 web application development devry university
 
4 introduction-php-mvc-cakephp-m4-controllers-slides
4 introduction-php-mvc-cakephp-m4-controllers-slides4 introduction-php-mvc-cakephp-m4-controllers-slides
4 introduction-php-mvc-cakephp-m4-controllers-slides
 
Introduction to windows power shell in sharepoint 2010
Introduction to windows power shell in sharepoint 2010Introduction to windows power shell in sharepoint 2010
Introduction to windows power shell in sharepoint 2010
 
Build Lightweight Web Module
Build Lightweight Web ModuleBuild Lightweight Web Module
Build Lightweight Web Module
 
Google Bot Herding, PageRank Sculpting and Manipulation
Google Bot Herding, PageRank Sculpting and ManipulationGoogle Bot Herding, PageRank Sculpting and Manipulation
Google Bot Herding, PageRank Sculpting and Manipulation
 
Knowledge is Power: Getting out of trouble by understanding Git - Steve Smith...
Knowledge is Power: Getting out of trouble by understanding Git - Steve Smith...Knowledge is Power: Getting out of trouble by understanding Git - Steve Smith...
Knowledge is Power: Getting out of trouble by understanding Git - Steve Smith...
 
Me and my importers
Me and my importersMe and my importers
Me and my importers
 
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014Hardcore URL Routing for WordPress - WordCamp Atlanta 2014
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014
 
Node.js: scalability tips - Azure Dev Community Vijayawada
Node.js: scalability tips - Azure Dev Community VijayawadaNode.js: scalability tips - Azure Dev Community Vijayawada
Node.js: scalability tips - Azure Dev Community Vijayawada
 
PowerShell Tips & Tricks for Exchange
PowerShell Tips & Tricks for ExchangePowerShell Tips & Tricks for Exchange
PowerShell Tips & Tricks for Exchange
 

Similar to Working Effectively with Legacy Javascript code in Opal

Share point hosted add ins munich
Share point hosted add ins munichShare point hosted add ins munich
Share point hosted add ins munichSonja Madsen
 
Bare-knuckle web development
Bare-knuckle web developmentBare-knuckle web development
Bare-knuckle web developmentJohannes Brodwall
 
HTML Templates Using Clear Silver
HTML Templates Using Clear SilverHTML Templates Using Clear Silver
HTML Templates Using Clear SilverPaulWay
 
[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress DevelopmentAdam Tomat
 
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"GeeksLab Odessa
 
async/await in Swift
async/await in Swiftasync/await in Swift
async/await in SwiftPeter Friese
 
Django Rest Framework and React and Redux, Oh My!
Django Rest Framework and React and Redux, Oh My!Django Rest Framework and React and Redux, Oh My!
Django Rest Framework and React and Redux, Oh My!Eric Palakovich Carr
 
Childthemes ottawa-word camp-1919
Childthemes ottawa-word camp-1919Childthemes ottawa-word camp-1919
Childthemes ottawa-word camp-1919Paul Bearne
 
TurboGears2 Pluggable Applications
TurboGears2 Pluggable ApplicationsTurboGears2 Pluggable Applications
TurboGears2 Pluggable ApplicationsAlessandro Molina
 
WordPress as the Backbone(.js)
WordPress as the Backbone(.js)WordPress as the Backbone(.js)
WordPress as the Backbone(.js)Beau Lebens
 
Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
 Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011 Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011Alessandro Nadalin
 
Summer - The HTML5 Library for Java and Scala
Summer - The HTML5 Library for Java and ScalaSummer - The HTML5 Library for Java and Scala
Summer - The HTML5 Library for Java and Scalarostislav
 
React mit TypeScript – eine glückliche Ehe
React mit TypeScript – eine glückliche EheReact mit TypeScript – eine glückliche Ehe
React mit TypeScript – eine glückliche Eheinovex GmbH
 
Advanced Perl Techniques
Advanced Perl TechniquesAdvanced Perl Techniques
Advanced Perl TechniquesDave Cross
 
Meta Buscadores
Meta BuscadoresMeta Buscadores
Meta Buscadorespechever
 

Similar to Working Effectively with Legacy Javascript code in Opal (20)

Redux vs Alt
Redux vs AltRedux vs Alt
Redux vs Alt
 
Share point hosted add ins munich
Share point hosted add ins munichShare point hosted add ins munich
Share point hosted add ins munich
 
Bare-knuckle web development
Bare-knuckle web developmentBare-knuckle web development
Bare-knuckle web development
 
Lecture14
Lecture14Lecture14
Lecture14
 
HTML Templates Using Clear Silver
HTML Templates Using Clear SilverHTML Templates Using Clear Silver
HTML Templates Using Clear Silver
 
[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development[Bristol WordPress] Supercharging WordPress Development
[Bristol WordPress] Supercharging WordPress Development
 
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
QA Lab: тестирование ПО. Яков Крамаренко: "KISS Automation"
 
async/await in Swift
async/await in Swiftasync/await in Swift
async/await in Swift
 
Django Rest Framework and React and Redux, Oh My!
Django Rest Framework and React and Redux, Oh My!Django Rest Framework and React and Redux, Oh My!
Django Rest Framework and React and Redux, Oh My!
 
Childthemes ottawa-word camp-1919
Childthemes ottawa-word camp-1919Childthemes ottawa-word camp-1919
Childthemes ottawa-word camp-1919
 
TurboGears2 Pluggable Applications
TurboGears2 Pluggable ApplicationsTurboGears2 Pluggable Applications
TurboGears2 Pluggable Applications
 
WordPress as the Backbone(.js)
WordPress as the Backbone(.js)WordPress as the Backbone(.js)
WordPress as the Backbone(.js)
 
Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
 Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011 Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
Be lazy, be ESI: HTTP caching and Symfony2 @ PHPDay 2011 05-13-2011
 
Summer - The HTML5 Library for Java and Scala
Summer - The HTML5 Library for Java and ScalaSummer - The HTML5 Library for Java and Scala
Summer - The HTML5 Library for Java and Scala
 
Url programming
Url programmingUrl programming
Url programming
 
React mit TypeScript – eine glückliche Ehe
React mit TypeScript – eine glückliche EheReact mit TypeScript – eine glückliche Ehe
React mit TypeScript – eine glückliche Ehe
 
PHP-Part4
PHP-Part4PHP-Part4
PHP-Part4
 
68837.ppt
68837.ppt68837.ppt
68837.ppt
 
Advanced Perl Techniques
Advanced Perl TechniquesAdvanced Perl Techniques
Advanced Perl Techniques
 
Meta Buscadores
Meta BuscadoresMeta Buscadores
Meta Buscadores
 

More from Forrest Chang

Crystal is a Rubyists friend (quick anecdote)
Crystal is a Rubyists friend (quick anecdote)Crystal is a Rubyists friend (quick anecdote)
Crystal is a Rubyists friend (quick anecdote)Forrest Chang
 
Making terminal based apps w:ruby
Making terminal based apps w:rubyMaking terminal based apps w:ruby
Making terminal based apps w:rubyForrest Chang
 
Ruby-ying Javascript: Avoiding jQuery Spaghetti
Ruby-ying Javascript: Avoiding jQuery SpaghettiRuby-ying Javascript: Avoiding jQuery Spaghetti
Ruby-ying Javascript: Avoiding jQuery SpaghettiForrest Chang
 
6 reasons Jubilee could be a Rubyist's new best friend
6 reasons Jubilee could be a Rubyist's new best friend6 reasons Jubilee could be a Rubyist's new best friend
6 reasons Jubilee could be a Rubyist's new best friendForrest Chang
 
Opal chapter 4_a_new_hope
Opal chapter 4_a_new_hopeOpal chapter 4_a_new_hope
Opal chapter 4_a_new_hopeForrest Chang
 
Data Intensive RIAs on Rails with very little code (Netzke)
Data Intensive RIAs on Rails with very little code (Netzke)Data Intensive RIAs on Rails with very little code (Netzke)
Data Intensive RIAs on Rails with very little code (Netzke)Forrest Chang
 
Opal - Ruby Style!! Ruby in the browser
Opal - Ruby Style!!  Ruby in the browserOpal - Ruby Style!!  Ruby in the browser
Opal - Ruby Style!! Ruby in the browserForrest Chang
 

More from Forrest Chang (11)

Crystal is a Rubyists friend (quick anecdote)
Crystal is a Rubyists friend (quick anecdote)Crystal is a Rubyists friend (quick anecdote)
Crystal is a Rubyists friend (quick anecdote)
 
Making terminal based apps w:ruby
Making terminal based apps w:rubyMaking terminal based apps w:ruby
Making terminal based apps w:ruby
 
Opal-hot-reloader
Opal-hot-reloaderOpal-hot-reloader
Opal-hot-reloader
 
Ruby-ying Javascript: Avoiding jQuery Spaghetti
Ruby-ying Javascript: Avoiding jQuery SpaghettiRuby-ying Javascript: Avoiding jQuery Spaghetti
Ruby-ying Javascript: Avoiding jQuery Spaghetti
 
Rubyconf 2014 recap
Rubyconf 2014 recapRubyconf 2014 recap
Rubyconf 2014 recap
 
6 reasons Jubilee could be a Rubyist's new best friend
6 reasons Jubilee could be a Rubyist's new best friend6 reasons Jubilee could be a Rubyist's new best friend
6 reasons Jubilee could be a Rubyist's new best friend
 
Opal a new_hope
Opal a new_hopeOpal a new_hope
Opal a new_hope
 
Opal chapter 4_a_new_hope
Opal chapter 4_a_new_hopeOpal chapter 4_a_new_hope
Opal chapter 4_a_new_hope
 
Data Intensive RIAs on Rails with very little code (Netzke)
Data Intensive RIAs on Rails with very little code (Netzke)Data Intensive RIAs on Rails with very little code (Netzke)
Data Intensive RIAs on Rails with very little code (Netzke)
 
Rubyconf2012 recap
Rubyconf2012 recapRubyconf2012 recap
Rubyconf2012 recap
 
Opal - Ruby Style!! Ruby in the browser
Opal - Ruby Style!!  Ruby in the browserOpal - Ruby Style!!  Ruby in the browser
Opal - Ruby Style!! Ruby in the browser
 

Recently uploaded

Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastPapp Krisztián
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfkalichargn70th171
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionOnePlan Solutions
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024VictoriaMetrics
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnAmarnathKambale
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrandmasabamasaba
 
tonesoftg
tonesoftgtonesoftg
tonesoftglanshi9
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...masabamasaba
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park masabamasaba
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in sowetomasabamasaba
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...Jittipong Loespradit
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...masabamasaba
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfonteinmasabamasaba
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsArshad QA
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyviewmasabamasaba
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplatePresentation.STUDIO
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...Shane Coughlan
 

Recently uploaded (20)

Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
MarTech Trend 2024 Book : Marketing Technology Trends (2024 Edition) How Data...
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 

Working Effectively with Legacy Javascript code in Opal

  • 1. WEWLJCIO - WORKING EFFECTIVELY WITH LEGACY JAVASCRIPT CODE IN OPAL FORREST CHANG FKCHANG2000@YAHOO.COM
  • 2. BACKGOUND - OPAL-HOT-RELOADER Hot reloader for Hot loaded code I merged a pull request that added hot css reloading Opal
  • 3. THE NEW CODE Worked But in Javascript No tests :( Want to extend code Want it to be easier to maintain
  • 4. REAL LIFE REFACTORING Real life better than canned examples Need tests Want to be in Ruby/Opal
  • 5. BY MICHAEL FEATHERS WORKING EFFECTIVELY WITH LEGACY CODE Similar situation "Legacy code" == code w/o tests How to put tests on something w/o tests But also a little different Want to convert languages Subject to the predefined browser API and a particular way of interacting with it
  • 6. THE SUBMITTED CODE Added a new if clause to OpalHotReloader#reload() to handle CSS hot reloading Implemented in Javascript via Opal x-string.
  • 7. ORIGINAL RELOAD() METHOD def reload(e) # original code reload_request = JSON.parse(`e.data`) if reload_request[:type] == "ruby" puts "Reloading ruby #{reload_request[:filename]}" eval reload_request[:source_code] if @reload_post_callback @reload_post_callback.call else puts "not reloading code" end end
  • 8. ADDED IF CODE TO RELOAD() METHOD # the new css hot reloading code if reload_request[:type] == "css" url = reload_request[:url] puts "Reloading CSS: #{url}" # Work outsources Javascript via x-string %x{ var toAppend = "t_hot_reload=" + (new Date()).getTime(); var links = document.getElementsByTagName("link"); for (var i = 0; i < links.length; i++) { var link = links[i]; if (link.rel === "stylesheet" && link.href.indexOf(#{url}) >= 0) { if (link.href.indexOf("?") === -1) { link.href += "?" + toAppend; } else { if (link.href.indexOf("t_hot_reload") === -1) { link.href += "&" + toAppend; } else { link.href = link.href.replace(/t_hot_reload=d{13}/, toAppend) } } } } } end end
  • 9. OBSERVATIONS reload() used to be small Now 3x the size Has an additional responsiblity
  • 10. REFACTORING Extract Method to handle new responsibilty Extract class to hold that responsibilty (SRP) Delegate to instance new class New instance @css_reloader to be created in initialize method
  • 11. REFACTORED RELOAD() def reload(e) reload_request = JSON.parse(`e.data`) if reload_request[:type] == "ruby" puts "Reloading ruby #{reload_request[:filename]}" eval reload_request[:source_code] if @reload_post_callback @reload_post_callback.call else puts "not reloading code" end end if reload_request[:type] == "css" @css_reloader.reload(reload_request) # extracted method called here end end
  • 12. THE NEW CSSRELOADER CLASS class OpalHotReloader class CssReloader def reload(reload_request) url = reload_request[:url] %x{ var toAppend = "t_hot_reload=" + (new Date()).getTime(); var links = document.getElementsByTagName("link"); for (var i = 0; i < links.length; i++) { var link = links[i]; if (link.rel === "stylesheet" && link.href.indexOf(#{url}) >= 0) { if (link.href.indexOf("?") === -1) { link.href += "?" + toAppend; } else { if (link.href.indexOf("t_hot_reload") === -1) { link.href += "&" + toAppend; } else { link.href = link.href.replace(/t_hot_reload=d{13}/, toAppend) } } } } } end end end
  • 13. TESTING THE SOLUTION No automated tests yet. Test manually PITA New code works!
  • 14. WRITING AUTOMATED TESTS Refactored works, we can now add automated tests Using - minitest also available for those who don't like rspecopal-rspec
  • 15. A PROBLEM Technique to update css involves manipulating style links in the global document object Could Create links in the actual DOM of the spec runner (not hard) But don't like the non transparency of this Don't like code that calls out directly to global document Would be nice to be able to inject a test document
  • 16. DEPENDENCY INJECTION Desired outcome: Inject test doc for test, inject the real document for application Don't need standard dependency injection methods (constructor, setter, interface) Able to just pass document as a parameter
  • 17. MORE ISSUES FOR DOCUMENT TEST DOUBLE Limited options for hot reloading of CSS - have to do it a certain way document interface not under my control - must match it Stubbing Javascript objects in Opal Opal/JS interface a problem here - Opal objects different Opal-rspec has powerful mock/stub capability, but only Opal objects Need to create own method
  • 18. 2 CONVENIENCE METHODS Creates javascript objects directly via x-strings create_link() to create the link DOM object that will get altered to facillitate the css hot reloading and fake_links_document() a convenience method which returns both a test double for global document object, which responds to the getElementsByTagName('link') call and a test double for the link itself, that I will inspect to see whether it has been correctly altered.
  • 19. CODE def create_link( href) %x| var ss = document.createElement("link"); ss.type = "text/css"; ss.rel = "stylesheet"; ss.href = #{href}; return ss; | end def fake_links_document(href) link = create_link(href) doc = `{ getElementsByTagName: function(name) { links = [ #{link}]; return links;}}` { link: link, document: doc} end
  • 20. ADD DOCUMENT TO RELOAD() SIGNATURE # change from def reload(reload_request) # to def reload(reload_request, document)
  • 21. CALL WITH THE NEW SIGNATURE # in OpalHotReloader#reload() # instead of calling it this way @css_reloader.reload(reload_request) # we pass in the real browser document @css_reloader.reload(reload_request, `document`)
  • 22. MODIFY CSSRELOADER TO TAKE DOCUMENT class OpalHotReloader class CssReloader def reload(reload_request, document) # pass in the "document" url = reload_request[:url] %x{ var toAppend = "t_hot_reload=" + (new Date()).getTime(); // invoke it here var links = #{document}.getElementsByTagName("link"); for (var i = 0; i < links.length; i++) { var link = links[i]; if (link.rel === "stylesheet" && link.href.indexOf(#{url}) >= 0) { if (link.href.indexOf("?") === -1) { link.href += "?" + toAppend; } else { if (link.href.indexOf("t_hot_reload") === -1) { link.href += "&" + toAppend; } else { link.href = link.href.replace(/t_hot_reload=d{13}/, toAppend) } } } } } end end end
  • 23. TESTING SIGNATURE CHANGE Must hand test again Works!
  • 24. REQUIRED TEST CASES A plain stylesheet link where we add the hot reload argument for the first time. Updating a link that has already been updated with a hot reload argument. Appending an additional hot reload argument parameter to a stylesheet link that already has a parameter.
  • 25. WRITING SPECS FOR THESE CASES require 'native' require 'opal_hot_reloader' require 'opal_hot_reloader/css_reloader' describe OpalHotReloader::CssReloader do def create_link( href) %x| var ss = document.createElement("link"); ss.type = "text/css"; ss.rel = "stylesheet"; ss.href = #{href}; return ss; | end def fake_links_document(href) link = create_link(href) doc = `{ getElementsByTagName: function(name) { links = [ #{link}]; return links;}}` { link: link, document: doc} end context 'Rack::Sass::Plugin' do it 'should add t_hot_reload to a css path' do css_path = 'stylesheets/base.css' doubles = fake_links_document(css_path) link = Native(doubles[:link]) expect(link[:href]).to match /#{Regexp.escape(css_path)}$/ subject.reload({ url: css_path}, doubles[:document]) expect(link[:href]).to match /#{Regexp.escape(css_path)}?t_hot_reload=d+/ end
  • 26. PAGE 2 it 'should update t_hot_reload argument if there is one already' do css_path = 'stylesheets/base.css?t_hot_reload=1111111111111' doubles = fake_links_document(css_path) link = Native(doubles[:link]) expect(link[:href]).to match /#{Regexp.escape(css_path)}$/ subject.reload({ url: css_path}, doubles[:document]) expect(link[:href]).to match /#{Regexp.escape('stylesheets/base.css?t_hot_reload=') }(d)+/ expect($1).to_not eq '1111111111111' end it 'should append t_hot_reload if there are existing arguments' do css_path = 'stylesheets/base.css?some-arg=1' doubles = fake_links_document(css_path) link = Native(doubles[:link]) expect(link[:href]).to match /#{Regexp.escape(css_path)}$/ subject.reload({ url: css_path}, doubles[:document]) expect(link[:href]).to match /#{Regexp.escape(css_path)}&t_hot_reload=(d)+/ end end end
  • 27. SPECS PASS - SAFE TO REFACTOR Added automated test coverage for the 3 cases Now safe to rewrite the reload() method in Ruby/Opal Spec provide safety net to prove we don't break the desired functionality A trick - have reload() delegate to reload_ruby() reload_js() to have both code side by side - handy for development and debugging
  • 28. THE TRICK require 'native' class OpalHotReloader class CssReloader def reload(reload_request, document) # currently using the Ruby version reload_ruby(reload_request, document) # reload_js(reload_request, document) end def reload_ruby(reload_request, document) url = reload_request[:url] puts "Reloading CSS: #{url}" to_append = "t_hot_reload=#{Time.now.to_i}" links = Native(`document.getElementsByTagName("link")`) (0..links.length-1).each { |i| link = links[i] if link.rel == 'stylesheet' && link.href.index(url) if link.href !~ /?/ link.href += "?#{to_append}" else if link.href !~ /t_hot_reload/ link.href += "&#{to_append}" else link.href = link.href.sub(/t_hot_reload=d{13}/, to_append) end end end } end
  • 29. PAGE 2 def reload_js(reload_request, document) url = reload_request[:url] %x{ var toAppend = "t_hot_reload=" + (new Date()).getTime(); var links = #{document}.getElementsByTagName("link"); for (var i = 0; i < links.length; i++) { var link = links[i]; if (link.rel === "stylesheet" && link.href.indexOf(#{url}) >= 0) { if (link.href.indexOf("?") === -1) { link.href += "?" + toAppend; } else { if (link.href.indexOf("t_hot_reload") === -1) { link.href += "&" + toAppend; } else { link.href = link.href.replace(/t_hot_reload=d{13}/, toAppend) } } } } } end end end
  • 30. IMPLEMENTATION Ruby version - a line by line translation Specs passed Can remove Javascript version
  • 31. OPAL ONLY CSSRELOADER require 'native' class OpalHotReloader class CssReloader def reload(reload_request, document) url = reload_request[:url] puts "Reloading CSS: #{url}" to_append = "t_hot_reload=#{Time.now.to_i}" links = Native(`document.getElementsByTagName("link")`) (0..links.length-1).each { |i| link = links[i] if link.rel == 'stylesheet' && link.href.index(url) if link.href !~ /?/ link.href += "?#{to_append}" else if link.href !~ /t_hot_reload/ link.href += "&#{to_append}" else link.href = link.href.sub(/t_hot_reload=d{13}/, to_append) end end end } end end end
  • 32. ONWARD Now have specs Converted code to Ruby Much easier to implment hot reloading of Rails CSS/SASS Already did it, it was easy, used TDD for that
  • 33. LINKS TO BLOG POST Blogger - code syntax highlighted Medium - prettier but no syntax highlighting http://funkworks.blogspot.com/2016/06/wewljcio-working-effectively- with.html https://medium.com/@fkchang2000/wewljcio-working-effectively-with- legacy-javascript-code-in-opal-4fd624693de4