
Continuous Integration is pretty awesome and there’s a few options out there in the Ruby world. Most of them are more than what I want for my personal projects though, so I decided to hack together my own. I mainly use RSpec and all I wanted was something that would run my spec every time I save it or it’s corresponding class/module. Enter, Speccer.
Speccer really has two parts, a TextMate command that replaces the normal Apple + S shortcut and the command line script that “receives” these saves. Set up your TextMate command like the image above, making sure to duplicate the settings exactly. Then copy in the code below.
1 #!/usr/bin/ruby 2 require 'fileutils' 3 require 'ftools' 4 5 logpath = File.expand_path( "~/log" ) 6 7 unless File.directory?( logpath ) 8 FileUtils.mkdir( logpath ) 9 end 10 11 log = File.open( File.join( logpath, "/spec.log" ), "w" ) 12 log.write "#{ Time.now }\n" 13 log.write "#{ ENV['TM_FILEPATH'] }\n" 14 log.write ENV['TM_PROJECT_DIRECTORY'] 15 log.close
Basically all this does is creates if it doesn’t exist, opens and writes the time, file saved and the project directory to it, every time you hit Apple + S. This acts as a sort of Queue, but in reality the file only ever has one record in it at a time. This is how we let the script in the next part know about when we saved the file.
Create (or in whichever you want) and add the following:
1 #!/usr/bin/ruby 2 require 'ftools' 3 4 log = File.open( File.expand_path( "~/log/spec.log"), "r" ) 5 6 loop do 7 8 trap("INT") { |this| puts ""; exit this } 9 10 last_time = @time 11 12 log.seek(0) 13 record = log.read.split("\n") 14 15 @time = record.first 16 @saved_file = record[1] 17 @proj_path = record.last 18 19 begin 20 21 unless @saved_file.include?( "_spec.rb" ) 22 saved_file_array = @saved_file.split( "/" ) 23 lib_position = saved_file_array.index( "lib" ) 24 spec_filename = File.basename( @saved_file, ".rb" ) << "_spec.rb" 25 spec_dir = saved_file_array[ lib_position+1..saved_file_array.length-2 ].join( "/" ) 26 @spec = "#{@proj_path}/spec/#{spec_dir}/#{spec_filename}" 27 else 28 @spec = @saved_file 29 end 30 31 if last_time != @time 32 system("clear") 33 puts @time 34 system("spec #{@spec} -c -f specdoc") 35 end 36 37 rescue 38 end 39 40 sleep 1 41 42 end
This actual script first opens the log file then just continuously checks to see if the Date is the same as the previous run through. If it is, it won’t do anything, but if it’s new it’ll run the spec. The if-statement in the middle just figures out which spec is associated with the Class/Module file being saved by breaking apart the file’s path and reconstructing it within the folder. Speccer assumes you set up your directory in the same structure as your folder and name your specs . Save the script and and you’re set.
Now just run then go writing your tests/specs and the file needed to make them pass. Every time you save one of them it’ll automatically run. Quick and easy continuous integration for the solo developer.