29 December 2013

Troubleshooting access on a Captive Network


The Symptomatic Experience

A computer (Mac OS X, 10.7.2-10.7.5) attempts to connect to a public wireless network which requires them to either accept some license/agreement and (potentially) authenticate before granting access to the Internet (e.g. at a coffee shop, Internet cafe, or university guest network).
  • The computer joins the wireless network successfully, but fails to load the "login" page.
  • The browser reports "Establishing secure connection" or the like, but the page fails to load.
Poking around...
  • If the user attempts to launch Keychain, the application fails to load, hanging (beachballs).
  • These symptoms occur when using Safari or Chrome (indeed, any browser that uses WebKit),
  • However, browsers that do not use WebKit (notably, FireFox), seem to work just fine.
  • The symptoms persist until the machine is rebooted.

The Problem

Stating the situation more precisely...
  1. A computer joins a wireless network that's running a captive portal.
    • The network is configured to redirect all attempts to get to the web to a login page to authenticate
    • and because we're authenticating, the redirect is to an https: URL.
  2. As part of the SSL handshake protocol (RFC 6101), the Server provides its certificate to the client.  The client "authenticates" the server, in part by ensuring that the certificate has not been revoked.
  3. The captive portal is not configured to pass through OSCP traffic to known Certificate Authority hosts (which is usually implemented in DER encoding over HTTP).  When the client attempts to check for a certificate revocation, the Captive Portal returns the redirect instead.
    • In Mac OS X, there is an error in this mechanism such that the "Login" keychain becomes corrupted.
Not only can this computer not gain access to the Internet, it now has a corrupt keychain.

Solutions

In my research, here are three solutions offered, in descending order of preference/correctness.

Best Solution: Configure Captive Portal to Pass-Through OCSP Traffic

The most complete solution is for the captive portal to allow OSCP to known hosts.  And example of this configuration is here: http://community.arubanetworks.com/t5/AAA-NAC-Guest-Access-BYOD/OCSP-captive-portal-issues-apple-laptops-amp-firefox/td-p/82456.

Next Best Solution: Explicitly Trust the Certificate of the Captive Portal

If you do not have the ability to modify the captive network configuration, then individual clients can get passed this problem by explicitly trusting the X.509 cert of the captive portal itself.  This would allow the computer to successfully establish an SSL connection to the captive portal and then the user could login.

By doing this, you are assuming that:
  1. you are connecting to the wireless network you are intending to.
  2. you trust that the people running that network are using valid certificates.

Step 1: Download the Captive Portal's Certificate

  1. Visit the captive portal page in Firefox
  2. Select Tools > Page Info > Security > View Certificate > Details > Export
  3. Save the certificate to your hard drive with the extension ".crt"

Step 2: Import the Certificate

If you cannot open Keychain Access because your keychain is corrupted, turn off wireless, delete ~/Library/Keychains/login.keychain and /Library/Keychains/System.keychain, and then reboot.
  1. Open Keychain Access.app
  2. Drag the certificate from Finder into a keychain
  3. Double click on the certificate and expand the "Trust" section
  4. Choose "When using this certificate: Always Trust"
  5. Close the popup window
... then try the login again.

Workaround: Turn Off Certificate Revocation

If, for some reason, you don't want to include the captive network's certificate, you can disable certificate revocation.  However, doing so comes with significant risk.  The whole point of having certificate revocation is to maintain trust.  If you just turn this feature off, then you risk trusting certificates that have been compromised.

To do this, you disable OSCP and CRL before you attempt to connect to the network.

You can either do this in the Keychain App:
  1. Preferences > Certificates
  2. Mark both OSCP and CRL to "Off"
  3. Close the Preferences window (important step as these preferences are not saved until you do)
Or you can change the settings from the command line:
defaults write com.apple.security.revocation CRLStyle -string "None"defaults write com.apple.security.revocation OCSPStyle -string "None"
Once you've completed the login sequence with the captive network, you should re-enable cert revocation checks:
defaults write com.apple.security.revocation CRLStyle -string "BestAttempt"defaults write com.apple.security.revocation OCSPStyle -string "BestAttempt"

Summary

A rather cryptic set of circumstances results when OCSP fails on Mac OS X (Lion) while attempting to gain access to the Internet from a captive portal: a keychain becomes corrupted and further attempts to access it hang (instead of reporting an error).

The best fix is for the captive portal administrator to poke holes in the firewall to allow for OSCP traffic to well-known hosts.  Barring that, the individual computer user can either explicitly download and trust the certificate of the captive portal login; or temporarily disable certificate revocation checking (not advised).

References

15 November 2013

Book Review: Rebuilding Rails

Rebuilding Rails from Noah Gibbs, a self-published eBook, is a guided tour through the internals of Ruby on Rails.  His basic premise is that the best way to get to know a combustion engine is to build one yourself!

Ruby on Rulers

The goal is to pull back the veil and demystify some of the "magic" behind Rails.  We do this by building a web application framework similar to Rails, named "Ruby on Rulers".  By the end of the book, Rulers contains the most fundamental features found in Rails.

As he walks us through the development of Rulers, he shows us how Rails is "merely" a MVC Rack application that takes advantage of the elegant dynamic features of the Ruby language.

In each chapter, Gibbs tackles a core aspect of Rails:

  • the core request/response processing chain
  • how requests are routed to the correct controller
  • how views are rendered
  • how models front for a data source (including discovering attributes and dynamic finders)
In each component, Gibbs leads us through a first-iteration implementation. Of course Ruby on Rails is a far more mature framework with a more sophisticated implementation.  Keeping it simple makes understanding the core of what's going on in Rails accessible.

Sample Source

Chapters begin by motivating the need for the targeted feature.  He then points you to his Github repo that contains sample code, chapter-by-chapter.

In Rails

At the end of each chapter, Gibbs points back to the parts of Ruby on Rails that implement the chapter's feature.  Included are exercises that challenge the reader to go a level deeper in their understanding.

Highlights

A few highlights:
  • Ruby on Rails is a "Rack Application."  Basically, this means that it provides a proc that takes a single argument (a hash named "env" containing both application environment parameters and request-specific parameters) and returns a three-element array: [HTTP return value, HTTP header parameters, the body of the response].  That's it.
  • Routes are "merely" method calls on a Routing object that creates one or more mappings from a regular expression to a controller-and-action pair.  The routing config is Ruby code evaluated directly (in a instance_eval() call).
  • Rails leverages the explicit separation of "message" from "method" in Ruby to dynamically create accessors for attributes on Models.  This simply involves implementing the "method_missing" method on the SQLModel base class which uses schema data to load (and update) attributes that match the name of columns in the table.
  • Providing "context" to ERb templates is a built-in feature of that template library. Controllers provide instance variables to Views by simply enumerating instance variables of the Controller (self.instance_variables.each {...}) and adding them to the template context (which is simply a hash).

The Good and The Bad

Overall, this is a really great resource.  There honestly is no better way to get a deeper understanding of something like Rails than to face down the problems that the authors of that framework did.  Gibbs clearly understands the material and is enthusiastic.

The scope of the book is just right.  Gibbs does a good job of going wide and shallow and not getting stuck in one particular area.  It's an excellent survey.

The book is self-published and it shows.  There are loads of grammar errors.  Much of the narrative is awkward.  In places, Noah attempts to be folksy or conversational in tone and it often falls a bit flat.  Talking people thought the innards of a web framework is not easy.  But this is where editors earn their pay.

In the final chapter, there is actually a missing chunk of code.  The final version of the Rulers::Application class (as it appears in the book, itself) is missing the #call(env) method.  For the engaged reader, this represents an unexpected exercise, but it's a little frustrating.

Throughout the book, the code examples includes some oddly styled code.  Gibbs makes liberal use of single character variables.  This makes the code much more difficult to grok.  Better to have used a smaller font and more verbose identifiers.

From a development approach perspective, I'm disappointed that there were no tests.  In building up something like a framework, having unit tests are not only helpful in showing where the interfaces lie, but also provide a basis for refactoring and adding new features with confidence.  There were some significant chunks of code that one is expected to key in without error.  Gibbs never promised to include tests, it's just something I felt like was really missing.

The exercises at the end of each chapter are really fantastic.  They are challenging!  And in being this way, it really helps the reader deepen their understanding.  You won't be able to just gloss your way over them.  He explains what you should do, but only hints at how it should be accomplished.  

Conclusion

All-in-all, Gibbs delivers.  This is a really great book; truly a labor of love.  $39.99 is a little steep given the lack of fit-and-finish.  That said, I'm really glad that I went through this book and grateful for the deeper understanding of how Rails works, under the covers.

27 October 2013

Needed to update OpenSSL Certificates as part of Ruby 2.0.0 install

[for some reason], when RVM installs Ruby 2.0.0 (MRI), it fails on dated certificates.  There's a simple fix, thanks to Michal Papis (currently from Engine Yard) for the fix and Daniel Kehoe (from the RailsApps Project) for pushing for a solution.

john@Slick:cliffschat [517]$ rvm install 2.0.0
Searching for binary rubies, this might take some time.
Checking requirements for osx.
Updating certificates in '/opt/local/etc/openssl/cert.pem'.
john password required for '/usr/bin/env PATH=/opt/local/bin:/Users/john/.rvm/gems/ruby-1.9.3-p448@chatter/bin:/Users/john/.rvm/gems/ruby-1.9.3-p448@global/bin:/Users/john/.rvm/rubies/ruby-1.9.3-p448/bin:/Users/john/.rvm/bin:/opt/local/sbin:/usr/local/heroku/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin:/Users/john/development/tools/apache-maven-3.0.4/bin:/Users/john/development/tools/sonar-runner-2.0/bin:/sbin:/usr/sbin:/usr/local/sbin mv -f /var/folders/by/fy0sbzy52xx8c23sgrd5n6t80000gn/T//tmp.zqrm6ETIUqreSbsocw /opt/local/etc/openssl/cert.pem': 

Not sure why, but RVM appears to be updating my OpenSSL certificate...

An explanation from Daniel Kehoe:

What is Happening

When creating a new Rails application, the Ruby language interpreter uses OpenSSL to connect to https://rubygems.org/. The Gemfile installed by the rails new command specifies https://rubygems.org/ as the source for gems and requires an SSL connection.
In the case of a new application generated from an application template hosted on GitHub, the Ruby language interpreter uses OpenSSL to connect to GitHub. GitHub requires all connections to be made using SSL.
The error message indicates the connection failed because OpenSSL was unable to verify the server certificate.
If you are seeing an error when you create a new Rails application, it is likely that you need to update OpenSSL certificate files on your computer. Users of older versions of Mac OS X and Ubuntu operating systems are likely to see these errors.
Check RubyGems issues on GitHub and look for recent updates to the issue SSL_connect failure when running ‘rails new’. You may find more information on Stack Overflow, especially this discussion: Bundle install fails with SSL certificate verification error. And please read thecomments below.




john@Slick:cliffschat [522]$ rvm osx-ssl-certs status all
Certificates for /System/Library/OpenSSL/cert.pem: Old.
Certificates for /opt/local/etc/openssl/cert.pem: Old.

john@Slick:cliffschat [523]$ rvm osx-ssl-certs update all
Updating certificates for /System/Library/OpenSSL/cert.pem: Updating certificates in '/System/Library/OpenSSL/cert.pem'.
Updated.
Updating certificates for /opt/local/etc/openssl/cert.pem: Updating certificates in '/opt/local/etc/openssl/cert.pem'.
Updated.

john@Slick:cliffschat [528]$ rvm install 2.0.0
Searching for binary rubies, this might take some time.
Found remote file https://rvm.io/binaries/osx/10.7/x86_64/ruby-2.0.0-p247.tar.bz2
Checking requirements for osx.
Certificates in '/opt/local/etc/openssl/cert.pem' already are up to date.
Requirements installation successful.
ruby-2.0.0-p247 - #configure
ruby-2.0.0-p247 - #download
#######################################################################   99.7%
ruby-2.0.0-p247 - #validate archive
ruby-2.0.0-p247 - #extract
ruby-2.0.0-p247 - #validate binary
ruby-2.0.0-p247 - #setup
Saving wrappers to '/Users/john/.rvm/wrappers/ruby-2.0.0-p247'........
ruby-2.0.0-p247 - #importing default gemsets, this may take time..........................

john@Slick:cliffschat [532]$ rvm --default use 2.0.0
Using /Users/john/.rvm/gems/ruby-2.0.0-p247

john@Slick:cliffschat [533]$ ruby -v
ruby 2.0.0p247 (2013-06-27 revision 41674) [x86_64-darwin12.5.0]

Voila!

25 October 2013

Great Article: class_eval and define_method, @tenderlove'd

Heard that Ruby is slow?  Heard that metaprogramming is slower?  They can be and it's up to you, developer, to make informed choices.

Aaron Patterson (@tenderlove) switched over the attribute class feature of ActiveSupport to use define_method rather than class_eval [git commit].  In it, he cites that doing so would "drop memory consumption and (increase) startup speed..."

This is of particular noteworthiness because, actually, this particular feature started out life using define_method.  And then circa 2009, Yehuda Katz specifically rewrote the code to use the class_eval style, noting that the class_eval was much easier to comprehend (agreed).  When someone says, "Yehuda Katz", think, "smart and prolific" [github].  So, reverting this work was no small move.

Unfortunately, Mr. Patterson didn't leave a crumb as to what led him to the performance difference conclusion.  So, I did a little digging.  Turns out, this is something that Aaron learned around March of this year (i.e. 2013).  And this is the main thing I want to direct your attention to: tenderlove's treatment of the topic:
http://tenderlovemaking.com/2013/03/03/dynamic_method_definitions.html
In it, Aaron carefully walks through, step by step, how to compare and detect the causes of the performance differences.  Along the way, I was introduced to a number of very helpful tools:

In his examination, Aaron is not satisfied with the performance of method definition, but digs into the performance of the dynamically generated methods, themselves (who might have thunk they'd be that different?).  Lots to learn from this:
  1. some mechanics of performance tuning in Ruby.
  2. how to write a high-signal blog post.  (great code-to-prose ratio, did I mention that?)
  3. ways to contribute to Open Source in addition to cutting code: help others level up.
Thank you, @tenderlove!


My teeny tiny OSS contribution?  I commented on Aaron's github commit with a link to his own blog post. :)

23 October 2013

Test-Driven Metaprogramming, by Example

If you've been following along in my blog, you'll know that the study group I attend is currently working our way through the Rebuilding Rails book, together.  In chapter 7, we tackle the meaty subject of ActiveRecord.  This one area where the metaprogramming facilities of Ruby really shine.

I wanted to tackle this work using Test-Driven Development.  There were some interesting challenges when it came to some required metaprogramming.  I learned a lot through the process.

The Story So Far...

Guided along by Noah's narrative, we have developed a core class called SQLiteModel — an ActiveRecord pattern implementation.  Application programmers would subclass for their concrete models and use the base functionality to find, create, update, and delete.  Each instance of this class corresponds directly to a row in the database.

Trimmed down (and mostly folded), here's the outline of the class, so far:

class SQLiteModel
  def self.connect(path_to_db)
    @db = SQLite3::Database.new path_to_db
    @dialect = SQLiteDialect.new table, schema
  end
  def self.table...
  def self.schema...
  def self.create(values)...
  def self.find_by_id(id)...
  def self.count...
  def [](attribute)...
  def []=(attribute, new_value)...
# def save
#   update_sql = @dialect.sql_for_update @values
#   @db.execute update_sql
# end
end
Listing 1 — sqlite_model.rb @ 3ae4ce6e7c.  Just as I tried to implement an instance method that wanted to access a metaclass variable.

As you can see, we can connect to a database, determine the name of the table that backs this specific SQLiteModel type, obtain schema information, insert new records, find records by id, find out how records there are and get/set values of individual rows.

(The experienced observer will note that @db and @dialect are not instance variables (i.e. variables specific to each instance of SQLiteModel).  You can tell because they are declared within a singleton method.  Therefore they are class variables.)

Things were going great!  However, when it came time to provide individual instances of SQLiteModel (i.e. objects that represent individual rows in the underlying table) with the ability to save changes, we hit a wall...

Accessing Singleton Class Instance Variables in Direct Instance Methods

# def save
#   update_sql = @dialect.sql_for_update @values
#   @db.execute update_sql
# end
Listing 2 — In sqlite_model.rb, the save() method.  This implementation won't work because @dialect and @db are instance variables on SQLiteModel's singleton class, not variables on individual instances. 

The problem here is that I want to access two variables defined at the class level: "@dialect" and "@db".

"A wall?!" my pair might say, "but all you have to do is provide an attribute reader on the singleton class and then call that reader."

"huh?," I would exclaim with a puzzled look on my face.  To which my partner would turn to the editor and write this:

class SQLiteModel
  def self.connect(path_to_db)
    @db = SQLite3::Database.new path_to_db
    @dialect = SQLiteDialect.new table, schema
  end
  
  def self.dialect
    @dialect
  end
  
  def self.db
    @db
  end

  ...
  
  def save
    update_sql = self.class.dialect.sql_for_update @values
    self.class.db.execute update_sql
  end
end
Listing 3 — In sqlite_model.rb, a straight-forward way for instances to access class singleton variables.

"ooooohhh!" I'd say, slapping my forehead.  But then we'd sit there and stair at those last two executable lines, trying not to think about how the "self.class." phrase would liter the codebase.  On the one-hand, rather literal ("my class' dialect attribute") but also perhaps a bit verbose (especially when repeated everywhere?).

The Essential Challenge

In effect we have discovered a new1 desired feature from the language.  Namely, in the same way that we can declare instance attributes (via attr_reader, attr_writer, or attr_accessor) that we would like to be able to declare a class attributes that is inherited by subclasses and accessible by instances.  Ruby is so pliable, we can actually add this feature to the language (and the Rails core team do so.  Here's a description of the feature: http://guides.rubyonrails.org/active_support_core_extensions.html#class-attributes )

So as to give credit where it's due, I had no idea of how that would be implemented.  Had I not had a working example in Rails (namely, https://github.com/rails/rails/blob/3-2-stable/activesupport/lib/active_support/core_ext/class/attribute.rb), at this point, I'd would have some spike work to do, personally.  But I'm lazy and so I read their code. :)

The Code

What follows is a test-driven approach to implementing class_attribute.  I originally did this in the following series of commits: https://github.com/jtigger/ruby-on-rulers/compare/3ae4ce6e7cc770dcf30fd645e340e81d560f28fc...7297d58f0a8d1a90a51d09653f654a47349110d7

Step 1: Setup and Teardown

In the first step, I had to discover how to clean-up class definitions so that the results of the unit tests were independent of each other.  Lee Jarvis posted a helpful technique to do this on Stackoverflow.  Here's how we do it in our unit tests...

class ClassExtTest < Test::Unit::TestCase
  def setup
    TestClasses.module_eval "class Foo; end"
    @foo = TestClasses::Foo.new
  end
  
  def teardown
    TestClasses.send(:remove_const, "Bar")
    TestClasses.send(:remove_const, "Foo")
  end
...
end
Listing 4 — A class definition can be "deleted" by calling remove_const on the containing module.

Step 2: Add Attribute Reader

And the next natural step is to begin using the class macro.  We create a private namespace (we'll call it TestClasses).

module TestClasses
end

class ClassExtTest < Test::Unit::TestCase
  ...  
  def test_class_attribute__creates_variable_reader_on_base_class
    TestClasses::Foo.class_eval "class_attribute :ree"
    assert_nil TestClasses::Foo.ree
  end
  ...
end
Listing 5 — the first test case.

which sets us up with the simplest thing that could possibly work:

class Class
  def class_attribute(attr)
    define_singleton_method(attr) { nil }
  end
end
Listing 6 — Monkey patching Class.  At first, we're just getting the attribute reader on the class.

We run it and the tests pass.  So far, so good. (git commit of steps 1 & 2)

Step 3: Verify the Class Attribute is Inherited 


class ClassExtTest < Test::Unit::TestCase
  def setup
    TestClasses.module_eval "class Foo; end"
    @foo = TestClasses::Foo.new
    TestClasses.module_eval "class Bar < Foo; end"
    @bar = TestClasses::Bar.new
  end
  ...
  def test_class_attribute__creates_variable_reader_on_subclass
    TestClasses::Foo.class_eval "class_attribute :ree"
    assert_nil TestClasses::Bar.ree
  end
  ...
end
Listing 7 — the second test case.

This one comes for free since public and protected methods defined on base classes are inherited by their subclasses.


Step 4: Add Attribute Writer

Building on what we've constructed thus far, we can both drive the ability to assign values to the class attribute and verify that it works for subclasses.

class ClassExtTest < Test::Unit::TestCase
  ...
  def test_class_attribute__GIVEN_subclass_has_no_value_defined_THEN_assignments_to_variable_applies_to_both_base_class_and_subclass
    TestClasses::Foo.class_eval "class_attribute :ree"
  
    TestClasses::Foo.ree = 42
  
    assert_equal 42, TestClasses::Foo.ree, "assignment failed for the base class"
    assert_equal 42, TestClasses::Bar.ree, "assignment worked for the base class, but not the subclass"
  end
  ...
end
Listing 8 — the third test case

However, as I got started down the road of implementing the assignment, I realized that I wanted to have the ability to remove methods (regardless of visibility):

class Class
  def class_attribute(attr)
    define_singleton_method(attr) { nil }
    
    # the writer simply redefines the reader
    define_singleton_method("#{attr}=") do |new_value|
      singleton_class.class_eval do
        # TODO: if "attr" is already defined, remove it...
        define_method(attr) { new_value }
      end
    end
  end
end
Listing 9 — I want to remove any existing definition of the writer method before redefining it.

Detour: Cleanly Removing Existing Methods

Out of the box, Ruby's Module class has a "undef_method", but if you call it for a method that does not exist, it raises an exception.  So, we'd like to check first that the method, in fact, exists; and if so, remove it.  But Module::method_defined?() only matches on public and protected methods, so to be thorough, we'd want to also call Module::private_method_defined?().  Not only is this getting a little complicated, but this is very likely something we'll be doing again and again.

So, I detoured: commented out the test in Listing 8, and set out to test-drive a method that would do just this...

class ModuleExtTest < Test::Unit::TestCase
  def setup
    TestClasses.module_eval "class Foo; end"
    @foo = TestClasses::Foo.new
  end
  
  def teardown
    @foo = nil
    TestClasses.send(:remove_const, "Foo")
  end
  
  def test_GIVEN_a_method_is_defined_on_a_module_THEN_remove_possible_method_undefines_it
    TestClasses::Foo.class_eval do
      public; def public_bar; nil; end
      protected; def protected_bar; nil; end
      private; def _private_bar; nil; end
    end
    
    assert TestClasses::Foo.method_defined?(:public_bar)
    assert TestClasses::Foo.method_defined?(:protected_bar)
    assert TestClasses::Foo.private_method_defined?(:_private_bar)
    
    TestClasses::Foo.class_eval do
      remove_possible_method :public_bar
      remove_possible_method :protected_bar
      remove_possible_method :_private_bar
    end
    
    assert !TestClasses::Foo.method_defined?(:public_bar), "expected method 'public_bar' to be removed, but it's still there."
    assert !TestClasses::Foo.method_defined?(:protected_bar), "expected method 'protected_bar' to be removed, but it's still there."
    assert !TestClasses::Foo.private_method_defined?(:_private_bar), "expected method '_private_bar' to be removed, but it's still there."
  end
  
  def test_GIVEN_a_method_is_NOT_defined_on_a_module_THEN_remove_possible_method_quietly_ignores
    TestClasses::Foo.class_eval do
      def ree
      end
    end
    foo = TestClasses::Foo.new
    assert !foo.respond_to?(:bar)
    
    TestClasses::Foo.class_eval do
      remove_possible_method :bar
    end
    
    assert !foo.respond_to?(:bar), "expected method 'bar' to be removed, but it's still there."
  end
end
Listing 10 — Specification of the "remove_possible_method" method.

Which, over the two iterations (we define and drive to one test at a time), yielded this monkey patch on Module:

class Module
  def remove_possible_method(name)
    if method_defined?(name) || private_method_defined?(name)
      undef_method(name)
    end
  end
end
Listing 11 — Adding remove_possible_method to Module.

With that new capability under our belts, we can now satisfy our attribute writer test (detour is captured in this commit: https://github.com/jtigger/ruby-on-rulers/commit/e3d24887128de2f1568011ce136e907807c44e9d):

class Class
  def class_attribute(attr)
    # define the reader
    define_singleton_method(attr) { nil }
    
    # the writer simply redefines the reader
    define_singleton_method("#{attr}=") do |new_value|
      
      singleton_class.class_eval do
        remove_possible_method(attr)
        define_method(attr) { new_value }
      end
    end
  end
end
Listing 12 — the first useful implementation of class_attribute.

Step 5: Ensure Writer Affects the Target Class Only

With all my current tests passing green, now is a good time to make sure we cover other highly important cases.  The most obvious one being to ensure that subclasses can override the value set in their super classes:

class ClassExtTest < Test::Unit::TestCase
  ...
  def test_class_attribute__GIVEN_subclass_HAS_a_value_defined_THEN_assignments_to_variable_applies_to_only_subclass
    TestClasses::Foo.class_eval "class_attribute :ree"
    
    TestClasses::Foo.ree = 42
    TestClasses::Bar.ree = 157
    
    assert_equal 42, TestClasses::Foo.ree, "assignment failed for the base class"
    assert_equal 157, TestClasses::Bar.ree, "assignment worked for the base class, but not the subclass"
  end
  ...
end
Listing 13 — An important use-case: assigning a value to the class attribute in the subclass.

As it turns out, this is how the implementation works, but it's lovely to make this fact plain and verifiable in a test.

Meanwhile... Back at the Ranch

And now we have just added a new feature to Ruby: the ability to define an attribute on a class that is inherited by subclasses and visible to direct instances.  Returning back to our original goal, now we can simply declare "db" and "schema" as class attributes...

class SQLiteModel
  class_attribute :db
  class_attribute :dialect
  
  def self.connect(path_to_db)
    self.db = SQLite3::Database.new path_to_db
    self.dialect = SQLiteDialect.new table, schema
  end
  ...
  def save
    update_sql = dialect.sql_for_update @values
    db.execute update_sql
  end
  ...
end
Listing 14 — SQLiteModel @ dcd61e9b8a5.  Class attributes simplify the syntax in this simplest case.  Not illustrated are the capabilities of subclasses to set their own value for these attributes.

And the syntax for using them is simplified.  That alone is almost reason to invest in this feature.  But there's more.  Even with the minimal implementation we did, here, subclasses of SQLiteModel can simply set their own value, overriding that for themselves.  This means Models default to sharing a DB connection, but can have different DB connections, if desired; same is true for dialect.

The story isn't over...

This is the starting point, not the conclusion.  In fact, there are a number of cases that we'll likely want to cover:
  • what about singleton classes?  does this code work properly if the class being decorated is one of those?
  • what about direct instances?  would it be useful for individual instances to also override the value for themselves (while allowing all the rest of the instances to continue to use the class-level value)?
  • since this is close to core language modification, perhaps we should be providing a means of determining if an instance has such an attribute (known as instance predicate methods).

Cheers!




1 Actually, this is a feature that Rails implements called "class_attribute".  This implementation has been all but lifted from their code (link at the bottom of the article.

20 October 2013

A Sliver of Ruby #4: The Ruby Language Specification — Objects and Classes

Having a rigorous language for describing the features of Ruby can be incredibly helpful, especially when reasoning metaprogramming code.

Such a rigorous definition exists and is defined in the Ruby Language Specification (published by the Japanese Information-technology Promotion Agency [IPA] in August, 2010).

At the core of the language are two fundamental concepts: objects and classes.

Here is a summary of their characteristics, capabilities and relationships:
  • everything in Ruby is an object (almost)1, even primitives and classes are objects.
  • objects have instance variables which hold that objects state (these bindings are always private).
  • there is a special kind of object known as a class.
    • classes (as an object) can have instance variables.
    • classes (and only classes) can also have constants.
    • classes (and only classes) can also have class variables.
    • classes (and only classes) also have methods which determine their behavior.
    • a class has one direct superclass.
  • classes have an associated collection of objects called direct instances.
    • direct instances have instance variables (but no other kind of variable binding)
    • direct instances obtain their behavior from their class; methods are never bound to them directly.
  • a class' instance variable is that class' own private state; whereas a class' class variables are state shared among the family of objects of that class (i.e. all subclasses and their direct instances).
  • there is a special kind of class known as a singleton class.
    • a singleton class is itself an object.
    • a singleton class is always associated with some other object.
      • the way this works is that the singleton class is inserted in between the object and its class.  E.g. if foo is a direct instance of Foo, then when an a singleton class is associated with foo, foo becomes a direct instance of that singleton class and that singleton class is a subclass of Foo.
    • In this association, then, the singleton class gets first crack at providing the behavior for that object.
      • this is how direct instances appear to have methods defined on them; that behavior is provided by the singleton class.
      • this is also how classes appear to have "class level methods"; these are merely methods defined on the singleton class for the given class.  In fact, this case is so common, that when a class is created, it comes complete with a singleton class, already.



1 — operators, blocks, and methods are not objects; although the last two can be wrapped in objects  (see also: http://stackoverflow.com/a/416154

06 October 2013

Moving a ClearCase Remote Client View

The ClearCase Remote Client Eclipse plugin does not include a feature to move a view (CC's term for a local working copy or checkout).  Thankfully, relocating a view is not difficult.

I ran into this problem, yesterday.  I joined a CC "project" which effectively means that I create two new streams and a view on each.  I'm on a windows machine for this work and I wanted to put my views close to the root of the drive.  I updated the path of my development stream, but forgot to do the same of my integration stream.

I had:

c:\clearcase\userj_proj1-v1
c:\Documents and Settings\userj\workspace\userj-proj1-v1_int

So I wanted to move that second view so that it becomes a sibling of the first.

Moving a ClearCase View

Turns out, it's two simple steps:

  1. Exit out of Eclipse/CCRC
  2. move the subtree to the new location in the file system,
  3. edit the .ccase_wvreg file (found in your user home directory) and update the path location.
  4. Restart Eclipse/CCRC.
In my case, .ccase_wvreg is located at c:\Documents and Settings\userj. It's merely a list of paths.

Reference

04 October 2013

Adventures In Native Extensions

It seemed like an innocent enough thing to do: install a gem.  But woe to the developer who assumes simplicity in a minefield of complexity!

I've reached Chapter 7 in "Rebuilding Rails" and it's been a fabulous ride, so far!  If you're an advanced beginning or competent Rails developer, going through Noah's guide is a wonderful way to deepen your understanding of what's really going on.

Anywho...

Attempt #1: gem install ... easy peazy! ... right?!

There I was, getting ready to start cutting code against the sqlite3 gem.  The next step was simply installing the gem.  Easy enough...

I simply added the gem to my project's gemspec:

<project-home>/rulers.gemspec:
# coding: utf-8
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'rulers/version'

Gem::Specification.new do |spec|
  spec.name          = "rulers"
  spec.version       = Rulers::VERSION
  spec.authors       = ["John S. Ryan"]

...

  spec.add_runtime_dependency "sqlite3"
end

and ran bundle install...

john@Slick:ruby-on-rulers (master) [1345]$ bundle install
Fetching gem metadata from https://rubygems.org/..........
Fetching gem metadata from https://rubygems.org/..
Resolving dependencies...
Using rake (10.1.0) 
Using bundler (1.3.5) 
Using erubis (2.7.0) 
Using multi_json (1.8.0) 
Using rack (1.5.2) 
Using rack-test (0.6.2) 
Using require_all (1.3.1) 
Installing sqlite3 (1.3.8) 
Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension.

        /Users/john/.rvm/rubies/ruby-1.9.2-p290/bin/ruby extconf.rb 
checking for sqlite3.h... *** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of
necessary libraries and/or headers.  Check the mkmf.log file for more
details.  You may need configuration options.

Provided configuration options:
  .
  .
  .
/Users/john/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/mkmf.rb:368:in `try_do': The complier failed to generate an executable file. (RuntimeError)
You have to install development tools first.
  from /Users/john/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/mkmf.rb:452:in `try_cpp'
  from /Users/john/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/mkmf.rb:853:in `block in find_header'
  from /Users/john/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/mkmf.rb:693:in `block in checking_for'
  from /Users/john/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/mkmf.rb:280:in `block (2 levels) in postpone'
  from /Users/john/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/mkmf.rb:254:in `open'
  from /Users/john/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/mkmf.rb:280:in `block in postpone'
  from /Users/john/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/mkmf.rb:254:in `open'
  from /Users/john/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/mkmf.rb:276:in `postpone'
  from /Users/john/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/mkmf.rb:692:in `checking_for'
  from /Users/john/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/mkmf.rb:852:in `find_header'
  from extconf.rb:34:in `<main>'


Gem files will remain installed in /Users/john/.rvm/gems/ruby-1.9.2-p290@rulers/gems/sqlite3-1.3.8 for inspection.
Results logged to /Users/john/.rvm/gems/ruby-1.9.2-p290@rulers/gems/sqlite3-1.3.8/ext/sqlite3/gem_make.out

An error occurred while installing sqlite3 (1.3.8), and Bundler cannot continue.
Make sure that `gem install sqlite3 -v '1.3.8'` succeeds before bundling.


Native Extensions

If you're new to the Ruby environment, you might not yet be familiar with the fact that Ruby has native extensions.  Native extensions are pieces of code (written in C and compiled to shared libraries) that either need to run much faster than Ruby can be interpreted or needs access to OS resources not available directly through the Ruby VM.

For more details, find this gentle yet informative treatment here: http://patshaughnessy.net/2011/10/31/dont-be-terrified-of-building-native-extensions

What Happened?

Back to the output of our first attempt.  When encountering this output for the first time, it can be rather hard to read.  But I've highlighted some important elements for ya...

Three key clues:

  1. there's an additional log file that might have the next level of details: mkmf.log
  2. it's the extconf.rb script that failed (which, if you read that link in the previous section, you'd know that it's responsible for generating the Makefile) which means that some system dependency wasn't satisfied (e.g. a missing C header file or a build tool).
  3. the causing symptom is "...install development tools first."  (and "development tools" on Mac OS X, that's the Xcode command-line tools).

First, was somehow finding that mkmf.log.  I searched from the root of the RVM ruby I'm using:

$ find /Users/john/.rvm/rubies/ruby-1.9.2-p290 -name mkmf.log

At first glance, I didn't see anything that jumped out at me as a problem.

Xcode / extconf.rb Out of Sync

But then I googled it and stumbled into what  Dave Isaacs reported that in some versions of Xcode, the gcc compiler had a new prefix: llvm-gcc-4.2... and that the Ruby extensions configurator (extconf.rb) is using the old name gcc-4.2:  http://stackoverflow.com/a/10458609/1190801 (who rightfully credited Michael Cohen: http://frozencanuck.wordpress.com/tag/extconf-rb/ ).

I added the symlink which resolved that problem...

$ sudo ln -s /usr/bin/{llvm-,}gcc-4.2

Sidebar: that's a fun little bit of globbing.  it expands into:

$ sudo ln -s /usr/bin/llbm-gcc-4.2 gcc-4.2

Cool, eh?  :)


Attempt #2: Missing Libraries

With the symlink in place, I tried again...

john@Slick:ruby-on-rulers (master) [1360]$ bundle install
Fetching gem metadata from https://rubygems.org/..........
Fetching gem metadata from https://rubygems.org/..
Resolving dependencies...
Using rake (10.1.0) 
Using bundler (1.3.5) 
Using erubis (2.7.0) 
Using multi_json (1.8.0) 
Using rack (1.5.2) 
Using rack-test (0.6.2) 
Using require_all (1.3.1) 
Installing sqlite3 (1.3.8) 
Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension.

        /Users/john/.rvm/rubies/ruby-1.9.2-p290/bin/ruby extconf.rb 
checking for sqlite3.h... yes
checking for sqlite3_libversion_number() in -lsqlite3... yes
checking for rb_proc_arity()... yes
checking for sqlite3_initialize()... yes
checking for sqlite3_backup_init()... yes
checking for sqlite3_column_database_name()... no
checking for sqlite3_enable_load_extension()... no
checking for sqlite3_load_extension()... no
checking for sqlite3_open_v2()... yes
checking for sqlite3_prepare_v2()... yes
checking for sqlite3_int64 in sqlite3.h... yes
checking for sqlite3_uint64 in sqlite3.h... yes
creating Makefile

make
/usr/bin/gcc-4.2 -I. -I/Users/john/.rvm/rubies/ruby-1.9.2-p290/include/ruby-1.9.1/x86_64-darwin10.8.0 -I/Users/john/.rvm/rubies/ruby-1.9.2-p290/include/ruby-1.9.1/ruby/backward -I/Users/john/.rvm/rubies/ruby-1.9.2-p290/include/ruby-1.9.1 -I. -DHAVE_RB_PROC_ARITY -DHAVE_SQLITE3_INITIALIZE -DHAVE_SQLITE3_BACKUP_INIT -DHAVE_SQLITE3_OPEN_V2 -DHAVE_SQLITE3_PREPARE_V2 -DHAVE_TYPE_SQLITE3_INT64 -DHAVE_TYPE_SQLITE3_UINT64 -I/Users/john/.rvm/usr/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE   -fno-common -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long  -fno-common -pipe  -o backup.o -c backup.c
/usr/bin/gcc-4.2 -I. -I/Users/john/.rvm/rubies/ruby-1.9.2-p290/include/ruby-1.9.1/x86_64-darwin10.8.0 -I/Users/john/.rvm/rubies/ruby-1.9.2-p290/include/ruby-1.9.1/ruby/backward -I/Users/john/.rvm/rubies/ruby-1.9.2-p290/include/ruby-1.9.1 -I. -DHAVE_RB_PROC_ARITY -DHAVE_SQLITE3_INITIALIZE -DHAVE_SQLITE3_BACKUP_INIT -DHAVE_SQLITE3_OPEN_V2 -DHAVE_SQLITE3_PREPARE_V2 -DHAVE_TYPE_SQLITE3_INT64 -DHAVE_TYPE_SQLITE3_UINT64 -I/Users/john/.rvm/usr/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE   -fno-common -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long  -fno-common -pipe  -o database.o -c database.c
/usr/bin/gcc-4.2 -I. -I/Users/john/.rvm/rubies/ruby-1.9.2-p290/include/ruby-1.9.1/x86_64-darwin10.8.0 -I/Users/john/.rvm/rubies/ruby-1.9.2-p290/include/ruby-1.9.1/ruby/backward -I/Users/john/.rvm/rubies/ruby-1.9.2-p290/include/ruby-1.9.1 -I. -DHAVE_RB_PROC_ARITY -DHAVE_SQLITE3_INITIALIZE -DHAVE_SQLITE3_BACKUP_INIT -DHAVE_SQLITE3_OPEN_V2 -DHAVE_SQLITE3_PREPARE_V2 -DHAVE_TYPE_SQLITE3_INT64 -DHAVE_TYPE_SQLITE3_UINT64 -I/Users/john/.rvm/usr/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE   -fno-common -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long  -fno-common -pipe  -o exception.o -c exception.c
/usr/bin/gcc-4.2 -I. -I/Users/john/.rvm/rubies/ruby-1.9.2-p290/include/ruby-1.9.1/x86_64-darwin10.8.0 -I/Users/john/.rvm/rubies/ruby-1.9.2-p290/include/ruby-1.9.1/ruby/backward -I/Users/john/.rvm/rubies/ruby-1.9.2-p290/include/ruby-1.9.1 -I. -DHAVE_RB_PROC_ARITY -DHAVE_SQLITE3_INITIALIZE -DHAVE_SQLITE3_BACKUP_INIT -DHAVE_SQLITE3_OPEN_V2 -DHAVE_SQLITE3_PREPARE_V2 -DHAVE_TYPE_SQLITE3_INT64 -DHAVE_TYPE_SQLITE3_UINT64 -I/Users/john/.rvm/usr/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE   -fno-common -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long  -fno-common -pipe  -o sqlite3.o -c sqlite3.c
/usr/bin/gcc-4.2 -I. -I/Users/john/.rvm/rubies/ruby-1.9.2-p290/include/ruby-1.9.1/x86_64-darwin10.8.0 -I/Users/john/.rvm/rubies/ruby-1.9.2-p290/include/ruby-1.9.1/ruby/backward -I/Users/john/.rvm/rubies/ruby-1.9.2-p290/include/ruby-1.9.1 -I. -DHAVE_RB_PROC_ARITY -DHAVE_SQLITE3_INITIALIZE -DHAVE_SQLITE3_BACKUP_INIT -DHAVE_SQLITE3_OPEN_V2 -DHAVE_SQLITE3_PREPARE_V2 -DHAVE_TYPE_SQLITE3_INT64 -DHAVE_TYPE_SQLITE3_UINT64 -I/Users/john/.rvm/usr/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE   -fno-common -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long  -fno-common -pipe  -o statement.o -c statement.c
/usr/bin/gcc-4.2 -dynamic -bundle -o sqlite3_native.bundle backup.o database.o exception.o sqlite3.o statement.o -L. -L/Users/john/.rvm/rubies/ruby-1.9.2-p290/lib -L/Users/john/.rvm/usr/lib -L. -L/usr/local/lib -Wl,-undefined,dynamic_lookup -Wl,-multiply_defined,suppress -Wl,-flat_namespace  -lruby.1.9.1 -lsqlite3  -lpthread -ldl -lobjc 


make install
make: /opt/local/bin/gmkdir: No such file or directory
make: [/Users/john/.rvm/gems/ruby-1.9.2-p290@rulers/gems/sqlite3-1.3.8/lib/sqlite3/sqlite3_native.bundle] Error 1 (ignored)
/opt/local/bin/ginstall -c -m 0755 sqlite3_native.bundle /Users/john/.rvm/gems/ruby-1.9.2-p290@rulers/gems/sqlite3-1.3.8/lib/sqlite3
make: /opt/local/bin/ginstall: No such file or directory
make: *** [/Users/john/.rvm/gems/ruby-1.9.2-p290@rulers/gems/sqlite3-1.3.8/lib/sqlite3/sqlite3_native.bundle] Error 1

Gem files will remain installed in /Users/john/.rvm/gems/ruby-1.9.2-p290@rulers/gems/sqlite3-1.3.8 for inspection.
Results logged to /Users/john/.rvm/gems/ruby-1.9.2-p290@rulers/gems/sqlite3-1.3.8/ext/sqlite3/gem_make.out

An error occurred while installing sqlite3 (1.3.8), and Bundler cannot continue.
Make sure that `gem install sqlite3 -v '1.3.8'` succeeds before bundling.


Notice that extconf.rb succeeded, this time (green section).  And that the compilation even succeeded (cyan section).

Things started going wrong during the install step.  Specifically, two command-line tools are missing: /opt/local/bin/gmkdir and /opt/local/bin/ginstall.  I checked and sure enough, those files didn't exist on my machine.  What are they?  Where would I get them?

More Googling...

Installing coreutils

...I learned that gmkdir and ginstall are part of a package called coreutils.  Which turns out to be a pretty fundamental package that includes a whole bunch of GNU style tools for BSD-based Unix systems (and Darwin is a BSD variant).

http://thoughtsthatleakedout.blogspot.com/2011/10/problem-with-gmkdir-when-updating-gems.html

... and I took a wild guessed that this was the same package on MacPorts...

https://lists.macosforge.org/pipermail/macports-users/2010-September/022031.html

So, I installed coreutils...

john@Slick:.rvm [507]$ sudo port install coreutils
Password:
--->  Computing dependencies for gettext
--->  Fetching archive for gettext
--->  Attempting to fetch gettext-0.18.3.1_1.darwin_11.x86_64.tbz2 from http://packages.macports.org/gettext
--->  Attempting to fetch gettext-0.18.3.1_1.darwin_11.x86_64.tbz2.rmd160 from http://packages.macports.org/gettext
--->  Installing gettext @0.18.3.1_1
--->  Cleaning gettext
--->  Computing dependencies for gettext
--->  Deactivating gettext @0.18.3.1_0
--->  Cleaning gettext
--->  Activating gettext @0.18.3.1_1
--->  Cleaning gettext
--->  Fetching archive for gmp
--->  Attempting to fetch gmp-5.1.2_0.darwin_11.x86_64.tbz2 from http://packages.macports.org/gmp
--->  Attempting to fetch gmp-5.1.2_0.darwin_11.x86_64.tbz2.rmd160 from http://packages.macports.org/gmp
--->  Installing gmp @5.1.2_0
--->  Cleaning gmp
--->  Deactivating gmp @5.0.5_0
--->  Cleaning gmp
--->  Activating gmp @5.1.2_0
--->  Cleaning gmp
--->  Computing dependencies for coreutils
--->  Fetching archive for coreutils
--->  Attempting to fetch coreutils-8.21_0.darwin_11.x86_64.tbz2 from http://packages.macports.org/coreutils
--->  Attempting to fetch coreutils-8.21_0.darwin_11.x86_64.tbz2.rmd160 from http://packages.macports.org/coreutils
--->  Installing coreutils @8.21_0
--->  Activating coreutils @8.21_0

The tools provided by GNU coreutils are prefixed with the character 'g' by default to distinguish them from the BSD commands.
For example, cp becomes gcp and ls becomes gls.

If you want to use the GNU tools by default, add this directory to the front of your PATH environment variable:
    /opt/local/libexec/gnubin/

--->  Cleaning coreutils
--->  Updating database of binaries: 100.0%
--->  Scanning binaries for linking errors: 100.0%
--->  No broken files found.
john@Slick:.rvm [508]$ which ginstall
/opt/local/bin/ginstall


Cool, thankfully that step worked.  Now, to try again...

Attempt #3: Success!!!

With the symlink to gcc in place and the missing GNU tools installed, gave it one more go...


john@Slick:ruby-on-rulers (master) [1362]$ bundle install
Fetching gem metadata from https://rubygems.org/..........
Fetching gem metadata from https://rubygems.org/..
Resolving dependencies...
Using rake (10.1.0) 
Using bundler (1.3.5) 
Using erubis (2.7.0) 
Using multi_json (1.8.0) 
Using rack (1.5.2) 
Using rack-test (0.6.2) 
Using require_all (1.3.1) 
Installing sqlite3 (1.3.8) 
Using rulers (0.7.0) from source at . 
Your bundle is complete!
Use `bundle show [gemname]` to see where a bundled gem is installed.

Hurray!!!

Retrospective

Here's a few things I learned about troubleshooting in this process:

  • gather all your forensics (i.e. read through all of the logging output you can get your hands on);
  • learn the process at hand (knowing what extconf.rb was doing was hugely helpful);
  • where you're given the gift of full command lines that were executed and failed, go run those manually to see if you get more information/context;
  • If at first you don't find it, google, google again.