Tech Racho エンジニアの「?」を「!」に。
  • 開発

週刊Railsウォッチ(20180615)TTY gemとHTTPClient gemは優秀、Rubyの謎フリップフロップ、ちょいゆるRubyスタイルガイドほか

こんにちは、hachi8833です。仙台疲れが今になって来たような気がしないでもありません。雨の降らない国に行きたいです。

晴耕雨読のウォッチ、いってみましょう。

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

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

今回も主に公式のコミット情報からです。

TableDefinition#columnでカラム定義が重複すると例外を出すように修正

# activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb#L354
       def column(name, type, options = {})
         name = name.to_s
         type = type.to_sym if type
         options = options.dup

-        if @columns_hash[name] && @columns_hash[name].primary_key?
-          raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
+        if @columns_hash[name]
+          if @columns_hash[name].primary_key?
+            raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
+          else
+            raise ArgumentError, "you can't define an already defined column '#{name}'."
+          end
         end

         index_options = options.delete(:index)
         index(name, index_options.is_a?(Hash) ? index_options : {}) if index_options
         @columns_hash[name] = new_column_definition(name, type, options)
         self
       end

つっつきボイス:TableDefinitionなんてのがあるのね」「マイグレーションがらみのようです」「create_tablet.columnが呼ばれるときの重複チェックを今回修正したと: テストコードがわかりやすい↓」「普通やらかさないエラーだろうけどraiseはしとかないとね😋」

# activerecord/test/cases/migration/change_schema_test.rb#L199
+      def test_create_table_raises_when_defining_existing_column
+        error = assert_raise(ArgumentError) do
+          connection.create_table :testings do |t|
+            t.column :testing_column, :string
+            t.column :testing_column, :integer
+          end
+        end
+
+        assert_equal "you can't define an already defined column 'testing_column'.", error.message
+      end

参考: Ruby on Rails 5.2 / ActiveRecord::ConnectionAdapters::TableDefinition — DevDocs

columnがconnection_adapters/abstract/schema_definitions.rbにあるということは、abstractすなわち複数のコネクタで共通で使われるメソッドなんでしょうね: ぱっと見ですが」「abstractクラスなのでそれで合ってると思います🧐(どこに実装されてるかとかはちゃんと追わないといけないですが)、上のエラーももしかするとDBMSの種類によっては通っちゃうことがあったのかもしれないですね: SQLite3とか割と作りが雑なんでカラム名かぶっても通っちゃうとかありそう、知らんけど😆」「😆」

「そういえば先週のウォッチでもSQLite3ラブラブ❤️な意見が出てました」「ちなみにSQLite3、かなり速いっすよ🕶: Win32アプリみたいなPCローカルアプリで使うDBMSとしては読み込み速度とかめっちゃ優秀」「あー、そういえば以前いた職場の社内ツールでも中でSQLite3が走ってました」「ただSQLite3って型とかが割と雑で、確か内部では数値なんかも文字列で保存してたような覚えがあるんですよ」「『保存してSQLっぽく検索できればそれでいいのっ』って感じなんでしょうね😓」「だからこそ速いんでしょうけどね🤓」

参考: SQLite Home Page


sqlite.orgより

ActiveSupport::Time.zone.atTime::atの引数の不揃いを解消

# 同PRより
# Before:
Time.at(946684800, 123456.789).nsec       #=> 123456789
Time.zone.at(946684800, 123456.789).nsec  #=> ArgumentError (wrong number of arguments (given 2, expected 1))
# After:
Time.at(946684800, 123456.789).nsec       #=> 123456789
Time.zone.at(946684800, 123456.789).nsec  #=> 123456789
# activesupport/lib/active_support/values/time_zone.rb#L357
-    def at(secs)
-      Time.at(secs).utc.in_time_zone(self)
+    #
+    # A second argument can be supplied to specify sub-second precision.
+    #
+    #   Time.zone = 'Hawaii'                # => "Hawaii"
+    #   Time.at(946684800, 123456.789).nsec # => 123456789
+    def at(*args)
+      Time.at(*args).utc.in_time_zone(self)
     end

つっつきボイス:Time.atTime.zone.atを揃えたようです」「おや?これで見るとTime.zone.atの方を変えてる?: Time.zone.atの方が使用頻度多いし(つかRailsではそもそもこっちを使うべき👮‍♂️)、Time.atをじかに使うことってほとんどないと思うんだけどなー」「それもそうですね...🤔」「breaking changeになりそうに見える🕶」「そのときはRailsアップグレードガイドに載るんでしょうね」

参考: Ruby on Rails 5.2 / Time::at — DevDocs
参考: Ruby on Rails 5.2 / Time::zone — DevDocs

.dup.freeze-ショートハンドに置き換え

# activemodel/lib/active_model/attributes.rb#L103
       def self.set_name_cache(name, value)
         const_name = "ATTR_#{name}"
         unless const_defined? const_name
-          const_set const_name, value.dup.freeze
+          const_set const_name, -value
         end
       end

つっつきボイス: 「出たな-🤣」「あ、これ以前のウォッチでもみんなで『キモチワルイー』って言ってた文字列dup&freezeのショートハンドですね😆」「確かRuby 2.5の機能じゃなかったっけ? Ruby 2.3からの機能でした(下記参考)」

2018/06/18追記: @sakuroさまよりTwitterにてご指摘頂いたので加筆・修正いたしました。ご指摘ありがとうございました 🙏

毎度のことですが、記号は検索しづらいです(リンクを見つけるのに30分近くかかりました😭)。マイナス記号-です。

参考: instance method String#-@ (Ruby 2.5.0)

selfがfreeze されている文字列の場合、selfを返します。 freezeされていない場合は元の文字列のfreezeされた (できる限り既存の) 複製を返します。
ruby-lang.orgより

参考: NEWS for Ruby 2.3.0 (Ruby 2.3.0)
参考: Feature #11782 String#+@ and String#-@

記号の雑学

ついでながら、マイナス記号とハイフン記号とダッシュ記号は本来は別の記号だったのですが、記号を増やしようがないタイプライターの時代に1つのキーで代用されてしまい(長いemダッシュは--としたり)、それがそのままASCIIなどにも持ち込まれてハイフンマイナスという苦し紛れな名前が付けられ、Unicodeで別記号が用意された今も地味に混乱を呼び続けてます。ハイフン記号とマイナス記号とダッシュ記号(emダッシュとenダッシュ)の使い分けには闇が横たわっています。ヨーロッパの一部には、ハイフンとダッシュを取り違えて使うとマジギレする国がありますのでご用心。見た目1ドットぐらいしか違わないんですけどね...😫。



Dash vs. Hyphen ~ IngliszTiczer.plより

参考: ハイフンマイナス - Wikipedia
参考: ハイフン - Wikipedia
参考: ダッシュ (記号) - Wikipedia

重複した子レコードを親がsaveしないよう修正

# 同issueより再現コード
# モデル

class Parent < ApplicationRecord
  has_many :children
end

class Child < ApplicationRecord
  belongs_to :parent
  validates :name, uniqueness: true
end

# コード
parent = Parent.new(children: [Child.new(name: 'Wiske'), Child.new(name: 'Wiske')])
parent.save
parent.errors.any?  # エラーになるはずが、ならない

つっつきボイス:validates uniqueness: trueだから本来エラーにならないといけないやつ: へー、この書き方↓するとすり抜けちゃってたのか😇」「😇」

Parent.new(children: [Child.new(name: 'Wiske'), Child.new(name: 'Wiske')])

「これは下手すると既存のアプリでも知らないうちにエラーを作り込んじゃってたりすることがあるかも?自分はこの書き方はしないけどねっ🕶」

「ついでに聞いちゃいますけど、今見ているコードにあるreflection↓っていう言葉は、ここではどういう意味が込められているんでしょうか?(英語的にいっぱい意味がありすぎるので🤯)」「reflectionというと、メソッドオブジェクトを取ってきてそれをゴニョゴニョしたいなんてときに使いますね」「あー、メタプログラミング的な?」「たぶんプログラミング関連ではそれ以外の意味でreflectionという言葉が出てくることはあまりないと思うので💦」

# activerecord/lib/active_record/autosave_association.rb#L381
       def save_collection_association(reflection)
         if association = association_instance_get(reflection.name)
           autosave = reflection.options[:autosave]
...
               if autosave != false && (@new_record_before_save || record.new_record?)
                 if autosave
                   saved = association.insert_record(record, false)
                 elsif !reflection.nested?
-                  association_saved = association.insert_record(record)
                   if reflection.validate?
-                    saved = association_saved
+                    valid = association_valid?(reflection, record, index)
+                    saved = valid ? association.insert_record(record, false) : false
+                  else
+                    association.insert_record(record)
                   end
                 end
               elsif autosave

「たとえばですが、reflectionという名前の変数があるとすると、その中には状況によってさまざまなオブジェクトが動的に入る可能性があるよ、という意図が強調される感じですかね」「おー、『あのクラスとあのクラスだけが入ると思うなよ』っていうイメージですか」

「あくまでイメージというか概念寄りの話ですが、reflectionという言葉が使われていると、そこにどんなオブジェクトが入るかわからないし、どんなオブジェクトが来てもいいという感じ: C言語の(void *)キャストとか、Javaの(object)キャストなんかが概念的に似ているかな」「なるほどー!😀」

参考: 強く型付けされているJavaの理解に必修の“型変換” (2/3):【改訂版】Eclipseではじめるプログラミング(18) - @IT

「このコードならreflection.validate?とあるから、普通ならreflectionにはActiveRecordオブジェクトやActiveModelのインスタンスが入るんだろうけど、それ以外のオブジェクトが入る可能性だってあるんだぜ、という主張を込めて自分なら使うかな😎、ここでは知らんけどw」「😃😃」

reflectionには「反射」「反省(self reflection)」「反映」などなどいろんな意味がありますが(「反」の文字が共通してますね🧐)、ポイントは意味が受動的なところかなと思いました。反映もapplyで表すと人間が能動的にやるイメージですが、reflectだと受動的というか性質に従って自動的に行われる、というニュアンスが強いと思います。reflectionがメタプロの文脈でよく使われるのもそれなのかなと。

人間の態度や状況が何かにreflectするとは、そうした態度や状況(またはそう思われるもの)がそこに存在することが示されていることを表す。
Cobuld英英辞典より大意

初期化ブロックがbuild_recordにあるのをbefore_addに移動

以下はコミットログから見繕いました。

# https://github.com/rails/rails/commit/c256d02f010228d260b408e8b7fda0a4bcb33f39#diff-20f545c453ee24942b6f7ae565e9e369R104
       def build(attributes = {}, &block)
         if attributes.is_a?(Array)
           attributes.collect { |attr| build(attr, &block) }
         else
-          add_to_target(build_record(attributes)) do |record|
-            yield(record) if block_given?
-          end
+          add_to_target(build_record(attributes, &block))
         end
       end

つっつきボイス: 「改修範囲が広いので取りあえずこれだけ引用してみました」「ここだけ見て言うと、add_to_targetというのはおそらくフックを追加するメソッドかな: で、そういうコールバック登録の枠組みが既にあるならそれに揃えようよってことなんだと思う」「😀」

# rails/activerecord/lib/active_record/associations/collection_association.rb#L282
      def add_to_target(record, skip_callbacks = false, &block)
        if association_scope.distinct_value
          index = @target.index(record)
        end
        replace_on_target(record, index, skip_callbacks, &block)
      end

force_equality?をpublic APIに

43ef00eの続きだそうです。

# https://github.com/rails/rails/pull/33067/files#diff-e66146ba2ab968e251944a764e4ed967R54
+      def force_equality?(value)
+        coder.respond_to?(:object_class) && value.is_a?(coder.object_class)
+      end

つっつきボイス:@kamipoさんが何度かに分けて修正したようです」「force_equality?ってメソッドがあるのか: どうやらrespond_to?(:object_class)でオブジェクトのクラスまで含めて等しいかどうかをチェックするやつみたいですね」「おー」「たとえばシリアライズしたときのパラメータのリストは同じでも、オブジェクトの種類が違うものがやってくることがあったりするけど、そういうのも検出するということでしょうね」「😃」

「このメソッドなら、たとえばSTI(Single Table Inheritance)なんかでそれが親クラスのオブジェクトなのか子クラスのオブジェクトなのか、なんてのも見分けられるはず」「なるほど!」「オブジェクトが参照しているデータベースが同じだとシリアライズした後では区別できなくなっちゃうけど、シリアライズより前にそういうところをチェックするときに使えるんじゃないかな?ってね🤓」「😋」「これが欲しい気持ち、よくわかる」

Rails: STI(Single Table Inheritance)でハマったところ

参考: Rails ActiveRecordのSTI(Single Table Inheritance)の使い方 | EasyRamble

Rails

Bundler 2リリース間近のチェックリスト

Bundler関連ということで関連してこちらも。


つっつきボイス: 「リリースはまだみたいなので、こういうことをやりますリストですね」「そういえば今はもうRubyをバージョンアップすると最新のBundlerが入るようになったんだっけ?どっちだったっけ?」「えーと」

そういえばRuby 2.5でのBundler標準化は延期されたのでした↓。

「チェックリストをざざーっと見た感じでは互換性の心配ほとんどなさそうというか、こっちでやることあまりないかも?: つか互換性なかったらRubyバージョンを単純に上げたときに即死だし😇」「Bundlerといえば、HerokuのBundlerが最新でないのでwarning出たりたまにつっかえたりするんですよね(今はどうだったかな💦)」「まーHerokuの場合Herokuの環境に身を任せないといけないので、面倒を見てくれる範囲は大きいけど自分はコンテナでやりたいかなー😂」「😀」「Linuxサーバーの面倒なところ触りたくないっという人にはもちろんHerokuはおすすめですね: Railsチュートリアルは今もHeroku使ってるんだったかな?」「今は違ってたような...?」

後で調べたら、Railsチュートリアルは今もHeroku使ってました

graphql-ruby: Railsとも連携


graphql-ruby.orgより

今回のウォッチは何となくShopify成分が多めでした。


つっつきボイス: 「これ扱ったことなかったっけ?」「なかったっぽかったので(と思ったらありました💦)」「このロゴは素晴らしいですね😍」「グラフ理論のグラフをうまくあしらってるし😎」

参考: apollo + rails(graphqlサーバー)でファイルをアップロードするmutationを作る方法 - Qiita

Active Record 5.2のメモリ肥大化を探る

このSam Saffaronさんのブログは良記事多いですね。翻訳許可をいただいたので今後出したいと思います。

# 同記事より
a = []
Topic.limit(1000).each do |u|
   a << u.id
end

つっつきボイス: 「あー、↑こうやって書けばそりゃ確かに肥大化するナ」「eachを使ってるから?」「eachだけじゃなくてu.idを参照してるから: このu.idを評価しないといけないのでu.idが呼ばれるたびにTopicというモデルのオブジェクトが生成される」「そっちかー」「しかもそれをa <<で代入しちゃってるからこのループの間このモデルオブジェクトがまったく解放されない」「😲」「pluckすると速いって記事に書いてあるのもたぶんそれで、pluckならモデルオブジェクトを保持する必要ないはずだし」「pluckは配列を返しさえすればいいですしね」

「確かこの間のRails Developers Meetup 2018でもまさにこの辺の話をしていた人がいたと思う」「自分見てなかったかも😓」

後でmorimorihogeさんからセッション名を教えていただきました↓。

参考: railsdm2018で「ActiveRecordデータ処理アンチパターン」を発表しました - Hack Your Design!

「まーでもActiveRecordの挙動とかlazy loadingのあたりなんかを忖度できるようにならないと、上のような書き方がヤバイ理由は見た瞬間にはわからないでしょうねー🧐」「そこが経験が必要なところかー😃」「あかんのはu.idという参照の仕方です😎: 終わってからGCすれば消えますけど(たぶんね)」「覚えます!」

参考: Ruby on Rails 5.2 / Enumerable#pluck — DevDocs

最近知ったRailsの便利なメソッド

Rails 5で「関連付け先のないレコード」を使う(Ruby Weeklyより)


つっつきボイス: 「記事のスタイリングとかシンタックスハイライトがちと読みづらい...」「関連付けのない場合ってことなのかな?ざざっと見た感じ、assosiation先のレコードがなくても取得したい場合にLEFT JOINでの外部結合をActiveRecordでどう書くかって話のように見える」「時間ないので次行きましょうー」

  • Rails 4までは生SQLでJOIN
# 同記事より
User.join('left outer join posts on posts.user_id = users.id')
  .where(posts: {user_id: nil})
  .first
  • Rails 5はちょっとだけクリーンで読みやすい気がする
# 同記事より
User.left_joins(:posts)
  .where(posts: {user_id: nil})
  .first

Rails 5.2のcredentialはセキュアではない?(RubyFlowより)


つっつきボイス: 「GitHub Wikiにざざっと書いた、1ページで収まる内容ですね」「これはわかりみあるヤツ: Rails 5.2のcrenentialは、言ってみれば例のTwelve-Factor Apps↓の原則3『設定を環境変数に格納する』に反してるんですよ」「あー」

参考: The Twelve-Factor App (日本語訳)


12factor.netより

「原理主義者としては許せないでしょうけど、そこまで行かなくても自分もこの辺は微妙: マスターキーの扱いっていろいろ難しいんですよ」「というと?」「チーム開発をしていると、開発メンバーが入れ替わるたびにマスターキーを変えないといけなくなるから: そして現実にメンバーの出入りはよくあることだし」「あー!🤫」「しかもマスターキーの変更履歴がリポジトリに残るのも、どうもねー🤔」「記事の人はnot secureとか書いてるけど、単にcredentialが好きじゃないんでしょうねー😆自分も使うつもりたぶんないし」「😆」

deep_pluck gemがRails 5.2に対応


つっつきボイス:pluckの入れ子版みたいなこのdeep_pluckウォッチで扱ったことありましたね: たぶんバッチとか書くときなんかに優秀なヤツ👍」「😀」「これもActiveRecordオブジェクトを生成しないから速いんだとしたら、自分なら生SQL書いちゃう、かなー?😆」「😆」

その他Rails

週刊Railsウォッチ(20170407)N+1問題解決のトレードオフ、Capybaraのテスト効率を上げる5つのコツほか


そろそろJSの組み合わせが爆発しそう。


つっつきボイス: 「ちょうど今日のチームミーティングでもWebpackについて発表ありましたけど、やっぱりWebpackerを知るにはWebpackそのものを知っておかないと結局後で困ることになりますね😆」「😆」


webpack.js.orgより



つっつきボイス: 「テストって最初のうちはどの程度までみっちり書けばいいのか真剣に悩んじゃいました」「それはもう誰かに決めてもらうのが早い😎」「🤣」「ただ思うのは、よほどシビアなアプリでもない限り、カバレッジの数字だけを当てにしてもあまり意味がないかなってことですね」「カバレッジの値が増えたからといって本当に必要な部分がカバーできてるかどうかはまた別なのか🙂」



つっつきボイス: 「2位のMagentoって知りませんでした」「自分も😁: それにしてもShopify、いつの間にかこんないい位置につけてるなー: ユーザー数はともかく、捌いているトラフィック数は凄い👁」「Shopify、Railsですしね🤠」「EC-CUBEと比較してみたいところだけど、日本製でほぼ日本市場だけだろうから単純な比較は難しいかなー」



つっつきボイス:mizchiさんいいこと言うなー: フロントエンドの強い人で今は確かフリーランスだったかな?」「さっきのreflectionの話もそうでしたけど、コードを書いた人の意図を読み取る能力と、読み取れるようにコードを書く能力ってやっぱり重要ですね🧔🏽」

そのうちIPA試験あたりにコード読解問題とか出たりするんでしょうか。


Ruby trunkより

Unicode 11のグルジア語の大文字小文字の取り扱いをどうしよう?


https://www.unicode.org/versions/Unicode11.0.0/ch07.pdf (Section 7.7, Georgian, pp. 320-321) より

Geogianが「グルジア語の」とも「ジョージア(州)の」とも読めてしまうので、いちいち断りが必要です。グルジアというとスターリンの出身国というイメージ。なおグルジア語とロシア語には共通部分がほぼありません。


Kartvelian languages - グルジア語 - Wikipediaより

参考: グルジア語 - Wikipedia


つっつきボイス: 「これはもう多言語マニアがいないとどうしようもない😇」「issueでもそう言ってました😆」

GRND_NONBLOCKを設定せずにgetrandomが複数呼ばれるとロックする

if which ruby >/dev/null && which gem >/dev/null; then
    PATH="$(ruby -e 'puts Gem.user_dir')/bin:$PATH"
fi

つっつきボイス:GRND_NONBLOCKって、またLinuxに新しいフラグが出たのか」「(Linuxでしたか😓)」「よく見つけたなこれ感」

参考: getrandom(2) - Linux manual page

Procの行番号/カラム番号、できればfirstやlastも取りたい

# rspec-parameterized gemのサンプル

  describe "lambda parameter" do
    where(:a, :b, :answer) do
      [
        [1 , 2 , -> {should == 3}],
        [5 , 8 , -> {should == 13}],
        [0 , 0 , -> {should == 0}]
      ]
    end

    with_them do
      subject {a + b}
      it "should do additions" do
        self.instance_exec(&answer)
      end
    end
  end

# 出力例

  lambda parameter
    a: 1, b: 2, answer: -> {should == 3}
      should do additions
    a: 5, b: 8, answer: -> {should == 13}
      should do additions
    a: 0, b: 0, answer: -> {should == 0}
      should do additions

tagomorisさんとjoker1007さんからのリクエストです。


つっつきボイス: 「最初気づかなかったけど、joker1007さんがそういう感じのgem作ってたそうです↓」「RSpecでwhere(:a, :b, :answer)みたいにwhereで指定したいってことのようだ: Procが複数になるとつらいとか、これは確かにやるなら言語でサポートする方がいいでしょうね😋」

Ruby

Relaxed Ruby Style: ちょいゆるRubyスタイルガイド

Version 2.3とあるのはRubyのことなのかこのスタイルガイドのことなのか、どちらなんでしょう?


つっつきボイス: 「rubocop.ymlに軽くパッチを当てて使うようです」「パッチじゃなくて、元々rubocopにはinherit_fromというデフォルト設定を読み込む機能があるので、それを使って読み込んだ上で自分達のルールとの差分を上書きする、みたいな使い方ですね」「あー、そうでした😓」「うん、こういうのいいよね: BPS社内でも標準rubocop.yml定めたいと思ってる🤓」


github.com/rubocop-hq/rubocopより

ramda-ruby:

# 同リポジトリより: トランスデューサー
  appender = R.flip(R.append)

  xform = R.map(R.add(10))
  R.transduce(xform, appender, [], [1, 2, 3, 4]) # [11, 12, 13, 14]

  xform = R.filter(:odd?.to_proc)
  R.transduce(xform, appender, [], [1, 2, 3, 4]) # [1, 3]

  xform = R.compose(R.map(R.add(10)), R.take(2))
  R.transduce(xform, appender, [], [1, 2, 3, 4]) # [11, 12]

  xform = R.compose(R.filter(:odd?.to_proc), R.take(2))
  R.transduce(xform, R.add, 100, [1, 2, 3, 4, 5]) # 104)
  R.transduce(xform, appender, [], [1, 2, 3, 4, 5]) # [1, 3])
  R.into([], xform, [1, 2, 3, 4, 5]) # [1, 3])

JavaScriptのRamdajsをRubyに移植したものだそうです。名前からlambdaのもじりという感じで、ramdajs.comには「育ちすぎたram(子羊)じゃないんだなー、たぶん」とありました。ramだ。

参考: ラムダ計算 - Wikipedia


つっつきボイス: 「ramda: いいのかその読み方で😆」「たぶん子羊じゃないといいつつ、シンボルマークは生意気盛りっぽい若羊ですね😄」「関数型の追求というよりは、フィルタ的な便利ツール集という印象」


ramdajs.comより

トランスデューサーそのものはめちゃめちゃ意味が広いですが、ここでは関数型言語よりの何かなんでしょうね。何も見ずに「translator + reducer」かなと推測。

参考: トランスデューサー - Wikipedia

Rubyとmallocの問題

TTY: Ruby錬金術師の秘薬

RubyKaigi 2018で自分が見てなかったやつです(´・ω・`)。


つっつきボイス: 「お、これ自分見ましたよ: いい内容👍」「😃」「TTYってマルチスレッド対応のプログレスバーとかいろいろ機能揃ってて便利😋」

「このTTYってrails new的にファイルをどさっと作るんで、腰を据えて本格的なCLIアプリを作るためのテンプレート的なものでしょうね: 気楽にさっと書くにはかなり重装備な感じ」「この間のウォッチで取り上げたoptparseとはまた違うんでしょうか?」「optparseは引数処理を楽に書けるヤツなのでまた違いますね🕶」
「TTYは、railsコマンドとかsystemdコマンドみたいなものすごく複雑なCLIを見通しよく作れますね: その気になればaptyarnだって作れちゃう😆」「🤣」「TTY上でmarkdownすら書ける」「何だかすげー」

「ただまあ、今こんなごついCLI書くぐらいならWebアプリにするよなという気もすると言えばする」「確かにー」「でも最初CLIで完成させてからそれをWebアプリ化するという流れもありかなとも思うし: CLIならバッチとかとっても扱いやすいし、融通が利きやすいし」「たぶんデバッグもしやすいし😃」

「『こういうCLIはRubyで作ればいいじゃん』っていう文化になったらいいなーと思うし」「こうやってTTYなんかで作ったRubyのCLIを、mrubyとかでコンパイルして配布できればいいのにとも思うし: 結局RubyのCLIって配布がだいたい問題になるんですよね」「確かにー」「CLIでのGo言語の強みはrun anywhereですからね🕶」


github.com/piotrmurach/ttyより

go-mruby: mrubyのGoバインディング

// 同リポジトリより
package main

import (
    "fmt"
    "github.com/mitchellh/go-mruby"
)

func main() {
    mrb := mruby.NewMrb()
    defer mrb.Close()

    // Our custom function we'll expose to Ruby. The first return
    // value is what to return from the func and the second is an
    // exception to raise (if any).
    addFunc := func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) {
        args := m.GetArgs()
        return mruby.Int(args[0].Fixnum() + args[1].Fixnum()), nil
    }

    // Lets define a custom class and a class method we can call.
    class := mrb.DefineClass("Example", nil)
    class.DefineClassMethod("add", addFunc, mruby.ArgsReq(2))

    // Let's call it and inspect the result
    result, err := mrb.LoadString(`Example.add(12, 30)`)
    if err != nil {
        panic(err.Error())
    }

    // This will output "Result: 42"
    fmt.Printf("Result: %s\n", result.String())
}

ついでにquartzという、RubyからGoプログラムを呼び出すgemも見つけたのですが、RubygemにGoのnative extensionを含める感じではなさそう...なぜかこの方面はさっぱり発展しません(´・ω・`)。

http.rbはいいぞ(Ruby Weeklyより)


同リポジトリより

# 同リポジトリより
HTTP.post("http://example.com/upload", form: { file: HTTP::FormData::File.new(io) })

つっつきボイス: 「このhttprb/httpってどうでしょう?」「少なくとも表の青いところにあるRuby標準のNet::HTTPはまず使うことはないと思う、というかつらすぎて使いたくない😆」「😆」「😆」


同記事より

参考: class Net::HTTP (Ruby 2.5.0)

「この表の中で一番メジャーなHTTPクライアントって、赤いところにあるHTTPClientなんじゃないかなー: 少なくとも自分的にはベスト」

「ただ、HTTPClientはREADMEがそっけないんですが、実はそこから地味にリンク貼られているRDocのAPIドキュメントがすごくしっかり書かれてるんですよ↓」「ほー!!」「ここ読むとわかりますけど、プロキシもちゃんと対応してるし、BASIC認証の先でさらにBASIC認証を突破するとか、環境変数からプロキシ渡すなんてのもできます」「いいこと聞いた!😍」「😍」

「表の緑色のところにあるFaraday↓もひと頃流行ったけど、Faradayの抽象化は人によって好みが分かれるかもしれない: クローラーを書くとかならFaradayが向いてますね」「逆にステータスコードが取りたいとかヘッダを確認したいとかならHTTPClientがいい」

「で、本題のhttprbは表の分類からもHTTPClientと同じところを狙ってるというのが取りあえずは見て取れますね」「😃」「おっ?httprbのインストールはgem install httpだって: このgem名、よく取れたなー😲」「Rubygems.orgで決めてるんでしたっけ?」「早いもの勝ちです😎」


rubygems.orgより

Rubyで書かれたワールドカップ試合情報CLI(RubyFlowより)

# 同リポジトリより
$ footty              # Defaults to today's world cup 2018 matches

今日は以下でした。

#1 Thu Jun/14       Russia (RUS) vs Saudi Arabia (KSA) Group A  @ Luzhniki Stadium, Moscow

つっつきボイス: 「試合結果というより、『今日ある試合は何だったっけ?』用っぽいです」「こういう文化っていいですよねー」

Rubyの謎機能: フリップフロップ

# 同記事より
irb(main):021:0> (1..10).each {|i| puts i if i==3..i==5 }
3
4
5
=> 1..10

つっつきボイス:Less Feature-Rich, More Funという記事を翻訳していて、一番最後にRubyのフリップフロップという謎の機能について言及されていたので」「何だこれ...確かに謎🤔」

「あー、if i==3..i==5..の前と後の条件がフリップフロップになってるのか!😲」「😲」「😲」「動作から言っても状態を保持しているんだろうし: こんなのがコードレビューに出てきたら泣いてやる😭」「おうち帰るー😭」「Ruby Gold試験になら出そうですね...😓」

追記(2018/06/17)

まったくの偶然ですが、フリップフロップが次から消えることになりそうです。

その他Ruby




RubyKaigiの応募要項です。


ほのっとしちゃいました。その後英語版↓も出ました。

クラウド/コンテナ/Linux

以下時間切れのため、つっつきはここまでです🙇。後追いで何か追記するかもしれません。

Linuxのloadavgの問題を追求

はてブで見つけました。


つっつきボイス: 「これはとてもいい記事」

Googleのgvisorすごいかも

この間のウォッチで軽く取り上げたgvisorですが、TCFM #22の前半がこの話題でもちきりでした。

ワンライナー特集

GitLabが立て続けに機能を拡大

最新の記事ではありませんが一応。


参考: GitLabがGoogleのKubernetes Engineを統合、コンテナアプリケーションのデプロイが超簡単に | TechCrunch Japan

その他クラウド/コンテナ/Linux

SQL

PostgreSQLのメモリ設定(Postgres Weeklyより)

ロシア発: PostgreSQL 10の論理レプリケーションの復旧(Postgres Weeklyより)


同記事より

かなり長いです。

はじめてのマテリアライズド・ビュー(Postgres Weeklyより)


同記事より

参考: マテリアライズドビュー - Wikipedia

JavaScript

Vue Native: VuejsでネイティブWebアプリを作るフレームワーク


vue-native.ioより

PhantomJSの開発が正式に終了し、アーカイブ化(JSer.infoより)

昨年のウォッチでもお伝えしたPhantomJSが正式に終了しました。お疲れさまです。

週刊Railsウォッチ(20171026)factory_girlが突然factory_botに改名、Ruby Prize最終候補者決定、PhantomJS廃止、FireFoxのFireBug終了ほか

参考: PhantomJSの開発が終了しリポジトリがアーカイブ化された - JSer.info

mobx: JSのステート管理ライブラリ(JSer.infoより)


mobx.js.orgより

JavaScriptのステート管理はVuejsにもあったりReduxもあったりと賑やかですね。js.orgに集結している?


redux.js.orgより

JavaScript: Reduxが必要なとき/不要なとき(翻訳)

ExcelでJavaScriptがサポート

TypeScriptを直接サポートするつもりはないそうです。

参考: Microsoft、Excelカスタム関数としてJavaScriptのサポートを発表

その他JavaScript

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

直感に反する「なぜか覚えられないUI」(Frontend Weeklyより)

↑著名な認知心理学者のDonald NormanことDon Normanの名前から「Norman door」と呼ばれているそうです。てっきりこのドアの発明者かと思ってしまいました。
引くかと思ったら押す、押すかと思ったら引くような、「押す/引く」表示がないとガンガンに間違えるドアだそうです。

参考: Urban Dictionary: Norman Door
参考: ドナルド・ノーマン - Wikipedia


つっつきボイス: 「ちなDonald Norman氏の今や古典とも言うべき誰のためのデザイン?は、主に工業デザインを扱っていますがITエンジニアも必読ですね🧐: おそらくですが、学校でデザインを学ぶ人はきっとどこかでこの本を読む機会があるんじゃないかな」「😃」

テスティングを楽しく学びたい人向けのサイトなど

  • 元記事: テストラジオ -- テスティングの話題が豊富なポッドキャスト

既に60回を超えているんですね。凄い。


testerchan.hatenadiary.comより

Apollo Clientとは


apollographql.comより

言語よろずの間

Mage: Goのタスクランナー

https://twitter.com/matsuu/status/1006200407259938816


同リポジトリより

英語の古語にある「メイジ(魔法使い)」だよなと思いつつ、日本人なのでつい「マゲ」かと思ってしまいました。

Fo: Goで関数型やってみる言語


play.folang.orgより

なお、Goでジェネリクスを欲しいと思ったことが今のところありませんでした。

参考: ジェネリックプログラミング - Wikipedia

Stack Overflowのデベロッパーアンケート結果2018年版

毎度お騒がせ。好きな言語1位がRustという。


insights.stackoverflow.comより


つっつきボイス: 「想像以上にめちゃ長い...」「呑みながらつっつくのによさそう🍶」

参考: 2018年 人気&嫌われプログラミング言語トップ25- Stack Overflow | マイナビニュース

その他言語

参考: 依存型 - Wikipedia
参考: 直観論理 - Wikipedia -- 依存型の基礎となる論理で、古典論理といくつかの点で異なります。





その他

Gitコマンドを異世界転生モノで解説するよ

らめぇそれ

「不正指令電磁的記録に関する罪」とは

はてブで知りました。

Windowsに新しいアプリインストール形式「MSIX」が登場予定

その他のその他





社内勉強会のお題が「トランザクションとロック」だったので、そういうときについ思い出す動画です。トランザクションとロックを人力でやってた時代は、特急券の指定券発行に30分かかってたそうです🚆。

番外

今どきの法科学

↑女性です。

あれそんなにヤバイ物質だったのか


つっつきボイス: 「これはねー、手の細胞が全部剥がれ落ちるまで辛抱強く待つしかない😇」「😇」

学校でがっつり教えられた人の立場は

香害

リアルポケモン認定したい

https://twitter.com/world_animal5/status/1004671391214514177

リンネが創始した生物の近代的な分類学は結局外観をベースとしていたために、特に遺伝子生物学が登場してからというものアドホックな修正やら論争やらが当分止みそうにありません。昔なら「葉緑体を持っていれば植物」でしたが、もうそんな素朴な分類ではどうにもならなさそう。分類学って人間の都合でしかないんだなと痛感します。

参考: カール・フォン・リンネ - Wikipedia
参考: 生物の分類 - Wikipedia

火星で有機物発見か

地球に巨大隕石がぶつかったか何かで火星に飛来した小型隕石によるコンタミの可能性が気になります。南極は一面真っ白で月の石や火星の石がちょくちょく見つかるので、逆もありそうな気がしてしまいます。

参考: 南極サイエンス基地 > 南極隕石


今週は以上です。

おたより発掘

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

週刊Railsウォッチ(20180608)特集「RubyKaigi 2018後の祭り」、`Enumerable#index_with`は優秀、コントローラから`@`を消し去るほか

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

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

Rails公式ニュース

Ruby Weekly

RubyFlow

160928_1638_XvIP4h

Postgres Weekly

postgres_weekly_banner

Frontend Weekly

frontendweekly_banner_captured


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。