Mocking Kernel#require
Posted by james on August 31st, 2008The other day, I remembered to add coverage analysis to my AMEE-Ruby tests, using rcov. The results were pretty good - most of the code was already tested, except a few failure cases, and I quickly wrote some new tests to make sure those were working properly. One little bit of code stood out though. Because AMEE talks XML and JSON, my gem can use JSON, but only if the JSON gem is available on the system (XML support is built into core Ruby). Problem is, require calls throw errors if they fail, so I had to write some code to handle the load failure and carry on regardless. This is the code inside amee.rb:
begin require 'json' rescue LoadError nil end
Problem with this is that the gem is installed on my system, so the require never fails, and the rescue is never used. Rcov notices, and I can't get to 100% coverage, which is annoying.
So, mocking to the rescue. We have to make Kernel#rescue throw an error if we try to require 'json', even if the gem is installed. At first, I tried to use flexmock to do this, but couldn't make it work - if anyone knows how, please tell me. My final approach was to monkeypatch Kernel#require inside my test so that require 'json' (and only json) would fail:
it "should cope if json gem isn't available" do # Monkeypatch Kernel#require to make sure that require 'json' # raises a LoadError module Kernel def require_with_mock(string) raise LoadError.new if string == 'json' require_without_mock(string) end alias_method :require_without_mock, :require alias_method :require, :require_with_mock end # Remove amee.rb from required file list so we can load it again $".delete_if{|x| x.include? 'amee.rb'} # Require file - require 'json' should throw a LoadError, # but we should cope with it OK. lambda { require 'amee' }.should_not raise_error end
We have to make a new require function, then use alias_method to rename the old one and install our new one in it's place. Rails includes alias_method_chain to make this easier, but that's not available in pure Ruby. Never mind. Once we've done the monkeypatch, we take amee.rb out of the $" array, which lists all the currently-required files, to make sure we can require it again, then simply run the require and make sure it catches the error that is thrown by our patched require. And the most satisfying part? The rescue is executed, the test works, and we get to 100% coverage. I've got a nice warm fuzzy feeling inside... mmmmmm.
CurrentCost data live on Pachube
Posted by james on August 29th, 2008So, the other day I got a nice little tray icon working for my CurrentCost power monitor. That's great, but data is only really gets fun when it's mashable, so the next step was to get it online somehow.
Pachube is a site which aggregates data feeds from real-world (and virtual-world) devices, shows them on a map, makes graphs, things like that, so it seemed like a good first attempt at putting my power data online. My first thought was to get my app to post data at regular intervals to the service, but unfortunately Pachube doesn't work like that. Instead, it acts more like a news reader, not a publishing platform - Google Reader instead of Blogger, if that makes sense. So, I had to publish my feed live on the web and point Pachube at the URL.
First step: EEML. This is an XML-based format which Pachube reads which can contain not only multiple data feeds, but tags and other metadata. So (as seems to be the fashion), I wrapped it up in a Ruby gem, available from GitHub as ever. The gem simply provides utility classes to build an EEML feed and convert it to the XML-based format for delivery over the web.
Then, the final step was to publish the data on the web. For that, we need a web server. However, having a full web server for just one feed seemed overkill, and I didn't want to publish to yet another intermediate server, so we need to serve the data directly. Ruby to the rescue once again. WEBrick is a simple web server which is part of the core Ruby libraries. You create a server, write simple servlet classes, and mount them at particular locations. For instance:
# Create WEBrick server s = WEBrick::HTTPServer.new( :Port => 50000 ) # A simple "hello world" servlet class HelloServlet < WEBrick::HTTPServlet::AbstractServlet def do_GET(request, response) response.status = 200 response['Content-Type'] = "text/xml" response.body = "hello world" end end s.mount("/", HelloServlet)
Now, http://localhost:50000/ will say "hello world". From here it's a simple modification to publish the EEML feed. EEML-Ruby includes a simple EEML server script as an example. So, after building this into the tray app, now whenever my CurrentCost is connected and the app is running, it serves up EEML data to the web. You can see the data feed (fairly intermittent, as obviously the meter isn't always connected to my PC at the moment) live on Pachube.
Some successful CurrentCost hacking
Posted by james on August 22nd, 2008After a bit of work, I've finally got my CurrentCost meter working in Ruby, and I now have a power monitor sitting in my system tray! There were a few stages involved...
Serial comms: The ruby-serialport library that already existed for Ruby was no good to me. Firstly, it didn't seem to be in a working state, but more importantly, the license it is under (GPL) is no good to me. So, I had to write my own. I've created a nice simple serial library (including a gem) for Ruby called RB232, which is available on GitHub. It only supports reading at the moment, and only works on Linux systems, but it's a start. Next!
Reading CurrentCost data: Once RB232 was in place, this was pretty easy. Just create a couple of classes to wrap up the process of getting data from the meter, and away you go. Easy. Also released as a Ruby gem on Github.
User interface: Last step was to make a simple user interface for the meter, which you can see in the picture above. It's a simple tray icon that changes colour based on power usage. It's based heavily on another very useful tool called cctrayrb, so many thanks to Daniel Parnell for doing the heavy GUI lifting there. The app is included as part of the currentcost-ruby gem mentioned above.
Anyway, it's all freely available, so if you have a CurrentCost meter and a serial cable for it, you can grab the code and get going. Enjoy :)
One Hundred Months
Posted by james on August 6th, 2008I just saw the One Hundred Months campaign, and decided it was ripe for a bit of automated Twittering. So, 5 minutes hacking and we have One Hundred Months on Twitter. Code (as ever these days) is available from GitHub.
I'm amazed by what computers can do sometimes. This one seriously took me longer to publish to the world than to write.
Hacking your energy usage with the CurrentCost
Posted by james on August 6th, 2008The other day, I managed to get hold of a CurrentCost energy monitor (available to buy from here, or maybe from your electricity supplier). Now, the nice thing about this particular monitor (apart from the ton of information on-screen) is the fact that it has a serial output on the bottom, which you can (with a bit of hacking) plug into your PC, and - bingo - lovely XML data!
However, once you have it connected and spewing XML at you, you really need something to do with all that data. I don't have anything big written yet, but my first step towards making something useful is a Ruby gem, which is available from GitHub. So far it can only parse the XML data from the meter - direct access to the serial port is hopefully coming soon.
In other news, the AMEE gem I started a while ago is still coming on. It can now use the XML and JSON interfaces, parse the whole Data API, and retrieve a list of Profiles. Not a bad start.