Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

これまでに見たことのないRubyトリック11選+ボーナス技

ちょっとしたRubyトリックをお探しですか?

ここにありますよ!

この記事では、筆者のお気に入りのトリックをいくつかご紹介します。どれも短いコードで試せるものばかりなので、ぜひ実際に手を動かしながら読んでみてください。

目次

  • 1. ディープコピー(Deep Copy)
  • 2. ラムダを呼び出すさまざまな方法
  • 3. 初期値入りの配列を作成する
  • 4. true・false・nilもオブジェクト
  • 5. ラムダは引数に厳密、Procはお構いなし
  • 6. irbやファイルなしでコードを直接実行する
  • 7. コマンド1行で作る自作ミニirb
  • 8. オブジェクトの凍結を解除する(危険!)
  • 9. 特別なIDを持つオブジェクトたち
  • 10. irbやpryでの大量出力を防ぐ
  • 11. callerメソッドで現在のコールスタックを取得する
  • ボーナス1:どんな値でも真偽値に変換する
  • ボーナス2:キーワードを変数名として使う
  • まとめ

1. ディープコピー(Deep Copy)

Arrayのように他のオブジェクトを内包するオブジェクトをcloneすると、中身のオブジェクトへの参照だけがコピーされる「浅いコピー(Shallow Copy)」になります。

実際に確認してみましょう。

food = %w( bread milk orange )
food.map(&:object_id)       # [35401044, 35401020, 35400996]
food.clone.map(&:object_id) # [35401044, 35401020, 35400996]

通常はシリアライズ用途で使われるMarshalクラスを利用すると、オブジェクトの「ディープコピー」を作成できます。

def deep_copy(obj)
  Marshal.load(Marshal.dump(obj))
end

実行結果はこちらです。

deep_copy(food).map(&:object_id) # [42975648, 42975624, 42975612]

要素ごとに新しいobject_idが割り当てられており、完全に独立したコピーが作られていることがわかります。

2. ラムダを呼び出すさまざまな方法

my_lambda = -> { puts 'Hello' }

my_lambda.call
my_lambda[]
my_lambda.()
my_lambda.===

可能な限り最初のcallを使いましょう。最も多くの人に知られている、読みやすい書き方だからです。

3. 初期値入りの配列を作成する

Array.newは引数に加えてブロックを受け取ることができ、n個の要素を持つ配列を生成できます。デフォルトでは要素はすべてnilですが、ブロックを渡すと、その戻り値が各要素になります。

例:

Array.new(10) { rand 300 }

このコードは、0〜299の範囲のランダムな数値を10個含む配列を生成します。

4. true・false・nilもオブジェクト

true.class  # TrueClass
false.class # FalseClass
nil.class   # NilClass

これらのオブジェクトはそれぞれ1つしか存在せず、たとえ作ろうとしても新しく生成することはできません。

これはまさに、デザインパターンの一つ「シングルトンパターン」が言語レベルで実装されている好例です。

5. ラムダは引数に厳密、Procはお構いなし

my_lambda = ->(a, b)  { a + b }
my_proc   = Proc.new  { |a, b| a + b }

my_lambda.call(2)
# ArgumentError: wrong number of arguments (1 for 2)

my_proc.call(2)
# TypeError: nil can't be coerced into Fixnum

ラムダは引数の個数が一致しないと即座にエラーになりますが、Procは足りない引数をnilとして補って処理を続けようとします(上記の例ではその結果、TypeErrorが発生しています)。この違いは覚えておくとデバッグに役立ちます。

6. irbやファイルなしでコードを直接実行する

rubyコマンドには、意外と知られていない便利なオプションが多数あります。

たとえば-eフラグを使うと、実行したいコード断片をコマンドラインから直接渡せます。

ruby -e '5.times { puts "Fun with Ruby" }'

その他のオプションについては、-hフラグで一覧を確認できます。

7. コマンド1行で作る自作ミニirb

irbが内部でどう動いているのか気になったことはありませんか? 以下はその超シンプル版です。

「REPL」の略称の意味を思い出してください。Read-Eval-Print Loop(読み込み・評価・表示・繰り返し)です。

ruby -n -e 'p eval($_)'

プロンプトは表示されませんが、そのままRubyのコードを入力してみてください。

"A" * 5
# "AAAAA"

これが機能するのは、-nフラグが次のような動作をするためです。

-n    スクリプト全体を 'while gets(); ... end' のループで囲んだものとして扱う

そして$_はグローバル変数で、次の内容を保持しています。

gets または readline によって読み込まれた、最後の入力行の文字列。

8. オブジェクトの凍結を解除する(危険!)

Rubyにはオブジェクトの凍結(freeze)を解除する公式のメソッドは存在しません。しかし、Fiddleクラスを使えばRubyの内部構造に直接アクセスし、無理やり実現することができます。

require 'fiddle'

str = 'water'.freeze
str.frozen? # true

memory_address = str.object_id * 2

Fiddle::Pointer.new(memory_address)[1] &= ~8

str.frozen? # false

注意: 実際のプロダクトコードで試すのは絶対におすすめしません。クラッシュや予期しない動作を引き起こす可能性があります。あくまでRubyの内部挙動への好奇心を満たすための実験として楽しんでください。

9. 特別なIDを持つオブジェクトたち

Rubyのオブジェクトには識別子(id)が割り振られており、object_idメソッドで参照できます。一部のオブジェクトは固定のidを持ちます。具体的には、整数(旧Fixnum)、true、false、nilです。

false.object_id # 0
true.object_id  # 2
nil.object_id   # 4

1.object_id # 3
2.object_id # 5

小さい整数のidは、「(数値 × 2) + 1」という式で計算されます。

おまけ:当時のFixnumの最大値は1073741823で、それを超えるとBignumオブジェクトになっていました。なお、Ruby 2.4以降では両者は統合され、すべてIntegerクラスとして扱われるようになっています。

10. irbやpryでの大量出力を防ぐ

irbで作業中、巨大な配列や文字列の中身で画面が埋め尽くされるのを避けたい場合は、コードの末尾にセミコロン;を付けるだけでOKです。

例:

require 'rest-client'

RestClient.get('www.rubyguides.com');

今度は;なしで同じコードを実行して、表示の違いを確かめてみてください 🙂

11. callerメソッドで現在のコールスタックを取得する

コード例を見てみましょう。

def foo
  bar
end

def bar
  puts caller
end

foo

出力:

-:3:in 'foo'
-:10:in '<main>'

デバッグ時に「このメソッドはどこから呼ばれたのか」を知りたい場合に非常に便利です。また、現在実行中のメソッド名だけが必要な場合は、__method__または__callee__を使用しましょう。

ボーナス1:どんな値でも真偽値に変換する

否定を二重に適用することで、どんなオブジェクトでも明示的にtruefalseへ変換できます。

!!(1)   # true
!!(nil) # false

ボーナス2:キーワードを変数名として使う

キーワード引数の名前として予約語を指定し、binding経由で取り出すテクニックです。

def foo(if: nil)
  binding.local_variable_get(:if)
end

foo(if: true)

まとめ

このRubyトリック集を楽しんでいただけたなら幸いです!

ぜひ友人にもシェアしてください。そして、次回の投稿を見逃さないように、下のフォームからブログを購読しておきましょう 🙂

  1. 【完全ガイド】Rubyの定数とは?定義方法・スコープ・注意点を徹底解説

    Rubyにおける定数とは? Rubyの定数(constant)は、必ずアルファベットの大文字で始まる変数の一種です。メタプログラミングを利用しない限り、メソッドの外側でしか定義できません。 定数は「変更されるべきではない値」を扱うために用意されていますが、実はRuby自体はその変更を強制的に防ぐ仕組みを持っていません。 定数の基本的な書き方は次のとおりです: FRUIT = orange 定数はRubyプログラミングにおいて重要なトピックです。この記事では、定義方法からスコープの挙動まで、詳しく解説していきます! 定数の定義方法 定数の宣言には特別な記号や構文は必要ありません。先頭の文字を

  2. Apple TV 4Kを使いこなす!知っておきたい10のヒントとコツ

    新しいApple TVをお買い上げになりましたか?それならこの記事は必見です。初代Apple TVの登場から久しく経ちますが、技術の進化とともに、後継モデルごとに大きくパワーアップしてきました。その最新作が「Apple TV 4K」です。Apple TV 4Kは、エンターテインメントシステムに大きな付加価値をもたらす非常に便利なガジェットです。ニュース、天気、2種類のストレージオプションなど、実用的な機能が豊富に搭載された、コンパクトで効率的なデバイスです。一見してわかる機能も多い一方で、ユーザーがまだ知らない隠れた機能も数多く存在します。この記事では、Apple TV 4Kをさらに快適に、そ