Wakotech Blog

ポエム

mineoのauデータ回線が0円/月1GBで持てるキャンペーンを開始したので契約した

まだ届いてませんが……
詳しくはこちらの通り。

最大30か月、ってのはauAQUOSと同時申し込みした場合の話なのでSIM目当ての方は気にしなくて結構です。
とはいえ、普通に申し込んでも-800円×6か月、docomo回線だと9か月のようです。
1GBプランは800円なので差引0円……なのですが、3GBプランが900円なのでこちらの方がお得そう。
1人5回線まで持てるみたいなので、余った回線をシェア可能なので低価格で結構な容量が持てそうです。大丈夫なのかこれというのが感想。
auiPadの月額料金が高くて解約してしまい、かつmineoはiOS8では動作しなかったのですが、検証の結果iPadは一応動作するとのこと。

king.mineo.jp

iPad用に契約したので届いたらiPhoneでも検証してみたいと思います。
単純に4Gエリアをすぐ外れるから圏外になる話という見解もありますがどんなものでしょう……
au回線は手元にないので届くのが楽しみです。6GBあればiPadで読書や動画をしても安心そうなのもポイント
(サポートが違うから当然といえば当然ですが、auのはじまらなかったデータシェアよりあまりにも安くてなんとも)

go getが失敗する場合の対処(unrecognized import path)

問題

go getコマンドでライブラリをダウンロードする際にエラーが出てしまっていました。その対処法を簡単ですが記します。
前回の記事のように私はIntelliJ IDEAで個別にGo SDKのパスを指定していたため、エラーメッセージが出ているもののIDE上では正常に動作していました。コマンドラインツールを導入する際に気づくことになりました。

$ go get github.com/revel/revel

とすると

package github.com/revel/revel
	imports bufio: unrecognized import path "bufio"
package github.com/revel/revel
	imports bytes: unrecognized import path "bytes"

のようにメッセージが表示されます。あまりエラーメッセージみたいではないように見えてしまうので見逃していましたが、正常な場合はこのようなメッセージが出ずにダウンロード、ビルドまで完了します。

解消

エラーメッセージの意味としてはpathが正しくないということなので、GOROOTを見直します。おそらく正しくないパスとなっていると思います。
(homebrewでgo1.4をインストールした場合は/usr/local/Cellar/go/1.4/libexecが正しいパスとなります。)
ここで修正すれば解消されるのですが、go1.4ではGOROOTを指定しなくても良いとのことなので、修正せずそのままGOROOTを消すことでも解消されます。

IntelliJ IDEAでGo言語を書く(golang plugin alpha)

近況

  • 都民になりました。
  • 新宿で働き始めました。

はじめに

go言語の導入については以下の記事等を参考にしてください。GOROOTとGOPATHも設定済みとします。

一度導入した後からの記事なのでこちらでは正常に動作していますが、間違いがあった場合はご指摘いただければと思います。
なお当記事はMac OS Xかつbrewでgoをインストールしている場合の説明となります。設定の差異は少ないと思いますのでご了承ください。

続きを読む

WindowsにRails開発環境を立てる(Vagrant+rails-dev-box+RubyMine)

__2016/3/8追記__
結構アクセスあるみたいなので追記しますが、あらかじめ言っておくとUnixネイティブ程には追いつけないです。
特にjavascriptの差分ビルド関連が遅かったりするので、可能である限りおすすめしません。私はあきらめました。

動機

  • デスクトップマシンのWindowsは持ち運ぶMacbookと違い常に電源やディスプレイが刺さっており、配線準備をせず起動できるため
  • Macbookよりマシンスペックが高いため
  • 録画したアニメを見ながら作業ができるため
  • KrileStarryEyesが使えるため

これからやることの概要

  • VirtualBoxVagrantとRubyMineをインストール
    • RubyMineはJetBrain社の有償IDE。30日間無料で試用可能
    • 学生ライセンスで無料で使用可能。学生は今すぐ登録しよう!
    • 試用期間が過ぎていて学生でない方は、他のエディタ+プラグイン等で対応ができるかと思いますが、ここでは触れません
  • Windowsにまともなターミナルとgitを導入(cmder+git bashでOK)
  • rails-dev-boxからclone
  • $ vagrant up
  • Ubuntu14.04イメージがダウンロードされるのでそれを待つ(モバイル回線非推奨)
  • RubyMineからVagrantをリモートサーバとして設定
  • Windows向けですがMacでも同様の環境を再現することはできます

手順

VagrantVirtualBox、RubyMineのインストール

それぞれダウンロードしてインストール

WindowsUnixライクなターミナルエミュレータとgitを導入

既に使用している方は大丈夫です。
私のおススメはcmder(導入参考リンク: 開発者がSurfacePro3を買ったらまずやること - Qiita)
git for Windowsはcmderのgit bashに付属しているのでこの方法が楽です。
個別に入れる場合はこちら: Redirecting Git for Windows' homepage...

rails-dev-boxからgit cloneし、OSイメージをダウンロード

rails-dev-boxからcloneします

$ git clone https://github.com/rails/rails-dev-box.git

cloneされたディレクトリに移動して、仮想マシンを立ち上げます
その際にOSイメージがダウンロードされるので少し時間がかかります(モバイル回線非推奨)

$ vagrant up

この時点で3000番ポートにはアクセスできることが確認できます
railsプロジェクトがある場合はホスト側(Windows)からlocalhost:3000でアクセスできるのが確認できます
~~インストール済のpythonの以下のコマンドを叩くことでも確認ができます~~
rubyの以下のコマンドでもサーバを建てることができます

$ ruby -run -e httpd . -p 3000

※Rails4.2を使用している場合、通常のrails serverコマンドではWebrickが従来の0.0.0.0ではなく127.0.0.1で起動しポートフォワードされないため、-b 0.0.0.0とオプションで指定する必要があります

RubyMineから接続する

RubyMineを起動し、新規プロジェクトを作成します
作成後にVagrantfileを指定するため、作成場所はどこでも問題ありません。RubyMineProjects下に置くのが良いでしょう
プロジェクト作成後は以下の手順でVagrant内と接続します

  1. File>Settings>Languages&Frameworks>Ruby SDK and GemsからRuby処理系側の+ボタンを押し、New remoteを選択
  2. Configure Remote Ruby Interpreter画面が開かれるので、Vagrantにチェックを入れ、Vagrant Instance FolderにはVagrantfileのあるディレクトリを、Ruby interpriter pathは/user/bin/rubyのままでOKを押します。するとVagrant内と接続をしてRubyを読みに行きます。鍵の発行をしていなかった場合ここで発行を促されるかもしれません
  3. File>Settings>Build, Execution, Deployment>Developmentから+ボタンを押し、リモートサーバを追加します。TypeはSFTPを選択し、hostは127.0.0.1、Portは2222、UsernameとPasswordはともにvagrantを入力し、Root pathがAutodetectで成功すれば成功なので、OKで閉じます。この際、Mappingからサーバ側のプロジェクトルートを設定することで同期範囲を限定することができます
  4. Tools>Deployment>BrowseRemoteHostで、Vagrant内のファイルが確認できます。Alt+1でProjectメニューを表示し、右クリック>Deployment>Download from [サーバ名]を選択し、サーバ内容をローカルに複製します
  5. 通常のリモート開発と同様の環境を再現することができました。syncすることで手元の編集事項がサーバに反映されたり、サーバでたたいたコマンドの変更結果を手元に反映させたりできます。

(自動同期については後日追記します)

※参考: RubyMine and Vagrant - YouTube

Vagrantの共有ディレクトリとの違いについて

Vagrantのディレクトリ共有設定は同一のディレクトリをホスト(Windows)とゲスト(Linux)の双方から見るため、ファイル操作に不整合が出る恐れがあるとのことです
また.git以下は片方のOSに対応した形でファイルが存在するため、気持ち悪い構造になっています
ruby/railsコマンドと同様、基本的にLinuxファイルシステムsshから操作し、IDEによるソースコード編集等のみホスト側で行う、というのが不整合が出ない形になるのではないでしょうか

RubyMineでの開発

RubyMineは非常に多機能で、調べながらでもまだまだすべての機能をつかいこなせていません
RubyMineAdventCalendar2014という非常に便利な情報源があるのでそちらを参考にすると良いです
またRubyMine内臓のshellからvagrant sshすることで、さながらローカルで開発しているのと同様の環境で開発できます(上で説明したcmderを使うよりも便利)

総括

以上の簡単な手順で十分使いやすい開発環境を整えることができます
ただしrubyのバージョン管理がrbenvでない等、実用に問題が出る可能性があります
rails-dev-boxは継続して更新されていますが、構築が合わない場合や他の言語の開発環境も必要な場合はAnsible等を使うのが良いかと思います
Ansibleを用いた環境構築についてもまた近々書きたいと思います

rubyで同一の変数に対して複数の対象と比較したい時の処理

プログラムを書いているとこのようなコードを書く場面にそこそこ出くわすと思います。

if hoge == :next || hoge == :end

このコードでは変数hogeは:nextか:endに一致するかを判定したいのですが、なんだか無駄な書き方な気がします。(DRYでない感じがします。)
2つならまだいいですが3つとなると少し厳しいです。

例えばcase文では複数要素を指定できるので、

case hoge
when :start
  # 処理
when :next, :end
  # 処理
end

とすることができます
ただし、:nextと:endのみにマッチすればよい(:startは必要無い)ときにcase文を使うのも気持ち悪いです。

caseを使わずDRYでもない書き方として、以下のように書くことにしました。

if [:next, :end].include?(hoge)

日本語の考え方だと難しいですが、英語的に見ればまあ納得な感じかと思います。
hoge.included?([:next, :end])の方がぱっとわかりやすいのですが。
他に簡潔な方法がなく読みにくいわけでもないのでこの書き方を使ってみようと思います。このようなことを書いている方が何人かいたのですが、有名な書き方ではないので悪しからず……。
近い未来にrubyにincluded?のようなものが実装されることを祈っています。

RailsでWebアプリを作るまでに使ったベストプラクティスっぽいgemのまとめ(2014)

先日、わこつAdvebtCalendar2014ことわこつ日記をリリースしました。
デザイン面で時間はかかったものの、コーディングの時間はほとんどかかっていません。が、開発する過程でベストプラクティスっぽいgemはどれだろうというのを調べ、今まで曖昧だった部分についてはっきりとさせました。
最低限これだけあれば最低限まともそうなwebアプリになるだろうというgemをリストアップして今年の学びの締めくくりとしたいと思います。

ユーザ管理関連

devise (ユーザ管理)

ユーザ登録の際のメアド管理やらパスワード管理やらまでしてくれます。パスワードも開発者が気にせずとも一方向性関数で安全に扱ってくれています。
後述のomniauthを使うことでのTwitterログインも継承クラスを少し書くだけで実装できるのでとても便利。
セッション管理も行ってくれ、簡単にログインユーザの情報を取り出せるメソッドも用意されています。
sessions_controllerは書かなくても処理されるので、SNSログインを使う場合は後述の通り、認証のコールバック内で処理を行うのがスマートそうです。
devise自体はとても大きく読み解くのも大変なので、あまり依存しすぎないようにはしたいです。

omniauth, omniauth-twitter (Twitterログイン)

TwitterOAuth認証を簡略化してくれるgemです。
DeviseのOmniauthCallbacksControllerを継承してコールバックの処理を書くことができるので、そこで認証のレスポンスからユーザ名やID、APIトークン等を簡単に取り出せます。
コールバック内にセッション操作やDB操作の処理を書くことでスッキリします。いろいろな書き方の記事がありますが恐らくこれが正解みたい……?

Devise+Omniauthについては以下の記事がとても良いと思います。

Rails - devise gemを使ってtwitter認証の設定 - Qiita

ビュー関連

simple_form (フォーム)

フォームをすっきりさせると共に、フォームでの入力エラーの表示もバリデーションから簡単に行えるようになります。

Railsのgemフォームコードをすっきりさせる simple_form - Rails Webook

kaminari (ページャ)

ページング表記をする際の処理が格段に簡単になります。
モデルの読み込み数を指定すればその個数ごとにページが区切られ(これだけでpageパラメータでアクセスできるようになり)、さらにページャリンクのヘルパーも自動で対応されます。

twitter-bootstrap-rails, less-rails, therubyracer (デザイン、css、less)

おなじみのBootstrapのgemです。私のようにデザインを専門にやっていないエンジニアの方は使っている方が多いと思います。
railsではassets pipelineという仕組みでjs、css開発を最適化している都合上、bootstrapにおいては不具合の原因となりやすくなっています。(何度となく直面している。)
このgemはrailsに最適化されているため、そのような問題をあまり意識することなく利用できます。また多様なヘルパーも用意されているため、erbテンプレートの場合煩雑になりがちなhtmlが非常にすっきりします。
部分的にbootswatchテーマを使用する場合はgemを入れるのではなく、/vendor/assets/stylesheets/bootswatc以下に配置し、bootstrap_and_overrides.css.lessにimport文を追記しましょう。

@import "bootswatch/variables.less";
@import "bootswatch/bootswatch.less";

ちなみにログインウィンドウをモーダルで実装した際に、bootstrapとbootswatchで競合してしまったため 、以下のサイトのような解決策が必要となります。

[rails][bootstrap]Rails4.1でBootswatchを試すと variable @zindex-modal-background is undefined エラーが発生 | hello-world.jp.net

bootswatchを使う場合はそのテンプレートベースで使用する前提でtwitter-bootswatch-railsを使うのが良さそうなのですが、パーツ利用にとどまる場合はこのようにするのがよさそうです。
参考

Ruby - twitter-bootstrap-railsでbootswatchを使う - Qiita

なお、lessを使用する場合はless-railsが必要になります。bootswatchがlessで配布されていることや、可読性、編集の容易さからlessを推奨します。(簡単な編集であればless初心者でもすぐに理解できます。)

上記のsimple_formと合わせてbootstrapの使用を紹介したこちらのページがとても良いです。

RailsにTwitter Bootstrapの導入と簡易な使い方 - Rails Webook

コントローラ関連

carrierwave, rmagick (画像アップロード)

画像アップロード処理に関するgemです。リサイズやiOSの傾きの修正、AWS等外部ストレージへの保存も簡単に行えます。

twitter (TwitterAPI操作)

TwitterAPIをラップしてくれています。gem名はそのまま「twitter」です。
Twitterログイン時に取得したAPIキーを使用して様々な処理をできます。実際使うのは投稿やフォロワー取得程度でしょうか。クライアントとしてアプリを作ったり、bot的な処理をさせる場合にも使用できます。
自身のAPIキーはTwitter Developpersから取得できるので、1アカウントから投稿、取得する場合は環境変数にキーを設定して動かせそうです。

設定関連

dotenv-rails

.envファイルに記述した変数を環境変数としてrails起動時に読み込んでくれます。
.envを.gitignoreで隠蔽し、読み込むときはENV['hoge']で良いので非常に楽です。(TwitterのCONSUMER_KEY等は公開するべきではないので、通常いずれかの手段で隠蔽します。)

デバッグ

pry

pry自体はirbコマンドを使いやすくしたものなのですが、コード中にbinding.pryと記述することで実行中にそこで一時停止し、pryを起動することができます。
pryが起動した時点での変数の確認や、メンバ変数、使用可能な関数を確認できるlsコマンド等便利なコマンドがあります。一時停止した地点から一行ずつ処理を進めるnextコマンドというものもあり、バグ解消に非常に便利です。
またrails cコマンドでコンソールを起動した際にもirbの代わりにpryが起動されるようになります。
pryはrailsでの開発に限らず、rubyでのスクリプト記述や他のフレームワークでも役に立つため特にオススメのgemです。

Better Errors

Railsのエラー画面をリッチにします。エラー発生時点での変数の状態を確認できるため、pryと合わせてバグ究明に役立ちます。

アプリケーションサーバ

unicorn

rials sコマンドで立ち上がるサーバ(Webrick)は簡易的なもので本番環境での利用は推奨されないため、一般的には別のものを用意します。
アプリケーションサーバunicornをnginxと組み合わせて使うのが高速で最近の流行だそうです。ここまでの中だとサーバ側の環境を整えるのが一番重そうですが、nginxの設定もそこまで難しくはないと思います。(apache+passengerよりは面倒でなかった。unicornの場合passengerと違い複数アプリを動かすことができる。)
サーバ側の設定はコード化しておくと楽です。この辺りはchef等でぐぐってください……。
他にもunicornの起動やnginxごとの再起動も自動化するスクリプトを書いておくと楽そうです。
……とは言ったものの、最近ではRaptorがいいというのも見るので、こちらも触ってみたいところです。

Ruby - 「RaptorはどのようにしてUnicornの4倍、Puma, Torqueboxの2倍の速度を達成したのか」を読んでまとめてみた - Qiita

これらのgemを有効活用すれば、最低限まともに見えるwebサービスが1人日程度で準備できてしまいます。Railsって怖いですね。
本当にRailsは怖いので、これらgemによる開発の効率化も良いのですが、仕組みを理解しないまま使うことを推奨するわけではありません。
参考

今すぐ辞めて欲しい、「Ruby on Rails勉強してます」「CakePHP勉強してます」

プログラミング初心者の落とし穴「Ruby on Rails勉強してます」「CakePHP勉強してます」 - カレーなる辛口Javaな転職日記

来年もRailsとうまい付き合い方をしていきたいものです。それではよいお年を。

rubyの簡単なスクリプトでファイル・文字列操作 〜MH4Gのお守りファイル処理を例に〜

ハンター的なお話(前置き)

私はモンスターハンター4Gにはまっています。スキルシミュレータ(泣)さんで装備を組ませていただいています。
そこで大事になるお守りなのですが、お守りの管理ってしっくりくるものがなく困っていたところ、(泣)さんでお守りのインポート/エクスポートができるようになりました。
ので、rubyで簡単なスクリプトを書いてソートしたのですが、思ったより色々やったのでファイル操作について書いておきます。

お守りデータの解釈

エクスポートされたお守りはこのような形です

,3,乗り,8
,2,溜め短縮,6
,1,納刀,6,属性解放,6

一番前にあるコロンはおそらく区切りでしょう。最後ではなく最前に持ってくる記法ですね。
ちなみに構成は、[,スロット,第1スキル名,第1スキルポイント(,第2スキル名,第2スキルポイント)]という形です。
このようなエクスポートされたお守りファイルをamulets.txtとして保存してあるとして、まずはこれを開いて解釈するスクリプトを書きます。

path = 'amulets.txt'
file = File.open(path)
amulets = Array.new

file.each_line do |line|
  arr = line.chomp.split(',')
  amulets << arr
end

File.openでファイルを開き、each_lineで各行ごとに、改行文字を取り除いた上でカンマで区切り1つのお守りの情報を配列とし、それをさらに配列amuletsに格納します。

次に見やすくすることが目的なので、スキル1とスキル2のスキル値の大きい方を前にするように入れ替えます。

amulets.each do |amu|
  if amu[4] && amu[5].to_i > amu[3].to_i
    amu[2..5] = amu[4], amu[5], amu[2], amu[3]
  end
end

まず最初にamu[4](スキル2)が存在するかを確認した上で、スキル1とスキル2のスキル値を比較します。存在を確認しないで比較すると、存在しない場合にエラーになります。
比較する際に、元の要素は文字列であるため、整数型にキャストしてから比較します。(文字列の場合'10'<'2'となる。これは後述のソートの際も同様の理由でキャストが必要。)
スキル2の方が大きい場合は入れ替えるのですが2要素がセットなので代入で入れ替えます。配列に複数代入するのにrubyではこの書き方ができます。

ソートの順序を定義する

このままでもソート自体はできるのですが、文字順になってしまい使い勝手が悪くなってしまいます。
そのためここでは、スキルシミュレータのスキル順序でソートのルールを定義します。
まず定義するためにシミュレータページからセレクトボックスの中身をいただいてきます。(個人利用なのでここには内容は載せません。)
セレクトボックスなので、以下の形式になっているはずです。

<select>
  <option value="スキル名">スキル名</option>
  <option value="スキル名">スキル名</option>
  <option value="スキル名">スキル名</option>
  <option value="スキル名">スキル名</option>
</select>

ここから正規表現でスキル名をこの順序で取り出します。最終的にはスキル名をキー、優先度を表す整数をバリューとしたハッシュを吐き出します。
まずは上記のソースからoption部分だけど切り出し、これをskills.txtとします。取り方にもよるのですが、私の場合インスペクタからだと改行されていなかったので、その前提で処理します。

require 'yaml'

path = 'skills.txt'
file = File.open(path)
hash = Hash.new

# 正規表現でスキル名を切り出し
skill_regexp = /<option\svalue=".*?">(.*?)<\/option>/
keys = file.scan(skill_regexp).map{|key| key[0]}
size = keys.size

# Hashの要素を追加
keys.each.with_index do |key, i|
  hash[key] = size-i
end

#YAMLファイルに出力
File.open('skills.yml', 'w') do |f|
  YAML.dump(hash, f)
end

正規表現は、.*では最長で検索され全体がマッチしてしまうため、最短検索の?をつけ.*?とします。括弧でくくった部分がマッチ結果として配列で返され(この場合は一箇所のみのため要素1つの配列)、scan関数で結果を配列に格納します。
そのため結果が2次元配列となってしまうが、keysを2次元配列にするべきではないためこの時点でmapで対処。(flattenでも同様になるが意味を明確にするためにmapを使用。)
ソートを降順で行うため、降順でハッシュにし、YAMLファイルへ出力。100要素をハッシュのためYAMLで外部に出力するのが適切かと思います。

実際にソートを実行する

require 'yaml'

path = 'amulets.txt'
file = File.open(path)
amulets = Array.new
file.each_line do |line|
  arr = line.chomp.split(',')
  amulets << arr
end

amulets.each do |amu|
  if amu[4] && amu[5].to_i > amu[3].to_i
    amu[2..5] = amu[4], amu[5], amu[2], amu[3]
  end
end

# 出力したYAMLを読み込む。Hash。
skills = YAML.load_file('skills.yml')

amulets.sort_by! do |amu|
  [skills[amu[2]], amu[3].to_i, amu[1].to_i]
end
amulets.reverse!

out_amulets = amulets.map{|amu|amu.join(',')}

File.open('out_amulets.txt', 'w') do |f|
  out_amulets.each{|amu| f.write("#{amu}\n")}
end

sort_by!はブロック引数でソートする破壊的メソッドです。配列で渡された場合は前からの優先度でソートします。
ここではamu[2]をキーとしたバリュー(つまりスキル名に対応した通し番号)、第1スキルポイント、スロット数の優先度でソートします。数値比較のため文字列は整数型にキャストしています。
このソートは降順で、昇順にするためには本来はreverseすれば良いのですが、複数項目を指定する場合は降順昇順が混在することはできません。そのため、降順に揃えます。
最後は元と同じようにカンマで繋げ、各行ファイル出力することで完了となります。


このような簡単なスクリプトでソートツールを自作できるわけです。が、今回は最適っぽいのを調べていたら時間がかかってしまいました。Rubyなので簡単な処理ほど別の記述の仕方がありそうという気がしてしまいます。
あまりファイル操作っぽい話ではなくなってしまいましたが、スクリプトっぽいのは書けたと思いますので今回はこれにて。明日はRailsについて書いて今年の締めとします。