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 がエラーになるのはうっかり忘れてたので直した https://t.co/a5lEu1OUaq
— ( Φ _⊞) (@n0kada) 2020年4月12日
とのことで 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"
unscoped
で default_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
こんなのが標準ライブラリにあるんですねー。 使う機会があれば使ってみたい。