Day before yesterday, I released my del.icio.us API wrapper gem rubycious. There are a couple of things I learnt while writing it that I’d like to share here. To give you a heads up on what’s inside:
If that’s piqued your curiousity click on through.
Before I go any further, I must warn you that some of the choices I’d made, design-wise weren’t exactly the smartest and I know that. But given those choices, I was faced with certain problems that had to be solved and I’m glad that it led me to learn about some cool Ruby meta-programming.
This is a class method which any object of type Class has(by that I mean, of course, any ruby Class (Ain’t ruby grand!)). It takes a block and dynamically puts the contents of that block inside your class. Now this is only useful if you have to dynamically add stuff to your class. One oft-used use case of this facility is in conjunction with self.included. Trivially though the following should illustrate what class_eval can do
class A
def do_something
something
end
end
A.class_eval do
def something
puts "Hello World!"
end
end
Now there are a couple of other methods in the eval family, namely, instance_eval(1)(2), module_eval(just an alias for class_eval) and just eval(1). They’re equally cool and useful and to pretty much the same thing so I’ll leave it to you to discover more about them.
This is basically a call_back defined for any module. When it gets included in a class this method is run. The reason I’m calling it self.included is usually its usage goes something like this:
module B
def self.included(base)
puts base.class
end
end
However the really interesting use case, like I mentioned earlier comes up when I put it together with class_eval like I did in Rubycious here. The module ClientHelper was meant to be included in any class that was a client and I didn’t want to redefine some of the httparty declarations in each of these classes.
This one is pretty basic and chances are you probably know about this one. If not you really should. Basically method_missing is the method called when a method called on an object is not found. It takes a symbol which contains the name of the missing method and and array of the arcuments passed to that method. The great thing about method missing is that it can be used to generate an arbitrary number of methods. See more here
YARD has emerged as the standard for documenting ruby projects of late, taking over from rdoc, and after using it to document rubycious, I can see why. YARD uses a tagging based approach to documentation. It uses directives like @param, @return, @see, @author etc. to structure your documentation and give nicely readable docs in a variety of formats. Read more about why you should use YARD here. Here is an example of code documented with YARD from rubycious:
# Use for searching all URLs
# NOTE: Use Sparingly. Call the update function to see if you need to fetch this at all.
# @todo Look into caching these results
# check the last update time before performing
# @param [Hash] options for searching for the URL (all optional)
# @option options [String] :tag |optional| "ruby"
# @option options [String] :start |optional| Integer: Start returning posts this
# many results into the set
# @option options [String] :results |optional| Integer: Return these many results
# @option options [String] :fromdt |optional| Format: Time#iso8601: On this date or later
# @option options [String] :todt |optional| Format: Time#iso8601: On this date or earlier
# @option options [String] :meta |optional| yes/no: Include change detection signatures
# on each item in a 'meta' attribute. Clients wishing to maintain a
# synchronized local store of bookmarks should retain the
# value of this attribute - its value will change when any
# significant field of the bookmark changes.
# @return [Array<:post>]
# @see Time#iso8601
def find(options)
response= handle_errors { self.class.get('/all', :query => options)}
response["posts"]["post"].collect{|i| Rubycious::Post.new(i)}
end
See more here
I used echoe for packaging and releasing the gem. Basically echoe creates a bunch of rake tasks for you that take you through the process of creating a gem. So, first you need to define a couple of defaults in your Rakefile:
require 'rubygems'
require 'rake'
require 'echoe'
Echoe.new('rubycious', '0.1.1') do |p|
p.description = "Ruby wrapper to the del.icio.us API"
p.url = "http://github.com/rjsvlajean/rubycious"
p.author = "Ratan Sebastian"
p.email = "rjsvaljean@gmail.com"
p.ignore_pattern = ["tmp/*", "script/*"]
p.development_dependencies = ["httparty"]
end
Dir["/tmp/tasks/*.rake"].sort.each { |ext| load ext } e
Next assuming that all your code is in your lib directory and you have a file having the same name as your gem in there, run:
$ rake manifest
$ rake build_gemspec
$ gem build rubycious-0.1.1.gemspec
$ gem push rubycious-0.1.1.gem
And that’s about it for now. I plan on doing a rewrite with a bit of a better design soon but for now Rubycious is pretty stable for those using basic auth. I’ll add oauth support soon in a couple of days and I’ll document the procedure here.
So, I’ve been using vim for my ruby/rails dev of late and I thought I’d share a few things I picked up along the way. Another tool that I’ve begun relying on heavily is GNU screen. It didn’t make sense to put that in a separate post so I’m going to include some of my screen setup here as well. This is primarily aimed at people who’ve already begun with vim and are looking for examples of development setups.
One of the core features of vim that you’ll find amazingly useful is the split screen. Incredibly useful when dealing with multiple files that you constantly have to refer to(while writing tests for instance). For more about some handy core features have a look at my .vimrc. Of course the real power of vim is in its amazing repository of plugins(advantage of being a nearly 20 year old project). Some of the ones that I find indispensible are:
For my complete .vim folder clone git://github.com/rjsvaljean/vim_config.git
GNU screen is one of those tools, that, once you’re exposed to will become essential to any sort of terminal intensive work that you do. I like to think of it as a window manager for your terminal. It basically hosts a bunch of terminals in different windows(tabs) and makes sure that you never have to Alt-Tab again. But of course its much more than that the killer feature is that ability to detach screen sessions. I do most of my development on a laptop which I almost never shutdown. So I’m working in my screen for project A, when I need to switch, I don’t need to worry about shutting down the various programs safely. I just need to detach the session and re-attach when I need it. This way I get back to work with no interuptions. It nicely allows you to keep all the terminal based programs that you run with a particular project in one place.
As I’d put in the list of plugins this ties vim, irb and screen together nicely. Next master fugitive(which is alarmingly simple to use) and you’ve got SCM integration in your editor. Its starting to look more like an IDE, isn’t it? Now sugar coat the whole deal by opening vim up in your project directory within a screen session. But of course development seldom involves just your editor so go ahead and open a bung of windows for your REPL, your test running window, IRC client etc. etc. But you don’t want ot keep repeating this every time you start a screen session of a different project. What I do is create a project specific .screenrc which in my project root directory with a bunch of screen -t declarations to open the windows that I need for that project and add an alias to my ~/.bashrc. Something like:
alias work="screen -c .screenrc"
This I find works pretty well. Additionally the irb_slime plugin I’d mentioned eariler requires you to specify the screen session name and the name of the window where your REPL is running. You only have to do this the first time but its still pretty annoying. To automate things further do the following in your .screerc
screen -t vim 0 vim -c 'let g:screen_sessionname=session'\
-c 'let g:screen_windowname=repl'
That makes sure that once you execute work in your project directory you’re all ready to start hacking.
Hope this helps!
Everyone knows how to setup passenger and apache on a linux box. But if you have multiple apps, its a pain keeping track of all the localhost port numbers that point to each of them. In this article I discuss you can have addresses like myapp.mybox.lan to point ot specific apps. I’ve written this for a linux system but it should work just as well for a Mac. Also, I haven’t tried this out with ngnix. I’ve also gone through the setting up of Passenger for those of you who still use script/server.
Installing the passenger apache modules is as easy as:
$ gem install passenger
$ passenger-install-apache2-module
That will download and compile passenger’s apache modules. Once compiled the installer will give you instructions to load these modules using apache configuration directives. You’ll probably have to edit your apache configuration file for that. If you’re on linux, these will probably be in /etc/apache2/[apache2.conf|httpd.conf]. Just append the three lines that the installer gives you to this file. They’ll look something like this:
LoadModule passenger_module /home/rjsvaljean/dev/ruby/lib/ruby/gems/1.8/gems/passenger-2.2.11/ext/apache2/mod_passenger.so
PassengerRoot /home/rjsvaljean/dev/ruby/lib/ruby/gems/1.8/gems/passenger-2.2.11
PassengerRuby /home/rjsvaljean/dev/ruby/bin/ruby
Once that’s done lets create our rails app in /path/to/app/blog. In order to demonstrate how to create different addresses for different apps create another app at /path/to/app/todolist. Say that we want those two apps accessible at blog.lan and todolist.lan. Notice that I’ve use the TLD .lan but that’s completely aribitrary. You can use anything that you want. Now comes the bit where we tell your computer to got to localhost when you point your browser to blog.lan. For this we need to edit our /etc/hosts file. You’ll need to be root to edit it. Add the following two lines:
127.0.0.1 blog.lan
127.0.0.1 todolist.lan
Now we need to instruct apache where to look when it gets a request for blog.lan. Open up the config file once more. First you need to declare that Named VirtualHosts are running on post 80 - your default port for http requests. To do that:
NameVirtualHost *:80
Now define your VirtualHost sections:
<VirtualHost *:80>
ServerName blog.lan
DocumentRoot /path/to/app/blog/public
</VirtualHost>
<VirtualHost *:80>
ServerName todolist.lan
DocumentRoot /path/to/app/todolist/public
</VirtualHost>
Now reload apache with ‘/etc/init.d/apache2 reload’ and you’re done. Pointing your browser to blog.lan or todolist.lan whould show you the default rails page for a new app.
I recently had to set up some cron jobs from an app that I was writing. I learned a couple of things so I thought I’d put them here. I’ve covered setting up precisely fortnightly cron jobs, setting up the whenever gem and how I tackled some of the errors that I came up against while trying to set it up.
Setting up precisely fortnightly jobs that need to run on every other monday is quite easy. You don’t have to settle for just running the jobs on the 1st and the 15th. Set your job to run onw whichever day of the week that you want it to and set it to run every week. Include this in the actual command to be run:
expr `date +\%W` \% 2 > /dev/null || fortnightly_script.sh
Whenever( github link ) is a nifty gem that you can use to modify your crontab easily from your application using some sort of capistrano recipie of rake task. First off install the gem with
$ gem install whenever
$ wheneverize # Excute this inside your app to setup the necessary files
Now edit the schedule.rb file where you can easily define your jobs in plain ruby. Now you can run the binary whenever —update-crontab to update your crontab cleanly from your capistrano recipies. When I tried to run the command however I ran into some difficulties. Read on …
I ran into this error while trying to use the whenever gem in my app. Whenever I tried to run the whenever command I got this error:
./Rakefile:3: undefined method `import' for main:Object (NoMethodError)
from /opt/ruby-enterprise-1.8.7-2009.10/lib/ruby/gems/1.8/gems/whenever-0.4.1/lib/whenever.rb:5:in `load'
from /opt/ruby-enterprise-1.8.7-2009.10/lib/ruby/gems/1.8/gems/whenever-0.4.1/lib/whenever.rb:5
from /opt/ruby-enterprise-1.8.7-2009.10/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
from /opt/ruby-enterprise-1.8.7-2009.10/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
from /opt/ruby-enterprise-1.8.7-2009.10/lib/ruby/gems/1.8/gems/whenever-0.4.1/bin/whenever:7
from /opt/ruby-enterprise-1.8.7-2009.10/bin/whenever:19:in `load'
from /opt/ruby-enterprise-1.8.7-2009.10/bin/whenever:19'''''
I fixed this by adding
require 'rake'
at the beginning of my Rakefile. I’m still not sure what exactly the problem was and how that line solved it. Maybe some of you more knowledgeable netizens could clear it up.