[ANN] rails_best_practices 0.6.6 released

flyerhzm Posted by flyerhzm on January 24, 2011

Comments

I just released rails_best_practices 0.6.6. It gives a big improvement for html output. The changes in 0.6.6 are as follows:

1. Don't check protected/private methods for use_before_filter_check.

2. Add link url to the errors in rails_best_pracitces html output, bringing you to the best practice you violate.

3. Support rhtml (I forgot it before)

4. Add link url to the filenames in rails_best_practices html output, bringing you to textmate who will open that file with that line number.

Check it here: https://github.com/flyerhzm/rails_best_practices

Autotest your rubygem

flyerhzm Posted by flyerhzm on January 18, 2011

Comments

Last blog post, I have introduced how to use bundler and rvm to build a rubygem, today I will say something about testing a rubygem. 

RSpec

RSpec is a Behaviour-Driven Development tool for Ruby programmers. It's an alternative to ruby unit test framework. If you are going to use rspec to test your rubygem, I strongly recommend you to use rspec2, which does a lot of improvement from rspec1. Check more info here: http://relishapp.com/rspec.

I don't want to teach you how to use the rspec, I just give you a short instruction.

  1. define spec_helper.rb
  2. write spec tests, one spec file corresponds to one lib file
  3. use rspec SPEC_FILES to test

It would be better to display the test result with color and nested format, just define .rspec file as follows

--format nested
--color

Autotest

It's fine that you type rspec command to test your spec files each time, but the better way is to make tests run automatically. It really saves your time.

autotest is also easy to use, to install it

gem install autotest

If you work on Mac OS X 10.5 or higher, the following two gems are also helpful

gem install autotest-fsevent autotest-growl

autotest-fsevent makes filesystem modification detection more efficient.

autotest-growl sends test results to growl notification.

then define the global autotest configuration in ~/.autotest

# Include plugins
require 'autotest/fsevent'
require 'autotest/growl'
 
# Skip some paths
Autotest.add_hook :initialize do |autotest|
  %w{.git .DS_Store ._* vendor}.each { |exception| autotest.add_exception(exception) }
  false
end

and integrate autotest with rspec2, add a file in your rubygem ./autotest/discover.rb

Autotest.add_discovery { "rspec2" }

After that, you can type autotest at the root directory of your rubygem, you will see all the spec files are running and get the test results. The test process is as follows

  1. You write some codes/specs that make the tests failure.
  2. Autotest runs that modified specs (or spec according to modified codes) and get failures, then you will see the growl notification who tells you your tests failed.
  3. You change your codes/specs to fix the failures.
  4. Autotest runs that modified specs again and get success. then you will see the growl notification who tells you your tests passed.
  5. Autotest runs all the specs that check if your modification affects other codes/specs, then you will see the growl notification who tells you if your all tests passed or failed. 

I'm really glad to play with autotest, but there is a problem if it takes a long time (more than several minutes) to run all the tests. As each time you fix the failures, autotest will run all the specs again for you, that means each time I fix failures, I have to wait a long time which is not I expect.

Watchr

Watchr is a modern continuous testing (flexible alternative to Autotest). The flexible means you can define the test strategy about when to test and test what files. The following is the .watchr example for rails_best_practices gem.

def growl
  title = "Watchr Test Results"
  image = $?.success? ? "~/.watchr/images/passed.png" : "~/.watchr/images/failed.png"
  message = $?.success? ? "success" : "failed"
  growlnotify = `which growlnotify`.chomp
  options = "-w -n Watchr --image '#{File.expand_path(image)}' -m '#{message}' '#{title}'"
  system %(#{growlnotify} #{options} &)
end

def run(cmd)
  puts cmd
  system(cmd)
end

def spec(file)
  if File.exists?(file)
    run("rspec #{file}")
    growl
  else
    puts("Spec: #{file} does not exist.")
  end
end

def run_all_specs
  run "rake spec"
  growl
end

def run_suite
  system "clear"
  run_all_specs
end

watch("spec/.*/*_spec\.rb") do |match|
  puts(match[0])
  spec(match[0])
end

watch("lib/(.*/.*)\.rb") do |match|
  puts(match[1])
  spec("spec/#{match[1]}_spec.rb")
end

# Ctrl-\
Signal.trap 'QUIT' do
  puts " --- Running all tests ---\n\n"
  run_suite
end

# Ctrl-C
Signal.trap 'INT' do
  if @interrupted then
    abort("\n")
  else
    puts "Interrupt a second time to quit"
    @interrupted = true
    Kernel.sleep 1.5
    # raise Interrupt, nil # let the run loop catch it
    run_suite
    @interrupted = false
  end
end

What the watchr configuration do are

  1. watch the codes in lib directory, if any file modifications occur, run the corresponding spec file.
  2. watch the codes in spec directory, if any file modifications occur, just run the spec file.
  3. after each spec running, send growl notification.
  4. type Ctrl + \ to run all tests.
  5. type Ctrl + C to stop test.

While I'm developing the rails_best_practices gem, I always run watchr .watchr at the terminal, so whenever I changed the codes/specs, I will got a notification from growl, it makes me more efficient to write robust rubygem. I hope it is also helpful to you.

Enjoy autotest for your rubygem!

Using bundler and rvm to build a rubygem

flyerhzm Posted by flyerhzm on January 15, 2011

Comments

Introduction

Bundler and RVM are two of the most important tools for me to develop ruby/rails projects, especially make it easier to build a rubygem. Here I will describe how I use them to build the rails_best_practices gem.

RVM

RVM is a command line tool which allows you to easily install, manage and work with multiple ruby environments from interpreters to sets of gems. I recommend you to install rvm before you starting to develop ruby/rails projects. Check it here: http://rvm.beginrescueend.com/.

Bundler

Bundler is a tool that manages gem dependencies for your ruby application. It is recommended to install bundler in rvm global gemset because the gems in global gemset can be also used in other gemset.

rvm gemset use global
gem install bundler

Check more info about bundler here: http://gembundler.com/

Generate rubygem skeleton

After installing rvm and bundler, we can start to build a rubygem. Bundler provides a way to generate a skeleton for creating a rubygem.

bundle gem GEM_NAME

change the GEM_NAME to your rubygem name, such as rails_best_practices, the following is the skeleton generated

create  rails_best_practices/Gemfile
create  rails_best_practices/Rakefile
create  rails_best_practices/.gitignore
create  rails_best_practices/rails_best_practices.gemspec
create  rails_best_practices/lib/rails_best_practices.rb
create  rails_best_practices/lib/rails_best_practices/version.rb

Let's go through these files one by one.

1. rails_best_practices.gemspec, it's the rubygem specification file, you can define the author, summary, description of this rubygem, add the dependencies and development dependencies, and define the files and executables which should be packaged into .gem. The following is the source code of rails_best_practices.gemspec.

# -*- encoding: utf-8 -*-
require File.expand_path("../lib/rails_best_practices/version", __FILE__)
Gem::Specification.new do |s|
  s.name        = "rails_best_practices"
  s.version     = RailsBestPractices::VERSION
  s.platform    = Gem::Platform::RUBY
  s.authors     = ["Richard Huang"]
  s.email       = ["flyerhzm@gmail.com"]
  s.homepage    = "http://rails-bestpractices.com"
  s.summary     = "a code metric tool for rails codes."
  s.description = "a code metric tool for rails codes, written in Ruby."

  s.required_rubygems_version = ">= 1.3.6"

  s.add_dependency("ruby_parser", "~> 2.0.4")
  s.add_dependency("ruby-progressbar", "~> 0.0.9")
  s.add_dependency("colored", "~> 1.2")
  s.add_dependency("erubis", "~> 2.6.6")
  s.add_dependency("haml", "~> 3.0.18")
  s.add_dependency("i18n")
  s.add_dependency("activesupport")

  s.add_development_dependency("rspec", "~> 2.0.1")
  s.add_development_dependency("watchr", "~> 0.6")
  s.add_development_dependency("bundler", ">= 1.0.0")

  s.files         = `git ls-files`.split("\n")
  s.test_files    = `git ls-files -- {test,spec,features}/*`.split("\n")
  s.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
  s.require_paths = ["lib"]
end

2. Gemfile, it's a format for describing gem dependencies for ruby programs used by Bundler. In common you don't need to change it, the following is the generated Gemfile.

source "http://rubygems.org"
gemspec

As you seen, it uses gemspec which tells Bundler the gem dependencies are defined in .gemspec file.

3. lib/rails_best_practices.rb, it is the main file where you write or require your logic codes.

4. lib/rails_best_practices/version.rb, it defines the version of the rubygem.

5. Rakefile, define the rake tasks to build, install and release your rubygem.

Gemset for your rubygem

RVM's gemset provides you a isolated rubygems environment, you can install the gems without gem version conflicts.

First you should create a gemset for your rubygem, what I always do is creating a .rvmrc file under the root directory of rubygem, here is the example of rails_best_practices gem.

rvm_gemset_create_on_use_flag=1
rvm gemset use rails_best_practices

It means whenever you enter the directory of rails_best_practices gem, rvm will create or use the gemset.

'rails_best_practices'. Let's make the gemset take effect, just leave and re-enter the rubygem directory.

$ cd ..
$ cd rails_best_practices
Now using gemset 'rails_best_practices'

As you seen, when you re-enter the rails_best_practices, rvm tells you the gemset 'rails_best_practices' take effects. Next we should use bundler to install the gem dependencies.

$ bundle install

Bundler will install all the dependent gems in the 'rails_best_practices' gemset.

Release your rubygem

For now, we have generated the skeleton of our rubygem and installed dependent gems. Next we can write any logic codes for your rubygems, test, and release them. I will introduce about test in the next blog post, here I will show you how to release your codes.

Suppose we have completed the rubygem or added a new feature, we want to release it. It's really easy, what you should do is changing the version number in lib/rails_best_practices/version.rb, from 0.0.1 to 0.1.0, then run rake task

rake release

After that, it will add a tag "0.1.0" to your git repository, build rails_best_practices.gem, and push the gem to rubygems.org. Then everybody can install your new rubygem.

That's all, with the help of rvm and bundler, writing a rubygem is as easy as possible. And you will see more benefits of rvm and bundler in my next blog post about testing a rubygem.

[ANN] rails_best_practices 0.6.5 released

flyerhzm Posted by flyerhzm on January 04, 2011

Comments

It's still a bug fixed version.

From 0.6.3, I added the html output. I put a result.html.haml file under assets directory, which is the html output template.

I defined the files, executables in the gemspec as follows

s.files        = Dir.glob("lib/**/*") + %w(rails_best_practices.yml MIT_LICENSE README.md) 
s.executables = ["rails_best_practices"] 
s.require_paths = ["lib"]

The problem is that if I add a new file/directory or an executable, I have to add it on gemspec explicitly. But I forgot adding assets directory to files, it's my fault. Now I change it to the codes which bundler generated.

s.files         = `git ls-files`.split("\n") 
s.test_files    = `git ls-files -- {test,spec,features}/*`.split("\n") 
s.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 
s.require_paths = ["lib"]

So I don't need to change the gemspec anymore when I add new file/directory or executable.

[ANN] rails_best_practices 0.6.4 released

flyerhzm Posted by flyerhzm on January 01, 2011

Comments

@faisal reported the issue that the colorful output of rails_best_practices is not compatible with metric_fu gem, it's an urgent issue as I added this colorful feature from 0.4.1 version more than 3 months ago.

So I quickly added a new command option --without-color, so the output with this option will be the same as the output before 0.4.1, and upgrade the rails_best_practices to 0.6.4 version.

Then I added a pull request to metric_fu, using --without-color option. Before @jscruggs merge this pull request, you can use my fork of metric_fu here. Enjoy the metric_fu with rails_best_practices!