<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Talk Like A Duck: Block Your Privates!</title>
    <link>http://talklikeaduck.denhaven2.com/articles/2007/09/04/block-your-privates</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>In Ruby, it's not the dog, it's the tricks!</description>
    <item>
      <title>Block Your Privates!</title>
      <description>&lt;p&gt;&lt;img src="http://talklikeaduck.denhaven2.com/files/180px-Russian-Matroshka_no_bg.jpg" class="tease-image"/&gt;
I&amp;#8217;ve noticed that some rubyists like to use indentation to delineate method visibility.
&lt;p&gt;The first time I noticed this was when Marcel Molina Jr. used it during the 
&lt;a href="http://rubyhoedown2007.confreaks.com/session01.html"&gt;charity testing workshop at the Ruby Hoedown.&lt;/a&gt;. I just encountered it again in at least one piece of sample code from Rob Orsini&amp;#8217;s &amp;#8220;Rails Cookbook.&amp;#8221;&lt;/p&gt;
&lt;p&gt;During the testing workshop, Chad Fowler expressed displeasure with this style, and I&amp;#8217;ve got to agree.&lt;/p&gt;&lt;/p&gt;


&lt;p style="clear:both;"&gt;Here&amp;#8217;s an example of this style:&lt;/p&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Gadget&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;framilize&lt;/span&gt;
    &lt;span class="ident"&gt;razzlitize&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;options&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:secret_ingredient_6X&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="ident"&gt;private&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;razzlitize&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The problem is that the indentation is &amp;#8220;artificial&amp;#8221;, there really is no nesting of evaluation scope here.
The way that Module#private and it&amp;#8217;s kin work when they are called without arguments is to set a marker onto
Ruby&amp;#8217;s eval stack which gets popped when the current evaluation context is exitted.  So the effects of 
the private method remain in effect until either the end of the current context, or one of the other methods
like public or protected, whichever comes first.  This means that if we extend the above example:&lt;/p&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Gadget&lt;/span&gt;
  &lt;span class="comment"&gt;#...&lt;/span&gt;
  &lt;span class="ident"&gt;private&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;razzlitize&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;dazzlitize&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The indentation can trick us into thinking that dazzlitize is public when it&amp;#8217;s really private.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;d always found the nature of methods like private without arguments to be a minor annoyance with
Ruby syntax. In my humble opinion they should have been able to take a block which delineated their effect.
What if we could write:
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Gadget&lt;/span&gt;
  &lt;span class="comment"&gt;#...&lt;/span&gt;
  &lt;span class="ident"&gt;private&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;razzlitize&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;dazzlitize&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Well, actually we &lt;strong&gt;can&lt;/strong&gt; write that, but it doesn&amp;#8217;t work as expected, since the block 
is silently ignored, and the method doesn&amp;#8217;t even get defined.&lt;/p&gt;
&lt;p&gt;So I started doing a little metaprogramming, to fix this. It seemed obvious how to do this. You 
alias_method Module#private so you can extend it, redefine the method to check for a block and if none 
is given, call the original method, otherwise evaluate the block in a way which makes any methods defined
private.  And of course you use test driven design to do this.&lt;/p&gt;
&lt;p&gt;I made some progress but ran into some problems:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The obvious way to evaluate the block:
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;module&lt;/span&gt;
  &lt;span class="keyword"&gt;alias&lt;/span&gt; &lt;span class="symbol"&gt;:old_private&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:private&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;private&lt;/span&gt;&lt;span class="punct"&gt;(*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;blk&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;blk_given?&lt;/span&gt;
       &lt;span class="ident"&gt;module_eval&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
         &lt;span class="ident"&gt;old_private&lt;/span&gt;
         &lt;span class="ident"&gt;blk&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;call&lt;/span&gt;
       &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="keyword"&gt;else&lt;/span&gt;
      &lt;span class="ident"&gt;old_private&lt;/span&gt;&lt;span class="punct"&gt;(*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Doesn&amp;#8217;t seem to work.  The method isn&amp;#8217;t made private.  I had to resort to getting a list of
the methods before the block, then calling old_private with the difference between the new methods after
the block is evaluated, and those before.&lt;/p&gt;
&lt;p&gt;The module_eval now looked something like this:&lt;/p&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;module_eval do
  existing = instance_methods(false)
  blk.call
  new_methods = instance_methods(false)-existing
  old_private(new_methods.map {|m| m.to_sym}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are some obvious shortcomings in this code, but at this point, the goal was to do the simplest
thing which could work for the test cases at hands, the complications would be dealt with later.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;To add insult to injury, calling old_private from within the new definition doesn&amp;#8217;t work either, 
the evaluation context gets marked as described above, but it gets popped off when we exit the context
of the new definition.  At this point I decided to punt, temporarily at least, and just define a new
method Module#with_private which took a block, and leave the existing Module#private alone.
&lt;li&gt;Then I decided that I should test changing the visibility of an existing method, in other words a test
case like this:
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;class Test
  protected
  def meth;end
  with_private do
     def meth;end
  end
end&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Test#meth should end up private, but my simple diff failed to notice the definition, things were starting
to get more complicated. It looked like I&amp;#8217;d need to hook Module#method_added and probably others. I began to
wonder whether it was worth it.
&lt;/ol&gt;
&lt;p&gt;Then I started to ponder the fact that the effect of private/protected/public gets popped when the 
evaluation context exits.  So I said to myself, &amp;#8220;Is there a way to take advantage of that?&amp;#8221;  Well, Virginia,
yes there is.
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Gadget&lt;/span&gt;
  &lt;span class="comment"&gt;#...&lt;/span&gt;
  &lt;span class="ident"&gt;class_eval&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
    &lt;span class="ident"&gt;private&lt;/span&gt;

    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;razzlitize&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;dazzlitize&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This seems to work as expected, here&amp;#8217;s a link to a 
&lt;a href="http://talklikeaduck.denhaven2.com/files/test_block_private.rb"&gt;test case file.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now I still prefer being able to give a block to Module#private and it&amp;#8217;s ilk, and I might still work
on that, but in the meantime, class_eval and module_eval seem to provide a way to actually do what I want.&lt;/p&gt;</description>
      <pubDate>Tue, 04 Sep 2007 11:28:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:a22bc9c4-17f0-42b2-93be-6ed10cc60a37</guid>
      <author>Rick DeNatale</author>
      <link>http://talklikeaduck.denhaven2.com/articles/2007/09/04/block-your-privates</link>
      <category>ruby</category>
      <category>best_practices</category>
      <category>style</category>
      <category>metaprogramming</category>
      <trackback:ping>http://talklikeaduck.denhaven2.com/articles/trackback/461</trackback:ping>
    </item>
    <item>
      <title>"Block Your Privates!" by Rick DeNatale</title>
      <description>&lt;p&gt;Oops Robert,&lt;/p&gt;


It doesn&amp;#8217;t work after all.  There was a misplaced end which confused me:
&lt;pre&gt;&lt;code&gt;class Module
 alias_method :old_private, :private
 @isPrivate = [ false ]
 class &amp;lt;&amp;lt; self
   attr_reader :isPrivate
 end
#  end &amp;lt;==== This end

 def private *args, &amp;amp;blk
  return old_private( *args ) unless blk
  Module.isPrivate.push true
  class_eval &amp;amp;blk
  Module.isPrivate.pop
 end   
 def method_added *args, &amp;amp;blk
  old_private args.first if Module.isPrivate.last
 end
# SHOULD BE HERE
end

class A
 def initialize
   puts pm
 end
 private do
   def pm; 46 end
 end
end

puts A.new.pm&lt;/code&gt;&lt;/pre&gt;

Now while the example you gave works, the use of private with no arguments or block is still broken.
&lt;pre&gt;&lt;code&gt;class B
   private
   def priv
   end
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Gives B.private_instance_methods(false) =&amp;gt; []&lt;/p&gt;


	&lt;p&gt;and B.public_instance_methods(false) =&amp;gt; [&amp;#8216;priv&amp;#8217;]&lt;/p&gt;


	&lt;p&gt;The problem still seems to be that if you execute private with no args inside a method, its effect gets popped off the stack when you return, and so it has no effect.&lt;/p&gt;


	&lt;p&gt;And I can&amp;#8217;t see a way to stack it when there&amp;#8217;s no block and no args and force it with method_added, since there&amp;#8217;s doesn&amp;#8217;t seem to be a way to know when the class definition scope is exitted and therefore when to pop it.&lt;/p&gt;</description>
      <pubDate>Wed, 05 Sep 2007 18:47:14 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:482fbaaa-41dd-48e5-a11b-c0dc82720cbb</guid>
      <link>http://talklikeaduck.denhaven2.com/articles/2007/09/04/block-your-privates#comment-881</link>
    </item>
    <item>
      <title>"Block Your Privates!" by Rick DeNatale</title>
      <description>&lt;p&gt;Robert,&lt;/p&gt;


	&lt;p&gt;Thanks.  I was thinking along those lines, but got tired. ;-)&lt;/p&gt;


I&amp;#8217;m not sure why 
&lt;pre&gt;&lt;code&gt;  return old_private(*args)&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Seems to work for the no block given case when:&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;  old_private(*args)&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;As the last expression doesn&amp;#8217;t seem to.&lt;/p&gt;


	&lt;p&gt;This does look like it could be the basis for a real implementation of the idea.&lt;/p&gt;</description>
      <pubDate>Wed, 05 Sep 2007 15:56:28 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:c63fc9e1-bcc1-41c6-84b4-90282fae13ab</guid>
      <link>http://talklikeaduck.denhaven2.com/articles/2007/09/04/block-your-privates#comment-879</link>
    </item>
    <item>
      <title>"Block Your Privates!" by Robert Dober</title>
      <description>&lt;p&gt;Sorry Rick I did not see the Preview button, bad bad me, let me give it a last shot:&lt;/p&gt;


	&lt;pre&gt;&lt;code&gt;class Module
 alias_method :old_private, :private
 @isPrivate = [ false ]
 class &amp;lt;&amp;lt; self
   attr_reader :isPrivate
 end
end&lt;/code&gt;&lt;/pre&gt;


	&lt;pre&gt;&lt;code&gt;def private *args, &amp;#38;blk
  return old_private( *args ) unless blk
  Module.isPrivate.push true
  class_eval &amp;#38;blk
  Module.isPrivate.pop
end   
def method_added *args, &amp;#38;blk
  old_private args.first if   Module.isPrivate.last
end&lt;/code&gt;&lt;/pre&gt;


	&lt;pre&gt;&lt;code&gt;class A
 def initialize
   puts pm
 end
 private do
   def pm; 46 end
 end
end&lt;/code&gt;&lt;/pre&gt;


	&lt;pre&gt;&lt;code&gt;puts A.new.pm&lt;/code&gt;&lt;/pre&gt;</description>
      <pubDate>Wed, 05 Sep 2007 15:37:02 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:6e753f5d-0c1c-432d-a05a-e8c702ebf699</guid>
      <link>http://talklikeaduck.denhaven2.com/articles/2007/09/04/block-your-privates#comment-878</link>
    </item>
    <item>
      <title>"Block Your Privates!" by Robert Dober</title>
      <description>&lt;p&gt;Hmm did not format&lt;/p&gt;


	&lt;p&gt;let me try again&lt;/p&gt;


	&lt;pre&gt;&lt;code&gt;class Module
   alias_method :&lt;i&gt;private&lt;/i&gt;, :priavte
   @isPrivate = [ false ]
   class &amp;lt;&amp;lt; self
      attr_reader :isPrivate
   end
   ...&lt;/code&gt;&lt;/pre&gt;</description>
      <pubDate>Wed, 05 Sep 2007 15:32:26 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:1d458732-3486-4d50-895b-85d15dbb6152</guid>
      <link>http://talklikeaduck.denhaven2.com/articles/2007/09/04/block-your-privates#comment-877</link>
    </item>
    <item>
      <title>"Block Your Privates!" by Robert Dober</title>
      <description>&lt;p&gt;Hey Rick, great to hear from you after some time, maybe you want to have a look at my shot at your problem.
Quite an ugly piece of code, but maybe it is useful to you.&lt;/p&gt;


	&lt;p&gt;Cheers
Robert&lt;/p&gt;


	&lt;p&gt;Here we go:&lt;/p&gt;


	&lt;p&gt;class Module
  alias_method :&lt;i&gt;private&lt;/i&gt;, :private
  @isPrivate = [ false ]
  class &amp;lt;&amp;lt; self
    attr_reader :isPrivate
  end
end&lt;/p&gt;


	&lt;pre&gt;&lt;code&gt;def private *args, &amp;#38;blk
  return &lt;i&gt;private&lt;/i&gt;( *args ) unless blk
  Module.isPrivate.push true
  class_eval &amp;#38;blk
  Module.isPrivate.pop
end   
def method_added *args, &amp;#38;blk
  &lt;i&gt;private&lt;/i&gt; args.first if Module.isPrivate.last
end&lt;/code&gt;&lt;/pre&gt;


	&lt;p&gt;class A
  def initialize
    puts pm
  end
  private do
    def pm; 46 end
  end
end&lt;/p&gt;


	&lt;p&gt;puts A.new.pm&lt;/p&gt;</description>
      <pubDate>Wed, 05 Sep 2007 15:30:33 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:9165d3a4-504f-41b4-aa50-f654c284763b</guid>
      <link>http://talklikeaduck.denhaven2.com/articles/2007/09/04/block-your-privates#comment-876</link>
    </item>
    <item>
      <title>"Block Your Privates!" by Daniel Berger</title>
      <description>&lt;p&gt;If def returned something useful we could just do:&lt;/p&gt;


	&lt;p&gt;private def foo
   ...
end&lt;/p&gt;


	&lt;p&gt;But, as the result of analysis paralysis, we get nothing. Boo.&lt;/p&gt;</description>
      <pubDate>Tue, 04 Sep 2007 12:09:55 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:2ddaf95d-1382-4753-b345-199a17d29309</guid>
      <link>http://talklikeaduck.denhaven2.com/articles/2007/09/04/block-your-privates#comment-868</link>
    </item>
  </channel>
</rss>
