Ruby のグローバル変数をそれぞれ調べてみた
Ruby のクリプティックなグローバル変数をそれぞれ調べてみました.
Ruby のグローバル変数って一番広いスコープで使えるので, どこでも使えて便利ですが, 変数名が少々難解なので, どの変数名がどういう意味だったかみたいなことを忘れがちです.
なので自分への備忘録という意味も含めて, それぞれのグローバル変数を実際のコードで試してみました.
グローバル変数には使う人が覚えやすいように, エイリアスというものが名付けられたものもあるので, それも一緒に紹介したいと思います.
$!
Ruby の raise
によって引き起こされた例外情報のメッセージです.
begin
puts foo
rescue NameError => e
puts $! # undefined local variable or method `foo' for main:Object
puts $!.class # NameError
puts $! == e # true
end
$!
は rescue NameError => e
の e
と同じオブジェクトになります.
$@
投げられた最後の例外のバックトレースの配列です.
example.rb
begin
puts foo
rescue NameError => e
puts $@ # example.rb:2:in `<main>'
puts $@ == $!.backtrace # true
end
$@
は $!.backtrace
と同じオブジェクトになります.
$&
正規表現で最後にマッチした文字列です.
'Hello World' =~ /\w+ \w+/
$& # => "Hello World"
$&.class # => String
$`
正規表現で最後にマッチした左側の文字列です.
'Hello World' =~ / /
$` # => "Hello"
$'
正規表現で最後にマッチして右側の文字列です.
'Hello World' =~ / /
$' # => "World"
$+
正規表現で最後にマッチした一番最後のグループです.
'Hello World' =~ /((\w+) (\w+))/
$+ # => "World"
$1
正規表現で最後にマッチした N 番目のグループです.
'Hello World' =~ /(\w+) (\w+)/
$1 # => "Hello"
$2 # => "World"
$~
正規表現で最後にマッチした MatchData
です.
'Hello World' =~ /(\w+) (\w+)/
$~ # => "Hello World"
$~[1] # => "Hello"
$~[2] # => "World"
$~.class # => MatchData
$/
ファイルを読み込む時の区切り文字です.
デフォルトは "\n"
です.
$/ # => "\n"
example1.txt
This is the first line.
This is the second line.
example2.txt
This sentence is separated by a tab.
def puts_lines(file)
File.open(file) do |f|
f.readlines do |line|
puts line
end
end
end
puts_lines('example1.txt')
# This is the first line.
# This is the second line.
$/ = "\t"
puts_lines('example2.txt')
# This
# sentence
# is
# separated
# by
# a
# tab.
example1.txt
と example2.txt
という二つのテキストファイルを用意して, 第一引数に指定されたファイルパスのファイルの内容を出力する関数 puts_lines
を定義し, それぞれのファイルで呼び出しています.
最初の example1.txt
は $/
がデフォルトの "\n"
のままなので, 一行目, 二行目と通常通りに表示されました.
一方の example2.txt
は $/
の値を "\t"
に割り当てたので, 一行にも関わらず, その一行内のタブで区切られた 7 つの単語がそれぞれ表示されました.
$\
print
関数などで出力する時の行末に付けられる文字です.
デフォルトは nil
なので, つまりは何も付けられないということです:
$\ # => nil
print 'Hello'
print 'World'
# HelloWorld
もし $\
を "\n"
とすると puts
と同じように print
でも行末に "\n"
が付けられます:
$\ = "\n"
print 'Hello'
print 'World'
# Hello
# World
$,
print
や join
でのオブジェクト間の文字として使われます.
デフォルトは nil
です.
$, # => nil
print 'Hello', 'World' # HelloWorld
['Hello', 'World'].join # => "HelloWorld"
$, = ' '
print 'Hello', 'World' # Hello World
['Hello', 'World'].join # => "Hello World"
$;
split
で文字列を分割する際のパターンに使用されます.
デフォルトは nil
です.
もし $;
が nil
の場合, split
は " "
で分割します.
$; # => nil
'Hello World'.split # => ["Hello", "World"]
$; = "\n"
"Hello\nWorld".split # => ["Hello", "World"]
$.
最後に読み込まれたファイルの現在の行数です.
次のファイルを用意して:
example.txt
This is the first line.
This is the second line.
次のコードを実行すると:
def puts_line_with_line_number(f)
line = f.readline
puts "#{$.}: #{line}"
end
File.open('example.txt') do |f|
puts_line_with_line_number(f)
puts_line_with_line_number(f)
end
このように出力されます:
1: This is the first line.
2: This is the second line.
$<
コマンドラインで与えられたファイルの仮想連結ファイルです.
$<
のエイリアスとして, グローバル定数 ARGF
を代わりに使うこともできます.
また $<.filename
のエイリアスとして, グローバル変数 $FILENAME
を代わりに使うこともできます.
次のファイルを用意して:
example.txt
This is the first line.
This is the second line.
次の Ruby スクリプトを用意して:
example.rb
puts $<.filename
puts $<.readline
puts $<.readline
次のコマンドを入力すると:
ruby example.rb < example.txt
次のように表示されます:
exmaple.rb
This is the first line.
This is the second line.
$>
print
や printf
がデフォルトで出力する場所です.
デフォルトで $stdout
が設定されています.
なので次の空ファイルを用意して:
example.txt
次の Ruby スクリプトを用意して:
example.rb
File.open('example.txt', 'w') do |f|
$> = f
puts 'Hello World'
end
次のコマンドを実行すると:
ruby example.rb
example.txt
は次のように書き換えられます:
Hello World
$_
gets
や readline
での最後の行です.
次の Ruby スクスプトファイルを用意して:
example.rb
print 'Please input something: '
gets
puts "Your input: #{$_}"
その example.rb
を実行すると, 次のようになります:
$ ruby example.rb
Please input something: Hello World
Your input: Hello World
gets
に Hello World
と入力した内容が $_
に入っているのがわかります.
$0
現在実行しているスクリプト名です.
次の Ruby スクリプトファイルを用意して:
example.rb
puts $0
その example.rb
を実行すると, 次のようになります:
$ ruby example.rb
example.rb
$*
スクリプトのパスを除いたコマンドライン引数です.
$*
のエイリアスとして, グローバル定数 ARGV
を代わりに使うこともできます.
次の Ruby スクリプトファイルを用意して:
example.rb
puts $*.inspect
次のコマンドを実行すると, このようになります:
$ ruby example.rb a b c
["a", "b", "c"]
example.rb
というスクリプトのパスが除かれた a
, b
, c
という 3 つの引数のみ $*
に入っているのがわかります.
$$
スクリプトを実行している Ruby のプロセス番号です.
次の Ruby スクリプトファイルを用意して:
example.rb
puts $$
次のコマンドを実行すると, このようになります:
$ ruby example.rb
34890
34890
は僕が実行した時の Ruby のプロセス番号です.
実際の番号はランダムになります.
$?
最後に実行した子プロセスの状態です.
次の Ruby スクリプトファイルを用意して:
example.rb
puts 'Correct command:'
puts `echo 'Hello World' | sed 's/ /+/'`
puts $?
puts
puts 'Wrong command:'
puts `echo 'Hello World' | sed --wrong-option 's/ /+/' 2> /dev/null`
puts $?
次のように実行すると, このようになります:
$ ruby example.rb
Correct command:
Hello+World
pid 42661 exit 0
Wrong command:
pid 42664 exit 1
最初の echo 'Hello World' | sed 's/ /+/'
は正しいコマンドなので exit 0
となりましたが, その次の echo 'Hello World' | sed --wrong-option 's/ /+/' 2> /dev/null
は誤ったオプション --wrong-option
を指定しているのでエラーとなり exit 1
となりました.
ちなみに 2> /dev/null
というのは, stderr に出力されるエラーメッセージを表示しないようにしています.
$:
load
や require
によって探索されるパスの配列です.
$:
のエイリアスとして, グローバル変数 $LOAD_PATH
を代わりに使うこともできます.
puts $:
# /usr/local/Cellar/rbenv/1.1.1/rbenv.d/exec/gem-rehash
# /usr/local/Cellar/rbenv/1.1.1/rbenv.d/exec/gem-rehash
# /usr/local/Cellar/rbenv/1.1.1/rbenv.d/exec/gem-rehash
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/awesome_print-1.8.0/lib
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/site_ruby/2.5.0
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/site_ruby/2.5.0/x86_64-darwin17
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/site_ruby
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/vendor_ruby/2.5.0
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/vendor_ruby/2.5.0/x86_64-darwin17
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/vendor_ruby
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/x86_64-darwin17
僕は rbenv
を使用して Ruby を使っているので, このようなロードパスが表示されるのでしょうね.
$"
require
によって読み込まれたモジュール名を含んだ配列です.
$"
のエイリアスとして, グローバル変数 $LOADED_FEATURES
を代わりに使うこともできます.
puts $"
# enumerator.so
# thread.rb
# rational.so
# complex.so
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/x86_64-darwin17/enc/encdb.bundle
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/x86_64-darwin17/enc/trans/transdb.bundle
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/x86_64-darwin17/rbconfig.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems/compatibility.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems/defaults.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems/deprecate.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems/errors.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems/version.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems/requirement.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems/platform.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems/basic_specification.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems/stub_specification.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems/util/list.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/x86_64-darwin17/stringio.bundle
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/uri/rfc2396_parser.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/uri/rfc3986_parser.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/uri/common.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/uri/generic.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/uri/ftp.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/uri/http.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/uri/https.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/uri/ldap.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/uri/ldaps.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/uri/mailto.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/uri.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems/specification.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems/exceptions.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems/dependency.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems/core_ext/kernel_gem.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/monitor.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/rubygems/path_support.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/version.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/core_ext/name_error.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/levenshtein.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/jaro_winkler.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/spell_checker.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/2.5.0/delegate.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/spell_checkers/name_error_checkers/class_name_checker.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/spell_checkers/name_error_checkers/variable_name_checker.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/spell_checkers/name_error_checkers.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/spell_checkers/method_name_checker.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/spell_checkers/key_error_checker.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/spell_checkers/null_checker.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean/formatters/plain_formatter.rb
# /Users/yu8mada/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/did_you_mean-1.2.0/lib/did_you_mean.rb
こうしてみると随分デフォルトで色々なモジュールが読み込まれているというのがわかります.
まとめ
Ruby のグローバル変数って, 変数名が難解ではじめ見たときは “???” という感じだったのですが, あくまで変数名が難解というだけですので, 一度それらの変数名と意味を覚えてしまったら二文字で入力できるので, 便利この上ありません.
僕はこの難解さが, いかにもプログラミングをしているという気持ちにさせてくれますので, 気に入っておりますw.
ただ $:
などのエイリアスがあるものは $LOAD_PATH
などのエイリアスを使ったほうがよりわかりやすくて良いという意見もあるので, そうなのかもしれません.
何かのプロジェクトでチームで開発している場合は, そのチームのどのようにコードを書くかというルールに従うべきなのでしょう.
でも一人だけで開発している分には, そのような難解なグローバル変数名をそのまま使っても全然良いのではと個人的には思っております.
それが Ruby らしさの一つでもあるような気がしますので.
あくまで今回紹介させていただきました Ruby のグローバル変数は全てというわけではありません. 網羅的な情報をお知りになりたい方は次の URL より参照していただければと思います.
関連記事
Ruby の正規表現を備忘録としてまとめてみた2018.08.30
Bundler をシングルファイル Ruby スクリプトで使う方法2018.04.23
Ruby の StandardError でどういう間違いをすると, どの例外が発生するのかのメモ2018.07.13
Git のコミット履歴を大胆に書き換えるなら git rebase -i がオススメ2018.08.23
Git で変更されたファイルを部分的にステージする方法2018.11.01