1. Play-By-Play: Layout

    July 9, 2010 by Craig

    I want to use HAML for my templates. I already have it installed; all I need to do now is convert the scaffolded ERB layout.

    html2haml app/views/layouts/application.html.erb app/views/layouts/application.haml
    

    One other thing I like to do is have the <title> and topmost <h1> tags have the same content. This is generally considered (by the SEO black-magicians)
    Change the so that it displays the Also have an h1 that contains this title. Set this variable on every page.<br />


  2. Play-By-Play: Heroku Setup

    June 7, 2010 by Craig

    Setting up the project is easy enough:

    heroku create softcraft-bakery
    

    Heroku creates a git repo for each project. I want to keep my main git repo on github.

    Add the heroku remote:

      git remote add heroku git@heroku.com:softcraft-bakery.git
      git push heroku master
    

    That gives me:

    -----> Heroku receiving push
     !     Heroku push rejected, no Rails or Rack app detected.
    
    This is caused by rails files being in a subdirectory of my git project. I don't want to mess around trying to figure out how to support an unexpected configuration, so I'll move everything up a level:
    

    rm README rm .gitignore git mv bakery/* . git commit -a -m "Moved rails files up a level" git push heroku

    Output:

    -----> Heroku receiving push -----> Gemfile detected, running Bundler -----> Bundler works best on the Bamboo stack. Please migrate your app: http://docs.heroku.com/bamboo Unresolved dependencies detected; Installing... Fetching source index from http://rubygems.org/ Resolving dependencies Installing abstract (1.0.0) from system gems Installing actionmailer (3.0.0.beta3) from rubygems repository at http://rubygems.org/ /usr/local/lib/ruby/site_ruby/1.8/rubygems/installer.rb:186:in `install': actionmailer requires Ruby version >= 1.8.7 (Gem::InstallError) from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/source.rb:42:in `install' from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/installer.rb:30:in `run' from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/installer.rb:18:in `each' from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/installer.rb:18:in `run' from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/installer.rb:6:in `install' from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/cli.rb:60:in `install' from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/vendor/thor/task.rb:33:in `send' from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/vendor/thor/task.rb:33:in `run' from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/vendor/thor/invocation.rb:109:in `invoke' from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/vendor/thor/invocation.rb:116:in `call' from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/vendor/thor/invocation.rb:116:in `invoke' from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/vendor/thor.rb:137:in `start' from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/vendor/thor/base.rb:378:in `start' from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/lib/bundler/vendor/thor.rb:124:in `start' from /usr/local/lib/ruby/gems/1.8/gems/bundler-0.9.9/bin/bundle:11 from /usr/local/bin/bundle:19:in `load' from /usr/local/bin/bundle:19 FAILED: Have you updated to use a 0.9 Gemfile? http://docs.heroku.com/gems#gem-bundler

    Now I have to set the Heroku "stack" (runtime environment & versions):
    heroku stack:migrate bamboo-ree-1.8.7
    

    Success!


  3. Play-by-Play: Rails Setup

    June 5, 2010 by Craig

    I still don’t have an official name for this project, so I’ll call it “bakery” in the interim.

    rails bakery
    git add bakery
    git commit -a -m "Basic Rails install"
    rails server
    

    This is new: there’s a single execution point for rails tasks. It’s nice to not have to type script/... all the time

    Fire up http://0.0.0.0:3000/ and see that it’s working.

    Gem Updates

    Update haml/sass:

    sudo gem update haml
    

    Add “gem haml” to Gemfile (another new feature).

    Update Ryan Bates’ Nifty Generators. They’re nifty. Especially when generating.

    sudo gem install nifty-generators
    

    Add “gem nifty-generators” to the Gemfile.

    Also update autotest and shoulda

    Hello World

    Time to get a Hello World going. It’s not working until I see Hello World.

    First, unpack the gems. How do I do that again?

    rake -T gem
    /Users/craig/Documents/SoftCraft/projects/bakery/rails/bakery/db/schema.rb doesn't exist yet. Run "rake db:migrate" to create it then try again. If you do not intend to use a database, you should instead alter /Users/craig/Documents/SoftCraft/projects/bakery/rails/bakery/config/boot.rb to limit the frameworks that will be loaded
    

    Fair enough.

    rake db:migrate
    (in /Users/craig/Documents/SoftCraft/projects/bakery/rails/bakery)
    
    rake -T gem
    (in /Users/craig/Documents/SoftCraft/projects/bakery/rails/bakery)
    rake rails:freeze:gems  # The rails:freeze:gems is deprecated, please use bundle install instead
    

    More Rails 3 changes. Looks like freezing isn’t necessary any more. That’s good; I never liked it anyway.

    Now, I need a “Hello World” page. That means I need a HomeController for the root route.

    rails generate controller Home
    

    Now I need a view. Since Home is a singleton controller, that’s the show view. Whip up Add views/home/show.haml and dump in Hello World.

    Now I need a route. In the new Rails 3 routing DSL that’s done by:

    root :to => "home#show"
    

    Lastly, I need to delete public/index.html.

    Hit localhost:3000 and it works!

    Shoulda

    Looks like Shoulda isn’t Rails 3 compatible yet.

    DEPRECATION WARNING: RAILS_ROOT is deprecated! Use Rails.root instead. (called from join at /Users/craig/.bundle/ruby/1.8/bundler/gems/shoulda-b8b6cad61981d47356de06c2a5586e281938c94e-rails3/lib/shoulda/autoload_macros.rb:40)
    /Users/craig/.bundle/ruby/1.8/bundler/gems/shoulda-b8b6cad61981d47356de06c2a5586e281938c94e-rails3/lib/shoulda/autoload_macros.rb:40:in `join': can't convert # into String (TypeError)
    	from /Users/craig/.bundle/ruby/1.8/bundler/gems/shoulda-b8b6cad61981d47356de06c2a5586e281938c94e-rails3/lib/shoulda/autoload_macros.rb:40:in `autoload_macros'
    

    I go to report this bug. Of course, when I register with RailsPlugins, I get this:

    We are sorry to say that something in our code went bang!

    Screw it, I’ll avoid Shoulda in the interim. Instead, I’ll create a regular Test::Unit controller test.


  4. Play-by-Play: Ruby, Rails, and Heroku Versions

    June 4, 2010 by Craig

    First, update to macports 1.8.2.

    Ruby Update

    sudo port install ruby
    

    I’m going to get 1.8.7 p249

    • p249 “has marshaling bugs that crash Rails 3.0.0
    • Get RVM to help manage the versions.
      bash < <( curl http://rvm.beginrescueend.com/releases/rvm-install-head )
      if [[ -s "$HOME/.rvm/scripts/rvm" ]]  ; then source "$HOME/.rvm/scripts/rvm" ; fi
      source ~/.rvm/scripts/rvm
      rvm notes
      

      Add to .profile:

      for profile in .bash_profile .bashrc ; do echo 'if [[ -s "$HOME/.rvm/scripts/rvm" ]]  ; then source "$HOME/.rvm/scripts/rvm" ; fi' >> $HOME/$profile done
      

      Is this necessary? Should it be in .bash_profile? (Probably not as it references .bash_profile). I’m still fairly new to UNIX and so don’t know my profile consequences off by heart.

    I’m not going to get into ruby 1.9 as Rails 3 isn’t stable on 1.9.1 (1.9.2 only) and Heroku only supports 1.9.1.

    Rails 3

    I’m preferring Rails 3 as:

    • It’s definitely the way of the future.
      • There’s quite a few new APIs — meaning old ones will be abandoned. Rails doesn’t sit still.
      • The API appears to be improved all the way around; it’s more fun to use.
    • It should be stable & released by the time I’m ready to launch.

    But which ruby version should I be using? All seem to have potential for issues. I’ll run 1.8.7@249 and see if it works.

    Rubygems

    RubyGems update, attempt 1:

     gem update --system
     Updating RubyGems
     /opt/local/lib/ruby/site_ruby/1.8/rubygems/spec_fetcher.rb:245: [BUG] Segmentation fault
     ruby 1.8.7 (2010-01-10 patchlevel 249) [i686-darwin9]
    Abort trap
    

    I didn’t sudo, and it gave me a segfault instead of a real error 🙁
    Attempt #2, this time with sudo:

     sudo gem update --system
    Password:
    Updating RubyGems
    Updating rubygems-update
    Successfully installed rubygems-update-1.3.7
    Updating RubyGems to 1.3.7
    Installing RubyGems 1.3.7
    RubyGems 1.3.7 installed
    Successfully uninstalled gemcutter-0.1.6
    Successfully uninstalled gemcutter-0.3.0
    ...
    

    Update Rails

    gem install rails --pre
    ...
    Installing ri documentation for rails-3.0.0.beta3...
    File not found: lib
    

    Found the issue here. How did we ever develop software before Google?
    This might not be a big deal after all.

    Heroku

    I’m going to try Heroku for deployment/hosting.
    First, I need Bundler:

    sudo gem install bundler
    /opt/local/lib/ruby/site_ruby/1.8/rubygems/spec_fetcher.rb:254: warning: getc is obsolete; use STDIN.getc instead
    

    I hate warnings.

    Next is the Heroku gem:

     
    sudo gem install heroku
    

    Time to read up on the Heroku quickstart.


  5. Play-by-Play: Initial Git

    June 3, 2010 by Craig

    Time to set up a GitHub project. Github is, at the very least, a good offsite storage system for the source code.

    cd "/Users/craig/Documents/SoftCraft/projects/bakery/"
    mkdir rails
    cd rails
    touch README
    touch .gitignore
    gitx
    git add .
    git commit -a -m "Initial commit"
    git remote add origin git@github.com:softcraft-development/bakery.git
    git push origin master
    

    And we’re in business!

    Update .git/config with a couple of nice features:

    [alias]
      undo = reset --hard HEAD
      wipe = clean -f -d
    

    While I’m at it, I’ll update my copy of git too.


  6. Play-by-Play: Units of Measurement

    June 2, 2010 by Craig

    Ok, time to get down to coding.

    (Actually, I started coding a month ago. I’ve been keeping a development log since the start; I’m just getting to posting it now.)

    I’ll be dealing with measurements quite a bit for ingredients and nutritionals, so I’ll want a measurement library.
    Google up “Ruby Measurement.”
    ruby-measure looks like what I want, but it’s undocumented. That’s a deal-breaker.

    Google “ruby units of measurement”
    Found ruby-units.
    Its old; last updated Oct 2006. That’s a bad sign.
    (Update: I eventually found the github project; it was last updated in March of 2010.)
    The documentation appears to be OK.
    Can it do density calculations? (Divide mass by volume to get density).
    It looks like it’s worth looking into.


  7. A Joke

    September 26, 2008 by Craig

    Why do computer scientists often confuse Christmas and Halloween?

    Because Oct 31 = Dec 25

    I’m not going to explain this one. If you don’t get it, you’re not going to find it funny anyway. 😛


  8. Stack Overflow

    September 15, 2008 by Craig

    Stack Overflow is a new site that aims to be the Wikipedia of programming questions and topics. It takes the basic concept of a question/answer messageboard on programming topics, adds in voting and wiki-editing, puts a very good user interface on it, and makes it available for free. The result is an excellent site to find solutions to software development problems of all sorts.

    Joel Spolsky is one of the founders; he’s written his own post about the launch.

    I’ve been in the beta for about a month now, and listening to the podcasts since their inception. I’m really impressed with the quality of the site and how well they’ve achieved their goals. Their aim is a lofty one: be the best site on the entire Internet for finding answers to programming questions. Even at this early stage, I think they’ve already accomplished that; it’s now just a matter of time before Google confirms it.

    If you develop software, it’s in your best interest to familiarize yourself with the site and discover its capabilities. As time goes on it could easily become your best resource on the Web for solving tricky problems effectively and efficiently.

    By the way, here’s my user page, for your enjoyment.


  9. .NET Generics and Type Inference Landmine

    May 21, 2008 by Craig

    Let’s say that you have a class that takes a generic type parameter:

    public class Foo<T> {
      public void accept(T someObject) { }
      public void doSomething() { }
    }
    

    It’s difficult to doSomething() to a collection of Foo<T>s when you don’t know what T is and/or there’s multiple types used for T. To work around this, you can create a typeless interface:

    public interface FooTypeless {
      void doSomething();
    }
    

    The declaration of Foo<T> now becomes:

    public class Foo<T> : FooTypeless
    

    Now you can have this method:

    public void doSomethingOnAllFoos(
      IEnumerable<FooTypeless> foos) {
    
      foreach( FooTypeless foo in foos ) { 
        foo.doSomething();
      }
    }
    

    Also, say that you have the following extension method:

    public static IEnumerable<T> toEnumerable<T>(this <T> obj ) {
      // Any IEnumerable implementation should work here; 
      // but we'll get to that in a bit
      return new T[] { obj };
    }
    

    Type inference would let you write this:

    Foo aFoo = new Foo();
    doSomethingOnAllFoos( aFoo.toEnumerable() );
    

    However, this code does not work; you get a compile error:

    cannot convert from ‘System.Collections.Generic.IEnumerable<Foo<string>>’ to ‘System.Collections.Generic.IEnumerable<FooTypeless>’

    This occurs even though Foo<string> inherits from FooTypeless. Even though the generic type parameters are compatible, the generic-enabled reference isn’t, at least according to the compiler. (We humans could probably see that IEnumerable is an interface that could safely be converted, but the existing compiler cannot).

    Now, you can do this:

    IEnumerable<FooTypeless> someFoos 
      = new Foo<String>[] { foo };
    

    …but not this:

    IEnumerable<Foo<String>> someStringFoos 
      = new Foo<String>[] { foo };
    IEnumerable<FooTypeless> someFoos 
      = someStringFoos;
    

    You may be tempted to try casting to work around this. For example, this works:

    IEnumerable<Foo<String>> someStringFoos 
      = new Foo<String>[] { foo };
    IEnumerable<FooTypeless> someFoos 
      = (IEnumerable<FooTypeless>) someStringFoos;
    

    However, this only works if someStringFoos is assigned an array. The following does not work:

    IEnumerable<Foo<String>> someStringFoos 
      = new List<Foo<String>> { foo };
    IEnumerable<FooTypeless> someFoos 
      = (IEnumerable<FooTypeless>) someStringFoos;
    

    If you try this, you’ll get an InvalidCastException. Furthermore, this generates the compiler error:

    IEnumerable<FooTypeless> someFoos 
      = new List<Foo<String>> { foo };
    

    Currently I have no idea why the array works but the List doesn’t; it doesn’t make a lot of sense to me.

    I originally discovered this by using type inference with my toEnumerable() extension method. An easy way around these problems is to avoid the type inference completely and explicitly specify the type of IEnumerable you want:

    Foo<String> aFoo = new Foo<String>();
    doSomethingOnAllFoos( aFoo.toEnumerable<FooTypeless>() );
    

    This works fine, even if toEnumerable() uses a non-array type (such as List) as its IEnumerable implementation. Execution-wise, nothing has changed, but the generic type used in the call can make or break the code.

    Stuff like this starts to make Java’s type erasure look not so ugly in comparison. 😛


  10. Stupid .NET Tricks #13

    by Craig

    In Java, making a field “final” means that you can only assign a value to it once. It’s an important part of making a class immutable. It helps to prevent bugs too: make a field final and you’ll get a compiler error if you leave it unassigned or try to reassign it anywhere.

    .NET has a similar concept with the “readonly” keyword for fields. However, there’s one important difference compared to Java: a “readonly” field can only be assigned in the class’s constructor, but it can be assigned multiple times within that constructor. The only restriction it places is that the field can’t be reassigned outside of the constructor. You don’t even get a compiler error for not assigning it at all; you only get a compiler warning (which can be turned off).

    This has encouraged bugs at least twice in my code: I assigned a value to a field twice within the constructor and then got unexpected results due to the incorrect object being used. One of these was caused by a conflict resolution from a Subversion Merge (and thus it was less-than-obvious that it had been introduced).