Ruby の開発版に右代入演算子とエンドレスメソッド定義構文が入った

Ruby の開発版に右代入演算子と実験的にエンドレスメソッド定義構文が新しく追加されました。

右代入演算子

左辺値を右辺の変数に代入する => 演算子が新しく追加されました。
これは expression => variable のように書くことができます。

# 左辺値を右辺の変数に代入する
42 => result
p result
# => 42

# メソッドチェーンの最後に代入演算子を書くことができる
(1..).lazy.select { _1 % 2 == 0 }.map { _1 * 2 } => x
p x.first(10)
# => [4, 8, 12, 16, 20, 24, 28, 32, 36, 40]

=> を使うことで左から処理を書いて自然とその流れのまま変数に代入する事ができます。
これは書いてて気持ちいいですね。
その反面、変数定義を探す場合、いつも左側を見る癖が付いているので右側に変数定義があると見落としてしまいそうなのがちょっと心配です。
また、次のように演算子を伴う式を左辺で書くとシンタックスエラーになりました。

# syntax error, unexpected =>, expecting end-of-input
1 + 2 => result

これは意図してないような気がするんですがどうなんでしょうね。

追記

=> は Hash を定義する時にも使われており例えば現行の Ruby でも

meth(key => value)

と書くことができます。
なので

meth a => result

というコードは

meth(a) => result

ではなくて

meth(a => result)

と解釈されます。
同様に

1 + 2 => result

(1 + 2) => result

ではなくて

1 + (2 => result)

と解釈されるのでえらーになるんですかね?

[追記 2]

とのことで 1 + 2 => result がエラーになることは意図していなかったらしいです。
最新版では以下のコードが動作します。

1 + 2 => result
result   # => 3

演算子の優先順位の問題、意図してるのかどうか判断するのがむずかしいなー。

エンドレスメソッド定義構文

実験的にエンドレスメソッド定義構文が追加されました。
エンドレス、と言っても永遠という意味ではなくて『end を書かずにメソッドを定義する』という意味のエンドレスです。
これにより def value(args) = expression という形でメソッドを定義する事ができるようになります。
もともとは今年のエイプリルフールネタで建てられたチケットがそのまま導入された形になります。
これを利用することで以下のような形でメソッドを定義する事ができます。

def hello(name) =
  puts("Hello, #{ name }")

hello("endless Ruby") #=> Hello, endless Ruby
def inc(x) = x + 1

p inc(42) #=> 43
x = Object.new

def x.foo = "FOO"

p x.foo #=> "FOO"
def fib(x) =
  x < 2 ? x : fib(x-1) + fib(x-2)

p fib(10) #=> 55

これは普通に便利そうですね。
ただし、 def value = 42 のように代入演算子を使用するので以下のような動作を期待するんですが、これはエラーになります。

value = 42
# 外のスコープの値を使用したい
def hoge = value

# error: undefined local variable or method `value' for main:Object (NameError)
p hoge

end がないことでスコープが曖昧に見えるので個人的には外にある変数はキャプチャされてもいいんじゃないかなあ、と思うんですがどうなんでしょうね。
この構文自体あんまりよく思ってない人もいるようなので今後どうなるのかは気になります。

ActiveRecord で unscoped を呼ぶとその前のクエリが消える

久々ですこんにちは。
毎日ブログを書くとはなんだったのか…。
そろそろアウトプットしたいな〜〜〜と思い始めてきたのでぼちぼち書いていきたい…。

unscoped を使うことで default_scope を取り除くことができる

さて、皆さん大好き default_scope ですが、モデルで default_scope を定義すると次のように暗黙的にクエリが追加されます。

class User < ActiveRecord::Base
  default_scope { order(:updated_at) }
end

# 暗黙的に ORDER BY のクエリが追加れる
puts User.all.to_sql
# => SELECT "users".* FROM "users" ORDER BY "users"."updated_at" ASC
puts User.where(name: "Tom").to_sql
# => SELECT "users".* FROM "users" WHERE "users"."name" = 'Tom' ORDER BY "users"."updated_at" ASC

毎回 order(:updated_at) する必要がないので便利ですね。
でも『あ〜今日は default_scope のクエリ追加してほしくないな〜〜〜』って思うときがあると思うんですよ。
そういう時に unscoped を使うと default_scope のクエリを取り除く事ができます。

# unscoped を付けると default_scope はつかなくなる
puts User.unscoped.all.to_sql
# => SELECT "users".* FROM "users"
puts User.unscoped.where(name: "Tom").to_sql
# => SELECT "users".* FROM "users" WHERE "users"."name" = 'Tom'

これで default_scope をつかっていてもシュッと取り除く事ができて便利ですね!

default_scope 以外のクエリも取り除かれる

unscoped を使うことで default_scope を取り除く事ができるようになります。
しかし unscoped はめちゃくちゃ強くて『呼び出すよりも前のリレーション』も取り除いてしまします。

# unscoped よりも前に付けた where のクエリも消してしまう
puts User.where(name: "Tom").unscoped.to_sql
# => SELECT "users".* FROM "users"

unscopeddefault_scope を消したい場合は必ず『一番最初』に unscoped を呼び出しましょう。
逆に『レシーバのクエリを全部消したい』場合は unscoped を呼び出すと一括で消すことができるので便利です。

あなたの知ってるRubyGemsTips で LT してきた

あなたの知ってるRubyGemsTips で LT してきました。
LT よかったよー、と言ってもらえたのでよかったよかった。

printf デバッグが捗る gem をつくった話

2年ぐらい前に binding-debug という gem をつくったんですが、最近いろいろと機能拡張したのでそれの紹介をしてきました。
以前は

require "binding/debug"

using BindingDebug

value = 42
binding.p "value"
# => value : 42

みたいに binding.p に文字列を渡して使うようになっていたんですが、いまは Ruby の闇の力を使い以下のように書くことができます。
以下、README にかかれているサンプル。

require "binding/debug"

using BindingDebug

def plus a, b
  a + b
end

foo = "homu"

# puts with blocks
puts {
  foo.to_s.upcase
  plus 1, 2
  (0..20).to_a
  foo.class.name
}
# output:
# foo.to_s.upcase : HOMU
# plus 1, 2 : 3
# (0..20).to_a : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
# foo.class.name : String

今回は5分の LT でユースケースや使い方ぐらいしか話せなかったんですが、機会があれば実装方法なんかも話してみたいですねー。
ご飯も美味しかったですし、運営の方々ありがとうございましたー。

JavaScript で全角スペースはホワイトスペースとして扱われる

JavaScript で全角スペースを書いた場合、ホワイトスペースとして扱われます。知らなかった…。
なので次のように全角スペースが含まれているコードでも実行する事ができます。

if ( true ) {
  console.log("hoge");
}

うーん…便利…なのか?

参照

Ruby でクラス名と同名のメソッドを定義する

Ruby ではクラスと同じ名前のメソッドを定義する事ができます。

class X
end

def X(a = nil)
  "X(#{a})"
end

# 何もつけなかった場合はクラスを参照
p X       # => X
# メソッドぽい呼び出しであればメソッドを参照
p X()     # => "X()"
p X 42    # => "X(42)"

この手のやつでよく利用されているのは Kernel.#Array メソッドや Kernel.#Integer メソッドですねー。

Array(arg) もクラスではなくてメソッドを呼び出しています。

Ruby の private メソッドを特定のコンテキストで public にする

Ruby では次のように private メソッドにすると『レシーバをつけたメソッド呼び出し』ができません。

class X
  private

  def value
    42
  end
end

x = X.new

# error: private method `value' called for #<X:0x00007fabe905fa40> (NoMethodError)
x.value

こういうときに refinements を使うと任意のコンテキストでのみ public 化することができます。

class X
  private

  def value
    42
  end
end

x = X.new
# error
# x.value

# refinements を使って public 化する
using Module.new {
  refine X do
    public :value
  end
}

# OK
x.value

べんり。

Ruby で任意の定数を参照した際に警告が出るようにする

Ruby で任意の定数を参照した際に警告が出るようにしたい場合、 Module#deprecate_constant を利用することができます。

class X
  Hoge = 42
end

# no warning
X::Hoge

# X::Hoge を参照すると警告を出すようにする
X.deprecate_constant :Hoge

# warning: constant X::Hoge is deprecated
X::Hoge

こんなのが標準ライブラリにあるんですねー。 使う機会があれば使ってみたい。