Devoured By Lions

the eternal struggle to tame complexity

Latest Capybara and Selenium

I just updated to the latest Capybara and Selenium on a project that I’ve been away from for a while and had to make the following change:

http://johnwilger.com/2011/04/capybara_selenium_and_firefox_3_5.html

Capybara::Selenium::Driver::DEFAULT_OPTIONS[:resynchronize] = false


I am also getting the following warning:

Selenium::WebDriver::Element#drag_and_drop_{by,on} is deprecated. Please use Selenium::WebDriver::Driver#action (and Selenium::WebDriver::ActionBuilder) instead.


However after some investigation it appears that this is an issue Capybara should deal with; presumably the Capybara implementation should be updated and not my integration test code (which should only use the external Capybara API).

Monads in Java

Preserving this from some old stuff I wrote. Don’t judge me.

The Curiously Recurring Installation Pattern*

Once again I find myself installing a piece of *nix software, only to struggle against its blind insistence on being installed in the bowels of my system. It goes something like this:

* ./configure # let it use the default path because we will rewrite the dest dir on install and stow it (ha ha.)
* make
* make install DESTDIR=”/my/software”

Depending on the software build system, this may or may not work. (see: http://www.ruby-forum.com/topic/818302). If it doesn’t, well, it’s your lucky day. You do have all the output in your terminal scrollback right? Good, ‘cause you’ll need to go and manually remove every last file it installed and try again.

If DESTDIR worked, you may be able to stow now:

* sudo stow -t /usr/local -d /my/software awesome-app

Except of course if the build system installed in this brilliant fashion: /my/software/usr/local/… Oops! Time to clean up again! (if you are brave/foolish you can certainly try ‘stow -t / -d /my/software awesome-app’ instead. Good luck with that.)

* cd /my/software/awesome-app
* mv usr/local/* .
* rm -r usr/local
* cd ..
* sudo stow -t /usr/local -d /my/software awesome-app

Since this is such a colossal PITA, in some cases wrappers have been developed that essentially put a big condom around builds and allow you to manage them like a sane, normal user, in your own directory. Some examples are RVM, the Ruby Version Manager, NVM, the Node Version Manager (takes care of NPM as well), and PythonBrew (an RVM equivalent for Python). While these are absolute life-savers, they are really covering up an underlying flaw which is that a lot of *nix software is built to install only into the global system (which frankly is mystifying given *nix’s heritage of strong user/system separation. maybe it’s just a legacy of the traditional *nix tool chain).

(* http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)

Ruby-oci8 on Fedora X86_64

Read: http://ruby-oci8.rubyforge.org/en/InstallForInstantClient.html
  • oracle-instantclient-basic-10.2.0.4-1.x86_64.rpm
  • oracle-instantclient-devel-10.2.0.4-1.x86_64.rpm
Set your LD_LIBRARY_PATH so compile can find Oracle libs. Double check the path here actually reflects the version of packages you downloaded: export LD_LIBRARY_PATH=/usr/lib/oracle/10.2.0.4/client/lib

Install ruby-oci8 gem: gem install ruby-oci8 (or via bundler)

With luck ruby-oc8 will build.

Tell SELinux that these libs can have an executable stack: (see: http://fedoraforum.org/forum/showthread.php?t=259605)
  • sudo /usr/bin/execstack -c /usr/lib/oracle/10.2.0.4/client64/lib/libclntsh.so.10.1
  • sudo /usr/bin/execstack -c /usr/lib/oracle/10.2.0.4/client64/lib/libnnz10.so
Test it:

require ‘dbi’
require ‘oci8’
dbh = DBI.connect(“DBI:OCI8:whatever”, username, password)
dbh.execute(‘select * from whatever’)

Oracle XE on Fedora X86_64

If you encounter problems installing Oracle XE on Fedora x86_64, install the ‘libaio.i686’ package before installing oracle-xe. If you have already installed the oracle-xe package, you may have to remove it and then reinstall it to ensure that it initializes the database correctly (it will have failed the first time).

Symptoms include the following on connect:

ERROR:ORA-01034: ORACLE not available
ORA-27101: shared memory realm does not exist
Linux Error: 2: No such file or directory

You will also see some errors on your tnslisteners.log.

This Software Shall Be Used for Good, Not Evil

http://www.infoq.com/presentations/Heretical-Open-Source

Douglas Crockford gave a really nice presentation at Strange Loop. I encourage you to check it out. He talks about the history of HTML, XML and JSON, and finally the legacy of (Admiral) Grace Murray Hopper, developer of the first compiler. However, in the middle he goes on a humorous and bizarre tangent regarding a clause he added to his JSON license, “The Software shall be used for Good, not Evil.”, and in the process takes a swipe at the OSI, Free Software Foundation and Richard Stallman (and Google for that matter). Now, while he certainly makes light of this clause, Crockford claims he is “serious” about it, while admitting it is “intentionally vague and unenforceable”. Well, the funny thing about legal documents is that most people really like them to be not-vague and enforceable. Ultimately I think his goals with his license were no different from those of free software enthusiasts - the right to dictate his (the author’s) particular terms of use. The only difference is that the FSF decides to use specific and enforceable legal language, instead of facetious sarcasm. It is true that software licenses and licensing are sometimes dreadfully tedious topics, and if you wish to avoid it all with a simple and liberal license, all the more power to you. I just find slamming free software a little tired.

Then again, he is a heretic.

Trials and Tribulations With Bundler


Bundler is awesome. But Bundler also sucks.

I have been trying to devise a strategy for deploying pre-packaged addons to a Ruby program, but have concluded, much to my surprise, that there is just no simple way to do this in the current Ruby ecosystem. My needs are simple:
  1. Deliver my addon code
  2. Deliver any necessary dependencies with my addon code
  3. Invoke this addon code from a main program without additional a-priori configuration of the main program
The first stop is RubyGems. Gems are great. They are the quantum of dependency management in Ruby, and are analogous to Maven artifacts in the Java ecosystem. An add-on is nominally equivalent to a gem. The tricky part however is obtaining all the gem dependencies. Unfortunately RubyGems only resolves dependencies during installation, so is not helpful in, say, bundling gems. If we are to build our add-on as a gem, then that implies that we need to explicitly run a “gem install” command at deploy time, and we get whatever version of gem dependencies rubygems resolves at deploy time (also assuming the installation machine has network access). This is not desirable. Instead we would like to bundle all the necessary dependencies together with the addon. This is where, you guessed it, Bundler comes in.

Bundler’s mandate is to perform dependency resolution and bundling, for applications. The distinction between applications and libraries is very explicit, in contrast with Maven for example, in which dependency management is handled uniformly (applications are “packaged” the same way as libraries). This is unfortunate and means that one must use the gem specification to specify library dependencies, and Bundler Gemfile to specify application dependencies. Bundler can parse dependencies from gem specs however. Bundler cannot (yet?) handle nesting/composing Gemfiles (because it is only designed for top-level applications). But with some subterfuge we can write something like this:
source “http://rubygems.org”

gem “json_pure”

Dir.glob(File.dirname(__FILE__) + ‘/ext/*/Gemfile’) do |file|
# evil
eval File.new(file).read
end
Here we have coerced our main Gemfile to load the contents of subordinate Gemfiles dynamically. We can reconfigure our addon such that it is no longer a gem, but instead specifies its dependencies in its own Gemfile.

We cannot pat ourselves on the back however, because this cleverness only gets us so far (not that far). Bundler resolves dependencies statically. It requires the static generation of a Gemfile.lock file which contains the static graph of dependencies resolved at the time bundle install was run (even if all the dependencies are already present in the right locations). So this is a dead end. We cannot just drop down an addon with its own Gemfile and dependencies without statically re-resolving the entire dependency graph (see for more details).

What have others done in this situation? There are of course Ruby applications that support “plugins” of some sort. The first one that came to mind was RedCar. It turns out RedCar plugins typically include the source of any dependencies. That is definitely one solution, however I would like to avoid that if possible. It’s possible to “include” third party Git repos in your own Git repo via the submodule mechanism. Unfortunately (to my knowledge) submodules do not support checking out specific paths. Using submodules would require additional mechanisms to filter in/out the right repository content when packaging the plugin.

At this point I’m thinking a simpler solution based directly on RubyGems alone might work. It should be possible to manually resolve dependencies at package time, and use a different mechanism to load them up at runtime.

It looks like a project called Isolate might be the right fit:


Update: I converted the project over to Isolate, and it appears to be working fine. Addon gems can be dropped right into the main program vendor location, and they will be found by the main Isolate.now! invocation, with no qualms.