こころがホッコリー

ただイカしたRubyistになりたい人生だった。

緯度経度を入力値に、2地点間の距離を算出するgemを作ってみた(国土地理院提供APIを使用)

松村 Advent Calendar 2016 の14日目です。 @muramurasan です。
タイトルの通り、gem作りの練習として「緯度経度を入力値に、2地点間の距離を算出するgem」を作ってみたので、その使い方を紹介させていただきたいと思います。
gemの名前は conncect_gsi_api という、一体何のgemなのかさっぱりわからないものになっています。(後悔)

github.com

インストール

Gemfile を使う場合は、下記の記述を追加して、bundle install してください。

gem 'connect_gsi_api'

手動でインストールして使う場合は、gem install connect_gsi_api を叩きましょう。

実際に使ってみた

インストールから、利用するところまで実際に紹介していきます。
まずはインストールをします。

$ gem install connect_gsi_api
Fetching: connect_gsi_api-0.1.0.gem (100%)
Successfully installed connect_gsi_api-0.1.0
Parsing documentation for connect_gsi_api-0.1.0
Installing ri documentation for connect_gsi_api-0.1.0
Done installing documentation for connect_gsi_api after 0 seconds
1 gem installed

次に、手っ取り早く使用感を確かめるために、irb を起動して使ってみます。

$ irb
irb(main):001:0> require "connect_gsi_api"
=> true
irb(main):002:0> ConnectGsiApi.distance2p 35.6581, 139.701742, 36.123456, 138.705749
=> 103682.866

こんな感じで、引数 出発地緯度出発地経度到着地緯度到着地経度 を渡して distance2pを呼び出すと、距離がメートルで返ってきます。
不正なパラメータを渡してしまったなど、エラーが起きている場合はnilが返ってくる仕様になっています。

なお、デバッグのため、コマンドにも対応しています。

$ bundle exec calcdist 35.6581 139.701742 36.123456 138.705749
103682.866

注意事項

あくまで、このgemは国土地理院提供のAPIを使用しているものですので、
APIの使用回数制限や、API側のインタフェース変更で、gemが使えなくなることが想定されます。
残念な仕様ではありますが、うまく値を取得できなかった場合は、nilを返すような仕様になっておりますので、
うまく利用者側でよしなにハンドリングしていただければと思います。

今年読んだ本の振り返り

dodosoft Advent Calendar 2016 9日目です。 @muramurasan です。

www.adventar.org

タイトルの通り、本エントリーでは今年読んだ本の感想をつらつらと書きたいと思います。
どれも個人的にはオススメの本ばかりです。

リファクタリング:Rubyエディション

名著・リファクタリングRuby版です。
コード・設計の見通しを良くするためのテクニックの数々が紹介されています。
原著のリファクタリングが、オブジェクト指向でいかにして問題を解決するか、
といった、いわば設計面での改善テクニックが多く書かれているのに対し、
Ruby版では、コードベースでいかにして見通しをよくするか、ということが多く書かれている印象です。
Rubyならではのテクニックが数多く紹介されているので、原著読んだ人は更に本書も読むことをオススメします。
(別の本と言っても過言ではないかと)

エッセンシャル思考 最少の時間で成果を最大にする

昨年、嫌われる勇気という本を読むことで、精神衛生面の防護壁を培いました。
嫌われる勇気が、「自分のペースで良いさ」という心構えを説いた本なのに対し、
このエッセンシャル思考は、実際どうすれば仕事は早く終わるのか、面倒事に関わらなくて済むのか、
といった実践面のことを書かれている本です。
作中、「エッセンシャル思考じゃない人の例」がたくさん出てくるので、グサグサ心に刺さります(笑)
文量はそこそこあるんですが、読みやすいのでサクサク進められると思います。

メタプログラミングRuby

いわゆる、黒魔術メタプログラミングの本です。
......と思っていたのですが、単なる黒魔術の説明書じゃないんです。
Rubyという言語がいったいどういう風に動いているのか、
その内部深くまで踏み込んで説明してくれている、いわばRubyの理解を深める本なのです。
「黒魔術なんか扱うことはないから、読まなくていいや」と思っていた方は、
その考えを改めて、ぜひ、本書を手にとってみることをオススメします。一皮剥けます。まじで。
今年読んだ本の中で一番タメになった本でした。オススメ。

ちなみにメタプログラミングRubyに影響を受けて作った、
「任意のメソッド呼び出しを監視する」というgem、okuribitoがこちら。

github.com

Effective Ruby

効果的なRubyプログラムを書くためのテクニックを紹介している本です。
が、まだこの本を読んで実践するだけの力がついていないなと、己の無力さを知ることとなりました。
正直、紹介されているテクニックの大部分については、使いどころがわからないんですよね。
それは、まだまだ書いているコードが幼稚であること、設計の選択肢が少ないことに他ならないと思います。
Rubyistとしてステップアップしたい方はぜひ、本書を手にとってみてください。

HTML5/CSS3 モダンコーディング

タイトル通り、HTML5、CSS3を用いた「今風」のコーディングスタイルを、
サンプルのウェブサイトを構築しながら学べる本です。
手を動かしながら学べるので、理解した気になって終わらないのが良いところかと。
また、作中に「昔はこんな辛みがあった、今はこうすれば大丈夫」という説明がまじえてあるので、
本当にこの本一冊で、今はどうすればいいのかを学べる印象です。

達人に学ぶDB設計 徹底指南書 - 初級者で終わりたくないあなたへ

DB周りの知識初級者から、中級者・上級者に引き上げてくれる本です。
確かに、Webアプリケーションを開発 / 保守 する上で、
最低限の知識だけで今まで戦ってきたんだな、というのを突きつけてくれました。
DB周りの知識を幅広く説明しており、論理設計のノウハウから、アンチパターン
物理設計の勘所、パフォーマンスチューニングのやり方まで......
嗚呼、これを知りたかった! ということがぎゅっ、と詰まって書かれている本です。
今年読んだ本のオススメ2番目ですかね......

大規模サービス技術入門

「1000台のシステムは、何が変わるのか?」という表題の通り、
サービスが大きくなっていった時に何を気にしなければならないのか?
データ構造、メモリ、OS、DB、サーバ/インフラ あらゆる要素について、
その勘所、テクニックを全編にわたって説明している本です。
が、残念ながら、書評を書いている現段階で、内容をあまり思い出せないことに気がつきました。
これは時間を置かずに、もう一度読まないといけないな、と思いました......

おわりに

この記事に取り組む前は「今年読んだ本全然無い......つらぽよ......」となっていたのですが、
いざ記事を書いてみると、意外と今年読んでいることに気がつきました。
こうして、これまでにやったことの棚卸をするのって大切ですね。

数学パズルでIQゴリラ並と判定を受けたミジンコがお世話になっているRubyの便利メソッドたち

dodosoft Advent Calendar 2016 6日目です。

www.adventar.org

dodosoftって何? という方は、こちらのエントリーをどうぞ。

okoysm.hatenablog.jp

目次

本日のお品書きはこちら。

自己紹介

Twitterではミジンコのアイコンで活動しています、@muramurasan です。
週末は dodosoft の輪読会に参加したり、デザイン思考の大学講義に出席したり、もくもくしたりしています。
普段はRuby On Railsを扱い、ECサイトのバックエンド部分を開発・保守しています。

本題

さて、本題です。 本記事では、ミジンコな私が、通称:数学パズル という本をRubyで解くのに、よくお世話になっている便利メソッドたちを紹介したいと思います。

プログラマ脳を鍛える数学パズル シンプルで高速なコードが書けるようになる70問

プログラマ脳を鍛える数学パズル シンプルで高速なコードが書けるようになる70問

ちなみにゴリラのIQは 70〜90 らしいです。意外と高いですね。

each_with_index

配列の中身をぐるぐる回しながら、インデックス(番号)を数え上げてくれます。
変数 i を定義して、インクリメントして......なんてコードを書かなくて済むので重宝します。

コード

array = ["Ruby", "On", "Rails"]
array.each_with_index { |item, i| puts "#{i}:#{item}" }

実行結果

0:Ruby
1:On
2:Rails

include?

配列の中に、指定の値が存在するかチェックしてくれるメソッドです。
配列ぐるぐる回して探索する......なんてコードを自分で書かなくてもいいわけですね。

コード

array = ["Ruby", "On", "Rails"]
puts array.include?("Rails")

実行結果

true

combination

配列から引数n個の要素を選んだときの組み合わせを数え上げてくれます。
地味に使いどころ少ないですが、組み合わせを数え上げる問題は瞬殺で解くことができます。

コード

# encoding: utf-8
array = ["生ハム", "メロン", "アイス", "キャンディー"]
array.combination(2) { |a, b| puts "#{a}#{b}" }

実行結果

生ハムメロン
生ハムアイス
生ハムキャンディー
メロンアイス
メロンキャンディー
アイスキャンディー

repeated_combination

配列から引数n個を選んだときの重複組み合わせを数え上げてくれます。
例えば、以下のような3食のメニューの組み合わせを吐かせたりすることができます。

コード

# encoding: utf-8
menu = ["和食", "洋食", "中華", "なし"]
menu.repeated_combination(3) {|a, b, c| puts "朝:#{a} 昼:#{b} 夕:#{c}" }

実行結果

朝:和食 昼:和食 夕:和食
朝:和食 昼:和食 夕:洋食
朝:和食 昼:和食 夕:中華
朝:和食 昼:和食 夕:なし
朝:和食 昼:洋食 夕:洋食
朝:和食 昼:洋食 夕:中華
朝:和食 昼:洋食 夕:なし
朝:和食 昼:中華 夕:中華
朝:和食 昼:中華 夕:なし
朝:和食 昼:なし 夕:なし
朝:洋食 昼:洋食 夕:洋食
朝:洋食 昼:洋食 夕:中華
朝:洋食 昼:洋食 夕:なし
朝:洋食 昼:中華 夕:中華
朝:洋食 昼:中華 夕:なし
朝:洋食 昼:なし 夕:なし
朝:中華 昼:中華 夕:中華
朝:中華 昼:中華 夕:なし
朝:中華 昼:なし 夕:なし
朝:なし 昼:なし 夕:なし

permutation

combinationと違い、こちらは配列から引数n個の要素を選んだときの順列を数え上げてくれます。

コード

# encoding: utf-8
array = ["", "", ""]
array.permutation(2) { |a, b| puts "#{a}#{b}" }

実行結果

あか
あお
かあ
かお
おあ
おか

発展

せっかく便利なメソッドなので、発展も紹介しておきます。
例えば、(都合の良い問題ですが)
「とある文字列から5文字選択した場合、回文はいくつ出来上がるか」 といった問題を瞬殺で解くことができます。

コード

STR = "APPLEPEN"
p STR.split("").permutation(5).map(&:join).select { |a| a == a.reverse }.uniq

実行結果

["PEAEP", "PEPEP", "PELEP", "PENEP", "EPAPE", "EPPPE", "EPLPE", "EPNPE"]

repeated_permutation なんてのもありますが、使ったことがないミジンコなので、割愛します。

product

これめちゃめちゃ使えます。
複数の配列を組み合わせて、その組み合わせを配列にして返してくれるというものです。
セットメニューを作り上げる例を見てみましょう。

コード

main  = ["ビーフ", "チキン"]
sub   = ["サラダ", "スープ"]
drink = ["コーヒー", "紅茶"]
main.product(sub, drink).each { |set| puts set.join(", ") }

実行結果

ビーフ, サラダ, コーヒー
ビーフ, サラダ, 紅茶
ビーフ, スープ, コーヒー
ビーフ, スープ, 紅茶
チキン, サラダ, コーヒー
チキン, サラダ, 紅茶
チキン, スープ, コーヒー
チキン, スープ, 紅茶

おわりに

書いてみると、半分以上がリファレンスのコピペになってしまいました。
ピックアップして紹介するのが目的の記事なので許してください......。

数学パズルは、dodosoftのメンバーと一緒に解くことがあるんですが、(みんな言語バラバラ)
Rubyは便利メソッドが多すぎるので、「卑怯だ!」と言われることがよくあります。いいんです。いーんです。
Rubyはいいぞ。」

CodeClimateのカバレッジ測定が、従来の設定で動かなくなったので修正してみた

Code Climate + Circle CI でRubyプロジェクトのコードカバレッジを計測しようとしてみたところ、
codeclimate-test-reporterのバージョンが上がっていて、
従来の設定(ネットに転がっているもの)では動かなくなっていたので、修正した部分を備忘録として残しておきます。

従来の設定

まず、従来の設定です。
spec_helper.rbに、以下のように書く、という情報が多く見受けられました。

require "simplecov"
require 'codeclimate-test-reporter'

SimpleCov.start do
  add_filter "/vendor/"
  add_filter "/spec/"

  formatter SimpleCov::Formatter::MultiFormatter[
              SimpleCov::Formatter::HTMLFormatter,
              CodeClimate::TestReporter::Formatter
            ]
end

これで、rspecを回してみると、以下のようなエラーが出ます。

Formatter CodeClimate::TestReporter::Formatter failed with CodeClimate::TestReporter::Formatter::InvalidSimpleCovResultError: undefined method `values' for #<SimpleCov::Result:0x007fb06257bdd0> (/Users/ym/.rbenv/versions/2.0.0-p647/lib/ruby/gems/2.0.0/gems/codeclimate-test-reporter-1.0.3/lib/code_climate/test_reporter/formatter.rb:21:in `rescue in format')

知らんがな(´・ω・`)

正しい設定

正しい設定はこちらです。まず、同じくspec_helper.rbを書きます。

require "simplecov"

SimpleCov.start do
  add_filter "/vendor/"
  add_filter "/spec/"
end

更に、CircleCIの方で CODECLIMATE_REPO_TOKEN=<token>GUI上で設定*1した上で、
bundle exec codeclimate-test-reporter を実行するよう circle.yml に仕込む必要があります。

test:
  override:
    - bundle exec rspec
    - bundle exec codeclimate-test-reporter

これで、カバレッジを測定した結果を、CodeClimateに送信してくれるようになります。

おわりに

今回の変更のくだりは、公式ドキュメントに書いてあります。

https://docs.codeclimate.com/docs/ruby

が、bundle exec codeclimate-test-reporter の実行を、CIツール側でどう設定するのかまでは書かれていなかったので、今回設定するのに苦労しました。

なお、Travis CIに対応させる方法は、こちらの記事が参考になります。(CircleCIに対応させる上で、私も参考にしました)

web-salad.hateblo.jp

link_toでページ内リンクとclass指定を共存させる方法

やろうとして、ちょっと詰まったので忘れないうちにメモ。

<a class="button" href="#about">LEARN MORE</a>

こんな感じのHTMLをlink_toで生成したいとする。

<%= link_to("LEARN MORE", anchor: "about", class: "button") %>

これだと駄目。

<%= link_to("LEARN MORE", { anchor: "about" }, class: "button") %>

こうやって、明示的に二番目のパラメータをHashにすることで、うまくいった。
こうすることで、class: "button" をHTMLパラメータ(三つ目のパラメータ)として認識させることができるんだと思う。

と考えると、上記であげた駄目な例は、以下の書き方と同義かな?

<%= link_to("LEARN MORE", { anchor: "about", class: "button" } ) %>