Ruby Tips

実行中のプログラムのディレクトリを取得する

$PROGRAM_NAME と __FILE__ で少し変わる。

main.rb

require_relative 'tmp/load.rb'
puts File.expand_path(File.dirname($PROGRAM_NAME))
puts File.expand_path(File.dirname(__FILE__))

tmp/load.rb

puts File.expand_path(File.dirname($PROGRAM_NAME))
puts File.expand_path(File.dirname(__FILE__))

実行結果

ファイルが /home/dir/ にあるとすると

/home/dir/
/home/dir/tmp
/home/dir
/home/dir

と表示される。

ps で表示されるプログラム名を変更する

$PROGRAM_NAME に代入すれば良い。

#!/usr/bin/env ruby

p Process.pid
p $PROGRAM_NAME
$PROGRAM_NAME = "new program name"
sleep

を実行してから

ps aux | grep <PID>

とすると確認できる。

rubygems のファイルを autoload したい

rubygems の FileName が使用されるときに filename をロードしたい。

autoload :FileName, 'filename'

とするとエラーになる。エラーを回避するには

gem 'filename'
autoload :FileName, 'filename'

とする。

ソースファイルにデータを配列として記述する

「%w」を使うと便利。

data = %w|
60.234630000001 60.234650000001 0.000020000000
60.251240000000 60.251260000000 0.000020000000
60.584040100000 60.584040200000 0.000000100000
|.map { |s| s.to_f }

他のプロセスの情報を取得する

gem の sys-proctable を使えばできるようだ。

gem install sys-proctable

でインストールする。

require 'sys/proctable'
p Sys::ProcTable.ps(Process.pid)

で実行した ruby のプロセスの情報を取得する。 Sys::ProcTable::ProcTableStruct を返す。

p Sys::ProcTable.ps

とするとすべてのプロセスの情報を取得する。 Sys::ProcTable::ProcTableStruct の配列を返す。

データが何を表すかは

man proc

などで調べる。

Process.daemon 後の PID とディレクトリ

Process.daemon を実行したときに PID とディレクトリがどうなるのか気になったので調べた。

dir = File.expand_path(File.dirname(__FILE__))
open(File.join(dir, 'out.txt'), 'a+') do |f|
  f.puts "before Process.daemon:\n PID=#{Process.pid}, Directory=#{Dir.pwd}"
end

Process.daemon

open(File.join(dir, 'out.txt'), 'a+') do |f|
  f.puts "after Process.daemon:\n PID=#{Process.pid}, Directory=#{Dir.pwd}"
end

を /home/user_name/sample に保存して実行すると out.txt ができる。

before Process.daemon:
 PID=3687, Directory=/home/user_name/sample
after Process.daemon:
 PID=3692, Directory=/

のようになっていて PID とディレクトリは変更される。 ディレクトリの方は Process.daemon(nochdir=nil,noclose=nil) の nochdir で 制御できる。

fork したプロセスが defunct になって残らないようにする

fork したプロセスを Process.kill しても defunct になって残る。 http://blog.hybridism.com/?p=106 にあるように

Process.detach(pid)
Process.kill(:INT, pid)

のようにする必要がある。

文字列から定数名を作る

active_support の constantize メソッドを使う。

require 'active_support'
require 'active_support/core_ext/string'

s = 'Time'
p time_const = s.constantize
p time_const.new

シグナルを受け取って終了する

Signal.trap を設定する。

Signal.trap(:TERM) do
  exit(0)
end

Signal.trap(:INT) do
  exit(0)
end

どのシグナルに対応すれば良いのかは、よくわからなかった。

CPU の情報を得る

sys-cpu を使う。

gem install sys-cpu

でインストールする。

以前は

require 'sys/cpu'

で良かったと思うのだが変更されたのだろうか (2011-09-25)。

require 'linux/sys/cpu'
require 'pp'

pp Sys::CPU.cpu_stats
pp Sys::CPU.load_avg
pp Sys::CPU.model
pp Sys::CPU.processors

クラス変数とクラスのインスタンス変数

クラス変数は子クラスと共有されるが、 クラスのインスタンス変数は共有されない。

class Parent
  @@class_var = :parent
  @instance_var = :parent

  def self.get(type)
    case type
    when :class
      @@class_var
    when :instance
      @instance_var
    else
      nil
    end
  end
end

class Child < Parent
  @@class_var = :child
  @instance_var = :child
end

puts "Class variable"
p Parent.get(:class)
p Child.get(:class)

puts "Instance variable"
p Parent.get(:instance)
p Child.get(:instance)

を実行すると

Class variable
:child
:child
Instance variable
:parent
:child

となる。

ファイルの MD5 を求める

require 'digest/md5'
path = ARGV[0]
puts Digest::MD5.file(path).to_s

Object の marshal

Marshal できないオブジェクトを含まない場合は、 とくに何もしなくても Marshal.dump できる。 拡張ライブラリを作成したときなどの場合に marshal するには メソッドを定義する必要がある。

http://www.ruby-lang.org/ja/man/html/Marshal.html を読めば必要なことは書いてある。

Object#_dump と Class#_load

class TestMarshal
  def _dump
    ...
  end

  def self.load(str)
    ...
  end
end

のようにインスタンスメソッドとクラスメソッドを定義する。

Object#marshal_dump と Object#marshal_load

特異メソッドが定義されている場合に なんとか dump するために用いることができる(らしい)。

Tags of current page