<?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/"
	xmlns:series="http://unfoldingneurons.com/"
	>

<channel>
	<title>MettaProgramming &#187; Ruby</title>
	<atom:link href="http://mettadore.com/category/ruby/feed/" rel="self" type="application/rss+xml" />
	<link>http://mettadore.com</link>
	<description>Thoughts on Software and Technology</description>
	<lastBuildDate>Fri, 03 Feb 2012 17:39:26 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Polymorphic :has_many, :through in Rails modules</title>
		<link>http://mettadore.com/ruby/polymorphic-has_many-through-in-rails-modules/</link>
		<comments>http://mettadore.com/ruby/polymorphic-has_many-through-in-rails-modules/#comments</comments>
		<pubDate>Tue, 15 Nov 2011 19:28:49 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://mettadore.com/?p=895</guid>
		<description><![CDATA[[Update: Stephan Wehner actually showed me how to get this working (see his branch). Something else was wrong in the program I was actually using, which went away when I built this simplified version- I just never really tested with the simplified version. Thus, this post is now pointless. Thanks Stephan.] Recently, I had need [...]]]></description>
			<content:encoded><![CDATA[<h3>[Update: <a href="http://stephan.sugarmotor.org/">Stephan Wehner</a> actually showed me how to get this working (see <a href="https://github.com/johnmetta/polymorphic_plugin/tree/class-name">his branch</a>). Something else was wrong in the program I was actually using, which went away when I built this simplified version- I just never really tested with the simplified version. Thus, this post is now pointless. Thanks Stephan.]</h3>
<p>Recently, I had need to create a plugin that held a polymorphic :has_many, :through relationship. I spent a day or so trying to get this to work, only to realize that it is essentially impossible to do inside a pluggable Rails module, but possible if you templatize the classes.</p>
<h3>PolymorphicPlugin Example Project</h3>
<p>There&#8217;s a <a href="http://stackoverflow.com/questions/8130537/polymorphic-has-many-through-as-module-in-rails-3-1-plugin">StackOverflow thread</a> that describes this problem and the solution a bit; however, Based on the difficulty, and the fact that I couldn&#8217;t find any documentation specific to this problem, I figured I&#8217;d write it up as an example, and create a PolymorphicPlugin gem to illustrate it better.</p>
<p>The <a href="https://github.com/johnmetta/polymorphic_plugin/tree/side-module">PolymorphicPlugin inside-module branch</a> is an example of the way you&#8217;d distribute a pluggable Rails module with all classes contained in the module. The generator only creates a migration in the Rails project.</p>
<p>The <a href="https://github.com/johnmetta/polymorphic_plugin/tree/outside-module">PolymorphicPlugin outside-module</a> branch is an example of the way you&#8217;d distribute a pluggable Rails module in such a way that the generator creates a migration in <em>and also copies model files to</em> the Rails project.</p>
<h3>Problem Description</h3>
<p>The idea is that there&#8217;s an &#8220;acts_as&#8221; like plugin that I want to add to my Rails models:</p>
<pre class="brush: ruby; title: ; notranslate">
module PolymorphicPlugin
  module PolymorphicHolder

    def self.included(base)
      base.extend ClassMethods
    end

    module ClassMethods
      def holds_things
        has_many :thing_groupings, :as =&gt; :thingable
        has_many :things, :through =&gt; :thing_groupings
        include PolymorphicPlugin::PolymorphicHolder::InstanceMethods
      end
    end

    module InstanceMethods

      def has_things?
        true
      end

    end
  end
end
</pre>
<p>You can see that anything that calls <code>holds_things</code> should have a :has_many relationship with <code>Thing</code> through the <code>ThingGrouping</code> join table. This is a standard paradigm for a polymorphic :has_many, :through relationship.</p>
<p>Basically, I want to do this:</p>
<pre class="brush: ruby; title: ; notranslate">
class User &lt; ActiveRecord::Base
  holds_things
end

class Admin &lt; ActiveRecord::Base
  holds_things
end

user = User.new
user.has_things? -&gt; true

admin = Admin.new
admin.has_things? -&gt; true
</pre>
<div id="attachment_897" class="wp-caption alignleft" style="width: 210px"><a href="http://mettadore.com/files/2011/11/Screen-Shot-2011-11-15-at-10.51.18-AM.png"><img src="http://mettadore.com/files/2011/11/Screen-Shot-2011-11-15-at-10.51.18-AM-300x283.png" alt="" title="Screen Shot 2011-11-15 at 10.51.18 AM" width="200" class="size-medium wp-image-897" /></a><p class="wp-caption-text">inside-module plugin layout</p></div>
<h3>The failing case</h3>
<p>Seems pretty simple, right?</p>
<p>Turns out it&#8217;s not. Take a look at the directory layout that I tried to use. This seems like a standard for a gemmable plugin. The model files are contained in the gem library, and accessed as part of the module. When you use <code>gem 'polymorphic_plugin'</code>, the only thing that gets copied to your Rails project is the migration file. Nice and clean.</p>
<p>Unfortunately, that doesn&#8217;t work. If you clone this branch and run <code>rake test</code> you&#8217;ll get exceptions. Specifically, a <code>NameError: uninitialized constant User::ThingGrouping</code> because our <code>User</code> model, by extending the <code>PolymorphicHolder</code> module, doesn&#8217;t have access to this unknown model called <code>ThingGrouping</code>.</p>
<p>And no, using things like <code>:class_name</code> and <code>:source</code> were no help. <a href="http://stackoverflow.com/questions/8130537/polymorphic-has-many-through-as-module-in-rails-3-1-plugin">I tried everything, or seemingly everything</a>. Nothing would make this work.</p>
<div id="attachment_898" class="wp-caption alignleft" style="width: 210px"><a href="http://mettadore.com/files/2011/11/Screen-Shot-2011-11-15-at-10.52.40-AM.png"><img src="http://mettadore.com/files/2011/11/Screen-Shot-2011-11-15-at-10.52.40-AM-300x281.png" alt="" title="Screen Shot 2011-11-15 at 10.52.40 AM" width="200" class="size-medium wp-image-898" /></a><p class="wp-caption-text">outside-module plugin layout</p></div>
<h3>The passing case</h3>
<p>That is until I pulled the models outside of the plugin module. </p>
<p>Take a look at the directory layout now and you&#8217;ll notice that the <code>Thing</code> and <code>ThingGrouping</code> models are no longer in the plugin&#8217;s lib directory. Moving them to the templates directory is the unfortunate answer.</p>
<p>I say &#8220;unfortunate&#8221; because this means that the models need to be distributed by copying them to the Rails project. In other words, there&#8217;s a line in my <code>PolymorphicPluginGenerator</code> that reads: <code>    template "thing.rb", File.join('app/models', "thing.rb")</code>. In other words: Copy the <code>Thing</code> model into this project so it can be accidentally futzed with by users and maybe, if we&#8217;re lucky, cause some interesting name collisions.</p>
<p><code>Thing</code> and <code>ThingGroup</code> are no longer contained inside my PolymorphicPlugin module. They are top-level classes equivalent to anything generated with <code>rails generate model</code>. Not a solution that I&#8217;m fond of, but one that passes my tests. We can at least have a polymorphic :has_many, :through relationship now.</p>
<h3>Outcome</h3>
<p>Polymorphic :has_many, :through relationships are available in pluggable Rails modules, but it&#8217;s a bit of a kludge. You&#8217;ll need to make sure you name your polymorphic classes smartly to avoid name collisions with the calling Rails project. You&#8217;d hate to create a plugin with a model like <code>Book</code> only to find that <code>Book</code> already exists in someone&#8217;s Rails project!</p>
<p>I&#8217;d love to be proven wrong on this, by the way. Go ahead and <a href="https://github.com/johnmetta/polymorphic_plugin">grab the Github repository</a> and play with the inside-module branch. If you can make it work, I&#8217;ll buy you a beer!</p>
]]></content:encoded>
			<wfw:commentRss>http://mettadore.com/ruby/polymorphic-has_many-through-in-rails-modules/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rails 3.1 Gemmable Plugins with RSpec</title>
		<link>http://mettadore.com/ruby/rails-3-1-gemmable-plugins-with-rspec/</link>
		<comments>http://mettadore.com/ruby/rails-3-1-gemmable-plugins-with-rspec/#comments</comments>
		<pubDate>Mon, 14 Nov 2011 19:41:27 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://mettadore.com/?p=888</guid>
		<description><![CDATA[I&#8217;ve had a bitch of a time lately getting the new Rails 3.1 plugin architecture to play nicely with RSpec. I actually gave up and coded an entire plugin with Test::Unit before finally figuring out a decent way to do it. Currently, the new Rails 3.1 mountable plugin architecture will not work with RSpec. There&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve had a bitch of a time lately getting the new Rails 3.1 plugin architecture to play nicely with RSpec. I actually gave up and coded an entire plugin with Test::Unit before finally figuring out a decent way to do it.</p>
<p>Currently, the new Rails 3.1 mountable plugin architecture <a href="https://github.com/rspec/rspec-rails/issues/258">will not work with RSpec</a>. There&#8217;s a gem called <a href="https://github.com/josevalim/enginex">Enginex</a> that will work with RSpec, but it <a href="https://github.com/josevalim/enginex/issues/35">won&#8217;t work with Rails 3.1</a>. So it looks like you either get RSpec or Rails 3.1. What&#8217;s the deal?</p>
<p>Playing around, I figured out that combining the two will work:</p>
<pre class="brush: bash; title: ; notranslate">
$ gem install enginex
…
$ enginex my_plugin --test-framework=rspec
…
$ rails -v
Rails 3.1.1
$ rails plugin new stock_plugin --full
…
$ rm -rf my_plugin/spec/dummy
$ cp -r stock_plugin/test/dummy my_plugin/spec
</pre>
<p>After that, it&#8217;s just a matter of modifying my_plugin/spec/dummy/config/application.rb to require your gem, and clean up the spec_helper.rb file. I also changed the Gem files so that my_plugin.gemspec held the dependencies, and Gemfile just called that. This is the way the stock Rails 3.1 generator works. Enginex uses Gemfile as the canonical source, and I like the new way better.</p>
<p>Using this I&#8217;ve currently got a Rails 3.1 gemmable plugin with RSpec, Cucumber, Capybara, Spork, Guard, and Simplecov working just fine.</p>
]]></content:encoded>
			<wfw:commentRss>http://mettadore.com/ruby/rails-3-1-gemmable-plugins-with-rspec/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Wrestling ActiveResource Associations</title>
		<link>http://mettadore.com/ruby/wrestling-activeresource-associations/</link>
		<comments>http://mettadore.com/ruby/wrestling-activeresource-associations/#comments</comments>
		<pubDate>Sat, 25 Jun 2011 01:13:50 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://mettadore.com/?p=830</guid>
		<description><![CDATA[I need to state up front that I don&#8217;t have a solution to this problem. Hopefully, I can iterate toward a solution- using this interim solution (discussed at the end). The basic problem that I&#8217;ve found is that ActiveResource is a great Rails model to inherit from, except when it isn&#8217;t. And it seems that [...]]]></description>
			<content:encoded><![CDATA[<p>I need to state up front that I don&#8217;t have a solution to <a href="http://stackoverflow.com/questions/6448135/has-many-through-with-activeresource-models">this problem</a>. Hopefully, I can iterate toward a solution- using this interim solution (discussed at the end).</p>
<p>The basic problem that I&#8217;ve found is that ActiveResource is a great Rails model to inherit from, except when it isn&#8217;t. And it seems that &#8220;when it isn&#8217;t&#8221; basically means &#8220;anytime you are using associations.&#8221; To be fair, associations don&#8217;t <em>always</em> break, it just turns out that my architecture illustrates exactly when they <em>do</em> break.</p>
<p>To lay out the situation, I have a backend server running Rails with three models, User, Service, and Groups. I have a Rails frontend server without a database hitting this (as well as other) backend servers.</p>
<h3>Backend</h3>
<pre class="brush: ruby; title: ; notranslate">class User  :members
  has_many :managed_groups, :class_name =&amp;gt; &quot;Group&quot;
  accepts_nested_attributes_for :managed_groups, :services, :groups
end

class Group  :members
  belongs_to :manager, :class_name =&amp;gt; &quot;User&quot;, :foreign_key =&amp;gt; :user_id
  accepts_nested_attributes_for :users  
end

class Service &amp;lt; ActiveRecord::Base
  belongs_to :user
end

class Member &amp;lt; ActiveRecord::Base
  belongs_to :group
  belongs_to :user
end</pre>
<p>You can see it&#8217;s really basic setup. Users can have many Services, but Service can only have one User. By contrast, users can Manage many groups, and can belong to many Groups, while Groups can have many users who belong to it.</p>
<p>Users -&gt; Services is a basic :has_many relationship and Users -&gt; Groups is a :has_many, :through relationship. There is nothing complicated about this setup at all…</p>
<h3>Frontend</h3>
<p>…until you get to an ActiveResource frontend</p>
<pre class="brush: ruby; title: ; notranslate">class User &amp;lt; ActiveResource::Base
  self.site = &amp;quot;http://localhost:8801&amp;quot;
end

class Group &amp;lt; ActiveResource::Base
  self.site = &amp;quot;http://localhost:8801&amp;quot;
end

class Service &amp;lt; ActiveResource::Base
  self.site = &amp;quot;http://localhost:8801&amp;quot;
end</pre>
<p>The frontend server sees all of these models as ActiveResources, which works fine if you&#8217;re accessing User.name, but which doesn&#8217;t work so well if you&#8217;re trying to access User.services because User.services doesn&#8217;t exist. ActiveResource simply doesn&#8217;t know anything about associations, so you have to work around a big problem.</p>
<h3>:include =&gt; :associated_model</h3>
<p>One easy way to make User.services available to ActiveResource is by including it in the UsersController. Here&#8217;s a sample UsersController#Show method on the backend:</p>
<pre class="brush: ruby; title: ; notranslate">def show
@user = User.find(params[:id])
  respond_to do |format|
    format.xml  { render <img src='http://mettadore.com/wp-includes/images/smilies/icon_mad.gif' alt=':x' class='wp-smiley' /> ml =&amp;gt; @user.to_xml(:include =&amp;gt; [:managed_groups, :services, :groups]) }
    format.json  { render :json =&amp;gt; @user.to_json(:include =&amp;gt; [:managed_groups, :services, :groups]) }
  end
end</pre>
<p>We just include a list of whatever associated objects we want to include in the returned user package. Easy enough. Starting up the Rails console on the frontend now allows you to access User.services. However, what if you tried the following:</p>
<pre class="brush: ruby; title: ; notranslate">
service = Service.create(:name =&amp;gt; &quot;Test Service&quot;)
user = User.first
user.services &amp;lt;&amp;lt; service
</pre>
<p>Turns out that we can&#8217;t do that. We get an exception that the User model expects a Service class, but was supplied with an IndifferentHash.</p>
<p>With a :has_many/:belongs_to relationship, this is easy to work around:</p>
<pre class="brush: ruby; title: ; notranslate">
service = Service.create(:name =&amp;gt; &quot;Test Service&quot;, :user_id =&amp;gt; User.first.id)
</pre>
<p>Of course, user_id is a &#8220;primitive&#8221; type, a direct attribute of Server. So we can force it by going to the other side of the relationship and set that attribute and not have a problem.</p>
<h3>:has_many, :through =&gt; :needles_in_your_eye</h3>
<p>Working around the :belongs_to issue was easy, working around :has_many, :through is as fun as… well, you get the idea.</p>
<p>The problem is that there&#8217;s no backdoor to setting the association. You simply can&#8217;t access an array of objects as an association through ActiveResource. Look at what we see when the frontend accesses the backend server with a PUT request at /users/1.xml:</p>
<pre class="brush: jscript; title: ; notranslate">
{&quot;user&quot;=&amp;gt;
  {&quot;created_at&quot;=&amp;gt;2011-06-23 02:58:15 UTC,
   &quot;id&quot;=&amp;gt;1,
   &quot;name&quot;=&amp;gt;&quot;John Metta&quot;,
   &quot;updated_at&quot;=&amp;gt;2011-06-23 02:58:15 UTC,
   &quot;managed_groups&quot;=&amp;gt;[],
   &quot;services&quot;=&amp;gt;[
     {&quot;created_at&quot;=&amp;gt;2011-06-23 02:58:15 UTC,
      &quot;id&quot;=&amp;gt;1,
      &quot;updated_at&quot;=&amp;gt;2011-06-23 02:58:15 UTC,
      &quot;user_id&quot;=&amp;gt;1}
   ],
   &quot;groups&quot;=&amp;gt;[
     {&quot;created_at&quot;=&amp;gt;2011-06-23 02:56:37 UTC,
      &quot;id&quot;=&amp;gt;1,
      &quot;updated_at&quot;=&amp;gt;2011-06-23 02:56:37 UTC,
      &quot;user_id&quot;=&amp;gt;nil,
      &quot;users&quot;=&amp;gt;[
        {&quot;created_at&quot;=&amp;gt;2011-06-23 03:36:28 UTC,
         &quot;id&quot;=&amp;gt;6,
         &quot;name&quot;=&amp;gt;&quot;Jefferey&quot;,
         &quot;updated_at&quot;=&amp;gt;2011-06-23 03:36:28 UTC},
        {&quot;created_at&quot;=&amp;gt;2011-06-23 02:59:36 UTC,
         &quot;id&quot;=&amp;gt;2,
         &quot;name&quot;=&amp;gt;&quot;George&quot;,
         &quot;updated_at&quot;=&amp;gt;2011-06-23 03:05:13 UTC}
       ]
     },
     {&quot;created_at&quot;=&amp;gt;2011-06-23 02:56:37 UTC,
      &quot;id&quot;=&amp;gt;1,
      &quot;name&quot;=&amp;gt;&quot;Site Admin&quot;,
      &quot;updated_at&quot;=&amp;gt;2011-06-23 02:56:37 UTC,
      &quot;user_id&quot;=&amp;gt;nil,
      &quot;users&quot;=&amp;gt;[
        {&quot;created_at&quot;=&amp;gt;2011-06-23 03:36:28 UTC,
         &quot;id&quot;=&amp;gt;6,
         &quot;name&quot;=&amp;gt;&quot;Jefferey&quot;,
         &quot;updated_at&quot;=&amp;gt;2011-06-23 03:36:28 UTC},
        {&quot;created_at&quot;=&amp;gt;2011-06-23 02:59:36 UTC,
         &quot;id&quot;=&amp;gt;2,
         &quot;name&quot;=&amp;gt;&quot;George&quot;,
         &quot;updated_at&quot;=&amp;gt;2011-06-23 03:05:13 UTC},
        {&quot;created_at&quot;=&amp;gt;2011-06-23 02:58:15 UTC,
         &quot;id&quot;=&amp;gt;1,
         &quot;name&quot;=&amp;gt;&quot;John Metta&quot;,
         &quot;updated_at&quot;=&amp;gt;2011-06-23 02:58:15 UTC}
       ]
     }
   ]
  },
  &quot;id&quot;=&amp;gt;&quot;1&quot;}
</pre>
<p>Cats talking to dogs, here. They&#8217;d both be happy eating a squirrel, sure, but they just speak different languages.</p>
<p>Basically, the backend tries to find the &#8220;groups&#8221; and &#8220;services&#8221; properties on the User model. ActiveRecord expects groups to be, well Group objects- but it&#8217;s a Hash, not a Group. In order for this to work, those should be named &#8220;groups_attributes&#8221; and &#8220;services_attributes.&#8221;</p>
<p>This is basically telling me that ActiveRecord and ActiveResource basically don&#8217;t know how to talk to one another. What the hell was the Rails core team thinking?</p>
<p>ActiveResource should be patched to format it&#8217;s JSON string to use MODEL_attributes, right? Well, that would break a lot of stuff. ActiveResource is supposed to talk fine to my Scala backend server too, which it wouldn&#8217;t.</p>
<p>ActiveRecord should automatically treat MODEL: {ASSOCIATED_MODEL: …}} as something that can be converted to an ActiveRecord, right? I&#8217;m not sure of this one- it seems too possible to break things down the line that we didn&#8217;t expect.</p>
<p>So, you can do it from either direction without possibly horribly breaking something down the line.</p>
<p>Ahh, apparently the Rails core team was thinking &#8220;You know, we shouldn&#8217;t do this because we might horribly break something down the line.&#8221;</p>
<h3>Wrestling ActiveResource to the ground</h3>
<p>In order to fix this, I&#8217;ve added a simple hack to my UsersController on the backend. I say it&#8217;s simple because it&#8217;s pretty dumb. I say it&#8217;s a hack because I think it&#8217;s really ugly and inelegant&#8211; something I don&#8217;t expect from Rails.</p>
<p>Here&#8217;s the full UsersController#Update method on my backend server:</p>
<pre class="brush: ruby; title: ; notranslate">
  def update
    @user = User.find(params[:id])

    respond_to do |format|
      begin
        groups = []
        params[:user][:groups].each do |g|
          groups &amp;lt;&amp;lt; Group.find(g[:id])
        end
        params[:user][:groups] = groups
      rescue
      end

      begin
        services = []
        params[:user][:services].each do |s|
          services &amp;lt; @user.errors, :status =&amp;gt; :unprocessable_entity }
        format.json  { render :json =&amp;gt; @user.errors, :status =&amp;gt; :unprocessable_entity }
      end
    end
  end
</pre>
<p>As you can see, we grab that rogue IndifferentHash groups list and, basically, walk through it and find the local groups that correspond to the Group that&#8217;s in the list. This works- it allows ActiveResource to barely communicate with ActiveRecord. It&#8217;s no longer cats and dogs talking, it&#8217;s more like dogs and wolfs.</p>
<p>Yes, I know, wolves bite.</p>
<h3>One Model, One Resource</h3>
<p>This hack works, but it&#8217;s just that- A hack. If something seems this inelegant to me, then I have to question whether it is just that inelegant.</p>
<p>Today a friend mentioned that he&#8217;s never used accepts_nested_attributes_for. Never. He has never used nested resources like this because his strong philosophy is &#8220;One model, one resource.&#8221; I&#8217;m going to explore this for a few reasons, not the least of which is that I don&#8217;t think I want to pass the groups around inside the user if the user is a member of 3000 groups that we don&#8217;t care about. That&#8217;s just stupid.</p>
<p>Trying this method would mean that the User model on the frontend would require a groups method that would search the join table based on the user, and an additional add_group method which would go through the Group model to create a new group and somehow add that group to the users list of groups.</p>
<p>There&#8217;s a hole in my bucket, dear Liza, dear Liza, a hole in my bucket, dear Liza, a hole…</p>
<p>Really not sure how that would work&#8211; at least without some inclusion of my hack above. It seems like there&#8217;s just no way to get around this problem elegantly. I hope I&#8217;m wrong about that.</p>
<p>Someone please tell me I&#8217;m wrong.</p>
]]></content:encoded>
			<wfw:commentRss>http://mettadore.com/ruby/wrestling-activeresource-associations/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Ruby, Chef, and Tilde- Home directory shortcut #fail</title>
		<link>http://mettadore.com/ruby/ruby-chef-and-tilde-home-directory-shortcut-fail/</link>
		<comments>http://mettadore.com/ruby/ruby-chef-and-tilde-home-directory-shortcut-fail/#comments</comments>
		<pubDate>Mon, 24 Jan 2011 21:17:17 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[chef]]></category>
		<category><![CDATA[knife]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[shell]]></category>

		<guid isPermaLink="false">http://mettadore.com/?p=740</guid>
		<description><![CDATA[This should have been obvious to me, but wasn&#8217;t, so I want to make sure that it&#8217;s in the Googleverse in case someone steps into the same pit of idiocy that I did. The problem is that Ruby and Ruby-based tools like Chef are becoming so natural that they feel like they&#8217;re just part of [...]]]></description>
			<content:encoded><![CDATA[<p>This should have been obvious to me, but wasn&#8217;t, so I want to make sure that it&#8217;s in the Googleverse in case someone steps into the same pit of idiocy that I did.</p>
<p>The problem is that Ruby and Ruby-based tools like Chef are becoming so natural that they feel like they&#8217;re just part of the BASH shell. It took me a while to figure out the following error:</p>
<pre>
% knife cookbook create somename

/Users/john/.rvm/gems/ruby-1.8.7-p302/gems/chef-0.9.12/lib/chef/knife/cookbook_create.rb:90:in `initialize': No such file or directory -
 ~/Dev/Chef/chef-repo/cookbooks/sti-rewrites/recipes/default.rb (Errno::ENOENT)
	from /Users/john/.rvm/gems/ruby-1.8.7-p302/gems/chef-0.9.12/lib/chef/knife/cookbook_create.rb:90:in `open'
	from /Users/john/.rvm/gems/ruby-1.8.7-p302/gems/chef-0.9.12/lib/chef/knife/cookbook_create.rb:90:in `create_cookbook'
	from /Users/john/.rvm/gems/ruby-1.8.7-p302/gems/chef-0.9.12/lib/chef/knife/cookbook_create.rb:74:in `run'
	from /Users/john/.rvm/gems/ruby-1.8.7-p302/gems/chef-0.9.12/lib/chef/knife.rb:127:in `run'
	from /Users/john/.rvm/gems/ruby-1.8.7-p302/gems/chef-0.9.12/lib/chef/application/knife.rb:121:in `run'
	from /Users/john/.rvm/gems/ruby-1.8.7-p302/gems/chef-0.9.12/bin/knife:25
	from /Users/john/.rvm/gems/ruby-1.8.7-p302/bin/knife:19:in `load'
	from /Users/john/.rvm/gems/ruby-1.8.7-p302/bin/knife:19
</pre>
<p>Because, no matter how much I confirmed that the directory existed, it still failed. Why?</p>
<p>Because Ruby, as anyone really thinking about it would naturally realize, doesn&#8217;t expand Bash shortcuts.</p>
<p>To wit: The following entry in my ~/.chef/knife.rb file:</p>
<pre>
...
cookbook_path [ '~/Dev/Chef/chef-repo/cookbooks', '~/Dev/Chef/chef-repo/cookbooks' ]
...
</pre>
<p>Which I generated by running a command at the bash shell:</p>
<pre>knife configure</pre>
<p>As anyone would expect, changing that line to:</p>
<pre>
...
cookbook_path [ '/Users/john/Dev/Chef/chef-repo/cookbooks', '/Users/john/Dev/Chef/chef-repo/cookbooks' ]
...
</pre>
<p>fixed the problem. D&#8217;oh!</p>
<p>As I use more Ruby-based server configuration tools, I think I need to be a bit more conscious of when I&#8217;m with the purview of the Bash shell, and when I&#8217;m not.</p>
]]></content:encoded>
			<wfw:commentRss>http://mettadore.com/ruby/ruby-chef-and-tilde-home-directory-shortcut-fail/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Creating a Robotic Secretary with Hazel, Automator, &amp; Ruby</title>
		<link>http://mettadore.com/analysis/creating-a-robotic-secretary-with-hazel-automator-ruby/</link>
		<comments>http://mettadore.com/analysis/creating-a-robotic-secretary-with-hazel-automator-ruby/#comments</comments>
		<pubDate>Mon, 18 Oct 2010 23:08:24 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Miscellany]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[Automator]]></category>
		<category><![CDATA[Hazel]]></category>
		<category><![CDATA[workflow]]></category>

		<guid isPermaLink="false">http://mettadore.com/?p=606</guid>
		<description><![CDATA[If you&#8217;re on a Mac, and have to do a task more than once, then you need to use Hazel and Automator, full stop. I&#8217;m a consultant, and that means I work on multiple projects, and have to bill those projects. Recently, I began working on a contract that required weekly billing, using an Excel [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re on a Mac, and have to do a task more than once, then you need to use Hazel and Automator, full stop.</p>
<p>I&#8217;m a consultant, and that means I work on multiple projects, and have to bill those projects. Recently, I began working on a contract that required weekly billing, using an Excel spreadsheet that can&#8217;t be modified, and a signature from a project manager in another city. Talk about tedious! My workflow for just filling out a weekly timesheet is this:</p>
<ol>
<li>Use Freshbooks daily to track time</li>
<li>On Friday, open Freshbooks and pull the hours on that project</li>
<li>Open Excel (in VMWare) to update the read-only Master Timesheet file by changing the date, and adding my hours into the day slots
<ol>
<li>I can&#8217;t use Open Office or anything on the Mac since the formatting changes when I save it as an Excel file- I&#8217;ve tried a bunch of ways to do this, but as I usually have VMWare open to work in Visual Studio for this project anyway, I just use MS Excel on Windows</li>
</ol>
</li>
<li>Save the timesheet under another name</li>
<li>Drag the timesheet into another folder in my Dropbox (so that I have a record)</li>
<li>Open my email client and create an email to my project manager that says little more than &#8220;Timesheet, Cheers, -J&#8221;</li>
<li>Drag the timesheet into the email (I Google Mail&#8217;s ability to drag a file to attach!) and hit send</li>
<li>When he sends it back, it&#8217;s an attachment as an image- save the image to my project folder locally</li>
<li>Print out the image</li>
<li>Sign it (in blue pen, mind you)</li>
<li>Scan the signed copy</li>
<li>Move the scanned copy file to my local computer</li>
<li>Open a web browser to connect to their email system, which I&#8217;m supposed to use, but which is proxied, so I can&#8217;t use my normal email client.</li>
<li>Create another email to the timesheet recipient</li>
<li>Attach the file using the dialog boxes (Drag is not possible) and send it</li>
<li>Grab the timesheet original off my scanner and put in an envelope to mail to New York.</li>
</ol>
<p>Now, if you think about doing all of that, it&#8217;s not like it takes half the day. Still, it takes enough time that a good bit of my morning is lost to it. There&#8217;s not only the time spent &#8220;actively doing everything&#8221; but the lost time where I could have been concentrating on something like our object model or database abstraction layer, but which I&#8217;m distracted by simultaneously dealing with the timesheet issue. Anyone working in a &#8220;mental sphere&#8221; such as programming knows that a few seconds of distraction with something will pull you out of the mindset for 20 minutes or more.</p>
<p>Plus, there&#8217;s the added issue of this just being boring. It&#8217;s something a robot should be doing- or at least a secretary. More importantly, it&#8217;s something that could happen automatically! We programmers tend to get annoyed when things &#8220;should happen automatically&#8221; and they don&#8217;t. It is, in fact, why many of us became programmers.</p>
<h3>Enter Hazel</h3>
<p>For a while, I&#8217;ve been simplifying things a wee bit using <a href="http://www.noodlesoft.com/hazel.php">Hazel</a>. For those who don&#8217;t know, Hazel is a Mac program that watches a folder and performs actions based on the folder contents. I first heard about it on the <a href="http://macpowerusers.com/2010/04/mpu-025-geeking-out-with-hazel/">Mac Power Users</a> podcast and bought the software pretty much immediately following the podcast.</p>
<div id="attachment_608" class="wp-caption alignright" style="width: 310px"><a href="http://mettadore.com/files/2010/10/Screen-shot-2010-10-18-at-2.33.46-PM.png"><img class="size-medium wp-image-608" src="http://mettadore.com/files/2010/10/Screen-shot-2010-10-18-at-2.33.46-PM-300x122.png" alt="" width="300" height="122" /></a><p class="wp-caption-text">Hazel rules screen</p></div>
<p>Hazel is one amazing piece of time-saving software. It has a super simple graphical dialog box to let you set things like which folder, what attributes (&#8220;if files are older than&#8221; and &#8220;if file is a:&#8221; (e.g. movie, soundfile, pdf, etc) and &#8220;if the name contains:&#8221;) and what actions (Open, move, delete, archive, change name, import into iTunes, etc.) to perform on files in that folder.</p>
<p>One of the ways that I use it is on my desktop. If there are any pictures or movies on my desktop that are older than 1 day, Hazel takes them off my desktop and puts them on my remote hard drive, in appropriate folders, and simultaneously imports them into iTunes (I don&#8217;t have iTunes copy files to the local drive, so they&#8217;re watched from the remote drive).</p>
<p>When dealing with my timesheet, I have Hazel set up so that anything that goes into the &#8220;Timesheets&#8221; folder and is an Excel file gets automatically moved to a subfolder called &#8220;archive&#8221; and gets renamed with the pattern &#8220;John_Metta_&lt;date added&gt;.xls.&#8221; That way, I have an easily recognizable location and file to drag into an email to my project manager.</p>
<p>Using Hazel to automatically move, delete and organize your files can save you a lot of time. It&#8217;s tiny little chunks of time, sure, but it&#8217;s time. In reality, it&#8217;s saving you more the headache of having to do the same thing over and over again. Hazel is powerful, check it out.</p>
<h3>Add A Little Ruby</h3>
<p>Because I love Ruby, I decided to automate the creation of the Excel spreadsheet a bit. The Windows version of Ruby has the win32ole module, which can open and handle spreadsheets really easily. So I created a small script that opened a read-only version of the master timesheet spreadsheet and changed the date and the hours/day based on the arguments.</p>
<p>Here&#8217;s the whole script:</p>
<pre>require 'win32ole'

xl = WIN32OLE.new('Excel.Application')
xls = xl.Workbooks.open("c:\timesheets\Timesheet")
sheet = xls.Worksheets(1)

sheet.Cells(4,11).Value = ARGV[0]

#Time cell index
t = 6
ARGV.each_with_index do |a, i|
  sheet.Cells(10,t+i).Value = a
end

xls.SaveAs("Z:\john\Dropbox\Consulting Stuff\Nova\timesheets\timesheet")
xls.Close
xl.Quit</pre>
<p>With this, the command:</p>
<pre> C:timesheets$ ruby timesheet.rb "10/16" 0 0 8 7 6 7 8</pre>
<p>will create the correct timesheet for the week beginning 10/16, with the correct dates all lined up for the hours, and will save that timesheet to my Dropbox/timesheets directory- afterwhich Hazel will do the rest.<sup><a href="http://mettadore.com/analysis/creating-a-robotic-secretary-with-hazel-automator-ruby/#footnote_0_606" id="identifier_0_606" class="footnote-link footnote-identifier-link" title="There&amp;#8217;s actually an API library for Freshbooks in Ruby that is written  and maintained by Ben Curren at Outright.com, so you could pull the  hours straight from the project in a Ruby script- I decided against this  step">1</a></sup></p>
<h3>More with Automator</h3>
<div id="attachment_611" class="wp-caption alignright" style="width: 310px"><a href="http://mettadore.com/files/2010/10/automator-icon.png"><img class="size-medium wp-image-611" src="http://mettadore.com/files/2010/10/automator-icon-300x300.png" alt="" width="300" height="300" /></a><p class="wp-caption-text">Automator: More &quot;secretary&quot; than I&#039;d thought!</p></div>
<p>Earlier this week, I was still frustrated at the workflow of timesheets, however, because I still had a bunch of steps. Hazel was good at moving files and renaming them, but I still had to email them, print them, etc. So I decided to get my programming game on… then I decided that I didn&#8217;t even <em>need</em> to. Like all Macs, my Mac has Automator- a program that will create &#8220;workflows&#8221; and &#8220;applications&#8221; which basically amount to my own personal robotic secretary. Hazel can run both applications and Automator workflows on files, so I decided to give it a try.</p>
<h4><strong>Mailing to my PM</strong></h4>
<p>The first thing I do when I have my timesheet is move it to the timesheets folder where it gets renamed and archived so that I can send it to my PM. It would only be a single step to mail the renamed file. So I opened my Automator script and used the &#8220;create mail message,&#8221; &#8220;add attachment to open messages,&#8221; and &#8220;send mail&#8221; actions to create a script. Now, whenever a folder goes into Timesheets, it gets moved, renamed, <em>and</em> automatically mailed to my PM in one step!<sup><a href="http://mettadore.com/analysis/creating-a-robotic-secretary-with-hazel-automator-ruby/#footnote_1_606" id="identifier_1_606" class="footnote-link footnote-identifier-link" title="In full disclosure, the Automator script actually uses &amp;#8220;Save to a variable&amp;#8221; &amp;#8220;create new mail message&amp;#8221; &amp;#8220;get from variable&amp;#8221; &amp;#8220;add attachments&amp;#8221; and &amp;#8220;send mail&amp;#8221;&amp;#8211; in that order. For some reason, the &amp;#8220;add attachments&amp;#8221; phase was throwing an error otherwise.">2</a></sup></p>
<h4><strong>Printing and Signing</strong></h4>
<p>When my PM signs and mails it back it&#8217;s an image. So, I created another automator script to take any images with the name pattern &#8220;John_Metta_*&#8221; and the extension JPG in my &#8220;Downloads&#8221; directory and automatically move them to the &#8220;timesheets/images&#8221; directory and send them to the printer. That means all I have to do is open the email and click &#8220;download&#8221; and I&#8217;ll soon have a printed timesheet awaiting my signature. Sounds pretty secretary-like to me.</p>
<h4><strong>Mailing the final</strong></h4>
<p>My Canon all-in-one will scan automatically save files to a specific directory, so I could just set up Hazel to monitor that directory. The problem with this is that ANYTHING I scan will get processed. Rather than that, I&#8217;ve decided to have Hazel monitor that directory for a specific file name. Thus, when I scan any document, I see a dialog box on my screen prompting me to add a name. I can add a name in the rare occasions I want to scan something else. If I just hit &lt;enter&gt;, I&#8217;ve set Hazel up with another Automator script: Take the file, rename it with the pattern &#8220;John_Metta_Timesheet_&lt;date addedd&gt;&#8221;, mail it to the company as an attachment, and then throw the local copy in the trash (because Google Apps mail will store it for me).</p>
<h3>A Robotic Secretary</h3>
<p>The function of a secretary is to take care of everything that doesn&#8217;t absolutely need your action. A secretary should take care of everything in a &#8220;Do everything and let me just sign the paper.&#8221; That&#8217;s almost what I have now.</p>
<p>With this workflow, I&#8217;ve gone from 16 tedious steps to</p>
<ol>
<li>Track time daily in Freshbooks</li>
<li>Friday morning, while working, run the ruby command with my hours<sup><a href="http://mettadore.com/analysis/creating-a-robotic-secretary-with-hazel-automator-ruby/#footnote_2_606" id="identifier_2_606" class="footnote-link footnote-identifier-link" title="This automatically does everything through emailing my timesheet to my PM">3</a></sup></li>
<li>Work until lunch/break, before stopping, check my email (have an email from my PM waiting)</li>
<li>Click &#8220;download&#8221;<sup><a href="http://mettadore.com/analysis/creating-a-robotic-secretary-with-hazel-automator-ruby/#footnote_3_606" id="identifier_3_606" class="footnote-link footnote-identifier-link" title="This automatically files and prints the timesheet, it&amp;#8217;s just awaiting my signature">4</a></sup></li>
<li>Sign, scan, then hit enter</li>
</ol>
<p>That&#8217;s it!<sup><a href="http://mettadore.com/analysis/creating-a-robotic-secretary-with-hazel-automator-ruby/#footnote_4_606" id="identifier_4_606" class="footnote-link footnote-identifier-link" title="Well, I still have to mail it to New York, but that final step is a lot less annoying when it&amp;#8217;s not preceded by so much tedium!">5</a></sup></p>
<h3>Coda</h3>
<p>I highly suggest looking into combining Hazel, Automator, and any other talents you may bring to creating robotic secretaries for your automated tasks. This is just an example of a way you can take a morning&#8217;s worth of frustration and productivity vacuum and turn it into a few steps. Best of all, it took me about as long as two of these frustrating mornings to set everything up&#8211; meaning that it pays itself off in about half a month, on a year-long contract.<sup><a href="http://mettadore.com/analysis/creating-a-robotic-secretary-with-hazel-automator-ruby/#footnote_5_606" id="identifier_5_606" class="footnote-link footnote-identifier-link" title="I&amp;#8217;m sure this&amp;#8217;ll only get easier as more companies have APIs available. As I mentioned, I could probably have an automated task in Windows start the Ruby&nbsp; script and use output from a Freshbooks API query to automate step 2 above, meaning that I&amp;#8217;d do nothing until I got an email from my PM. However, I wanted the additional steps of adding my hours manually- more as a double check than anything.">6</a></sup></p>
<ol class="footnotes"><li id="footnote_0_606" class="footnote">There&#8217;s actually an API library for Freshbooks in Ruby that is written  and maintained by Ben Curren at Outright.com, so you could pull the  hours straight from the project in a Ruby script- I decided against this  step</li><li id="footnote_1_606" class="footnote">In full disclosure, the Automator script actually uses &#8220;Save to a variable&#8221; &#8220;create new mail message&#8221; &#8220;get from variable&#8221; &#8220;add attachments&#8221; and &#8220;send mail&#8221;&#8211; in that order. For some reason, the &#8220;add attachments&#8221; phase was throwing an error otherwise.</li><li id="footnote_2_606" class="footnote">This automatically does everything through emailing my timesheet to my PM</li><li id="footnote_3_606" class="footnote">This automatically files and prints the timesheet, it&#8217;s just awaiting my signature</li><li id="footnote_4_606" class="footnote">Well, I still have to mail it to New York, but that final step is a lot less annoying when it&#8217;s not preceded by so much tedium!</li><li id="footnote_5_606" class="footnote">I&#8217;m sure this&#8217;ll only get easier as more companies have APIs available. As I mentioned, I could probably have an automated task in Windows start the Ruby  script and use output from a Freshbooks API query to automate step 2 above, meaning that I&#8217;d do nothing until I got an email from my PM. However, I wanted the additional steps of adding my hours manually- more as a double check than anything.</li></ol>]]></content:encoded>
			<wfw:commentRss>http://mettadore.com/analysis/creating-a-robotic-secretary-with-hazel-automator-ruby/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Using Github as a Small-Scale CDN (w/Rails)</title>
		<link>http://mettadore.com/ruby/using-github-as-a-small-scale-cdn-wrails/</link>
		<comments>http://mettadore.com/ruby/using-github-as-a-small-scale-cdn-wrails/#comments</comments>
		<pubDate>Thu, 16 Sep 2010 01:11:32 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[CDN]]></category>
		<category><![CDATA[Github]]></category>
		<category><![CDATA[rails]]></category>

		<guid isPermaLink="false">http://mettadore.com/?p=524</guid>
		<description><![CDATA[I love Github. Like tomato sandwiches, Celtic music, beer, and programming- Github is something that, try as I might, I just can&#8217;t make myself sick of.1 Recently, I took the Git survey, and it contained an interesting question along the lines of &#8220;What do you use Git for?&#8221; The answers were things like &#8220;configuration files&#8221; [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://mettadore.com/files/2010/09/github-logo.png"><img class="alignleft size-full wp-image-525" src="http://mettadore.com/files/2010/09/github-logo.png" alt="" width="210" height="210" /></a>I love Github.</p>
<p>Like tomato sandwiches, Celtic music, beer, and programming- Github is something that, try as I might, I just can&#8217;t make myself sick of.<sup><a href="http://mettadore.com/ruby/using-github-as-a-small-scale-cdn-wrails/#footnote_0_524" id="identifier_0_524" class="footnote-link footnote-identifier-link" title="I&amp;#8217;ve tried for the past two summers to make myself sick of eating tomato sandwiches. I just can&amp;#8217;t.">1</a></sup></p>
<p>Recently, I took the Git survey, and it contained an interesting question along the lines of &#8220;What do you use Git for?&#8221; The answers were things like &#8220;configuration files&#8221; and &#8220;large binary files.&#8221;</p>
<p>I use Git and Github for a lot- configuration files are one use (I love the &#8220;raw&#8221; path), but it was only a small percentage of what that list suggested, so I started wondering how else I could use it.</p>
<p>Today, I thought of an interesting way: Github as a CDN.<sup><a href="http://mettadore.com/ruby/using-github-as-a-small-scale-cdn-wrails/#footnote_1_524" id="identifier_1_524" class="footnote-link footnote-identifier-link" title="The title is with Rails because that&amp;#8217;s what I used, but it would take 2.4 minutes to make this a &amp;#8220;With Django&amp;#8221; or &amp;#8220;With Lift&amp;#8221; example">2</a></sup></p>
<p>If you know what a <a href="http://en.wikipedia.org/wiki/Content_delivery_network">Content Delivery Network (CDN)</a> is, you don&#8217;t want me to explain. If you don&#8217;t, then it&#8217;s good enough to say that it&#8217;s a way to server up pictures or other content from another server. It&#8217;s often used to, say, serve the main portion of an html page from a webserver, but serve the images, CSS files, etc. from something like Amazon to speed things up.</p>
<p><img class="alignright" src="http://johnmetta.com/brand/logo.png" alt="" width="300" />I recently finished work on <a href="http://positivelyglorious.com/software-media/john-metta-an-intentional-brand/">The Great John Metta Branding Project</a> and, like with so many projects, stored the images in Dropbox. Then, deciding I might want to version them, I stored them in Github. Then, just as I was starting to begin the rather annoying process of copying all these logos and textmarks to my various sites throughout the web and updating all the image tags, I thought to myself &#8220;Hey, if these are already in Github, and I can access the raw files, why don&#8217;t I just use that as the image source?&#8221; But I don&#8217;t want to have to remember the URL each time. What if it was somewhat dynamically generated?</p>
<h2>A RESTful CDN system for a logo</h2>
<p>This is exactly why I made <a href="http://johnmetta.com">johnmetta.com</a> a Rails project, to play with stuff like this and then have a place to have it be live if I wanted to use it.</p>
<p>I&#8217;ve got a lot of different styles that my logo can take. Stacked, Icon only, textmark only, icon one-color grey, textmark one-color blue, etc. Ideally, I wouldn&#8217;t have to remember the path to each, I could type something like http://johnmetta.com/brand/icon/blue/transparent/logo.png<sup><a href="http://mettadore.com/ruby/using-github-as-a-small-scale-cdn-wrails/#footnote_2_524" id="identifier_2_524" class="footnote-link footnote-identifier-link" title="Actually having &amp;#8220;logo.png&amp;#8221; is unnecessary, however, sometimes the software using the URL will depend on that, so I just made it convention so that I don&amp;#8217;t have to think about when sometimes is.">3</a></sup> and have the app return the image that is strictly the icon (no words) with blue coloring and transparency inside the logo (instead of the normal white).</p>
<p>Since none of these actual images is created on the fly, I created a sensible directory structure and embedded all <img class="alignright" src="http://johnmetta.com/brand/icon/logo.png" alt="" width="100" />the files in this structure, naming them all <span style="font-family: courier new,courier">logo.png</span> and putting the default logo in the top level. So the above image would be {base}/full/logo.png, while a version with the icon on top would be {base}/full/stacked/logo.png. A one-color version of only the icon might be {base}/icon/blue/logo.png</p>
<p><img class="alignleft" src="http://johnmetta.com/brand/stacked/blue/logo.png" alt="" width="200" />So I created a <a href="http://github.com/johnmetta/brander">Brander</a> class which would turn arguments into an appropriate path and added some new routes such as &#8220;brand/:type/:color/logo.png&#8221; and created a call to brander in the controller&#8217;s &#8220;brand&#8221; action that ends with a redirect to the returned URL.</p>
<p>It&#8217;s all really simple, but it allows me to have a url like http://johnmetta.com/brand/icon/logo.png and supply my logo, and http://johnmetta.com/brand/stacked/blue/logo.png for a one-color blue stacked logo. Then, if I update the colors (move the files, whatever) they update automatically. At a maximum, I just check in the changes and make minimal changes to the routes- but don&#8217;t have to copy files to servers.</p>
<h2>A Good Illustration</h2>
<p>Right now, the Brander class is pretty dumb- little more than a way to translate a route into the correct external URL. It was built up not as an illustration of how to accomplish &#8220;Github as a CDN,&#8221; but merely as a toy to test one way that it might be done on a small scale. It might be better done as a class where instance attributes make more sense, and I&#8217;ll clean it up a bit, but not much more than that.</p>
<p>Also, it&#8217;s cool to know that stuff like this can be set up so easily, and for my uses- where bandwith might reach a whopping few requests per day, it&#8217;s useful while being low impact. But for a real CDN, you&#8217;d still want to use something like AWS- or at least talk to the Github guys before swamping their webservers.</p>
<ol class="footnotes"><li id="footnote_0_524" class="footnote">I&#8217;ve tried for the past two summers to make myself sick of eating tomato sandwiches. I just can&#8217;t.</li><li id="footnote_1_524" class="footnote">The title is with Rails because that&#8217;s what I used, but it would take 2.4 minutes to make this a &#8220;With Django&#8221; or &#8220;With Lift&#8221; example</li><li id="footnote_2_524" class="footnote">Actually having &#8220;logo.png&#8221; is unnecessary, however, sometimes the software using the URL will depend on that, so I just made it convention so that I don&#8217;t have to think about when sometimes is.</li></ol>]]></content:encoded>
			<wfw:commentRss>http://mettadore.com/ruby/using-github-as-a-small-scale-cdn-wrails/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>So you want to hire a ninja, do you?</title>
		<link>http://mettadore.com/analysis/so-you-want-to-hire-a-ninja-do-you/</link>
		<comments>http://mettadore.com/analysis/so-you-want-to-hire-a-ninja-do-you/#comments</comments>
		<pubDate>Wed, 28 Jul 2010 22:36:33 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Miscellany]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[jobs]]></category>
		<category><![CDATA[ninja]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[rockstar]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[zombie]]></category>

		<guid isPermaLink="false">http://mettadore.com/?p=437</guid>
		<description><![CDATA[I took a trip to Portland recently to traipse through OSCON. I was mostly in the exhibition hall with all the great schwag and company booths&#8211; many which had posted job announcements. While there, I was once again frustrated by a trend I keep seeing. The trend can be described as an &#8220;arms race of [...]]]></description>
			<content:encoded><![CDATA[<p>I took a trip to Portland recently to traipse through OSCON. I was mostly in the exhibition hall with all the great schwag and company booths&#8211; many which had posted job announcements. While there, I was once again frustrated by a trend I keep seeing. The trend can be described as an &#8220;arms race of job announcements,&#8221; and has gotten to the point where it&#8217;s difficult to find a development job listed by a company that is not seeking a &#8220;ninja,&#8221; or a &#8220;rockstar,&#8221; or some similarly absurdly described candidate.</p>
<h3>Smart and Gets Things Done</h3>
<p>As best I can tell, this trend really took off&#8211; even if it didn&#8217;t start&#8211; with Joel Spolsky&#8217;s blog article titled &#8220;<a href="http://www.joelonsoftware.com/articles/fog0000000073.html">The Guerrilla Guide to Interviewing</a>.&#8221; In that article, he stated that there was one primary requirement for working at Fog Creek Software: &#8220;Smart, and gets things done.&#8221;</p>
<p><a href="http://mettadore.com/files/2010/07/dwight.jpg"><img class="size-medium wp-image-441 alignright" src="http://mettadore.com/files/2010/07/dwight-218x300.jpg" alt="" width="218" height="300" /></a></p>
<p>His basic argument, with which I tend to agree, is that it doesn&#8217;t really matter what your past qualifications are as much as it matters that you can do to things: 1) Learn shit, and 2) Actually do shit.</p>
<p>His point? If you can&#8217;t learn, you&#8217;ll be stuck trying to write software in Visual Basic and someone will eventually shove you off of a roof out of frustration. Furthermore, if you don&#8217;t actually DO anything, but rather just talk about it, or think about it, or tell others why you could do it better&#8211; then you won&#8217;t even write software in Visual Basic. You won&#8217;t write any software at all, and someone will eventually shove you off of a roof out of frustration.</p>
<p>But if you can learn, it doesn&#8217;t matter what you come into the job knowing, because that&#8217;s merely a starting point. It&#8217;s how your knowledge and skills translate over time that&#8217;s important. You can learn &lt;insert whatever you need to do your job here&gt; quickly. I say quickly because you are a DOER, and doers always learn new stuff, so they can DO more stuff.</p>
<p>The most important thing here: The job will probably change, and when it changes, it&#8217;s the people who can LEARN, ADAPT and DO that will help the company succeed. The person who came to the job with one incredible skill but can&#8217;t learn probably has that one incredible skill in a stupid technology like Visual Basic, and someone will eventually shove&#8211;</p>
<p>well, you get the idea.</p>
<h3>The problem with catchy words</h3>
<p>So, herein lies a bit of the problem. Joel also talks about hiring the best people, treating them like &#8220;rockstars,&#8221; etc. Again, I think he has a point, but that there are a great deal of people who are stupidly picking up the hot new terms like &#8220;rockstar&#8221; and &#8220;ninja&#8221; and using the words, basically, without using their brains.</p>
<p>I see them a lot. Those posting that sound all hip and cool: &#8220;Are you a Python Guru?&#8221; or &#8220;We&#8217;re looking for a Ruby Rockstar for-&#8221; or &#8220;We want a PHP ninja to-&#8221; Everytime I see one of them I want to slap them in the head with the nearest O&#8217;Reilly book and then vomit.</p>
<p>This type of job posting proves one thing to the very people that you want hire: That they don&#8217;t want to work for you.</p>
<p>Why?</p>
<p>Because the very people you want to hire are the ones who describe themselves as &#8220;hard working&#8221; or &#8220;with a lot to learn&#8221; or even &#8220;not as good as many, but loyal, friendly and likes to learn new things.&#8221;</p>
<h3>Do you really want to hire a ninja?</h3>
<p>What&#8217;s a ninja?</p>
<p>It&#8217;s such a stupid, overused buzzword! Do you even know  what it means? It&#8217;s either an assassin or a stupid 14 year old jumping  out of a dumpster brandishing a medieval sword.</p>
<p>You don&#8217;t want either  of those things!</p>
<div id="attachment_438" class="wp-caption alignleft" style="width: 310px"><a href="http://mettadore.com/files/2010/07/GirlNinjas.jpg"><img class="size-medium wp-image-438" src="http://mettadore.com/files/2010/07/GirlNinjas-300x240.jpg" alt="" width="300" height="240" /></a><p class="wp-caption-text">Ninja: It&#039;s a word that&#039;s THIS overused</p></div>
<p>Yes, there&#8217;s some evidence that a well trained ninja was, if absolutely nothing else, a competent assassin (though the Samurai made fun of them). A ninja is basically a person who does one single thing really well, they kill people, and the rest of life- including the whole &#8220;getting along with people&#8221; part- they could give a rat&#8217;s ass about.</p>
<p>Human interaction to a ninja is &#8220;kill them!&#8221;</p>
<p>Conflict resolution to a ninja: &#8220;Kill them!&#8221;</p>
<p>For those who miss my subtly: A ninja programmer&#8217;s response to pretty much anything is going to be this: &#8220;Do it my way and no-one gets stabbed in the face with my medieval sword.&#8221;<sup><a href="http://mettadore.com/analysis/so-you-want-to-hire-a-ninja-do-you/#footnote_0_437" id="identifier_0_437" class="footnote-link footnote-identifier-link" title="No, don&amp;#8217;t ask your ninja programmer why they have a European weapon, you&amp;#8217;ll get stabbed in the face.">1</a></sup></p>
<p>Think about it. Do you really want to hire someone who does <em>one single thing</em> really well? To the exclusion of things like &#8220;showering&#8221; and, say &#8220;talking to other human beings?&#8221;</p>
<h3>Ninjas are Zombies!</h3>
<p>Here&#8217;s a neat trick: think of another stupid, overused buzzword: Zombie. What if I told you that ninjas are just zombies with black bags over their heads?</p>
<p>They do one thing really well: kill people (eating their brains- mostly the brains of your team if you hire them), and they could give a rat&#8217;s ass about things like &#8220;human interaction&#8221; and &#8220;conflict resolution.&#8221; What&#8217;s their solution to everything? &#8220;Kill them! (and, since we&#8217;re here, we could maybe snack on their brains too&#8230;)&#8221;</p>
<p>Ninjas are zombies! They&#8217;re mindless idiots going around trying to do one thing.</p>
<p>That&#8217;s it.</p>
<p>When you say &#8220;I want a ninja&#8221; you&#8217;re saying &#8220;you can be a complete asshole, refuse to learn anything new, refuse to respond to other human needs or the needs of the business, and also be a social trainwreck. Oh, and you don&#8217;t really need to know, or care, about 90% of programming or computer work, but if you can sit in your hole and &lt;do that one thing well&gt; and not talk to anyone, you&#8217;re the guy for us!&#8221;</p>
<p>You want a ninja-zombie as your lead developer, don&#8217;t you? Admit it.</p>
<h3>Rockstars: They go to 11</h3>
<p>Alright, I think you get my point, but let me touch upon rockstars for a moment. Here&#8217;s another place where I think Joel&#8217;s point was completely missed by a lot of people. Joel says &#8220;hire the best people you can find and treat them like rockstars&#8221; and in pure politician-like &#8220;I don&#8217;t really want to put any actual cognitive thought into this process, so I&#8217;ll just pull a buzzword&#8221;-style, job announcements start popping up for undefinable qualities such as &#8220;Ruby Rockstar.&#8221;</p>
<div id="attachment_440" class="wp-caption alignright" style="width: 310px"><a href="http://mettadore.com/files/2010/07/spinal-tap.jpg"><img class="size-medium wp-image-440" src="http://mettadore.com/files/2010/07/spinal-tap-300x201.jpg" alt="" width="300" height="201" /></a><p class="wp-caption-text">You want these guys in your company?</p></div>
<p>The mistake here is that all the corporate bozos think &#8220;Hey, &#8216;Rockstar&#8217; is the current buzzword, so I&#8217;ll use that too!&#8221; without stopping to think about one thing: &#8220;Rockstars don&#8217;t usually make the best employee material.&#8221;</p>
<p>Think of the words &#8220;punctual&#8221; and &#8220;hardworking.&#8221; Okay, now, keep those words in your head, and think of the word &#8220;rockstar.&#8221;</p>
<p>Yeah, your neck hurts doesn&#8217;t it?</p>
<p>See what happens when you take things out of context? Joel&#8217;s statement was &#8220;<em>treat</em> them like rockstars.&#8221; In otherwords, treat them like they mean something, like they matter, like the company depends on their happiness… so they will be happy… and do really good work… and make you more money.</p>
<p>The line was emphatically NOT &#8220;Make them <em>into</em> rockstars.&#8221;</p>
<p>Seriously! Think about your average caricature of a rockstar.<sup><a href="http://mettadore.com/analysis/so-you-want-to-hire-a-ninja-do-you/#footnote_1_437" id="identifier_1_437" class="footnote-link footnote-identifier-link" title="which is all we&amp;#8217;re really talking about in either case- neither Joel or you are talking about Dar Williams, here.">2</a></sup> They show up late, drunk, stoned, with a 16 year old&#8217;s bra stuck to their belt, and give you a loud, shitty performance of something they don&#8217;t feel like playing before hopping back into the bus for more sex, booze, and food.</p>
<p>Okay people, repeat this after me:</p>
<p><strong>&#8220;I don&#8217;t want to hire a Rockstar!&#8221;</strong></p>
<p>A rockstar is probably worse than a ninja, because at least a ninja- or a zombie, for that matter- can do <em>one</em> freakin&#8217; thing well. The only thing the rockstar can do is pray to god that the sound team can mix together the shit they call a studio performance, and that the stage crew can hit blow the fireworks early to cover the guitarist tripping and falling because they&#8217;re too freakin stoned to remember that there&#8217;s a drumset behind them.</p>
<p>They think of themselves as the best thing that&#8217;s ever happened to you, and if you tell them otherwise, they&#8217;ll freak out.</p>
<p>Rockstars <em>look</em> good. Full stop.</p>
<p>You know who the rockstar is? It&#8217;s the young programmer I met at the <a href="http://opensourcebridge.org">Open Source Bridge conference</a> who immediately berated me for using a different database strategy than him&#8211; without ever stopping to listen to the problem I was solving, to hear about my application&#8217;s design, or to learn <em>why</em> I would choose one over the other.</p>
<p>I was wrong, they were right, and I should really just stop being stupid and do it their way.</p>
<p>Yeah, that&#8217;s who I want on <em>my</em> team.</p>
<p>Fucking rockstars.</p>
<h3>Are you an incompetent programmer with an overblown sense of self-worth?</h3>
<p>Here&#8217;s the part that bugs me the most: The people posting these job announcements are actively selecting for people with a tendency to overstate their abilities while understating their faults.<br />
<a href="http://mettadore.com/files/2010/07/cat.jpg"><img class="alignleft size-medium wp-image-444" src="http://mettadore.com/files/2010/07/cat-265x300.jpg" alt="" width="265" height="300" /></a><br />
It&#8217;s called the <a href="http://en.wikipedia.org/wiki/Dunning-Kruger_effect">Dunning-Kruger effect</a> and it&#8217;s well documented in both the scientific literature and<a href="http://en.wikipedia.org/wiki/Dunning-Kruger_effect">popular journalism</a>.</p>
<p>The basic Gist is this: Incompetent people tend to overstate their abilities and think they are amazing, while highly competent people tend to downplay their skills and think that they are less than amazing.</p>
<p>And you know it&#8217;s true.</p>
<p>Go pick the first male rockstar-ninja-zombie programmer you can find and I&#8217;ll pick the first quiet, understated female programmer I can find. Then we&#8217;ll see which one can actually shut the hell up about how great they are and get something done.</p>
<p>The best people for the job are not the ones who are going to feel comfortable applying for the &#8220;Amazing Rockstar!!1!&#8221; position for the very reason that <em>they are the ones that you want to hire</em>: because they are too busy being amazed at all the stuff they <em>don&#8217;t</em> know to be rockstars who tell you everything that they <em>do</em> know.</p>
<p>They don&#8217;t think they know everything. In fact, with everything there is out there, they realize that they know basically <em>nothing</em>. Most importantly: They know that there&#8217;s a lot to learn, and they are trying to learn it.</p>
<p>The rockstars? The ninjas? They already know it, and they&#8217;ll tell you.</p>
<p>In fact, They&#8217;re more than happy to tell you <em>how much</em> they know.</p>
<p>Every single time you interact with them.</p>
<h3>Folk Developer: Will learn and be nice for food</h3>
<p>I don&#8217;t apply to any of these positions because, while there are a lot of things that I <em>am</em> and <em>can</em> do, there are certain things that I am emphatically <em>not</em>. A partial list of the things that I&#8217;m not is:</p>
<ul>
<li>Rockstar</li>
<li>Ninja</li>
<li>Zombie</li>
<li>Best person in the world at &lt;fill in whatever you want here&gt;</li>
</ul>
<p>Me, I&#8217;m not any of that. And that makes me think, from the majority of jobs I see lately, that I won&#8217;t be good enough to make the cut. And let&#8217;s face it, if they&#8217;re advertising for a rockstar, then I am probably not, because I do a lot of things competently, not one thing <em>better than everyone else including you</em>.</p>
<p><a href="http://mettadore.com/files/2010/07/ad-tiger.gif"><img class="alignleft size-full wp-image-465" src="http://mettadore.com/files/2010/07/ad-tiger.gif" alt="" width="251" height="243" /></a>See here&#8217;s the thing: I&#8217;ve been programming for 25+ years, I&#8217;m competent in at least 10 different languages, and really good in at least 4.<sup><a href="http://mettadore.com/analysis/so-you-want-to-hire-a-ninja-do-you/#footnote_2_437" id="identifier_2_437" class="footnote-link footnote-identifier-link" title="5 if we count Ruby, which I&amp;#8217;m learning more about every day">3</a></sup> I&#8217;ve built everything from robotic control systems to mathematical models, from spatial applications to social web applications. I&#8217;ve <em>taught</em> programming, and am about to do so again, and I do other things like start a <a href="http://rubygorge.org">Ruby users group</a>.</p>
<p>By many-if-not-all accounts, I&#8217;d be one hell of a developer to have on a team; yet many teams are seeking rockstars.</p>
<p>I am not a rockstar.</p>
<p>I&#8217;m not the guy on stage with lights and explosions and a screaming electric guitar.</p>
<p>I&#8217;m the guy who goes to a party and sits on the couch singing a song on a guitar. A really fun song, with really good guitar work, but not anything that needs lights and explosions. I may also pick up a banjo or back someone up on a number of other instruments, but mostly I just stay at the party and hang out with people.</p>
<p>No lights. No explosions.</p>
<p>I&#8217;m a folk developer.</p>
<p>I&#8217;m a seeker, I&#8217;m a learner. I&#8217;m a hard worker who will spend his free time coming up to speed on a technology for curiosity as well as success. I&#8217;m loyal, I&#8217;m friendly, I&#8217;ve got a sense of humor and would much rather laugh at myself than at anyone else. I spend my off time programming, like lots of people who love programming, but I also spend my off time playing the Irish flute and banjo, cycling, brewing cider and mead, working in community theater, and lots of other social pursuits.</p>
<p>Despite this (or, rather, because of it) I see myself as little more than &#8220;a decent programmer who&#8217;s probably not as good as most, but might be better than some.&#8221; In fact, I don&#8217;t have enough fingers to count the number of jobs I&#8217;ve actually <em>turned down</em> because I thought that I was probably not good enough&#8211; only to find that someone else was hired whom I actually know that I can outperform.</p>
<p>I am not going to apply for a job as a Python ninja or a Ruby Rockstar, because I&#8217;m not a ninja or a rockstar. I&#8217;m a person who knows a heck of a lot less about Ruby than many other Ruby programmers.</p>
<p>I&#8217;m a person with a lot to learn.</p>
<p>Exactly zero of my qualities describe a rockstar.</p>
<h3>Are you an incompetent company with an overblown sense of  self-worth?</h3>
<p>And I know that&#8217;s also true of many of my developer friends and colleagues. Companies select for people who are not them.</p>
<p>Here&#8217;s the clincher. Most of those companies who are hiring ninjas and rockstars are probably doing so because they see themselves as ninja and rockstar companies.</p>
<p>They are the companies that say things like &#8220;do you want to work in our cool-ass company where everything is better than any other company you&#8217;ve ever worked for, where we have foosball all day and are all awesome and badass about everything we do?&#8221;</p>
<p>Sound familiar? I&#8217;ll bet it does.</p>
<p>It sounds like a rockstar of a company.</p>
<ol class="footnotes"><li id="footnote_0_437" class="footnote">No, don&#8217;t ask your ninja programmer why they have a European weapon, you&#8217;ll get stabbed in the face.</li><li id="footnote_1_437" class="footnote">which is all we&#8217;re really talking about in either case- neither Joel or you are talking about Dar Williams, here.</li><li id="footnote_2_437" class="footnote">5 if we count Ruby, which I&#8217;m learning more about every day</li></ol>]]></content:encoded>
			<wfw:commentRss>http://mettadore.com/analysis/so-you-want-to-hire-a-ninja-do-you/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Stop being stupid about belongs_to!</title>
		<link>http://mettadore.com/ruby/stop-being-stupid-about-belongs_to/</link>
		<comments>http://mettadore.com/ruby/stop-being-stupid-about-belongs_to/#comments</comments>
		<pubDate>Wed, 21 Jul 2010 20:38:19 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[belongs_to]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[screwhead]]></category>

		<guid isPermaLink="false">http://mettadore.com/?p=429</guid>
		<description><![CDATA[This is just a post that may help me stop being stupid. Writing it may help carve it into the permanent portion of my memory instead of the &#8220;forget about it and then periodically have to think twice and remember that you did something stupid&#8221; portion. It&#8217;s a small thing, more of an annoyance than [...]]]></description>
			<content:encoded><![CDATA[<p>This is just a post that may help me stop being stupid. Writing it may help carve it into the permanent portion of my memory instead of the &#8220;forget about it and then periodically have to think twice and remember that you did something stupid&#8221; portion.</p>
<p>It&#8217;s a small thing, more of an annoyance than a real problem. Something like my tendency to forget &#8220;end&#8221; after blocks (a Python holdover) and to assume that zero equals false (a sort of &#8220;everything else&#8221; holdover).</p>
<p>It boils down to this:</p>
<p><span style="font-size: large">belongs_to is singular,  you stupid dipshit! Stop being a mindless screwhead and remember that for a change, John!</span></p>
<p>Honestly, it only takes me a second once I get the ever familiar error, but it&#8217;s just better to not get the error at all, right? Efficiency and correctness.</p>
<p>If anyone reads this and runs into me later, I wouldn&#8217;t mind if you repeat that statement to me.</p>
<p>More reminders couldn&#8217;t hurt.</p>
]]></content:encoded>
			<wfw:commentRss>http://mettadore.com/ruby/stop-being-stupid-about-belongs_to/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Quick, &#8220;random records&#8221; module</title>
		<link>http://mettadore.com/ruby/quick-random-records-module/</link>
		<comments>http://mettadore.com/ruby/quick-random-records-module/#comments</comments>
		<pubDate>Wed, 23 Jun 2010 23:46:10 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[ActiveRecord]]></category>
		<category><![CDATA[gems]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[random]]></category>
		<category><![CDATA[ungems]]></category>

		<guid isPermaLink="false">http://mettadore.com/?p=420</guid>
		<description><![CDATA[There are plenty of times when I want to grab either one or many random records from a database in Rails. For instance, one random user, one random post, 5 random items, etc. Honestly, it&#8217;s one of those things I do in nearly every app I&#8217;ve written, so a while ago I created a module [...]]]></description>
			<content:encoded><![CDATA[<p>There are plenty of times when I want to grab either one or many random records from a database in Rails. For instance, one random user, one random post, 5 random items, etc. Honestly, it&#8217;s one of those things I do in nearly every app I&#8217;ve written, so a while ago I created a module to add to any ActiveRecord class that gave me one() and some() methods. This way, I can just include Randomizer and have the methods. Everyone probably already has their method&#8211; I actually got this from somewhere else and modified it a bit&#8211; I figured I&#8217;d post mine in case someones searching the innerwebs.<sup><a href="http://mettadore.com/ruby/quick-random-records-module/#footnote_0_420" id="identifier_0_420" class="footnote-link footnote-identifier-link" title="It&amp;#8217;s one of those things that could be in a plugin or gem, but I&amp;#8217;m getting really sick of gems and plugins that carry all the infrastructure to support being gems or plugins when they are really simply a wee bit of code in one small file. Thus, I&amp;#8217;m starting to just publish Gists and add them manually to my lib directory. They&amp;#8217;re not really gems&amp;#8211; they&amp;#8217;re more like ungems. Maybe shards.">1</a></sup></p>
<p>[gist id=450723] </p>
<ol class="footnotes"><li id="footnote_0_420" class="footnote">It&#8217;s one of those things that could be in a plugin or gem, but I&#8217;m getting really sick of gems and plugins that carry all the infrastructure to support being gems or plugins when they are really simply a wee bit of code in one small file. Thus, I&#8217;m starting to just publish Gists and add them manually to my lib directory. They&#8217;re not really gems&#8211; they&#8217;re more like ungems. Maybe shards.</li></ol>]]></content:encoded>
			<wfw:commentRss>http://mettadore.com/ruby/quick-random-records-module/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Secure password generator-as-manager without single-point failure</title>
		<link>http://mettadore.com/ruby/secure-password-generator-as-manager-without-single-point-failure/</link>
		<comments>http://mettadore.com/ruby/secure-password-generator-as-manager-without-single-point-failure/#comments</comments>
		<pubDate>Thu, 17 Jun 2010 00:34:08 +0000</pubDate>
		<dc:creator>john</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[passfish]]></category>
		<category><![CDATA[password generators]]></category>
		<category><![CDATA[password managers]]></category>
		<category><![CDATA[passwords]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://mettadore.com/?p=412</guid>
		<description><![CDATA[Ahh, security. It&#8217;s it&#8217;s like flossing and using condoms. We all know we should do it but… well, it&#8217;s business time! We&#8217;ve all got the same issues. &#8220;Use strong passwords!&#8221; which means &#8220;don&#8217;t use just words&#8221; is something we all try to take seriously, but it just ends up being something like &#8220;c00lp455&#8243; with even [...]]]></description>
			<content:encoded><![CDATA[<p>Ahh, security. It&#8217;s it&#8217;s like flossing and using condoms. We all know we <em>should</em> do it but… well, it&#8217;s business time!</p>
<p>We&#8217;ve all got the same issues. &#8220;Use strong passwords!&#8221; which means &#8220;don&#8217;t use just words&#8221; is something we all try to take seriously, but it just ends up being something like &#8220;c00lp455&#8243; with even the most basic cracker program would handle easily&#8211; replacing letters with numbers was maybe a good strategy in 1988, but you might as well just use &#8220;coolpass&#8221; today, because that&#8217;s not any easier than using numbers for any attack.</p>
<p>&#8220;Don&#8217;t use the same password often,&#8221; &#8220;Use passwords with enough entropy (randomness),&#8221; &#8220;Use passwords longer than 8 characters with upper and lower case letters, numbers AND PUNCTUATION!!&#8221;</p>
<p>Whatever.</p>
<p>It basically comes down to this: We all have one password we use for freakin&#8217; everything, and that password is probably something like &#8220;mysillyp455.&#8221;</p>
<p>Sigh.</p>
<p>I&#8217;ve been wanting to get away from this lately, but have been generally disappointed at the options.</p>
<p>There are dozens of password managers out there, and hundreds or thousands of password generators. I have issues with all of them, and recently decided to address them in a bit of a crazy way: By completely re-thinking how I handle passwords.</p>
<h3>Password generators suck</h3>
<p>You know it&#8217;s true. They come up with the most ridiculous passwords that you&#8217;ll ever see. Who the hell is gonna remember &#8217;5+b(*|$1e8+8@&#8217; is their password?</p>
<p>Oh, right you want <em>pronounceable</em> passwords, because &#8216;m4k1tw0rk&#8217; is going to work better than &#8216;makeitwork.&#8217; Right. See above.</p>
<p>I mean, they do their job, sure, but password generators generating random strings are not really very useful to me, because I&#8217;ll never be able to recreate the password, which means I have to write it down somewhere or store it in a password manager…</p>
<h3>Password managers suck</h3>
<p>Yeah, I know, you&#8217;re a dedicated 1password user and you think I&#8217;m an idiot. It&#8217;s a decent solution<sup><a href="http://mettadore.com/ruby/secure-password-generator-as-manager-without-single-point-failure/#footnote_0_412" id="identifier_0_412" class="footnote-link footnote-identifier-link" title="or at least it would be if they&amp;#8217;d make a freakin&amp;#8217; Android app!">1</a></sup> but it, like any manager, still suffers from some serious flaws.</p>
<p>One is, of course, that if you&#8217;re somewhere or somehow don&#8217;t have that manager available, it&#8217;s absolutely impossible to get your password. This has recently happened to me while trying to use an app called LastPass, which generated really nice, ridiculously hard passwords for all kinds of stuff, that I could then never remember and I couldn&#8217;t get later when I screwed up my master password.</p>
<p>Reminder emails galore!</p>
<p>Here&#8217;s another problem: My passwords are stored on somebody else&#8217;s webapp database. Oh, sure, they&#8217;re stored &#8216;securely,&#8217; but how the hell do I know that&#8217;s true (read the TOS people, they limit their liability for a reason).</p>
<p>If the pentagon can get hacked, some 24 year old start-up geek is certainly vulnerable.</p>
<h3>Single points of failure suck</h3>
<p>The biggest things about all of these is the &#8216;single point of failure&#8217; issue. Password managers store passwords in encrypted files, so that&#8217;s nice. But what if someone gets your all important 1password that secures all your other passwords? You are, in a word, <a href="http://en.wikipedia.org/wiki/Fsck">fscked</a>.</p>
<p>So, the basic problem with all of these is that they are not actually as secure as we think, and when they are, they&#8217;re not easy. So we either have secure and hard as hell, or we have easy and fundamentally flawed, right?</p>
<p>Maybe not.</p>
<h3>Password generation <em>as</em> password management</h3>
<p>Okay, no lie, this came to me while somewhat tipsy and pouring down beer at a local pub:</p>
<p>What if your password wasn&#8217;t stored anywhere, ever. What if you could simply have a way to securely <em>recall</em> those ridiculous passwords that generators come up with out of thin air?</p>
<p>Think about it. 5+b(*|$1e8+8@ is probably a pretty damn secure password&#8211; if you used that for anything, you&#8217;d be pretty safe, but you&#8217;d never remember it. But what if that was, in a way, mnemonically generated?</p>
<p>Enter <a href="http://github.com/mettadore/passfish">Passfish</a>.<sup><a href="http://mettadore.com/ruby/secure-password-generator-as-manager-without-single-point-failure/#footnote_1_412" id="identifier_1_412" class="footnote-link footnote-identifier-link" title="Disclaimer: this is a proof of concept. A crazy scheme. It needs work, so I wouldn&amp;#8217;t jump into using it. At least not yet.">2</a></sup></p>
<p>Passfish is a program (actually, it&#8217;s an idea)<sup><a href="http://mettadore.com/ruby/secure-password-generator-as-manager-without-single-point-failure/#footnote_2_412" id="identifier_2_412" class="footnote-link footnote-identifier-link" title="actually-actually, it&amp;#8217;s planned to be an algorithm, but right now it&amp;#8217;s simply a quick hack as a proof of concept">3</a></sup> that generates passwords from the combination of words, a secret key file, and (optionally) name and passphrase parameters. Using this combination of items, Passfish will generate a high entropy password.</p>
<pre>$ passfish 'name@email.com'
 9!b%e+70
</pre>
<p>Now, that password is not stored anywhere, not in any encrypted file, nowhere.</p>
<p>Furthermore, if you use the Bash shell&#8217;s ability to ignore certain commands, that won&#8217;t even be in your Bash history. No-one can get it in a file, no-one can see what you&#8217;ve typed. It&#8217;s ephemeral. You call it up, and then it goes away.</p>
<p>But it&#8217;s still insecure as hell, right? I mean, anyone can figure out that name@email.com turns into SOMETHING.</p>
<h3>Generation and modification of hashes on the fly</h3>
<p>Keyfiles solve this. When you have a private keyfile, the string name@email.com is combined with the contents of this file, a hash is generated from that combined string, and the hash is modified in a repeatable way. This means that you can have super simple &#8220;passwords&#8221; (e.g. name@email.com) and even write them down on your forehead, and no-one will be able to generate your actual password without having your same keyfile.</p>
<p>But wait, there&#8217;s more!</p>
<pre>$ passfish 'email' --name 'work'
(|@+#^7b
$ passfish 'email' --name 'home'
$1e8+8@
</pre>
<p>You can specify an additional parameter, a name. This allows you to increase the security because you could have the same &#8220;password&#8221; for multiple accounts. You can also have passphrases:</p>
<pre>$ passfish 'email' --passphrase 'I hate Dirty Dancing!'
$1e8+8@
</pre>
<p>This allows even more security!</p>
<p>There&#8217;s also a length parameter:</p>
<pre>$ passfish 'email' --name 'work' --length 13
$1e8+8@$1e8+8
</pre>
<h3>Simple mnemonics for complex passwords</h3>
<p>One of the things many people do when thinking of passwords, is create devices that they use in ALL of their passwords. For instance, start with an @ and end with a $, then capitalize the first letter, so a password could be something like &#8216;@Email$&#8217;.</p>
<p>What Passfish allows you to do is to create similar mnemonics, but use them wisely to create <em>truely</em> complex passwords. For instance, it&#8217;s a <em>website</em> that I use at <em>work</em> called &#8220;<em>workstuff.com</em>&#8221;</p>
<pre>$ passfish "workstuff.com" -n "website" -p "at work"
$1e8+8@
</pre>
<p>Thus, the password is not stored anywhere, but I have an easy way to remember it.</p>
<h3>No single points of failure</h3>
<p>This way, even if someone steals my computer, they can&#8217;t get my passwords unless they have ALL of the following:</p>
<ol>
<li>The password identifier</li>
<li>The understanding that I&#8217;m using some stupid geeks weird Passfish program</li>
<li>Access to my private key file (which could be any file I choose)</li>
<li>Knowledge of the name, passphrase and password length</li>
</ol>
<p>Rather than a single point of failure, there are multiple points for each password, because even if someone got your private key file figured out, they&#8217;d still have to spend considerable time getting each password&#8211; <strong>and access to one password makes it no easier to access another password!</strong> It&#8217;s not an all-or-nothing proposition.</p>
<h3>The Status &amp; Future</h3>
<p>So, what&#8217;s the status? Well, it&#8217;s currently an <a href="http://github.com/mettadore/passfish.git">open source application on Github</a>, and it&#8217;s little more than a proof of concept. All it does now is combine all the parameters together into a string, hash it, and modify the hash. Pretty stupid, I know. (The plan is to do things better, like use the passphrase parameter to strengthen or change the hashing, etc.)</p>
<p>And as for the &#8220;but that&#8217;s stupid and hard&#8221; people, the other plan is to create apps that tie in with this underlying generator for things like Android and LaunchBar. For instance, a LaunchBar plugin that lets you type the identifier, name and passphrase, and then automatically copies the generated password to the clipboard, so that you don&#8217;t have to even see it, much less go to a terminal window to use Passfish.</p>
<p>So, it&#8217;s new, it&#8217;s still pretty dumb, but as a proof of concept, I throw it out there as an idea, knowing that&#8211; because it&#8217;s open source&#8211; any serious vulerabilities or blindspots will be illuminated.</p>
<p>Check it out, fork, modify, correct. Throw me ideas and comments or ignore it altogether.</p>
<ol class="footnotes"><li id="footnote_0_412" class="footnote">or at least it would be if they&#8217;d make a freakin&#8217; Android app!</li><li id="footnote_1_412" class="footnote">Disclaimer: this is a proof of concept. A crazy scheme. It needs work, so I wouldn&#8217;t jump into using it. At least not yet.</li><li id="footnote_2_412" class="footnote">actually-actually, it&#8217;s <em>planned</em> to be an <em>algorithm</em>, but right now it&#8217;s simply a quick hack as a proof of concept</li></ol>]]></content:encoded>
			<wfw:commentRss>http://mettadore.com/ruby/secure-password-generator-as-manager-without-single-point-failure/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

