Archive for the ‘ruby’ Category

replacer.rb and deleter.rb

Friday, October 30, 2009

From time to time I find myself needing to replace certain strings globally (eg: in a directory tree), or deleting lines based on a match. I find sed extremely annoying and I don’t manage to get around its syntax. So ruby comes in handy!

replacer.rb

exp_search = '<%=launchBean\.getCustomVersion\(\)%>'
exp_replace = '${xsession.info.launchBean.customVersion}'
directory = '**/'
file_mask = '*.jsp'

Dir.glob(directory+file_mask).each do |file|
  File.open(file, 'r+') do |f|
    content = f.read
    if /#{exp_search}/ =~ content
      s = content.gsub(/#{exp_search}/, exp_replace)
      f.rewind
      f.write s
      puts "#{file}: #{content.split(/#{exp_search}/).size-1} matches"
    end
  end
end

deleter.rb

exp_search = 'useBean.*launchBean'
directory = '**/'
file_mask = '*.jsp'

Dir.glob(directory+file_mask).each do |file|
  count = 0
  content = ""
  File.open(file, 'r+') do |f|
    while line = f.gets
      if /#{exp_search}/ =~ line
        count += 1
      else
        content = content << line
      end
    end
  end
  if count > 0
    File.open(file, 'w') do |f|
      f.write content
      puts "#{file}: #{count} lines deleted"
    end
  end
end

These commands are especially useful if you have to refactor a codebase that doesn’t provide direct support with refactoring tools. In this case, I was refactoring a few hundred JSPs of a legacy system.

Credits to RSF & Ruby One-Liners for most of the code & ideas. rcscript seems to be a bit too much for me at this time, I’m perfectly happy modifying replacer.rb and deleter.rb when I need it.

Advertisements

Running JRuby with Terracotta

Tuesday, October 27, 2009

Lately I have been doing some interesting work integrating Terracotta in our application. We use Terracotta in a very limited scenario: as a tool to implement asynchronous DB replication on PostgreSQL (unfortunately the existing tools out there are not suitable for the kind of usage that we do of PostgreSQL – anyways, I’ll talk more in details about this in further posts).
At a certain point in time we decided to drive some java code with JRuby, in order to process information like log files more efficiently. The java code needed to integrate with Terracotta, so we have had to modify jruby scripts in the following way (eg.: jruby_tc.bat on Windows):

@echo off
rem ---------------------------------------------------------------------------
rem jruby.bat - Start Script for the JRuby Interpreter
rem
rem for info on environment variables, see internal batch script _jrubyvars.bat

setlocal

rem Terracotta
set TC_INSTALL_DIR="C:\Program Files\terracotta\terracotta-3.0.1"
set TC_CONFIG_PATH="C:\whatever\tc-config.xml"
call %TC_INSTALL_DIR%\bin\dso-env.bat -q
set JAVA_OPTS=%JAVA_OPTS% %TC_JAVA_OPTS%

rem Sometimes, when jruby.bat is being invoked from another BAT file,
rem %~dp0 is incorrect and points to the current dir, not to JRuby's bin dir,
rem so we look on the PATH in such cases.
IF EXIST "%~dp0_jrubyvars.bat" (set FULL_PATH=%~dp0) ELSE (set FULL_PATH=%~dp$PATH:0)

call "%FULL_PATH%_jrubyvars.bat" %*

if %JRUBY_BAT_ERROR%==0 "%_STARTJAVA%" %_VM_OPTS% -Xbootclasspath/a:"%JRUBY_CP%" -classpath ^
   "%CP%;%CLASSPATH%" -Djruby.home="%JRUBY_HOME%" -Djruby.lib="%JRUBY_HOME%\lib" ^
   -Djruby.shell="cmd.exe" -Djruby.script=jruby.bat org.jruby.Main %JRUBY_OPTS% %_RUBY_OPTS%
set E=%ERRORLEVEL%

call "%FULL_PATH%_jrubycleanup"

rem 1. exit must be on the same line in order to see local %E% variable!
rem 2. we must use cmd /c in order for the exit code properly returned!
rem    See JRUBY-2094 for more details.
endlocal & cmd /d /c exit /b %E%

The relevant differences are in bold in the batch file above. I’ve called the batch jruby_tc.bat in order to differentiate it from usual jruby.bat. As you can see these changes are for Terracotta 3.0.1 but they should work just the same for Terracotta 3.1

TDD live demo in ruby

Sunday, January 15, 2006

Marco Abis has published all the stuff related to the Second Italian Agile day. This means that there’s also the zip file of all the steps related to my session.

I have collected all the different versions of the code that I was developing during my session, I have cleared them a bit (ie: I have removed insignificant steps, typos, etc.) and I have written a small comment for each step. What I have obtained is a sequence of 49 steps, made by 42 live steps and 7 offline to complete the work. What’s interesting is that first file was saved at 3:40:48 PM, while the last file at 4:41:06 PM ==> it means 42 steps in 62 minutes. Steps have not all the same length of course, but I can assure you that there are always less than 3 minutes between one step and the next one.

(more…)

Lost in time, lost in space

Monday, January 9, 2006

Yesterday I’ve forgotten to add one important point to my post about “Everyday ruby”: after developing the script under Windows with ruby 1.8.2 I recognized I could have put it in crontab on a linux server, where several metrics are already gained or calculated every night. When I tried I had a bad surprise: our old linux server was running debian woody, an old stable release dated 2002, on which only ruby 1.6.7 is available. Hence, some of the libraries that I used were not available. For example, I have used new FileUtils module. After 5 seconds of panic I’ve thought that the script could easily recognize which ruby version is running, deciding to redefine a few methods for backward compatibility. It took me 10 minutes to understand what I was missing and write the following:

def is_old_ruby?
VERSION < "1.8.0"
end

require is_old_ruby? ? 'ftools' : 'fileutils'

if is_old_ruby?
def pwd
Dir.pwd
end
def mkdir_p(path)
Dir.mkdir(path) if !File.exist? path
end
def cd(path)
Dir.chdir(path)
end
else
include FileUtils::Verbose
end

Ugly, but it saved my day.

It took me some more minutes to understand that I needed to invoke shell commands or external programs differently between Windows and linux. Therefore, with a little help from the following method, I’ve simply modified a few invocations accordingly:

def is_win?
is_old_ruby? ? PLATFORM =~ "mswin" : PLATFORM.match("mswin")
end

I know I could have done it the same way with other languages, but believe me when I tell you that backward compatibility with statically typed language is a lot more harder, even in the simplest case like this one.

This is another good reason why choosing ruby for your everyday tasks at the border of your programming environment may be a good idea. Even when java pays the bills.

Everyday ruby

Sunday, January 8, 2006

Some week ago I was doing a peer review of one of my team-mates. We came across one of the objectives that he had since our last review (more than one year and a half ago): P. should have deepen his knowledge and practice of the ruby language. The idea here was partially inspired by PragProg’s concept of “learn a new language every year”. Another source of inspiration came from the hacker’s culture as described by Paul Graham articles.
P. wholeheartly agreed with the objective and slowly started devoting some spare time to study ruby, mainly by means of reading the PragProg’s so called PickAxe book, at that time at his first edition, freely available on the web and automatically installed with ruby. The problem is that everyday job is to develop in java, there is really a little space for ruby in everyday activities.
Infact, P. clearly missed his objective, as he recognized himself as well. I wouldn’t blame him, I know and I have seen that he tried. Apparently there was really no time, nor any significant occasion.

But is this really true?

(more…)

Jim Freeze talking about writing DSLs in ruby

Thursday, December 29, 2005

Jim Freeze has an interesting post about writing DSLs in ruby. Check What is a DSL? – O’Reilly Ruby:

The third time around, after the Ruby DSL hype had been going around for a while, I decided to use Ruby. This time, I was able to create the DSL in about five minutes. It was readable, and I was able to focus on the end users frame of reference.

The moral of this story is, don’t write a mini language if you don’t have too. And, don’t settle for a simple DSL when a full featured one is needed. Consider extending a GPL into a DSL. Particularly an expressive language that is good at creating a readable DSL — like Ruby.

(more…)

Why Ruby is an acceptable LISP

Tuesday, December 6, 2005

Why Ruby is an acceptable LISP, by Eric Kidd

Eric Kidd makes a few fair and thoughtful points about ruby and lisp.

  1. LISP is a dense functional language.
  2. LISP has programmatic macros.

This post has been recognized as well in one of the most important blog of the lisp community. Very good news for ruby diffusion!

Credits to cas for mentioning it.