週刊Railsウォッチ(20180730)Rubyの速い書き方集、最近登場のRailsアプリたち、RubyWorld Conference受付開始ほか

こんにちは、hachi8833です。やっとGobyにRipperライブラリをマージしました。

束の間の涼しい夏日のウォッチ、いってみましょう。

各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ

【お知らせ】週刊Railsウォッチ「公開つっつき会 第1回」今週8/2(木)開催

今週木曜日です。引き続き参加をお待ちしております!🙇懇親会にて軽食&ビールもお待ちしています🍺。

Rails: 先週の改修(Rails公式ニュースより)

先週は公式の更新情報がなかったので、masterブランチなどから見繕いました。

scopingメソッドの廃止(オープン中)

これまでのscopingは、元のスコープチェインを伝搬させる目的で、リレーション由来の名前付きスコープメソッドの委譲に使われてきた。しかしクラスメソッドへのクエリがすべて汚染されるという望ましくない振る舞いが生じていた(例↓)。

class Topic < ActiveRecord::Base
  scope :toplevel, -> { where(parent_id: nil) }
  scope :children, -> { where.not(parent_id: nil) }
  scope :has_children, -> { where(id: Topic.children.select(:parent_id)) }
end

# 期待どおり動作
Topic.toplevel.where(id: Topic.children.select(:parent_id))

# `toplevel`から`Topic.children`にお漏らししてるので動かない
Topic.toplevel.has_children

#29301で名前付きスコープ内のレシーバがモデルクラスから元のスコープチェインに変更されたので、クラスメソッドのクエリ汚染は必要でなくなった。
同PRより大意

# activerecord/lib/active_record/relation.rb#L310
    def scoping
-      previous, klass.current_scope = klass.current_scope(true), self
-      yield
+      previous, klass.current_scope = klass.current_scope(true), scope
+      delegate_to { yield }
     ensure
       klass.current_scope = previous
     end

kamipoさんによるPRです。まだマージされていません。


つっつきボイス: 「Railsdmのオーラスでkamipoさんが言及してたので(先週のウォッチ)」

Rubocopのお導きでパフォーマンスを改善

# actionpack/lib/action_controller/metal/strong_parameters.rb#L793
     protected
       attr_reader :parameters

-      def permitted=(new_permitted)
-        @permitted = new_permitted
-      end
+      attr_writer :permitted
  • getter/setterメソッドよりattr_accessorを使うべし(メソッドは12%遅い)
  • map.flatten(1)よりflat_mapを使うべし(flattenは66%遅い)
    • (正確には「map.flatten(1)は66%遅い」ですね☺️)
  • 引数が1つならhash.merge!よりhash[]=を使うべし(merge!は166%遅い)

つっつきボイス: 「flat_mapって初めて見た😧」「TechRachoにあるRubycop式Rubyスタイルガイドにも載ってた気がします(↓あった:2-70)」「flattenは泥臭いデータ構造を処理するときに結構使うけど最近あまり使ってない😆、flattenの動作は再帰的だと思われるので遅そう」「何となく英語圏にflatten好きが多い気も」「ちーっす」「お、ちょうどいいところへ: flat_mapって使います?」「存在は知ってるけど使ったことはちょっと…🤔」「やっぱりねー」「flattenしてからmapするってことかな?」「可読性とのバランスもあるし、速い書き方よりメジャーな書き方の方がいいときもあると思うんだけどなー☺️」

【保存版】Rubyスタイルガイド(日本語・解説付き)総もくじ

  • #flat_map: 配列の階層を1段階浅くする
  • #flatten: 配列の階層を完全にフラットにする(再帰)

参考: instance method Array#flatten (Ruby 2.5.0)
参考: instance method Enumerable#collect_concat (Ruby 2.5.0)flat_mapはこのエイリアスでした

「『merge!は166%遅い』というのもスゴイ😮」「これは確かにhash[]=の方がわかりやすいし速いのも納得だけど、例外が発生する可能性があるならmerge!がいいかもね: それにフレームワークのコード(strong parametersとか)はいくつ渡すか決められないものも多いからmerge!になるだろうし」

このPRで引用されていた#32337で、fast-rubyとfasterer gemを知りましたのでこの後の「Ruby」のコーナーで。

ブロック渡しよりシンボル渡し

2014年のコミットなのでだいぶ古いですが、上の#32381で言及されていたので。

def finalize!
  route_sets.each do |routes|
    routes.finalize!
  end
end

# ↓

def finalize!
  route_sets.each(&:finalize!)
end

ざっと見ると、インスタンス変数の個数が少ない場合はブロック渡しのほうが速く(Procオブジェクトが生成されないので)、多くなるとシンボル渡しの方が速くなるとあります(16833#)。


つっつきボイス: 「&:finalize!みたいなProcにシンボルを渡す記法、今でこそ慣れたけど最初見たときは『へ?👁』って思いましたね: もうイディオムとして普及しているので、単純な呼び出しならProcシンボル渡しの方がいいのかも」

自分でもRuby 2.5.1でベンチ回してみました。

参考: class Proc (Ruby 2.2.0)

参考: &演算子と、procと、Object#method について理解しなおす - Qiita

日付を2000-01-01で正規化してサマータイムのDBとの日付のズレを修正

# activerecord/lib/active_record/connection_adapters/abstract/quoting.rb#L132
       def quoted_time(value) # :nodoc:
+        value = value.change(year: 2000, month: 1, day: 1)
         quoted_date(value).sub(/\A\d\d\d\d-\d\d-\d\d /, "")
       end

つっつきボイス: 「今はもう2000-01-01で正規化できちゃうのね(遠い目」「UNIX時間だと1970年あたりから開始でしたっけ↓」「connection_adaptersのあたりとか触ったことない」「サマータイムなければいいのにって思うし」

参考: Ruby on Rails 5.2 / ActiveRecord::ConnectionAdapters::Quoting#quoted_date — DevDocs

参考: UNIX時間 - Wikipedia — 「協定世界時 (UTC) での1970年1月1日午前0時0分0秒から」

「そういえば昔『インターネット時間』ってものがありましたねー: 自分が覚えているのはPSOことファンタシースターオンライン(セガのネトゲ)で使われてたくらい😆」

参考: ファンタシースターオンライン - Wikipedia

「あ、ちょうど今日タバコ吸いながらその話になったんですが、その昔腕時計で有名なSWATCHがインターネット時間を提唱したんだそうです↓」「へー?そっちが元だったのか」「何でも一日を1000で割るという豪快な案らしくて🤣」「何ちゅう🤣」「PSOもたぶん初期がそれだったし: 世界中で同時にサービスしてたからでしょうけど」「時差というか経度に影響されない時間だからですね」「細かい単位を小数点で表せるのは10進数ならでは」「結局インターネット時間はさっぱり定着してませんが😎: UNIX時間でいいけど別に」

参考: スウォッチ・インターネットタイム - Wikipedia


Wikipediaより: [CC BY 2.5](Creative Commons — Attribution 2.5 Generic — CC BY 2.5)

Railsガイドへのリンクを遅まきながらHTTPS化

# README.md#L78
 5. Follow the guidelines to start developing your application. You may find
    the following resources handy:
-    * [Getting Started with Rails](http://guides.rubyonrails.org/getting_started.html)
-    * [Ruby on Rails Guides](http://guides.rubyonrails.org)
+    * [Getting Started with Rails](https://guides.rubyonrails.org/getting_started.html)
+    * [Ruby on Rails Guides](https://guides.rubyonrails.org)
     * [The API Documentation](http://api.rubyonrails.org)
     * [Ruby on Rails Tutorial](https://www.railstutorial.org/book)

つっつきボイス: 「ほら、Chromeが最近…」「API DocはまだHTTPS化されてない?」

なおAPI Documentationは既にHTTPSされてますが、執筆時点のmasterのリンクはまだ修正されてないようです。

limit(1).firstlimit(1).lastで前者だけがデフォルトで主キーでソートされていたのを修正

# activerecord/lib/active_record/relation/finder_methods.rb#L552
       def ordered_relation
-        if order_values.empty? && primary_key
+        if order_values.empty? && primary_key && limit_value.blank?
           order(arel_attribute(primary_key).asc)
         else
           self
         end
       end

よくみると2016年にオープンされていたのをkamipoさんがつい最近マージしていました。breaking changeなのでバックポートはしないようです。類似の#27597はbreakingではないので早々にマージされたとのこと。


つっつきボイス: 「2年越しのマージ」「あーなるほど、遅延評価されるときにfirstlastの結果が違ってたということか: でもlimit(1).firstなんて異常な書き方は普通まずしないし😆」「でもスコープにlimit書いちゃうと踏むことがあるかも?」「#27597は以前のウォッチで見たことあるな」「#27597は明らかにバグだから全員困るけど、この#24131は修正することで逆に困る人が出てくるからバックポートしなかったんでしょうね」

Active Recordコールバックの引数を厳密にチェック

# activemodel/lib/active_model/callbacks.rb#L127
     private

       def _define_before_model_callback(klass, callback)
-        klass.define_singleton_method("before_#{callback}") do |*args, &block|
-          set_callback(:"#{callback}", :before, *args, &block)
+        klass.define_singleton_method("before_#{callback}") do |*args, **options, &block|
+          options.assert_valid_keys :if, :unless, :prepend
+          set_callback(:"#{callback}", :before, *args, **options, &block)
         end
       end

       def _define_around_model_callback(klass, callback)
-        klass.define_singleton_method("around_#{callback}") do |*args, &block|
-          set_callback(:"#{callback}", :around, *args, &block)
+        klass.define_singleton_method("around_#{callback}") do |*args, **options, &block|
+          options.assert_valid_keys :if, :unless, :prepend
+          set_callback(:"#{callback}", :around, *args, **options, &block)
         end
       end

       def _define_after_model_callback(klass, callback)
-        klass.define_singleton_method("after_#{callback}") do |*args, &block|
-          options = args.extract_options!
+        klass.define_singleton_method("after_#{callback}") do |*args, **options, &block|
+          options.assert_valid_keys :if, :unless, :prepend
           options[:prepend] = true
           conditional = ActiveSupport::Callbacks::Conditionals::Value.new { |v|
             v != false
           }
           options[:if] = Array(options[:if]) << conditional
-          set_callback(:"#{callback}", :after, *(args << options), &block)
+          set_callback(:"#{callback}", :after, *args, **options, &block)
         end
       end

つっつきボイス: 「おー、今までの*argsの他に**optionsも追加されてる」「options.assert_valid_keys :if, :unless, :prependでアサーション追加してますね」「コールバックメソッドに余計なオプションを付けられないようにしてるようだ」

番外: Railsガイドの囲みの背景色を変更

PRそのものより、これを投げたlanzhihengさんのアバターが喚起する極めて強い既視感が気になったので。


つっつきボイス: 「こういう修正は地味だけど重要ですね: 見やすいは正義」「とりあえずアバターをどぞ」「これは結城浩さんのスレッドおばけっぽいw: 結城さんのアバターはこういうクォータービューじゃないけど😆」「好きなのかな?」「間違える人いそう😆」

Rails

⭐今週の人気Railsリポジトリ(2018/07/23)⭐

今回最も盛り上がりました。目ぼしいもののみピックアップしてみました。Railsアプリでないものもあったりします。こちらの記事に⭐を進呈いたします。おめでとうございます。


つっつきボイス: 「お、知らないものがいろいろあるなー」「どれどれ👀」

Zammad: ヘルプデスク/カスタマーサポートアプリ



同サイトより

「ヘルプデスク/カスタマーサポートのシステム」「Redmineと同じような感じで、Railsで書かれたアプリか」「errbitみたいな感じで導入できそう」「そんな感じで単体でも導入できるしRailsエンジニアがカスタマイズもできると: これなかなかよさそうじゃない❤️」「😃」

flutie: content_forを改善

Factory_botでおなじみThoughtbotのgemです。


同リポジトリより


つっつきボイス: 「フルーティ?」「むむん?ははー、content_forをもっと使いやすくするgemか!」「地味といえば地味」「SEO的な改修をしたい人向けっぽいかも」「確かに今のcontent_forって生々しすぎてちょっと使いづらいし、デフォルト値書き忘れたりするし、lambda渡し始めるとつらくなってくるし」「content_forって、記述したものがyieldで呼び出されるのが違和感あるんですよ: 『え?yieldでやるの?』っていう気持ちになるし、そのことを知らないと直感的にわかりづらい」「その意味ではflutiecontent_forよりは読みやすいですね❤️」

#同リポジトリより
content_for(:site_page_title, 'My title of my page')
page_title(:app_name => 'My app name', :page_title_symbol => :site_page_title, :separator => " | ")
=> "My app name | My title of my page"

参考: Ruby on Rails 5.2 / ActionView::Helpers::CaptureHelper#content_for — DevDocs

OpenProject: プロジェクト管理



同サイトより


つっつきボイス: 「これはプロジェクトマネージメントのアプリ」「おおー!?これなかなかよくできてるかも: ガントチャートもカンバンも標準でついてて必要な機能がひととおり揃ってそうな感じ」「Redmineにライバル出現?」「JIRAより好きかも」「UIがんばってるし」「Redmineのデータをインポートできたらスゴイな(追伸: 一応手順あり)」「OpenProject悪くなさそう: 機会があったら使ってみたい😋(自前でホスティングするのは面倒だけど)」

bootstrap-rubygem: Bootstrap 4の公式gem


つっつきボイス: 「前からあるんでしょうね」「ですね: SCSS版のBootstrap 4が使えるヤツ」「そういえばBootstrap 4って今もjQuery必須なんですね🤔」「jQuery手放してないですね」「jQueryがないとBootstrap 4でJavaScriptが動かないから😅」「将来はjQueryなくすみたいなプランぐらいあってもよさそうだけど(追記: 今の所見当たりませんでした)」


getbootstrap.comより

Skinny: RailsにインスパイアされたScala言語向けWebフレームワーク


同サイトより


つっつきボイス: 「サーブレット?」「Javaサーブレットですね」「ScalaでRailsが動く?」「いや、これはRailsにインスパイアされたとあるから、RailsっぽいWebフレームワーク」「コマンドもRailsっぽい↓」「PHPのSymfonyフレームワークなんかもRailsに影響受けてますしね」

# 同サイトより
./skinny db:migrate test
./skinny test

参考: Scala - Wikipedia
参考: Symfony - Wikipedia


Wikipediaより(パブリックドメイン)

react-rails: React.jsの「公式」gem


つっつきボイス: 「お、Webpackerをちゃんとサポートしてるし😃」「Sprocketsもサポートされてる」「サポートされているWebpackerは3まで… 4はまだ入ってない(惜しい!)😢」「誰か人柱になる😆?(チラッチラッ」

Rails 5: Webpacker公式README — Webpack v4対応版(翻訳)

「そういえばreact_on_railsなんてgemもありませんでした?」「紛らわしい😅」「お、でもこのreact-railsはReact.jsの公式ですよ」「ほんとだ!😲」「待てよ、ということはReact.jsはWebpackerを公式に推しているってことなんじゃ?」「😃」「公式が推してくれているんなら、Webpackerを導入するときに宗教戦争にならないで済みそう?」「もしそうなら安心感が違う😋」「ま、いつまで公式に推してくれるかはわかりませんけどね😎」

Oj: Ruby製高速JSONパーサー


同リポジトリより

# 同リポジトリより
require 'oj'

h = { 'one' => 1, 'array' => [ true, false ] }
json = Oj.dump(h)

# json =
# {
#   "one":1,
#   "array":[
#     true,
#     false
#   ]
# }

h2 = Oj.load(json)
puts "Same? #{h == h2}"
# true

つっつきボイス: 「高速なJSONパーサー」「このロゴ見たことがある気がします」「こういう高速なgemはあるときRailsにしれっと入るかもしれませんからね🕶」「よく見るとC拡張だった…」「ほんとだ: 環境によってはインストール面倒かも」

後でohler.com/ojを見てみると、Oj 3.0.0でRuby標準のjson gemの代わりに使ったり、RailsモードにすることでActiveSupport 5.0のエンコード/デコードをすべて置き換えられると書かれています。

その他

  • snibox/sniboxはスニペットマネージャ」「スニペットをリモートに置く理由って、ローカルに置いとくと何かのはずみで消えそうでコワイからだよねっ😨」

  • refinery/refinerycmsはRailsのCMS、trestleは管理画面フレームワーク」「こういうのはどっちももの凄い数あるしなー🤓」「でもCMSでは誰もWordPressに勝てないという…」

  • activerecord-importは息の長いアプリ: いいやつ❤️」

  • ifmeorg/ifmeって何だろう…?」「メンタルヘルスのコミュニティみたいだけど」「そのサイトをRailsで作ってソースを公開しましたってことなのかな…🤔」

  • spreadsheet_architect、すごい名前😆」「ActiveRecordからXLSXやODSやCSVを作成できるらしい」「ODSってたしかOpenOfficeのフォーマットですね」「使ってみないとわからないけどActiveRecordから楽に作れるならいいかも」

# 同リポジトリより
Post.to_xlsx(instances: posts, spreadsheet_columns: Proc.new{|instance|
  [
    ['Title', :title],
    ['Content', instance.content.strip],
    ['Author', (instance.author.name if instance.author)],
    ['Published?', (instance.published ? 'Yes' : 'No')],
    :published_at, # uses the method name as header title Einstance. 'Published At'
    ['# of Views', :number_of_views, :float],
    ['Rating', :rating],
    ['Category/Tags', "#{instance.category.name} - #{instance.tags.collect(&:name).join(', ')}"]
  ]
})
  • 「突然にRailsの#33079が: Rails 6でWebpackerがデフォルトのJSコンパイルになると」

  • acts-as-taggable-on! こんな古いのまだあったとは👴」「だいぶ前に自分で書く方が早いって言ってたヤツですね」

  • RRRSpecといえばクックパッドさんの有名な分散RSpecシステム」

参考: 分散テスト実行システムRRRSpecをリリースしました - クックパッド開発者ブログ

  • koudokuはStripe IDを設定すれば購読フローを楽に作れそう」「どうやらサインアップが必要っぽいかな?」

Stripe決済を自社サービスに導入してわかった5つの利点と2つの惜しい点


「しかし知らないgemやアプリが結構ありましたね」「しばらくサーベイしていないと意外にいろんなのが出てるなー」「GitHub Trending以外にも情報源が見つかってうれしい😋」

なお、上の元記事は以下から抜粋・再構成したものだそうです。

参考: Weekly trending Ruby on Rails repositories. June, 11

テストでTimecopとVCRを連携させる(Hacklinesより)

短い記事です。


つっつきボイス: 「VCRってブラウザの画面操作を記録再生するツールですね」「VCRでwebmockが動かなくなってハマってた人いましたよ😨」「VCRはHTTPリクエストを横からトラップするから」「うろ覚えですけど、テスト書いている途中にwebmockしたいリクエストを間違えたりすると、VCRが無いときは単にwebmockが『mockがない』ってエラーを出すだけなのに、VCRと組み合わさると実際にリクエスト飛ばしてwebmockのカセットが作成される、みたいなことがありました」「ありゃー」「この種の自動でよしなにやってくれるgemはさり気に注意が必要🧐: ロード順序が変わると動かなくなったりとか」「VCRはこれはこれでいいgemだけどしっかり理解して使わないといけないっすね💦」

参考: VCRを使って開発中にあほみたいにリクエストを飛ばさないようにする - かずおの開発ブログ(主にRuby)

rails_event_store: ActiveRecord向けEvent Store

記事を先に出してましたが。

Rails: Event Storeの新しいAPIを解説する(翻訳)


つっつきボイス: 「rails_event_store、一度使ったことある気がする」

Avdi Grimm氏のオンライン講座「Master the Object-Oriented Mindset」(Hacklinesより)

略してMOOMだそうです。


つっつきボイス: 「Avdi Grimmさんなのでたぶんちゃんとしてそう」「現実のオブジェクト指向設計って、単に勉強しただけでは意外に習得できなくて、自分で実際に何度もやってみて失敗を重ねていかないとなかなか腑に落ちないところがありますね🧐」「それあるかも😲」

Dockerイメージビルドを10分から5分に短縮(Hacklinesより)


同記事より


つっつきボイス: 「この手のDockerビルドの速度改善はいろいろやり方がありますね」「意識的にキャッシュするように書いたりとか」

Rails 5.1の機能を使ってメール送信をリファクタリング(Ruby Weeklyより)

# 同記事より
# app/mailers/application_mailer.rb

class ApplicationMailer < ActionMailer::Base

  default from: "\"mkdev\" <#{ENV['SUPPORT_EMAIL']}>",
          subject: -> { default_i18n_subject },
          to: -> { @recipient.email }

  before_action :load_recipient

  private

  def load_recipient
    @recipient = params[:recipient]

    I18n.locale = if @recipient.is_a?(User)
                    @recipient.locale
                  elsif @recipient.user
                    @recipient.user.locale
                  else
                    :en
                  end
  end

end

つっつきボイス: 「Rails 5.1の#27825でメイラーがパラメタライズされたのでそれを活用したと記事の冒頭にありました」「その機能追加されてたなー: 上のsubject: -> { default_i18n_subject }みたいにパラメータにlambda使えたり」「書きやすくなったしこれはいいんじゃないかな😃」

その他Rails



つっつきボイス: 「社内Slackで貼っていただいたやつです」「これはついウケた: Rails本体ですらRubocopに怒られてしまうのかと😅」「DHHは見た感じRubocopに何言われても気にしてなさそうですけどね🤔」「気にしてなさそう😆」

Ruby trunkより

ruby -wcを取れるAPIが欲しい


つっつきボイス: 「-wcって何だったかな」「コンパイルのみってことらしいです」「ははぁいわゆるシンタックスチェックか」「Dry-run的な」「Ruby Language Serverで使いたいんだそうです」「分かりみある」「Ruby Language Serverってまだそんなに普及してないのかな?」「でもたとえばGitLabにRuby Language Serverが入ったらめちゃくちゃうれしい」「今ならGitLabのWebIDEも使えますしね」「そうなったらもうGitLabだけで開発しちゃう❤️: リポジトリをチェックアウトしてIDEで開かなくてよくなるし😋」「そういえば2017年のRubyKaigiの発表でもRuby Language Serverをエディタのシンタックスハイライトに使ってましたね」

doendブロックと{}ブロックの挙動が違う->仕様どおり

# 同issueより
puts [1,2,3].map do |i|
  puts i
end
#<Enumerator:0x007ffe930b76d0>

puts [1, 2, 3].map { |i| puts i }
1
2
3

演算子結合の優先順位の違いのようです。


つっつきボイス: 「へー、挙動違うのか: でも普段こんなコードをそもそも書かないし」「書かないですねー」「こういうのを見つける人たちがスゴイ💪」

ハングルのUnicode正規化が仕様と異なる(調査中->closed)

-if length>2 and 0 <= (trail=string[2].ord-TBASE) and trail < TCOUNT
+if length>2 and 0 < (trail=string[2].ord-TBASE) and trail < TCOUNT 

ハングルはわかりませんが、Rubyのunicode_normalizeがNFC(デフォルト)、NFD、NFKC、NFKDのすべてに対応していることを今頃知りました。


つっつきボイス: 「RubyというよりはUnicodeの仕様の話が中心ですね: 主に私の興味で選びました」「Unicodeは言語側で面倒見るのは大変だし、Unicodeのテストコードを書くだけでもつらそう…」「unicode_normalizeにはハングルにだけ特殊な正規化コードがあることをついでに知りました」

参考: instance method String#unicode_normalize (Ruby 2.5.0)
参考: Unicode正規化 - Wikipedia
参考: Unicode正規化 — ハングルの正規化について説明しています。

なお#14934はつっつきの時点では調査中でしたが、その後Martin先生が「パッチは技術的には正しいが現実には問題ない」として今後に備えてテストをコミットしてクローズされました。

Ruby

臨時ニュース: RubyWorld Conference 2018参加受付開始

fast-ruby: ベンチマークを元にした「Rubyが速くなる書き方集」

# 同リポジトリより
$ ruby -v code/general/attr-accessor-vs-getter-and-setter.rb
ruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin14]
Calculating -------------------------------------
   getter_and_setter    61.240k i/100ms
       attr_accessor    66.535k i/100ms
-------------------------------------------------
   getter_and_setter      1.660M (± 9.7%) i/s -      8.267M
       attr_accessor      1.865M (± 9.2%) i/s -      9.248M

Comparison:
       attr_accessor:  1865408.4 i/s
   getter_and_setter:  1660021.9 i/s - 1.12x slower

つっつきボイス: 「おー、なるほど: 現実にこれがコメントで付いた場合にどこまでそれに従うかというのはあるけどなっ」「速さが問題にならない箇所なら見やすさを優先したいときもあるし」「そういえばJavaの文字列にもこんなのがありましたね」「というと?」「Javaだと+じゃなくてStringBuilderで結合するみたいな定番中の定番の書き方があるんですよ」「Rubyで言うと+じゃなくて式展開で文字列を組み立てるみたいなヤツです」

参考: StringBuilder (Java Platform SE 8 )

Rubyでの文字列出力に「#+」ではなく式展開「#{}」を使うべき理由

fasterer: 「fast-ruby」にインスパイアされたRuby高速化サジェスチョンツール

# 同リポジトリより
app/models/post.rb
Array#select.first is slower than Array#detect. Occurred at lines: 57, 61.

db/seeds/cities.rb
Hash#keys.each is slower than Hash#each_key. Occurred at lines: 15, 33.

test/options_test.rb
Hash#merge! with one argument is slower than Hash#[]. Occurred at lines: 84.

test/module_test.rb
Don't rescue NoMethodError, rather check with respond_to?. Occurred at lines: 272.

spec/cache/mem_cache_store_spec.rb
Use tr instead of gsub when grepping plain strings. Occurred at lines: 161.

つっつきボイス: 「でこっちのfastererがサジェスチョンしてくれるツールですね」「まあこういうツールがあってもいいけどね🕶、これがCIに入ったらますます怒られることが増えそうだなー」「サジェスチョンが賢ければいいんですけど、たとえば#merge!を使うと必ず怒られたりしたらつらい😅」「『こっちの方が速い』と言われればもっともなんだけど、本質的な指摘とも限らないし」「サジェスチョンの言い回し次第かも」「でもどんな感じなのか一度使ってみたいですね😃」

「上のArray#select.firstよりArray#detectの方が速いというのは確かにもっとも: #selectは全部をまとめたものを出すんですけど、#detectは最初に見つけたものを出すんで、結果は同じでも見つけた瞬間に終わる#detectの方が速いし、たぶん可読性もこっちの方がいいし」「たいていの言語でも、全部をスキャンするメソッドと見つけた時点で終わるメソッドがそれぞれありますからね」「後者はany?的なメソッドですね」

「fastererがrubocop -aみたいに自動書き換えまでやってくれるならいいかなという気はする」「rubocop -aも万能じゃないですけどね😅」「でも-aがあるからrubocop使う気になれるというのはある: 重箱の隅的な指摘はこれでだいたい消えるし」

pragmatic_segmenter: 文章を文ごとに区切るgem(Ruby Weeklyより)

# 同リポジトリより
text = "Hello world. My name is Mr. Smith. I work for the U.S. Government and I live in the U.S. I live in New York."
ps = PragmaticSegmenter::Segmenter.new(text: text)
ps.segment
# => ["Hello world.", "My name is Mr. Smith.", "I work for the U.S. Government and I live in the U.S.", "I live in New York."]

# Specify a language
text = "Այսօր երկուշաբթի է: Ես գնում եմ աշխատանքի:"
ps = PragmaticSegmenter::Segmenter.new(text: text, language: 'hy')
ps.segment
# => ["Այսօր երկուշաբթի է:", "Ես գնում եմ աշխատանքի:"]

# Specify a PDF document type
text = "This is a sentence\ncut off in the middle because pdf."
ps = PragmaticSegmenter::Segmenter.new(text: text, language: 'en', doc_type: 'pdf')
ps.segment
# => ["This is a sentence cut off in the middle because pdf."]

# Turn off text cleaning and preprocessing
text = "This is a sentence\ncut off in the middle because pdf."
ps = PragmaticSegmenter::Segmenter.new(text: text, language: 'en', doc_type: 'pdf', clean: false)
ps.segment
# => ["This is a sentence cut", "off in the middle because pdf."]

# Text cleaning and preprocessing only
text = "This is a sentence\ncut off in the middle because pdf."
ps = PragmaticSegmenter::Cleaner.new(text: text, doc_type: 'pdf')
ps.clean
# => "This is a sentence cut off in the middle because pdf."

つっつきボイス: 「どこからどこまでが1つの文かをマルチリンガルで検出するやつですね: READMEに区切りのルールがびっしり書いてあります」「言われてみれば?!も文の終わりを表すのか: ラノベをこれで処理したら相当戸惑いそうではある😆」

「そういえばタイ語は文末にストップマーク(。や.など)がなくてスペースを置く、でも行末だとスペースは略すという凄い言語なのでパーサー泣かせで有名です😢」「単語と単語の間はスペースあるんでしょうか?」「えっとどっちだったかな…(追記: 単語間のスペースはありませんでした)」「まあそもそも文の中に単語があるみたいな構成の言語ばかりじゃないですしね: ヒエログリフとか😆」「そういえばヒエログリフは顔が右を向いてるか左を向いてるかで文の進行方向が変わりますね😅」

参考: TRADOS - Wikipedia — 翻訳支援ツール(文の区切りを事細かに設定可能)

どこまで継承でやるか

継承は悪か
(中略)
「継承はカプセル化の概念を破壊する」件については、また別にもう少し考えなければなりません。 なぜ継承がカプセル化の概念を破壊するかといえば、 サブクラスはインスタンスの構造に直接触ることができるからです。
インスタンス変数を直接参照すれば、スーパークラスの実装に強く依存してしまいますし、 インスタンス変数を直接更新すれば、インスタンスの不整合な状態を作り出すことができます。 確かにこれはカプセル化の原則に対立します。
しかし、スーパークラスで定義されたインスタンス変数に直接触ることができることは、 オブジェクト指向言語にとって必須ではありません。たとえばC++はprivateなメンバには サブクラスからもアクセスすることができません。そしてさいわいなことにprivateがデフォルトです。 これが私の考えるC++の唯一優れた点なのですが。
(中略)
結局問題なのはRubyのような言語がスーパークラスのインスタンス変数に簡単に触れてしまうという 「言語上の欠陥」なのであって継承そのものの問題ではないのですよね。 Rubyの次の世代の言語はぜひ「インスタンス変数はクラスローカル」が常識になってもらいたいものです。 事実、Perl6ではそうなるってDamian Conwayが言ってました。
同記事より

2003年のMatzの日記です。


つっつきボイス: 「何でも継承で書くもんじゃないというのはそのとおりですね🧐」「どちらかというと、オブジェクト指向の教科書がおしなべて最初にextends(Javaで言う継承)がオブジェクト指向』的なことを書いてしまっているから、それに釣られてみんな何でも継承でやろうとしちゃっている面があるんじゃないかな」「Matzも『is-aの関係かどうかが継承を使うときの唯一の基準』と書いてますしね」「言い換えれば継承は機能を拡張するためのものじゃないってこと」

「『スーパークラスのインスタンス変数に簡単に触れてしまう』はどうでしょう?」「Rubyのprivateはprivateじゃないから😆」「Rubyのprotectedが一番難しい: 毎回ググってるし」「そういえばC++はvirtualを書かないとメソッドをオーバーライドできないので、他の言語をやってからC++をやると結構戸惑う💦: virtualだと同名の別メソッドができるし」

参考: JavaやC#の常識が通用しないRubyのprivateメソッド - give IT a try
参考: 仮想関数 - C++入門

書籍『Working with TCP Sockets』

TCPソケットをRubyで解説しています。有料です。

参考: 「Working with TCP Sockets」を読んだ - Fire Engine


つっつきボイス: 「TCPソケットのようなネイティブなものを勉強するなら個人的にはC言語でやるのをおすすめしたい🧐」

Rake::DSLを使おう(Ruby Weeklyより)

# 同記事より
# lib/tasks/bicycle.rake

class BicycleTasks
  include Rake::DSL

  def initialize
    namespace :bicycle do
      task :assemble do
        bicycle = Bicycle.new

        # Assemble the bicycle:
        attach_wheels(bicycle)
        attach_handlebars(bicycle)
        attach_brakes(bicycle)
      end
    end
  end

  private

  def attach_wheels(bicycle)
    # ...
  end

  def attach_handlebars(bicycle)
    # ...
  end

  def attach_brakes(bicycle)
    # ...
  end
end

# Instantiate the class to define the tasks:
BicycleTasks.new

しかしなぜか最近のRuby公式ドキュメントにはRake::DSLのドキュメントが見当たらないようです。

参考: Module: Rake::DSL (Ruby 2.2.1)
参考: library rake (Ruby 2.5.0)

Ruby 2.5.1のmasterにはRake::DSLモジュールはあり、読み込めました。

splatとdouble splatの挙動


つっつきボイス: 「上みたいに示されると引数の"a" => 1, a: 1のハッシュが別物というのは何となくわかる気がする」「3つ以上引数が渡されるとどうなるのかな?↓あー[[{"a"=>1}], {:a=>1, :b=>2, :c=>3, :d=>4}]だから1つ目以外は全部**kに吸い込まれるのか😲」「1つ目のsplat *aと2つ目のdouble splat **kが連続しているとどっちに吸い込まれるのかがわかりにくいってのが問題なんでしょうね🤔」

irb(main):004:0> p m("a" => 1, a: 1)
[[{"a"=>1}], {:a=>1}]
=> [[{"a"=>1}], {:a=>1}]
irb(main):005:0> p m("a" => 1, a: 1, b: 2)
[[{"a"=>1}], {:a=>1, :b=>2}]
=> [[{"a"=>1}], {:a=>1, :b=>2}]
irb(main):006:0> p m("a" => 1, a: 1, :b => 2)
[[{"a"=>1}], {:a=>1, :b=>2}]
=> [[{"a"=>1}], {:a=>1, :b=>2}]
irb(main):007:0> p m("a" => 1, a: 1, :b => 2, c: 3, :d => 4)
[[{"a"=>1}], {:a=>1, :b=>2, :c=>3, :d=>4}]
=> [[{"a"=>1}], {:a=>1, :b=>2, :c=>3, :d=>4}]

Rubyのパラメータと引数の対応付けを理解する(前編)

クラウド/コンテナ/インフラ/Linux/Serverless

Googleの「Serverless containers」と「Knative」


つっつきボイス: 「ああこれね: Serveless containersといいつつサーバーあるじゃんって思ったり😆」「流行り系」「これはもうリソースすら意識しなくてよくなるってことですかね?」「今日のBPS勉強会で出てきたDockerの話で言うとそうでしょうね: AWSのFargateに近い感じで、インスタンスを意識しなくてよくなる」
GKEというかKubernetesのPodって、AWS ECSでいうサービス(タスク定義の実体)に相当するんだと思うんだけど、とにかくKubernetesのPodだとまだインスタンスを意識しないといけない」


github.com/knative/docsより

「Knativeは何でしょうね?Kubernetesのnative?」「まだ詳しく見てないけど、KnativeはKubernetesが最終的に目指したい夢なんでしょうね」「ただこうやって自動化すると今度はlocalityの問題が出てくるから大変: 現在の管理ツールでどのインスタンスで動作するのかまで設定しないといけない理由のひとつが、データベースとアプリのコンテナみたいなものは互いにうんと近くないとパフォーマンスがめちゃくちゃ落ちるから」「あー😲」「だからそういうクリティカルなもの同士はlocalityつまりできる限り同じ物理サーバ上で動くことを担保したい: AWSのDedicated Hostsもそのためのオプション」「ふむぅ」「だから単に自動化されると、いつの間にかlocalityが失われてパフォーマンスが落ちたなんてときにトラブルシューティングしようがなくなってしまうので、そういう部分をうまく設定できるかが重要: まだちゃんと見てないけど、やるからにはそういう部分を扱えるだろうと予想してる」「😀」

「ちなみにlocalityはインフラ業者側にとっても常に切実な問題で、同じ物理サーバーに乗っていればネットワークトラフィックがその中で収まるのに、遠くに配置されてしまえばその分トラフィックが増えてしまう: だからインフラ業者もlocalityを損なわないようにいろいろやっているはず」「なるほどー」

参考: [速報]Google、コンテナ実行環境をサーバレスで提供する「Serverless containers」発表。Google Cloud Next ’18 - Publickey

参考: 最強のServerlessプラットフォーム? Knative登場 - Cloud Penguins

RailsをDockerに置くな(Hacklinesより)

短い記事です。


つっつきボイス: 「気持ちは一応わかる: 記事にもあるprybundle openbundle installとかはDockerに置いても一応同じことはできなくはないんだけど、やり方が面倒になるのは確か」「確かRailsdmでもこのあたりについて話していた発表があったと思う↓」「Docker化するとコマンドが増えますし」「本来の設計からかけ離れてしまったり」「複数のサーバークラスタに分散しているときにどのコンテナでrails consoleを実行すべきか?、とかDockerだと何かとややこしくなるわけですよ」「ふーむ」

Twitterのアプリ連携仕様が変更


つっつきボイス: 「めちゃめちゃ不評を買ってたやつですね😆」「😆」「開発者を切り捨てる方向に向かってるとしか思えない…」

Go Cloud: クラウド全般向けライブラリ

// 同記事より
// setupBucket opens an AWS bucket.
func setupBucket(ctx context.Context) (*blob.Bucket, error) {
    // Obtain AWS credentials.
    sess, err := session.NewSession(&aws.Config{
        Region: aws.String("us-east-2"),
    })
    if err != nil {
        return nil, err
    }
    // Open a handle to s3://go-cloud-bucket.
    return s3blob.OpenBucket(ctx, sess, "go-cloud-bucket")
}

つっつきボイス: 「マルチクラウドプラットフォームでやれるみたいなので、Terraformをちょっと思い出す」


terraform.ioより

「ちなみにTerraformは理想は高いけど、AWS向けに書いたTerraformのコードが無修正でGCPで使えるかというと現実にはそんなことはないので😆」「😆」「Terraform自体はどんなものでしたっけ?」「Terraformはクラウドの設定をTerraformの書式で書けるもので、普通だとGCPにはGCPの設定ファイルを書かないといけないしAWSだとCloudFormationというのがあってそれで書かないといけないので互換性がないんですけど、Terraformの中間コードで設定を書けばGCPにもAWSにも変換できるというものです」「😃」「おー、もっと壮大なものを想像してたんですが、設定を生成するマクロというか中間言語的なものだったんですね😲」

「Terraformが流行った理由のひとつが、かつてのAWS CloudFormationがJSONにしか対応していなくて設定がとてもつらかったからなんですが、ここ一年ぐらいの間にCloudFormationがYAMLでも書けるようになったりGUIエディタが使えるようになったりと充実してきたせいか、前ほどTerraformの話題を見かけなくなったような気がする」「ふーむ」

モバイル/Android/iOS

Flutter Weekly


flutterweekly.netより

早くも#29だそうです。


つっつきボイス: 「社内アプリチームのFlutter勢からです」「iOSアプリもAndroidアプリもこれで書けるとしたらスゴイかも😳」

参考: FlutterでAndroid/iOS両対応アプリを作ってみる

Firebase SDK 2.0がリリース


つっつきボイス: 「社内でもアプリチームが使ってるみたいですね」「Firebaseはフロント系の人には大人気です: サーバーサイドのコードが要らないのでフロントエンジニアだけでアプリが作れるし」「お?!」「Firebaseの裏にデータベースを置いてそこにアクセスするAPIを自由に書けるみたいな感じ?」「それもできますが、Firebase自体はもっともっと壮大ですよ: Firebaseがあればマジでサーバーレスで何でもできる💪」「管理コンソールも充実してるし」「通知やレポートを投げたりとかもできるし」「データベースを置くとかもできるし、アプリのリリース管理もできるし、ほんと何でもできる」「アプリに更新をプッシュするだけじゃなかったんですね😆」「そういえばFirebaseは何年か前にGoogleが買収したんでしたね」「(最初からGoogleの製品だと思ってた…😅)」「フロントエンジニアにとってはとてもいいプラットフォーム❤️」

参考: Cloud Functions for Firebase  |  Firebase

SQL

PostgreSQLのSQL方言は先進的(Postgres Weeklyより)


同PDFより


つっつきボイス: 「ぽすぐれは機能が異常に多いからもうしょうがない😆」「使ったことないSQLとかいっぱいあるし」「(スライドを見ながら)ちょうどXMLTABLEが目についたので: 自分が学生だった頃は、データベースで一番権威のある国際会議のプロポーザルが2000ページぐらいあったんですけど、その半分ぐらいがXMLデータベースだった」「😲」

私の愛するPostgreSQLクエリたち(Postgres Weeklyより)


つっつきボイス: 「バックスラッシュ\使うクエリとかあったねー」「もう思い出せない…💦」「\?とかすれば表示されますよ😎」「PostgreSQLはコマンドもバックスラッシュだらけですし」「しかもロングバージョンがないし」「そんなにたくさんはないから覚えられますけどね😉」

PostgreSQLのJSONドキュメントAPI拡張「dox」を作った(Postgres Weeklyより)

# 同リポジトリより
select * from dox.search(collection => 'customers', term => 'jill'); -- full text search on a single term
select * from dox.find_one(collection => 'customers', term => '{"name": "Jill"}'); -- simple query
select * from dox.find(collection => 'customers', term => '{"company": "Red:4"}'); -- find all Red:4 people

つっつきボイス: 「生のJSONBの検索はいろいろつらいからもう少しマシな方法でやれるようにしたってことか」「クエリとして書けるようにしたんですね」「JSONBの比較演算子はもう宇宙語並にわけわからないし」「こうやって見やすく書けるならいいかもね😋」

参考: JSON関数と演算子

JavaScript

Note.muがフロントエンドをAngular.jsからNuxt.jsに移行予定


ja.nuxtjs.orgより


つっつきボイス: 「Nuxt.jsはVue.jsのベストプラクティス的なものらしいですね」「移行することのビジネス上のメリットがどのぐらいあるのか知りたいところではある🤔」

WebAssemblyの未来を探る(JavaScript Weeklyより)

プロポーザルなどが紹介されています。


つっつきボイス: 「最近のWebAssemblyではLinuxカーネルも動きますからね😎」「マジで😲?!」「シェルはまだ動かないみたいですが」「LLVMも動いたと思う」「mrubyも動きますしね」「それだけ動けばもうたいていのものは動きそう」


スレチですがこんな記事も見つけました。

参考: サクッと Go → WebAssembly を試す - Qiita

Go 1.11beta1で動きました😋↓

hypernova: JSのビューをサーバーサイドレンダリング(JavaScript Weeklyより)

airbnb製です。gemもあり、Railsでも使えると言ってます。

# 同記事より
class SampleController < ApplicationController
  around_filter :hypernova_render_support
end
<%= render_react_component('MyComponent.js', :name => 'Hypernova The Renderer') %>

hypernova {名} : 極超新星


つっつきボイス: 「似たようなSSR(サーバーサイドレンダリング)用のものをどこかで見た気が」「これを入れるだけでちゃんと動くならいいけど、どうせデバッグしないといけなくなるだろうし😆SSRは基本やりたくない」

「SSRは、速度向上と、SEO向けの対応という2つの側面がありますね」「後者は、SPAアプリとかでJavaScriptで画面を作っていると、動的なコンテンツを検索エンジンのクローラーが評価できなくなってSEO的に不利だから、その対応としてSSRを行うというヤツ」「もともとそれがSSRの目的でしたね」

「今はクローラーがJavaScriptを実行してからクロールするらしいから大丈夫になったのかな?」「Googleはそうだと言ってるけど、どこまで大丈夫かはまだ読みきれないところがある🤔」

参考: SPAを導入する際に必要だったSEO対策についての話 -SSR? Prerendering?- - Qiita

CSS/HTML/フロントエンド/テスト

Chrome 68リリースでついにHTTPサイトに警告表示開始

たまたま気づきましたが、Windows版(上)とMac版(下)でメッセージの訳文が違ってますね。


つっつきボイス: 「違ってる😆」「そんなに強い言葉でもないからまあ大丈夫かな…」「背景が赤だったらインパクト大きい」

参考: 「Chrome 68」公開、HTTPサイトに「保護されていません」の警告を開始 - CNET Japan

重要なHTTPセキュリティヘッダーとデプロイ方法(Hacklinesより)


つっつきボイス: 「X-Content-Type-Optionsは、最近これを付けないと通らないことある」「このヘッダーって、確かすごく古いブラウザで問題が起きないようにするやつでしたね: 古いIEでPDFの中身を見ると落ちちゃう場合にnosniffを指定する」「X-Frame-Optionsは、iframeを開いていいかどうかを判断するヤツで、SAMEORIGINにするとoriginが同じなら開ける」「任意のJSをぶち込まれてもこれが入ってれば防げることになっている」「面倒だけどこの手のヘッダーはまだまだ必要なので、こういう記事は読んでおくとよいです❤️」

参考: X-Content-Type-Options: nosniff つかわないやつは死ねばいいのに! - 葉っぱ日記
参考: X-Frame-Options - HTTP | MDN

言語よろず部屋

臨時ニュース: Python作者Guido van Rossum氏が意思決定から手を引くと表明

BDFL(Benevolent Dictator For Life: 優しい終身の独裁者)という略語を初めて知りました。

参考: 優しい終身の独裁者 - Wikipedia
参考: どうなるPython--生みの親「優しい終身の独裁者から引退」表明で衝撃 - ZDNet Japan

その他

セキュリティ関連

PDFは無料で読めます。

四分位数とは

平成29年度の中学校の指導要領に含まれているそうです。


同記事より


つっつきボイス: 「四分位数…?」「なるほど箱ひげ図ね: 大学に入って必要に迫られて使ったけど習った覚えがない😆」「箱ひげ図ってたいてい縦向きですよね」「箱ひげ図は、最大値と最小値がひげの端で、端から1/4のところに第1四分位点と第3四分位点のところに箱を置いて、さらに中央値(メジアン)を置くことで分散を見やすくしたりする」「箱ひげ図という表し方があることを知っておくとデータを見せるときに便利❤️」

参考: 箱ひげ図 - Wikipedia

追記(2018/08/08): 上記訂正します🙇。四分点の定義は図によって異なるので注意が必要なんですね。

参考: 4-2. 箱ひげ図の見方 | 統計学の時間 | 統計WEB

誰しも最初は


つっつきボイス: 「あのhikaliumさんでもそうだったとは😲: 小学生のときにOS自作本を読んでその道に進んだスゴイひとで、例のTuring Complete FMによく登場している人」

番外

火星の話題2つ

参考: 火星に巨大地下湖、欧州探査機が発見 水の存在「疑いない」 写真3枚 国際ニュース:AFPBB News

ついでながら、明日7/31は火星が大接近します。

参考: 火星大接近2018 | 国立天文台(NAOJ)


つっつきボイス: 「この間から真夜中に火星ばかり異様に目立っててキモチワルイと思ってました」「天文好きな人はぜひ✨🌗」「そういえば天文出身の人ってまだBPSにいないな: ちなみに上の世代でコンピューターに詳しい人って数学とか天文とか音楽の人が多い」

そういえばパズル作者としても有名なこの方↓も天文出身でした。

参考: 岸田孝一 - Wikipedia


今回は以上です。公開つっつき会でお会いしましょう!

バックナンバー(2018年度後半)

週刊Railsウォッチ(20180723)Railsdm Day 3 Extremeを後追い、PSDにはZeplin.io、好みの分かれるJSX、負荷テストツール比較ほか

今週の主なニュースソース

ソースの表記されていない項目は独自ルート(TwitterやRSSなど)です。

Rails公式ニュース

Ruby Weekly

RubyFlow

160928_1638_XvIP4h

Hacklines

Hacklines

Postgres Weekly

frontendweekly_banner_captured

JavaScript Weekly

javascriptweekly_logo_captured

デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ 開発エンジニア積極採用中です! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好き。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

ActiveSupport探訪シリーズ