Rubyをちょろっと始めました

いい加減「スクリプト言語bashしか使えません」状態はヤバいなぁと思ってRubyをちょろっと始めました。まだ右も左も分かりません。

今日はpythonのrelpath関数みたいなのがRubyには見当たらないー!と思って自作してしまったのですが、実はPathname#relative_path_fromってのがあることが判明。早まりました。大ショック。

とりあえずRuby初心者がコーディングするとこうなる記録としてソース貼っておきます。文字列のスライス周りとかもっと奇麗に短くかける方法がある気がする…というかあるよね…。

!/usr/bin/ruby                                                                                               
def normalize ( path )
  ret = [];
  path += "/" if path.end_with?('.') || path.end_with?('..');
  for e in "^#{path}$".split('/') do
    if e == '..' then
      ret.pop;
    elsif e != '.' && e != '' then
      ret.push(e);
    end
  end
  return ret.join('/')[1..-2];
end

def rel_path ( dest, base )

  base = normalize(base);
  dest = normalize(dest);

  sa = base.split('/');
  da = dest.split('/',-1);

  i = 0;
  while i < sa.length && sa[i] == da[i] do
    i = i + 1;
  end

  if (sa[0]==''?1:0) < i then
    return '../' * (sa.length - i) + da[i..-1].join('/');
  end

  return dest;

end

Rubyは言語としてはすごくコンパクトかつきれいにプログラムが書けそうでいいなぁと思いましたが、ライブラリ類がちょっと違和感あり。"/a/b/c/".split('/') の結果が[ '', 'a', 'b', 'c', '' ]じゃなくて[ '', 'a', 'b', 'c' ]になるのがデフォなのはどうかなと思う。普通にCSVの解析とかで事故るような…ってやっぱ驚いてる人いますね

で、テスト。

def test_rel_path(dest,base,expect)
  ret = rel_path(dest,base);
  puts "rel_path('%s','%s')='%s'" % [ dest, base, ret ];
  if(ret!=expect) then
    puts "Error: expecting result=" + expect;
  end
end

test_rel_path('/etc/my.cnf', '/etc/', 'my.cnf');
test_rel_path('/etc/./my.cnf', '/etc/samba/../',  'my.cnf');
test_rel_path('/etc/my.cnf', '/etc/', 'my.cnf');
test_rel_path('/etc/my.cnf', 'etc/', '/etc/my.cnf');
test_rel_path('/var/log/httpd/httpd.conf', '/var/log', 'httpd/httpd.conf');
test_rel_path('/var/log/messages', '/var/log/httpd/','../messages');
test_rel_path('/var/log/messages', 'var/log/httpd', '/var/log/messages');
test_rel_path('var/log/messages', '/var/log/httpd', 'var/log/messages');
test_rel_path('/etc/cron.d/', '/var/log/httpd', '/etc/cron.d/');
test_rel_path('/etc/cron.d', '/var/log/httpd', '/etc/cron.d');
test_rel_path('var/bar/', 'var/log/httpd', '../../bar/');
test_rel_path('/var/log/messages', '/var/log/httpd/../', 'messages');

実行結果

rel_path('/etc/my.cnf','/etc/')='my.cnf'
rel_path('/etc/./my.cnf','/etc/samba/../')='my.cnf'
rel_path('/etc/my.cnf','/etc/')='my.cnf'
rel_path('/etc/my.cnf','etc/')='/etc/my.cnf'
rel_path('/var/log/httpd/httpd.conf','/var/log')='httpd/httpd.conf'
rel_path('/var/log/messages','/var/log/httpd/')='../messages'
rel_path('/var/log/messages','var/log/httpd')='/var/log/messages'
rel_path('var/log/messages','/var/log/httpd')='var/log/messages'
rel_path('/etc/cron.d/','/var/log/httpd')='/etc/cron.d/'
rel_path('/etc/cron.d','/var/log/httpd')='/etc/cron.d'
rel_path('var/bar/','var/log/httpd')='../../bar/'
rel_path('/var/log/messages','/var/log/httpd/../')='messages'