Tatva-Artha

meaning of "it"

Archive for July, 2009

Grails TDD simplified

without comments

Let me start by saying that Testing Grails sucks. This is not to say that there aren’t supporting tools and technologies. There is super classes GrailsUnitTestCase, GroovyTestCase etc. and there is few solutions for mocking needs. However, in general, the cycle of writing a failing test, execute to fail, some code to make is pass, execute to verify passed and refactor takes a long time. This “long time” phrase is relative and I mostly compare with folks coming from plain-old Java world or from Ruby world. I have experience with both and grails is slow relative to both.

Of course there is some progress being made so that you are able to run specific test class using following command:

# specify <Class> without the trailing "Tests"
$ grails test-app [-unit | -integration ] <Class>

The above command makes is so that you don’t have to run entire test suite. This still leaves a few things desirable:

  • The user still have responsibility to specify -unit or -integration depending on which test is being run. The framework doesn’t figure this out automatically.
  • The above command won’t fail is the specified test class is not found.
  • When the test fails, the stack trace is long, long, very long. It takes pathetically long time to find the line that points to the problem in your test.

So, I wrote following script (in Ruby!) to resolve above issues.

Script: gtest

#!/usr/bin/ruby
 
if ARGV.length != 1
 puts "Expected 1 argument."
 exit -1
end
 
test_name=ARGV[0]
 
unit_or_int=""
test_file_found=false
if File.exists?("test/unit/#{test_name}Tests.groovy")
  test_file_found=true
  unit_or_int="-unit"
elsif File.exists?("test/integration/#{test_name}Tests.groovy")
  test_file_found=true
  unit_or_int="-integration"
else
  puts "No Unit or Integration test found for #{test_name}"
  exit -1
end
testfile="test/reports/plain/TEST-#{test_name}Tests.txt"
#system("touch #{testfile}")
cmd="touch #{testfile}; (grails test-app #{unit_or_int} #{test_name} &); tail -f #{testfile} | filter_groovy_trace"
puts cmd
exec(cmd)

Script: filter_groovy_trace

grep -Ev "at org.codehaus.|at groovy.lang|at gant.Gant|at TestApp_groovy|--Output from test|--------|at org.gmock.internal|^Testcase: |at sun.reflect| at net.sf.cglib|at java.lang.reflect"

With these two scripts in my path all I need to do is:

gtest <Class>

I have been using it for over a month and it has served me well. It still doesn’t come close to what you could do in Java (execute individual test from inside IDE) or ruby (the java runtime initialization takes for ever compared to ruby runtime), but it reduces the pain considerably.

There is one more thing we can do to make it faster. Take out the xsl transformation at the end of test execution. I couldn’t find the command line option for that. I know it exists.

Reduced Pain => Enjoy!

Written by Sharad

July 29th, 2009 at 8:08 pm

Posted in All

Executing Mysql command on remote machine using Capistrano

without comments

On a project recently, I needed to frequently clear out some database table on staging server. Since I was going to need it occasionally for the foreseeable future, I wanted to add a capistrano task. Capistrano is good for this kind of stuffs, however what made this one interesting is the fact that the mysql command doesn’t take password on the command line, for obvious reasons. This was tricky until I remembered that deprec gem does offer ability to create databases on remote machine.

Crack opened the deprec gem and found interesting solution. Here is how one of the mysql task looks like inside deprec:

desc "Create a database" 
task :create_database, :roles => :db do
  cmd = "CREATE DATABASE IF NOT EXISTS #{db_name}"
  run "mysql -u #{mysql_admin_user} -p -e '#{cmd}'" do |channel, stream, data|
    if data =~ /^Enter password:/
       channel.send_data "#{mysql_admin_pass}\n"
     end
  end       
end

So, I ended up doing this:

task :delete_confs do
  cmd = "delete from <table>; select count(*) from table"
  run "mysql -h <host> -u <user> -p <database> -e \"#{cmd}\"" do |channel, stream, data|
    if data =~ /^Enter password:/
      channel.send_data "pword\n"
    end
    puts data # data gets updated after mysql command executes!
  end
end

This turned out all working great.

Another interesting thing I found is that the “data” variable inside the block is kept updated with latest output from the ssh command. I could not have guessed this initially since you would expect it to be statically holding “Enter password:” and that’s it for the length of block.

Capistrano uses Net::SSH underneath so I am guessing there could be more options for even lower level access. And, yes there may be bash shell solution to this entire problem. The goal here was to create a capistrano task which fits will with ruby/rails development in general.

Fun stuff!

Written by Sharad

July 29th, 2009 at 6:34 pm

Posted in All

Converting all .html.erb views to .haml

without comments

After trying haml and sass on a few occasions, I am sold. Recently, I needed to convert all my /app/views/**/*.html.erb views into /app/views/**/*.haml and I ended up writing a rake task as follows:

require 'haml'
require 'haml/exec'
 
namespace :haml do
  task :convert do
    Dir.glob("app/views/**/*.html.erb").each do |html|
      puts html + "..."
      Haml::Exec::HTML2Haml.new([html, html.gsub(".html.erb", ".haml")]).process_result
      File.delete(html)
    end
  end
end

This did the trick. There was only one minor thing I had to fix with the new *.haml files. The blocks with an “<%= end %>” were converted into “- end”. Instead the correct format was to not use “- end” and properly indent the code inside block.

So, for example, a .html.erb code as follows:

<% form_for @booking do |f| %>
<%= f.error_messages %>
<%= f.label :booking_reference %>
<%= f.text_field :booking_reference %>
<%= f.label :remarks %>
<%= f.text_area :remarks %>
<p>
  <%= f.submit "Submit" %>
</p>
<% end %>

was converted to:

- form_for @booking do |f|
= f.error_messages
= f.label :booking_reference
= f.text_field :booking_reference
= f.label :remarks
= f.text_area :remarks
%p
  = f.submit "Submit"
- end

Instead, it should have been:

- form_for @booking do |f|
  = f.error_messages
  = f.label :booking_reference
  = f.text_field :booking_reference
  = f.label :remarks
  = f.text_area :remarks
  %p
    = f.submit "Submit"

Once I fixed this manually (and it could be a lot if you have lots of files), it all worked as expected.

Written by Sharad

July 26th, 2009 at 7:47 pm

Posted in All

Behavioral Economics 2: Sales tactics for the downturn

without comments

WSJ had a recent article on how a luxury wrist-watch seller manages to sell expensive watches in such times of recession. A few good tips, that apply to other fields in some form or another are:

  • If customer asks for price of an item, say “the *value* is $xx”. Use the word “value” instead of “price”. Fair enough.
  • If customer shows interest in one of your products, do not ask yes/no type question. Yes/No question has at most a 50/50 chance of going positive. Instead, invite them to try. In short, don’t offer them an easy way out.
  • Focus on decision maker, don’t ignore others. With regard to watch purchase, the article talks about keeping the wife occupied while husband is looking to buy expensive watch. If wife is left-out, she might feel bored and will look for a way out.
  • Make necessity and benefits of your product apparant. Keep their current (old) watch in between 2 brand new watch, to signify it is time to upgrade. Sneaky but, I guess, it can work.

Atleast some of these should apply to software consulting also. Nice article indeed.

Written by Sharad

July 25th, 2009 at 8:53 pm

Posted in All

Behavioral Economics: understanding human reasoning for marketing and sales

without comments

Business Week’s latest issue has an article on how companies analyze human reasoning and behavior to increase marketing and sales. It talks about 2 things:

  • Present Bias: People are more inclined to focus on immediate hassles of changing a habit than future benefit. To me, this also explains the laziness which prevents most of us from achieving big results, on personal or professional level.
  • Loss Aversion: People work harder to avoid losses than to pursue gains. This led the company to change the words in their advertisements from “save money” to “stop wasting money”. Again, very true in day to day context. We start doing exercise after encountering major disease, not before. It is a “loss aversion” after we have already encountered disease where as it was just a “potential benefit” before then.

My takeaway: Restate my “future-benefit” goals into a “loss-aversion” goals and, may be, I will have a better chance of achieving it :-)

Written by Sharad

July 25th, 2009 at 4:08 pm

Posted in All

Ruby gotcha: defining class in ruby

without comments

Coming from Java this may be a little surprise that order of class initialization (order of method definitions) does impact the outcome of your program, as I just found out.

For example, consider 2 cases where I define a singleton class:

Case-1:

class A
  @@instance = A.new
  def self.instance
    @@instance
  end
  attr_reader :x
  private
  def initialize
    @x = 99
  end
end

Output:

>> A.instance.x
=> nil

Case-2:

class A
  private
  def initialize
    @x = 99
  end
  @@instance = A.new
  public
  def self.instance
    @@instance
  end
  attr_reader :x
end

Output:

>> A.instance.x
=> 99

The location of constructor/initialize() is different. And as we can see from output, the our constructor isn’t yet defined when A.new() was called in the first case and hence the @x instance variable didn’t get initialized the way we would have expected it to. The execution doesn’t complain since it uses the default/inbuilt constructor until our constructor gets defined.

Now I know.

Written by Sharad

July 23rd, 2009 at 8:19 pm

Posted in All

Producer/Consumer using beanstalkd in Ruby

with 2 comments

Got basic queueing to work in ruby using beanstalkd/beanstalk-client.

Producer.rb

#!/usr/bin/env ruby
 
require 'rubygems'
require 'beanstalk-client'
 
beanstalk = Beanstalk::Pool.new(['localhost:11300'])
while(true) do
	sleep(10)
	puts "posting message ..."
	beanstalk.put(Time.now.to_s)
end

Consumer.rb

#!/usr/bin/env ruby
 
require 'rubygems'
require 'beanstalk-client'
 
beanstalk = Beanstalk::Pool.new(['localhost:11300'])
loop do
  job = beanstalk.reserve
  puts job.body
  job.delete
end

Commands:

$ beanstalkd -d -p 11300
$ ./producer.rb
# consumer in a different terminal
$ ./consumer.rb

Enjoy!

Written by Sharad

July 21st, 2009 at 9:37 pm

Posted in All

Installing beanstalkd on ubuntu

with one comment

Here is a commad dump for installing beanstalkd on ubuntu.

$ wget http://xph.us/dist/beanstalkd/beanstalkd-1.3.tar.gz
$ tar zxvf beanstalkd-1.3.tar.gz
$ rm beanstalkd-1.3.tar.gz
$ cd beanstalkd-1.3/
$ ./configure

You might run into following error:

configure: error: Unable to locate libevent headers, please use --with-event=DIR

If so, install "libevent-dev" package.

$ sudo apt-get install libevent-dev

..continue..

$ ./configure
$ make
$ sudo make install

At this point, beanstalkd should be installed in proper location. Verify:

$ which beanstalkd

Enjoy!

Written by Sharad

July 21st, 2009 at 9:04 pm

Posted in All

Installing mysql based gems on ubuntu

with one comment

When intall Datamapper’s mysql adapter, do_mysql gem you man run into installation failure such as:

/usr/bin/ruby1.8 extconf.rb install do_mysql

checking for mysql_query() in -lmysqlclient… no
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of
necessary libraries and/or headers. Check the mkmf.log file for more
details. You may need configuration options.

Solution:

$ sudo apt-get install libmysqlclient16-dev

Written by Sharad

July 21st, 2009 at 7:31 pm

Posted in All

Generating hashed passwords from commandline

with 3 comments

ruby -r ‘digest/sha1′ -e ‘puts Digest::SHA1.hexdigest("password")’

Written by Sharad

July 21st, 2009 at 6:58 pm

Posted in All