PerlerのRuby日記

Rubyとか

privateなセッタメソッドはself.をつけて呼ばなければならない

Rubyのprivateなセッタメソッドについてメモ。

Rubyのprivateメソッドはレシーバを省略しないと呼べない仕様だけど、
末尾に「=」がつくセッタメソッドに限ってはself付きで呼ばないと動いてくれないようだ。

class Foo
  def foo
    bar=("bar=")           # NG(ローカル変数代入扱いになる)
    self.bar=("self.bar=") # OK

    bar("bar")             # OK
    self.bar("self.bar")   # Error
  end

  private

  def bar(i)
    puts i
  end

  def bar=(i)
    puts i
  end
end

Foo.new.foo
self.bar=
bar
aaa.rb:7:in `foo': private method `bar' called for #<Foo:0x00007ff5e3930270> (NoMethodError)
	from aaa.rb:21:in `<main>'

Kernel.openにパイプを渡す

Ruby2.4.3のリリースに、Net::FTP脆弱性の修正をした、というのを見た。

CVE-2017-17405: Net::FTP におけるコマンドインジェクションの脆弱性について

ローカルのファイルを開くために、それぞれ内部で Kernel#open を使用しています。しかし、もし localfile 引数がパイプ文字 "|" で開始されていた場合、パイプ文字以降に並べられたコマンドが実行されてしまいます。

module function Kernel.#open (Ruby 2.4.0)

ファイル名 file が `|' で始まる時には続く文字列をコマンドとして起動し、コマンドの標準入出力に対してパイプラインを生成します

ファイル名が "|-" である時、open は Ruby の子プロセス を生成し、その子プロセスとの間のパイプ(IOオブジェクト)を返します。(このときの動作は、IO.popen と同じです。File.open にはパイプラインを生成する機能はありません)。

ファイル名の代わりに、 "|" を先頭につけたものを渡せば、パイプとかforkとかできるらしい。そういえばPerlでもこんなのあったわ。

やってみたメモ

パイプから読み取り

foo.txt

aaaaaa
bbbbbb
cccccc

pipe_r.rb

io = Kernel.open("| cat foo.txt")

# 愚直に3回呼ぶ
#puts io.gets
#puts io.gets
#puts io.gets

# 一気読みする
#puts io.readlines

# 一行ずつ読む
io.each do |line|
  puts line
end

io.close
$ ruby pipe_r.rb
aaaaaa
bbbbbb
cccccc
パイプへ書き込み

pipe_w.rb

io = Kernel.open("| cat", "w")
io.puts("Yeeeees!")
io.close
$ ruby pipe_w.rb
Yeeeees!
forkしてやりとり (IO.#popenのマニュアルのサンプルそのまま)

fork.rb

io = Kernel.open("|-", "r+")
if io  # parent
  io.puts "foo"
  puts io.gets
  io.close
else   # child
  s = gets
  print "child output: " + s
  exit
end
$ ruby fork.rb
child output: foo


使う機会があるかはわからないが、一応まとめてみた。

Railsのconfig/routes.rbの書き方を冗長で自明にした

何をしたか

Railsのconfig/routes.rbの書き方にいい加減嫌気がさしたので単純を羅列する方法に変えた。
自分一人ならレールに乗るのもいいけど、複数人でさわるならわかりやすさ重視の方がいいとおもう。

変更前
Rails.application.routes.draw do
  root to: 'root#index'

  resources :books, except: [:destroy] do
    scope module: :books do
      resources :authors, only: [:index, :show] do
        resource :emails
      end
    end
  end
end
変更後
Rails.application.routes.draw do
  root to: 'root#index'

  get   'books'     => 'books#index' , as: :books
  get   'books/:id' => 'books#show'  , as: :book
  post  'books'     => 'books#create'
  patch 'books/:id' => 'books#update'

  get 'books/:book_id/authors'     => 'books/authors#index', as: :book_authors
  get 'books/:book_id/authors/:id' => 'books/authors#show' , as: :book_author

  get    'books/:book_id/authors/:author_id/emails' => 'books/emails#show'   , as: :book_author_emails
  post   'books/:book_id/authors/:author_id/emails' => 'books/emails#create'
  patch  'books/:book_id/authors/:author_id/emails' => 'books/emails#update'
  delete 'books/:book_id/authors/:author_id/emails' => 'books/emails#destroy'
end

文字が多いとか縦に伸びるとかデメリットもないでもないけど、見ただけで分かるという点で、自分はこれでいいとおもった。