Ruby, regex and match
Tuesday, January 30th, 2007I’ve just spent two hours trying to figure out how to get the next match from a string using regex in Ruby. I then found out about the scan method. Doh!
I’ve just spent two hours trying to figure out how to get the next match from a string using regex in Ruby. I then found out about the scan method. Doh!
A handy tip for getting documentation on your Ruby gems is to use gem_server which fires off a local server which you can access on http://127.0.0.1:8808. Very handy. Another way is to run gem environment gemdir to get your gem install dir, append doc onto the end and the gem documents are all in there e.g. /usr/local/lib/ruby/gems/1.8/doc
In Rails you can’t have a column named format in a table as it is a reserved Ruby word. Fair enough. But how then can you handle a database that has a column named that in Rails without using views?
It turns out to be surprisingly logical; modify your Rails model with two new methods. You need a getter and setter so for example:
def dialect return self.format end def dialect=(value) self.format = value end
Now my model has a method of dialect which gets and sets to format in the database.
We are getting to a point in our project where we want the different bits to start integrating. One part is Java, another is C++ and the part I am responsible for is Ruby on Rails. All of this runs off of a MySQL 5 database.
The database schema is owned by a C++ guy and while he was willing to modify some of his style to fit Rails conventions I told him not to. To be honest I was worried when I said that. It was a risk thinking that Rails would be able to handle a non-standard database. Not only were primary and join tables named completely differently to Rails conventions but the columns were quite different and the data the one Rails app needed to get at was spread over multiple databases.
About 10 minutes ago I sat back in my creaky chair and sighed a sigh of relief. It all works. Rails handles the non-standard setup just fine.
We first made views of the underlying tables (which is why we are on MySQL 5) to get as close to Rails conventions as we could. It wasn’t perfect though as all our views are prefixed. By default Rails won’t handle that unless I bastardised my model naming which we weren’t going to do. The next trick was to use AustinMoody’s def self.table_name() “mpq.mpqs” end tip to tell Rails what table (actually, views) to use. It also solved the multiple-database problem as you just prefix the table name with the database name.
I then found out about the :join_table option on has_and_belongs_to_many in your models which deals with the join tables.
And that is all it took. I am relieved and impressed with Rails. I get all the good stuff while working on a decidely non-conventional Rails database setup.
Ruby really is more productive. I wanted to add OPML support to a project of ours and from past .NET experience with this wasn’t looking all that forward to it. But rexml and rio came to the rescue.
Here is some sample Ruby code that extracts all the URLs from an OPML file:
opml_file = ''
rio('http://share.opml.org/opml/top100.opml') > opml_file
opml_doc = Document.new(opml_file)
urls = XPath.match(opml_doc, '//@xmlUrl')
That is it. rio does the hard work of saving the web-stored OPML file into a string. rexml does the hard job of parsing that string into an XML document and then we use XPath to find all of the xmlUrl attributes.
rexml comes with most standard Ruby installs and you can install rio with gem install rio. The rio documentation is here.
I just booked my place at the European Ruby on Rails conference being held on the 14th and 15th of September in London. If you are going drop me a line.
Read on Nabble - Ruby and CruiseControl
Johan: Maybe it’s just me, but wouldn’t it be nice to be able to define an ‘inline’
antbuilder task - e.g. contain ant
tags directly within the CC
config.xml file?
Jeffrey: I think that would make sense for a very limited audience…. Very
limited. Like just you.
rev = `svn info`.match('Revision: (\d+)')[1]
That bit of Ruby code will return the Subversion revision number of the working copy it is run in.
`svn info` returns
Path: .
URL: http://svn.yourdomain.com/trunk/Repository UUID: 4e38b711-8f0e-1410-9e15-e3a330ac0d60
Revision: 894
Node Kind: directory
Schedule: normal
Last Changed Author: pwatson
Last Changed Rev: 894
Last Changed Date: 2006-07-28 14:48:28 +0100 (Fri, 28 Jul 2006)
Properties Last Updated: 2006-07-28 14:50:11 +0100 (Fri, 28 Jul 2006)
The regex bit (.match(’Revision: (\d+)’)[1]) then returns the 894 number from that string.
(Thanks to Dela for the regex.)
Just a quick one before a longer “Rails Continuous Integration” post but if you are trying to get Cerberus to work on Windows then after the gem install you have to set an environment variable yourself. Create one called CERBERUS_HOME with a value of C:\ruby\lib\ruby\gems\1.8\gems\cerberus-0.1.1
I have never been a big language geek. My CV lists a raft of them; C#, JavaScript, Ruby, VBScript and even COBOL. But I know many coders (like Kenny, Brian or David) who have a much deeper understanding than I do. On a daily basis Brian shows me twists and turns of C# that I had no idea about. I am not ashamed about this though. Programmers aren’t one type. We have generalists and specialists, high-level chaps and on-the-metal sorts.
Occasionally though along comes a language or system that works the way I think. I then go to another level of understanding with it. HTML and CSS may not be strict programming languages but I do know them to a far greater degree than I do other languages. I am dead confident with them which is a nice feeling.
I reckon Ruby is fast revealing itself to be a language I will grow to be confident in, one I’ll understand beyond my usual level. It feels right.
Just an hour ago I needed some Ruby code that would generate a random string of characters (for a password system in this case.) One Google later and I came across this post. A comment by Scott Becker blew me away with its usesfulness and simplicity. Here is the code:
schars = "0124356789abcdefghijk"
password = ""
1.upto(8) { password += schars[rand(schars.length),1] }
In other languages a line like that would leave me scratching my head and turning to Brian but in Ruby it made elegant, simple sense.