<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-16908486</id><updated>2024-06-10T00:55:35.912-07:00</updated><category term="ruby"/><category term="opal"/><category term="javascript"/><category term="rails"/><category term="ruby-fying javascript"/><category term="presentations lessig hardt takahashi"/><category term="tdd"/><category term="psa"/><category term="agile"/><category term="conveying_new_ideas"/><category term="emacs"/><category term="jdd"/><category term="martial_arts"/><category term="bdd"/><category term="bjj"/><category term="bjj_diary"/><category term="definitions"/><category term="empowerment"/><category term="happiness"/><category term="jsapabo"/><category term="kent beck"/><category term="opal-irb"/><category term="osx"/><category term="twitter"/><category term="visualization"/><category term="ward"/><category term="24"/><category term="3EZ"/><category term="Comcast Xfinity"/><category term="IR"/><category term="RF"/><category term="XiD-P"/><category term="agile agile_diary"/><category term="agile_diary"/><category term="alexa"/><category term="apache"/><category term="apple"/><category term="applescript&#xa;automation&#xa;outlook&#xa;microsoft&#xa;Script Edito"/><category term="camera"/><category term="cisco 9856HDC"/><category term="cox cable"/><category term="cox contour"/><category term="david vs goliath"/><category term="daycoder"/><category term="dragonfly"/><category term="eff you dongle"/><category term="ftp"/><category term="fun"/><category term="game of life"/><category term="hyperloop"/><category term="implementation patterns"/><category term="jruby"/><category term="jubilee"/><category term="logitech"/><category term="macbook exec"/><category term="makemacbookPro"/><category term="microsoft"/><category term="net::ftp"/><category term="oauth"/><category term="omniauth"/><category term="omniauth-twitter"/><category term="opal-jquery"/><category term="pair_programming"/><category term="passenger"/><category term="productivity"/><category term="rails ruby_way"/><category term="react.rb"/><category term="reactjs"/><category term="refactoring"/><category term="refinerycms"/><category term="require &#39;node.js&#39;"/><category term="revolution"/><category term="rspec"/><category term="ruby everywhere"/><category term="ruby_way"/><category term="salesforce"/><category term="save ruby"/><category term="scaling"/><category term="shortcuts"/><category term="simplicity"/><category term="social media"/><category term="software"/><category term="tdd bdd"/><category term="til"/><category term="time rails activesupport"/><category term="troubleshooting"/><category term="universal remote"/><category term="unix"/><category term="user experience"/><category term="vertx"/><title type='text'>Putting the fun into Funkworks</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>132</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-16908486.post-1876272849861066582</id><published>2023-10-13T16:01:00.001-07:00</published><updated>2023-10-13T16:01:36.761-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="applescript&#xa;automation&#xa;outlook&#xa;microsoft&#xa;Script Edito"/><title type='text'>PSA: Getting Microsoft Outlook (or any other Applescript-able app)&#39;s dictionary</title><content type='html'>&lt;div class=&quot;content&quot; tabindex=&quot;0&quot;&gt;&lt;div class=&quot;ac-container ac-adaptiveCard&quot; streaming=&quot;&quot;&gt;&lt;div class=&quot;ac-textBlock&quot;&gt;&lt;p&gt;So you’re on a Mac and you need to use Microsoft Outlook. Maybe it’s not the best, but luckily, Outlook is scriptable via OSX automation (AppleScript/Javascript/Objective C). Unfortunately, you may have discovered that there are hardly any resources on the internet for AppleScript and Outlook. Sure, there are some examples out there (old ones) and some questions on Stack Overflow and similar sites, but you might find that they don’t cover the things you want to do. In my case, I just wanted to set the importance of an outgoing email I already constructed with AppleScript to high.&lt;/p&gt;&lt;p&gt;If only there were some sort of reference. Once upon a time, there was an official Microsoft Office 2004 (yes, that old) Reference, but that is nowhere to be found. You’ll find a number of posts of people failing to get that reference, in many cases reaching out to Microsoft support, who also cannot provide any answers.&lt;/p&gt;&lt;p&gt;This was me, for years. Every now and then, I would look again, hoping to find the right magic keywords to finally get an answer. I’ve also tried various AI chatbots, like Bard, Bing, ChatGPT, but they have all failed to give me the answer to my questions or references that still exist. Yes, even the mighty “Generative AI that will change everything” failed me here.&lt;/p&gt;&lt;p&gt;Luckily, today I stumbled upon this article [&lt;a href=&quot;https://stackoverflow.com/questions/64445534/where-is-the-ozfficial-documentation-applescript-commands-for-powerpoint&quot; target=&quot;_blank&quot;&gt;where is the official documentation applescript commands for powerpoint&lt;/a&gt;], which finally gave me what I was looking for. Gotta give credit where credit is due!&lt;/p&gt;&lt;p&gt;I learned that you can add the application and then get access to its AppleScript reference via the Script Editor library. Search has in the past pointed me to the Script Editor’s library, but if you open it up, you’ll find it only has entries for Apple-made software.&lt;/p&gt;&lt;p&gt;Let me save you a few years of looking and get you on your way to automating Outlook (or any other application not made by Apple that can be scripted)&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Open Script Editor&lt;/li&gt;&lt;li&gt;Go to Window &amp;gt; Library&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&amp;nbsp;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjX99ObleRGofZ9wyPjkZwOAWjM9CWbWpjRquCp4oRG4tGndtywTaYb5Umrqvi-zjlw597IadM9Rdj8jZosfqAWrdA4OeRSkVz2qFfooZq3dC3k0sewuSTyjdvAeVZ_QEFMUBeeKfSFCQ_CP2fIqx4OGOhVfPnj--aRoQUA0JmM80IxBtbeTFfKdg&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;356&quot; data-original-width=&quot;752&quot; height=&quot;151&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEjX99ObleRGofZ9wyPjkZwOAWjM9CWbWpjRquCp4oRG4tGndtywTaYb5Umrqvi-zjlw597IadM9Rdj8jZosfqAWrdA4OeRSkVz2qFfooZq3dC3k0sewuSTyjdvAeVZ_QEFMUBeeKfSFCQ_CP2fIqx4OGOhVfPnj--aRoQUA0JmM80IxBtbeTFfKdg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Click the + button on the Library&amp;nbsp;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEibWw_lR18eQ30wFvv6HsM7x7IiuD6kicrLt86leA8l0Ce3qJfW71_v11NNZuEzhK2aqy7JnApbD8_bHIUhkF9askBv4go1OkZSRebRLPnz_O9vpcISkqGNMSpwkfbZbu6LVjRjUJBQL-xFvrAURIffNPTX6M5HoeO8AUDpGDXklAinRqw2S2YZPg&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;113&quot; data-original-width=&quot;234&quot; height=&quot;155&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEibWw_lR18eQ30wFvv6HsM7x7IiuD6kicrLt86leA8l0Ce3qJfW71_v11NNZuEzhK2aqy7JnApbD8_bHIUhkF9askBv4go1OkZSRebRLPnz_O9vpcISkqGNMSpwkfbZbu6LVjRjUJBQL-xFvrAURIffNPTX6M5HoeO8AUDpGDXklAinRqw2S2YZPg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Navigate to your app (e.g., /Applications/Microsoft Outlook in my case) and Open it&amp;nbsp;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEileI4TtcsnSVzoyNtPyfL9n6MIGg1hJZ62jDV5LRu_4CpOPpO-660jJDxlOCgHnI4lVelf54hx_ibLgbxs7yg8cvoeYdrjz6fx6gVPBn_pLevEV-g8UjKOLYmcQap2ah2XD5UH6aFZSJYB8ZWZLJYW4oclGrM36jb27CdYwImJPUV0lu7t_ALwRw&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;454&quot; data-original-width=&quot;716&quot; height=&quot;203&quot; src=&quot;https://blogger.googleusercontent.com/img/a/AVvXsEileI4TtcsnSVzoyNtPyfL9n6MIGg1hJZ62jDV5LRu_4CpOPpO-660jJDxlOCgHnI4lVelf54hx_ibLgbxs7yg8cvoeYdrjz6fx6gVPBn_pLevEV-g8UjKOLYmcQap2ah2XD5UH6aFZSJYB8ZWZLJYW4oclGrM36jb27CdYwImJPUV0lu7t_ALwRw&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Open the reference from the library&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;That’s it! Now you can explore the AppleScript reference for Outlook and automate your tasks with ease. I hope this saves you some time and frustration. Happy scripting!&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;P.S. The answer to my question is&amp;nbsp;&lt;span class=&quot;s1&quot; style=&quot;font-family: Verdana; font-size: 12px; font-variant-ligatures: no-common-ligatures; text-indent: -124.9px;&quot;&gt;&lt;b&gt;set&lt;/b&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;color: #6c05d3; font-family: Verdana; font-size: 12px; font-variant-ligatures: no-common-ligatures; text-indent: -124.9px;&quot;&gt;priority&lt;/span&gt;&lt;span class=&quot;s1&quot; style=&quot;font-family: Verdana; font-size: 12px; font-variant-ligatures: no-common-ligatures; text-indent: -124.9px;&quot;&gt; &lt;b&gt;to&lt;/b&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot; style=&quot;color: #6c05d3; font-family: Verdana; font-size: 12px; font-variant-ligatures: no-common-ligatures; text-indent: -124.9px;&quot;&gt;&lt;i&gt;priority high&amp;nbsp;&lt;/i&gt;&lt;/span&gt;that&#39;s how you set the priority to high in Microsoft Outlook!&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;&lt;cib-overlay&gt;&lt;/cib-overlay&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/1876272849861066582/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/1876272849861066582' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/1876272849861066582'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/1876272849861066582'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2023/10/psa-getting-microsoft-outlook-or-any.html' title='PSA: Getting Microsoft Outlook (or any other Applescript-able app)&#39;s dictionary'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/a/AVvXsEjX99ObleRGofZ9wyPjkZwOAWjM9CWbWpjRquCp4oRG4tGndtywTaYb5Umrqvi-zjlw597IadM9Rdj8jZosfqAWrdA4OeRSkVz2qFfooZq3dC3k0sewuSTyjdvAeVZ_QEFMUBeeKfSFCQ_CP2fIqx4OGOhVfPnj--aRoQUA0JmM80IxBtbeTFfKdg=s72-c" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-7563192369430354568</id><published>2020-02-27T14:44:00.001-08:00</published><updated>2020-02-27T14:44:34.617-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="dragonfly"/><category scheme="http://www.blogger.com/atom/ns#" term="rails"/><category scheme="http://www.blogger.com/atom/ns#" term="refinerycms"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>PSA: Require login for access to uploaded files in refinerycms</title><content type='html'>So you&#39;re using &lt;a href=&quot;https://www.refinerycms.com/&quot;&gt;refinery cms&lt;/a&gt; and &lt;a href=&quot;https://github.com/heartcombo/devise&quot;&gt;devise&lt;/a&gt; together in your &lt;a href=&quot;https://rubyonrails.org/&quot;&gt;Rails&lt;/a&gt; app and
you have a before_filter in ApplicationController that requires login
to access pages on your site, yet your uploaded resources do not
require login and are publically accessible.  What gives?
&lt;br /&gt;
&lt;br /&gt;
The simple answer is that &lt;a href=&quot;https://markevans.github.io/dragonfly/&quot;&gt;Dragonfly&lt;/a&gt;, which is used by refinerycms
works as Rack middleware. As such, it ignores your before_filter. So a
solution is to insert &lt;a href=&quot;https://github.com/wardencommunity/warden&quot;&gt;warden&lt;/a&gt; authentication via the before_serve
mechanism in Dragonfly, which I learned to do from &lt;a href=&quot;https://github.com/markevans/dragonfly/wiki/Example:-Authentication&quot;&gt;https://github.com/markevans/dragonfly/wiki/Example:-Authentication&lt;/a&gt;. Conveniently,
refinerycms-dragonfly, the plugin that adds Dragonfly support to
refinerycms, allows one to configure a dragonfly_before_serve callback
to do such a thing.
&lt;br /&gt;
You will need 2 things
&lt;br /&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;refinerycms-dragonfly version 1.0.2, which at the time of writing is not available in rubygems, You can access it via git until that happens with the following line in your Gemfile&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot;&gt;gem &lt;span style=&quot;color: #cc9393;&quot;&gt;&#39;refinerycms-dragonfly&#39;&lt;/span&gt;, &lt;span style=&quot;color: #cc9393;&quot;&gt;&#39;1.0.2&#39;&lt;/span&gt;, 
&lt;span style=&quot;color: #bfebbf;&quot;&gt;  git&lt;/span&gt;: &lt;span style=&quot;color: #cc9393;&quot;&gt;&#39;https://github.com/refinery/refinerycms&#39;&lt;/span&gt;, 
&lt;span style=&quot;color: #bfebbf;&quot;&gt;  branch&lt;/span&gt;: &lt;span style=&quot;color: #cc9393;&quot;&gt;&#39;master&#39;&lt;/span&gt;, &lt;span style=&quot;color: #bfebbf;&quot;&gt;ref&lt;/span&gt;: &lt;span style=&quot;color: #cc9393;&quot;&gt;&#39;c3879931612d8cdceb2a635d5b9f8fcfd56e09b6&#39;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;overriding the dragonfly_before_serve in your config (for example config/initializers/refinery/resources.rb - depending on how you have Dragonfly/S3 configured)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot;&gt;config.dragonfly_before_serve = &lt;span style=&quot;color: #dcdccc; font-weight: bold;&quot;&gt;lambda&lt;/span&gt; { |job, env| 
  user = env[&lt;span style=&quot;color: #cc9393;&quot;&gt;&#39;warden&#39;&lt;/span&gt;].user &lt;span style=&quot;color: #bfebbf;&quot;&gt;:user&lt;/span&gt; &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #7f9f7f;&quot;&gt;get devise user from scope &#39;user&#39;&lt;/span&gt;
  &lt;span style=&quot;color: #dcdccc; font-weight: bold;&quot;&gt;throw&lt;/span&gt; &lt;span style=&quot;color: #bfebbf;&quot;&gt;:halt&lt;/span&gt;, [401, {&lt;span style=&quot;color: #cc9393;&quot;&gt;&quot;Content-Type&quot;&lt;/span&gt; =&amp;gt; &lt;span style=&quot;color: #cc9393;&quot;&gt;&quot;text/plain&quot;&lt;/span&gt;}, [&lt;span style=&quot;color: #cc9393;&quot;&gt;&quot;Unauthorized&quot;&lt;/span&gt;]] &lt;span style=&quot;color: #f0dfaf; font-weight: bold;&quot;&gt;unless&lt;/span&gt; user
}
&lt;/pre&gt;
&lt;/div&gt;
And that&#39;s it!  Happy private file-ing.
</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/7563192369430354568/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/7563192369430354568' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/7563192369430354568'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/7563192369430354568'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2020/02/psa-require-login-for-access-to.html' title='PSA: Require login for access to uploaded files in refinerycms'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-3821282914628699256</id><published>2019-02-11T15:17:00.000-08:00</published><updated>2019-02-11T15:17:30.134-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="apple"/><category scheme="http://www.blogger.com/atom/ns#" term="eff you dongle"/><category scheme="http://www.blogger.com/atom/ns#" term="macbook exec"/><category scheme="http://www.blogger.com/atom/ns#" term="makemacbookPro"/><title type='text'>PSA: Using Pro display monitors with the Macbook Exec, er Pro</title><content type='html'>Possibly the best computing accessory I have is the wonderful&amp;nbsp;&lt;a href=&quot;https://www.dell.com/en-us/shop/dell-ultrasharp-34-curved-ultrawide-monitor-u3415w/apd/210-adtr/monitors-monitor-accessories&quot; target=&quot;_blank&quot;&gt;Dell U3415W &lt;/a&gt;it&#39;s a 34 inch curved widescreen monitor that sports a whopping 3440x1440 resolution. One can lay 3 screens (&amp;nbsp;browser, editor, console&amp;nbsp;&amp;nbsp;side by side, which is invaluable for a Web developer.&amp;nbsp; It also has crisp clean text and images. It&#39;s a joy to work with and forced me to buy a similarly spec&#39;d monitor at home because I found I could not live without it.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Getting a new computer should also be a joyous occasion. We just got brand new &lt;i&gt;Macbook &lt;strike&gt;Execs&lt;/strike&gt; Pros&lt;/i&gt;&lt;b&gt;** &lt;/b&gt;and the necessary &quot;&lt;i&gt;Eff you, Dongle!&lt;/i&gt;&quot;&lt;b&gt;***&lt;/b&gt; to connect our various pro equipment to them. Unfortunately, to my dismay, the Macbook was unable recognize the Dell&#39;s full resolution and gave us half the resolution.&lt;br /&gt;
&lt;div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8sTavG0JwWqTAohYpajixgvIBgFXnButAZJVhE_6H7D67d6J8M6T4SLO_C4jnh8OcCnZnS_LNtYel2AKIhTXVQTVoQJmQccICu8uYfSAQkjtw2pyk9EmQkrI9xVMe_Uv75I5X1w/s1600/Photo_-_Google_Photos.png&quot; imageanchor=&quot;1&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;236&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8sTavG0JwWqTAohYpajixgvIBgFXnButAZJVhE_6H7D67d6J8M6T4SLO_C4jnh8OcCnZnS_LNtYel2AKIhTXVQTVoQJmQccICu8uYfSAQkjtw2pyk9EmQkrI9xVMe_Uv75I5X1w/s640/Photo_-_Google_Photos.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Fortunately, the aforementioned &quot;Eff you, Dongle&quot; supports HDMI, so we tried that. Success, except, it only supports 30HZ and 50HZ and not the full 60HZ.&amp;nbsp; Hmm, we kind of like it when our fairly decked out (has to last for years) nearly $4000 laptops &quot;Just work.&quot; That used to be Apple&#39;s motto, but has not been for a while. Ironically the 2013 Macbook Pro that is getting replaced handles this monitor fine, without a dongle. I guess that&#39;s just a feature of the Macbook Execs - we get the privilege to pay extra to get parity the old hardware. Unfortunately, it still didn&#39;t work.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
After a bit of research and experimenting apparently there are 2 solutions to get this working with the Dell.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li&gt;Usb-c to displayport cables are purported to work&lt;/li&gt;
&lt;li&gt;One can turn off DP 1.2 on the Dell. This gives us the full resolution at 60HZ but loses the ability to daisy chain monitors via displayport which the Dell supports. The way you do this in the Dell U3415W is: Menu -&amp;gt; Input Source -&amp;gt; DP -&amp;gt; Hold check for 8 sec -&amp;gt; Disable.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
I chose option 2 as I had the dongle already.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
TLDR;&amp;nbsp; If you&#39;re expensive widescreen monitor is not working on your Macbook Pro (cough) through a mini display port dongle, turning off DP 1.2 may solve this for you. Interestingly my LG 3440x1440 monitor does work - I&#39;ll have to check if it supports daisy chaining.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;** Macbook Exec&lt;/b&gt;: is what I&#39;m calling the Macbook Pros made starting with the touch bars. As a pro, I want the most powerful/capable/best hardware I can buy, which Apple used to provide. The latest Macbook Pros seem to be targeting NOT the pro market, but more of an &quot;Exec&quot; - someone who wants something expensive, thin and good looking - a prestige type item to go along the the C that&#39;s starts the initials of the job title. It&#39;s not how it works, but how it looks, and Dahling, it looks mahvelous!&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;img src=&quot;https://i18.photobucket.com/albums/b127/swapmeetlouie/billy_crystal.jpg&quot; /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
(Photo from Dreamstime.com)&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;/b&gt;&lt;br /&gt;
&lt;div&gt;
&lt;b&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/b&gt;&lt;/div&gt;
&lt;b&gt;
&lt;div&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;
** Eff you, Dongle!:&lt;/b&gt; Is what I&#39;ve named Apple&#39;s development policy for a good number of years. It started with removing the headphone jacks on iPhones, which unfortunately has contaminated the Android market now too, but goes hand in hand with the Macbook Exec philosophy. If you want to do anything with your laptop that&#39;s requires more than a keyboard, trackpad, microphone and camera you need a dongle. It&#39;s infuriating to me because it totally ignores the investment that the user put in, that already works with their older products. One is forced to buy dongles, or new equipment. It&#39;s a money grab move that ignores what the users actually want.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://thumbs.dreamstime.com/z/arrogant-executive-3395738.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;640&quot; src=&quot;https://thumbs.dreamstime.com/z/arrogant-executive-3395738.jpg&quot; width=&quot;472&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Real life &quot;Eff you, Dongle!&quot; scenarios&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Pro user&lt;/b&gt;: I want to use my laptop to make music. I already have expensive, non USB C equipment that work fine with my old MBP.&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Apple&lt;/b&gt;: Eff you, Dongle!&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Pro User&lt;/b&gt;: I want to do photography on my MBP. I have expensive cameras, can plug in my cable, or SD cards into my old MBP!&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Apple&lt;/b&gt;: Eff you, Dongle!&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Pro User&lt;/b&gt;: I use my laptop as a workstation and am on it all day. I have high quality, often ergonomic keyboard and pointing devices as well as super large expensive monitors, that all can work without a dongle on my old MBP&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Apple&lt;/b&gt;: Eff you, Dongle!&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Pro User&lt;/b&gt;: I have $400 headphones and I&#39;d like to use it with phone, and since I listen a lot I&#39;d like to use my nice headphones and charge at the same time.&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;Apple&lt;/b&gt;: Eff you, Dongle! Or buy new headphones.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/3821282914628699256/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/3821282914628699256' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/3821282914628699256'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/3821282914628699256'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2019/02/psa-using-pro-display-monitors-with.html' title='PSA: Using Pro display monitors with the Macbook Exec, er Pro'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8sTavG0JwWqTAohYpajixgvIBgFXnButAZJVhE_6H7D67d6J8M6T4SLO_C4jnh8OcCnZnS_LNtYel2AKIhTXVQTVoQJmQccICu8uYfSAQkjtw2pyk9EmQkrI9xVMe_Uv75I5X1w/s72-c/Photo_-_Google_Photos.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-8836789281487745481</id><published>2018-08-28T08:54:00.003-07:00</published><updated>2018-09-17T10:16:05.564-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="camera"/><category scheme="http://www.blogger.com/atom/ns#" term="osx"/><category scheme="http://www.blogger.com/atom/ns#" term="psa"/><title type='text'>PSA - Restarting your MacbookPro camera without rebooting</title><content type='html'>I&#39;ve been encountering this issue lately where my camera would stop working. I regularly do a lot of video meetings, so this is a hindrance. I had been rebooting my machine, but that&#39;s a bit of a diversion, esp. when one is busy and/or has a lot of things in progress. I &lt;a href=&quot;https://www.quora.com/How-do-I-activate-the-camera-on-my-MacBook-Pro&quot; target=&quot;_blank&quot;&gt;discovered&lt;/a&gt; today one only needs to kill VDCAssistant (it will restart) and your camera functionality will be restored.&lt;br /&gt;
&lt;br /&gt;
Update: I found today killing it once didn&#39;t work, but killing it a 2nd time (though I had photobooth up to test the camera - that might&#39;ve had something to do with it) worked.&amp;nbsp; Still better than a reboot.</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/8836789281487745481/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/8836789281487745481' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/8836789281487745481'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/8836789281487745481'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2018/08/psa-restarting-your-macbookpro-camera.html' title='PSA - Restarting your MacbookPro camera without rebooting'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-5114880667095625325</id><published>2018-06-18T13:49:00.002-07:00</published><updated>2018-06-18T13:49:43.769-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="oauth"/><category scheme="http://www.blogger.com/atom/ns#" term="omniauth"/><category scheme="http://www.blogger.com/atom/ns#" term="omniauth-twitter"/><category scheme="http://www.blogger.com/atom/ns#" term="rails"/><category scheme="http://www.blogger.com/atom/ns#" term="twitter"/><title type='text'>PSA - Fixing Omniauth Rails app with Twitter Oauth started failing -  OAuth::Unauthorized 403 Forbidden Error</title><content type='html'>Just a a PSA for those with Rails apps using Omniauth-Twitter who may have noticed that &lt;i&gt;Sign in with Twitter&lt;/i&gt; authentication now fails with a 403.&amp;nbsp; I found the answer via this &lt;a href=&quot;https://stackoverflow.com/questions/50826742/omniauth-twitter-with-rails-5-stopped-working-oauthunauthorized-403-forbidden&quot; target=&quot;_blank&quot;&gt;stackoverflow post&lt;/a&gt;.&amp;nbsp; For my app in particular it was due to &lt;a href=&quot;https://twittercommunity.com/t/action-required-sign-in-with-twitter-users-must-whitelist-callback-urls/105342&quot; target=&quot;_blank&quot;&gt;Twitter&#39;s decision to only allow apps to whitelist callback URLs&lt;/a&gt;.&amp;nbsp; If one follows many typical omniauth-twitter tutorials, one leverages the ability of the apps to override the callback URL - i.e you can test with localhost:3000 but deploy to whatever real URL and the app override&#39;s the callback URL.&amp;nbsp; Per the stackoverflow post, I supplied 2 URLs, the base app URL and the &lt;base app=&quot;&quot; url=&quot;&quot;&gt;&lt;/base&gt;/auth/twitter/callback both with https. I also noticed that the callback locking and allow application to be used with &lt;i&gt;Sign in with Twitter&lt;/i&gt; checkboxes were unchecked and checked those.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1_U5-iBKEi7ms8SEuuaDO1mRok5gNJ5YkkpxyxPaHPFZDMzu-Be-8PJXgVlFhvicRM1wJsvMPdbwN9wpT-sqpQR6261CKtyIElPmwFaBhMTjA2Rsb9W8MU7QOjoAGQPNNm6uVtw/s1600/twitter_oauth.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;83&quot; data-original-width=&quot;809&quot; height=&quot;65&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1_U5-iBKEi7ms8SEuuaDO1mRok5gNJ5YkkpxyxPaHPFZDMzu-Be-8PJXgVlFhvicRM1wJsvMPdbwN9wpT-sqpQR6261CKtyIElPmwFaBhMTjA2Rsb9W8MU7QOjoAGQPNNm6uVtw/s640/twitter_oauth.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/5114880667095625325/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/5114880667095625325' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/5114880667095625325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/5114880667095625325'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2018/06/psa-fixing-omniauth-rails-app-with.html' title='PSA - Fixing Omniauth Rails app with Twitter Oauth started failing -  OAuth::Unauthorized 403 Forbidden Error'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1_U5-iBKEi7ms8SEuuaDO1mRok5gNJ5YkkpxyxPaHPFZDMzu-Be-8PJXgVlFhvicRM1wJsvMPdbwN9wpT-sqpQR6261CKtyIElPmwFaBhMTjA2Rsb9W8MU7QOjoAGQPNNm6uVtw/s72-c/twitter_oauth.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-2643986871861059337</id><published>2018-01-30T16:05:00.001-08:00</published><updated>2019-04-18T15:58:32.054-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="psa"/><category scheme="http://www.blogger.com/atom/ns#" term="salesforce"/><category scheme="http://www.blogger.com/atom/ns#" term="til"/><title type='text'>PSA: TIL how to stop Salesforce from truncating your debug logs</title><content type='html'>A tip for anyone who might need it. Those who have used the&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt; System.debug()&lt;/span&gt; call will have noticed that it truncates the output. A workaround is to convert the data to JSON with&amp;nbsp; a &lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;JSON.serialize()&lt;/span&gt;&amp;nbsp; call.&lt;br /&gt;
&lt;br /&gt;
So instead of&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;System.debug(haccIdList);&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Do this&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;System.debug(JSON.serialize(haccIdList));&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Answer found &lt;a href=&quot;https://salesforce.stackexchange.com/questions/116502/console-log-truncates-my-debug&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Additional Search words: salesforce trucates logs, full salesforce output, System.debug&lt;br /&gt;
&lt;br /&gt;
UPDATED:&lt;br /&gt;
&lt;br /&gt;
As of the&lt;a href=&quot;https://releasenotes.docs.salesforce.com/en-us/spring19/release-notes/rn_forcecom_developer_console.htm&quot; target=&quot;_blank&quot;&gt; Spring 2019 update&lt;/a&gt; this no longer works and the debug log is truncated.&amp;nbsp; The solution is to open the raw log file to see it was original found &lt;a href=&quot;https://salesforce.stackexchange.com/questions/255527/system-debugjson-serializeo-not-longer-shows-full-string&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;&amp;nbsp;but is mentioned in the release notes.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/2643986871861059337/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/2643986871861059337' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/2643986871861059337'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/2643986871861059337'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2018/01/psa-til-how-to-stop-salesforce-from.html' title='PSA: TIL how to stop Salesforce from truncating your debug logs'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-6598551895243710702</id><published>2017-10-06T13:03:00.001-07:00</published><updated>2017-10-06T13:20:33.757-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="hyperloop"/><category scheme="http://www.blogger.com/atom/ns#" term="jdd"/><category scheme="http://www.blogger.com/atom/ns#" term="opal"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="save ruby"/><title type='text'>RejectConf, Saving Ruby, JDD</title><content type='html'>&lt;div id=&quot;content&quot;&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline1&quot;&gt;
&lt;h2 id=&quot;orgheadline1&quot;&gt;
The 1st ever RejectConf&lt;/h2&gt;
&lt;h2 id=&quot;orgheadline1&quot;&gt;
&lt;div id=&quot;content&quot; style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline1&quot;&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline1&quot;&gt;
So at RubyConf 2006 in Denver Colorado,&amp;nbsp;&lt;a href=&quot;https://twitter.com/the_zenspider&quot;&gt;Ryan Davis&lt;/a&gt;&amp;nbsp;organized the first&amp;nbsp;&lt;a href=&quot;http://juixe.com/techknow/index.php/2006/10/29/rubyconf-first-annual-rejectconf/&quot;&gt;RejectConf&lt;/a&gt;&amp;nbsp;- an opportunity to present for people whose conference proposals were rejected. I think there a few more RejectConfs were organized at various Ruby related conferences. RejectConfs got renamed as Lightning Talks, becaming an official conference slot at many Ruby related conferences. In my experience, Lightning Talks an opportunity to see talks that got rejected by the conference commitee. Very often there&#39;s really good talks. Capped at a short time (generally 5 minutes), it allows one to sample many different topics. Definitely worthwhile attending one when at a conference&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/h2&gt;
&lt;h2 id=&quot;orgheadline2&quot;&gt;
Reevaluating the ROI on writing proposals&lt;/h2&gt;
&lt;h2&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline2&quot;&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline2&quot;&gt;
I write a number of conference proposals a year. I spend a fair amount of time on writing proposals. At least an hour, frequently a good amount more - because I do want them to be accepted. I propose a number of different topics with a lot of frequency and have been doing so since 2006, but I don&#39;t really have good success ratio. (See my email screenshot below). While versions of some of the these talks do get presented at&amp;nbsp;&lt;a href=&quot;https://www.meetup.com/ocruby/&quot;&gt;OCRuby,&lt;/a&gt;&amp;nbsp;the local Ruby Users Group that I run, I find myself reevaluating the ROI in writing proposals. Apparently I&#39;m not good at writing them.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRx-hz1zRzbzP1ZCOdzqiBf0aTGgj5vwKO3DAagLNJAgOGj0Qme2GpJk5VNc-PdSuO4Lp6STZlJFJVJoAx0pcxGzCWaJNh8MzlyTgYMNRHlAxKovSXC24W1iUDGPYJThYNH4WzyA/s1600/Pasted_Image_10_6_17__12_26_PM.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;946&quot; data-original-width=&quot;1197&quot; height=&quot;504&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRx-hz1zRzbzP1ZCOdzqiBf0aTGgj5vwKO3DAagLNJAgOGj0Qme2GpJk5VNc-PdSuO4Lp6STZlJFJVJoAx0pcxGzCWaJNh8MzlyTgYMNRHlAxKovSXC24W1iUDGPYJThYNH4WzyA/s640/Pasted_Image_10_6_17__12_26_PM.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;span id=&quot;goog_948099706&quot;&gt;&lt;/span&gt;&lt;span id=&quot;goog_948099707&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/h2&gt;
&lt;h2 id=&quot;orgheadline3&quot;&gt;
The Overlying Theme - Saving Ruby and JDD&lt;/h2&gt;
&lt;h2&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline3&quot;&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline3&quot;&gt;
A few years ago, I realized the underlying theme of nearly all presentations I make - conference, meetup, is along the lines of &quot;Ongoing Joy Driven Development (JDD) for someone who loves Ruby.&quot; I love to code, I love Ruby and I want to keep on doing it for a long time. To support this theme I&#39;ve explored a lot of &quot;less than mainstream&quot; Ruby and/Ruby-esque technology to aid me in continuinge to be a &quot;Happily employed Rubyist&quot; indefinitely. Being a Happy Programmer is the Ruby Way. As someone who is a passionate about being a happy programmer I want to give back - spread the joy - thus ongoing efforts to do so. Part of that story is the notion - &quot;Save Ruby&quot; - Mainstream Ruby isn&#39;t hotbed of growth and innovation it once was. In many areas hot and up and coming areas of technology Ruby isn&#39;t applicable or even considered - that&#39;s bad for people who want to keep doing Ruby professionally. I want to help address that.&lt;br /&gt;
As a person of limited resources, I have to evaluate the best use my time, and I&#39;m thinking perhaps I should blog more instead of submitting proposals. Hopefully blogging, maybe some screencasts help help me spread the word compared to all the hours that go into proposals that never get seen by many people. So I thought I&#39;d just include my 3 proposals for RubyConf this year in their entirety, with hopes of spreading the message. Please tell if any of topics are of interest and I&#39;ll write more on them.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/h2&gt;
&lt;h2 id=&quot;orgheadline16&quot;&gt;
Proposals&lt;/h2&gt;
&lt;h3 id=&quot;orgheadline4&quot;&gt;
Title - COMPS - The All Ruby Isomorphic Application Architecture&lt;/h3&gt;
&lt;h3 id=&quot;orgheadline5&quot;&gt;
Abstract&lt;/h3&gt;
&lt;h2&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline16&quot;&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline16&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-orgheadline4&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-orgheadline5&quot;&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgheadline5&quot;&gt;
Building big apps is a big problem. There&#39;s complexity on the frontend, complexity on backend, and one has to link the 2 together.&lt;br /&gt;
As popluar as React is, which has several comprehensive solutions for the frontend, there still no integrated front/backend framework (think Meteor) for React for JS.&lt;br /&gt;
COMPS - Components, Operations, Models, Policies, Stores is not only the 1st integrated front/backend architecture for React, but is also an all Ruby solution.&lt;br /&gt;
Build your big apps with the best that React and Rails have to offer in an integrated all Ruby architecture. For the Rubyist Joy, Productivity, Familiarity in 1 package&lt;br /&gt;
front backend, on front end many options flux, redux, mobx&lt;br /&gt;
A solution, ALl ruby&lt;br /&gt;
Hinging both front and back&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/h2&gt;
&lt;h3 id=&quot;orgheadline6&quot;&gt;
Details&lt;/h3&gt;
&lt;h2&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot;&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-orgheadline6&quot;&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgheadline6&quot;&gt;
When webapps were primarily server rendered pages will small amounts of AJAX, Rails was a sublime solution. It still is. Rails is omokase, a carefully selected package that was designed to fit together, with a beautiful, programmer happiness inducing Ruby DSL. One thing that continues to bring, joy, productivity, and maintainability to Rails application is that &quot;there&#39;s a place for everything.&quot;&lt;br /&gt;
Fast forward to today, where SPAs (Single Page Applications) are common place and Javascript rules the heap with a vibrantly expanding, but ever chaotic ecosystem that promises things such as Isomorphic code (running on both ends), Rails and thus Ruby is less relevant. One can integrate React.js with Ruby on Rails, but it&#39;s still largely duct taped together, there&#39;s no built integration. On top of that there 2 languates, 2 paradigms, 2 tool sets - a costly integration.&lt;br /&gt;
COMPS is the architecture that is offered by ruby-hyperloop, a framework that integrates React.js on the frontend with Ruby on Rails on the backend via a single Ruby DSL. Like Rails, there&#39;s a place for everything. Components deliver interactive user experiences, Operations encapsulate business logic, Models magically synchronize data between clients and servers, Policies govern authorization and Stores hold local state.&lt;br /&gt;
Also like Rails, it is unified in a single Ruby DSL. Ruby is used to write front end logic, backend logic, logic that is shared by both front and backend and even markup via the React.rb DSL that can be rendered on both server and client side. As a Ruby framework, the toolset is that of Ruby, so there&#39;s a single, stable toolset which Rubyists already know.&lt;br /&gt;
For Ruby web developers, it is a route to continued relevance and employability in a world where server rendered Ruby webapps are having less and less relevance.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/h2&gt;
&lt;h3 id=&quot;orgheadline7&quot;&gt;
Pitch&lt;/h3&gt;
&lt;h2&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot;&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-orgheadline7&quot;&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgheadline7&quot;&gt;
In a technology landscape where SPAs, speed, scaleability, concurrency, etc. are the hot topics, Ruby and Rails are less and less relevant. COMPS provides an all Ruby path for Ruby based web developers to stay relevant, productive, employable while continuing to enjoy the Joy of Ruby.&lt;br /&gt;
I am a core committer and contributor to aforementioned and related technologies and a would be evangelist for keeping Rubyist happy and future employable.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/h2&gt;
&lt;h3 id=&quot;orgheadline8&quot;&gt;
Title - Is Ruby dying? What&#39;s a Rubyist to do?&lt;/h3&gt;
&lt;h3 id=&quot;orgheadline9&quot;&gt;
Abstract&lt;/h3&gt;
&lt;h2&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot;&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-orgheadline8&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-orgheadline9&quot;&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgheadline9&quot;&gt;
The language we love is fading, reduced #s of: conferences, projects, commits, job positions. It&#39;s dropped out of the IEEE Spectrum top 10, and is being dropped by numerous code schools,&lt;br /&gt;
While reports of Ruby&#39;s demise are greatly exaggerated, where there&#39;s smoke, there&#39;s fire. What&#39;s Ruby&#39;s relevance in these hot areas in tech:&lt;br /&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Front end web frameworks&lt;/li&gt;
&lt;li&gt;Isomorphic code&lt;/li&gt;
&lt;li&gt;Mobile&lt;/li&gt;
&lt;li&gt;Scaling, speed, size, paralleism/concurrency&lt;/li&gt;
&lt;/ul&gt;
The typical answer is that Ruby is not. It&#39;s little known that Ruby or Ruby-esque solutions exist in these categories. There is a future off the beaten path!&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/h2&gt;
&lt;h3 id=&quot;orgheadline10&quot;&gt;
Details&lt;/h3&gt;
&lt;h2&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot;&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-orgheadline10&quot;&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgheadline10&quot;&gt;
This talk will go over not typically known Ruby and/or Ruby-esque solutions to the tech areas in which the world at large feels Ruby has little to no relevance. The desired outcome is to educate Rubyists on paths that can lead to their future happiness and employability.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/h2&gt;
&lt;h3 id=&quot;orgheadline11&quot;&gt;
Pitch&lt;/h3&gt;
&lt;h2&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot;&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-orgheadline11&quot;&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgheadline11&quot;&gt;
I love Ruby the language, it&#39;s library and community. It&#39;s given me years of joyful employment and I&#39;ve been trying to give back at every opportunity. While I&#39;ve been trying to explore, create, spread, and evangelize the &quot;Future of Ruby&quot; for a while now, seeing this year that Ruby has dropped out of the IEEE Spectrum top 10 and that code schools are dropping Ruby has convince me that it is still worth trying to show the Ruby community that there is a future for Ruby and Ruby-esque solutions. Hopefully the message can be heard, else we all switch to being Javascript programmers.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/h2&gt;
&lt;h3 id=&quot;orgheadline12&quot;&gt;
Title - The Web is better in Ruby&lt;/h3&gt;
&lt;h3 id=&quot;orgheadline13&quot;&gt;
Abstract&lt;/h3&gt;
&lt;h2&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot;&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-orgheadline12&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-orgheadline13&quot;&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgheadline13&quot;&gt;
Look at where web tech has evolved towards.&lt;br /&gt;
HTML: HTML is a bad programming language, thus: erb, haml, JSX. Rails introduced partials coz there&#39;s no extract method for HTML.&lt;br /&gt;
CSS: SASS, LESS were invented to make CSS a real programming language: inheritance, reuse, variables, etc.&lt;br /&gt;
Javascript: Many made their own JS classes, then ES6 made classes official.&lt;br /&gt;
All 3 technologies are evolving to be OO programming languages. What if they could all be modeled by a single language. One can do all 3 as JS, but it&#39;s not a great OO language. Did you know you can already do them all as Ruby, &amp;amp; it&#39;s good?&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/h2&gt;
&lt;h3 id=&quot;orgheadline14&quot;&gt;
Details&lt;/h3&gt;
&lt;h2&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot;&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-orgheadline14&quot;&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgheadline14&quot;&gt;
Web technology is a jumble of different languages that somehow manages to work together. It is unlikey that Tim Berners-Lee would have imagined how web technology would&#39;ve evolved from what he initially invented.&lt;br /&gt;
As web programming approaches and tools have evolved they are reaching more towards becoming Object Oriented programming languages.&lt;br /&gt;
Markup: The web world has re-learned what the Java world learned decades ago, that XML is a bad as programming language (i.e. Ant). Libraries like erb, haml, slim etc, try to add programming to HTML, and a such are popular. Libraries like markaby, paggio, builder bring the full power of Ruby to markup, leveraging on Ruby&#39;s DSL abilities to make Ruby look something like haml or slim.&lt;br /&gt;
Rails added partials to solve cut and paste of HTML. If HTML were a real programming language, one could refactor.&lt;br /&gt;
Css: SASS and LESS were invented to make Css a real programming language. SASS brings variables, nesting, partials, imports, mixins, inheritance, operators. As such it&#39;s used very widely. It should be no surprise that SASS&#39;s creator was a Rubyist.&lt;br /&gt;
Javascript: Many libraries implemented classes, then ES6 made those classes official. Unfortunately the Javascript world is divided classes and Object Oriend, some love ES6 classes, others think it&#39;s the worst addition. As such, Javascript isn&#39;t a particularly good Object Oriented language.&lt;br /&gt;
Since the 3 main web technologies are evolving towards being Object Oriented programming languages, it would be nice to have a single language to express them. This trend has been happening in the Javascript world, where esp. the React.js folk are trying to express everything in Javascript.&lt;br /&gt;
However, Ruby is both a better Object Oriented language, fulling embracing the Object Oriented paradigm, and a has stronger DSL capabilities than Javascript. JSX was likely invented in part because Javascript cannot provide a DSL that looks like markup, Ruby can.&lt;br /&gt;
A Ruby based approach to modeling all 3 could be both more expressive and more beautiful. Similarly, Ruby being a very Object Oriented programming language, perhaps second only to Smalltalk, lends to Object Oriented solutions, not commonly done in Javascript simply because Javascript is not as Object Oriented a language.&lt;br /&gt;
This talk will explore how that would look and would be better and then show how the capability already exists and is being used.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/h2&gt;
&lt;h3 id=&quot;orgheadline15&quot;&gt;
Pitch&lt;/h3&gt;
&lt;h2&gt;
&lt;div style=&quot;font-size: medium; font-weight: normal;&quot;&gt;
&lt;div class=&quot;outline-2&quot;&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-orgheadline15&quot;&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgheadline15&quot;&gt;
The web is better in Ruby, which should make Rubyists happier and more productive. Combined with some other technologies, an all Ruby approach could allow Ruby based web developers to stay relevant and employable as server rendered webapps become less relevant.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;status&quot; id=&quot;postamble&quot; style=&quot;font-size: medium; font-weight: normal;&quot;&gt;
&lt;div class=&quot;author&quot; style=&quot;font-size: 14.4px; margin: 0.2em;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/6598551895243710702/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/6598551895243710702' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/6598551895243710702'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/6598551895243710702'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2017/10/rejectconf-saving-ruby-jdd.html' title='RejectConf, Saving Ruby, JDD'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRx-hz1zRzbzP1ZCOdzqiBf0aTGgj5vwKO3DAagLNJAgOGj0Qme2GpJk5VNc-PdSuO4Lp6STZlJFJVJoAx0pcxGzCWaJNh8MzlyTgYMNRHlAxKovSXC24W1iUDGPYJThYNH4WzyA/s72-c/Pasted_Image_10_6_17__12_26_PM.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-4120828180469703709</id><published>2017-09-14T15:08:00.002-07:00</published><updated>2017-09-14T15:08:30.826-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bjj"/><category scheme="http://www.blogger.com/atom/ns#" term="bjj_diary"/><category scheme="http://www.blogger.com/atom/ns#" term="martial_arts"/><title type='text'>BJJ diary 9/12/17</title><content type='html'>&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline11&quot;&gt;
&lt;h2 id=&quot;orgheadline11&quot;&gt;
Class&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline11&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-orgheadline3&quot;&gt;
&lt;h3 id=&quot;orgheadline3&quot;&gt;
Clock choke&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgheadline3&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-4&quot; id=&quot;outline-container-orgheadline1&quot;&gt;
&lt;h4 id=&quot;orgheadline1&quot;&gt;
Setup&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-orgheadline1&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;On left of turtle&lt;/li&gt;
&lt;li&gt;Left hand over, seat belt grip&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-4&quot; id=&quot;outline-container-orgheadline2&quot;&gt;
&lt;h4 id=&quot;orgheadline2&quot;&gt;
Action&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-orgheadline2&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Right hand guides opponent&#39;s right lapel to sink left hand in deep&lt;/li&gt;
&lt;li&gt;Right arm chicken wing opponent&#39;s OR grab opponent&#39;s left lapel w/right hand&lt;/li&gt;
&lt;li&gt;cinch tight, walk clockwise&lt;/li&gt;
&lt;li&gt;I found the other lapel tighter&lt;/li&gt;
&lt;li&gt;Can&#39;t really tell if choke is in until guy taps&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-orgheadline6&quot;&gt;
&lt;h3 id=&quot;orgheadline6&quot;&gt;
Turn into guard against clock choke&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgheadline6&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-4&quot; id=&quot;outline-container-orgheadline4&quot;&gt;
&lt;h4 id=&quot;orgheadline4&quot;&gt;
Setup&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-orgheadline4&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;turtled with opponent on top, with clock choke grep&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-4&quot; id=&quot;outline-container-orgheadline5&quot;&gt;
&lt;h4 id=&quot;orgheadline5&quot;&gt;
Action&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-orgheadline5&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;turn into him to guard, or half guard&lt;/li&gt;
&lt;li&gt;If he stays connected he gets rolled&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-orgheadline10&quot;&gt;
&lt;h3 id=&quot;orgheadline10&quot;&gt;
Specific Training&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgheadline10&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-4&quot; id=&quot;outline-container-orgheadline7&quot;&gt;
&lt;h4 id=&quot;orgheadline7&quot;&gt;
Setup&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-orgheadline7&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;One guy in turtle, one guy on back&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-4&quot; id=&quot;outline-container-orgheadline8&quot;&gt;
&lt;h4 id=&quot;orgheadline8&quot;&gt;
Action&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-orgheadline8&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Guy on bottom tries to get to guard&lt;/li&gt;
&lt;li&gt;Guy on top takes back or submits&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-4&quot; id=&quot;outline-container-orgheadline9&quot;&gt;
&lt;h4 id=&quot;orgheadline9&quot;&gt;
Insights&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-orgheadline9&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Turning into guard works well&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline12&quot;&gt;
&lt;h2 id=&quot;orgheadline12&quot;&gt;
Sparring&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline12&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Bobby&#39;s knee shield hard to pass, unable to get around fast enough, or get pulled back in to 1/2 guard before finishing pass&lt;/li&gt;
&lt;li&gt;Got a feel of what electric chair feels like, able to pull leg out before too late&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/4120828180469703709/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/4120828180469703709' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/4120828180469703709'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/4120828180469703709'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2017/09/bjj-diary-91217.html' title='BJJ diary 9/12/17'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-2414349586912642602</id><published>2017-09-12T13:59:00.000-07:00</published><updated>2017-09-12T13:59:13.505-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bjj"/><category scheme="http://www.blogger.com/atom/ns#" term="bjj_diary"/><category scheme="http://www.blogger.com/atom/ns#" term="martial_arts"/><title type='text'>BJJ Diary 9/11/17</title><content type='html'>&lt;br /&gt;
&lt;div class=&quot;status&quot; id=&quot;postamble&quot; style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;div id=&quot;content&quot; style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
Instead of just taking notes for myself, I decided to put these notes in a blog in case they are of any use to anyone else.&lt;br /&gt;
&lt;br /&gt;
YIL (yesterday I learned)&lt;br /&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline10&quot;&gt;
&lt;h2 id=&quot;orgheadline10&quot;&gt;
Class&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline10&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-orgheadline3&quot;&gt;
&lt;h3 id=&quot;orgheadline3&quot;&gt;
Gravity Throw&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgheadline3&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-4&quot; id=&quot;outline-container-orgheadline1&quot;&gt;
&lt;h4 id=&quot;orgheadline1&quot;&gt;
Setup&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-orgheadline1&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Left hand grips elbow&lt;/li&gt;
&lt;li&gt;Right hand grabs same side collar&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-4&quot; id=&quot;outline-container-orgheadline2&quot;&gt;
&lt;h4 id=&quot;orgheadline2&quot;&gt;
Action&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-orgheadline2&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Circle left&lt;/li&gt;
&lt;li&gt;Drop, left foot can block is right foot&lt;/li&gt;
&lt;li&gt;Right leg butterfly hook throws&lt;/li&gt;
&lt;li&gt;Come to mount or kesa gatame&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-orgheadline6&quot;&gt;
&lt;h3 id=&quot;orgheadline6&quot;&gt;
Turtle Escape 1&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgheadline6&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-4&quot; id=&quot;outline-container-orgheadline4&quot;&gt;
&lt;h4 id=&quot;orgheadline4&quot;&gt;
Setup&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-orgheadline4&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Opponent on top, North/South style, with seat belt grip&lt;/li&gt;
&lt;li&gt;Stays in position&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-4&quot; id=&quot;outline-container-orgheadline5&quot;&gt;
&lt;h4 id=&quot;orgheadline5&quot;&gt;
Action&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-orgheadline5&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Sit to guard&lt;/li&gt;
&lt;li&gt;Head up, guard choke&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Head down gives guillotine&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;If can, can put fist in throat to pry head out if he doen&#39;t let go of heads&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-orgheadline9&quot;&gt;
&lt;h3 id=&quot;orgheadline9&quot;&gt;
Turtle Escape 2&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgheadline9&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-4&quot; id=&quot;outline-container-orgheadline7&quot;&gt;
&lt;h4 id=&quot;orgheadline7&quot;&gt;
Setup&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-orgheadline7&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;like above but circling to your right side&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-4&quot; id=&quot;outline-container-orgheadline8&quot;&gt;
&lt;h4 id=&quot;orgheadline8&quot;&gt;
Action&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-orgheadline8&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Fall to left shoulder, shoulder needs to be low to have space&lt;/li&gt;
&lt;li&gt;Get knee or foot in&lt;/li&gt;
&lt;li&gt;Turn to guard&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline14&quot;&gt;
&lt;h2 id=&quot;orgheadline14&quot;&gt;
Sparring&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline14&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-orgheadline11&quot;&gt;
&lt;h3 id=&quot;orgheadline11&quot;&gt;
Don&#39;t let heavier guard passer secure belt&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgheadline11&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Gives him grips&lt;/li&gt;
&lt;li&gt;Makes it hard to to use legs as frames&lt;/li&gt;
&lt;li&gt;Happened when I pulled a closer guard on Matt&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-orgheadline12&quot;&gt;
&lt;h3 id=&quot;orgheadline12&quot;&gt;
Technical standup is an option to stopping guard pass&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgheadline12&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;In response to above, I had a hard time keeping him at correct distance until I stood up&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-orgheadline13&quot;&gt;
&lt;h3 id=&quot;orgheadline13&quot;&gt;
Protect face when going for armbar&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgheadline13&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Got backfisted in the eye by Alex when hitting the armbar&lt;/li&gt;
&lt;li&gt;If going for opponents right arm, left hand in front of face ad right grabs his arm, if hand comes loose, left hand catches&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/2414349586912642602/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/2414349586912642602' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/2414349586912642602'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/2414349586912642602'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2017/09/bjj-diary-91117.html' title='BJJ Diary 9/11/17'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-6085352359587641732</id><published>2017-08-03T17:59:00.001-07:00</published><updated>2017-08-03T18:03:58.635-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="alexa"/><category scheme="http://www.blogger.com/atom/ns#" term="cisco 9856HDC"/><category scheme="http://www.blogger.com/atom/ns#" term="Comcast Xfinity"/><category scheme="http://www.blogger.com/atom/ns#" term="cox cable"/><category scheme="http://www.blogger.com/atom/ns#" term="cox contour"/><category scheme="http://www.blogger.com/atom/ns#" term="IR"/><category scheme="http://www.blogger.com/atom/ns#" term="logitech"/><category scheme="http://www.blogger.com/atom/ns#" term="RF"/><category scheme="http://www.blogger.com/atom/ns#" term="universal remote"/><category scheme="http://www.blogger.com/atom/ns#" term="XiD-P"/><title type='text'>PSA: Logitech Remotes and Cox Contour 2 boxes</title><content type='html'>It took me a while to find a solution, so I thought I&#39;d make this hopefully a little more easier to find so others in the same boat can find it. I did find the solution from this &lt;a href=&quot;http://forums.cox.com/forum_home/tv_forum/f/4/t/15989.aspx&quot; target=&quot;_blank&quot;&gt;forum article&lt;/a&gt;. I recently upgraded from the old Cox Contour boxes to the new improved, and pretty spiffy w/voice control &lt;a href=&quot;https://www.cox.com/residential/tv/contour.html?campcode=flowlanding_contour_learn1_3_19052016085608#home&quot; target=&quot;_blank&quot;&gt;Cox Contour &lt;/a&gt;2. The new system is good, though the experience was terrible and I eventually hope find a way to give Cox the boot for their terrible practices. &amp;nbsp;I have among other universal remotes, the Logitech Harmony 650 remote and I wanted to set it up to be able to control the cable box/DVR. The model number on the box is a Cisco 9865HDC which the Logitech supported, so I plugged that in, but it didn&#39;t work. So then I tried to learn the remote keys, which the Logitech can also do, but nothing happened. From that I learned that the &lt;a href=&quot;https://www.cox.com/residential/support/contour-2-xr5-remote.html&quot; target=&quot;_blank&quot;&gt;Cox remote works on RF&lt;/a&gt;&amp;nbsp;- which is more efficient on the battery. I, as did some others thought that we were SOL as the Logitech is an IR universal remote, but it turns out that the Contour box can in fact be controlled by IR, but just not the generic (?) Cisco 9865HDC code. &amp;nbsp;Apparently the code that works is the Comcast Xfinity XiD-P (vs the Cox XiD-P which doesn&#39;t work). &amp;nbsp;Apparently Cox are using the same cable box technology.&lt;br /&gt;
&lt;br /&gt;
So now I&#39;m happily using my &lt;a href=&quot;https://www.amazon.com/gp/product/B004OVECU0/ref=as_li_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=B004OVECU0&amp;amp;linkCode=as2&amp;amp;tag=fkchang-20&amp;amp;linkId=41212e6fe16d19b8bd19b523b0d13c45&quot; target=&quot;_blank&quot;&gt;Logitech Harmony 650&lt;/a&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;1&quot; src=&quot;//ir-na.amazon-adsystem.com/e/ir?t=fkchang-20&amp;amp;l=am2&amp;amp;o=1&amp;amp;a=B004OVECU0&quot; style=&quot;border: none !important; margin: 0px !important;&quot; width=&quot;1&quot; /&gt; to control my Contour 2 box. I also used my Logitech to IR program my &lt;a href=&quot;https://www.amazon.com/gp/product/B072MF92S5/ref=as_li_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=B072MF92S5&amp;amp;linkCode=as2&amp;amp;tag=fkchang-20&amp;amp;linkId=9cf7fc364872f75705df9cb4b8992ff8&quot; target=&quot;_blank&quot;&gt;Broadlink RM Pro&lt;/a&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;1&quot; src=&quot;//ir-na.amazon-adsystem.com/e/ir?t=fkchang-20&amp;amp;l=am2&amp;amp;o=1&amp;amp;a=B072MF92S5&quot; style=&quot;border: none !important; margin: 0px !important;&quot; width=&quot;1&quot; /&gt; (which also doesn&#39;t recognize the cable box as Cisco) so I can control it from my &lt;a href=&quot;https://www.amazon.com/gp/product/B01DFKC2SO/ref=as_li_tl?ie=UTF8&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=B01DFKC2SO&amp;amp;linkCode=as2&amp;amp;tag=fkchang-20&amp;amp;linkId=c2092bfacec500f3e089c49b6aa3d4b7&quot; target=&quot;_blank&quot;&gt;Echo Dot&lt;/a&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; height=&quot;1&quot; src=&quot;//ir-na.amazon-adsystem.com/e/ir?t=fkchang-20&amp;amp;l=am2&amp;amp;o=1&amp;amp;a=B01DFKC2SO&quot; style=&quot;border: none !important; margin: 0px !important;&quot; width=&quot;1&quot; /&gt;&amp;nbsp;along with my TV.&lt;br /&gt;
&lt;br /&gt;
Hope this helps somebody!&lt;br /&gt;
&lt;br /&gt;
Search keywords (just repeated to hopefully give higher search index): Logitech, Harmony, 650, Cox Contour 2, Cisco 9856HDC, IR, RF, Universal remote</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/6085352359587641732/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/6085352359587641732' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/6085352359587641732'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/6085352359587641732'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2017/08/psa-logitech-remotes-and-cox-contour-2.html' title='PSA: Logitech Remotes and Cox Contour 2 boxes'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-2355576156430455763</id><published>2017-06-27T10:25:00.003-07:00</published><updated>2017-06-27T10:25:56.429-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="psa"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>PSA: fixing nokogiri compile errors after upgrading to Sierra</title><content type='html'>Hopefully bumping this up in the search to make it easier for others to find&lt;br /&gt;
&lt;br /&gt;
Long story short, I had to recompile nokogiri after upgrading to Sierra and I got errors like this&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;
warning: cast from &#39;unsigned char *&#39; to &#39;unsigned short *&#39; increases required alignment from 1 to 2 [-Wcast-align]&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&lt;/code&gt;It took a while to find the right answer for my situation, to include some false starts, ultimate the advice here solved it for me.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://stackoverflow.com/questions/39671424/gemloaderror-in-rails-application-due-to-nokogiri-gem&quot;&gt;https://stackoverflow.com/questions/39671424/gemloaderror-in-rails-application-due-to-nokogiri-gem&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
In short:&amp;nbsp;&lt;span style=&quot;background-color: white; color: #242729; font-family: Arial, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, sans-serif; font-size: 15px;&quot;&gt;I needed to reinstall nokogiri and link it to libxml2 in the appropriate MacOSX SDK directory.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;background-color: white; color: #242729; font-family: Arial, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, sans-serif; font-size: 15px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;pre class=&quot;lang-rb prettyprint prettyprinted&quot; style=&quot;background-color: #eff0f1; border: 0px; color: #393318; font-family: Consolas, Menlo, Monaco, &amp;quot;Lucida Console&amp;quot;, &amp;quot;Liberation Mono&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, &amp;quot;Courier New&amp;quot;, monospace, sans-serif; font-size: 13px; font-stretch: inherit; font-variant-numeric: inherit; line-height: inherit; margin-bottom: 1em; max-height: 600px; overflow: auto; padding: 5px; vertical-align: baseline; width: auto; word-wrap: normal;&quot;&gt;&lt;code style=&quot;border: 0px; font-family: Consolas, Menlo, Monaco, &amp;quot;Lucida Console&amp;quot;, &amp;quot;Liberation Mono&amp;quot;, &amp;quot;DejaVu Sans Mono&amp;quot;, &amp;quot;Bitstream Vera Sans Mono&amp;quot;, &amp;quot;Courier New&amp;quot;, monospace, sans-serif; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline; white-space: inherit;&quot;&gt;&lt;span class=&quot;pln&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;gem install nokogiri &lt;/span&gt;&lt;span class=&quot;pun&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;pln&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt; &lt;/span&gt;&lt;span class=&quot;pun&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;pln&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;pun&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;pln&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;xml2&lt;/span&gt;&lt;span class=&quot;pun&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;pln&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;pun&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;str&quot; style=&quot;border: 0px; color: #7d2727; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;/Applications/&lt;/span&gt;&lt;span class=&quot;typ&quot; style=&quot;border: 0px; color: #2b91af; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;Xcode&lt;/span&gt;&lt;span class=&quot;pun&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pln&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pun&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;typ&quot; style=&quot;border: 0px; color: #2b91af; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;Contents&lt;/span&gt;&lt;span class=&quot;pun&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;typ&quot; style=&quot;border: 0px; color: #2b91af; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;Developer&lt;/span&gt;&lt;span class=&quot;pun&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;typ&quot; style=&quot;border: 0px; color: #2b91af; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;Platforms&lt;/span&gt;&lt;span class=&quot;pun&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;typ&quot; style=&quot;border: 0px; color: #2b91af; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;MacOSX&lt;/span&gt;&lt;span class=&quot;pun&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;pln&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;pun&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;typ&quot; style=&quot;border: 0px; color: #2b91af; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;Developer&lt;/span&gt;&lt;span class=&quot;pun&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;typ&quot; style=&quot;border: 0px; color: #2b91af; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;SDKs&lt;/span&gt;&lt;span class=&quot;pun&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;typ&quot; style=&quot;border: 0px; color: #2b91af; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;MacOSX10&lt;/span&gt;&lt;span class=&quot;pun&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;lit&quot; style=&quot;border: 0px; color: #7d2727; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;12.sdk&lt;/span&gt;&lt;span class=&quot;pun&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;pln&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;usr&lt;/span&gt;&lt;span class=&quot;pun&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;pln&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;pun&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;pln&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;libxml2&lt;/span&gt;&lt;span class=&quot;pun&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;pln&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt; &lt;/span&gt;&lt;span class=&quot;pun&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;pln&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;pun&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;pln&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;pun&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;pln&quot; style=&quot;border: 0px; color: #303336; font-family: inherit; font-size: inherit; font-stretch: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; margin: 0px; padding: 0px; vertical-align: baseline;&quot;&gt;libraries&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/2355576156430455763/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/2355576156430455763' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/2355576156430455763'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/2355576156430455763'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2017/06/psa-fixing-nokogiri-compile-errors.html' title='PSA: fixing nokogiri compile errors after upgrading to Sierra'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-4778423998819120792</id><published>2017-06-01T15:38:00.001-07:00</published><updated>2017-06-01T15:38:16.817-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ftp"/><category scheme="http://www.blogger.com/atom/ns#" term="net::ftp"/><category scheme="http://www.blogger.com/atom/ns#" term="psa"/><category scheme="http://www.blogger.com/atom/ns#" term="troubleshooting"/><title type='text'>PSA: ftp default modes, linux and OSX</title><content type='html'>If you&#39;ve encountered the error&amp;nbsp;500 Illegal PORT command on something that worked on OSX (i.e. development environment), but failed on Linux (staging/production environments), I may have a fix for you. Linux FTP defaults to &lt;a href=&quot;http://www.serv-u.com/kb/1138/Active-and-Passive-FTP-Transfers-Defined&quot; target=&quot;_blank&quot;&gt;active mode&lt;/a&gt;, so you need to switch to passive mode for it to work as it did in development. It would seem that FTP defaults to passive mode on OSX (might be a BSD thing). &amp;nbsp;If for example you were using Ruby&#39;s Net::FTP.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot; style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot; style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #7cb8bb;&quot;&gt;Net&lt;/span&gt;::&lt;span style=&quot;color: #7cb8bb;&quot;&gt;FTP&lt;/span&gt;.open(&lt;span style=&quot;color: #7cb8bb;&quot;&gt;ENV&lt;/span&gt;[&lt;span style=&quot;color: #cc9393;&quot;&gt;&#39;FTP_HOSTNAME&#39;&lt;/span&gt;]) &lt;span style=&quot;color: #f0dfaf; font-weight: bold;&quot;&gt;do&lt;/span&gt; |ftp|
  ftp.login(&lt;span style=&quot;color: #7cb8bb;&quot;&gt;ENV&lt;/span&gt;[&lt;span style=&quot;color: #cc9393;&quot;&gt;&#39;FTP_USERNAME&#39;&lt;/span&gt;], &lt;span style=&quot;color: #7cb8bb;&quot;&gt;ENV&lt;/span&gt;[&lt;span style=&quot;color: #cc9393;&quot;&gt;&#39;FTP_PASSWORD&#39;&lt;/span&gt;])
  ftp.chdir(&lt;span style=&quot;color: #cc9393;&quot;&gt;&#39;incoming&#39;&lt;/span&gt;)
  ftp.list(&lt;span style=&quot;color: #cc9393;&quot;&gt;&#39;*.csv&#39;&lt;/span&gt;)
&lt;span style=&quot;color: #f0dfaf; font-weight: bold;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
Would fail on 500 Illegal PORT command, but it&#39;s e&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #7cb8bb;&quot;&gt;Net&lt;/span&gt;::&lt;span style=&quot;color: #7cb8bb;&quot;&gt;FTP&lt;/span&gt;.open(&lt;span style=&quot;color: #7cb8bb;&quot;&gt;ENV&lt;/span&gt;[&lt;span style=&quot;color: #cc9393;&quot;&gt;&#39;FTP_HOSTNAME&#39;&lt;/span&gt;]) &lt;span style=&quot;color: #f0dfaf; font-weight: bold;&quot;&gt;do&lt;/span&gt; |ftp|
  ftp.login(&lt;span style=&quot;color: #7cb8bb;&quot;&gt;ENV&lt;/span&gt;[&lt;span style=&quot;color: #cc9393;&quot;&gt;&#39;FTP_USERNAME&#39;&lt;/span&gt;], &lt;span style=&quot;color: #7cb8bb;&quot;&gt;ENV&lt;/span&gt;[&lt;span style=&quot;color: #cc9393;&quot;&gt;&#39;FTP_PASSWORD&#39;&lt;/span&gt;])
  ftp.chdir(&lt;span style=&quot;color: #cc9393;&quot;&gt;&#39;incoming&#39;&lt;/span&gt;)
  ftp.passive = &lt;span style=&quot;color: #dfaf8f;&quot;&gt;true&lt;/span&gt;
  ftp.list(&lt;span style=&quot;color: #cc9393;&quot;&gt;&#39;*.csv&#39;&lt;/span&gt;)
&lt;span style=&quot;color: #f0dfaf; font-weight: bold;&quot;&gt;end&lt;/span&gt;&lt;/pre&gt;
Make the corresponding switch to passive as appropriate to your system.&lt;br /&gt;
&lt;br /&gt;
Have a good day!</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/4778423998819120792/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/4778423998819120792' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/4778423998819120792'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/4778423998819120792'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2017/06/psa-ftp-default-modes-linux-and-osx.html' title='PSA: ftp default modes, linux and OSX'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-3664623205544651966</id><published>2017-05-27T03:26:00.003-07:00</published><updated>2017-05-27T03:26:28.631-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="jdd"/><category scheme="http://www.blogger.com/atom/ns#" term="opal"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby-fying javascript"/><title type='text'>Opening up the node ecosystem for Ruby - http example</title><content type='html'>&lt;div id=&quot;content&quot;&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline1&quot;&gt;
&lt;h2 id=&quot;orgheadline1&quot;&gt;
Non browser use of npm modules from Ruby&lt;/h2&gt;
&lt;h2 id=&quot;orgheadline1&quot;&gt;
&lt;div id=&quot;content&quot; style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline1&quot;&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline1&quot;&gt;
In my&amp;nbsp;&lt;a href=&quot;http://funkworks.blogspot.com/2017/05/require-nodejs-opening-entire-server.html&quot;&gt;last article,&lt;/a&gt;&amp;nbsp;I teased of the capability of&amp;nbsp;&lt;code&gt;require(&#39;nodejs&#39;)&lt;/code&gt;&amp;nbsp;to open up the entire node.js ecosystem to the Rubyist. While using npm modules from Opal in the browser via Webpack has been written about, no one has written about using npm modules from&amp;nbsp;&lt;a href=&quot;http://opalrb.org/&quot;&gt;Opal&lt;/a&gt;&amp;nbsp;on node.js.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/h2&gt;
&lt;h2 id=&quot;orgheadline2&quot;&gt;
Node module as a Javascript object&lt;/h2&gt;
&lt;h2&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline2&quot;&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline2&quot;&gt;
When using&amp;nbsp;&lt;code&gt;require()&lt;/code&gt;&amp;nbsp;in node, you will get back either a Javascript object or a function. Since handling a Javascript object from Opal is the easier situation, we&#39;ll start with an example of such&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/h2&gt;
&lt;h2 id=&quot;orgheadline3&quot;&gt;
Hello World with the http module&lt;/h2&gt;
&lt;h2&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline3&quot;&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline3&quot;&gt;
For the example, we will use the built in node module -&amp;nbsp;&lt;code&gt;http&lt;/code&gt;. The code:&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-javascript&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;http = require(&lt;span style=&quot;color: green;&quot;&gt;&#39;http&#39;&lt;/span&gt;)
&lt;span style=&quot;color: blue;&quot;&gt;var&lt;/span&gt; &lt;span style=&quot;color: #ba36a5;&quot;&gt;port&lt;/span&gt; = process.env.port || 1337;
http.createServer(&lt;span style=&quot;color: blue;&quot;&gt;function&lt;/span&gt;(&lt;span style=&quot;color: #ba36a5;&quot;&gt;req&lt;/span&gt;, &lt;span style=&quot;color: #ba36a5;&quot;&gt;res&lt;/span&gt;) {
  res.writeHead(200, { &lt;span style=&quot;color: green;&quot;&gt;&#39;Content-Type&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;text/plain&#39;&lt;/span&gt; });
  res.end(&lt;span style=&quot;color: green;&quot;&gt;&#39;Hello World\n&#39;&lt;/span&gt;);
}).listen(port);
&lt;/pre&gt;
&lt;/div&gt;
This example simply requires the http module and then uses&amp;nbsp;&lt;code&gt;http.createServer()&lt;/code&gt;&amp;nbsp;to create an http server that returns &quot;Hello World&quot; on port 1337.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/h2&gt;
&lt;h2 id=&quot;orgheadline4&quot;&gt;
Compiling Ruby to Javascript&lt;/h2&gt;
&lt;h2&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline4&quot;&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline4&quot;&gt;
Before we get started, we&#39;ll need to transpile the Ruby code into Javascript. While one can use opal to compile and run a ruby file on node (the default runner) i.e. like this:&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-bash&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;opal hello_world.rb
&lt;/pre&gt;
&lt;/div&gt;
with the current Opal verision (v0.11.0.rc1), it is better to compile to Javascript 1st and then run with node for these reasons:&lt;br /&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;You get a Javascript file that you can inspect - helpful for debugging.&amp;nbsp;&lt;code&gt;opal hello_world.rb&lt;/code&gt;&amp;nbsp;doesn&#39;t persist the compiled Javascript&lt;/li&gt;
&lt;li&gt;The NODE_PATH is set and not modifiable, so you won&#39;t be able to npm install packages. I may submit a pull request to fix this in the future.&lt;/li&gt;
&lt;li&gt;Because node is event driven, you need to to pass a -E if you DON&#39;T want node to exit after the Javascript is evaluated. This would be the case for applications that need to stay and respond to input&lt;/li&gt;
&lt;/ul&gt;
To automate the process to keep the developer happy, I suggest a Rakefile. As a project setup to explore this capability, I planned to make a number of experiments, each in their own files in the&amp;nbsp;&lt;code&gt;src&lt;/code&gt;&amp;nbsp;directory. My Rakefile dynamically creates a &quot;compile and run&quot; Rake task for every ruby file in the&amp;nbsp;&lt;code&gt;src&lt;/code&gt;&amp;nbsp;directory.&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&#39;opal&#39;&lt;/span&gt;

&lt;span style=&quot;color: #6434a3;&quot;&gt;Dir&lt;/span&gt;[&lt;span style=&quot;color: green;&quot;&gt;&#39;src/*.rb&#39;&lt;/span&gt;].each { |rb_file|
  desc &lt;span style=&quot;color: green;&quot;&gt;&quot;Build and run &lt;/span&gt;&lt;span style=&quot;color: #ba36a5;&quot;&gt;#{rb_file}&lt;/span&gt;&lt;span style=&quot;color: green;&quot;&gt;&quot;&lt;/span&gt;
  basename = &lt;span style=&quot;color: #6434a3;&quot;&gt;File&lt;/span&gt;.basename(rb_file, &lt;span style=&quot;color: green;&quot;&gt;&#39;.rb&#39;&lt;/span&gt;) 
  task basename &lt;span style=&quot;color: blue;&quot;&gt;do&lt;/span&gt;
    &lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;puts&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&quot;Building &lt;/span&gt;&lt;span style=&quot;color: #ba36a5;&quot;&gt;#{basename}&lt;/span&gt;&lt;span style=&quot;color: green;&quot;&gt;&quot;&lt;/span&gt;
    &lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;system&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&quot;opal -rconsole -Ec &lt;/span&gt;&lt;span style=&quot;color: #ba36a5;&quot;&gt;#{rb_file}&lt;/span&gt;&lt;span style=&quot;color: green;&quot;&gt; &amp;gt; &lt;/span&gt;&lt;span style=&quot;color: #ba36a5;&quot;&gt;#{basename}&lt;/span&gt;&lt;span style=&quot;color: green;&quot;&gt;.js&quot;&lt;/span&gt;
    &lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;puts&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&quot;\trunning&quot;&lt;/span&gt;
    &lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;system&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&#39;say running&#39;&lt;/span&gt;
    &lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;system&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&quot;node &lt;/span&gt;&lt;span style=&quot;color: #ba36a5;&quot;&gt;#{basename}&lt;/span&gt;&lt;span style=&quot;color: green;&quot;&gt;.js&quot;&lt;/span&gt;
  &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
}
&lt;/pre&gt;
&lt;/div&gt;
I put some debugging info to know what state the process was, to include an audio clue that the web server has started &quot;running.&quot;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/h2&gt;
&lt;h2 id=&quot;orgheadline5&quot;&gt;
Baby steps&lt;/h2&gt;
&lt;h2&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline5&quot;&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline5&quot;&gt;
To get started, let&#39;s require the module and examine the object. Since I require console in the opal compile line in the Rakefile, I have access to the console via&amp;nbsp;&lt;code&gt;$console&lt;/code&gt;. In Ruby (and with Opal as well), one typically uses the&amp;nbsp;&lt;code&gt;p()&lt;/code&gt;&amp;nbsp;method which calls the inspect() method of the object. Being that we will deal with a plain Javascript object which doesn&#39;t have a&amp;nbsp;&lt;code&gt;$inspect()&lt;/code&gt;&amp;nbsp;method like all Opal objects, we can&#39;t call that and want must use&amp;nbsp;&lt;code&gt;$console.log()&lt;/code&gt;&amp;nbsp;instead.&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&#39;nodejs&#39;&lt;/span&gt;

http = node_require(&lt;span style=&quot;color: green;&quot;&gt;&#39;http&#39;&lt;/span&gt;)

&lt;span style=&quot;color: #ba36a5;&quot;&gt;$console&lt;/span&gt;.log http
&lt;/pre&gt;
&lt;/div&gt;
Running that file will print out the contents of the http object, which looks like this on my system.&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-javascript&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;$ rake http_ex
Building http_ex
        running
{ IncomingMessage:
   { [Function: IncomingMessage]
     super_:
      { [Function: Readable]
        ReadableState: [Function: ReadableState],
        super_: [Object],
        _fromList: [Function: fromList] } },
  OutgoingMessage:
   { [Function: OutgoingMessage]
     super_:
      { [Function: Stream]
        super_: [Object],
        Readable: [Object],
        Writable: [Object],
        Duplex: [Object],
        Transform: [Object],
        PassThrough: [Object],
        Stream: [Circular] } },
  METHODS:
   [ &lt;span style=&quot;color: green;&quot;&gt;&#39;ACL&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;BIND&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;CHECKOUT&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;CONNECT&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;COPY&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;DELETE&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;GET&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;HEAD&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;LINK&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;LOCK&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;M-SEARCH&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;MERGE&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;MKACTIVITY&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;MKCALENDAR&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;MKCOL&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;MOVE&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;NOTIFY&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;OPTIONS&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;PATCH&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;POST&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;PROPFIND&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;PROPPATCH&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;PURGE&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;PUT&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;REBIND&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;REPORT&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;SEARCH&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;SUBSCRIBE&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;TRACE&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;UNBIND&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;UNLINK&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;UNLOCK&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;UNSUBSCRIBE&#39;&lt;/span&gt; ],
  Agent:
   { [Function: Agent]
     super_:
      { [Function: EventEmitter]
        EventEmitter: [Circular],
        usingDomains: &lt;span style=&quot;color: #d0372d;&quot;&gt;false&lt;/span&gt;,
        defaultMaxListeners: [Getter/Setter],
        init: [Function],
        listenerCount: [Function] },
     defaultMaxSockets: &lt;span style=&quot;color: #d0372d;&quot;&gt;Infinity&lt;/span&gt; },
  globalAgent:
   Agent {
     domain: &lt;span style=&quot;color: #d0372d;&quot;&gt;null&lt;/span&gt;,
     _events: { free: [Function] },
     _eventsCount: 1,
     _maxListeners: &lt;span style=&quot;color: #d0372d;&quot;&gt;undefined&lt;/span&gt;,
     defaultPort: 80,
     protocol: &lt;span style=&quot;color: green;&quot;&gt;&#39;http:&#39;&lt;/span&gt;,
     options: { path: &lt;span style=&quot;color: #d0372d;&quot;&gt;null&lt;/span&gt; },
     requests: {},
     sockets: {},
     freeSockets: {},
     keepAliveMsecs: 1000,
     keepAlive: &lt;span style=&quot;color: #d0372d;&quot;&gt;false&lt;/span&gt;,
     maxSockets: &lt;span style=&quot;color: #d0372d;&quot;&gt;Infinity&lt;/span&gt;,
     maxFreeSockets: 256 },
  ServerResponse: { [Function: ServerResponse] super_: { [Function: OutgoingMessage] super_: [Object] } },
  STATUS_CODES:
   { &lt;span style=&quot;color: green;&quot;&gt;&#39;100&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Continue&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;101&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Switching Protocols&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;102&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Processing&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;200&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;OK&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;201&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Created&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;202&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Accepted&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;203&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Non-Authoritative Information&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;204&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;No Content&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;205&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Reset Content&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;206&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Partial Content&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;207&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Multi-Status&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;208&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Already Reported&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;226&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;IM Used&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;300&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Multiple Choices&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;301&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Moved Permanently&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;302&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Found&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;303&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;See Other&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;304&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Not Modified&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;305&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Use Proxy&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;307&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Temporary Redirect&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;308&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Permanent Redirect&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;400&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Bad Request&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;401&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Unauthorized&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;402&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Payment Required&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;403&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Forbidden&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;404&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Not Found&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;405&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Method Not Allowed&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;406&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Not Acceptable&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;407&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Proxy Authentication Required&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;408&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Request Timeout&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;409&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Conflict&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;410&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Gone&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;411&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Length Required&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;412&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Precondition Failed&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;413&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Payload Too Large&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;414&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;URI Too Long&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;415&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Unsupported Media Type&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;416&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Range Not Satisfiable&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;417&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Expectation Failed&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;418&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;I\&#39;m a teapot&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;421&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Misdirected Request&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;422&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Unprocessable Entity&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;423&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Locked&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;424&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Failed Dependency&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;425&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Unordered Collection&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;426&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Upgrade Required&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;428&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Precondition Required&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;429&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Too Many Requests&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;431&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Request Header Fields Too Large&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;451&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Unavailable For Legal Reasons&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;500&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Internal Server Error&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;501&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Not Implemented&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;502&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Bad Gateway&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;503&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Service Unavailable&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;504&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Gateway Timeout&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;505&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;HTTP Version Not Supported&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;506&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Variant Also Negotiates&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;507&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Insufficient Storage&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;508&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Loop Detected&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;509&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Bandwidth Limit Exceeded&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;510&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Not Extended&#39;&lt;/span&gt;,
     &lt;span style=&quot;color: green;&quot;&gt;&#39;511&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;Network Authentication Required&#39;&lt;/span&gt; },
  _connectionListener: [Function: connectionListener],
  Server: { [Function: Server] super_: { [Function: Server] super_: [Object] } },
  createServer: [Function: createServer],
  ClientRequest: { [Function: ClientRequest] super_: { [Function: OutgoingMessage] super_: [Object] } },
  request: [Function: request],
  get: [Function: get] }
&lt;/pre&gt;
&lt;/div&gt;
So now that we&#39;ve confirmed that we have a way to require node modules into Opal, we just need to manipulate the Javascript objects. The basic techniques of accessing Javascript from Opal that we will be using have been written about&amp;nbsp;&lt;a href=&quot;http://funkworks.blogspot.com/2015/06/accessing-javascript-from-opal.html&quot;&gt;here&lt;/a&gt;.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/h2&gt;
&lt;h2 id=&quot;orgheadline6&quot;&gt;
Simplest thing that could possibly work&lt;/h2&gt;
&lt;h2&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline6&quot;&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline6&quot;&gt;
To duplicate the original in the simplest way possible, we could call the original javascript via x-strings (the Opal mechanism for invoking arbitrary Javascript), like such.&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&#39;nodejs&#39;&lt;/span&gt;

http = node_require(&lt;span style=&quot;color: green;&quot;&gt;&#39;http&#39;&lt;/span&gt;)

port = 1337
&lt;span style=&quot;color: green;&quot;&gt;`&lt;/span&gt;
&lt;span style=&quot;color: green;&quot;&gt;http.createServer(function(req, res) {&lt;/span&gt;
&lt;span style=&quot;color: green;&quot;&gt;  res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/plain&#39; });&lt;/span&gt;
&lt;span style=&quot;color: green;&quot;&gt;  res.end(&#39;Hello World\n&#39;);&lt;/span&gt;
&lt;span style=&quot;color: green;&quot;&gt;}).listen(port);&lt;/span&gt;
&lt;span style=&quot;color: green;&quot;&gt;`&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
Run the Rake task and then visit&amp;nbsp;&lt;a href=&quot;http://localhost:1337/&quot;&gt;http://localhost:1337/&lt;/a&gt;&amp;nbsp;with your browser and you&#39;ll get back &quot;Hello World.&quot;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/h2&gt;
&lt;h2 id=&quot;orgheadline7&quot;&gt;
Making it all Ruby&lt;/h2&gt;
&lt;h2&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline7&quot;&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline7&quot;&gt;
Now while that works, that&#39;s not particularly satisfying. In some cases it may be totally appropriate you invoke Javascript from Opal, but let&#39;s go beyond that and keep all the code in Ruby. We can use Opal&#39;s&amp;nbsp;&lt;code&gt;JS&lt;/code&gt;&amp;nbsp;mechanism to call functions and attributes on the Javascript object without resorting to x-strings. As explained in the&amp;nbsp;&lt;a href=&quot;http://funkworks.blogspot.com/2015/06/accessing-javascript-from-opal.html&quot;&gt;aforementioned document&lt;/a&gt;&amp;nbsp;methods in Opal when compiled to Javascript are prefixed with $ to maintain a non colliding namespace w/existing methods on Javascript objects. The&amp;nbsp;&lt;code&gt;JS&lt;/code&gt;&amp;nbsp;mechanism allows us to call the methods on the Javascript objects without prepending a $,&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&#39;nodejs&#39;&lt;/span&gt;

http = node_require(&lt;span style=&quot;color: green;&quot;&gt;&#39;http&#39;&lt;/span&gt;)
port = 1337

http.&lt;span style=&quot;color: #6434a3;&quot;&gt;JS&lt;/span&gt;.createServer(&lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;lambda&lt;/span&gt; { |req, res|
                       res.&lt;span style=&quot;color: #6434a3;&quot;&gt;JS&lt;/span&gt;.writeHead(200, { &lt;span style=&quot;color: green;&quot;&gt;&#39;Content-Type&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;text/plain&#39;&lt;/span&gt; }.to_n)
                       res.&lt;span style=&quot;color: #6434a3;&quot;&gt;JS&lt;/span&gt;.end(&lt;span style=&quot;color: green;&quot;&gt;&quot;Hello World\n&quot;&lt;/span&gt;)
                     }).&lt;span style=&quot;color: #6434a3;&quot;&gt;JS&lt;/span&gt;.listen(port)
&lt;/pre&gt;
&lt;/div&gt;
So now it&#39;s all Ruby, but it&#39;s is somewhat annoying. We have to use the .JS feature 4 times, and we have to call&amp;nbsp;&lt;code&gt;to_n()&lt;/code&gt;&amp;nbsp;on the Hash so that&amp;nbsp;&lt;code&gt;res.writeHead()&lt;/code&gt;&amp;nbsp;can handle it properly. While String, Numeric, and Array objects in Opal are implemented directly with the corresponding Javascript types, Hash requires more to support all the features of Ruby&#39;s Hash thus we need to use&amp;nbsp;&lt;code&gt;to_n()&lt;/code&gt;&amp;nbsp;to convert it back to a plan Javascript objects when passing to native Javascript functions. Needing to track this level of detail feels un Ruby like. What&#39;s a solution? One option is to use&amp;nbsp;&lt;code&gt;Native()&lt;/code&gt;call to wrap the Javascript object so that we can just call methods and attributes like it was a Ruby object (also described in the&amp;nbsp;&lt;a href=&quot;http://funkworks.blogspot.com/2015/06/accessing-javascript-from-opal.html&quot;&gt;aforementioned document&lt;/a&gt;).&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&#39;nodejs&#39;&lt;/span&gt;
&lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&#39;native&#39;&lt;/span&gt;

http = Native(node_require(&lt;span style=&quot;color: green;&quot;&gt;&#39;http&#39;&lt;/span&gt;))

port = 1337
http.createServer(&lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;lambda&lt;/span&gt; { |req, res|
                    opal_res = Native(res)
                    opal_res.writeHead(200, { &lt;span style=&quot;color: green;&quot;&gt;&#39;Content-Type&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;text/plain&#39;&lt;/span&gt; }.to_n)
                    opal_res.end(&lt;span style=&quot;color: green;&quot;&gt;&quot;Hello World\n&quot;&lt;/span&gt;)
                  }).listen(port)
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/h2&gt;
&lt;h2 id=&quot;orgheadline8&quot;&gt;
Wrapping Javascript code instead of calling it directly&lt;/h2&gt;
&lt;h2&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline8&quot;&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline8&quot;&gt;
That&#39;s somewhat better, no more uses of&amp;nbsp;&lt;code&gt;.JS&lt;/code&gt;, though we had to wrap the res object with&amp;nbsp;&lt;code&gt;Native()&lt;/code&gt;&amp;nbsp;to avoid using JS on on res. We also still have to convert the headers Hash. Again, it&#39;s decidedly un Ruby like to make one have to remember when to do things and when not. Uniformity of interfaces is something that Rubyists strive towards. It&#39;d be nicer if we didn&#39;t have to wrap or convert objects.&lt;br /&gt;
Let&#39;s Ruby-fy this code a bit more. Let&#39;s imagine a simpler interface. It would be nice to be able write something like this:&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;port = 1337

&lt;span style=&quot;color: #6434a3;&quot;&gt;HTTP&lt;/span&gt;::&lt;span style=&quot;color: #6434a3;&quot;&gt;Server&lt;/span&gt;.listen(port) { |req, res|
  res.writeHead(200, {&lt;span style=&quot;color: green;&quot;&gt;&#39;Content-Type&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;text/plain&#39;&lt;/span&gt;})
  res.end &lt;span style=&quot;color: green;&quot;&gt;&quot;Hello World\n&quot;&lt;/span&gt;
}
&lt;/pre&gt;
&lt;/div&gt;
To implement such an interface we could do something like this&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&#39;nodejs&#39;&lt;/span&gt;
&lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&#39;native&#39;&lt;/span&gt;

&lt;span style=&quot;color: blue;&quot;&gt;module&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;HTTP&lt;/span&gt;
  &lt;span style=&quot;color: #6434a3;&quot;&gt;HTTP_JS&lt;/span&gt; = Native(node_require(&lt;span style=&quot;color: green;&quot;&gt;&#39;http&#39;&lt;/span&gt;))
  &lt;span style=&quot;color: blue;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;Server&lt;/span&gt;
    &lt;span style=&quot;color: blue;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #ba36a5;&quot;&gt;self&lt;/span&gt;.&lt;span style=&quot;color: #006699;&quot;&gt;listen&lt;/span&gt;(port, &amp;amp;block)
      &lt;span style=&quot;color: #6434a3;&quot;&gt;HTTP_JS&lt;/span&gt;.createServer(&lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;lambda&lt;/span&gt; { |req_js, res_js|
                             block.call(Native(req_js), Native(res_js))
                           }).listen(port)

    &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
  &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
&lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;

port = 1337
&lt;span style=&quot;color: #6434a3;&quot;&gt;HTTP&lt;/span&gt;::&lt;span style=&quot;color: #6434a3;&quot;&gt;Server&lt;/span&gt;.listen(port) { |req, res|
  res.writeHead(200, {&lt;span style=&quot;color: green;&quot;&gt;&#39;Content-Type&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;text/plain&#39;&lt;/span&gt;}.to_n )
  res.end &lt;span style=&quot;color: green;&quot;&gt;&quot;Hello World\n&quot;&lt;/span&gt;
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/h2&gt;
&lt;h2 id=&quot;orgheadline9&quot;&gt;
Taking a cue from Rack&lt;/h2&gt;
&lt;h2&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-decoration-color: initial; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline9&quot;&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline9&quot;&gt;
Close, but no cigar, I still have to call a&amp;nbsp;&lt;code&gt;to_n()&lt;/code&gt;&amp;nbsp;on the headers. Let&#39;s step back a bit. The problems is that we are dealing come from trying to exactly parallel the original Javascript code: exposing additional Javascript objects from our initial method call, needing converting to matching data types to pass back to Javascript, etc.&lt;br /&gt;
Separating boiler plate from content, what do we actually care about in a web response? Primarily just return code, headers, and body. Let&#39;s take a cue from&amp;nbsp;&lt;a href=&quot;http://rack.github.io/&quot;&gt;Rack&#39;s&lt;/a&gt;&amp;nbsp;interface which focuses just on those values.&lt;br /&gt;
If rewrite the&amp;nbsp;&lt;code&gt;HTTP::Server.listen()&lt;/code&gt;&amp;nbsp;API to be more Rack like, it could look like this.&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #6434a3;&quot;&gt;HTTP&lt;/span&gt;::&lt;span style=&quot;color: #6434a3;&quot;&gt;Server&lt;/span&gt;.listen(port) { |req, res|
  [200, {&lt;span style=&quot;color: green;&quot;&gt;&#39;Content-Type&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;text/plain&#39;&lt;/span&gt;}, &lt;span style=&quot;color: green;&quot;&gt;&quot;Hello World\n&quot;&lt;/span&gt;]
}
&lt;/pre&gt;
&lt;/div&gt;
So here&#39;s one way of making that happen.&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&#39;nodejs&#39;&lt;/span&gt;
&lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&#39;native&#39;&lt;/span&gt;

&lt;span style=&quot;color: blue;&quot;&gt;module&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;HTTP&lt;/span&gt;
  &lt;span style=&quot;color: #6434a3;&quot;&gt;HTTP_JS&lt;/span&gt; = Native(node_require(&lt;span style=&quot;color: green;&quot;&gt;&#39;http&#39;&lt;/span&gt;))
  &lt;span style=&quot;color: blue;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;Server&lt;/span&gt;
    &lt;span style=&quot;color: blue;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #ba36a5;&quot;&gt;self&lt;/span&gt;.&lt;span style=&quot;color: #006699;&quot;&gt;listen&lt;/span&gt;(port, &amp;amp;block)
      &lt;span style=&quot;color: #6434a3;&quot;&gt;HTTP_JS&lt;/span&gt;.createServer(&lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;lambda&lt;/span&gt; { |req_js, res_js|
                             req_opal = Native(req_js)
                             res_opal = Native(res_js)
                             status, headers, body = block.call(req_opal,  res_opal)
                             res_opal.writeHead(status, headers.to_n)
                             res_opal.end(body)
                           }).listen(port)

    &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
  &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
&lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;

port = 1337
&lt;span style=&quot;color: #6434a3;&quot;&gt;HTTP&lt;/span&gt;::&lt;span style=&quot;color: #6434a3;&quot;&gt;Server&lt;/span&gt;.listen(port) { |req, res|
  [200, {&lt;span style=&quot;color: green;&quot;&gt;&#39;Content-Type&#39;&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;text/plain&#39;&lt;/span&gt;}, &lt;span style=&quot;color: green;&quot;&gt;&quot;Hello World\n&quot;&lt;/span&gt;]
}
&lt;/pre&gt;
&lt;/div&gt;
Much nicer. Direct, to the point and all in Ruby. It&#39;s the Ruby and the Rails way to let us focus on the problem we want solve and to leave the boiler plate up to the system to handle.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/h2&gt;
&lt;h2 id=&quot;orgheadline10&quot;&gt;
Thus endeth the chapter&lt;/h2&gt;
&lt;h2&gt;
&lt;div style=&quot;font-size: medium; font-weight: normal;&quot;&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline10&quot;&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline10&quot;&gt;
Admittedly this example is both simplistic and unrealistic. One could do better than to wrapping the&amp;nbsp;&lt;code&gt;http&lt;/code&gt;&amp;nbsp;module to use from Opal, but it shows some mechanisms and an approach. Future articles will cover&lt;br /&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Less simplistic/more practical examples&lt;/li&gt;
&lt;li&gt;When node_require returns a Javascript function&lt;/li&gt;
&lt;/ul&gt;
Until then enjoy!&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/3664623205544651966/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/3664623205544651966' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/3664623205544651966'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/3664623205544651966'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2017/05/opening-up-node-ecosystem-for-ruby-http.html' title='Opening up the node ecosystem for Ruby - http example'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-7002050595683761838</id><published>2017-05-05T15:40:00.001-07:00</published><updated>2017-05-05T15:41:36.588-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="jdd"/><category scheme="http://www.blogger.com/atom/ns#" term="opal"/><category scheme="http://www.blogger.com/atom/ns#" term="require &#39;node.js&#39;"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby everywhere"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby-fying javascript"/><title type='text'>require &#39;nodejs&#39; - opening the entire server side node.js to Rubyist - in Ruby</title><content type='html'>I preface this with the&lt;a href=&quot;http://funkworks.blogspot.com/2017/05/taking-andrzejs-blogging-challenge-of.html&quot; target=&quot;_blank&quot;&gt; Roderick Disclaimer (scroll to the end)&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
I&#39;m going to spill the current &quot;best kept secret in Opal.&quot; The two words&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #dcdccc; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: #cc9393;&quot;&gt;&#39;nodejs&#39;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
has the ability open the entire server side Node.js ecosystem to Rubyists, in Ruby. For Rubyists, think about that.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://cdn.meme.am/instances/76828158.jpg#.WQz-bedX5n0.twitter&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://cdn.meme.am/instances/76828158.jpg#.WQz-bedX5n0.twitter&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
It&#39;s a little known fact&amp;nbsp;&lt;a href=&quot;http://ruby-hyperloop.io/tutorials/showcase/&quot;&gt;webpack&lt;/a&gt;&amp;nbsp;with Opal has opened up the npm ecosystem to Rubyists in Ruby on the browser. This fact is known and leveraged heavily by&amp;nbsp;&lt;a href=&quot;http://ruby-hyperloop.io/&quot;&gt;ruby-hyperloop.io&lt;/a&gt;&amp;nbsp;allowing one to transparently use React.js npm modules as Ruby object.&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;require &#39;nodejs&#39;&lt;/code&gt; on the other hand is not documented. You&#39;ll only find out about if you know where in the&amp;nbsp;&lt;a href=&quot;https://github.com/opal/opal&quot;&gt;opal source code&lt;/a&gt;&amp;nbsp;to look, or if you ask the right person the right question.&lt;br /&gt;
&lt;br /&gt;
I&#39;m going to document this with a series articles showing the wrapping of a npm module to be used via Ruby DSL. I&#39;ll show techniques and approaches to enable it. Enjoy the journey.&lt;br /&gt;
&lt;br /&gt;
Rubyists can now enjoy the benefits of the juggernaut Javascript phenomenon outside the browser, happily via Ruby. Npm, prepare to be assimilated!&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://i.imgflip.com/1oielp.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;240&quot; src=&quot;https://i.imgflip.com/1oielp.jpg&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/7002050595683761838/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/7002050595683761838' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/7002050595683761838'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/7002050595683761838'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2017/05/require-nodejs-opening-entire-server.html' title='require &#39;nodejs&#39; - opening the entire server side node.js to Rubyist - in Ruby'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-7717218417876727433</id><published>2017-05-05T14:36:00.002-07:00</published><updated>2017-05-05T14:43:13.619-07:00</updated><title type='text'>Taking Andrzej&#39;s blogging challenge of sorts - and you should too</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://cdn-images-1.medium.com/max/800/1*cYK866CP_fzsJ-APGlc9cg.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; src=&quot;https://cdn-images-1.medium.com/max/800/1*cYK866CP_fzsJ-APGlc9cg.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
The best tech person I follow on Snapchat is&amp;nbsp;&lt;a href=&quot;https://twitter.com/andrzejkrzywda&quot; target=&quot;_blank&quot;&gt;Andrzej Krzywda&lt;/a&gt;. His efforts to make &lt;a href=&quot;https://medium.com/planet-arkency/snapchat-for-programmers-84f5aee42e1c&quot; target=&quot;_blank&quot;&gt;Snapchat for programmers&lt;/a&gt;&amp;nbsp;really changed my opinion on what Snapchat could be - that is it&#39;s own post. Long story short, Snapchat is not longer just entertainment for me. Today he snapped about blogging and programmer, and in participating in you Snap question, &amp;nbsp;we discussed a number of things privately.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I fit the profile of someone who blogs, but not as frequent as I want to. On Snapchat Andrzej talked a brought up a topic that struck a strong chord with me. There&#39;s substantial knowledge out there that never goes anywhere because some one doesn&#39;t write/blog about it. In our private discussion he asked me:&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;blockquote&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;how many blogposts did you write in 2017? could it be that you want to cover a topic really well and this limits you?&lt;/span&gt;&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
His question is really on the spot. I definitely want to write an article well, and usually don&#39;t have the time time get it done at that level I would like. &amp;nbsp;I might start, but I don&#39;t finish. Consequently, &amp;nbsp;I have a huge backlog of topics I want or wanted to write about that grows all the time. Aside from this perfectionist type issue, I believe the other part of the problem is that things I want to write about are deep. &amp;nbsp;Andrezj asked me what I meant by deep, and I gave him a couple of examples topics and he was very interested in those topics. This took me back to the point I noticed in his Snap, that this knowledge, which at least is of interest to him, is going no where unless it gets persisted outside my head.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
An a programmer who works with and contributes to open source, this is especially important to me. So much has been shared to me via code, blog posts, videos, etc., it&#39;s only fitting that I give back. I have the desire to do so, and hopefully have experiences worth sharing, so time to do something about it.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
Take the challenge!&lt;/h2&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Another other topic from Andrzej&#39;s Snap storm, was about getting the content out there. Blogging doesn&#39;t have to a the novel level effort. He presented an anecdote about someone he worked with who would put out timely blogs before and after lunch, showing what is possible. &amp;nbsp;This was revisited when Andrzej gave me this advice&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;blockquote&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;open your blog editor and this there and publish :) timebox to 10 mninutes, just your toughts. won&#39;t be perfect but 15 minutes from now more people will be able to read it :)&lt;/span&gt;&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
It struck me that I should do just that. Time boxing helps w/so many types of paralysis. 10 minutes, I could afford 10 minutes. &amp;nbsp;So I&#39;ll do it&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
Take the challenge!&lt;/h2&gt;
&lt;br /&gt;
&amp;nbsp;So this is not the topic he was asking about, but the first post by me in &amp;nbsp;accepting that challenge. &amp;nbsp;If your in the same boat as me, blogs, but much less than you would like to, you should too.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;
Take the challenge!&lt;/h2&gt;
&lt;br /&gt;
&lt;h4&gt;
The Roderick Disclaimer&lt;/h4&gt;
I should add a &quot;I want to get this info out there, so please excuse any mistakes made in haste&quot; disclaimer going forward. This disclaimer needs a name. I shall call it Roderick, because I have no better name and the time box is up&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/7717218417876727433/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/7717218417876727433' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/7717218417876727433'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/7717218417876727433'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2017/05/taking-andrzejs-blogging-challenge-of.html' title='Taking Andrzej&#39;s blogging challenge of sorts - and you should too'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-5023667099009946335</id><published>2017-03-20T12:18:00.000-07:00</published><updated>2017-03-20T12:49:05.241-07:00</updated><title type='text'></title><content type='html'>&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline1&quot;&gt;
&lt;h2 id=&quot;orgheadline1&quot;&gt;
A Positive note - I&#39;m on Team Hanna&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline1&quot;&gt;
This is not my usual faire, but I think in world that seems to be more and more divided and negative, a positive note is warranted. So let reaffirm my view of the future is not completely bleak. Also, I want to much deserved kudos, cuz that&#39;s just the kind of thing more people should do.&lt;br /&gt;
&lt;br /&gt;
My kids&#39; piano teacher, also my oldest sons&#39; former classmate&amp;nbsp;&lt;a href=&quot;https://www.hannaeyre.com/&quot;&gt;Hanna Eyre&lt;/a&gt;&amp;nbsp;got onto &quot;Team Adam&quot; on&amp;nbsp;&lt;a href=&quot;http://www.nbc.com/the-voice&quot;&gt;The Voice&lt;/a&gt;&amp;nbsp;last week.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline2&quot;&gt;
&lt;h2 id=&quot;orgheadline2&quot;&gt;
The Blind Audition&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline2&quot;&gt;
Here&#39;s her blind audition video:&lt;br /&gt;
&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;335&quot; src=&quot;https://www.youtube.com/embed/hmHQxaW6Eaw&quot; width=&quot;440&quot;&gt;&lt;/iframe&gt;&lt;br /&gt;
&lt;br /&gt;
Hanna did well - 3 out of 4 judges turned around. The judges were also impressed that Hanna is only 15 years old.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhe8I2a1Qx1YG9ZC6oEs8XhlHKmLj3JdbxiZDMXoVUFqto6c4ZEPr0GAUeiB9sb7vH2O8lmlUFzvuLvlkJ6CiHxVq8DQTpvb6ZBvWDBCIH5P9pEJ_-v_Aiir_2PNTsQoKkWlcZSuA/s1600/15_years_old.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;250&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhe8I2a1Qx1YG9ZC6oEs8XhlHKmLj3JdbxiZDMXoVUFqto6c4ZEPr0GAUeiB9sb7vH2O8lmlUFzvuLvlkJ6CiHxVq8DQTpvb6ZBvWDBCIH5P9pEJ_-v_Aiir_2PNTsQoKkWlcZSuA/s320/15_years_old.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyIV2KehGTe2QPBfnNWPnbXi19i4b3yXQlw5MX3IEspW_gblOIwUN2uBKb0AdM4EkBWAF07NQHK36LrXZZr2ffPtxZDK9tLeJK8MrU9Zp-n-O2z1voxLiV96UDzR863ojz4NRJKQ/s1600/wow_15.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;250&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyIV2KehGTe2QPBfnNWPnbXi19i4b3yXQlw5MX3IEspW_gblOIwUN2uBKb0AdM4EkBWAF07NQHK36LrXZZr2ffPtxZDK9tLeJK8MrU9Zp-n-O2z1voxLiV96UDzR863ojz4NRJKQ/s320/wow_15.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So before she gets famous, let me take the opportunity to tell you a few &quot;Things about Hanna you didn&#39;t know&quot;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline3&quot;&gt;
&lt;h2 id=&quot;orgheadline3&quot;&gt;
Talent&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline3&quot;&gt;
&lt;div class=&quot;figure&quot; style=&quot;padding: 1em;&quot;&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUqG8zmEP8OBDrg5m0MnIjJA4Sl6JnqyMl-DKvuAJqzFVDFNxQeSo7Sa4sSTZqq0EO4eZ79r4hwxqLkv5_LV0TLYrjrbPKAAOB8SJun9k1WAlKal8YDg0uka6PBp1Dl8Vyn7pyuw/s1600/miraculously_talented.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;203&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUqG8zmEP8OBDrg5m0MnIjJA4Sl6JnqyMl-DKvuAJqzFVDFNxQeSo7Sa4sSTZqq0EO4eZ79r4hwxqLkv5_LV0TLYrjrbPKAAOB8SJun9k1WAlKal8YDg0uka6PBp1Dl8Vyn7pyuw/s320/miraculously_talented.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Ok, so musical talent is something you probably DID know her. Adam Levine (I realize the pic has Blake, but I can&#39;t control when the subtitles show) called her &quot;miraculously talented&quot; just from listening to one song. Besides singing well, Hanna also plays and teaches piano. She is a student at the&amp;nbsp;&lt;a href=&quot;http://www.ocsarts.net/&quot;&gt;Orange County School of the Arts (OCSA)&lt;/a&gt;&amp;nbsp;- an audition based arts school where she eagerly soaking as much as the music program as she can. I remember her telling me about looking forward to composition classes and learning other instruments. So she is ever expanding here palette. Her sheer excitement over her opportunities is uplifting. She has been writing songs since she was 11, one of which won her 1st place in the Music category and 1st place overall at Mind the Gap, the 2013 TEDx Bommer Canyon competition.&lt;br /&gt;
&lt;div class=&quot;figure&quot; style=&quot;padding: 1em;&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXnrR104uuQ1vAtfQ5-YGDRC8jLxidGlYXCkc4FEafba2wCpZ6XzDTY3__hc2nfgqoWG5UlW4JKdt016AYPccqOUjr7QMCQSq3XtnU9m31MyaUE9hYX4Yl8d0jkEX-wdTQje3Z4w/s1600/good_voice.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;173&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXnrR104uuQ1vAtfQ5-YGDRC8jLxidGlYXCkc4FEafba2wCpZ6XzDTY3__hc2nfgqoWG5UlW4JKdt016AYPccqOUjr7QMCQSq3XtnU9m31MyaUE9hYX4Yl8d0jkEX-wdTQje3Z4w/s320/good_voice.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
Anyways, she&#39;s not just a good singer, more on this. Oh, and a reminder - only 15, she&#39;s just getting started&lt;br /&gt;
&lt;div class=&quot;figure&quot; style=&quot;padding: 1em;&quot;&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline4&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinlEchAZ4uOb3QNQUNK3dnuOIvFVD4AxlOh9KRKd8T5mICg46eWXlbYq1XLSoKb5czRNbVqz3WxgEHIafiuKisz2oSqIfNnbc0pEghSzNSMUneNWOIrmYrmmOeedIb0W0xh0emBg/s1600/gwen_15.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;194&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinlEchAZ4uOb3QNQUNK3dnuOIvFVD4AxlOh9KRKd8T5mICg46eWXlbYq1XLSoKb5czRNbVqz3WxgEHIafiuKisz2oSqIfNnbc0pEghSzNSMUneNWOIrmYrmmOeedIb0W0xh0emBg/s320/gwen_15.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h2 id=&quot;orgheadline4&quot;&gt;
Smart&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline4&quot;&gt;
Aside musically talented, she&#39;s smart cookie. She was in the all the &quot;smart kids classes&quot; along w/my son, so if she didn&#39;t take the musical route via OCSA, I have no doubt she&#39;d be tearing through honors and AP classes in high school, outside of her various musical pursuits.&lt;br /&gt;
Talented and smart? What else could you ask for?&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline5&quot;&gt;
&lt;h2 id=&quot;orgheadline5&quot;&gt;
Sweet&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline5&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCN9Zhagt8vW2MtWzHuOqlEzyQL9_vh8ajurXgOwpUuHyUNI4m5asBO7fx28vM4bAhHIRthL8kxFG-MbgjiXiQXJqHUGTnVBTv3N_TX6tPKnjLUeJR8TwvoJWPjQ2JWzKyfJy96Q/s1600/sweet_hanna.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;212&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCN9Zhagt8vW2MtWzHuOqlEzyQL9_vh8ajurXgOwpUuHyUNI4m5asBO7fx28vM4bAhHIRthL8kxFG-MbgjiXiQXJqHUGTnVBTv3N_TX6tPKnjLUeJR8TwvoJWPjQ2JWzKyfJy96Q/s320/sweet_hanna.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;figure&quot; style=&quot;padding: 1em;&quot;&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
She and my oldest son went to school together up until high school. Before I learned how musically talented she is, I remember a sweet, petite girl was who helped my son carry back large percussion pieces (remember the petite part?) back from the bus after an away performance. I was impressed at how helpful she was at a time most kids couldn&#39;t wait to go home after a long day out. She is genuinely a sweet soul.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-GFYxcU0h4DOvZUfh4zJEntI-SxEERDXLYvtiATfDr2kncYbORHj9LdNRJecVHf4ntliTRKKTrnh-SnXEokjpMhC0oKDKPehVyaTOr5sjXlc6EjEiojvOMO4TPUTaTMPq4Zo6kg/s1600/sparkly_talented_and_young.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;253&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-GFYxcU0h4DOvZUfh4zJEntI-SxEERDXLYvtiATfDr2kncYbORHj9LdNRJecVHf4ntliTRKKTrnh-SnXEokjpMhC0oKDKPehVyaTOr5sjXlc6EjEiojvOMO4TPUTaTMPq4Zo6kg/s320/sparkly_talented_and_young.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;figure&quot; style=&quot;padding: 1em;&quot;&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
Gwen Stefani mentioned &quot;sparkly&quot; - I think that&#39;s a good word.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline6&quot;&gt;
&lt;h2 id=&quot;orgheadline6&quot;&gt;
That Smile&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline6&quot;&gt;
&lt;div class=&quot;figure&quot; style=&quot;padding: 1em;&quot;&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYj9ujDdEbmmwG19-4ZW2BG3C4FLQit6fvMGTBZNHLL0F9h_uJKUuVJLsASMSn4GURKpAiZ0UkMOIN01wrjWkx5JWF5PSBr4p6hbHr3Tdb4a06hiDfWU8siJ-37GRa5G_Ub8aRFg/s1600/smile.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;203&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYj9ujDdEbmmwG19-4ZW2BG3C4FLQit6fvMGTBZNHLL0F9h_uJKUuVJLsASMSn4GURKpAiZ0UkMOIN01wrjWkx5JWF5PSBr4p6hbHr3Tdb4a06hiDfWU8siJ-37GRa5G_Ub8aRFg/s320/smile.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
Blake Shelton mentioned when she smiles &quot;the room lights up&quot; when she smiles, and later references her smile again &quot;stand there and do that and I&#39;ll buy your record.&quot; Hanna smiles a lot. It is an honest, joyous smile that is pretty infectious.&lt;br /&gt;
&lt;div class=&quot;figure&quot; style=&quot;padding: 1em;&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHEygStH8LRieIG4uwOahLgfPE2aOCw25W0lFg7K2U3fQZ7I1pPdwqFu1U2xGj9IFb8YiBjk_GFJ-7Cv6m8n7NBwhMvF0197Xosg8lVMxZGcqhMN3Sf6bQI9SHkqA9DubiyekupQ/s1600/room_lights_up.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;263&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHEygStH8LRieIG4uwOahLgfPE2aOCw25W0lFg7K2U3fQZ7I1pPdwqFu1U2xGj9IFb8YiBjk_GFJ-7Cv6m8n7NBwhMvF0197Xosg8lVMxZGcqhMN3Sf6bQI9SHkqA9DubiyekupQ/s320/room_lights_up.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline7&quot;&gt;
&lt;h2 id=&quot;orgheadline7&quot;&gt;
Music lessons and my kids&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline7&quot;&gt;
As mentioned before, Hanna teaches my kids piano. While I may some coincidental semblance the &quot;Asian Tiger parent&quot;, I&#39;m interested in music lessons NOT to get them into Juilliard, NOR as typical Asian &quot;piano and/or violin&quot; Tiger level training, because that&#39;s something some of us do. I love music, and I want them to have the opportunity to enjoy it. I have a friend who&#39;s mother taught piano, but he didn&#39;t want to learn it. He regretted setting the foundation younger in life as he tried to learn in his adulthood. I want to put that foundation in early, while&#39;s it&#39;s easier and they have the time build that skill. But most importantly, I want them to enjoy it.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline8&quot;&gt;
&lt;h2 id=&quot;orgheadline8&quot;&gt;
Talented teacher&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline8&quot;&gt;
While she clearly has talent as performer she is also a gifted teacher. My kids have had another teacher, but Hanna is a better fit for my musical goals. Firstly, Hanna loves music, it should be obvious, but I&#39;ll restate it. That comes through in her teaching, along with her normal &quot;sparkly&quot; enthusiasm. She loves music, and she wants you love music.&lt;br /&gt;
&lt;br /&gt;
Secondly, she&#39;s good at teaching kids (my kids range from 6-15 a pretty wide range). To start, she has seemingly unlimited patience, at least with my kids. I&#39;m told that might not be true for her siblings, but hey, she&#39;s human. I have recollection of less patient music teachers. Arguably anyone with longer attention spans should also benefit from her patience.She&#39;s also a kid herself, so there&#39;s a relate-ability there that maybe a 50 year old virtuoso might not have with kids. Her approach is non traditional in that she quickly makes the jump to songs the kids want to play after establishing a certain level of basics. This differs from a typical classical music based curriculum where the songs are often not what the children want to play&lt;br /&gt;
&lt;br /&gt;
What she did with my kids was to find a song they liked and then teach them to play it. My kids being very into computer games picked themes to various games that Hanna never heard before. Hanna would find them on YouTube with her iPhone and after a few listens turnaround and teach them. It&#39;s impressive to see how quickly she&#39;s able to learn the song and then make a suitable level piano arrangement on the fly. Getting quickly to a song they like is a rewarding and motivating way to teach. Some of her students take the more traditional classical music approach, as I noted from classical pieces in their recitals, so she can also teach that route, if desired. I know from talking with her, her approach to teaching mirrors her own progression from classical music to the contemporary music that she loved.&lt;br /&gt;
&lt;br /&gt;
I think an approach that explicitly follows the direction of &quot;music you like&quot; needs to be more prevalent. Like any skill, when music lessons become a chore, it&#39;s harder for most people to progress. A related anecdote, my wife, who loves music and singing, took piano lessons for several years, but pretty much forgot it all. Reason: she never learned songs she liked so she didn&#39;t stick with it. When I asked her why she didn&#39;t to go to a store like (the long defunct)&amp;nbsp;&lt;a href=&quot;https://en.wikipedia.org/wiki/Sam_Goody&quot;&gt;Sam Goody&lt;/a&gt;&amp;nbsp;and just buy the sheet music to songs she liked, her reply was she didn&#39;t know that was even a possibility. I&#39;m fortunate enough that I knew at a young age, that one could just learn to play songs they liked regardless of what they were being taught, but apparently it is not common knowledge.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline9&quot;&gt;
&lt;h2 id=&quot;orgheadline9&quot;&gt;
Deserving&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline9&quot;&gt;
So I think I&#39;ve been a #TeamHanna member before there was such a thing. I&#39;ve known for a long time that she would do well in whatever she pursued. she pursued. For those who don&#39;t know Hanna, if the video gives you the impression that she&#39;s awesome, know that it&#39;s true. Hard to think of someone more deserving of the success she&#39;s currently experiences. I wish her the best on the Voice and everything else she pursues. Hanna, if you read this, I hope this makes your day, because you deserve it. Keep living the dream and realize that this is the tip of the iceberg and it will all just keep going up. Don&#39;t listen to any haters that might come your way. May you inspire many other young people. Stay sparkly!&lt;br /&gt;
&lt;div class=&quot;figure&quot; style=&quot;padding: 1em;&quot;&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCcgeXu_90sTqfQy-UxPHEmvTRSGa_mQpcep5gtYl5-2U8Av1221i_GBafbHrKAgFDtrtkmjap2IJkWRvaAdrqLvEgaCXoDzQ-5UhZvvqSLzHgY1FFJK5D4cqyoc5QCF94y0vMig/s1600/only_the_tip.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;209&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhCcgeXu_90sTqfQy-UxPHEmvTRSGa_mQpcep5gtYl5-2U8Av1221i_GBafbHrKAgFDtrtkmjap2IJkWRvaAdrqLvEgaCXoDzQ-5UhZvvqSLzHgY1FFJK5D4cqyoc5QCF94y0vMig/s320/only_the_tip.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline10&quot;&gt;
&lt;h2 id=&quot;orgheadline10&quot;&gt;
Random Aside&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline10&quot;&gt;
So I&#39;m plenty backlogged on desired blog posts, but I just wanted to get a positive word out in a timely manner.&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/5023667099009946335/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/5023667099009946335' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/5023667099009946335'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/5023667099009946335'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2017/03/a-positive-note-im-on-team-hanna-this.html' title=''/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/hmHQxaW6Eaw/default.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-1347800718084132137</id><published>2017-02-02T14:07:00.000-08:00</published><updated>2017-02-02T14:07:47.570-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="24"/><category scheme="http://www.blogger.com/atom/ns#" term="fun"/><category scheme="http://www.blogger.com/atom/ns#" term="social media"/><category scheme="http://www.blogger.com/atom/ns#" term="twitter"/><title type='text'>A clever use of social media by @24fox</title><content type='html'>&lt;style type=&quot;text/css&quot;&gt;
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Calibri}
&lt;/style&gt;


&lt;br /&gt;
&lt;div class=&quot;p1&quot;&gt;
So I’m a 24 (the show) fan. &amp;nbsp;I see this in my tweet stream:&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;style type=&quot;text/css&quot;&gt;
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Calibri}
&lt;/style&gt;

&lt;br /&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;
&lt;div dir=&quot;ltr&quot; lang=&quot;en&quot;&gt;
Join the CTU — Tweet &lt;a href=&quot;https://twitter.com/24fox&quot;&gt;@24fox&lt;/a&gt; + ⏰ + &lt;a href=&quot;https://twitter.com/hashtag/24Legacy?src=hash&quot;&gt;#24Legacy&lt;/a&gt; to receive your badge! &lt;a href=&quot;https://t.co/I2ADUR4p4b&quot;&gt;pic.twitter.com/I2ADUR4p4b&lt;/a&gt;&lt;/div&gt;
— 24: Legacy (@24fox) &lt;a href=&quot;https://twitter.com/24fox/status/827240296408707072&quot;&gt;February 2, 2017&lt;/a&gt;&lt;/blockquote&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
So of course, I’m in. I tweet (trying to be slightly clever w/my wording) and 2 min later I get my badge.&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;p1&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;
&lt;div dir=&quot;ltr&quot; lang=&quot;en&quot;&gt;
&lt;a href=&quot;https://twitter.com/fkchang2000&quot;&gt;@fkchang2000&lt;/a&gt; The CTU could use someone like you. Catch the series premiere of &lt;a href=&quot;https://twitter.com/hashtag/24Legacy?src=hash&quot;&gt;#24Legacy&lt;/a&gt;, February 5 on &lt;a href=&quot;https://twitter.com/FOXTV&quot;&gt;@FOXTV&lt;/a&gt;. ⏰ &lt;a href=&quot;https://t.co/CeDAJJx9ut&quot;&gt;pic.twitter.com/CeDAJJx9ut&lt;/a&gt;&lt;/div&gt;
— 24: Legacy (@24fox) &lt;a href=&quot;https://twitter.com/24fox/status/827266876187086848&quot;&gt;February 2, 2017&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; charset=&quot;utf-8&quot; src=&quot;//platform.twitter.com/widgets.js&quot;&gt;&lt;/script&gt;
&lt;script async=&quot;&quot; charset=&quot;utf-8&quot; src=&quot;//platform.twitter.com/widgets.js&quot;&gt;&lt;/script&gt;



&lt;style type=&quot;text/css&quot;&gt;
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Calibri}
li.li1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Calibri}
ul.ul1 {list-style-type: disc}
ul.ul2 {list-style-type: circle}
&lt;/style&gt;


&lt;br /&gt;
&lt;div class=&quot;p1&quot;&gt;
So I think this is brilliant.&lt;/div&gt;
&lt;ul class=&quot;ul1&quot;&gt;
&lt;li class=&quot;li1&quot;&gt;I’m already a fan, and thus I follow&amp;nbsp;@24fox.&lt;/li&gt;
&lt;li class=&quot;li1&quot;&gt;Though I already know the new 24 reboot is airing right after Superbowl, I won’t be forgetting, make no doubt.&lt;/li&gt;
&lt;li class=&quot;li1&quot;&gt;I get to be immersed a bit more in the 24 “fantasy”. I can get a CTU badge simply by tweeting&lt;/li&gt;
&lt;ul class=&quot;ul2&quot;&gt;
&lt;li class=&quot;li1&quot;&gt;So of course, I do it. &amp;nbsp;ROI guaranteed.&lt;/li&gt;
&lt;/ul&gt;
&lt;li class=&quot;li1&quot;&gt;24 legacy gets advertised to my (paltry) twitter follower base, non 24 fans get some advertising that I happily buy into.&lt;/li&gt;
&lt;li class=&quot;li1&quot;&gt;I love my badge, it’s taped on the whiteboard to my left.&lt;/li&gt;
&lt;li class=&quot;li1&quot;&gt;Win win, I’m happy, they get more exposure&lt;/li&gt;
&lt;li class=&quot;li1&quot;&gt;If they choose to look, they can see which one of the fanbase will respond and follow directions - include 3 specific words in their reply. This might be useful data.&lt;/li&gt;
&lt;/ul&gt;
&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot;; font-size: 14px;&quot;&gt;Technology wise , it looks pretty simple. &amp;nbsp;It&#39;s almost certainly done with a twitter bot that looks for the specific 3 words tweeted to @24fox. When it gets such a tweet, it slaps the tweeter’s avatar and user name onto a CTU badge template, and then tweets the image with a random selection of canned response.&lt;/span&gt;&lt;span style=&quot;font-family: &amp;quot;calibri&amp;quot;; font-size: 14px;&quot;&gt;Very nice, hats of the 24 Legacy social media team&lt;/span&gt;&lt;br /&gt;
&lt;script async=&quot;&quot; charset=&quot;utf-8&quot; src=&quot;//platform.twitter.com/widgets.js&quot;&gt;&lt;/script&gt;
</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/1347800718084132137/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/1347800718084132137' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/1347800718084132137'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/1347800718084132137'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2017/02/p.html' title='A clever use of social media by @24fox'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-5167065743742420598</id><published>2016-06-02T17:58:00.000-07:00</published><updated>2016-06-30T11:27:31.929-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="opal"/><category scheme="http://www.blogger.com/atom/ns#" term="refactoring"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby-fying javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="tdd"/><title type='text'>WEWLJCIO - Working Effectively with Legacy Javascript Code in Opal</title><content type='html'>&lt;div id=&quot;content&quot;&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline1&quot;&gt;
&lt;h2 id=&quot;orgheadline1&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Background&lt;/span&gt;&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline1&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;I&#39;ve been working on&amp;nbsp;&lt;a href=&quot;https://github.com/fkchang/opal-hot-reloader&quot; target=&quot;_blank&quot;&gt;opal-hot-reloader&lt;/a&gt;, a hot reloader for&amp;nbsp;&lt;a href=&quot;http://opalrb.org/&quot; target=&quot;_blank&quot;&gt;Opal&lt;/a&gt;&amp;nbsp;applications including built in&amp;nbsp;&lt;a href=&quot;http://reactrb.org/&quot; target=&quot;_blank&quot;&gt;react.rb&lt;/a&gt;&amp;nbsp;support. I merged a pull request (thanks Brock!) that added hot css reloading. The code worked, but it was implemented primarily in Javascript and did not have tests. To make the code easier to read, maintain and extend, I wanted to both add tests and convert it to Ruby/Opal. In particular, I plan to extend the code to handle css served by the&amp;nbsp;&lt;a href=&quot;http://rubyonrails.org/&quot; target=&quot;_blank&quot;&gt;Ruby on Rails&lt;/a&gt;&amp;nbsp;pipeline so I want to shape the code to be more amenable to extension.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Now if this situation sounds a bit like&amp;nbsp;&lt;a href=&quot;http://c2.com/cgi/wiki?WorkingEffectivelyWithLegacyCode&quot; target=&quot;_blank&quot;&gt;Working Effectively With Legacy Code&lt;/a&gt;&amp;nbsp;by Michael Feathers, it should, and thus the title of this post. This particular situation does present a slightly different set of conditions than many refactorings, i.e.:&lt;/span&gt;&lt;br /&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The desire to convert languages - Javascript to Ruby (or transpiled Ruby via Opal). The interface between those Javascript and Opal objects in the browser affects how things need to proceed.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The predefined browser API and test doubles&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Hopefully, this article can bring some different insights for Opal developers.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline2&quot;&gt;
&lt;h2 id=&quot;orgheadline2&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Where to start?&lt;/span&gt;&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline2&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Let&#39;s look at the code. An additional&amp;nbsp;&lt;code&gt;if clause&lt;/code&gt;&amp;nbsp;was added to&amp;nbsp;&lt;code&gt;OpalHotReloader#reload()&lt;/code&gt;&amp;nbsp;that performs the css hot reloading on the client side. The functionality is implemented in Javascript via an Opal x-string.&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #d55e00;&quot;&gt;reload&lt;/span&gt;(e)
  &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #009e73; font-style: italic;&quot;&gt;original code&lt;/span&gt;
  reload_request = &lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;JSON&lt;/span&gt;.parse(&lt;span style=&quot;color: #848ea9;&quot;&gt;`e.data`&lt;/span&gt;)
  &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;if&lt;/span&gt; reload_request[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:type&lt;/span&gt;] == &lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;ruby&quot;&lt;/span&gt;
    &lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;puts&lt;/span&gt; &lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;Reloading ruby &lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{reload_request[:filename]}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;&lt;/span&gt;
    &lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;eval&lt;/span&gt; reload_request[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:source_code&lt;/span&gt;]
    &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;@reload_post_callback&lt;/span&gt;
      &lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;@reload_post_callback&lt;/span&gt;.call
    &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;else&lt;/span&gt;
      &lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;puts&lt;/span&gt; &lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;not reloading code&quot;&lt;/span&gt;
    &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
  &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
  &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #009e73; font-style: italic;&quot;&gt;the new css hot reloading code&lt;/span&gt;
  &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;if&lt;/span&gt; reload_request[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:type&lt;/span&gt;] == &lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;css&quot;&lt;/span&gt;
    url = reload_request[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:url&lt;/span&gt;]
    &lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;puts&lt;/span&gt; &lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;Reloading CSS: &lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{url}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;&lt;/span&gt;
    &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #009e73; font-style: italic;&quot;&gt;Work outsources Javascript via x-string&lt;/span&gt;
    &lt;span style=&quot;color: #848ea9;&quot;&gt;%x{&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;      var toAppend = &quot;t_hot_reload=&quot; + (new Date()).getTime();&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;      var links = document.getElementsByTagName(&quot;link&quot;);&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;      for (var i = 0; i &amp;lt; links.length; i++) {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;        var link = links[i];&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;        if (link.rel === &quot;stylesheet&quot; &amp;amp;&amp;amp; link.href.indexOf(&lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{url}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;) &amp;gt;= 0) {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;          if (link.href.indexOf(&quot;?&quot;) === -1) {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;            link.href += &quot;?&quot; + toAppend;&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;          } else {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;            if (link.href.indexOf(&quot;t_hot_reload&quot;) === -1) {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;              link.href += &quot;&amp;amp;&quot; + toAppend;&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;            } else {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;              link.href = link.href.replace(/t_hot_reload=\d{13}/, toAppend)&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;            }&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;          }&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;        }&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;      }&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;    }&lt;/span&gt;

  endx
&lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline3&quot;&gt;
&lt;h2 id=&quot;orgheadline3&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;First steps&lt;/span&gt;&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline3&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The first thing I noticed was the formerly smallish&amp;nbsp;&lt;code&gt;reload()&lt;/code&gt;&amp;nbsp;method had tripled in size and gained a new responsibilty - css hot reloading. I&#39;ll want to refactor that code out the body of the&amp;nbsp;&lt;code&gt;reload()&lt;/code&gt;&amp;nbsp;method as a method of a new class,&lt;code&gt;OpalHotReloader::CssReloader&lt;/code&gt;&amp;nbsp;dedicated to just css hot reloading (&lt;a href=&quot;https://en.wikipedia.org/wiki/Single_responsibility_principle&quot; target=&quot;_blank&quot;&gt;SRP&lt;/a&gt;). We&#39;ll instantiate this class instance as&lt;code&gt;@css_reloader&lt;/code&gt;&amp;nbsp;in the initializer for&amp;nbsp;&lt;code&gt;OpalHotReloader&lt;/code&gt;&amp;nbsp;and then delegate css hot reloading to that instance in&lt;code&gt;OpalHotReloader::CssReloader::reload()&lt;/code&gt;.&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #d55e00;&quot;&gt;reload&lt;/span&gt;(e)
  reload_request = &lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;JSON&lt;/span&gt;.parse(&lt;span style=&quot;color: #848ea9;&quot;&gt;`e.data`&lt;/span&gt;)
  &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;if&lt;/span&gt; reload_request[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:type&lt;/span&gt;] == &lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;ruby&quot;&lt;/span&gt;
    &lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;puts&lt;/span&gt; &lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;Reloading ruby &lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{reload_request[:filename]}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;&lt;/span&gt;
    &lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;eval&lt;/span&gt; reload_request[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:source_code&lt;/span&gt;]
    &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;if&lt;/span&gt; &lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;@reload_post_callback&lt;/span&gt;
      &lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;@reload_post_callback&lt;/span&gt;.call
    &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;else&lt;/span&gt;
      &lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;puts&lt;/span&gt; &lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;not reloading code&quot;&lt;/span&gt;
    &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
  &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
  &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;if&lt;/span&gt; reload_request[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:type&lt;/span&gt;] == &lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;css&quot;&lt;/span&gt;
    &lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;@css_reloader&lt;/span&gt;.reload(reload_request) &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #009e73; font-style: italic;&quot;&gt;extracted method called here&lt;/span&gt;
  &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
&lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline4&quot;&gt;
&lt;h2 id=&quot;orgheadline4&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;CssReloader&lt;/span&gt;&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline4&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;For our combination of&amp;nbsp;&lt;a href=&quot;http://refactoring.com/catalog/extractMethod.html&quot; target=&quot;_blank&quot;&gt;Extract Method&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a href=&quot;http://refactoring.com/catalog/extractClass.html&quot; target=&quot;_blank&quot;&gt;Extract Class&lt;/a&gt;, we simply relocated the code to a&amp;nbsp;&lt;code&gt;reload()&lt;/code&gt;&amp;nbsp;method of the new class. We don&#39;t have tests yet, so we test it manually. The code still works! Here is the code for the new class.&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;OpalHotReloader&lt;/span&gt;
  &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;CssReloader&lt;/span&gt;

    &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #d55e00;&quot;&gt;reload&lt;/span&gt;(reload_request)
      url = reload_request[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:url&lt;/span&gt;]
      &lt;span style=&quot;color: #848ea9;&quot;&gt;%x{&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;        var toAppend = &quot;t_hot_reload=&quot; + (new Date()).getTime();&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;        var links = document.getElementsByTagName(&quot;link&quot;);&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;        for (var i = 0; i &amp;lt; links.length; i++) {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;          var link = links[i];&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;          if (link.rel === &quot;stylesheet&quot; &amp;amp;&amp;amp; link.href.indexOf(&lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{url}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;) &amp;gt;= 0) {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;            if (link.href.indexOf(&quot;?&quot;) === -1) {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;              link.href += &quot;?&quot; + toAppend;&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;            } else {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;              if (link.href.indexOf(&quot;t_hot_reload&quot;) === -1) {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;                link.href += &quot;&amp;amp;&quot; + toAppend;&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;              } else {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;                link.href = link.href.replace(/t_hot_reload=\d{13}/, toAppend)&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;              }&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;            }&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;          }&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;        }&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;      }&lt;/span&gt;
    &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;

  &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
&lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline5&quot;&gt;
&lt;h2 id=&quot;orgheadline5&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Writing tests&lt;/span&gt;&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline5&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Now that we&#39;ve verified it still works as expected. We will write some tests. We&#39;ll use&amp;nbsp;&lt;a href=&quot;https://github.com/opal/opal-rspec&quot; target=&quot;_blank&quot;&gt;opal-rspec&lt;/a&gt;, which is a popular choice in the opal community and my preferred test framework for Ruby. From here on, I will be referring to the tests as specs since I&#39;m using RSpec.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Because of how we hot reload css via direct maninpulation of stylesheet links in the&amp;nbsp;&lt;code&gt;document&lt;/code&gt;, I was faced with the problem of how to set up a test. I could create stylesheet links in the actual DOM of spec runner (fairly easy to do), but I don&#39;t like the idea of calling out to methods the on the global&amp;nbsp;&lt;code&gt;document&lt;/code&gt;&amp;nbsp;object. I want to be able to inject a&amp;nbsp;&lt;i&gt;test document&lt;/i&gt;&amp;nbsp;for the spec, and inject the real&amp;nbsp;&lt;code&gt;document&lt;/code&gt;&amp;nbsp;for the actual application. Fortunately, we can dispense with standard dependency injection (constructor, setter, interface) techniques altogether and just pass the &quot;document&quot; in as a parameter to the method.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Here&#39;s where it gets little tricky. To do hot css reloading we have to manipulate the browser DOM via the global&amp;nbsp;&lt;code&gt;document&lt;/code&gt;object. This browser interface is not under my control, so we have to abide by this interface. Because of the interface between Opal objects and Javascript objects (some details described&amp;nbsp;&lt;a href=&quot;http://funkworks.blogspot.com/2015/06/accessing-javascript-from-opal.html&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;) we&#39;ll want to create suitable test doubles in pure Javascript. While opal-rspec gives you the full power of rspec&#39;s mock library, these test doubles are Opal objects which won&#39;t act the way the Javascript DOM objects I&#39;m looking to mock/stub out will. We&#39;ll need to create our own method of creating these test doubles.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;To create the doubles, I&#39;ve created two methods:&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;code&gt;create_link()&lt;/code&gt;&amp;nbsp;to create the link DOM object that will get altered to facillitate the css hot reloading and&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;code&gt;fake_links_document()&lt;/code&gt;&amp;nbsp;a convenience method which returns both a test double for global&amp;nbsp;&lt;code&gt;document&lt;/code&gt;&amp;nbsp;object, which responds to the&amp;nbsp;&lt;code&gt;getElementsByTagName(&#39;link&#39;)&lt;/code&gt;&amp;nbsp;call and a test double for the link itself, that I will inspect to see whether it has been correctly altered.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #d55e00;&quot;&gt;create_link&lt;/span&gt;( href)
  &lt;span style=&quot;color: #848ea9;&quot;&gt;%x|&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;  var ss = document.createElement(&quot;link&quot;);&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;  ss.type = &quot;text/css&quot;;&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;  ss.rel = &quot;stylesheet&quot;;&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;  ss.href = &lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{href}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;;&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;  return ss;&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;|&lt;/span&gt;
&lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;

&lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #d55e00;&quot;&gt;fake_links_document&lt;/span&gt;(href)
  link = create_link(href)
  doc = &lt;span style=&quot;color: #848ea9;&quot;&gt;`{ getElementsByTagName: function(name) { links = [ &lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{link}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;]; return links;}}`&lt;/span&gt;
  { &lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;link&lt;/span&gt;: link, &lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;document&lt;/span&gt;: doc}
&lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;To suport this new &quot;parameter injection&quot; we need to change the existing interface. We change the signature of the&lt;code&gt;OpalHotReloard::CssReloader#reload()&lt;/code&gt;&amp;nbsp;to take in the document&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #009e73; font-style: italic;&quot;&gt;from&lt;/span&gt;
&lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #d55e00;&quot;&gt;reload&lt;/span&gt;(reload_request) 
&lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #009e73; font-style: italic;&quot;&gt;to&lt;/span&gt;
&lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #d55e00;&quot;&gt;reload&lt;/span&gt;(reload_request, document)
&lt;/pre&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Then we call it with the new signature.&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #009e73; font-style: italic;&quot;&gt;in OpalHotReloader#reload()&lt;/span&gt;
&lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #009e73; font-style: italic;&quot;&gt;instead of calling it this way&lt;/span&gt;
&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;@css_reloader&lt;/span&gt;.reload(reload_request)
&lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #009e73; font-style: italic;&quot;&gt;we pass in the real browser document&lt;/span&gt;
&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;@css_reloader&lt;/span&gt;.reload(reload_request, &lt;span style=&quot;color: #848ea9;&quot;&gt;`document`&lt;/span&gt;)
&lt;/pre&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;The class at this point looks like this&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;OpalHotReloader&lt;/span&gt;
  &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;CssReloader&lt;/span&gt;

    &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #d55e00;&quot;&gt;reload&lt;/span&gt;(reload_request, document) &lt;span style=&quot;color: #5f7f5f;&quot;&gt;#  &lt;/span&gt;&lt;span style=&quot;color: #009e73; font-style: italic;&quot;&gt;pass in the &quot;document&quot;&lt;/span&gt;
      url = reload_request[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:url&lt;/span&gt;]
      &lt;span style=&quot;color: #848ea9;&quot;&gt;%x{&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;        var toAppend = &quot;t_hot_reload=&quot; + (new Date()).getTime();&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;        // invoke it here&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;        var links = &lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{document}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;.getElementsByTagName(&quot;link&quot;);&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;        for (var i = 0; i &amp;lt; links.length; i++) {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;          var link = links[i];&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;          if (link.rel === &quot;stylesheet&quot; &amp;amp;&amp;amp; link.href.indexOf(&lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{url}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;) &amp;gt;= 0) {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;            if (link.href.indexOf(&quot;?&quot;) === -1) {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;              link.href += &quot;?&quot; + toAppend;&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;            } else {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;              if (link.href.indexOf(&quot;t_hot_reload&quot;) === -1) {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;                link.href += &quot;&amp;amp;&quot; + toAppend;&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;              } else {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;                link.href = link.href.replace(/t_hot_reload=\d{13}/, toAppend)&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;              }&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;            }&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;          }&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;        }&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;      }&lt;/span&gt;
    &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;

  &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
&lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;We test out the new interface and it still works. Yay!&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline6&quot;&gt;
&lt;h2 id=&quot;orgheadline6&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Writing specs with the new interface&lt;/span&gt;&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline6&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Now we can write specs and inject our own test doubles for&amp;nbsp;&lt;code&gt;document&lt;/code&gt;. There are 3 cases we want to prove are handled correctly:&lt;/span&gt;&lt;br /&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;A plain stylesheet link where we add the hot reload argument for the first time.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Updating a link that has already been updated with a hot reload argument.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Appending an additional hot reload argument parameter to a stylesheet link that already has a parameter.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: #848ea9;&quot;&gt;&#39;native&#39;&lt;/span&gt;
&lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: #848ea9;&quot;&gt;&#39;opal_hot_reloader&#39;&lt;/span&gt;
&lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: #848ea9;&quot;&gt;&#39;opal_hot_reloader/css_reloader&#39;&lt;/span&gt;
describe &lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;OpalHotReloader&lt;/span&gt;::&lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;CssReloader&lt;/span&gt; &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;do&lt;/span&gt;

  &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #d55e00;&quot;&gt;create_link&lt;/span&gt;( href)
    &lt;span style=&quot;color: #848ea9;&quot;&gt;%x|&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;    var ss = document.createElement(&quot;link&quot;);&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;    ss.type = &quot;text/css&quot;;&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;    ss.rel = &quot;stylesheet&quot;;&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;    ss.href = &lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{href}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;;&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;    return ss;&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;  |&lt;/span&gt;
  &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;

  &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #d55e00;&quot;&gt;fake_links_document&lt;/span&gt;(href)
    link = create_link(href)
    doc = &lt;span style=&quot;color: #848ea9;&quot;&gt;`{ getElementsByTagName: function(name) { links = [ &lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{link}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;]; return links;}}`&lt;/span&gt;
    { &lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;link&lt;/span&gt;: link, &lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;document&lt;/span&gt;: doc}
  &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;


  context &lt;span style=&quot;color: #848ea9;&quot;&gt;&#39;Rack::Sass::Plugin&#39;&lt;/span&gt; &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;do&lt;/span&gt;
    it &lt;span style=&quot;color: #848ea9;&quot;&gt;&#39;should add t_hot_reload to a css path&#39;&lt;/span&gt; &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;do&lt;/span&gt;
      css_path = &lt;span style=&quot;color: #848ea9;&quot;&gt;&#39;stylesheets/base.css&#39;&lt;/span&gt;
      doubles = fake_links_document(css_path)
      link = Native(doubles[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:link&lt;/span&gt;])
      expect(link[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:href&lt;/span&gt;]).to match &lt;span style=&quot;color: #848ea9;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{Regexp.escape(css_path)}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;$/&lt;/span&gt;
      subject.reload({ &lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;url&lt;/span&gt;: css_path}, doubles[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:document&lt;/span&gt;])
      expect(link[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:href&lt;/span&gt;]).to match &lt;span style=&quot;color: #848ea9;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{Regexp.escape(css_path)}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;\?t_hot_reload=\d+/&lt;/span&gt;
    &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;

    it &lt;span style=&quot;color: #848ea9;&quot;&gt;&#39;should update t_hot_reload argument if there is one already&#39;&lt;/span&gt; &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;do&lt;/span&gt; 
      css_path = &lt;span style=&quot;color: #848ea9;&quot;&gt;&#39;stylesheets/base.css?t_hot_reload=1111111111111&#39;&lt;/span&gt;
      doubles = fake_links_document(css_path)
      link = Native(doubles[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:link&lt;/span&gt;])
      expect(link[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:href&lt;/span&gt;]).to match &lt;span style=&quot;color: #848ea9;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{Regexp.escape(css_path)}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;$/&lt;/span&gt;
      subject.reload({ &lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;url&lt;/span&gt;: css_path}, doubles[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:document&lt;/span&gt;])
      expect(link[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:href&lt;/span&gt;]).to match &lt;span style=&quot;color: #848ea9;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{Regexp.escape(&#39;stylesheets/base.css?t_hot_reload=&#39;)}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;(\d)+/&lt;/span&gt;
      expect(&lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;$1&lt;/span&gt;).to_not eq &lt;span style=&quot;color: #848ea9;&quot;&gt;&#39;1111111111111&#39;&lt;/span&gt;
    &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;

    it &lt;span style=&quot;color: #848ea9;&quot;&gt;&#39;should append t_hot_reload if there are existing arguments&#39;&lt;/span&gt; &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;do&lt;/span&gt;
      css_path = &lt;span style=&quot;color: #848ea9;&quot;&gt;&#39;stylesheets/base.css?some-arg=1&#39;&lt;/span&gt;
      doubles = fake_links_document(css_path)
      link = Native(doubles[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:link&lt;/span&gt;])
      expect(link[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:href&lt;/span&gt;]).to match &lt;span style=&quot;color: #848ea9;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{Regexp.escape(css_path)}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;$/&lt;/span&gt;
      subject.reload({ &lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;url&lt;/span&gt;: css_path}, doubles[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:document&lt;/span&gt;])
      expect(link[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:href&lt;/span&gt;]).to match &lt;span style=&quot;color: #848ea9;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{Regexp.escape(css_path)}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;\&amp;amp;t_hot_reload=(\d)+/&lt;/span&gt;
    &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
  &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;

&lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline7&quot;&gt;
&lt;h2 id=&quot;orgheadline7&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Specs pass - Safe to refactor&lt;/span&gt;&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline7&quot;&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Now that we have test coverage for the 3 cases, we can now rewrite the&amp;nbsp;&lt;code&gt;reload()&lt;/code&gt;&amp;nbsp;method in Ruby/Opal. The safety net of the newly writen specs will ensure that we do it correctly. For development, it will be handy to have both versions code side by side both for coding and testing. I did a little trick of having Javascript and Ruby versions of&amp;nbsp;&lt;code&gt;reload()&lt;/code&gt;&amp;nbsp;and then having the&amp;nbsp;&lt;code&gt;reload()&lt;/code&gt;&amp;nbsp;call either of those as needed. The code looked like this.&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: #848ea9;&quot;&gt;&#39;native&#39;&lt;/span&gt;
&lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;OpalHotReloader&lt;/span&gt;
  &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;CssReloader&lt;/span&gt;

    &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #d55e00;&quot;&gt;reload&lt;/span&gt;(reload_request, document)
      &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #009e73; font-style: italic;&quot;&gt;currently using the Ruby version&lt;/span&gt;
      reload_ruby(reload_request, document)
      &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #009e73; font-style: italic;&quot;&gt;reload_js(reload_request, document)&lt;/span&gt;
    &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;

    &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #d55e00;&quot;&gt;reload_ruby&lt;/span&gt;(reload_request, document)
      url = reload_request[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:url&lt;/span&gt;]
      &lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;puts&lt;/span&gt; &lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;Reloading CSS: &lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{url}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;&lt;/span&gt;
      to_append = &lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;t_hot_reload=&lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{Time.now.to_i}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;&lt;/span&gt;
      links = Native(&lt;span style=&quot;color: #848ea9;&quot;&gt;`document.getElementsByTagName(&quot;link&quot;)`&lt;/span&gt;)
      (0..links.length-1).each { |i|
        link = links[i]
        &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;if&lt;/span&gt; link.rel == &lt;span style=&quot;color: #848ea9;&quot;&gt;&#39;stylesheet&#39;&lt;/span&gt; &amp;amp;&amp;amp; link.href.index(url)
          &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;if&lt;/span&gt;  link.href !~ &lt;span style=&quot;color: #848ea9;&quot;&gt;/\?/&lt;/span&gt;
            link.href += &lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;?&lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{to_append}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;&lt;/span&gt;
          &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;else&lt;/span&gt;
            &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;if&lt;/span&gt; link.href !~ &lt;span style=&quot;color: #848ea9;&quot;&gt;/t_hot_reload/&lt;/span&gt;
              link.href += &lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{to_append}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;&lt;/span&gt;
            &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;else&lt;/span&gt;
              link.href = link.href.sub(&lt;span style=&quot;color: #848ea9;&quot;&gt;/t_hot_reload=\d{13}/&lt;/span&gt;, to_append)
            &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
          &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
        &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
      }
    &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;

    &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #d55e00;&quot;&gt;reload_js&lt;/span&gt;(reload_request, document)
      url = reload_request[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:url&lt;/span&gt;]
      &lt;span style=&quot;color: #848ea9;&quot;&gt;%x{&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;        var toAppend = &quot;t_hot_reload=&quot; + (new Date()).getTime();&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;        var links = &lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{document}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;.getElementsByTagName(&quot;link&quot;);&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;        for (var i = 0; i &amp;lt; links.length; i++) {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;          var link = links[i];&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;          if (link.rel === &quot;stylesheet&quot; &amp;amp;&amp;amp; link.href.indexOf(&lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{url}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;) &amp;gt;= 0) {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;            if (link.href.indexOf(&quot;?&quot;) === -1) {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;              link.href += &quot;?&quot; + toAppend;&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;            } else {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;              if (link.href.indexOf(&quot;t_hot_reload&quot;) === -1) {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;                link.href += &quot;&amp;amp;&quot; + toAppend;&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;              } else {&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;                link.href = link.href.replace(/t_hot_reload=\d{13}/, toAppend)&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;              }&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;            }&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;          }&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;        }&lt;/span&gt;
&lt;span style=&quot;color: #848ea9;&quot;&gt;      }&lt;/span&gt;
    &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;

  &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
&lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;We implement the Ruby version, a line by line translation, and the specs pass. Now that the Ruby version works, we don&#39;t need the Javascript version. We can remove the unnecessary code.&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: #848ea9;&quot;&gt;&#39;native&#39;&lt;/span&gt;
&lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;OpalHotReloader&lt;/span&gt;
  &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;CssReloader&lt;/span&gt;

    &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #d55e00;&quot;&gt;reload&lt;/span&gt;(reload_request, document)
      url = reload_request[&lt;span style=&quot;color: #d55e00; font-weight: bold;&quot;&gt;:url&lt;/span&gt;]
      &lt;span style=&quot;color: #0072b2; font-weight: bold;&quot;&gt;puts&lt;/span&gt; &lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;Reloading CSS: &lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{url}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;&lt;/span&gt;
      to_append = &lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;t_hot_reload=&lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{Time.now.to_i}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;&lt;/span&gt;
      links = Native(&lt;span style=&quot;color: #848ea9;&quot;&gt;`document.getElementsByTagName(&quot;link&quot;)`&lt;/span&gt;)
      (0..links.length-1).each { |i|
        link = links[i]
        &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;if&lt;/span&gt; link.rel == &lt;span style=&quot;color: #848ea9;&quot;&gt;&#39;stylesheet&#39;&lt;/span&gt; &amp;amp;&amp;amp; link.href.index(url)
          &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;if&lt;/span&gt;  link.href !~ &lt;span style=&quot;color: #848ea9;&quot;&gt;/\?/&lt;/span&gt;
            link.href += &lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;?&lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{to_append}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;&lt;/span&gt;
          &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;else&lt;/span&gt;
            &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;if&lt;/span&gt; link.href !~ &lt;span style=&quot;color: #848ea9;&quot;&gt;/t_hot_reload/&lt;/span&gt;
              link.href += &lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color: #e69f00; font-weight: bold;&quot;&gt;#{to_append}&lt;/span&gt;&lt;span style=&quot;color: #848ea9;&quot;&gt;&quot;&lt;/span&gt;
            &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;else&lt;/span&gt;
              link.href = link.href.sub(&lt;span style=&quot;color: #848ea9;&quot;&gt;/t_hot_reload=\d{13}/&lt;/span&gt;, to_append)
            &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
          &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
        &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
      }
    &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;


  &lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
&lt;span style=&quot;color: #56b4e9; font-weight: bold;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Now I&#39;m ready to be able to extend this class to support css from Rails&#39; asset pipeline!&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: &amp;quot;arial&amp;quot; , &amp;quot;helvetica&amp;quot; , sans-serif;&quot;&gt;Thanks to&amp;nbsp;&lt;a href=&quot;http://blog.scottnelsonsmith.com/&quot; target=&quot;_blank&quot;&gt;Scott Smith&lt;/a&gt;&amp;nbsp;for proofreading this.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;status&quot; id=&quot;postamble&quot;&gt;
&lt;div class=&quot;validation&quot; style=&quot;font-size: 14px; margin: 0.2em;&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/5167065743742420598/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/5167065743742420598' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/5167065743742420598'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/5167065743742420598'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2016/06/wewljcio-working-effectively-with.html' title='WEWLJCIO - Working Effectively with Legacy Javascript Code in Opal'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-1527638763461233793</id><published>2016-01-25T11:29:00.000-08:00</published><updated>2016-02-04T16:58:02.750-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="opal"/><category scheme="http://www.blogger.com/atom/ns#" term="rails"/><category scheme="http://www.blogger.com/atom/ns#" term="react.rb"/><category scheme="http://www.blogger.com/atom/ns#" term="reactjs"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>Getting started with react.rb and Ruby on Rails</title><content type='html'>&lt;a href=&quot;https://facebook.github.io/react/&quot; style=&quot;font-family: &#39;Helvetica Neue&#39;, Arial, Helvetica, sans-serif;&quot; target=&quot;_blank&quot;&gt;React.js&lt;/a&gt;&lt;span style=&quot;font-family: &#39;Helvetica Neue&#39;, Arial, Helvetica, sans-serif;&quot;&gt;&amp;nbsp;was the hottest Javascript framework of 2015. The&amp;nbsp;&lt;/span&gt;&lt;b style=&quot;font-family: &#39;Helvetica Neue&#39;, Arial, Helvetica, sans-serif;&quot;&gt;reactjs&lt;/b&gt;&lt;span style=&quot;font-family: &#39;Helvetica Neue&#39;, Arial, Helvetica, sans-serif;&quot;&gt;&amp;nbsp;team brought this goodness to Ruby on Rails via the&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/reactjs/react-rails&quot; style=&quot;font-family: &#39;Helvetica Neue&#39;, Arial, Helvetica, sans-serif;&quot; target=&quot;_blank&quot;&gt;react-rails&lt;/a&gt;&lt;span style=&quot;font-family: &#39;Helvetica Neue&#39;, Arial, Helvetica, sans-serif;&quot;&gt;&amp;nbsp;gem. From its project page, React-rails can:&lt;/span&gt;&lt;br /&gt;
&lt;div id=&quot;content&quot; style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: -webkit-standard; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline1&quot;&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline1&quot;&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Provide various react builds to your asset bundle&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Transform .jsx in the asset pipeline&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Render components into views and mount them via view helper &amp;amp; react_ujs&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Render components server-side with prerender: true&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Generate components with a Rails generator&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Be extended with custom renderers, transformers and view helpers&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;While&amp;nbsp;&lt;code&gt;react-rails&lt;/code&gt;&amp;nbsp;provides easy integration with Rails, a Rails developer cannot leverage the full benefits of React.js, particularly isomorphic/&lt;a href=&quot;https://medium.com/@mjackson/universal-javascript-4761051b7ae9#.rxrgqe5wb&quot; target=&quot;_blank&quot;&gt;universal&lt;/a&gt;&amp;nbsp;domain logic code and views since different languages are used on server and client sides.&amp;nbsp;&lt;a href=&quot;https://github.com/zetachang/react.rb&quot; target=&quot;_blank&quot;&gt;React.rb/reactive-ruby&lt;/a&gt;&amp;nbsp;(&lt;b&gt;react.rb&lt;/b&gt;&amp;nbsp;from here on) addresses this by allowing one to write React components in Ruby, courtesy of&amp;nbsp;&lt;a href=&quot;http://opalrb.org/&quot; target=&quot;_blank&quot;&gt;Opal&lt;/a&gt;. Now the Rails programmer can also enjoy universal domain logic and views written in Ruby. I should note that using Opal with Rails without react.rb also enables univeral domain logic and views (via opal-haml and opal-erb).&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Since I plan to write in depth about react.rb in subsequent posts, the focus of this article will be limited to just getting&amp;nbsp;&lt;code&gt;react.rb&lt;/code&gt;&amp;nbsp;up and running on Rails from scratch.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline2&quot;&gt;
&lt;h2 id=&quot;orgheadline2&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;
Generate a rails project that uses Opal&lt;/span&gt;&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline2&quot;&gt;
&lt;div target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;The easiest way to create a Rails project that uses&amp;nbsp;&lt;a href=&quot;http://opalrb.org/&quot; target=&quot;_blank&quot;&gt;Opal&lt;/a&gt;&amp;nbsp;is to use the&amp;nbsp;&lt;code&gt;--javascript=opal&lt;/code&gt;&amp;nbsp;option. Manual instructions on how add Opal support to an existing Rails project are given on the&amp;nbsp;&lt;a href=&quot;https://github.com/opal/opal-rails&quot; target=&quot;_blank&quot;&gt;opal-rails&lt;/a&gt;&amp;nbsp;site. Create a new Rails project with the following command:&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-bash&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;% rails new getting-started-react-rails --javascript=opal
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline3&quot;&gt;
&lt;h2 id=&quot;orgheadline3&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;
Add react.rb gems to Gemfile&lt;/span&gt;&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline3&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;To use&amp;nbsp;&lt;code&gt;react.rb&lt;/code&gt;, you need to add 3 gems to your Gemfile: reactive-ruby&lt;sup&gt;&lt;a class=&quot;footref&quot; href=&quot;https://www.blogger.com/blogger.g?blogID=16908486#fn.1&quot; id=&quot;fnr.1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, react-rails and therubyracer&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-orgheadline4&quot;&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgheadline4&quot;&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;gem &lt;span style=&quot;color: green;&quot;&gt;&#39;reactive-ruby&#39;&lt;/span&gt;, &lt;span style=&quot;color: green;&quot;&gt;&#39;0.7.29&#39;&lt;/span&gt; &lt;span style=&quot;color: #8d8d84;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #8d8d84; font-style: italic;&quot;&gt;nail down compatible version w/ pre 0.14 react-rails&lt;/span&gt;
gem &lt;span style=&quot;color: green;&quot;&gt;&#39;react-rails&#39;&lt;/span&gt;, &lt;span style=&quot;color: green;&quot;&gt;&#39;1.3.2&#39;&lt;/span&gt; &lt;span style=&quot;color: #8d8d84;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #8d8d84; font-style: italic;&quot;&gt;react.rb not compatible ith 1.4.* yet so use this one&lt;/span&gt;
gem &lt;span style=&quot;color: green;&quot;&gt;&#39;opal-rails&#39;&lt;/span&gt; &lt;span style=&quot;color: #8d8d84;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #8d8d84; font-style: italic;&quot;&gt;already added w/the --javascript=opal option&lt;/span&gt;
gem &lt;span style=&quot;color: green;&quot;&gt;&#39;therubyracer&#39;&lt;/span&gt;, &lt;span style=&quot;color: #d0372d;&quot;&gt;platforms&lt;/span&gt;: &lt;span style=&quot;color: #d0372d;&quot;&gt;:ruby&lt;/span&gt; &lt;span style=&quot;color: #8d8d84;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #8d8d84; font-style: italic;&quot;&gt;Required for server side prerendering&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Run&amp;nbsp;&lt;code&gt;bundle install&lt;/code&gt;&amp;nbsp;after these have been added to your Gemfile.&lt;/span&gt;&lt;br /&gt;
&lt;h3 id=&quot;orgheadline4&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;
Update&lt;/span&gt;&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-orgheadline4&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Since this article was written there has been Rails generator code that has been written as a&amp;nbsp;&lt;a href=&quot;https://rubygems.org/gems/reactive_rails_generator&quot; target=&quot;_blank&quot;&gt;standalone gem&lt;/a&gt;&amp;nbsp;that is pending integration with react.rb gem. Some of conventions described in this article, which currently match that of existing documentation and sample Rails project in react.rb will likely be changing as part of that.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline5&quot;&gt;
&lt;h2 id=&quot;orgheadline5&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;
Convert application.js to application.js.rb&lt;/span&gt;&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline5&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;When using opal-rails, it is recommented&lt;sup&gt;&lt;a class=&quot;footref&quot; href=&quot;https://www.blogger.com/blogger.g?blogID=16908486#fn.2&quot; id=&quot;fnr.2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&amp;nbsp;to convert the application.js file to application.js.rb. Make yours look like this:&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #8d8d84;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #8d8d84; font-style: italic;&quot;&gt;app/assets/javascripts/application.js.rb&lt;/span&gt;
&lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&#39;opal&#39;&lt;/span&gt;
&lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&#39;opal_ujs&#39;&lt;/span&gt;
&lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&#39;turbolinks&#39;&lt;/span&gt;
&lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&#39;react&#39;&lt;/span&gt;
&lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&#39;react_ujs&#39;&lt;/span&gt;
&lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&#39;components&#39;&lt;/span&gt; &lt;span style=&quot;color: #8d8d84;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #8d8d84; font-style: italic;&quot;&gt;to include isomorphic react components on the client&lt;/span&gt;
require_tree &lt;span style=&quot;color: green;&quot;&gt;&#39;.&#39;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline6&quot;&gt;
&lt;h2 id=&quot;orgheadline6&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;
Setup for isomorphic&lt;sup&gt;&lt;a class=&quot;footref&quot; href=&quot;https://www.blogger.com/blogger.g?blogID=16908486#fn.3&quot; id=&quot;fnr.3&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&amp;nbsp;React components&lt;/span&gt;&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline6&quot;&gt;
&lt;div target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;A big perk of react.js is isomorphic code (same code on server and client side), which leads to A united UI layer. As mentioned before&amp;nbsp;&lt;a href=&quot;https://github.com/reactjs/react-rails&quot; target=&quot;_blank&quot;&gt;react-rails&lt;/a&gt;&amp;nbsp;provides server rendered react.js components, as well as other perks as detailed in this&amp;nbsp;&lt;a href=&quot;http://bensmithett.com/server-rendered-react-components-in-rails/&quot; target=&quot;_blank&quot;&gt;this article&lt;/a&gt;. This quote from the aforementioned article gives one a sense of how big a perk this is.&lt;/span&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;The Holy Grail. The united UI layer. Serve up real HTML on first page load, then kick off a client side JS app. All without duplicating a single line of UI code.&lt;/span&gt;&lt;/blockquote&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Those who have struggled with duplicated views on front and back ends, in different languages should appreciate that sentiment. To support isomorphic react.rb components you need to setup a structure for these&amp;nbsp;&lt;b&gt;shared&lt;/b&gt;components. The current convention is to make a&amp;nbsp;&lt;code&gt;app/views/components&lt;/code&gt;&amp;nbsp;directory containing the components and a&amp;nbsp;&lt;code&gt;components.rb&lt;/code&gt;&amp;nbsp;manifest file that will require all the&amp;nbsp;&lt;code&gt;react.rb&lt;/code&gt;&amp;nbsp;components, like so:&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #8d8d84;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #8d8d84; font-style: italic;&quot;&gt;app/views/components.rb&lt;/span&gt;
&lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&#39;opal&#39;&lt;/span&gt;
&lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;require&lt;/span&gt; &lt;span style=&quot;color: green;&quot;&gt;&#39;reactive-ruby&#39;&lt;/span&gt;
require_tree &lt;span style=&quot;color: green;&quot;&gt;&#39;./components&#39;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;You may have noticed that, that the&amp;nbsp;&lt;code&gt;application.js.rb&lt;/code&gt;&amp;nbsp;we created&amp;nbsp;&lt;code&gt;require=s this =components.rb&lt;/code&gt;&amp;nbsp;file to compile these universal&amp;nbsp;&lt;code&gt;react.rb&lt;/code&gt;&amp;nbsp;components.&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline7&quot;&gt;
&lt;h2 id=&quot;orgheadline7&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;
Make a controller to demonstrate react components&lt;/span&gt;&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline7&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;We will be demonstrating several types of components as examples. Let&#39;s make a dedicated controller to demo these components with dedicated actions for each case.&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-bash&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;% rails g controller home isomorphic iso_convention search_path client_only
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline8&quot;&gt;
&lt;h2 id=&quot;orgheadline8&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;
Create your first React Component&lt;/span&gt;&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline8&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;So now that we&#39;re setup for isomorphic components, lets make our first react.rb component. We&#39;ll start with a simple &quot;Hello World&quot; component. This component takes a single, required param message of type&amp;nbsp;&lt;code&gt;String&lt;/code&gt;. Note, param in&amp;nbsp;&lt;code&gt;react.rb&lt;/code&gt;&amp;nbsp;corresonds to prop in react.js;&amp;nbsp;&lt;code&gt;react.rb&lt;/code&gt;&amp;nbsp;calls props &quot;params&quot; to provide a more Rails familiar API. The component renders this message param in an&amp;nbsp;&lt;b&gt;h1&lt;/b&gt;&amp;nbsp;element, and renders a button that, when clicked, calls&amp;nbsp;&lt;code&gt;alert()&lt;/code&gt;&amp;nbsp;with the same message.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Put the following into this file&amp;nbsp;&lt;b&gt;app/views/components/hello.rb&lt;/b&gt;:&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: blue;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;Hello&lt;/span&gt;
  &lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;include&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;React&lt;/span&gt;::&lt;span style=&quot;color: #6434a3;&quot;&gt;Component&lt;/span&gt;
  required_param &lt;span style=&quot;color: #d0372d;&quot;&gt;:what&lt;/span&gt;, &lt;span style=&quot;color: #d0372d;&quot;&gt;type&lt;/span&gt;: &lt;span style=&quot;color: #6434a3;&quot;&gt;String&lt;/span&gt;

  &lt;span style=&quot;color: blue;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #006699;&quot;&gt;message&lt;/span&gt;
    &lt;span style=&quot;color: green;&quot;&gt;&quot;Hello &lt;/span&gt;&lt;span style=&quot;color: #ba36a5;&quot;&gt;#{what}&lt;/span&gt;&lt;span style=&quot;color: green;&quot;&gt;&quot;&lt;/span&gt;
  &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;

  &lt;span style=&quot;color: blue;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #006699;&quot;&gt;render&lt;/span&gt;
    div {
      h1 { message }
      button {&lt;span style=&quot;color: green;&quot;&gt;&quot;Press me&quot;&lt;/span&gt;}.on(&lt;span style=&quot;color: #d0372d;&quot;&gt;:click&lt;/span&gt;) {alert message}
    }
  &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
&lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;You can render the&amp;nbsp;&lt;code&gt;Hello&lt;/code&gt;&amp;nbsp;component directly without needing a template file in your controller with&amp;nbsp;&lt;code&gt;render_component()&lt;/code&gt;.&amp;nbsp;&lt;code&gt;render_component()&lt;/code&gt;&amp;nbsp;takes an optional (more on this later) class name of the component and any parameters you wish to pass the component. Implement the&amp;nbsp;&lt;code&gt;isomorphic&lt;/code&gt;&amp;nbsp;action in the&amp;nbsp;&lt;code&gt;HomeController&lt;/code&gt;&amp;nbsp;like so&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: blue;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;HomeController&lt;/span&gt; &amp;lt; &lt;span style=&quot;color: #6434a3;&quot;&gt;ApplicationController&lt;/span&gt;
  &lt;span style=&quot;color: blue;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #006699;&quot;&gt;isomorphic&lt;/span&gt;
    render_component &lt;span style=&quot;color: green;&quot;&gt;&#39;Hello&#39;&lt;/span&gt;, &lt;span style=&quot;color: #d0372d;&quot;&gt;message&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;World&#39;&lt;/span&gt;
  &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
&lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Start the server, then visit&amp;nbsp;&lt;a href=&quot;http://localhost:3000/home/isomorphic&quot; target=&quot;_blank&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://localhost:3000/home/isomorphic&quot; target=&quot;_blank&quot;&gt;http://localhost:3000/home/isomorphic&lt;/a&gt;&amp;nbsp;to view the component. By default, react.rb prerenders the component on the server (the reverse of react-rails&#39;&amp;nbsp;&lt;code&gt;react_component()&lt;/code&gt;, but you can force Rails to NOT prerender by appending ?no_prerender=1 to the url, like so&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-bash&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;http://localhost:3000/home/isomorphic?&lt;span style=&quot;color: #ba36a5;&quot;&gt;no_prerender&lt;/span&gt;=1
&lt;/pre&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Let&#39;s take a quick look at the HTML returned by the server in both cases (formatted to be more human-readable)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;For&amp;nbsp;&lt;a href=&quot;http://localhost:3000/home/isomorphic&quot; target=&quot;_blank&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://localhost:3000/home/isomorphic&quot; target=&quot;_blank&quot;&gt;http://localhost:3000/home/isomorphic&lt;/a&gt;&amp;nbsp;we see the&amp;nbsp;&lt;b&gt;h1&lt;/b&gt;&amp;nbsp;and button rendered from the server:&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-html&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&amp;lt;&lt;span style=&quot;color: #006699;&quot;&gt;div&lt;/span&gt; &lt;span style=&quot;color: #ba36a5;&quot;&gt;data-react-class&lt;/span&gt;=&lt;span style=&quot;color: green;&quot;&gt;&quot;React.TopLevelRailsComponent&quot;&lt;/span&gt;
     &lt;span style=&quot;color: #ba36a5;&quot;&gt;data-react-props&lt;/span&gt;=&lt;span style=&quot;color: green;&quot;&gt;&quot;{&quot;render_params&quot;:{&quot;message&quot;:&quot;World&quot;},&quot;component_name&quot;:&quot;Hello&quot;,&quot;controller&quot;:&quot;Home&quot;}&quot;&lt;/span&gt;&amp;gt;
  &amp;lt;&lt;span style=&quot;color: #006699;&quot;&gt;div&lt;/span&gt; &lt;span style=&quot;color: #ba36a5;&quot;&gt;data-reactid&lt;/span&gt;=&lt;span style=&quot;color: green;&quot;&gt;&quot;.3hx9dqn6rk&quot;&lt;/span&gt;
       &lt;span style=&quot;color: #ba36a5;&quot;&gt;data-react-checksum&lt;/span&gt;=&lt;span style=&quot;color: green;&quot;&gt;&quot;487927662&quot;&lt;/span&gt;&amp;gt;
    &amp;lt;&lt;span style=&quot;color: #006699;&quot;&gt;h1&lt;/span&gt; &lt;span style=&quot;color: #ba36a5;&quot;&gt;data-reactid&lt;/span&gt;=&lt;span style=&quot;color: green;&quot;&gt;&quot;.3hx9dqn6rk.0&quot;&lt;/span&gt;&amp;gt;&lt;span style=&quot;color: black; font-weight: bold; text-decoration: underline;&quot;&gt;Hello World&lt;/span&gt;&amp;lt;/&lt;span style=&quot;color: #006699;&quot;&gt;h1&lt;/span&gt;&amp;gt;
    &amp;lt;&lt;span style=&quot;color: #006699;&quot;&gt;button&lt;/span&gt; &lt;span style=&quot;color: #ba36a5;&quot;&gt;data-reactid&lt;/span&gt;=&lt;span style=&quot;color: green;&quot;&gt;&quot;.3hx9dqn6rk.1&quot;&lt;/span&gt;&amp;gt;Press me&amp;lt;/&lt;span style=&quot;color: #006699;&quot;&gt;button&lt;/span&gt;&amp;gt;
  &amp;lt;/&lt;span style=&quot;color: #006699;&quot;&gt;div&lt;/span&gt;&amp;gt;
&amp;lt;/&lt;span style=&quot;color: #006699;&quot;&gt;div&lt;/span&gt;&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;For&amp;nbsp;&lt;a href=&quot;http://localhost:3000/home/isomorphic?no_prerender=1&quot; target=&quot;_blank&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://localhost:3000/home/isomorphic?no_prerender=1&quot; target=&quot;_blank&quot;&gt;http://localhost:3000/home/isomorphic?no_prerender=1&lt;/a&gt;&amp;nbsp;there is no prerendering and the rendering is done by the client&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-html&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&amp;lt;&lt;span style=&quot;color: #006699;&quot;&gt;div&lt;/span&gt; &lt;span style=&quot;color: #ba36a5;&quot;&gt;data-react-class&lt;/span&gt;=&lt;span style=&quot;color: green;&quot;&gt;&quot;React.TopLevelRailsComponent&quot;&lt;/span&gt;
     &lt;span style=&quot;color: #ba36a5;&quot;&gt;data-react-props&lt;/span&gt;=&lt;span style=&quot;color: green;&quot;&gt;&quot;{&quot;render_params&quot;:{&quot;message&quot;:&quot;World&quot;},&quot;component_name&quot;:&quot;Hello&quot;,&quot;controller&quot;:&quot;Home&quot;}&quot;&lt;/span&gt;&amp;gt;
&amp;lt;/&lt;span style=&quot;color: #006699;&quot;&gt;div&lt;/span&gt;&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline9&quot;&gt;
&lt;h2 id=&quot;orgheadline9&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;
Rails conventions, isomorphic (i.e. universal) components and the &quot;default&quot; component&lt;/span&gt;&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline9&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;In the Rails tradition of convention over configuration, you can structure/name your components to match your controllers to support a &quot;default&quot; component, i.e. a component you do NOT need to specify, for a controller action. To make a default component for the&amp;nbsp;&lt;code&gt;HomeController#iso_convention&lt;/code&gt;&amp;nbsp;action, create the following file:&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #8d8d84;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #8d8d84; font-style: italic;&quot;&gt;app/views/components/home/iso_convention.rb&lt;/span&gt;
  &lt;span style=&quot;color: blue;&quot;&gt;module&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;Components&lt;/span&gt;
    &lt;span style=&quot;color: blue;&quot;&gt;module&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;Home&lt;/span&gt;
      &lt;span style=&quot;color: blue;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;IsoConvention&lt;/span&gt;
        &lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;include&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;React&lt;/span&gt;::&lt;span style=&quot;color: #6434a3;&quot;&gt;Component&lt;/span&gt;

        &lt;span style=&quot;color: blue;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #006699;&quot;&gt;render&lt;/span&gt;
          h1 { &lt;span style=&quot;color: green;&quot;&gt;&quot;the message is: &lt;/span&gt;&lt;span style=&quot;color: #ba36a5;&quot;&gt;#{params[:message]}&lt;/span&gt;&lt;span style=&quot;color: green;&quot;&gt;&quot;&lt;/span&gt; }
        &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
      &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
    &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
  &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;We now call&amp;nbsp;&lt;code&gt;render_component()&lt;/code&gt;&amp;nbsp;in the action, passing only the desired params in the action.&amp;nbsp;&amp;nbsp;&lt;code&gt;render_component()&lt;/code&gt;&amp;nbsp;will instantiate the&amp;nbsp;&lt;b&gt;default&lt;/b&gt;&amp;nbsp;component.&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: blue;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;HomeController&lt;/span&gt; &amp;lt; &lt;span style=&quot;color: #6434a3;&quot;&gt;ApplicationController&lt;/span&gt;
  &lt;span style=&quot;color: blue;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #006699;&quot;&gt;iso_convention&lt;/span&gt;
    render_component &lt;span style=&quot;color: #d0372d;&quot;&gt;message&lt;/span&gt;: &lt;span style=&quot;color: green;&quot;&gt;&#39;World&#39;&lt;/span&gt;
  &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
&lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Browsing&amp;nbsp;&lt;a href=&quot;http://localhost:3000/home/iso_convention&quot; target=&quot;_blank&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://localhost:3000/home/iso_convention&quot; target=&quot;_blank&quot;&gt;http://localhost:3000/home/iso_convention&lt;/a&gt;&amp;nbsp;will render the&amp;nbsp;&lt;code&gt;Components::Home::IsoConvention&lt;/code&gt;&amp;nbsp;component&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline10&quot;&gt;
&lt;h2 id=&quot;orgheadline10&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;
The component search path&lt;/span&gt;&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline10&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;For consistency, you should stick with the Rails directory and filename conventions. There is some flexibility in where you can place components. The search path for isomorphic components in react.rb is described here:&amp;nbsp;&lt;a href=&quot;https://github.com/zetachang/react.rb#changing-the-top-level-component-name-and-search-path&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;&amp;nbsp;which writes:&lt;/span&gt;&lt;br /&gt;
&lt;blockquote&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Changing the top level component name and search path&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;You can control the top level component name and search path.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;You can specify the component name explicitly in the render_component method. render_component &quot;Blatz will search the for a component class named Blatz regardless of the controller method.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Searching for components normally works like this: Given a controller named &quot;Foo&quot; then the component should be either in the Components::Foo module, the Components module (no controller - useful if you have just a couple of shared components) or just the outer scope (i.e. Module) which is useful for small apps.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Saying render_component &quot;::Blatz&quot; will only search the outer scope, while &quot;::Foo::Blatz&quot; will look only in the module Foo for a class named Blatz.&lt;/span&gt;&lt;/blockquote&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline11&quot;&gt;
&lt;h2 id=&quot;orgheadline11&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;
Exploring the component search path&lt;/span&gt;&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline11&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Let&#39;s play around with several components that have the same class name and see how the search path resolves which component to use. Create the file below:&lt;/span&gt;&lt;br /&gt;
&lt;code&gt;&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;app/views/components/search_path.rb&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;  &lt;span style=&quot;color: #8d8d84;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #8d8d84; font-style: italic;&quot;&gt;This class departs from 1 class/file and diretory&lt;/span&gt;
  &lt;span style=&quot;color: #8d8d84;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #8d8d84; font-style: italic;&quot;&gt;structure/convention, using this to test search path&lt;/span&gt;

&lt;span style=&quot;color: blue;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;SearchPath&lt;/span&gt;
  &lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;include&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;React&lt;/span&gt;::&lt;span style=&quot;color: #6434a3;&quot;&gt;Component&lt;/span&gt;
  &lt;span style=&quot;color: blue;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #006699;&quot;&gt;render&lt;/span&gt;
    h1 {&lt;span style=&quot;color: green;&quot;&gt;&quot;::SearchPath&quot;&lt;/span&gt;}
  &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
&lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;

&lt;span style=&quot;color: blue;&quot;&gt;module&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;Home&lt;/span&gt;
  &lt;span style=&quot;color: blue;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;SearchPath&lt;/span&gt;
    &lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;include&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;React&lt;/span&gt;::&lt;span style=&quot;color: #6434a3;&quot;&gt;Component&lt;/span&gt;
    &lt;span style=&quot;color: blue;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #006699;&quot;&gt;render&lt;/span&gt;
      h1 {&lt;span style=&quot;color: green;&quot;&gt;&quot;Home::SearchPath&quot;&lt;/span&gt;}
    &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
  &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
&lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;

&lt;span style=&quot;color: blue;&quot;&gt;module&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;Components&lt;/span&gt;
  &lt;span style=&quot;color: blue;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;SearchPath&lt;/span&gt;
    &lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;include&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;React&lt;/span&gt;::&lt;span style=&quot;color: #6434a3;&quot;&gt;Component&lt;/span&gt;
    &lt;span style=&quot;color: blue;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #006699;&quot;&gt;render&lt;/span&gt;
      h2 { &lt;span style=&quot;color: green;&quot;&gt;&#39;Components::SearchPath&#39;&lt;/span&gt; }
    &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
  &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
&lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;

&lt;span style=&quot;color: blue;&quot;&gt;module&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;Components&lt;/span&gt;
  &lt;span style=&quot;color: blue;&quot;&gt;module&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;Home&lt;/span&gt;
    &lt;span style=&quot;color: blue;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;SearchPath&lt;/span&gt;
      &lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;include&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;React&lt;/span&gt;::&lt;span style=&quot;color: #6434a3;&quot;&gt;Component&lt;/span&gt;
      &lt;span style=&quot;color: blue;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #006699;&quot;&gt;render&lt;/span&gt;
        h2 { &lt;span style=&quot;color: green;&quot;&gt;&#39;Components::Home::SearchPath&#39;&lt;/span&gt; }
      &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
    &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
  &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
&lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;To render the &quot;default&quot; component, we can just call&amp;nbsp;&lt;code&gt;render_component()&lt;/code&gt;:&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: blue;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;HomeController&lt;/span&gt; &amp;lt; &lt;span style=&quot;color: #6434a3;&quot;&gt;ApplicationController&lt;/span&gt;
  &lt;span style=&quot;color: blue;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #006699;&quot;&gt;search_path&lt;/span&gt;
    render_component
  &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
&lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Hitting&amp;nbsp;&lt;a href=&quot;http://localhost:3000/home/search_path&quot; target=&quot;_blank&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://localhost:3000/home/search_path&quot; target=&quot;_blank&quot;&gt;http://localhost:3000/home/search_path&lt;/a&gt;&amp;nbsp;the component rendered&amp;nbsp;&lt;code&gt;Home::SearchPath&lt;/code&gt;&amp;nbsp;as evidenced by the text in the H1 element.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Specifying the component by unqualified class name in&amp;nbsp;&lt;code&gt;render_component()&lt;/code&gt;, yields the same result:&amp;nbsp;&lt;code&gt;Home::SearchPath&lt;/code&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: blue;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;HomeController&lt;/span&gt; &amp;lt; &lt;span style=&quot;color: #6434a3;&quot;&gt;ApplicationController&lt;/span&gt;
  &lt;span style=&quot;color: blue;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #006699;&quot;&gt;search_path&lt;/span&gt;
    render_component &lt;span style=&quot;color: green;&quot;&gt;&quot;SearchPath&quot;&lt;/span&gt;
  &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
&lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;We can explore what will be found next the search path by changing the found component&#39;s name to&amp;nbsp;&lt;code&gt;SearchPath1&lt;/code&gt;, and then refreshing&amp;nbsp;&lt;a href=&quot;http://localhost:3000/home/search_path&quot; target=&quot;_blank&quot;&gt;http://localhost:3000/home/search_path&lt;/a&gt;&amp;nbsp;to see which component is found. Doing this for each found component gets the following results:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;table border=&quot;2&quot; cellpadding=&quot;6&quot; cellspacing=&quot;0&quot; frame=&quot;hsides&quot; rules=&quot;groups&quot; style=&quot;border-collapse: collapse;&quot;&gt;&lt;colgroup&gt;&lt;col class=&quot;org-left&quot; style=&quot;margin-left: 0px; margin-right: auto; text-align: left;&quot;&gt;&lt;/col&gt;&lt;col class=&quot;org-left&quot; style=&quot;margin-left: 0px; margin-right: auto; text-align: left;&quot;&gt;&lt;/col&gt;&lt;/colgroup&gt;&lt;thead&gt;
&lt;tr&gt;&lt;th class=&quot;org-left&quot; scope=&quot;col&quot; style=&quot;margin-left: 0px; margin-right: auto; text-align: center; vertical-align: top;&quot;&gt;&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Class name changed from SearchPath&lt;/span&gt;&lt;/th&gt;&lt;th class=&quot;org-left&quot; scope=&quot;col&quot; style=&quot;margin-left: 0px; margin-right: auto; text-align: center; vertical-align: top;&quot;&gt;&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Component Rendered by search path&lt;/span&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td class=&quot;org-left&quot; style=&quot;margin-left: 0px; margin-right: auto; text-align: left; vertical-align: top;&quot;&gt;&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;none&lt;/span&gt;&lt;/td&gt;&lt;td class=&quot;org-left&quot; style=&quot;margin-left: 0px; margin-right: auto; text-align: left; vertical-align: top;&quot;&gt;&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Home::SearchPath&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;org-left&quot; style=&quot;margin-left: 0px; margin-right: auto; text-align: left; vertical-align: top;&quot;&gt;&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Home::SearchPath&lt;/span&gt;&lt;/td&gt;&lt;td class=&quot;org-left&quot; style=&quot;margin-left: 0px; margin-right: auto; text-align: left; vertical-align: top;&quot;&gt;&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Components::Home::SearchPath&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;org-left&quot; style=&quot;margin-left: 0px; margin-right: auto; text-align: left; vertical-align: top;&quot;&gt;&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Components::Home::SearchPath&lt;/span&gt;&lt;/td&gt;&lt;td class=&quot;org-left&quot; style=&quot;margin-left: 0px; margin-right: auto; text-align: left; vertical-align: top;&quot;&gt;&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;::SearchPath&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;org-left&quot; style=&quot;margin-left: 0px; margin-right: auto; text-align: left; vertical-align: top;&quot;&gt;&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;::SearchPath&lt;/span&gt;&lt;/td&gt;&lt;td class=&quot;org-left&quot; style=&quot;margin-left: 0px; margin-right: auto; text-align: left; vertical-align: top;&quot;&gt;&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Components::SearchPath&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;If we rename all the&amp;nbsp;&lt;code&gt;SearchPath1&lt;/code&gt;&amp;nbsp;classes back to&amp;nbsp;&lt;code&gt;SearchPath&lt;/code&gt;, we can force the search path to find our desired component by specifying the full namespace in the&amp;nbsp;&lt;code&gt;render_component()&lt;/code&gt;&amp;nbsp;call&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: blue;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;HomeController&lt;/span&gt; &amp;lt; &lt;span style=&quot;color: #6434a3;&quot;&gt;ApplicationController&lt;/span&gt;
  &lt;span style=&quot;color: blue;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #006699;&quot;&gt;search_path&lt;/span&gt;
    render_component &lt;span style=&quot;color: green;&quot;&gt;&quot;SearchPath&quot;&lt;/span&gt;
    &lt;span style=&quot;color: #8d8d84;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #8d8d84; font-style: italic;&quot;&gt;render_component &quot;Components::SearchPath&quot;&lt;/span&gt;
    &lt;span style=&quot;color: #8d8d84;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #8d8d84; font-style: italic;&quot;&gt;render_component &quot;Components::Home::SearchPath&quot;&lt;/span&gt;
    &lt;span style=&quot;color: #8d8d84;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #8d8d84; font-style: italic;&quot;&gt;render_component &quot;Home::SearchPath&quot;&lt;/span&gt;
    &lt;span style=&quot;color: #8d8d84;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #8d8d84; font-style: italic;&quot;&gt;render_component &quot;::SearchPath&quot;&lt;/span&gt;
  &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
&lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline12&quot;&gt;
&lt;h2 id=&quot;orgheadline12&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;
Directory conventions for react-rails, Opal and react.rb&lt;/span&gt;&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline12&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;The&amp;nbsp;&lt;b&gt;react-rails&lt;/b&gt;&amp;nbsp;Javascript component generators create react.js components in the&amp;nbsp;&lt;code&gt;app/assets/javascripts/components&lt;/code&gt;&amp;nbsp;directory. This makes sense, esp. since Rails out of the box does NOT support isomorphic code and views; hence this directoy is a logical and &quot;Rails-like&quot; place for Javascript to go. Similarly, if you are just using opal-rails and not not react.rb, then by convention, your&amp;nbsp;&lt;code&gt;Opal&lt;/code&gt;&amp;nbsp;code will be placed under&amp;nbsp;&lt;code&gt;app/assets/javascripts&lt;/code&gt;&amp;nbsp;where the asset pipeline knows how to find and transpile the&amp;nbsp;&lt;code&gt;Opal&lt;/code&gt;&amp;nbsp;files to Javascript. React.rb challenges these directory conventions. As react.js is often called the&amp;nbsp;&lt;b&gt;V&lt;/b&gt;&amp;nbsp;of&amp;nbsp;&lt;b&gt;MVC&lt;/b&gt;, then it makes sense for react.rb components to live under the&amp;nbsp;&lt;code&gt;app/views/components&lt;/code&gt;&amp;nbsp;directory, esp. as they can also be rendered on the server. React.rb is young, and conventions may change, but at the momemnt this is the prescribed convention.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;You can create react.rb components more in line with react-rails and Opal conventions by placing them somewhere under the&amp;nbsp;&lt;code&gt;app/assets/javascripts&lt;/code&gt;&amp;nbsp;directory. The Opal files will be found by Rails anywhere that the asset pipeline is configured to find javascript files for both server and client rendering, but I would recommend a structure similar to how react-rails, i.e. in&amp;nbsp;&lt;code&gt;app/assets/javascripts/components&lt;/code&gt;&amp;nbsp;to make them easy to find.&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Let&#39;s put the &quot;client side only&quot; component into&amp;nbsp;&lt;code&gt;app/assets/javascripts&lt;/code&gt;. Since Opal will find the file anywhere the asset pipeline knows to look, this would be more for organizational conventions rather than a configuration necessary to make it work.&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #8d8d84;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #8d8d84; font-style: italic;&quot;&gt;app/assets/javascripts/components/client_only.rb&lt;/span&gt;
&lt;span style=&quot;color: blue;&quot;&gt;class&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;ClientOnly&lt;/span&gt;
  &lt;span style=&quot;color: #006fe0; font-weight: bold;&quot;&gt;include&lt;/span&gt; &lt;span style=&quot;color: #6434a3;&quot;&gt;React&lt;/span&gt;::&lt;span style=&quot;color: #6434a3;&quot;&gt;Component&lt;/span&gt;
  required_param &lt;span style=&quot;color: #d0372d;&quot;&gt;:message&lt;/span&gt;, &lt;span style=&quot;color: #d0372d;&quot;&gt;type&lt;/span&gt;: &lt;span style=&quot;color: #6434a3;&quot;&gt;String&lt;/span&gt;

  &lt;span style=&quot;color: blue;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #006699;&quot;&gt;render&lt;/span&gt;
    h1 { &lt;span style=&quot;color: green;&quot;&gt;&quot;Client only: &lt;/span&gt;&lt;span style=&quot;color: #ba36a5;&quot;&gt;#{params[:message]}&lt;/span&gt;&lt;span style=&quot;color: green;&quot;&gt;&quot;&lt;/span&gt; }
  &lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
&lt;span style=&quot;color: blue;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;Then in the template for the&amp;nbsp;&lt;code&gt;client_only&lt;/code&gt;&amp;nbsp;action , you can render the component client side via the&amp;nbsp;&lt;code&gt;react_component()&lt;/code&gt;&amp;nbsp;view helper provided by react-rails. Since react.rb wraps calls to react.js, the components become react.js components.&lt;/span&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-html&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&amp;lt;&lt;span style=&quot;color: #006699;&quot;&gt;h1&lt;/span&gt;&amp;gt;&lt;span style=&quot;color: black; font-weight: bold; text-decoration: underline;&quot;&gt;Home#client_only&lt;/span&gt;&amp;lt;/&lt;span style=&quot;color: #006699;&quot;&gt;h1&lt;/span&gt;&amp;gt;
&amp;lt;&lt;span style=&quot;color: #006699;&quot;&gt;p&lt;/span&gt;&amp;gt;Find me in app/views/home/client_only.html.erb&amp;lt;/&lt;span style=&quot;color: #006699;&quot;&gt;p&lt;/span&gt;&amp;gt;
&amp;lt;%= react_component &#39;ClientOnly&#39;, message: &#39;World&#39; %&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-orgheadline13&quot;&gt;
&lt;h2 id=&quot;orgheadline13&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;
That&#39;s all for now.&lt;/span&gt;&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-orgheadline13&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;So now you have a Rails project with react.rb running with several examples of react.rb components. All of this code exists in a rails project&amp;nbsp;&lt;a href=&quot;https://github.com/fkchang/getting-started-react-rails&quot; target=&quot;_blank&quot;&gt;here.&lt;/a&gt;&amp;nbsp;This should be enough to get one started. There will be react.rb articles to follow. Enjoy react.rb and Rails!&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;footnotes&quot;&gt;
&lt;h2 class=&quot;footnotes&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;
Footnotes:&amp;nbsp;&lt;/span&gt;&lt;/h2&gt;
&lt;div id=&quot;text-footnotes&quot;&gt;
&lt;div class=&quot;footdef&quot; style=&quot;margin-bottom: 1em;&quot;&gt;
&lt;sup&gt;&lt;a class=&quot;footnum&quot; href=&quot;https://www.blogger.com/blogger.g?blogID=16908486#fnr.1&quot; id=&quot;fn.1&quot;&gt;&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;1&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;br /&gt;
&lt;div class=&quot;footpara&quot; style=&quot;display: inline;&quot;&gt;
&lt;div class=&quot;footpara&quot; style=&quot;display: inline;&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;reactive-ruby will fold back into react.rb with the 0.9.0 versions (currently at 0.7.36). Plans are discussed in the react.rb&amp;nbsp;&lt;a href=&quot;https://github.com/zetachang/react.rb#road-map&quot;&gt;roadmap&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;footdef&quot; style=&quot;margin-bottom: 1em;&quot;&gt;
&lt;sup&gt;&lt;a class=&quot;footnum&quot; href=&quot;https://www.blogger.com/blogger.g?blogID=16908486#fnr.2&quot; id=&quot;fn.2&quot;&gt;&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;2&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;br /&gt;
&lt;div class=&quot;footpara&quot; style=&quot;display: inline;&quot;&gt;
&lt;div class=&quot;footpara&quot; style=&quot;display: inline;&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;A change was made starting with Opal 0.8.*, to support ordered requires. If one wishes to continue to use application.js instead application.rb, one needs to manually load each opal file in the application.js, as below. Use of application.rb will automatically load the files in question&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-javascript&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #8d8d84;&quot;&gt;// &lt;/span&gt;&lt;span style=&quot;color: #8d8d84; font-style: italic;&quot;&gt;application.js&lt;/span&gt;
&lt;span style=&quot;color: #8d8d84;&quot;&gt;//&lt;/span&gt;&lt;span style=&quot;color: #8d8d84; font-style: italic;&quot;&gt;= require opal&lt;/span&gt;
&lt;span style=&quot;color: #8d8d84;&quot;&gt;//&lt;/span&gt;&lt;span style=&quot;color: #8d8d84; font-style: italic;&quot;&gt;= require greeter&lt;/span&gt;
&lt;span style=&quot;color: #8d8d84;&quot;&gt;//&lt;/span&gt;&lt;span style=&quot;color: #8d8d84; font-style: italic;&quot;&gt;= require_self&lt;/span&gt;
Opal.load(&lt;span style=&quot;color: green;&quot;&gt;&#39;greeter&#39;&lt;/span&gt;); &lt;span style=&quot;color: #8d8d84;&quot;&gt;//you have to load the Opal file&lt;/span&gt;
&lt;span style=&quot;color: #8d8d84;&quot;&gt;// &lt;/span&gt;&lt;span style=&quot;color: #8d8d84; font-style: italic;&quot;&gt;etc.&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;footdef&quot; style=&quot;margin-bottom: 1em;&quot;&gt;
&lt;sup&gt;&lt;a class=&quot;footnum&quot; href=&quot;https://www.blogger.com/blogger.g?blogID=16908486#fnr.3&quot; id=&quot;fn.3&quot;&gt;&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;3&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;&lt;br /&gt;
&lt;div class=&quot;footpara&quot; style=&quot;display: inline;&quot;&gt;
&lt;div class=&quot;footpara&quot; style=&quot;display: inline;&quot;&gt;
&lt;span style=&quot;font-family: Helvetica Neue, Arial, Helvetica, sans-serif;&quot;&gt;While the pattern is that universal will be taking the place of isomorphic, I will use the term isomorphic here because the react.rb docs refer to it as isomorphic&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/1527638763461233793/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/1527638763461233793' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/1527638763461233793'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/1527638763461233793'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2016/01/getting-started-with-reactrb-and-ruby.html' title='Getting started with react.rb and Ruby on Rails'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-2854772229874448913</id><published>2015-09-04T09:33:00.000-07:00</published><updated>2015-09-04T09:34:41.436-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="opal"/><category scheme="http://www.blogger.com/atom/ns#" term="opal-irb"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>Opal-irb upgraded to 0.8.0 opal and released as rubygems</title><content type='html'>&lt;a href=&quot;https://github.com/fkchang/opal-irb&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;Opal-irb&lt;/a&gt;, which previously had to be installed as a gem on github has been released as bonafide rubygems.org gem. This means that instead of doing this:&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;gem &lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;opal-irb&#39;&lt;/span&gt;, &lt;span style=&quot;color: #f5666d;&quot;&gt;github&lt;/span&gt;: &lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;fkchang/opal-irb&#39;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
You can get it from rubygems&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;gem &lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;opal-irb&#39;&lt;/span&gt;, &lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;0.7.0&#39;&lt;/span&gt; &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;for Opal 0.7.*&lt;/span&gt;
gem &lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;opal-irb&#39;&lt;/span&gt;, &lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;0.8.*&#39;&lt;/span&gt; &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;for Opal 0.8.*&lt;/span&gt;
gem &lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;opal-irb&#39;&lt;/span&gt;          &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;for latest, 0.8.0 at time of writing&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
The 3 example apps have also been upgraded to opal 0.8.0 as part of this move. I&#39;ve taken to using the same major/minor versions of opal to signify compatibility w/the corresponding versions of opal.</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/2854772229874448913/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/2854772229874448913' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/2854772229874448913'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/2854772229874448913'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2015/09/opal-irb-upgraded-to-080-opal-and.html' title='Opal-irb upgraded to 0.8.0 opal and released as rubygems'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-7111578141043707775</id><published>2015-08-11T16:06:00.001-07:00</published><updated>2019-06-13T17:50:30.641-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="opal"/><category scheme="http://www.blogger.com/atom/ns#" term="opal-irb"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>An overview of opal-irb&#39;s features</title><content type='html'>I have discovered that many of the features in&amp;nbsp;&lt;a href=&quot;https://github.com/fkchang/opal-irb/blob/master/README.md&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;opal-irb&lt;/a&gt;&amp;nbsp;are unknown to people I would&#39;ve expected to have known about those features. This post is an attempt to rectify that.&lt;br /&gt;
My approach has 3 sections:&lt;br /&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;What opal-irb has in common with irb&lt;/li&gt;
&lt;li&gt;How opal-irb differs from irb&lt;/li&gt;
&lt;li&gt;Features unique to opal-irbIn Common with irb&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-sec-0-1&quot;&gt;
&lt;h3 id=&quot;sec-0-1&quot;&gt;
Terminal Emulation (of sorts)&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-0-1&quot;&gt;
Some people might take this for granted, but irb runs in a terminal, and thus supports terminal formating among other things. Opal-irb presently uses a fork of&amp;nbsp;&lt;code&gt;jqconsole&lt;/code&gt;, which supports some level of ANSI codes display. For example, to change the default text to red (like test runners often do) in opal-irb, you can run the following:&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #dcdccc; font-weight: bold;&quot;&gt;puts&lt;/span&gt; &lt;span style=&quot;color: #cc9393;&quot;&gt;&quot;\033[31mRed Text&quot;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
You can try this&amp;nbsp;&lt;a href=&quot;http://git.io/vmQVY&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;from here&lt;/a&gt;&amp;nbsp;if the embedded iframe below doesn&#39;t look right&lt;br /&gt;
&lt;iframe allowfullscreen=&quot;&quot; ext=&quot;&quot; frameborder=&quot;0&quot; height=&quot;500&quot; mred=&quot;&quot; src=&quot;https://fkchang.github.io/opal-irb/index-jq.html#code:puts%20&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-sec-0-2&quot;&gt;
&lt;h3 id=&quot;sec-0-2&quot;&gt;
History up down history&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-0-2&quot;&gt;
Like irb, opal-irb stores a history of previous statements. You can navigate this history with the up/down arrows or use the &quot;GNU readline commands&quot;.&lt;/div&gt;
&lt;div class=&quot;outline-4&quot; id=&quot;outline-container-sec-0-2-1&quot;&gt;
&lt;h4 id=&quot;sec-0-2-1&quot;&gt;
GNU readline commands (emacs subset)&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-0-2-1&quot;&gt;
A subset of the gnu readline manipulation is supported. I&#39;ll likely add more support over time. The currently supported bindings are:&lt;br /&gt;
&lt;pre class=&quot;example&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: auto; padding: 8pt;&quot;&gt;Up/Down Arrow and ctrl-p/ctrl-n: Navigate through history
ctrl-a:                          Beginning of line
ctrl-e:                          End of line
ctrl-b:                          Back 1 character
ctrl-f:                          Forward 1 character
ctrl-d:                          Delete 1 character
ctrl-k:                          Kill to the end of the line
alt-b:                           Back 1 word
alt-f:                           Forward 1 word
alt-d:                           Delete 1 word
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-sec-0-3&quot;&gt;
&lt;h3 id=&quot;sec-0-3&quot;&gt;
Autocomplete&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-0-3&quot;&gt;
A work-in-progress (I am presently adding auto complete to the multi-line editor); auto complete is supported. It follows the same tab completion model that irb does. It looks like this:&lt;br /&gt;
&lt;pre class=&quot;example&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: auto; padding: 8pt;&quot;&gt;opal&amp;gt; S&lt;tab&gt;
STDERR          STDIN           STDOUT          ScriptError     Set
SignalException StandardError   StopIteration   String          StringIO
StringScanner   Struct          Symbol          SyntaxError     SystemCallError
SystemExit
&lt;/tab&gt;&lt;/pre&gt;
&lt;pre class=&quot;example&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: auto; padding: 8pt;&quot;&gt;opal&amp;gt; ST&lt;tab&gt;
STDERR STDIN  STDOUT
&lt;/tab&gt;&lt;/pre&gt;
&lt;pre class=&quot;example&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: auto; padding: 8pt;&quot;&gt;opal&amp;gt; STDI&lt;tab&gt;
&lt;/tab&gt;&lt;/pre&gt;
&lt;pre class=&quot;example&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: auto; padding: 8pt;&quot;&gt;opal&amp;gt; STDIN
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-sec-0-4&quot;&gt;
&lt;h3 id=&quot;sec-0-4&quot;&gt;
Multi Line Input&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-0-4&quot;&gt;
Like&amp;nbsp;&lt;b&gt;irb&lt;/b&gt;, you can enter multi-line input. You can type multiple lines until your entry is complete. It indicates an incomplete line with leading periods:&lt;br /&gt;
&lt;pre class=&quot;example&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: auto; padding: 8pt;&quot;&gt;Welcome to Opal 0.7.1
type help for assistance
opal&amp;gt; class Foo
...   def bar
...     :bar
...     end
...     end
 =&amp;gt; &quot;bar&quot;
opal&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-sec-1&quot;&gt;
&lt;h2 id=&quot;sec-1&quot;&gt;
Different than irb&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-1&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-sec-1-1&quot;&gt;
&lt;h3 id=&quot;sec-1-1&quot;&gt;
Last value returned&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-1-1&quot;&gt;
In irb the last value returned is stored in _ variable:&lt;br /&gt;
&lt;pre class=&quot;example&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: auto; padding: 8pt;&quot;&gt;2.2.1 :001 &amp;gt; 2 * 3
 =&amp;gt; 6
2.2.1 :002 &amp;gt; puts _
6
 =&amp;gt; nil
2.2.1 :003 &amp;gt;
&lt;/pre&gt;
In opal-irb, the last value is stored as $_. This departure from irb&#39;s behavior is due to issues I had wrt binding of variables and visibility from the repl. I may revisit this again to make it match irb&#39;s behavior since I did not intend to change the behavior.&lt;br /&gt;
&lt;pre class=&quot;example&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: auto; padding: 8pt;&quot;&gt;opal&amp;gt; 2 * 3
 =&amp;gt; 6
opal&amp;gt; puts $_
6
 =&amp;gt; nil
opal&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-sec-1-2&quot;&gt;
&lt;h3 id=&quot;sec-1-2&quot;&gt;
Help&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-1-2&quot;&gt;
Help in irb allows you to lookup documentation for methods via ri and rdoc docs.&lt;br /&gt;
&lt;pre class=&quot;example&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: auto; padding: 8pt;&quot;&gt;2.0.0-p247 :001 &amp;gt; help

Enter the method name you want to look up.
You can use tab to autocomplete.
Enter a blank line to exit.

&amp;gt;&amp;gt;
&lt;/pre&gt;
Opal-irb&#39;s help shows how to operate opal-irb. The present output is below. I intend to implement help for method lookup in a different fashion.&lt;br /&gt;
&lt;pre class=&quot;example&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: auto; padding: 8pt;&quot;&gt;opal&amp;gt; help
help:                            This text
$_                               last value returned is stored in this global
history:                         Shows history
irb_link_for history_num:        Create a link for the code in the history
ctrl-c:                          Abort prompt
ctrl-m:                          Pop up multi-line editor
ctrl-Enter:                      Submit code in multi-line editor
ctrl-l:                          Creates a link with the code you have on the current line/lines

EDITOR FUNCTIONALITY
Up/Down Arrow and ctrl-p/ctrl-n: Navigate through history
ctrl-a:                          Beginning of line
ctrl-e:                          End of line
ctrl-b:                          Back 1 character
ctrl-f:                          Forward 1 character
ctrl-d:                          Delete 1 character
ctrl-k:                          Kill to the end of the line
alt-b:                           Back 1 word
alt-f:                           Forward 1 word
alt-d:                           Delete 1 word
 =&amp;gt; nil
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-sec-2&quot;&gt;
&lt;h2 id=&quot;sec-2&quot;&gt;
Beyond irb&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-2&quot;&gt;
There are number of things that opal-irb does that irb does not:&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-sec-2-1&quot;&gt;
&lt;h3 id=&quot;sec-2-1&quot;&gt;
&quot;Live gist&quot;, create a link w/code&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-2-1&quot;&gt;
To be able to share the code at the prompt in&amp;nbsp;&lt;b&gt;opal-irb&lt;/b&gt;, hit&amp;nbsp;&lt;code&gt;ctl-l&lt;/code&gt;&amp;nbsp;(&lt;code&gt;l&lt;/code&gt;&amp;nbsp;for&amp;nbsp;&lt;code&gt;link&lt;/code&gt;), and the link will be shown above the line in question. To get a link for any other part of the history you can simply navigate the history and then hit ctl-l on the desired code.&lt;br /&gt;
I like to call this feature &quot;Live gist.&quot; Like a gist, it&#39;s shareable bit of code. Unlike a gist, it&#39;s &quot;live code&quot; – clicking link puts you in an environment in which you can play with the code.&lt;br /&gt;
This code link can be shared in real app that has opal-irb embedded. I have already used this in a production codebase to duplicate a bug condition for a coworker to debug.&lt;br /&gt;
The various embedded opal-irb&#39;s on this page are all done via &quot;live gist.&quot;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-sec-2-2&quot;&gt;
&lt;h3 id=&quot;sec-2-2&quot;&gt;
Enhanced History&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-2-2&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-4&quot; id=&quot;outline-container-sec-2-2-1&quot;&gt;
&lt;h4 id=&quot;sec-2-2-1&quot;&gt;
History Command (like shells have, bash, etc.)&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-2-2-1&quot;&gt;
You can type&amp;nbsp;&lt;code&gt;history&lt;/code&gt;&amp;nbsp;at the prompt to get a listing of your history. You will get a listing of the code you&#39;ve typed in including line numbers.&lt;br /&gt;
&lt;pre class=&quot;example&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: auto; padding: 8pt;&quot;&gt;opal&amp;gt; history
1: class Foo
  def bar
    :bar
  end
end
2: f = Foo.new
3: f.bar
4: history
 =&amp;gt; nil
opal&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-4&quot; id=&quot;outline-container-sec-2-2-2&quot;&gt;
&lt;h4 id=&quot;sec-2-2-2&quot;&gt;
Link for History&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-2-2-2&quot;&gt;
As an alternate to navigating through history and typing&amp;nbsp;&lt;code&gt;ctrl-l&lt;/code&gt;, you can generate a &quot;live gist&quot; with the&amp;nbsp;&lt;code&gt;irb_link_for&lt;/code&gt;&amp;nbsp;command, using the history number shown by the history command. This behavior differs from&amp;nbsp;&lt;code&gt;jsbin&lt;/code&gt;,&amp;nbsp;&lt;code&gt;jsfiddle&lt;/code&gt;, etc. in that you do a bunch of experimentation and then quickly generate several &quot;live gists&quot; - a behavior that I think matches repl-based experimentation.&lt;br /&gt;
&lt;pre class=&quot;example&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: auto; padding: 8pt;&quot;&gt;irb_link_for &lt;history_num&gt;
&lt;/history_num&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-sec-2-3&quot;&gt;
&lt;h3 id=&quot;sec-2-3&quot;&gt;
Multiline edit&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-2-3&quot;&gt;
While&amp;nbsp;&lt;b&gt;opal-irb&lt;/b&gt;&amp;nbsp;supports multi-line input in the same fashion as&amp;nbsp;&lt;b&gt;irb&lt;/b&gt;, I have to confess that I&#39;ve often made typos with multi-line input. This required me to start over since there is no way edit a previous line. If you&#39;ve done this, you know my pain. You have to hit&amp;nbsp;&lt;code&gt;ctrl-c&lt;/code&gt;&amp;nbsp;to interrupt it and start again.&lt;br /&gt;
To address this, I added multi-line editor support. To invoke it, hit&amp;nbsp;&lt;code&gt;ctl-m&lt;/code&gt;&amp;nbsp;(m for the multi-line editor) and a window will pop up with whatever code you had on the prompt. The editor has syntax highlighting, some level smart indenting and a WIP autocomplete functionality.&lt;br /&gt;
The editor can be used with all code in the history. Simply navigate back to the desired code in your history and hit&amp;nbsp;&lt;code&gt;ctl-m&lt;/code&gt;.&lt;br /&gt;
To run the code either hit the run it button, or the&amp;nbsp;&lt;code&gt;ctrl-Enter&lt;/code&gt;&amp;nbsp;short cut. To close the window, either hit the close icon, or hit escape.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-sec-2-4&quot;&gt;
&lt;h3 id=&quot;sec-2-4&quot;&gt;
Requiring code at run time&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-2-4&quot;&gt;
One of the purposes for&amp;nbsp;&lt;b&gt;opal-irb&lt;/b&gt;&amp;nbsp;is to be able to explore things at run-time. To help facilitate this, there are 2 commands.&lt;/div&gt;
&lt;div class=&quot;outline-4&quot; id=&quot;outline-container-sec-2-4-1&quot;&gt;
&lt;h4 id=&quot;sec-2-4-1&quot;&gt;
require_remote&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-2-4-1&quot;&gt;
Part of&amp;nbsp;&lt;b&gt;opal-parser&lt;/b&gt;,&amp;nbsp;&lt;code&gt;require_remote&lt;/code&gt;&amp;nbsp;allows you require a remote ruby file.&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;require_remote &lt;url_to_ruby_file&gt;&lt;span style=&quot;color: #cc9393;&quot;&gt;&quot;&lt;/span&gt;
&lt;/url_to_ruby_file&gt;&lt;/pre&gt;
&lt;/div&gt;
As an example, I&#39;ll require the raw form of this gist, which prints out &quot;require_remote is cool&quot; 10 times.&lt;br /&gt;
&lt;div class=&quot;gist&quot; id=&quot;gist24880677&quot; style=&quot;color: #333333; direction: ltr; font-size: 16px;&quot;&gt;
&lt;div class=&quot;gist-file&quot; style=&quot;border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-color: rgb(221, 221, 221) rgb(221, 221, 221) rgb(204, 204, 204); border-style: solid; border-top-left-radius: 3px; border-top-right-radius: 3px; border-width: 1px; font-family: Consolas, &#39;Liberation Mono&#39;, Menlo, Courier, monospace; margin-bottom: 1em;&quot;&gt;
&lt;div class=&quot;gist-data&quot; style=&quot;background-color: white; border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-bottom-width: 1px; overflow: auto; word-wrap: normal;&quot;&gt;
&lt;div class=&quot;js-gist-file-update-container js-task-list-container file-box&quot;&gt;
&lt;div class=&quot;file&quot; id=&quot;file-require_remote_is_cool-rb&quot;&gt;
&lt;div class=&quot;blob-wrapper data type-ruby&quot; style=&quot;border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; overflow-x: auto; overflow-y: hidden;&quot;&gt;
&lt;table class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;8&quot; style=&quot;border-collapse: collapse; border: 0px; color: #333333; font-size: 12px; line-height: 1.4; margin: 0px; padding: 0px;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td class=&quot;blob-num js-line-number&quot; data-line-number=&quot;1&quot; id=&quot;file-require_remote_is_cool-rb-L1&quot; style=&quot;-webkit-user-select: none; background-color: transparent; border-color: rgb(238, 238, 238); border-style: solid; border-width: 0px 1px 0px 0px; color: rgba(0, 0, 0, 0.298039); cursor: pointer; line-height: 18px; min-width: inherit; padding: 1px 10px !important; text-align: right; vertical-align: top; white-space: nowrap; width: 7px;&quot;&gt;&lt;/td&gt;&lt;td class=&quot;blob-code blob-code-inner js-file-line&quot; id=&quot;file-require_remote_is_cool-rb-LC1&quot; style=&quot;background-color: transparent; border: 0px; overflow: visible; padding: 1px 10px !important; position: relative; vertical-align: top; white-space: pre; word-wrap: normal;&quot;&gt;(&lt;span class=&quot;pl-c1&quot; style=&quot;color: #0086b3;&quot;&gt;0&lt;/span&gt;..&lt;span class=&quot;pl-c1&quot; style=&quot;color: #0086b3;&quot;&gt;10&lt;/span&gt;).each {|&lt;span class=&quot;pl-smi&quot;&gt;i&lt;/span&gt;| puts &lt;span class=&quot;pl-s&quot; style=&quot;color: #183691;&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;require_remote is cool&lt;span class=&quot;pl-pds&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; }&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;gist-meta&quot; style=&quot;background-color: #f7f7f7; color: #767676; font-family: Helvetica, arial, nimbussansl, liberationsans, freesans, clean, sans-serif, &#39;Segoe UI Emoji&#39;, &#39;Segoe UI Symbol&#39;; font-size: 12px; overflow: hidden; padding: 10px;&quot;&gt;
&lt;a href=&quot;https://gist.github.com/fkchang/c52173c276976a9ccede/raw/e1f92fdcc1592401cb0811dd1d180521ba0c65d3/require_remote_is_cool.rb&quot; style=&quot;border: 0px; color: #666666; float: right; font-weight: bold; text-decoration: none;&quot;&gt;view raw&lt;/a&gt;&lt;a href=&quot;https://gist.github.com/fkchang/c52173c276976a9ccede#file-require_remote_is_cool-rb&quot; style=&quot;border: 0px; color: #666666; font-weight: bold; text-decoration: none;&quot;&gt;require_remote_is_cool.rb&lt;/a&gt;&amp;nbsp;hosted with ❤ by&amp;nbsp;&lt;a href=&quot;https://github.com/&quot; style=&quot;border: 0px; color: #666666; font-weight: bold; text-decoration: none;&quot;&gt;GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
You can try this&amp;nbsp;&lt;a href=&quot;https://git.io/vOmoR&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;from here&lt;/a&gt;&amp;nbsp;if the embedded iframe below doesn&#39;t look right&lt;br /&gt;
&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;500&quot; src=&quot;https://fkchang.github.io/opal-irb/index-jq.html#code:require_remote%20&#39;https%3A%2F%2Fgist.githubusercontent.com%2Ffkchang%2Fc52173c276976a9ccede%2Fraw%2Fe1f92fdcc1592401cb0811dd1d180521ba0c65d3%2Frequire_remote_is_cool.rb&#39;&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-4&quot; id=&quot;outline-container-sec-2-4-2&quot;&gt;
&lt;h4 id=&quot;sec-2-4-2&quot;&gt;
require_js (asynchronous require)&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-2-4-2&quot;&gt;
require_js allows you to require javascript with a URL. It is asynchronous, which when typed in by hand, is usually fine, the file will get required before your code that uses it gets done. If not hand typed, say via live-gist, you&#39;ll need to put some sort of delay. I&#39;ve made a raphael based example.&lt;br /&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;does a&amp;nbsp;&lt;code&gt;require_js&lt;/code&gt;&amp;nbsp;of the raphael.js lib&lt;/li&gt;
&lt;li&gt;Adds a reanimate button (via Opal-browser&#39;s DOM DSL)&lt;/li&gt;
&lt;li&gt;delays via a&amp;nbsp;&lt;code&gt;Timeout&lt;/code&gt;&amp;nbsp;and creates an animation and bind reanimation code to the reanimate button&lt;/li&gt;
&lt;/ul&gt;
You can try this&amp;nbsp;&lt;a href=&quot;http://git.io/vOm1c&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;directly here&lt;/a&gt;&amp;nbsp;if the embedded iframe below doesn&#39;t look right&lt;br /&gt;
&lt;iframe allowfullscreen=&quot;&quot; animate=&quot;&quot; aphael=&quot;&quot; ative=&quot;&quot; b.append_to=&quot;&quot; bbb=&quot;&quot; blue=&quot;&quot; body=&quot;&quot; circle.animate=&quot;&quot; circle=&quot;&quot; click=&quot;&quot; def=&quot;&quot; document=&quot;&quot; duration=&quot;&quot; end=&quot;&quot; enough=&quot;&quot; fa3=&quot;&quot; fff=&quot;&quot; fill=&quot;&quot; frameborder=&quot;0&quot; give=&quot;&quot; gold=&quot;&quot; green=&quot;&quot; height=&quot;500&quot; i=&quot;&quot; imeout.new=&quot;&quot; lement.id=&quot;&quot; load=&quot;&quot; main=&quot;&quot; none=&quot;&quot; on=&quot;&quot; orange=&quot;&quot; paper.circle=&quot;&quot; paper.rect=&quot;&quot; paper=&quot;&quot; pink=&quot;&quot; reanimate=&quot;&quot; rect.attr=&quot;&quot; rect=&quot;&quot; red=&quot;&quot; require_js=&quot;&quot; reset=&quot;&quot; size=&quot;&quot; src=&quot;https://fkchang.github.io/opal-irb/index-jq.html#code:require_js%20&#39;https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fraphael%2F2.1.4%2Fraphael-min.js&#39;%0ADocument.ready%3F%20do%20%0A%20%20%23%20adding%20a%20button%20w%2Fopal-browser%2C%20because...%0A%20%20b%20%3D%20DOM%20do%20%0A%20%20%20%20button.main!%20&quot; stroke-width=&quot;&quot; stroke=&quot;&quot; stroke_opacity=&quot;&quot; stroke_width=&quot;&quot; time=&quot;&quot; to=&quot;&quot; w=&quot;&quot; white=&quot;&quot; yellow=&quot;&quot;&gt;%20%24stroke_width%2C%0A%20%20%20%20%20%20&#39;stroke-opacity&#39;%20%3D&gt;%20%24stroke_opacity%7D%2C%20%0A%20%20%20%20%24duration)%0Aend%0Adef%20reset%0A%20%20%24paper.clear%0A%20%20%24circle%20%3D%20%24paper.circle(100%2C%20100%2C%2060)%0Aend&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-4&quot; id=&quot;outline-container-sec-2-4-3&quot;&gt;
&lt;h4 id=&quot;sec-2-4-3&quot;&gt;
require_js_sync (synchronous require)&lt;/h4&gt;
&lt;div class=&quot;outline-text-4&quot; id=&quot;text-2-4-3&quot;&gt;
Synchronous calls are atypical with javascript api&#39;s, chrome says this is deprecated, so it might be going away in chrome any time. That being said, if you are going to script a &quot;live gist&quot; or similar, this may be more handing than putting in a delay&lt;br /&gt;
For an example, I do the same raphael example, but without the delay&lt;br /&gt;
You can try this&amp;nbsp;&lt;a href=&quot;http://git.io/vOmDg&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;directly here&lt;/a&gt;&amp;nbsp;if the embedded iframe below doesn&#39;t look right&lt;br /&gt;
&lt;iframe allowfullscreen=&quot;&quot; animate=&quot;&quot; aphael=&quot;&quot; ative=&quot;&quot; b.append_to=&quot;&quot; bbb=&quot;&quot; blue=&quot;&quot; body=&quot;&quot; circle=&quot;&quot; click=&quot;&quot; document=&quot;&quot; duration=&quot;&quot; end=&quot;&quot; fa3=&quot;&quot; fff=&quot;&quot; fill=&quot;&quot; frameborder=&quot;0&quot; gold=&quot;&quot; green=&quot;&quot; height=&quot;500&quot; i=&quot;&quot; lement.id=&quot;&quot; main=&quot;&quot; none=&quot;&quot; on=&quot;&quot; orange=&quot;&quot; paper.circle=&quot;&quot; paper.rect=&quot;&quot; paper=&quot;&quot; pink=&quot;&quot; reanimate=&quot;&quot; rect.attr=&quot;&quot; rect=&quot;&quot; red=&quot;&quot; reset=&quot;&quot; size=&quot;&quot; src=&quot;https://fkchang.github.io/opal-irb/index-jq.html#code:def%20animate%0A%20%20%24circle.animate(%20%7Bfill%3A%20%24fill%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20stroke%3A%20%24stroke%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20&#39;stroke-width&#39;%20%3D&amp;gt;%20%24stroke_width%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20&#39;stroke-opacity&#39;%20%3D&amp;gt;%20%24stroke_opacity%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24duration)%0Aend%0Adef%20reset%0A%20%20%24paper.clear%0A%20%20%24circle%20%3D%20%24paper.circle(100%2C%20100%2C%2060)%0Aend%0ADocument.ready%3F%20do%0A%20%20require_js_sync%20&#39;https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fraphael%2F2.1.4%2Fraphael-min.js&#39;%0A%20%20%23%20adding%20a%20button%20w%2Fopal-browser%2C%20because...%0A%20%20b%20%3D%20DOM%20do%0A%20%20%20%20button.main!%20&quot; stroke=&quot;&quot; stroke_opacity=&quot;&quot; stroke_width=&quot;&quot; w=&quot;&quot; white=&quot;&quot; width=&quot;100%&quot; yellow=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-sec-2-5&quot;&gt;
&lt;h3 id=&quot;sec-2-5&quot;&gt;
Say, say, say, what you want…&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-2-5&quot;&gt;
On&amp;nbsp;&lt;b&gt;osx&lt;/b&gt;, I make lots of use of the built-in&amp;nbsp;&lt;code&gt;say&lt;/code&gt;&amp;nbsp;command. For example, I have a function that copies over the production database and loads it into a designated database. The data is not small and this can take a while, so the function lets me know what step it&#39;s doing. This allows me to do other work while it&#39;s happening. So even if my terminal window is obscured, I&#39;ll know when the job is done the moment it happens.&lt;br /&gt;
This might be a novelty in the browser, but I decided to implement that for opal-irb. I&#39;ll likely make it a full-fledged gem in the future.&lt;br /&gt;
You can try this&amp;nbsp;&lt;a href=&quot;http://git.io/vYveZ&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;directly here&lt;/a&gt;&amp;nbsp;if the embedded iframe below doesn&#39;t look right. In either case, type in&amp;nbsp;&lt;code&gt;say_something&lt;/code&gt;&amp;nbsp;to try it out. This is only supported by default in reasonably modern webkit browsers. Firefox supports speech but it has to be turned on. You can check for browser capability&amp;nbsp;&lt;a href=&quot;http://caniuse.com/#feat=speech-synthesis&quot;&gt;here&lt;/a&gt;&lt;br /&gt;
&lt;iframe allowfullscreen=&quot;&quot; also=&quot;&quot; appreciate=&quot;&quot; do=&quot;&quot; end=&quot;&quot; frameborder=&quot;0&quot; height=&quot;500&quot; is=&quot;&quot; nifty=&quot;&quot; pal=&quot;&quot; pretty=&quot;&quot; say=&quot;&quot; src=&quot;https://fkchang.github.io/opal-irb/index-jq.html#code:def%20say_something%0A%20%20(1..8).each%20%7B%7Ci%7C%20say%20i%7D%0A%20%20say%20&quot; we=&quot;&quot; who=&quot;&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-sec-3&quot;&gt;
&lt;h2 id=&quot;sec-3&quot;&gt;
Examples&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-3&quot;&gt;
I have several example opal-irb pages referenced from the README on&amp;nbsp;&lt;a href=&quot;https://github.com/fkchang/opal-irb&quot;&gt;https://github.com/fkchang/opal-irb&lt;/a&gt;. They are:&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-sec-3-1&quot;&gt;
&lt;h3 id=&quot;sec-3-1&quot;&gt;
Homebrew console example&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-3-1&quot;&gt;
&lt;a href=&quot;http://fkchang.github.io/opal-irb/index-homebrew.html&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;http://fkchang.github.io/opal-irb/index-homebrew.html&lt;/a&gt;&lt;br /&gt;
&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;500&quot; src=&quot;https://fkchang.github.io/opal-irb/index-homebrew.html&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;This was my 1st attempt, port of a&amp;nbsp;&lt;a href=&quot;https://github.com/larryng/coffeescript-repl&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;coffescript repl&lt;/a&gt;&amp;nbsp;with hand written terminal code. It&#39;s not as full featured as the following&amp;nbsp;&lt;b&gt;jq-console example&lt;/b&gt;:&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-sec-3-2&quot;&gt;
&lt;h3 id=&quot;sec-3-2&quot;&gt;
jq-console Example&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-3-2&quot;&gt;
&lt;a href=&quot;http://fkchang.github.io/opal-irb/index-jq.html&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;http://fkchang.github.io/opal-irb/index-jq.html&lt;/a&gt;&lt;br /&gt;
&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;500&quot; src=&quot;https://fkchang.github.io/opal-irb/index-jq.html&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;This uses (a fork of)&amp;nbsp;&lt;code&gt;jq-console&lt;/code&gt;, for improved console support. Most of my development has been on a&amp;nbsp;&lt;code&gt;jq-console&lt;/code&gt;&amp;nbsp;based&amp;nbsp;&lt;b&gt;opal-irb&lt;/b&gt;, though I might revisit a&amp;nbsp;&lt;code&gt;jq-console&lt;/code&gt;&amp;nbsp;port because I&#39;d like to remove the&amp;nbsp;&lt;b&gt;jquery&lt;/b&gt;&amp;nbsp;dependency in&amp;nbsp;&lt;b&gt;opal-irb&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-sec-3-3&quot;&gt;
&lt;h3 id=&quot;sec-3-3&quot;&gt;
Embedded console example&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-3-3&quot;&gt;
&lt;a href=&quot;https://fkchang.github.io/opal-irb/index-embeddable.html&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;http://fkchang.github.io/opal-irb/index-embeddable.html&lt;/a&gt;&lt;br /&gt;
&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;700&quot; src=&quot;https://fkchang.github.io/opal-irb/index-embeddable.html&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;This example is closer to how I see&amp;nbsp;&lt;b&gt;opal-irb&lt;/b&gt;&amp;nbsp;being used in real apps - where&amp;nbsp;&lt;b&gt;opal-irb&lt;/b&gt;&amp;nbsp;is embedded with in the app/page itself. This example shows some nominal DOM elements, there for the purpose of providing DOM elements to manipulate with opal, and a button to show the&amp;nbsp;&lt;b&gt;irb&lt;/b&gt;&amp;nbsp;panel if it&#39;s been closed.&amp;nbsp;&amp;nbsp;&lt;b&gt;Opal-irb&lt;/b&gt;&amp;nbsp;supports 2 ways to invoke a hidden opal-irb:&lt;br /&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;hot key&lt;/li&gt;
&lt;li&gt;click event on a DOM element&lt;/li&gt;
&lt;/ul&gt;
Both are documented in the&amp;nbsp;&lt;a href=&quot;https://github.com/fkchang/opal-irb/blob/master/README.md&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;README&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-sec-3-4&quot;&gt;
&lt;h3 id=&quot;sec-3-4&quot;&gt;
Embedded in opal playground&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-3-4&quot;&gt;
&lt;a href=&quot;https://fkchang.github.io/opal-playground/&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;http://fkchang.github.io/opal-playground/&lt;/a&gt;&lt;br /&gt;
&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;800&quot; src=&quot;https://fkchang.github.io/opal-playground/&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;&lt;b&gt;Opal-irb&lt;/b&gt;&amp;nbsp;has been embedded into my fork of the&amp;nbsp;&lt;b&gt;opal-playground&lt;/b&gt;.&amp;nbsp;&lt;b&gt;Opal-irb&lt;/b&gt;&amp;nbsp;is available in the RESULTS section by hitting the blue &quot;Show Irb&quot; button. I am hoping to take the opal-playground direction more towards&amp;nbsp;&lt;b&gt;opal-inspector&lt;/b&gt;, but there are times you want to use a REPL in addition to just editing the code, and this provides that.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-sec-3-5&quot;&gt;
&lt;h3 id=&quot;sec-3-5&quot;&gt;
And much more&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-3-5&quot;&gt;
I demo a good number of these opal-irb features in my&amp;nbsp;&lt;a href=&quot;https://www.youtube.com/watch?feature=player_detailpage&amp;amp;v=GH9FAfKG-qY#t=1838&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;RubyConf 2013 talk &quot;Opal - A New Hope&quot;&lt;/a&gt;; this may be easier to digest than the written word.&lt;br /&gt;
I also made a&amp;nbsp;&lt;a href=&quot;https://www.youtube.com/watch?v=mQTulgBm5Nk&quot;&gt;video&lt;/a&gt;&amp;nbsp;for the in progress auto complete in the console.&lt;br /&gt;
This is just the beginning of much more with regard to in browser opal tools. I&amp;nbsp;&lt;a href=&quot;https://www.youtube.com/watch?feature=player_detailpage&amp;amp;v=GH9FAfKG-qY#t=2099&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;previewed&lt;/a&gt;&amp;nbsp;a prototype of opal-inspector 2 years back, and I intend on bringing features previously only supported in Smalltalk and Lisp machines.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;status&quot; id=&quot;postamble&quot; style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;div id=&quot;content&quot; style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-sec-3&quot;&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-sec-3-5&quot;&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-3-5&quot;&gt;
Thanks to&amp;nbsp;&lt;a href=&quot;http://blog.scottnelsonsmith.com/&quot;&gt;Scott Smith&lt;/a&gt;&amp;nbsp;for proofreading this.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/7111578141043707775/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/7111578141043707775' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/7111578141043707775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/7111578141043707775'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2015/08/an-overview-of-opal-irbs-features.html' title='An overview of opal-irb&#39;s features'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-8067592705193718379</id><published>2015-07-18T21:48:00.001-07:00</published><updated>2015-07-19T17:00:00.698-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="agile"/><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="opal"/><category scheme="http://www.blogger.com/atom/ns#" term="rspec"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>Sharing executable test code with opal-playground</title><content type='html'>&lt;br /&gt;
&lt;div class=&quot;status&quot; id=&quot;postamble&quot; style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;div id=&quot;content&quot; style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;&quot;&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-sec-1&quot;&gt;
&lt;h2 id=&quot;sec-1&quot;&gt;
Situation&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-1&quot;&gt;
I was reviewing a pull request from a non-colocated team mate. In discussing the pull request, I realized one of the assertions on his spec (we use&amp;nbsp;&lt;a href=&quot;http://rspec.info/&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;rspec&lt;/a&gt;) didn&#39;t work exactly the way he expected. To aid in the discussion, I sent him some code via chat. Shortly thereafter, I realized I could do better than just pasting in some code.&lt;br /&gt;
&quot;Do better?&quot; you ask. What do I mean? In general, what&#39;s the problem with sending a teammate a spec via chat, email, whatever?&lt;br /&gt;
When the teammate receives the code, he may want to run it in order to understand it. In this case, being a spec file, he will need to paste the code into a running test system to explore how it works.&lt;br /&gt;
That can be a bit of a hassle, especially when using Rails where specs often do not run that fast. It&#39;s not that running them is impossible, but it may be sufficiently inconvenient that one wouldn&#39;t just immediately do it.&lt;br /&gt;
Here&#39;s the epiphany:&lt;br /&gt;
What if I could send someone specs that:&lt;br /&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;ran nearly instantenously&lt;/li&gt;
&lt;li&gt;didn&#39;t require any setup&lt;/li&gt;
&lt;/ul&gt;
The remainder of this article shows you how.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-sec-2&quot;&gt;
&lt;h2 id=&quot;sec-2&quot;&gt;
Solution&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-2&quot;&gt;
Aside from the&amp;nbsp;&lt;code&gt;jsbin&lt;/code&gt;-like workspace,&amp;nbsp;&lt;a href=&quot;http://fkchang.github.io/opal-playground&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;opal-playground&lt;/a&gt;&amp;nbsp;has a&amp;nbsp;&lt;a href=&quot;http://fkchang.github.io/opal-playground/rspec/&quot;&gt;rspec page&lt;/a&gt;&amp;nbsp;configured to run spec tests by writing or pasting them in and executing. Now instead of sending my co-workers snippets of code, I test the spec in the Opal playground and test it. When I&#39;m satisfied that it&#39;s doing what I want, I send the link directly to him. Here&#39;s what I originally pasted to him:&lt;br /&gt;
(I&#39;ve embedded the actual rspec page in an iframe&amp;nbsp;&lt;a href=&quot;http://git.io/vmalc&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;direct link&lt;/a&gt;&amp;nbsp;if below iframe doesn&#39;t look right in your browser). You can vertically scroll the text pane to see the remaining&amp;nbsp;&lt;b&gt;rspec&lt;/b&gt;&amp;nbsp;content.&lt;br /&gt;
&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;500&quot; src=&quot;http://git.io/vmalc&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;Note that both tests pass. You can change the code and press the blue&amp;nbsp;&lt;b&gt;Run Code&lt;/b&gt;&amp;nbsp;button (it will be under the &quot;hamburger menu&quot; in the upper right corner if the browser width is narrow enough) to run it again. Notice that the 2nd test&#39;s &quot;it&quot; statement says it should fail, but it passes.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-sec-3&quot;&gt;
&lt;h2 id=&quot;sec-3&quot;&gt;
How Technology Helped Solve the Original Problem&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-3&quot;&gt;
The code in these rspec pages are not the code in the PR, but rather simplified code that exercises expectations in the same or similar fashion to the code in the original PR. The problem in the original pull request contained a rspec stating that a method (in this sample&#39;s case&amp;nbsp;&lt;code&gt;#name&lt;/code&gt;) must be invoked.&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;it &lt;span style=&quot;color: #cc9393;&quot;&gt;&quot;should initialize with the given name&quot;&lt;/span&gt; &lt;span style=&quot;color: #f0dfaf; font-weight: bold;&quot;&gt;do&lt;/span&gt;
  allow_any_instance_of(&lt;span style=&quot;color: #7cb8bb;&quot;&gt;User&lt;/span&gt;).to receive(&lt;span style=&quot;color: #bfebbf;&quot;&gt;:name&lt;/span&gt;)
  u = &lt;span style=&quot;color: #7cb8bb;&quot;&gt;User&lt;/span&gt;.new
&lt;span style=&quot;color: #f0dfaf; font-weight: bold;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
As you can see above, the&amp;nbsp;&lt;code&gt;#name&lt;/code&gt;&amp;nbsp;method is never invoked and yet the specs still passes. So I changed the &quot;it&quot; comment to point this out and sent it to the teammate:&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;it &lt;span style=&quot;color: #cc9393;&quot;&gt;&quot;should fail&quot;&lt;/span&gt; &lt;span style=&quot;color: #f0dfaf; font-weight: bold;&quot;&gt;do&lt;/span&gt;
  allow_any_instance_of(   &lt;span style=&quot;color: #7cb8bb;&quot;&gt;User&lt;/span&gt;).to receive(&lt;span style=&quot;color: #bfebbf;&quot;&gt;:name&lt;/span&gt;)
  u = &lt;span style=&quot;color: #7cb8bb;&quot;&gt;User&lt;/span&gt;.new
&lt;span style=&quot;color: #f0dfaf; font-weight: bold;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
Before my teammate had the time to digest the implications, he countered with a suggestion code suggestion.&lt;br /&gt;
&lt;blockquote&gt;
try allow_any_instance_of(Kass).to receive(:stuff).with(params)&lt;/blockquote&gt;
To which I replied&lt;br /&gt;
&lt;blockquote&gt;
Why should adding&amp;nbsp;&lt;code&gt;with&lt;/code&gt;&amp;nbsp;make it pass?&lt;/blockquote&gt;
Following my lead, he countered with his own spec to demonstrate&lt;br /&gt;
(&lt;a href=&quot;http://git.io/vma45&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;direct link&lt;/a&gt;&amp;nbsp;if below iframe doesn&#39;t look right)&lt;br /&gt;
&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;500&quot; src=&quot;http://git.io/vma45&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;What his spec showed was that is if he added a parameter expecation, and the method expected to be called was called, but not with that parameter, the spec will fail&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;it &lt;span style=&quot;color: #cc9393;&quot;&gt;&quot;should fail&quot;&lt;/span&gt; &lt;span style=&quot;color: #f0dfaf; font-weight: bold;&quot;&gt;do&lt;/span&gt;
  allow_any_instance_of(&lt;span style=&quot;color: #7cb8bb;&quot;&gt;User&lt;/span&gt;).to receive(&lt;span style=&quot;color: #bfebbf;&quot;&gt;:name&lt;/span&gt;).with(&lt;span style=&quot;color: #cc9393;&quot;&gt;&#39;hello&#39;&lt;/span&gt;)
  u = &lt;span style=&quot;color: #7cb8bb;&quot;&gt;User&lt;/span&gt;.new
  u.name
&lt;span style=&quot;color: #f0dfaf; font-weight: bold;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
Soon thereafter, he reasoned about he realized I was right.&lt;br /&gt;
&lt;blockquote&gt;
Oh… but I see that you&#39;re saying what if it&#39;s not called at all?&lt;/blockquote&gt;
To confirm his understanding, I sent a spec which uses his expectation, should fail if his understanding was correct, but passed:&lt;br /&gt;
(&lt;a href=&quot;http://git.io/vqMDa&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;direct link&lt;/a&gt;&amp;nbsp;if below iframe doesn&#39;t look right)&lt;br /&gt;
&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;550&quot; src=&quot;http://git.io/vqMDa&quot; width=&quot;100%&quot;&gt;&lt;/iframe&gt;The spec in question that proved my point, which was the mistake in his PR.&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;it &lt;span style=&quot;color: #cc9393;&quot;&gt;&quot;will pass if not called at all&quot;&lt;/span&gt; &lt;span style=&quot;color: #f0dfaf; font-weight: bold;&quot;&gt;do&lt;/span&gt;
  allow_any_instance_of(&lt;span style=&quot;color: #7cb8bb;&quot;&gt;User&lt;/span&gt;).to receive(&lt;span style=&quot;color: #bfebbf;&quot;&gt;:name&lt;/span&gt;).with(&lt;span style=&quot;color: #cc9393;&quot;&gt;&#39;hello&#39;&lt;/span&gt;)
  u = &lt;span style=&quot;color: #7cb8bb;&quot;&gt;User&lt;/span&gt;.new
&lt;span style=&quot;color: #f0dfaf; font-weight: bold;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
With that knowledge gained, my teammate was able to construct his spec in a way that tested what it was supposed to.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-sec-4&quot;&gt;
&lt;h2 id=&quot;sec-4&quot;&gt;
Summary&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-4&quot;&gt;
In doing code discussion, some tool support can be handy. Sometimes even the exact code is not enough - while it&#39;s not ambiguous to the interpreter or compiler, it&#39;s not always clear to the programmer. A key goal of Agile is to improve communication. In this case, discussing&amp;nbsp;&lt;b&gt;rspec&lt;/b&gt;&amp;nbsp;specs using the rspec &quot;worksheet&quot; page helped a bunch.&lt;br /&gt;
It was:&lt;br /&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Quick: write some, easily run without any setup&lt;/li&gt;
&lt;li&gt;Collaborative: you can send them back and forth&lt;/li&gt;
&lt;li&gt;Facillitated communication: my teammate quickly responded in kind&lt;/li&gt;
&lt;li&gt;Retainable as a url: he can always go back and review the example via the url vs. digging through a large spec file to find it. While collocation is best for communication, &quot;executable rspec gists&quot; can help to mitigate the &quot;distance&quot; barrier when the teammate is remote.&lt;/li&gt;
&lt;li&gt;While facilitated by opal, the code itself doesn&#39;t have to be client-side opal; the code discussed above was, indeed, backend code.&lt;/li&gt;
&lt;/ul&gt;
Other uses:&lt;br /&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Send exercises while mentoring&lt;/li&gt;
&lt;li&gt;Perform a code interview without needing setup.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-sec-5&quot;&gt;
&lt;h2 id=&quot;sec-5&quot;&gt;
Teaser&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-5&quot;&gt;
I plan on making some more log posts on how opal based tools can help with collaboration&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/8067592705193718379/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/8067592705193718379' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/8067592705193718379'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/8067592705193718379'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2015/07/sharing-executable-test-code-with-opal.html' title='Sharing executable test code with opal-playground'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-6493064182198343801</id><published>2015-06-24T20:02:00.000-07:00</published><updated>2015-06-24T20:07:18.476-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="opal"/><category scheme="http://www.blogger.com/atom/ns#" term="opal-jquery"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby-fying javascript"/><title type='text'>Ruby-fying JavaScript - Wrapping opal-jquery</title><content type='html'>In my last post about&amp;nbsp;&lt;a href=&quot;http://funkworks.blogspot.com/2015/06/accessing-javascript-from-opal.html&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;accessing JavaScript from Opal&lt;/a&gt;, I asserted that it is preferable to wrap JavaScript libraries in&amp;nbsp;&lt;b&gt;Opal&lt;/b&gt;; the reasons why are best shown by example.&lt;br /&gt;
Let&#39;s look at&amp;nbsp;&lt;a href=&quot;https://github.com/opal/opal-jquery&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;Opal-jquery&lt;/a&gt;, one of the &quot;official Opal libraries&quot;, as a source of good concrete examples.&amp;nbsp;&lt;b&gt;Opal-jquery&lt;/b&gt;&amp;nbsp;wraps&amp;nbsp;&lt;b&gt;jQuery&lt;/b&gt;&amp;nbsp;with an idiomatic&amp;nbsp;&lt;b&gt;Ruby&lt;/b&gt;&amp;nbsp;frontend. There are some differences from the original JavaScript API, but my opinion it that these changes are for the better.&lt;br /&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-sec-1&quot;&gt;
&lt;h2 id=&quot;sec-1&quot;&gt;
Basic jQuery&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-1&quot;&gt;
I call the&amp;nbsp;&lt;code&gt;jQuery/$&lt;/code&gt;&amp;nbsp;function &quot;jQuery&#39;s universal entry point.&quot; Nearly all uses of&amp;nbsp;&lt;b&gt;jQuery&lt;/b&gt;&amp;nbsp;start from this function. One of the primary uses of&amp;nbsp;&lt;code&gt;$&lt;/code&gt;&amp;nbsp;is as a selector for elements. It is very typical to chain one or more actions directly from the selector, as shown here:&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-javascript&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;$(&lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;a&#39;&lt;/span&gt;).action()                                 &lt;span style=&quot;color: #5f7f5f;&quot;&gt;// &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;select by node type&lt;/span&gt;
$(&lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;#element-id&#39;&lt;/span&gt;).action().action2()             &lt;span style=&quot;color: #5f7f5f;&quot;&gt;// &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;select by id&lt;/span&gt;
$(&lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;.cssSelector&#39;&lt;/span&gt;).action().action2().action3()  &lt;span style=&quot;color: #5f7f5f;&quot;&gt;// &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;select by class&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
Interestingly, this same &quot;universal entry point&quot; function is also how one sets up &quot;Document ready&quot; actions. All of the various invocations below&amp;nbsp;&lt;i&gt;can&lt;/i&gt;&amp;nbsp;be used to setup &quot;Document ready&quot; actions.&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-javascript&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;$(document).ready(&lt;span style=&quot;color: brown; font-weight: bold;&quot;&gt;function&lt;/span&gt;() {alert(&lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;document is ready&#39;&lt;/span&gt;)});
$(&lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;p&#39;&lt;/span&gt;).ready(&lt;span style=&quot;color: brown; font-weight: bold;&quot;&gt;function&lt;/span&gt;(){alert(&lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;fires whether or not there is p element&#39;&lt;/span&gt;)});
$(&lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;never-matching_selector&#39;&lt;/span&gt;).ready(&lt;span style=&quot;color: brown; font-weight: bold;&quot;&gt;function&lt;/span&gt;(){alert(&lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;still fires&#39;&lt;/span&gt;)});
$().ready(&lt;span style=&quot;color: brown; font-weight: bold;&quot;&gt;function&lt;/span&gt;() { alert(&lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;this works, but the doc says &quot;not recommended&quot;&#39;&lt;/span&gt;)});
$(&lt;span style=&quot;color: brown; font-weight: bold;&quot;&gt;function&lt;/span&gt;(){ alert(&lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;function called directly&#39;&lt;/span&gt;);});
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-sec-2&quot;&gt;
&lt;h2 id=&quot;sec-2&quot;&gt;
Ruby-fying Javascript - Object oriented basic jQuery&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-2&quot;&gt;
Rather than having a function that is the universal entry point,&amp;nbsp;&lt;code&gt;opal-jquery&lt;/code&gt;&amp;nbsp;assigns selector entry points to appropriate constants (classes/objects). At the top level, we call these selectors from the constants themselves.&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-sec-2-1&quot;&gt;
&lt;h3 id=&quot;sec-2-1&quot;&gt;
Selectors&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-2-1&quot;&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #2f8b58; font-weight: bold;&quot;&gt;Element&lt;/span&gt;.find(&lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;#mydiv&#39;&lt;/span&gt;)          &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;top level find&lt;/span&gt;
&lt;span style=&quot;color: #2f8b58; font-weight: bold;&quot;&gt;Document&lt;/span&gt;.find(&lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;#mydiv&#39;&lt;/span&gt;)         &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;Document is a special instance of Element&lt;/span&gt;
&lt;span style=&quot;color: #2f8b58; font-weight: bold;&quot;&gt;Element&lt;/span&gt;.id(&lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;mydiv&#39;&lt;/span&gt;)             &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;find by id&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
I like that&amp;nbsp;&lt;code&gt;find()&lt;/code&gt;&amp;nbsp;is a consistent selector. It can find from the top, and relative to an&amp;nbsp;&lt;code&gt;Element&lt;/code&gt;&amp;nbsp;instance.&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;mydiv = &lt;span style=&quot;color: #2f8b58; font-weight: bold;&quot;&gt;Element&lt;/span&gt;.find &lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;#mydiv&#39;&lt;/span&gt;
h1_children_of_mydiv = mdiv.find &lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;h1&#39;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;code&gt;Opal-jquery&lt;/code&gt;&amp;nbsp;also implements a Ruby convention where the&amp;nbsp;&lt;code&gt;Element.[]&lt;/code&gt;&amp;nbsp;method is used as a selector. This comes in handy for those who miss the terseness of&amp;nbsp;&lt;b&gt;$&lt;/b&gt;.&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;mydiv = &lt;span style=&quot;color: #2f8b58; font-weight: bold;&quot;&gt;Element&lt;/span&gt;[&lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;#mydiv&#39;&lt;/span&gt;]
ols = &lt;span style=&quot;color: #2f8b58; font-weight: bold;&quot;&gt;Element&lt;/span&gt;[&lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;ol&#39;&lt;/span&gt;]
help_sections = &lt;span style=&quot;color: #2f8b58; font-weight: bold;&quot;&gt;Element&lt;/span&gt;[&lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;.help&#39;&lt;/span&gt;]
&lt;/pre&gt;
&lt;/div&gt;
Opal-jquery moves jQuery functionality from a &quot;universal entry point&quot; function, to appropriate constants, classes and modules. Here&#39;s a brief summary of these constants:&lt;br /&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;&lt;code&gt;Element&lt;/code&gt;&amp;nbsp;- bridged class to the&amp;nbsp;&lt;b&gt;jQuery&lt;/b&gt;&amp;nbsp;object.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Document&lt;/code&gt;&amp;nbsp;- object as constance, instance of&amp;nbsp;&lt;code&gt;Element&lt;/code&gt;, extended with selected document specific methods.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Event&lt;/code&gt;&amp;nbsp;- class encapsulating events.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HTTP&lt;/code&gt;&amp;nbsp;- class wrapping&amp;nbsp;&lt;b&gt;jQuery&lt;/b&gt;&amp;nbsp;ajax functionality.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LocalStorage&lt;/code&gt;&amp;nbsp;- not part of&amp;nbsp;&lt;b&gt;jQuery&lt;/b&gt;, local storage wrapper for convenience.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Kernel&lt;/code&gt;&amp;nbsp;- extended with&amp;nbsp;&lt;code&gt;alert()&lt;/code&gt;&amp;nbsp;so it&#39;s accessible everywhere, like it is in JavaScript.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-3&quot; id=&quot;outline-container-sec-2-2&quot;&gt;
&lt;h3 id=&quot;sec-2-2&quot;&gt;
Document Ready&lt;/h3&gt;
&lt;div class=&quot;outline-text-3&quot; id=&quot;text-2-2&quot;&gt;
In&amp;nbsp;&lt;b&gt;Opal-jQuery&lt;/b&gt;&amp;nbsp;&quot;Document ready&quot; actions are setup with&amp;nbsp;&lt;code&gt;Document.ready?()&lt;/code&gt;&amp;nbsp;method:&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #2f8b58; font-weight: bold;&quot;&gt;Document&lt;/span&gt;.ready? &lt;span style=&quot;color: brown; font-weight: bold;&quot;&gt;do&lt;/span&gt;
  alert &lt;span style=&quot;color: #4e9a06;&quot;&gt;&quot;Welcome to opal-jquery!&quot;&lt;/span&gt;
&lt;span style=&quot;color: brown; font-weight: bold;&quot;&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;code&gt;Document.ready?()&lt;/code&gt;&amp;nbsp;employs 2 Ruby idioms:&lt;br /&gt;
&lt;ol class=&quot;org-ol&quot;&gt;
&lt;li&gt;The method name ends in a &#39;?&#39;, which reads well to my eyes.&lt;/li&gt;
&lt;li&gt;It takes a block, which also reads well.&amp;nbsp;&amp;nbsp;&lt;b&gt;Opal-jquery&lt;/b&gt;&amp;nbsp;departs from&amp;nbsp;&lt;b&gt;jQuery&lt;/b&gt;&#39;s single universal function for all of the ways to setup &quot;Document ready&quot; actions.&lt;/li&gt;
&lt;/ol&gt;
A number of the &quot;Document ready&quot; Javascript examples I showed above work, but don&#39;t make logical sense - i.e. calling&amp;nbsp;&lt;code&gt;ready()&lt;/code&gt;&amp;nbsp;off of the results of a selector where the element is not&amp;nbsp;&lt;code&gt;document&lt;/code&gt;. In&amp;nbsp;&lt;b&gt;Opal-jQuery&lt;/b&gt;&amp;nbsp;you can only set &quot;Document ready&quot; actions with&amp;nbsp;&lt;code&gt;Document.ready&lt;/code&gt;&amp;nbsp;. I feel this expresses the intent clearly and makes for less of a violation of the Principle of Least Surprise, but not even having the option to construct semantically odd lines. The following below will&amp;nbsp;&lt;b&gt;not&lt;/b&gt;&amp;nbsp;work because there is no&amp;nbsp;&lt;code&gt;Element#ready?()&lt;/code&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #2f8b58; font-weight: bold;&quot;&gt;Element&lt;/span&gt;.find(&lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;a&#39;&lt;/span&gt;).ready? { action }     &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;equivalent to $(&#39;a&#39;).ready(function(){action});&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-sec-3&quot;&gt;
&lt;h2 id=&quot;sec-3&quot;&gt;
Blocks&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-3&quot;&gt;
As is typical with Ruby, in&amp;nbsp;&lt;b&gt;Opal-jquery&lt;/b&gt;&amp;nbsp;we make use of blocks where anonymous functions are typically used in&amp;nbsp;&lt;b&gt;jQuery&lt;/b&gt;, or JavaScript in general. The examples read well.&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;element = &lt;span style=&quot;color: #2f8b58; font-weight: bold;&quot;&gt;Element&lt;/span&gt;.find &lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;#my_element&#39;&lt;/span&gt;
element.on(&lt;span style=&quot;color: #f5666d;&quot;&gt;:click&lt;/span&gt;) { alert(&lt;span style=&quot;color: #4e9a06;&quot;&gt;&quot;I&#39;ve been clicked&quot;&lt;/span&gt;) }                          &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;no event&lt;/span&gt;
element.on(&lt;span style=&quot;color: #f5666d;&quot;&gt;:click&lt;/span&gt;) { |event| alert(&lt;span style=&quot;color: #4e9a06;&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color: #0084c8; font-weight: bold;&quot;&gt;#{evt.current_target}&lt;/span&gt;&lt;span style=&quot;color: #4e9a06;&quot;&gt; been clicked&quot;&lt;/span&gt;) } &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;event&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
Note that you can pass lambdas, methods, etc. in place of a block, similar to how one would use a named function or function stored in a variable in JavaScript.&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;element = &lt;span style=&quot;color: #2f8b58; font-weight: bold;&quot;&gt;Element&lt;/span&gt;.find &lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;#my_element&#39;&lt;/span&gt;
my_lambda = &lt;span style=&quot;color: #a020f0; font-weight: bold;&quot;&gt;lambda&lt;/span&gt; { alert &lt;span style=&quot;color: #4e9a06;&quot;&gt;&quot;separate lambda&quot;&lt;/span&gt; }
element.on(&lt;span style=&quot;color: #f5666d;&quot;&gt;:click&lt;/span&gt;) &amp;amp;my_lambda

&lt;span style=&quot;color: brown; font-weight: bold;&quot;&gt;def&lt;/span&gt; &lt;span style=&quot;color: #00578e; font-weight: bold;&quot;&gt;some_method&lt;/span&gt;
  alert &lt;span style=&quot;color: #f5666d;&quot;&gt;:some_method&lt;/span&gt;
&lt;span style=&quot;color: brown; font-weight: bold;&quot;&gt;end&lt;/span&gt;
element.on(&lt;span style=&quot;color: #f5666d;&quot;&gt;:click&lt;/span&gt;) &amp;amp;some_method

instance_method = obj.method(&lt;span style=&quot;color: #f5666d;&quot;&gt;:an_instance_method&lt;/span&gt;)
element.on(&lt;span style=&quot;color: #f5666d;&quot;&gt;:click&lt;/span&gt;) &amp;amp;instance_method
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-sec-4&quot;&gt;
&lt;h2 id=&quot;sec-4&quot;&gt;
Consistency with Native&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-4&quot;&gt;
In&amp;nbsp;&lt;a href=&quot;http://funkworks.blogspot.com/2015/06/accessing-javascript-from-opal.html&quot; target=&quot;&amp;quot;_blank&amp;quot;&quot;&gt;accessing JavaScript from Opal&lt;/a&gt;, I showed how attributes of&amp;nbsp;&lt;code&gt;Native&lt;/code&gt;&amp;nbsp;are accessed by the&amp;nbsp;&lt;code&gt;[]&lt;/code&gt;&amp;nbsp;and&amp;nbsp;&lt;code&gt;[]=&lt;/code&gt;&amp;nbsp;methods.&amp;nbsp;&amp;nbsp;&lt;code&gt;Element&lt;/code&gt;&amp;nbsp;instances adhere to this convention. - Consistency is good and helps support the&amp;nbsp;&lt;b&gt;Principle of Least Surprise&lt;/b&gt;.&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;native = Native(&lt;span style=&quot;color: #4e9a06;&quot;&gt;`returnsJsObject`&lt;/span&gt;)
value = native[&lt;span style=&quot;color: #f5666d;&quot;&gt;:attr_name&lt;/span&gt;]
native[&lt;span style=&quot;color: #f5666d;&quot;&gt;:attr_name&lt;/span&gt;] = new_value

elt = &lt;span style=&quot;color: #2f8b58; font-weight: bold;&quot;&gt;Element&lt;/span&gt;.find(&lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;#anId&#39;&lt;/span&gt;)
value = elt[&lt;span style=&quot;color: #f5666d;&quot;&gt;:attr_name&lt;/span&gt;]
elt[&lt;span style=&quot;color: #f5666d;&quot;&gt;:attr_name&lt;/span&gt;] = new_value
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-sec-5&quot;&gt;
&lt;h2 id=&quot;sec-5&quot;&gt;
Conclusion&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-5&quot;&gt;
For the Rubyist reader, there are advantages in wrapping&amp;nbsp;&lt;b&gt;jQuery&lt;/b&gt;&amp;nbsp;in&amp;nbsp;&lt;b&gt;Opal-JQuery&lt;/b&gt;: the code reads well, expresses intent clearly, and uses conventions and idioms that a Rubyist should already be familiar with. Hopefully this brief overview gives you ideas on how one could wrap other JavaScript libraries w/idiomatic Ruby for similar benefits. In future articles we will look at more examples of Ruby-fication of jQuery&#39;s API, as well as show you some techniques used to wrap jQuery so that you might be able to apply them to wrapping other JavaScript libraries.&lt;br /&gt;
Thanks to&amp;nbsp;&lt;a href=&quot;http://blog.scottnelsonsmith.com/&quot;&gt;Scott Smith&lt;/a&gt;&amp;nbsp;for proofreading this and a number of the previous Opal blog posts.&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/6493064182198343801/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/6493064182198343801' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/6493064182198343801'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/6493064182198343801'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2015/06/ruby-fying-javascript-wrapping-opal.html' title='Ruby-fying JavaScript - Wrapping opal-jquery'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-8781442533987640363</id><published>2015-06-09T18:24:00.001-07:00</published><updated>2016-01-25T12:07:25.605-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="opal"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><title type='text'>Accessing Javascript from Opal</title><content type='html'>&lt;div class=&quot;status&quot; id=&quot;postamble&quot; style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;div id=&quot;content&quot; style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: Times; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;&quot;&gt;
So if you&#39;ve decided to take the plunge and try Opal, the 1st question you might have is, &quot;Do I lose access to all the JavaScript libraries out there?&quot; The answer is no. Ideally you&#39;ll want Ruby wrappers that &quot;ruby-fy&quot; the JavaScript in question. It&#39;ll make you happier but that&#39;s not always available. A great example of a Ruby-fied wrapper is&amp;nbsp;&lt;a _blank=&quot;&quot; href=&quot;https://github.com/opal/opal-jquery&quot; target=&quot;&quot;&gt;opal-jquery&lt;/a&gt;; this shows how the jQuery interface can be made more Ruby like.&lt;br /&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-sec-1&quot;&gt;
&lt;h2 id=&quot;sec-1&quot;&gt;
Calling JavaScript Directly&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-1&quot;&gt;
To invoke JavaScript and store the return value in Opal, use x-strings, either via the backtick operator or the %x syntax. Some documentation here:&amp;nbsp;&lt;a _blank=&quot;&quot; href=&quot;http://opalrb.org/docs/compiled_ruby/#javascript-from-ruby&quot; target=&quot;&quot;&gt;http://opalrb.org/docs/compiled_ruby/#javascript-from-ruby&lt;/a&gt;&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;backticks, good for 1 line&lt;/span&gt;
location = &lt;span style=&quot;color: #4e9a06;&quot;&gt;`window.location`&lt;/span&gt;

&lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;%x for multi line, I often use | as delimeter, esp. for JavaScript&lt;/span&gt;
&lt;span style=&quot;color: #4e9a06;&quot;&gt;%x|&lt;/span&gt;
&lt;span style=&quot;color: #4e9a06;&quot;&gt;  var f = new Foo();&lt;/span&gt;
&lt;span style=&quot;color: #4e9a06;&quot;&gt;  f.bar&lt;/span&gt;
&lt;span style=&quot;color: #4e9a06;&quot;&gt;|&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-sec-2&quot;&gt;
&lt;h2 id=&quot;sec-2&quot;&gt;
Interpolation&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-2&quot;&gt;
&lt;b&gt;Opal&lt;/b&gt;&amp;nbsp;uses&amp;nbsp;&lt;b&gt;x-strings&lt;/b&gt;&amp;nbsp;to support&amp;nbsp;&lt;i&gt;interpolation&lt;/i&gt;&amp;nbsp;just as&amp;nbsp;&lt;b&gt;Ruby&lt;/b&gt;&amp;nbsp;does:&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;it should be noted that prompt is already exposed in opal-browser&lt;/span&gt;
&lt;span style=&quot;color: #4e9a06;&quot;&gt;`prompt(&#39;what have you done since  &#39; + &lt;/span&gt;&lt;span style=&quot;color: #0084c8; font-weight: bold;&quot;&gt;#{RUBY_RELEASE_DATE}&lt;/span&gt;&lt;span style=&quot;color: #4e9a06;&quot;&gt;)`&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-sec-3&quot;&gt;
&lt;h2 id=&quot;sec-3&quot;&gt;
Simple return values&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-3&quot;&gt;
So you can now invoke any JavaScript you want, but what about the return values? X-strings return the native types, some of which you can use and manipulate directly in Opal.&lt;br /&gt;
In Opal, 3 &quot;Ruby&quot; types get compiled to the native Javascript types but are still treated as Ruby objects by Opal. These types are&lt;br /&gt;
&lt;ul class=&quot;org-ul&quot;&gt;
&lt;li&gt;Strings (with the exception that these are treated as immutable)&lt;/li&gt;
&lt;li&gt;Numeric&lt;/li&gt;
&lt;li&gt;Array&lt;/li&gt;
&lt;/ul&gt;
See&amp;nbsp;&lt;a _blank=&quot;&quot; href=&quot;http://opalrb.org/docs/compiled_ruby/&quot; target=&quot;&quot;&gt;http://opalrb.org/docs/compiled_ruby/&lt;/a&gt;&amp;nbsp;for more details on what Opal compiles to.&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;&lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;numbers&lt;/span&gt;
n = &lt;span style=&quot;color: #4e9a06;&quot;&gt;`2 + 2`&lt;/span&gt;
triple product = n * 3 &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;=&amp;gt; 12&lt;/span&gt;

&lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;strings&lt;/span&gt;
str = &lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;abcdef&#39;&lt;/span&gt;
str[3..-1]             &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;=&amp;gt; &#39;def&#39;&lt;/span&gt;

&lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;array&lt;/span&gt;
array = &lt;span style=&quot;color: #4e9a06;&quot;&gt;`[1, 2, 3]`&lt;/span&gt;
array.size             &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;=&amp;gt; 3&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
In addition,&amp;nbsp;&lt;code&gt;true&lt;/code&gt;,&amp;nbsp;&lt;code&gt;false&lt;/code&gt;, and&amp;nbsp;&lt;code&gt;null&lt;/code&gt;&amp;nbsp;map to&amp;nbsp;&lt;code&gt;true&lt;/code&gt;,&amp;nbsp;&lt;code&gt;false&lt;/code&gt;, and&amp;nbsp;&lt;code&gt;nil&lt;/code&gt;&amp;nbsp;respectively. JavaScript that evaluates these values can be used directly in Opal.&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-sec-4&quot;&gt;
&lt;h2 id=&quot;sec-4&quot;&gt;
Manipulating JavaScript objects&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-4&quot;&gt;
Manipulating native JavaScript objects is a little more cumbersome. Because of how Opal is compiled&amp;nbsp;&lt;sup&gt;&lt;a class=&quot;footref&quot; href=&quot;#fn.1&quot; id=&quot;fnr.1&quot; name=&quot;fnr.1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, you cannot access methods and properties directly. (This, however, changes in a future version of opal&amp;nbsp;&lt;sup&gt;&lt;a class=&quot;footref&quot; href=&quot;#fn.2&quot; id=&quot;fnr.2&quot; name=&quot;fnr.2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;). You&amp;nbsp;&lt;i&gt;can&lt;/i&gt;&amp;nbsp;do further manipulation via x-strings if needed.&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;w = &lt;span style=&quot;color: #4e9a06;&quot;&gt;`window`&lt;/span&gt;
location = &lt;span style=&quot;color: #4e9a06;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #0084c8; font-weight: bold;&quot;&gt;#{w}&lt;/span&gt;&lt;span style=&quot;color: #4e9a06;&quot;&gt;.location`&lt;/span&gt;
href = &lt;span style=&quot;color: #4e9a06;&quot;&gt;`&lt;/span&gt;&lt;span style=&quot;color: #0084c8; font-weight: bold;&quot;&gt;#{location}&lt;/span&gt;&lt;span style=&quot;color: #4e9a06;&quot;&gt;.href`&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-sec-5&quot;&gt;
&lt;h2 id=&quot;sec-5&quot;&gt;
Native - Making life easier&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-5&quot;&gt;
That&#39;s pretty cumbersome. Pretty un-Ruby-like if you ask me. In the Ruby way of making the developer happy, you can use&amp;nbsp;&lt;code&gt;Kernel#Native()&lt;/code&gt;&amp;nbsp;to wrap a native object for more convenient access in Opal.&lt;br /&gt;
Ruby implements the&amp;nbsp;&lt;a _blank=&quot;&quot; href=&quot;http://en.wikipedia.org/wiki/Uniform_access_principle&quot; target=&quot;&quot;&gt;&lt;b&gt;Uniform Access Principle&lt;/b&gt;&lt;/a&gt;. As such, you can&#39;t access the equivalent of properties on Ruby objects; rather all access is via methods even if they look like properties (due to parentheses being optional in Ruby). In JavaScript, the difference between properties and functions/methods is significant. So how would you do the different accesses in Opal if everything is a method?&lt;br /&gt;
In a nutshell, what&amp;nbsp;&lt;code&gt;Native()&lt;/code&gt;&amp;nbsp;does is create a Ruby/Opal object with a&amp;nbsp;&lt;code&gt;@native&lt;/code&gt;&amp;nbsp;instance variable wrapping the native object. It uses&amp;nbsp;&lt;code&gt;method_missing()&lt;/code&gt;&amp;nbsp;to call native methods on&amp;nbsp;&lt;code&gt;@native&lt;/code&gt;, and&amp;nbsp;&lt;code&gt;[]&lt;/code&gt;&amp;nbsp;and&amp;nbsp;&lt;code&gt;[]=&lt;/code&gt;&amp;nbsp;for reading/setting properties&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;obj = Native(&lt;span style=&quot;color: #4e9a06;&quot;&gt;`returnSomeObj()`&lt;/span&gt;) &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;need x-strings to get a JS object into opal&lt;/span&gt;
obj[&lt;span style=&quot;color: #f5666d;&quot;&gt;:property&lt;/span&gt;]                  &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;property reader&lt;/span&gt;
obj[&lt;span style=&quot;color: #f5666d;&quot;&gt;:property&lt;/span&gt;] = &lt;span style=&quot;color: #4e9a06;&quot;&gt;&#39;new value&#39;&lt;/span&gt;    &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;property writer&lt;/span&gt;
obj.method                      &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;method call without parameters&lt;/span&gt;
obj.method2(1, 2)               &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;method call with parameters&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
To get a feel of accessing a property vs a method/function on a native object, play around w/this&amp;nbsp;&amp;nbsp;&lt;a _blank=&quot;&quot; href=&quot;http://fkchang.github.io/opal-irb/index-embeddable.html#code:w%20=%20Native(`window`)%0Aw.prompt%20%20%20#%20calls%20method,%20pops%20up%20empty%20prompt%0Aw[:prompt]%20#%20give%20you%20back%20the%20function%20that%20is%20in%20the%20property&quot; target=&quot;&quot;&gt;opal-irb example&lt;/a&gt;&amp;nbsp;a bit&lt;br /&gt;
Let&#39;s revisit of href example using&amp;nbsp;&lt;code&gt;Native()&lt;/code&gt;:&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;w = Native(&lt;span style=&quot;color: #4e9a06;&quot;&gt;`window`&lt;/span&gt;)
location = w.location
href = location.href
&lt;/pre&gt;
&lt;/div&gt;
Much nicer, don&#39;t you agree?&lt;br /&gt;
It&#39;s worth noting that&amp;nbsp;&lt;code&gt;Native()&lt;/code&gt;&amp;nbsp;works where methods will resolve themselves as properties if that&#39;s what they are.&lt;br /&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;w = Native(&lt;span style=&quot;color: #4e9a06;&quot;&gt;`window`&lt;/span&gt;) &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;=&amp;gt; #&lt;native: object=&quot;&quot; window=&quot;&quot;&gt;&lt;/native:&gt;&lt;/span&gt;
w[&lt;span style=&quot;color: #f5666d;&quot;&gt;:location&lt;/span&gt;]         &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;property =&amp;gt; #&lt;native:http: fkchang.github.io=&quot;&quot; index-embeddable.html=&quot;&quot; opal-irb=&quot;&quot;&gt;&lt;/native:http:&gt;&lt;/span&gt;
w.location           &lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;=&amp;gt; #&lt;native:http: fkchang.github.io=&quot;&quot; index-embeddable.html=&quot;&quot; opal-irb=&quot;&quot;&gt;&lt;/native:http:&gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;outline-2&quot; id=&quot;outline-container-sec-6&quot;&gt;
&lt;h2 id=&quot;sec-6&quot;&gt;
Conclusion&lt;/h2&gt;
&lt;div class=&quot;outline-text-2&quot; id=&quot;text-6&quot;&gt;
Writing wrapper classes is useful in making the interfaces to your Javascript code more Ruby-like. Even without wrapper classes, you will find x-strings and&amp;nbsp;&lt;code&gt;Native()&lt;/code&gt;&amp;nbsp;options useful. These Opal features can bring a lot of joy and productivity to the client-side Ruby developer. I&#39;ll cover wrapping Javascript in Opal classes in a future issue.&lt;br /&gt;
Enjoy!&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;footnotes&quot;&gt;
&lt;h2 class=&quot;footnotes&quot;&gt;
Footnotes:&amp;nbsp;&lt;/h2&gt;
&lt;div id=&quot;text-footnotes&quot;&gt;
&lt;div class=&quot;footdef&quot; style=&quot;margin-bottom: 1em;&quot;&gt;
&lt;sup&gt;&lt;a class=&quot;footnum&quot; href=&quot;#fnr.1&quot; id=&quot;fn.1&quot; name=&quot;fn.1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;br /&gt;
&lt;div class=&quot;footpara&quot; style=&quot;display: inline;&quot;&gt;
As indicated by&amp;nbsp;&lt;a _blank=&quot;&quot; href=&quot;http://opalrb.org/docs/compiled_ruby/#ruby-from-javascript&quot; target=&quot;&quot;&gt;http://opalrb.org/docs/compiled_ruby/#ruby-from-javascript&lt;/a&gt;, compiled Opal method names get a&amp;nbsp;&lt;code&gt;$&lt;/code&gt;&amp;nbsp;prepended to them to avoid conflict with JavaScript methods. As such running a method on a native object would compile to that method name prepended with a &quot;$&quot;, which would not exist on the object.&lt;/div&gt;
&lt;div class=&quot;footpara&quot; style=&quot;display: block;&quot;&gt;
This&amp;nbsp;&lt;a _blank=&quot;&quot; href=&quot;http://opalrb.org/try/?code:w%20=%20`window`%0Aw.location&quot; target=&quot;&quot;&gt;example&lt;/a&gt;&amp;nbsp;ought to make it a bit clearer&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;footdef&quot; style=&quot;margin-bottom: 1em;&quot;&gt;
&lt;sup&gt;&lt;a class=&quot;footnum&quot; href=&quot;#fnr.2&quot; id=&quot;fn.2&quot; name=&quot;fn.2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;br /&gt;
&lt;div class=&quot;footpara&quot; style=&quot;display: inline;&quot;&gt;
This recently merged&amp;nbsp;&lt;a _blank=&quot;&quot; href=&quot;https://github.com/opal/opal/pull/879&quot; target=&quot;&quot;&gt;PR&lt;/a&gt;&amp;nbsp;from&amp;nbsp;&lt;a href=&quot;https://github.com/jeremyevans&quot;&gt;Jeremy Evans&lt;/a&gt;&amp;nbsp;into master supports a much handier way to access JavaScript functions and properties than using x-stings. With a native object, you can use object.JS to get at the JavaScript. This functionality will most likely NOT go into 0.8, but some future version, possibly 0.9. Examples:&lt;/div&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;o = &lt;span style=&quot;color: #4e9a06;&quot;&gt;`returnAnObject()`&lt;/span&gt;
&lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;access properties like this&lt;/span&gt;
o.&lt;span style=&quot;color: #2f8b58; font-weight: bold;&quot;&gt;JS&lt;/span&gt;[&lt;span style=&quot;color: #f5666d;&quot;&gt;:property&lt;/span&gt;]
&lt;span style=&quot;color: #5f7f5f;&quot;&gt;# &lt;/span&gt;&lt;span style=&quot;color: #204a87;&quot;&gt;access functions like this&lt;/span&gt;
o.&lt;span style=&quot;color: #2f8b58; font-weight: bold;&quot;&gt;JS&lt;/span&gt;.javascriptMethod(1, 2)
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;footpara&quot; style=&quot;display: block;&quot;&gt;
Let&#39;s look at the href example I&#39;ve been using with this new syntax&lt;/div&gt;
&lt;div class=&quot;org-src-container&quot;&gt;
&lt;pre class=&quot;src src-ruby&quot; style=&quot;border: 1px solid rgb(204, 204, 204); box-shadow: rgb(238, 238, 238) 3px 3px 3px; font-family: monospace; margin: 1.2em; overflow: visible; padding: 1.2em 8pt 8pt; position: relative;&quot;&gt;w = &lt;span style=&quot;color: #4e9a06;&quot;&gt;`window`&lt;/span&gt;
location = w.&lt;span style=&quot;color: #2f8b58; font-weight: bold;&quot;&gt;JS&lt;/span&gt;[&lt;span style=&quot;color: #f5666d;&quot;&gt;:location&lt;/span&gt;]
href = location.&lt;span style=&quot;color: #2f8b58; font-weight: bold;&quot;&gt;JS&lt;/span&gt;[&lt;span style=&quot;color: #f5666d;&quot;&gt;:href&lt;/span&gt;]
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/8781442533987640363/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/8781442533987640363' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/8781442533987640363'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/8781442533987640363'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2015/06/accessing-javascript-from-opal.html' title='Accessing Javascript from Opal'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-16908486.post-1824412976665051036</id><published>2015-05-29T10:08:00.002-07:00</published><updated>2015-05-29T10:08:34.350-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="javascript"/><category scheme="http://www.blogger.com/atom/ns#" term="opal"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby"/><category scheme="http://www.blogger.com/atom/ns#" term="ruby-fying javascript"/><title type='text'>Ruby-fying Javascript - Avoiding jQuery Spaghetti slides</title><content type='html'>Hi All:&lt;br /&gt;
&lt;br /&gt;
I did a talk at &lt;a href=&quot;http://www.meetup.com/ocruby/&quot; target=&quot;_blank&quot;&gt;OCRuby&lt;/a&gt; last night. &amp;nbsp;It went pretty well. &amp;nbsp;Here are the It was based on my&amp;nbsp;&lt;a href=&quot;http://funkworks.blogspot.com/2015/04/ruby-fying-javascript-avoiding-jquery.html&quot; target=&quot;_blank&quot;&gt;blog post&lt;/a&gt;&amp;nbsp;on the subject, so hopefully the 2 will reinforce each other I do think the missing ingredient could be been the in person explanations. &amp;nbsp;If there&#39;s interested, I could probably try to record it. &amp;nbsp;Let me know.&lt;br /&gt;
&lt;br /&gt;
Resources:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;OCRuby&amp;nbsp;&lt;a href=&quot;http://www.slideshare.net/fkchang/rubyfying-javascript-avoiding-j-query-spaghetti&quot; target=&quot;_blank&quot;&gt;slides&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;nbsp;The original&amp;nbsp;&lt;a href=&quot;http://funkworks.blogspot.com/2015/04/ruby-fying-javascript-avoiding-jquery.html&quot; target=&quot;_blank&quot;&gt;blog post&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://funkworks.blogspot.com/2014/01/opal-new-hope-for-ruby-programmers.html&quot; target=&quot;_blank&quot;&gt;Opal talk at RubyConf 2013 and slides&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://funkworks.blogspot.com/feeds/1824412976665051036/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/16908486/1824412976665051036' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/1824412976665051036'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/16908486/posts/default/1824412976665051036'/><link rel='alternate' type='text/html' href='http://funkworks.blogspot.com/2015/05/ruby-fying-javascript-avoiding-jquery.html' title='Ruby-fying Javascript - Avoiding jQuery Spaghetti slides'/><author><name>Forrest Chang</name><uri>http://www.blogger.com/profile/04290038091668118139</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry></feed>