<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>7fff &#187; Ruby</title>
	<atom:link href="http://7fff.com/category/ruby/feed/" rel="self" type="application/rss+xml" />
	<link>http://7fff.com</link>
	<description></description>
	<lastBuildDate>Fri, 30 Dec 2011 21:03:10 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Correlate time zone abbreviations with time zone names</title>
		<link>http://7fff.com/2011/11/07/correlate-time-zone-abbreviations-with-time-zone-names/</link>
		<comments>http://7fff.com/2011/11/07/correlate-time-zone-abbreviations-with-time-zone-names/#comments</comments>
		<pubDate>Mon, 07 Nov 2011 20:09:28 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://7fff.com/?p=672</guid>
		<description><![CDATA[There has got to be any easier way.


require 'rubygems'
require 'tzinfo'
require 'active_support'
require 'active_support/values/time_zone'

time_zone_names = [ 'Eastern Time (US &#38; Canada)', 'Central Time (US &#38; Canada)', 'Paris' ]
abbrev_to_zone = time_zone_names.inject({}) do &#124;map, name&#124;
  map[ActiveSupport::TimeZone.find_tzinfo(name).current_period.abbreviation.to_s] = name; map
end

p Time.now.zone
p abbrev_to_zone[Time.now.zone]
p abbrev_to_zone['CET']

]]></description>
			<content:encoded><![CDATA[<p></p><p>There has got to be any easier way.</p>
<pre name="code" class="ruby">

require 'rubygems'
require 'tzinfo'
require 'active_support'
require 'active_support/values/time_zone'

time_zone_names = [ 'Eastern Time (US &amp; Canada)', 'Central Time (US &amp; Canada)', 'Paris' ]
abbrev_to_zone = time_zone_names.inject({}) do |map, name|
  map[ActiveSupport::TimeZone.find_tzinfo(name).current_period.abbreviation.to_s] = name; map
end

p Time.now.zone
p abbrev_to_zone[Time.now.zone]
p abbrev_to_zone['CET']
</pre>
]]></content:encoded>
			<wfw:commentRss>http://7fff.com/2011/11/07/correlate-time-zone-abbreviations-with-time-zone-names/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rails 3.0 to 3.1 gotcha: Changed ActiveSupport::JSON.backend</title>
		<link>http://7fff.com/2011/10/06/rails-3-0-to-3-1-gotcha-changed-activesupportjson-backend/</link>
		<comments>http://7fff.com/2011/10/06/rails-3-0-to-3-1-gotcha-changed-activesupportjson-backend/#comments</comments>
		<pubDate>Thu, 06 Oct 2011 18:10:02 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://7fff.com/?p=669</guid>
		<description><![CDATA[Ow.
In Rails 3.0, the default ActiveSupport::JSON backend is YAML.
In Rails 3.1, it&#8217;s YAJL.
They deserialize JSON times differently. In 3.0 . . .


ruby-1.9.2-p290 :001 &#62; ActiveSupport::JSON.decode( '{&#34;at&#34;: &#34;2011-10-13T12:00:00+00:00&#34;}' )
 =&#62; {&#34;at&#34;=&#62;2011-10-13 07:00:00 -0500} 

See the lack of quotation marks around what &#8220;at&#8221; points to? It&#8217;s not a String. YAML converts the value to an actual DateTime. [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>Ow.</p>
<p>In Rails 3.0, the default ActiveSupport::JSON backend is YAML.</p>
<p>In Rails 3.1, it&#8217;s YAJL.</p>
<p>They deserialize JSON times differently. In 3.0 . . .</p>
<pre name="code" class="ruby">

ruby-1.9.2-p290 :001 &gt; ActiveSupport::JSON.decode( '{&quot;at&quot;: &quot;2011-10-13T12:00:00+00:00&quot;}' )
 =&gt; {&quot;at&quot;=&gt;2011-10-13 07:00:00 -0500} 
</pre>
<p>See the lack of quotation marks around what &#8220;at&#8221; points to? It&#8217;s not a String. YAML converts the value to an actual DateTime. (There a DATE_REGEX defined in ActiveSupport::JSON that does the matching.</p>
<p>But in 3.1:</p>
<pre name="code" class="ruby">

ruby-1.9.2-p290 :001 &gt; ActiveSupport::JSON.decode( '{&quot;at&quot;: &quot;2011-10-13T12:00:00+00:00&quot;}' )
 =&gt; {&quot;at&quot;=&gt;&quot;2011-10-13T12:00:00+00:00&quot;} 
</pre>
<p>We had the yajl-ruby gem installed for development, so were getting the the Strings. Then on our staging server, we were getting the already-parsed time value, and were getting errors.</p>
<p>This strikes me as a substantive change. I&#8217;m not sure I&#8217;d call it a bug, but it was unexpected.</p>
]]></content:encoded>
			<wfw:commentRss>http://7fff.com/2011/10/06/rails-3-0-to-3-1-gotcha-changed-activesupportjson-backend/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>RSpec and let</title>
		<link>http://7fff.com/2011/10/02/rspec-and-let/</link>
		<comments>http://7fff.com/2011/10/02/rspec-and-let/#comments</comments>
		<pubDate>Sun, 02 Oct 2011 21:43:48 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://7fff.com/?p=647</guid>
		<description><![CDATA[So here&#8217;s a good one. We had a spec that looked something like this:


require 'time'

class SomeModel
  def self.all
    @all &#124;&#124;= []
  end
  def self.create!(time)
   all &#60;&#60; new
  end
end

describe &#34;surprise&#34; do
  subject { SomeModel }
  let!(:now) { Time.now }
  ['9 AM', '10 AM', '11 [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>So here&#8217;s a good one. We had a spec that looked something like this:</p>
<pre name="code" class="ruby">

require 'time'

class SomeModel
  def self.all
    @all ||= []
  end
  def self.create!(time)
   all &lt;&lt; new
  end
end

describe &quot;surprise&quot; do
  subject { SomeModel }
  let!(:now) { Time.now }
  ['9 AM', '10 AM', '11 AM'].each do |hour|
    let!(:time) { Time.mktime(now.year, now.month, now.day, Time.parse(hour).hour) }
    let!(:some_model) { SomeModel.create!(time) }
  end
  its(:all) { should have(3).items }
end
</pre>
<p>(In the original code, rather than check that the <code>.all</code> method returned a enumeration with 3 items, we were describing the behavior of a different object to see if it could do something when three collaborating objects had already been created via factories.)</p>
<p>The spec told us this:</p>
<pre name="code" class="ruby">

     Failure/Error: its(:all) { should have(3).items }
       expected 3 items, got 1
</pre>
<p>That&#8217;s funny. How come we don&#8217;t have three items? Let&#8217;s try a bit of puts debugging. We&#8217;ll dump the value of hour just inside the block passed to <code>#each</code>. And we get:</p>
<pre name="code" class="ruby">

hour: 9 AM
hour: 10 AM
hour: 11 AM
</pre>
<p>Well that&#8217;s expected. Gee, maybe our collaborator is buggy (and maybe we should be mocking it anyway, but let that pass). Let&#8217;s show the hour inside of what the let defines:</p>
<pre name="code" class="ruby">

  ['9 AM', '10 AM', '11 AM'].each do |hour|
    puts &quot;hour: #{hour}&quot;
    let!(:time) { puts &quot;hour inside time: #{hour}&quot;; Time.mktime(now.year, now.month, now.day, Time.parse(hour).hour) }
    let!(:some_model) { SomeModel.create!(time) }
  end
</pre>
<p>What do we get?</p>
<pre name="code" class="ruby">

hour: 9 AM
hour: 10 AM
hour: 11 AM
hour inside time: 11 AM
F
</pre>
<p>Interesting.</p>
<p>The problem is that we hadn&#8217;t internalized properly the documentation for the RSpec <code>let</code> (and <code>let!</code>) helper. The documentation says: &#8220;Use <code>let</code> to define a memoized helper method. The value will be cached across multiple calls in the same example but not across examples. Note that <code>let</code> is lazy-evaluated: it is not evaluated until the first time the method it defines is invoked. You can use <code>let!</code> to force the method&#8217;s invocation before each example&#8221; (<a href="https://www.relishapp.com/rspec/rspec-core/docs/helper-methods/let-and-let">https://www.relishapp.com/rspec/rspec-core/docs/helper-methods/let-and-let</a>).</p>
<p>The key phrase is &#8220;define a . . . method.&#8221; So what our code is doing above is simply redefining the <code>#time</code> and <code>#some_model</code> methods over and over. Then, since the execution is deferred, we would get the <code>#time</code> method returning &#8216;11 AM&#8217; and the <code>#some_model</code> method instantiating only one <code>SomeModel</code>.</p>
<p>Before we touch on one way to fix this, let&#8217;s look at some of the implications of what let does. For one thing, let&#8217;s remember that the method will only be executed once (since it&#8217;s memoized). For example:</p>
<pre name="code" class="ruby">

describe &quot;no surprise&quot; do
  let(:x) { puts &quot;x defined to return 'a'&quot;; &quot;a&quot; }
  let(:x) { puts &quot;x defined to return 'b'&quot;; &quot;b&quot; }
  it &quot;should have the expected setup value&quot; do
    x.should == &quot;b&quot;
    x.should == &quot;b&quot;
  end
end
</pre>
<p>When this spec is run, we are going to see &#8220;x defined to return &#8216;b&#8217;&#8221; once. We don&#8217;t see &#8220;x defined to return &#8216;a&#8217;&#8221; because the execution is deferred, and the second <code>let(:x)</code> wipes out the first. Since the result is memoized, we only see &#8220;x defined to return &#8216;b&#8217;&#8221; get printed out once:</p>
<pre name="code" class="ruby">

$ rspec spec/example2_spec.rb
x defined to return 'b'
.

Finished in 0.00034 seconds
1 example, 0 failures
</pre>
<p>Additionally, since <code>let</code> defines methods, and since execution of the methods is deferred until after they have all been defined, you can have earlier methods depend on later methods:</p>
<pre name="code" class="ruby">

describe &quot;no surprise&quot; do
  let(:x) { y + 1 }
  let(:y) { 1 }
  it &quot;should not matter in what order these methods are defined&quot; do
    x.should == 2
  end
end
</pre>
<p>So why the confusion? I think there are a couple of reasons. The main thing is that word &#8220;let.&#8221; It sounds as though we are assigning a value to a key. It is not uncommon to see sequences of lets like so:</p>
<pre name="code" class="ruby">

let!(:last) { Factory(:user, last_name: 'zzz', first_name: 'aaa') }
let!(:center) { Factory(:user, last_name: 'aaa', first_name: 'abc') }
let!(:first) { Factory(:user, last_name: 'aaa', first_name: 'aabc') }
</pre>
<p>So let looks something like an assignment. Why is it called let? I don&#8217;t know. Maybe it&#8217;s supposed to feel a bit like Common Lisp where let is a stand-in for lambda. Maybe the thought was that if &#8220;assigns&#8221; or &#8220;set&#8221; was used, it would be ambiguous given how these terms are used elsewhere in Ruby and Rails.</p>
<p>If you ask me, a name such as &#8220;dm&#8221; (for define_method) would have been more appropriate. Then noobs (like me &#8212; I&#8217;ve always used <code>Test::Unit</code>) would wonder what it stands for, look it up in the documentation, and get some insight. &#8220;let&#8221; is just too abstract.</p>
<p>The original problem? If we must use <code>let</code>, perhaps define an <code>Array</code> with the <code>let</code>:</p>
<pre name="code" class="ruby">

describe &quot;surprise&quot; do
  subject { SomeModel }
  let!(:now) { Time.now }
  let!(:some_models) do
    ['9 AM', '10 AM', '11 AM'].map do |hour|
      SomeModel.create!(Time.mktime(now.year, now.month, now.day, Time.parse(hour).hour))
    end
  end
  its(:all) { should have(3).items }
end
</pre>
<p>One last thing. Discussions in books are a bit misleading, or don&#8217;t tell the truth soon enough. For instance, in Noel Rappin&#8217;s book <em>Rails Test Prescriptions</em> (which is not only excellent but actually funny), he introduces let by saying: &#8220;Using let(), you can make a variable available within the current example group[.] . . . The symbol can then be called as if it was a local variable&#8221; (p. 193). Well, this is true, but by saying that &#8220;you can make a variable available,&#8221; it sounds like variable assignment &#8212; which it just isn&#8217;t. Among other things, just saying that makes one thing that the order of the let&#8217;s is important in terms of the values that will eventually be assigned. Thankfully he says just a wee bit later, &#8220;a let() call is syntactic sugar for defining a method and memoizing the the result.&#8221; Yes. But this is one of those cases where easing into the truth can be harmful.</p>
<p>The <em>RSpec Book</em> (Chelimsky, et al.) does a similar thing, rhetorically: &#8220;When the code in a before block is only creating instance variables and assigning them values, which is most of the time, we can use RSpec&#8217;s let() method instead&#8221; (p. 55). Again, this is a bit slippery. It&#8217;s not like creating instance variables at all. It&#8217;s like calling a method. Which, of course, Chelimsky immediately explains.</p>
<p>The upshot:</p>
<ol>
<li>Don&#8217;t put your calls to <code>let</code> inside of loops! (If you must, have the calls to <code>let</code> define different symbols.)</li>
<li>Don&#8217;t assume that the methods will run in the order of the <code>let</code>s.</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://7fff.com/2011/10/02/rspec-and-let/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Best way to test Ruby class methods?</title>
		<link>http://7fff.com/2011/09/07/best-way-to-test-ruby-class-methods/</link>
		<comments>http://7fff.com/2011/09/07/best-way-to-test-ruby-class-methods/#comments</comments>
		<pubDate>Wed, 07 Sep 2011 14:59:50 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://7fff.com/?p=628</guid>
		<description><![CDATA[Let&#8217;s say that we have a Ruby object with some class methods. In my case, we want to be able to inject a driver at the class level that all instances will use:


class Mod::Thingy
  def self.driver
  end
  def self.driver=(d)
  end
end

And let&#8217;s say that .driver has a default value. So the class [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>Let&#8217;s say that we have a Ruby object with some class methods. In my case, we want to be able to inject a driver at the class level that all instances will use:</p>
<pre name="code" class="ruby">

class Mod::Thingy
  def self.driver
  end
  def self.driver=(d)
  end
end
</pre>
<p>And let&#8217;s say that .driver has a default value. So the class looks more like this:</p>
<pre name="code" class="ruby">

class Mod::Thingy
  def self.driver
    @driver || DefaultDriver
  end
  def self.driver=(d)
    @driver = d
  end
end
</pre>
<p>Now here&#8217;s the dealio. Let&#8217;s say that we test for the default value first. So we check <code>Mod::Thingy.driver == DefaultDriver</code>. Then we test the setter. We do <code>Mod::Thingy.driver = OtherDriver</code>, and then check the return value of <code>Mod::Thingy.driver</code>. Fair enough.</p>
<p>But what if we ran the examples in reverse? Now we do <code>Mod::Thingy.driver = OtherDriver</code> first, check it; but now in our second test, we can&#8217;t test the default value, because the state of <code>Mod::Thingy</code> has been changed.</p>
<p>Strategies:</p>
<ol>
<li>
We might use RSpec&#8217;s <code>around</code> feature to save the state of <code>Mod::Thingy.driver</code> and restore it afterwards. What I don&#8217;t like about this is that now the around method has to know all about all of the setters at the class level. Meanwhile, it is possible to imagine objects that are difficult to set back to their default state: Perhaps the class methods have order dependencies themselves. This would make the test need to know a lot about the inner state of the object.
</li>
<li>
We might provide a <code>.reset!</code> method on the object. But this seems a bit nutty: Add a method just to make testing easier?
</li>
<li>
What about this in an RSpec <code>before(:each)</code> block:</p>
<pre name="code" class="ruby">

    Mod.send(:remove_const, 'Thingy')
    load &quot;#{PROJECT_ROOT}/lib/mod/thingy.rb&quot;
</pre>
<p>Now we&#8217;re getting a nice clean class. To me, (3) is more parallel to the testing convention of new&#8217;ing up an object instance for the test.
</li>
</ol>
<p>Thoughts?</p>
]]></content:encoded>
			<wfw:commentRss>http://7fff.com/2011/09/07/best-way-to-test-ruby-class-methods/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Spying on Ruby&#8217;s Net::HTTP</title>
		<link>http://7fff.com/2011/08/04/spying-on-rubys-nethttp/</link>
		<comments>http://7fff.com/2011/08/04/spying-on-rubys-nethttp/#comments</comments>
		<pubDate>Thu, 04 Aug 2011 15:03:58 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://7fff.com/?p=623</guid>
		<description><![CDATA[I&#8217;ve heard two people complain that they can&#8217;t see OAuth HTTP behavior and get unexpected 401s. If you want to see what&#8217;s going on at the transport level, here&#8217;s a monkeypatch (depends on ActiveSupport for the alias_method_chain) just for you:


class Net::HTTP

  def initialize_with_debug(*args, &#38;block)
    initialize_without_debug(*args, &#38;block)
    set_debug_output $stderr
 [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>I&#8217;ve heard two people complain that they can&#8217;t see OAuth HTTP behavior and get unexpected 401s. If you want to see what&#8217;s going on at the transport level, here&#8217;s a monkeypatch (depends on ActiveSupport for the alias_method_chain) just for you:</p>
<pre name="code" class="ruby">

class Net::HTTP

  def initialize_with_debug(*args, &amp;block)
    initialize_without_debug(*args, &amp;block)
    set_debug_output $stderr
  end

  alias_method_chain :initialize, :debug
end
</pre>
]]></content:encoded>
			<wfw:commentRss>http://7fff.com/2011/08/04/spying-on-rubys-nethttp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ruby&#8217;s Hash#default=</title>
		<link>http://7fff.com/2011/07/21/rubys-hashdefault/</link>
		<comments>http://7fff.com/2011/07/21/rubys-hashdefault/#comments</comments>
		<pubDate>Thu, 21 Jul 2011 15:28:25 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://7fff.com/?p=621</guid>
		<description><![CDATA[If Ruby&#8217;s Hash#default= returned the Hash instead of the default object, you could write:


TRANSLATION = { 'hello' =&#62; 'bonjour' }.default=('unknown')

]]></description>
			<content:encoded><![CDATA[<p></p><p>If Ruby&#8217;s Hash#default= returned the Hash instead of the default object, you could write:</p>
<pre name="code" class="ruby">

TRANSLATION = { 'hello' =&gt; 'bonjour' }.default=('unknown')
</pre>
]]></content:encoded>
			<wfw:commentRss>http://7fff.com/2011/07/21/rubys-hashdefault/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Another reason to dislike the Ruby 1.9 Hash syntax</title>
		<link>http://7fff.com/2011/07/09/another-reason-to-dislike-the-ruby-1-9-hash-syntax/</link>
		<comments>http://7fff.com/2011/07/09/another-reason-to-dislike-the-ruby-1-9-hash-syntax/#comments</comments>
		<pubDate>Sat, 09 Jul 2011 16:07:31 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://7fff.com/?p=611</guid>
		<description><![CDATA[I&#8217;m not religious about the old or new Ruby Hash syntax, but it is interesting that if you inspect a Hash in 1.9, you get the old syntax:


ruby-1.9.2-p180 :001 &#62; { foo: 'bar' }
 =&#62; {:foo=&#62;&#34;bar&#34;} 

If the new syntax is so ding-dang good, then I think inspect should use it, when it can.
]]></description>
			<content:encoded><![CDATA[<p></p><p>I&#8217;m not religious about the old or new Ruby Hash syntax, but it is interesting that if you inspect a Hash in 1.9, you get the old syntax:</p>
<pre name="code" class="ruby">

ruby-1.9.2-p180 :001 &gt; { foo: 'bar' }
 =&gt; {:foo=&gt;&quot;bar&quot;} 
</pre>
<p>If the new syntax is so ding-dang good, then I think inspect should use it, when it can.</p>
]]></content:encoded>
			<wfw:commentRss>http://7fff.com/2011/07/09/another-reason-to-dislike-the-ruby-1-9-hash-syntax/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Helpful Rails book: Rails AntiPatterns, by Pytel and Saleh</title>
		<link>http://7fff.com/2011/05/24/helpful-rails-book-rails-antipatterns-by-pytel-and-saleh/</link>
		<comments>http://7fff.com/2011/05/24/helpful-rails-book-rails-antipatterns-by-pytel-and-saleh/#comments</comments>
		<pubDate>Wed, 25 May 2011 00:33:48 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Reading]]></category>
		<category><![CDATA[Reviews]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://7fff.com/?p=600</guid>
		<description><![CDATA[So I&#8217;m reading Chad Pytel and Tammer Saleh&#8217;s book Rails AntiPatterns: Best Practice Ruby on Rails Refactoring, and it&#8217;s a good one. Oops, but I got the title wrong: It&#8217;s RailsTM AntiPatterns: Best Practice Ruby on RailsTM Refactoring. (I don&#8217;t want to get sued for leaving out those TMs.)
I&#8217;ve been writing RailsTM code for a [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>So I&#8217;m reading Chad Pytel and Tammer Saleh&#8217;s book <a href="http://www.amazon.com/gp/product/0321604814/ref=as_li_ss_tl?ie=UTF8&#038;tag=ce1-20&#038;linkCode=as2&#038;camp=217145&#038;creative=399349&#038;creativeASIN=0321604814">Rails AntiPatterns: Best Practice Ruby on Rails Refactoring</a>, and it&#8217;s a good one. Oops, but I got the title wrong: It&#8217;s <em>Rails<sup>TM</sup> AntiPatterns: Best Practice Ruby on Rails<sup>TM</sup> Refactoring</em>. (I don&#8217;t want to get sued for leaving out those TMs.)</p>
<p>I&#8217;ve been writing Rails<sup>TM</sup> code for a long time, and this book is embarrassing to read. Honestly, after reading a couple of chapters I cranked up my editor and made some tweaks to my code. Whew. Truly, this book has the goods on any number of things <em>you&#8217;re doing wrong</em> with your Rails<sup>TM</sup> app, and I would advise you to take seriously their advice.</p>
<p>There are chapters that teach things you should already know (on Models, Views, and Controllers), but also chapters that go beyond (those on using third-party code and services), and some where I think these guys know more than just about anyone (the chapter on testing). I kinda wish the testing chapter didn&#8217;t use Shoulda, but I guess it&#8217;s OK, since they invented it.</p>
<p>It&#8217;s hard to find things to gripe about. One oddity is that they recommend HTTP 401 for application-level (i.e., controller) authorization errors (p. 205): But I thought 401 was reserved for specifically HTTP-related auth (e.g., basic or digest &#8211; see the <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html">RFC</a>). I guess you can use it like this. They also talk about denormalization, and replacing joins with column constants (pp. 79-82). I guess so. (To be sure, they say that if there&#8217;s going to be a UI, you do want the table.) I think increasingly we need to look at our schemas as though a non-Rails application will be using it, sooner rather than later: In which case, such constants really do need to be in a separate table, even if there is no UI. So I would advocate sucking in a table with the right codes, putting the key values into the table, and just leaving out the association if you want to avoid the joins. Also in this area, they put their constant values into an Array (p. 81). Dudes, use a Set. Please.</p>
<p>These manufactured gripes aside, it&#8217;s a lovely book. Now let me get back to my editor and my Rails<sup>TM</sup> app so I can remove some more embarrassments. Sheesh, Law of Demeter AGAIN!?</p>
]]></content:encoded>
			<wfw:commentRss>http://7fff.com/2011/05/24/helpful-rails-book-rails-antipatterns-by-pytel-and-saleh/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Russ Olsen&#8217;s Eloquent Ruby, and the teaching of Ruby</title>
		<link>http://7fff.com/2011/03/05/russ-olsens-eloquent-ruby-and-the-teaching-of-ruby/</link>
		<comments>http://7fff.com/2011/03/05/russ-olsens-eloquent-ruby-and-the-teaching-of-ruby/#comments</comments>
		<pubDate>Sat, 05 Mar 2011 23:35:26 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Reading]]></category>
		<category><![CDATA[Reviews]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://7fff.com/?p=586</guid>
		<description><![CDATA[Russ Olsen has just come out with a wonderful book on Ruby called Eloquent Ruby. If you&#8217;re a Rubyist, you should get it. What&#8217;s great about it is that it combines a breezy, even sometimes funny, style that is &#8220;teacherly&#8221; but also accurate in matter of detail.

There are a couple of things that really make [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>Russ Olsen has just come out with a wonderful book on Ruby called <a href="http://www.amazon.com/gp/product/0321584104?ie=UTF8&#038;tag=ce1-20">Eloquent Ruby</a>. If you&#8217;re a Rubyist, you should get it. What&#8217;s great about it is that it combines a breezy, even sometimes funny, style that is &#8220;teacherly&#8221; but also accurate in matter of detail.</p>
<p><center><iframe src="http://rcm.amazon.com/e/cm?lt1=_blank&#038;bc1=000000&#038;IS2=1&#038;bg1=FFFFFF&#038;fc1=000000&#038;lc1=0000FF&#038;t=ce1-20&#038;o=1&#038;p=8&#038;l=as4&#038;m=amazon&#038;f=ifr&#038;asins=0321584104" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe></center></p>
<p>There are a couple of things that really make the book work. First, there&#8217;s a nice little <code>Document</code> class that Olsen bends this way and that, using it as the vehicle for explaining subclassing, modules, mixins, and metaprogramming. My first impression was that it was a little lame, but by the end of the book I was very impressed with the range of examples. Indeed, the use of a Document class reminded me of some of the class examples from the Gang of Four book.</p>
<p>A second fine feature is that there are many sections devoted to a particular topic &#8220;In the Wild.&#8221; We have needed this in Ruby books for a long time &#8212; a coupling between Ruby as we know it in a textbook, and Ruby in the real world. These are really quite different &#8220;Rubies,&#8221; but Olsen is adept at showing through sometimes-simplified examples that the occasionally imponderable real-world Ruby really does share an idea of code with what learners start with.</p>
<p>I also like the chapter near the end of the book on the various Ruby interpreters, and how you can get something out of reading the code, be it in C, Java, or Ruby.</p>
<p>Now, about teaching Ruby.</p>
<p>Ruby is a tough teach. Students plateau at an average level of competence quickly, but the real power of Ruby comes after a stiff hike up the mountain to enlightenment.</p>
<p>I used to think that one could use the <a href="http://www.amazon.com/gp/product/1934356085?ie=UTF8&#038;tag=ce1-20">Programming Ruby</a> book alone, and this would do the job. But it&#8217;s long, and in its new edition somewhat hobbled by not discussing Ruby 1.8.x. In a number of places there is discussion that seems aimed at Java developers (see how easy it is in Ruby!) that feels out-of-date to me now.</p>
<p>But having read Olsen&#8217;s book, I&#8217;m now thinking that a better sequence is to pair Cooper&#8217;s <a href="http://www.amazon.com/gp/product/1430223634?ie=UTF8&#038;tag=ce1-20">Beginning Ruby</a> with <em>Eloquent Ruby</em>, supplemented, perhaps, with the Flanagan/Matz <a href="http://www.amazon.com/gp/product/0596516177?ie=UTF8&#038;tag=ce1-20">The Ruby Programming Language</a>. This way, you get to be effective and productive quickly (via Cooper), wade into the depths and improve your style (Olsen), and get the final word on syntax and semantics (Flanagan/Matz). A place where I think <em>Programming Ruby</em> may still have the edge is in some of the metaprogramming discussion, but here I think the best resource out there is Thomas&#8217;s <a href="http://www.pragprog.com/screencasts/v-dtrubyom/the-ruby-object-model-and-metaprogramming">video series</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://7fff.com/2011/03/05/russ-olsens-eloquent-ruby-and-the-teaching-of-ruby/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rapid software development with my 8-year-old</title>
		<link>http://7fff.com/2011/02/28/rapid-software-development-with-my-8-year-old/</link>
		<comments>http://7fff.com/2011/02/28/rapid-software-development-with-my-8-year-old/#comments</comments>
		<pubDate>Mon, 28 Feb 2011 15:03:40 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://7fff.com/?p=579</guid>
		<description><![CDATA[So my 8-year-old daughter has been increasingly interested in what computers can do, and how to make them do things. We&#8217;ve done some Scratch (http://scratch.mit.edu/) together, and we&#8217;ve done some Lego/software integration with MIT&#8217;s kit (not Mindstorms &#8212; we used the earlier kit MIT made that doesn&#8217;t have Lego branding and so forth). That was [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>So my 8-year-old daughter has been increasingly interested in what computers can do, and how to make them do things. We&#8217;ve done some Scratch (<a href="http://scratch.mit.edu/">http://scratch.mit.edu/</a>) together, and we&#8217;ve done some Lego/software integration with MIT&#8217;s kit (not Mindstorms &#8212; we used the earlier kit MIT made that doesn&#8217;t have Lego branding and so forth). That was pretty fun.</p>
<p>But what she really wanted was a multiplication drill-and-practice program. I said to her: &#8220;Are you sure?&#8221; (because I personally find drill-and-practice dead boring). Well that&#8217;s what she wanted. So we did it.</p>
<p>We did it in Ruby for my convenience. I decided that the hassles would be worth it. For instance, we talked a lot about what it means to convert a string typed by the human into an integer for the computer&#8217;s math. I wrote the code, and explained each and every line to her. The program would show a random multiplication (e.g., &#8220;7 x 8 = &#8220;), and she would have to type in the answer.</p>
<p>Here are the iterations we went through, and my observations regarding kids&#8217; games based on this single case:</p>
<ol>
<li>Report the number correct in a row. She likes the idea of breaking her longest streak of correct answers. <em>Kids like self-created goals.</em> I had introduced the idea of a variable to her earlier, but now we talked about it at greater length, since the counter had to be updated only under certain conditions.</li>
<li>Every 5 correct in a row, pop up a funny image. We used some lolcat images from icanhascheezburger.com. <em>My observation here is that kids like frequent rewards. But not too frequent!</em> We allowed that launching the browser to show an image would just be &#8220;magic.&#8221;
</li>
<li>She got interested in the basic stats: Number correct, number wrong, percent correct. We talked a lot about percentages, which is a bit ahead of where she is in math. I noticed shortly afterwards that she could correctly predict that if she got the next one right, she&#8217;d have 75% correct. <em>To me, this suggests that there are a lot of possibilities for passive learning; she started to &#8220;get&#8221; percentages without a lot of direction from me.</em> Some of this coding I just did without a lot of explanation: In particular, rounding for the percentages seemed to be too hard for her at this point.</li>
<li>As she was doing this, she told me that her goal was to get 100 in a row. At 90, she got one &#8220;wrong&#8221; because she just pressed return instead of entering a number (a case we hadn&#8217;t thought of). We had to stop the program to fix it, but that broke her streak. She suggested that there be some means to go backwards. So we introduced a cheat: If she types &#8220;cheat&#8221; the most recent answer would be forgotten. <em>This suggests to me that kids love to &#8220;win&#8221; but at the same time they can become very unhappy if there is a glitch that seems &#8220;wrong&#8221; to them.</em> Providing a means to get past a &#8220;mistake&#8221; seems to be very appealing. I am not sure that the availability of &#8220;cheats&#8221; is a good lesson to teach; it might set up the wrong expectations about the real world. On the other hand, it&#8217;s called a &#8220;cheat&#8221; for good reason, so I encouraged her to feel guilty about using the cheat. We decided to report on the number of cheats used over the course of a game. That way, if she never uses a cheat, she can brag about it (&#8221;I got 20 in a row, and didn&#8217;t use a cheat!&#8221;).</li>
<li>Finally, she wanted a bigger payoff at the end. She asked if she could enter her goal (20 in a row), and, if achieved, get a big fat message. So we did that. Now when you get to your goal, it prints out &#8220;You Win!&#8221; with a lot of asterisks around it. <em>To a kid, a &#8220;big&#8221; reward is something that is different from the rest of game flow (there are no asterisks elsewhere in the experience).</em></li>
</ol>
<p>So that was fun. The quality of the technology &#8212; the bells and whistles for the platform &#8212; seemed to matter a lot less than iterating through the game design, and thinking about the right rewards and punishments to encourage sticking to the activity.</p>
]]></content:encoded>
			<wfw:commentRss>http://7fff.com/2011/02/28/rapid-software-development-with-my-8-year-old/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

