Lumped tweets

Just marks

rails で cookies を使ったテストをrequest, feature spec ではない書き方でテストするための方法が知りたい

この記事でわかること

request spec や feature spec ではない、 cookies だけをどうにかして取り出してテストを書きたいフレンズが、テストを書けるといいなぁって思えるようになる。 ただし、厳密には違う。違うんだ……どうしたらいんだ……教えてくれ…………(ほんとう?

背景

例えば以下のようなコードでテストを書きたかった

# app/models/state.rb # めっちゃだめなクラス名だな……
class State
  class CookiesAdapter
    def initialize(cookies)
      @cookies = cookies
    end

    def transition!(key)
      @cookies['state_transition'] = { value: key }
    end

    def in?(key)
      @cookies['state_transition'] = 
    end
  end

  def initialize(adapter)
    @adapter = adapter
  end
  
  def transition!(key)
    @adapter.transition!(key)
  end

  def in?(key)
    @adapter.in?(key)
  end
end

class HogeController
  def show
    @state = State.new(State::CookiesAdapter.new(cookies))
  end
  # ... 
end

State インスタンスの振る舞いは、実際には hogeAdapter の同名のメソッドを呼ぶことで、上の実装では CookiesAdapter しかないが、まぁRedisなりなんなりのAdapterがあればいい感じに振る舞いを分離できて幸せそう。 AdapterPattern のようなナニだ。

で、Cookiesを使いたい時に、 Rails では ActionDispatch::Cookies に実装*1があり、他にもあるが一番わかり易いのが ActionDispatch::Request#cookies_jar*2Cookies::CookiesJar.build 経由で cookies_jar を作って、その alias として cookies*3でのアクセスが実現できている。

困ること

  1. Cookies を直接インスタンス化するために必要なパラメーターがわからん(調べればいいんですが)
  2. request spec として、リクエストが透けた形で↑のモデルのテストを書きたくない
  3. feature spec として以下略
  4. ActionControllerインスタンス化でもいいけど、なんかもう少し上手いやつないかなぁ

ということでテストの書き方二種

二種? というのは、rails のバージョンで異なるため。古いバージョンとかは知らない。4.2は古いっていうのは、はいそうですね。

rails 4.2

RSpec.describe State::CookiesAdapter do
  let(:cookies) { ActionDispatch::Request.new({}).cookies }

え、なにそれ辛い。辛いというか、 とくに new({}) あたりが、「本当にそうなのか」がワカラナイ。 一応、 Rails.application.env_config でよいっぽいというStackOverflowの気持ちを見ることができるが、ほんと〜?となる。

unit testing - Setup cookie.signed in Rails 5 controller integration tests - Stack Overflow

rails 5

RSpec.describe State::CookiesAdapter do
  let(:cookies) { ActionDispatch::Request.empty.cookie_jar }

https://github.com/rails/rails/blob/master/actionpack/test/dispatch/cookies_test.rb#L12 rails が 自らのテスト↑で @requestRequest.empty で作成してそこから cookie_jar を取ってる。( 厳密には cookies_jar )

なんか結局イマイチだけど、まぁ rails がそうやってるなら、まぁいいんじゃないかな? となる。

おわりに

  1. rails5 を使おう
  2. そうでないなら ActionDispatch::Request.new({}).cookie_jar で一応取れる。ほんと〜?

河辺

拝啓

おげんきですか? 僕は元気です。

はじめに

壁 AdventCalendarが前回あったのは、 2015年である。

adventar.org

もはや知る人ぞ知らなくて良い、伝説となった(伝説のまま誰にも語り継がれず、そのまま闇に葬ったほうがよさそう)壁 Advent Calendarだが、 去年は「今年は?」「え、今年はやらないんですか?」「そんな馬鹿な」みたいに本人をつっついても全く本人が動かなかった。

そうして、世界のすべてが「なかったことにしたかった」壁アドベントカレンダー、それが

ということで帰ってきた。

何が言いたいかって、特に言いたいことはないよ。

本文

壁とは一体何かを考える。 物理的、あるいは精神的、抽象具体、様々な形式を用いて壁を認識することができるだろう。 壁、それは一人ひとりの解釈による部分が多く、また世界そのものは世界中の生命体の認識の最大公約数、あるいは認識によるだと定義したとして、その世界における壁とはつまり全ての生命体が「壁」と認識するもの、それはつまり何なのだろうかと思考するに、それはすなわち壁、なのではないか。壁という概念、壁という認識、壁という虚像に虚構に抽象に具体が混じり合ってもまだ壁と考えうる壁、それはすなわち壁、壁ってナニか?という疑問に対して招聘するは壁という認識そのもの、思考において壁を壁と認識した時に壁は初めて壁となり、そうでないものは壁とならず壁は壁たり得ないためそれは壁でなく、では元々何だったのかというと壁ではないなにかでしかなく、つまり僕達が今壁と考えうるものは全て壁であり、思考が思考する為の土台、壁が壁たりうる為の壁は、すなわち個々人の認識、いや、全ての思考する某の認識に依って壁が壁として起立するのである。壁とは本来何を指し示すかなどこの世界においては一切の意味はなく、壁が壁として認識される思考される事そのものに意味があり、壁が実際に、この言葉は間違っておりつまり、壁が「壁」として物理的に、つまりこの地球上に壁としてラベル付された形で壁があってもそれが全ての思考する某によって、壁として認識されなければそれは壁ではなくただのナニかに成り下がるわけだが、しかしであるならばそこにある壁というラベルは一体何なのか、この答えを出すためにも壁という概念についてより深く、より洗練された考察を導き出し演繹し、壁が壁たりうる為の思考する某の共通項を導き出すこと、その為の問いを今我々は壁として認識してしまっているがため、この概念の坩堝に対して何を振りかざしたところで思考の壁を超越し、壁を壁として俯瞰的に、概念的にあるいはよりもっと高度な次元から課題という壁を認識し、いや、そもそも次元という壁を認識してしまっている時点で壁を真に俯瞰して、客観して観察することは出来ないのではないだろうかという思考もまた、一つの壁ではないだろうかと考えうるに、世界の万物は、あるいは思考する某そのものもまた壁なのではないかと考えうるわけだ。

おわりに

kotobank.jp

Rustを使ってみた感想

背景

RubyKaigi2017に参加した。 楽しかった。

せっかくRubyKaigiに来てるので、セッションの間とか終わったあとの飲み会後とか、来てからとかセッションを聞いてない時間とかにRのつく言語を触ろうと思った。 ので、Rustでほしいと思ったツールを作った

概要

github.com

これを作った。

No Test なので実用的じゃないです。

感想

  • Rust素人なのでめっちゃ &mut を使ってしまった
  • String&strChar とかの違いに戸惑った
  • 色々めんどくなってべた書き! 所有権難しい><;

終わり

PyQを嫁にやらせてみている感想

先にまとめ

まだ一章? だけど、 PyQくらいStep by Stepでも、隣に少しは分かる人が居ないと本当の初心者には難しいのかも? と思った。 ただ、隣に少しでも分かる人がいると内容もわかりやすいし、結構小さい粒度で成功体験を得られるので良いサービスな気がする。

なぜやっているのか

PyQ というサービスが有る。プログラミング初心者はPython初学者に向けたサービス。 pyq.jp

嫁が「プログラミング勉強して、エンジニアとしてお賃金を稼ぎたい」と言い始めたので、話題になっていたPyQに登録してやってみている。

嫁のステータスとしては

  1. PCは触っているが、Huluでドラマを見たり、とある会社に所属してデータ入力をしているくらい
  2. 大学でWordやExcelは触っていたが、あんまりちゃんと使っていたわけではない感じ
  3. プログラミングは変数も知らない感じ。

とまぁ、「プログラミングに関しては本当にド素人で、キーボードをタイプすることには抵抗がない」くらいのステータス。

やっているのを横で見ていての感想

まずどんなサービスなのか

実際の画面をキャプチャしてよいのかわからないので、以下の公式サイトに有る画像を見てほしい

https://pyq.jp/static/img/landing_ss.289c5bc8d34b.png

https://pyq.jp/

こういう感じで、Side by Side に「問題文や解説文」が左側、右側にエディターがあって、右上の「実行」を押すと右下にTerminalで出力結果が出たりする感じだ。 問題によっては「判定」ボタンがあって、テストが通ってOK,NGが出る感じ。

内容も

f:id:holloword:20170809122048p:plain

ref: https://pyq.jp/quests/

こういう感じで、本当に初歩の初歩から初めていく。

個人的には本当に初歩の初歩からなのでわかりやすいとは感じたが……

言葉選びが突拍子がない

割りと初っ端から「写経」という言葉が出てくる。 写経という言葉を見て嫁は笑っていたが、これをうまく表現する言葉がないなぁと感じた。 コピペではなくて、見ながらタイプすることを、写経と表現されても、真の初学者にはわからない気がした。 実際には、「書き写しましょう」 みたいな言葉が出ていて、あぁ同じものをタイプすればいいんだな、と気がつくが、 「写経」という言葉の仰々しさに「うっ」っとくる。

エラーの説明がちょっとわかりずらい

SyntaxErrorとかを説明するフェーズがあったり、「SyntaxErrorの詳細はこちら」みたいなLinkを飛んで見たりできるが、その文章が初学者にはちょっとわかりづらい。 まぁこればっかりはしょうがない気もするが、エラーをいい感じに表現するのは難しい…… そしてこれを僕が改めて説明するのもまた、難しい……

コメントの必要性があんまりわからない

「コメント」ができるよ、みたいな課題があって、そう言われても、ぶっちゃけ初学者には「これができてなんなん?」みたいな感じになる。 実際そういうニュアンスで聞かれた。「まー、プログラムの説明を書くためのもんだよ」と説明しても、「ふ〜ん」みたいな感じ。 とはいえ、こればっかりはまじで書いてみないとわからない気もしているので限界な気もする。

変数がなんで嬉しいのかが遠い

a = 'ほげ'
print(a)

みたいなコードがあって、でもこれがなんで嬉しいのかが「こうやってできる」と「これはこう嬉しい」が遠いから、ちょっとわかりずらい。 「例えば a が【寿限無寿限無五劫の擦り切れ海砂利水魚の……】だったら、何度も打つの大変だけど、 a って入れるだけでそれが出てきたら楽だし?」みたいな説明をして「確かにそれは嬉しいね」となったけど、実際には関数の返り値を使いまわすとか、そういう使い方のほうが嬉しかったりして、ちょっと違うなーって思いながら説明する。

ココらへんで思ったこと

頻繁に「これがなんで嬉しいの?」と聞いてくる嫁氏は、割りと筋が良い気がするなぁと思ったりした。 「なんでこうなってるの?」と聞くこと、考えることはプログラミングをしていく上で必須スキルだけど、前段の自発的に聞くことすら出来ない人がたまにいる。(自分のことですごめんなさい……) ただ、「なんでこうなってるの?」と聞いたときにPyQ上だけだとどうしても書いてあることで理解できないとそこに対してあんまり納得がないまま進むことになってしまう。

あとで「ああこれってこういうときに嬉しいのね」ということが分かっても、そこまでで離脱する可能性もあってちょっと難しいなぁという感じ。

とはいえ

まだ初めて二時間くらいなので、とりあえず一ヶ月分はやりきってほしいので横でアドバイスしながら、「とりあえず実行してみ?」みたいなスタンスで見守っていく。

気持ちが高まったら続編も書く。

faraday-middleware と Oj の組み合わせで動かなくなる話

背景

faraday-middleware が突如として ArgumentError: options must be a hash. というエラーを吐いて落ちた この原因を探ってしまったので(本当は issue にあった)、記録として残しておく。現状この問題は解決済み

結論

Oj で mimic mode を使っていると、 faraday-middleware の v0.12.0 で入った改修により、落ちる。

github.com

回避方法としては Oj のアップデートを行うか、 mimic mode を利用しない。

faraday middleware 側の改修も Master には取り込まれているが、 2017-08-03時点ではReleaseされていない。

概要

Oj という Gem は、Rubyの早いJsonParseであり、大部分がCで実装されている。 また、Oj は mimic というモードを備えており、これを利用すると、既存の JSON.parse などのコードをOjのコードに差し替える。

Faraday Middleware の https://github.com/lostisland/faraday_middleware/pull/156/files#diff-5af7802308edb2ce67e963810b810354R11 この改修により、 parse_option を特に指定しない場合において JSON.parse(body, nil) が実行されるようになった。

しかし、 Oj の mimic mode によって上書きされた JSON.parse は、第二引数が Hash かどうかだけをチェックしており、ここで落ちる https://github.com/ohler55/oj/blob/b1504563d8eaadad549aa56b1eaac1845bb63a3d/ext/oj/mimic_json.c#L513

元の JSON.parse では、 オプションが nil の場合はOptionのパースは実行されないので、落ちない https://github.com/flori/json/blob/master/ext/json/ext/parser/parser.c#L1734-L1739

よって、今回の問題は Oj を利用しており、 Oj の mimic mode を利用している場合のみ発生していた。

というのが ↑ の issue にまとまってるので読むと良い。

技術的負債ナイトに参加してきたので簡単にまとめる

なにぞ?

↓ のSpeeeさんで行われた技術的負債ナイトに参加してきた。 その軽いまとめ。 speee.connpass.com

まとめしか書かない。内容はそのうち資料が揚がる……きっと……

sinsoku_listy

  1. 低品質なコードが悪いのではなく、低品質なコードを混入させないのが大切
  2. 普段から定期的にリファクタリングする
  3. レビューしたら自分がメンテできないコードは Approve しない。 Approve したコードは自分でもメンテするつもりでいるべき。

takanamito

  1. すべてを返済しようとしない
  2. 返済した結果、どうなるのかについては事業責任者を交えてしっかりビジョンを持つ
  3. 運用系タスクをやることで仕様が透けて見える
  4. 仕様ではなく運用をドキュメントにしてもらう

ayasuda

  1. 調査記録はQiitaとかEsaに書いても読まれないし、「そもそもここに調査記録があるとは思っていなかった」として調べない。なのでコメントを書く
  2. yardoc 良いぞ

joker1007

  1. 意識を強く持たないと人は容易にまれ窓に割れ窓を重ねる
  2. 自分のストレスや怒りを見逃すな
  3. DBの設計に関しては最新の注意を払って頑張る

最後に

最初二つ目くらいまではBearにまとめて書いてたけど途中から諦めてSlackに書き出したので雑になった。