Thursday, December 25, 2008
The day Merb joined Rails
It's a historic day in history of Rails (and Merb). Eyepoppingly shocking, Merb 2 has a new name -- Rails 3. Yes! Merb is being merged into Rails 3!
DHH and Yehuda Katz announced it almost simultaneously. 96% people are positive about the merger. If you belong to 4%, David has an answer for you.
Ezra explains how Merb is undergoing a rebirth. This merger would hopefully break the myth that Rails is a monolith. Interesting to see community putting an end to drama and coming together.
Friday, December 19, 2008
Programming has evolved
When I look at the recent advancements in Behaviour Driven Development in Rails, I tend to think that programming has really evolved. Not in terms of advanced data structures and superior algorithms, but as a focus shift of intention.
Earlier the focus was the machine. Days are gone when we thought so much about saving an extra byte, trading code simplicity for speed. A compromise here, a saving there, ad infinitum.
The focus has definitely shifted to human understandability. Beauty of code now lies in its simplicity (some folks would argue that it always did, and they're right, but its more so apparent now).
First it was Ruby, then Rails, and now BDD frameworks like rSpec and Cucumber prove the point. Just have a look at these executable code examples.
Ruby
Rails
rSpec
And now, Cucumber
More beautiful, more succinct, more concise. That's what programming has evolved to be.
Earlier the focus was the machine. Days are gone when we thought so much about saving an extra byte, trading code simplicity for speed. A compromise here, a saving there, ad infinitum.
The focus has definitely shifted to human understandability. Beauty of code now lies in its simplicity (some folks would argue that it always did, and they're right, but its more so apparent now).
First it was Ruby, then Rails, and now BDD frameworks like rSpec and Cucumber prove the point. Just have a look at these executable code examples.
Ruby
animals = [ "Tiger", "Cow", "Python", "Horse" ]Does a C for loop or C++ iterator look more elegant?
animals.each do |animal|
puts animal + "is cool!"
end
#=> Tiger is cool! Cow is cool! ...
Rails
class ProjectCode that you can just read, isn't it?
belongs_to :portfolio
has_one :project_manager
has_many :milestones
has_and_belongs_to_many :categories
end
rSpec
lambda {Yes, that's a real executable example.
employee.develop_great_new_social_networking_app
}.should change(employee, :title).from("Mail Clerk").to("CEO")
And now, Cucumber
Scenario: Search by topic
Given there are 240 courses where neither has the topic "biology"
And there are 3 courses A,B,C that each have "biology" as one of the topics
When I search for "biology"
Then I should see a the following courses:
| title |
| A |
| B |
| C |
More beautiful, more succinct, more concise. That's what programming has evolved to be.
Labels:
code beauty,
cucumber,
programming,
rspec,
ruby on rails
Thursday, December 18, 2008
Git your branch name into your shell
I use git on my Ubuntu for my Rails projects, and very frequently I need to know what branch I'm working on right now.
If I can just get my shell to display the current local branch all the time in the prompt, it'd be a lot easier. I just found I could do so.
You need to modify the environment variable PS1 to show your current local git branch.
For me, it looks like this now.
And it renders out like
In short, you need to append the following to the PS1 string.
The redirection of stderr to /dev/null is required since it suppresses git error messages in case you're not inside a git directory.
Ugly though it may be, it works. And to make the PS1 persist, add the line into your ~/.bashrc file.
PS: I use bash. For zsh and others, its even easier to do this.
If I can just get my shell to display the current local branch all the time in the prompt, it'd be a lot easier. I just found I could do so.
You need to modify the environment variable PS1 to show your current local git branch.
For me, it looks like this now.
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w [$(git branch 2>/dev/null| grep "\*" | cut -f 2 -d " ")]\$ '
And it renders out like
kazim@invincible:~/projects/aprioriate [refactoring]$
In short, you need to append the following to the PS1 string.
[$(git branch 2>/dev/null| grep "\*" | cut -f 2 -d " ")]\$
The redirection of stderr to /dev/null is required since it suppresses git error messages in case you're not inside a git directory.
Ugly though it may be, it works. And to make the PS1 persist, add the line into your ~/.bashrc file.
PS: I use bash. For zsh and others, its even easier to do this.
Monday, October 13, 2008
Finally, a solution to file sharing woes
File sharing was never easy, especially for big files. I don't trust GMail, even when it says it allows attachment size of 20M. I often had my GMail frozen attaching just a 7M file, after some 20 minutes (which is way too much for just a 7M file!).
Enter DropBox. 20GB of free online storage. And a desktop interface which sticks to your Windows Explorer/Mac Finder/GNOME Nautilus seamlessly. I won't say this is a new solution, since we had GMail drive once, and many others kept popping up.
What makes DropBox special is ease of use with friendliness. And you can keep working while it synchronizes your files quietly in the background. You can also set maximum download/upload limits, so that your browsing experience remains okay.
Go ahead. Tour Dropbox. See the screencast. Download it. Link your computer and start sharing. And be thankful to me forever!
Enter DropBox. 20GB of free online storage. And a desktop interface which sticks to your Windows Explorer/Mac Finder/GNOME Nautilus seamlessly. I won't say this is a new solution, since we had GMail drive once, and many others kept popping up.
What makes DropBox special is ease of use with friendliness. And you can keep working while it synchronizes your files quietly in the background. You can also set maximum download/upload limits, so that your browsing experience remains okay.
Go ahead. Tour Dropbox. See the screencast. Download it. Link your computer and start sharing. And be thankful to me forever!
Thursday, March 20, 2008
Shortcuts in GNOME
There are more than one ways to set Keyboard Shortcuts in GNOME. In my Ubuntu 7.04, you can either go to System -> Keyboard Shortucts and change/add keybndings there. This way, you can change keybindings for most common operations like "Launch Web Browser" etc.
There's another way, a very versatile one, provided by GTK. In almost any GTK application, you can give shortcuts to menu items. Just open the menu, and point with your mouse on the menu item you want to give a shortcut to, and press the shortcut key. GNOME will automatically assign that shortcut to that menu item, and remember it.
If the procedure outlined above doesn't work for you for some reason, launch gconf-editor from a terminal. Make sure that desktop/gnome/interface/can_change_accels is true. Happy shortcuts!
There's another way, a very versatile one, provided by GTK. In almost any GTK application, you can give shortcuts to menu items. Just open the menu, and point with your mouse on the menu item you want to give a shortcut to, and press the shortcut key. GNOME will automatically assign that shortcut to that menu item, and remember it.
If the procedure outlined above doesn't work for you for some reason, launch gconf-editor from a terminal. Make sure that desktop/gnome/interface/can_change_accels is true. Happy shortcuts!
Saturday, February 23, 2008
Recovering a (Lost) ReiserFS Partition
The partition table on my sister's laptop always seemed fishy to me. It just didn't have the right feel about it. The cylinder numbers and sizes and all, but I never cared. As the laptop went through a series of installations, Ubuntu or Windows, the abnormality showed up.
After installing Windows, I found hard to install GRUB on MBR. The grub-install would refuse, and so would the grub. I was troubled when the output of cfdisk said that 30G is unusable space, out of my 60G disk.
But, I thought its just another routine partition table corruption, and I had a tool in my swiss-army knife - testdisk (http://www.cgsecurity.org/wiki/TestDisk). Testdisk analyses your disk for lost partitions and tries to guess the correct partition table. Then it shows the guess to the user, who can then choose to write the table or not.
In my case, though testdisk correctly guessed the partitions (it found more than actual ones), it could not guess a proper partition table. Instead, it asked me to specify which partition is primary, logical or bootable primary. Now that was difficult for me. And I didn't want to take risks.
One good thing about testdisk is that it lets you peek inside partitions and read filenames. I was particularly interested in recovering a ReiserFS partition, which was 20G in size. Fortunately, testdisk was able to see this partition, and the filenames too. It was found lying from cylinders 3856 to 6287.
Anybody who knows a bit about recovery knows that if you know the cylinder numbers, you've solved the problem. Recovering a partition becomes an easy job. I started by dd'ing out from cylinder 3856 about 1MB. But the result was not as expected. It wasn't a superblock. It was just 'data'. Just data? How could it be that testdisk was lying?
I checked the calculations again, yet to no avail. It was data there. One thing was for sure -- the superblock must begin somewhere near cylinder 3856. I got a weird idea. I quickly made a dummy file of 200M using dd. I made a loop device out of it, and did a reiserfs format over it.
I intended to find out the pattern with which a reiserfs superblock starts. The output of hexdump showed something like this:
Look how smartly the filesystem developers have written ReIsEr2Fs there! The third line, which has 2 and a space, actually contains disk label.
With this amount of information, I tried to find the superblock in the 10MB dump.
And fortunately, it was there! At an offset of about 1d200h from cylinder 3856.
Looking a few 100 bytes before this pattern, I found exactly the same fingerprint of ReiserFS superblock! After calculating and adding, I did a dd dump from the correct byes, and here it was -- the superblock!
I took a bigger dump (2G), and tried to mount it. But mount refused, simply because there was not enough space on the loop device than the partition required (20G).
I looked for some IRC help, and enouf on ##linux suggested the offset option of the mount command. It can do just what I wanted -- to mount a range of bytes of a disk as a device.
And there it was! Recovered intact. The next thing I did was to backup the 15G data it had. And I got a treat from my sister, too. :-P
Simplicity is often wonderful. And so is Linux.
After installing Windows, I found hard to install GRUB on MBR. The grub-install would refuse, and so would the grub. I was troubled when the output of cfdisk said that 30G is unusable space, out of my 60G disk.
But, I thought its just another routine partition table corruption, and I had a tool in my swiss-army knife - testdisk (http://www.cgsecurity.org/wiki/TestDisk). Testdisk analyses your disk for lost partitions and tries to guess the correct partition table. Then it shows the guess to the user, who can then choose to write the table or not.
In my case, though testdisk correctly guessed the partitions (it found more than actual ones), it could not guess a proper partition table. Instead, it asked me to specify which partition is primary, logical or bootable primary. Now that was difficult for me. And I didn't want to take risks.
One good thing about testdisk is that it lets you peek inside partitions and read filenames. I was particularly interested in recovering a ReiserFS partition, which was 20G in size. Fortunately, testdisk was able to see this partition, and the filenames too. It was found lying from cylinders 3856 to 6287.
Anybody who knows a bit about recovery knows that if you know the cylinder numbers, you've solved the problem. Recovering a partition becomes an easy job. I started by dd'ing out from cylinder 3856 about 1MB. But the result was not as expected. It wasn't a superblock. It was just 'data'. Just data? How could it be that testdisk was lying?
$ file mydump
mydump: data
I checked the calculations again, yet to no avail. It was data there. One thing was for sure -- the superblock must begin somewhere near cylinder 3856. I got a weird idea. I quickly made a dummy file of 200M using dd. I made a loop device out of it, and did a reiserfs format over it.
$ dd if=/dev/zero of=check-rfs bs=1M count=200
$ sudo losetup -f check-rfs
$ sudo mkfs.reiserfs /dev/loop0
$ hd check-rfs | less
I intended to find out the pattern with which a reiserfs superblock starts. The output of hexdump showed something like this:
00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00010000 00 32 00 00 ec 11 00 00 13 20 00 00 12 00 00 00 |.2....... ......|
00010010 00 00 00 00 00 20 00 00 00 04 00 00 93 98 2f 43 |..... ......../C|
00010020 84 03 00 00 1e 00 00 00 00 00 00 00 00 10 cc 03 |................|
00010030 02 00 01 00 52 65 49 73 45 72 32 46 73 00 00 00 |....ReIsEr2Fs...|
00010040 03 00 00 00 02 00 01 00 02 00 00 00 00 00 00 00 |................|
Look how smartly the filesystem developers have written ReIsEr2Fs there! The third line, which has 2 and a space, actually contains disk label.
With this amount of information, I tried to find the superblock in the 10MB dump.
$ hd mydump | grep -i reiser2fs
And fortunately, it was there! At an offset of about 1d200h from cylinder 3856.
0001d200 02 00 01 00 52 65 49 73 45 72 32 46 73 00 00 00 |....ReIsEr2Fs...|
Looking a few 100 bytes before this pattern, I found exactly the same fingerprint of ReiserFS superblock! After calculating and adding, I did a dd dump from the correct byes, and here it was -- the superblock!
$ file dump-again
dump-again: ReiserFS V3.6 block size 4096 num blocks 4883760 r5 hash
I took a bigger dump (2G), and tried to mount it. But mount refused, simply because there was not enough space on the loop device than the partition required (20G).
I looked for some IRC help, and enouf on ##linux suggested the offset option of the mount command. It can do just what I wanted -- to mount a range of bytes of a disk as a device.
$ sudo mount /dev/sda recovered/ -o ro,loop,offset=31716679680
$ ls recovered/
bin cdrom etc initrd initrd.img.old lost+found mnt proc sbin sys tools var vmlinuz.old
boot dev home initrd.img lib media opt root srv tmp usr vmlinuz
And there it was! Recovered intact. The next thing I did was to backup the 15G data it had. And I got a treat from my sister, too. :-P
Simplicity is often wonderful. And so is Linux.
Sunday, January 6, 2008
Reinventing Rails
These holidays, I was busy developing spendwrite.com. The idea behind spendwrite is a community driven website where users share their experiences about the various places they visit in their town, like restaurants, coffee shops, dentists or shopping malls etc. Everyone reviews the outlets and rates them, so one can easily find the best of places around them.
In the process of development, I learned that it requires a lot of courage and patience to develop a web application. It also requires foresight.
To start with, I chose PHP as the language. Though I love the Ruby on Rails framework, I didn't choose it because its painfully slow. What I intended was, a functionality similar to the one offered by RoR framework, without a real framework in place.
MVC is the leading architecture used by modern frameworks. Rails is no exception, and so many other frameworks use it. So I decided to have an MVC architecture for my website.
I'd learned a lot about MVC and wrote little applications using Rails as well. But the advantage of using MVC was not entirely clear to me before I developed spendwrite.com.
To begin with, I had vague ideas only. I created four directories, like Rails does, called 'models', 'views', 'controllers' and 'helpers'. To be true to MVC, a templating engine was required to play the role of 'views'. Enter Smarty, the templating engine we all know and love. With its caching abilities, it was clearly better than any other templating engines available for php.
Initially, I was creating a model for each table in my database. But as I wrote more code, I found out that much of the code to the models are common. Thats where ActiveRecord component of RoR clicked to my mind. ActiveRecord has a basic CRUD code same for all models. On top of that, individual models define their own methods.
So, I did the same. I carefully wrote CRUD functions, and made this code common to all models. This modular approach was fruitful. Models were tidy now, and the code was easier to manage and debug. Once the CRUD is solid, the models work flawlessly.
Controllers. I must confess, that the habit of writing all-code-in-one-file doesn't go overnight. I wrote a lot of code in controllers, which I shouldn't have. For example, the code for validating user input. Though I had defined helpers like validate_numericality_of and validate_minlength_of etc. in a helpers file, yet writing validation logic in controllers didn't make sense. It took some time for me to realize that validation actually belongs to models, and not to controllers.
Code rearrangement followed. By having all the validation done in models, you relieve controllers of the repetitious job.
For authorization, I'd love to implement something like before_filter in Rails. Since I really couldn't find equivalent, I wrote a model for authorization, and every controller must call a method must_authorize(); if it wants so.
As I write more and more code, I come to realise the beauty of MVC. If you follow the MVC principles strictly, you write less code and error free code. And I also realize how beautifully Rails has implemented MVC architecture.
Rails is no doubt the most productive framework available today for web development. The more you don't use Rails, the more you realize it. :-P
Learning by experimenting is the best way to learn. And while I do, I find myself reinventing Rails. Any coincidence?
In the process of development, I learned that it requires a lot of courage and patience to develop a web application. It also requires foresight.
To start with, I chose PHP as the language. Though I love the Ruby on Rails framework, I didn't choose it because its painfully slow. What I intended was, a functionality similar to the one offered by RoR framework, without a real framework in place.
MVC is the leading architecture used by modern frameworks. Rails is no exception, and so many other frameworks use it. So I decided to have an MVC architecture for my website.
I'd learned a lot about MVC and wrote little applications using Rails as well. But the advantage of using MVC was not entirely clear to me before I developed spendwrite.com.
To begin with, I had vague ideas only. I created four directories, like Rails does, called 'models', 'views', 'controllers' and 'helpers'. To be true to MVC, a templating engine was required to play the role of 'views'. Enter Smarty, the templating engine we all know and love. With its caching abilities, it was clearly better than any other templating engines available for php.
Initially, I was creating a model for each table in my database. But as I wrote more code, I found out that much of the code to the models are common. Thats where ActiveRecord component of RoR clicked to my mind. ActiveRecord has a basic CRUD code same for all models. On top of that, individual models define their own methods.
So, I did the same. I carefully wrote CRUD functions, and made this code common to all models. This modular approach was fruitful. Models were tidy now, and the code was easier to manage and debug. Once the CRUD is solid, the models work flawlessly.
Controllers. I must confess, that the habit of writing all-code-in-one-file doesn't go overnight. I wrote a lot of code in controllers, which I shouldn't have. For example, the code for validating user input. Though I had defined helpers like validate_numericality_of and validate_minlength_of etc. in a helpers file, yet writing validation logic in controllers didn't make sense. It took some time for me to realize that validation actually belongs to models, and not to controllers.
Code rearrangement followed. By having all the validation done in models, you relieve controllers of the repetitious job.
For authorization, I'd love to implement something like before_filter in Rails. Since I really couldn't find equivalent, I wrote a model for authorization, and every controller must call a method must_authorize(); if it wants so.
As I write more and more code, I come to realise the beauty of MVC. If you follow the MVC principles strictly, you write less code and error free code. And I also realize how beautifully Rails has implemented MVC architecture.
Rails is no doubt the most productive framework available today for web development. The more you don't use Rails, the more you realize it. :-P
Learning by experimenting is the best way to learn. And while I do, I find myself reinventing Rails. Any coincidence?
Labels:
frameworks,
mvc,
php,
ruby on rails,
spendwrite,
Web 2.0
Subscribe to:
Posts (Atom)