ホーム ブログ ページ 34

UnityのEventSystemのクリックイベント実装方法

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Unityを使っていて実装で詰まったところの備忘録としてUIが重なった時の処理を書いていきます。 主に、EventSystemについて書いていきたいと思います。 EventSystemで制御している時は、EventSystemを介して制御しましょうと言う話です

はじめに

こんにちは、初めまして。今回初めて投稿させていただきます新卒でエンジニアとして入社した者です。

今回、Inputを使ったクリックイベントを実装しました。しかしEventSystemはそのクリックイベントには干渉してこないので何かしらのオブジェクトが重なってもInputのクリックイベントが実行されてしまうと言うバグが出ました。
その時のEventSystemで制御する方法を書いていきます。

EventSystem とは

これは、UIのイベントを制御するオブジェクトで、Unity上の入力をうまく処理してオブジェクトにイベントを送信する仕組みのことです。基本的にUnityのuGUIはこれで管理されています。

なぜこのバグが起こったのか?

このバグが起こった原因は、EventSystemとInputクラスの処理が連携していないことに原因がありました。
EventSystemは上記の通り、uGUIの入力を管理するコンポーネントです。ボタンなどに対しての入力エベントを管理しています。
対してInputクラスは座標を取得してその座標内にオブジェクトがあるならば、クリックイベントを実行する実装になっていました。

これでは、どちらも独立しているので、座標でイベントを管理しているとどんなにUIが重なってもその場所がタップされると実行されてしまうという状況でした。

解決方法

解決方法として、複数方法がありました。

  • raycastでどのオブジェクトが重なっているかを判定して一番上にあるもののクリックイベントを実行する方法
  • IPoinerClickHandlerインターフェースを使い、InputをEventSystemに組み込んで実装する方法

今回は後者で実装しました。

実装方法

IPoinerClickHandlerインターフェースをクラスに実装してください。そうすることで、InputでとっているクリックイベントをEventSystemに組み込むことができます。このようにするとInputクラスでの入力とEventSystemでの入力を連携させることができました。

ソースコードは以下のようになります。

class TestInput : IPoinerClickHandler {
  public void OnPointerClick(PointerEventData eventData) {
    //ここにタップ処理を追加する
  }
}

このインターフェースは様々な種類があります。
詳細は下記URLで詳しく書いてあります。
https://docs.unity3d.com/Manual/SupportedEvents.html

まとめ

EventSystemを挟むことで簡単に制御ができるようになりました。
EventSystemで管理しているUIは、EventSystemを介して制御してあげましょう。そうしないと今回の私のようにバグを生み出してしまうのでやめましょう。

もし、興味のある人はuGUIのソースコードは、BitbacketのUnity Technologies/Unity/UIにて公開されているので読んでみてはいかがでしょうか?

Unityのインストールが上手くいかなかった時の対処法まとめ

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Unityのインストールが上手くいかなかったときに参考にしたサイトや方法のまとめです

初めてUnity(ver5.6)をDLした際全く起動が出来ず四苦八苦したときの思い出を元に試した方法を幾つかまとめました。
もし似たような環境でUnityが起動しない!という方は参考になれば幸いです。

作業環境

当初の私の作業環境がこちら。
【使用PC】IntelCorei7-4790K
【OS】Windows7
【主な使用ブラウザ】Internet Explorer11(以下IE)

今回起動したかったUnityはバージョン5.6。2017年現在最新バージョンのものです。
公式サイトを開き最新バージョンをDL。しかしインストールしてもエラー画面により一向に起動しない。そんな状態でした。
というわけでインターネットに頼りつつ幾つかの方法を試してみましたので箇条書きしていきます。
参考にしたサイトもリンクさせていただいておりますので詳しくはそちらをご参考ください。

対処方法

Unityログインアカウント名を確認してみる

Unityを起動する際に最初に設定した自身のUnityIDを入力するのですが、海外製ソフトの為か、日本語が混じると動作が不安定だったり不調が起こりやすくなるそうです。ログインアカウント名は全てアルファベットで作成してください。

再起動

まずは再起動してみましょう。たまたま起動が失敗した場合もありますのでUnityやPCを再起動してみてください。

再インストール

インストール自体がそもそも上手くいかない場合があります。この場合は前のデータをアンインストールし、PCを再起動してから再びWebサイトから最新バージョンのデータをDLしてみてください。
また再インストールした際以前の設定がそのまま使用されるパターンがあります。アンインストールだけでは消えないフォルダが存在している為なので、一から設定をしなおしたい場合はそれらを削除することをお奨めします。以下のリンクを参考にしてください。
FreelyApps:Unityの再インストール

前バージョンUnityを起動してみる

Unity5.6自体の問題やPC自体が新バージョンに対応してない可能性もあります。
もしそうであれば、前のバージョンのUnityなら起動できる場合がありますのでお試しください。

使用ブラウザを変えてみる

上記の古いバージョンのUnityをIEブラウザでDLしてみたところうまくDLがいかない、ファイルが開けないということがありました。
こちらの問題は使用ブラウザを変更することで解決されます。Unityにはブラウザとの互換性の問題もあるらしく、その中でもFireFoxがブラウザの中では最も互換性が良いようです。
IEやGoogleChromeではDLが上手くいかない場合はブラウザを変えてみてください。

セキュリティソフトの設定見直し

PCのセキュリティソフトの中でUnityと相性の悪いものも存在します。セキュリティソフトによって起動できないパターンもありますので、セキュリティソフト対象からUnityを除外に設定してみましょう。
SAKスタッフブログ:Unity起動時のエラーとその対処法

DEP有効にしてUnity.exeを追加

Windowsのアップデートか何かでUnityが起動しなくなった場合、
「コントロールパネル→システム→システムの詳細設定→パフォーマンス→データ実行防止→DEP有効にしてUnity.exeを追加」
で起動できた場合もあるそうです。ただセキュリティ上の問題があるかもしれないのできちんと調べたほうがよさそうとのこと。
商人の街ブログ:Unityで遊んでみようか 第1回 Unityを起動せよ<Unity起動エラー対策(仮)>
誰かのメモ:Unity が起動しなくなった

ディスプレイアダプターのドライバーを更新

ディスプレイアダプターのドライバーのバージョンが古いと最新バージョンのUnityと
噛み合わない可能性があります。もしその場合は最新バージョンにアップデートしてみてください。私はここが問題だったようで更新したら解決しました。
Windows 7 で、ディスプレイアダプターのドライバーを更新する⽅法についてpdf
また、ディスプレイアダプターにIntel HD Graphics系を使用しており、WindowsUpdateが上手くいかない場合は以下のリンクに対処法がありましたのでご参照ください
taccumanote:Windows UpdateでIntel HD Graphics系の更新プログラムのインストールが出来ないときの対処法

最後に

今回は使いませんでしたが色々記事を検索しているとサポートセンターに連絡するとすぐ解決した、みたいな人もいらっしゃったのでどうしても分からない場合はサポートセンターにお問い合わせください。
ユニティ・テクノロジーズ・ジャパン合同会社:無料サポート
Unityはそれ一つで2Dゲームから3Dゲームまで簡単につくることができてしまうのでぜひDLしてお楽しみください!

Box Drive パブリックベータ版(Windows)を使用して見た

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Box DriveはWindowsおよびmacOSで動作するデスクトップアプリケーションです。
ファイルの編集、検索、共有などをエクスプローラーや、Finder から操作することが出来ます。
イメージ的には、NAS(ネットワーク接続ハードディスク)を使用している感覚に近いと思います。

いままでのBox Sync との違いは、使用しているPCのHDDを圧迫しない。不要なファイルがPCに残らない。
※厳密にはアップロードやファイルを編集する時には一時的にはHDDを使っているようですが。

Box Drive

待ち望んでいたBox Drive(以前までは、Box for Desktopという名称の予定でした)が
パブリックベータではありますが、リリースしたので早速使ってみました。
詳しくはこちらを参照

enter image description here

使用上の注意点(Windowsの場合)

  1. Box SyncとBox Drive は同時に実行しない。Box Syncはアインインストールしましょう。
  2. Box Driveは、Windows 7 64ビットおよびWindows 10 64ビットのみをサポートします。 32ビット版とWindows 8.xはサポートされていません。 その他の注意点はこちらを参照して下さい。

こんな所が便利??

メールを送信する時、(普段の仕事で使用するときには、)基本的に共有リンクを使うのですが、
BOXにアクセス出来ない会社様の場合、メールに直接ファイルを添付して送信しています。ファイルがBOX上にのみある場合は、ダウンロードしてから、メールに添付する操作をしていましたが、直接ドラッグ&ドロップでコピーできます(貼り付けられます。)

enter image description here

その他 使用方法

共有リンク

Drive から、共有リンクを作成する方法は、
対象のファイル・フォルダで、右クリックすることで、BOX  >  Copy Link で共有リンクが取得できます。

enter image description here

検索

BOXには強力な検索機能がありますが、
それを使用するには、タスクトレイのBox Driveアイコンを選択するか
Ctrl + Shift + Alt + B で下図のような検索ウィンドウを表示して、検索を実施することが可能です。
残念ながら、エクスプローラー上から検索は出来ません。

enter image description here

個人的に残念な事。(今後に期待)

BOX の新UIからアカウント設定よりブラウザでBOXに接続した時に表示されるホームページ(初期ページ)の設定で「お気に入り」を選択出来るようになったことで、使いやすくなりましたが、Box Driveでの表示されるのは、「すべてのファイル」を選択した時と同じなので、表示が切り換えられる仕組みに期待しています。

enter image description here

まとめ

とりあえず、待ち望んでいたアプリケーションが出てきたので簡単に使用してみました。
まだファイルをロックしたり、ロック解除したりする機能も、パブリックベータ版には実装されていないようなので、今後のアップデートに期待しています。

Boxの販売パートナーもしてます。

enter image description here

お問い合わせは、こちら へ
BOXを使ったのアプリケーション開発も。

Rubyを書くときに気をつけたいこと

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Ruby初心者の私がコードを書くときに気をつけていることをまとめてみました。

はじめに

 こんにちは。今年新卒で入社したエンジニアです。
Rubyを学習し始めてからインターンの数日を除くと1ヶ月半ほどになりますが、先日初めてコードレビューを行った際に先輩方から「Rubyらしいコードで書こう」との指摘をいただいたのを機に色々調査しながらコードの修正を行いました。基本的なことですが備忘録という意味も兼ねてまとめたいと思います。
 

目次

 1. 適切なメソッドを使う
 2. 目的と同じ実装をしてくれるライブラリを使う
 3. 読み手に分かりやすいように書く

1. 適切なメソッドを使う

 この記事のきっかけとなったコード修正で一番多かったのがこれでした。
Rubyには初めから便利なメソッドが多数用意されており、それを利用することでRubyらしくちょっとだけクールなコードを書く事ができます。
今回この記事を書くきっかけになった実装が文字列処理を含むものだったので、文字列自体の処理を簡素化して実際にコードレビュー前と後の差に似せて出してみようと思います。
stringという小文字とコンマで表された文字列をコンマで区切って全て大文字にして配列に格納するコードを例にします。

# 修正前
str = []
string.split(",").each do |s|
  str << s.upcase
end

ここで使ったeachは単に各要素を参照して処理を行うだけで戻り値に変化はありません。
このコードをmapを使って修正すると以下のようになります。

# 修正後
str = st.split(",").map {|s| s.upcase}

mapは各要素を参照して処理をしたあと、結果を新しい配列にしてくれます。
Rubyには同じような処理をするメソッドでも明確な違いを持ったメソッドが多数あります。

今回例に挙げた配列の要素の数だけ各要素を参照してブロックを実行するメソッドについて基本的なものをまとめておきます。

  • each 要素を順番に参照してブロック内の処理を行う
  • reverse 要素を逆順に参照してブロック内の処理を行う
  • map 要素を順番に参照してブロック内の処理を行い、各要素の処理された結果を新しい配列として作成
  • select 要素を順番に参照してブロック内に書かれた条件を満たすものだけ返す(ブロックが真を返す要素だけで配列を作成)
  • reject selectとは真逆で要素を順番に参照してブロック内に書かれた条件を満たさないだけ返す(ブロックが偽を返す要素だけで配列を作成)

自分が実装したい処理、目的と合うメソッドを使う事で処理をシンプルにまとめることができるので、もっと適切なメソッドがないか、使いやすいメソッドがないか考えながらコードを書くと自然とRubyらしいコードが書けるようになると思います。

2. 目的と同じ実装をしてくれるライブラリを使う

Rubyを使っているとよくgemという言葉を耳にします。
gemとはRuby用のライブラリやアプリケーションを指す言葉で、誰でも簡単に公開することができます。
それゆえ大量のgemが存在し、目的のものが見つかりやすいうえgemの中でも同じような実装をするものも多数あるので目的に合わせて好みのものを選んで使うこともできます。
よく使われるものでbundlerやrails、知名度が高いものの中でもnokogiriやkaminari、kakurenboなど親近感の湧く和名のgemもよく見かけますね。
gemはコマンド1つでインストール出来るうえ簡単に実装することも出来るので1から全てを実装せずに済みます。
実装に直接関わるものだけでなく、デバッグ時に役立つブレークポイントをつけてくれるgemや好きな時刻に変更したり、とある時刻で止めたりしてくれるgemなど多数存在します。
これらを活用すると実装のコードをシンプルにしたり時間効率を上げることももちろん可能になります。
何か新しく実装を加える時は似たような実装ないか探してみたら夢を叶えてくれるgemに出会えるかもしれません。

3. 読み手が分かりやすいように書く

 これはどの言語にも言えることですが、他の言語に比べてRubyはやる気さえあればどこまでもコンパクトに書けてしまう言語だと思っています。
ですがコンパクトに書く事だけに意識を向けてコードを書いてしまっては読み手にとっては難解なコードになりかねません。
※後述するFizzBuzzの最短コードは文字数を減らすのが目的で書かれているので説明がないとどういう処理なのか分からない人がほとんどだと思います。
私が分かりやすいコードにするために心がけていることは以下の2点です。

  • 変数やメソッド、クラスの命名
     多少長くなってもいいのでその変数が何で使われているのか、何を意味しているのかを見てわかるように命名する
  • 改行やスペースを活用する
     稀に巡り会うずらずらとスペースも改行もなしで何行にも渡るコードは、見にくくて時折書いた本人でも嫌になることもあるので、見やすいように書く

1点目はごく当たり前のことですが、私は実装を進めていると2点目を忘れがちで必死にコードをガリガリと書いてしまいます。
配列や括弧の中であれば普通に改行しても問題ないですが、改行したら文末と解釈されてしまって正常にプログラムが動作しないからどうしようもない!という場合があります。その時はバックスラッシュ(option+¥)を文末に入れることで「ここは改行されているけど文末ではない」と教えることが出来ます。
今挙げた2つのルールはプロジェクトによって明確にこうだと決まっていることが大半なので合わせて書くことも大切ですが、もし特に決まっていない場合のことも考えて自分ルールを作っておくとコードを書くときに迷わずに済むかもしれません。

最後に

 これらは基本中の基本で、この他にももっと留意すべき点や使うと便利なものはまだまだあると思いますが基本が一番大切だと思うので書かせていただきました。
私がインターン時に初めてRubyを学習した際に先輩からRubyは「クールに書く」「車輪の再開発は良くない」と言われたのを覚えています。
正直その当時はあまりピンと来ていなかったのですが、これらは今回の1、2に通ずるもので実際に書いて修正しながらコードを書いていくうちに言葉の意味が理解できてきました。
先輩方のようなシンプルでかつ読みやすい優しいコードが書けるようにこれからも学習していきたいと思います。
 

おまけ: FizzBuzz

 おまけ程度に書くつもりが結構なボリュームになってしまいましたが、私がRubyを初めて学習したときに見つけたFizzBuzz最短実装を目指す人たちのコードや記事が面白かったので紹介したいと思います。
※FizzBuzzとは1から100まで順番に数え、3の倍数の時はFizz、5の倍数の時はBuzz、15の倍数の時はFizzBuzzと言うゲームのことです。
ちなみにこのFizzBuzzをRubyで何も考えずに実装すると以下のようになります。

(1..100).each do |number|
  if number % 15 == 0
    puts "FizzBuzz"
  elsif number % 3 == 0
    puts "Fizz"
  elsif number % 5 == 0
    puts "Buzz"
  else
    puts number
  end
end

条件文をどうにかしたい。15の倍数はどうにか省略できないものかと試行錯誤して書いてみたコードが以下です。

(1..100).each do |n|
  str = "#{['Fizz'][n%3]}#{['Buzz'][n%5]}"
  str = n.to_s  if str == ""
  puts str
end

配列アドレスに剰余を入れる事によって割り切れるときつまり剰余が0のときに配列の0番目が呼び出されるので3の倍数ならFizz、5の倍数ならBuzz、15の倍数ならFizzとBuzzが両方呼び出されてもしどちらも呼び出されなかったら数値自身を入れて出力するといった実装です。無茶苦茶なコードですが私にはこれが限界でした。
ちなみにRubyを用いた最短コードが51byteで書かれたこのコードのようです。

1.upto(100){|n|puts'FizzBuzz
'[i=n**4%-15,i+13]||n}

面白かったのでこのコードを書かれた方が解説しているページのリンクを載せておきます。
perlだともっと短いコード(最短30byte)で書けたり、FizzBuzzを実装してくれるgemやRubyでもっと変わった方法で実装されている方も多数いました。興味があったら是非調べてみてください。

知っておきたいgitコマンド

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

 addやcommitなどのメジャーなgitコマンドは知っていたが、gitを使用した開発で初めてお世話になったコマンドがあったので、紹介したいと思います。

作業中に別の作業に変更する

 優先度の高い仕事が手元から離れて優先度が低い作業に取り掛かっている時に、優先度の高い仕事が再度自分の手元に戻ってきた場合にstashコマンドが役に立ちます。
 stashコマンドとは、現在作業しているブランチの作業内容を一時的に保存することや保存されているstashを取得することができます。以下で自分がよく使用したコマンドの一部を紹介したいと思います。

変更内容の保存
git stash
保存されている中で最新のstashを取り出す
git stash pop
 指定したstashを取り出すには、popの後ろにstash@{0}と指定する。0の所は、stashの番号を入力する。
保存されているstashの一覧表示
git stash list
保存されているstashのファイルを確認
git stash show stash@{0}
保存されているstashの全削除
git stash drop
 一部のstashのみ削除する場合は、dropの後ろにstash@{0}と指定する。

add,commitの取り消し

 自分がadd,commitの取り消しを初めて行う際に、変更内容まで消えてしまうのではないかと不安になった為、まとめました。

addの取り消し
git reset HEAD 「取り消すファイル名」
 こちらのコマンドは、変更内容はそのままでaddされた状態のみ取り消します。
最新のcommitの取り消し
git reset --soft HEAD^
 こちらのコマンドは、最新のコミットの取り消しを行います。変更内容はそのままです。今回は、オプションに--softを使用していますが、--hardを使用すると変更内容まで取り消してしますので注意が必要です。
ファイルの変更内容の取り消し
 git statusコマンドを使用すると、作業しているブランチの変更ファイル一覧が表示されるのですが、その中には変更内容に必要ないファイルがあることがあります。このような場合は、git checkout 「変更内容を取り消すファイル名」コマンドを使用するとファイルが変更前の状態になります。

gitのgrepコマンド

 grepコマンドは、ファイルの中の文字列を検索する場合によく使用します。先輩に言われるまでLinuxのgrepコマンドを使用していたのですが、gitにもgrepコマンドがあるということでgitのgrepを使用してみました。
linuxのgrepコマンド grep -r 「検索する文字列」 「探すディレクトリ」
gitのgrepコマンド git grep 「検索する文字列」
こちらの2つのコマンドを調べた結果、gitのgrepには、メリット・デメリットがあります。

  • メリット gitのgrepはリポジトリ以外を検索しない為、linuxのgrepよりも速く見つけることができる。
  • デメリット gitのgrepはリポジトリの中しか検索対象にならない為、linuxのファイルを確認することができない。また、検索する場合は、リポジトリのディレクトリに移動する必要がある。

まとめ

 今回は、自分が知らなかったgitコマンドについてまとめてみました。内容に関しては初心者向けの記事になりましたが、git初心者の方の参考になれば幸いです。

ゲーム分析手法入門

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

ゲーム業界でプランナーやりたいけどどういうことをすればいいのかわからないという人たちに向けて自分なりの分析方法についてまとめてみました。

はじめに

はじめまして
新卒でプランナーをやっていますモツ太郎です。
記事を書くことが決まってから何を書こうかなーと思い悩んでいましたが、自分がプランナーとしてやってきたことをつらつらと書いていきたいと思います。
というわけでまず初めにアプリ分析のやり方について記事にしたいと思います。
※あくまで個人のやり方です。

アプリ分析する意味について

おそらくこの記事を読んでいる人はプランナーってなにをしているのだろう?と思っている人が多いのではないかと思います。
プランナーと一概に言ってもその仕事は多岐にわたっており、一言で表すのは難しいですが、今回のアプリ分析に関してはプランナーがやる仕事のうちの施策を考えるというところに役にたつものだと考えています。
プランナーとしてやっていこうと思ったらなぜそれが面白いと感じられるのかというところをきちんと考えアウトプットできないと意味がありません。
そこで以前自分が先輩に教えてもらった分析資料のフォーマットを使いながらどういうところに注目しているのかというのを見ていきましょう。

分析内容

基本情報

enter image description here

上記の画像を見てみれば大体わかると思いますが、タイトル通り基本的なものしかないです。ただここからきちんと書き出しておくことは大切で、自分たちが作ろうとしているゲームとあっているのかという前提を確認するために必要になります。
例えば、コンシューマのゲームを作ろうとしているのにプラットフォームがスマートフォンのゲームを参考にしたところで的が外れたものになってしまいます。また産出国も同様で自分たちが日本でだしたいのにアメリカで売れているものを参考にしたところでやりたいことが違ってきてしまいます。そういう前提の条件を確認するためのシートになります。

調査・考察

enter image description here

ここではそのアプリが「誰に」「何を」させたいのかというところを見ます。
「メインターゲット」「コンセプト」のところですね。
この部分は新規で作るときに必ず大事になってきます。この部分がないとゲーム作るときになにをすればいいのかということが全く分かりません。
そして、それは一人ならいいのですが、チームで開発する際にみんなでどんなゲームを作りたいかという完成系のイメージの共有ができず、バラバラの方向を向かってしまいます。

更新頻度系はユーザーを飽きさせないためにどういう頻度でやっているというのはわかりますが、最初は優先度低くてもいいと思います。
ただ「各ユーザー層向けのマネタイズ&要素」は重要です。
結局は売り上げが立たないとアプリは続けることができないのでその分析しようと思ったものが「どうやって」続けていくことができているのかというところはきちんとつかみましょう。

遷移画像

enter image description here

初めから細かくやっていこうと思うと先が続かなくなるところです。
最初あまり細かくやらずに大雑把にできるようにしましょう。
大雑把にどういう画面の遷移をたどっているか、どういう機能がまとめられているかというところを見ることが重要です。

総評

enter image description here

そのアプリを分析してどういう印象を得たか、どういうことをやっていると感じたかをまとめます。
そして、なぜ売れていると感じたか、どういうところが他と差別化できており、売り上げにつながっているかをまとめていきます。

おわりに

今回ゲームの分析手法を紹介してきましたがいかがだったでしょうか。
もちろん細かくやっていくとキリはないのであくまで簡易のものとなっていますが、プランナーを目指す人達はぜひ一度やってみてほしいです。
また、一人でやるだけではなく周りの人たちと同じものを分析してみて最後に見せあうor話し合うということでほかの人の考え方を学ぶことで色々な人たちの考え方も知ることができ、今後のプランナーとしてやっていくうえで大事なことになると思うのでぜひやってみてくださいね。
そして今後ゲーム業界で働こうと思った時には役に立ててくれると幸いです。

BoxのAPIを使って見よう。(その2)~実際にBoxへ認可要求・アクセストークンを取得しAPIで情報取得

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

今回は、前回(その1) で説明出来なかった部分の補足となっています。

1.認可コード要求・応答

1.1. 認可コード要求・応答

リファレンスサイト を参照して頂ければ解決しますが、ポイントになる部分のみを、抜き出して書いておきます。
前回(その1) で説明をした下図の遷移に関しての補足となります。

enter image description here

以下ののURLに対して、パラメタを設定して送信することで、認可コードを得る事ができます。
■URL
https://account.box.com/api/oauth2/authorize

■パラメタ
response_type
  「code」固定です。
client_id
  認証を要求するアプリケーションのクライアントID
redirect_uri
  認証が完了した場合に、ブラウザにリダイレクトされるURL
state
  認証が完了した場合のリダイレクトURLに同じ文字列が返ります。攻撃からの保護のため、リクエスト時にランダムなハッシュ値を格納し、応答時に、同じ値が返却されてくるかチェックに使用すると良いでしょう。

■リクエスト例

https://account.box.com/api/oauth2/authorize?response_type=code&client_id=<MY_CLIENT_ID>&redirect_uri=<MY_REDIRECT_URL>&state=<MY_SECURITY_TOKEN>

client_id と、redirect_uri は、下図の登録したアプリケーションの構成情報から取得します。

enter image description here

実行すると、下図のBoxの認証画面が表示され、ログインすることで登録したアプリケーションでBoxにアクセス許可を求めてきます。
Boxへのアクセスを許可」を選択することで、認証コードを得ることができます。

enter image description here

1.2.認可コード応答

認可コードは、以下のパラメタに格納されています。

code=<認可コード>

2.アクセストークン要求・応答

2.1.アクセストークン要求

enter image description here

以下ののURLに対して、パラメタを設定して送信することで、アクセストークンを得る事ができます。
■URL
https://api.box.com/oauth2/token

■パラメタ
grant_type
  「authorization_code」固定です。
code
  認可コード応答で取得した認可コード
client_id
  認証を要求するアプリケーションのクライアントID
client_secret
  認証を要求するアプリケーションのクライアント秘密コード

■リクエスト例

curl https://api.box.com/oauth2/token \
-d 'grant_type=authorization_code' \
-d 'code=<MY_AUTH_CODE>' \
-d 'client_id=<MY_CLIENT_ID>' \
-d 'client_secret=<MY_CLIENT_SECRET>' \
-X POST

client_id と、client_secret は、下図の登録したアプリケーションの構成情報から取得できます。

enter image description here

実行すると、アクセストークン を得ることができます。

2.2.アクセストークン応答

アクセストークンは、JSON型の応答 access_token に含まれています。

{
    "access_token": "T9cE5asGnuyYCCqIZFoWjFHvNbvVqHjl",
    "expires_in": 3600,
    "restricted_to": [],
    "token_type": "bearer",
    "refresh_token": "J7rxTiWOHMoSC1isKZKBZWizoRXjkQzig5C6jFgCVJ9bUnsUfGMinKBDLZWP9BgR"
}

3.Boxファイル情報取得(アクセス例)

以下のように、リクエストヘッダに Authorization: Bearer YOUR_ACCESS_TOKEN をセットして
送信することで、各種操作が可能となります。

curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
https://api.box.com/2.0/files/123456789

まとめ

次回は、BOXのAPIを使って、EXCEL(VBA)から呼び出して見たいと思います。

RailsでLoggerを使ってLogローテション

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

RailsでLogローテーションについて学んだのでそれの備忘録兼、復習です。

はじめに

 初めまして、17新卒でエンジニアとして入社したむらさきです。
 4月にエンジニアとして入社し、Ruby on Railsを使用してwebサイトの改修や機能の追加などを行っています。入社前のインターンに参加するまでRubyもRailsもwebサイト構築もしたことの無かったのですが、この3ヵ月弱で色々なことを学んで少しずつですが成長を日々実感しています。
 さて、今回から記事を書くわけですが、他のエンジニアの方々のような難しいことを書く知識はないので、実際に仕事で制作した「Rubyでlogを作成してローテーションさせる」機能について復習を兼ねてまとめたいと思います。

開発環境

Windows10(64bit)  CentOS7.3.1611  Rails 4.1.4   ruby2.2.0

今回の目的

 今回は以下の2つを目的としていきます

  • 処理ごとに出力される内容をLogとして日ごとにファイルに出力する。
  • 出力したLogファイルを定期的に削除する。

目次

  1. CustomLoogerの作成
  2. Logへの出力方法
  3. Logのフォーマットを変更する
  4. 古いLogを削除させる
  5. crontabの設定

1.CustomLoggerの作成

 Logを書き出す方法はいくつかありますが今回はrubyに標準搭載されているライブラリのLoggerを使用します。
Logファイルを格納するフォルダを/public/custom_log/に作成して、その直下にcustom.logを日付ごとに作成していくようにします。
開発環境、テスト環境、本番環境によって記述する場所が違うので気を付けましょう。今回は開発環境で行うのでdevelopment.rbに記述します。

#config/environments/development.rb
config.custom_logger = logger.new('public/custom_log/custom.log', 'daily')

第1引数で作成するファイルの場所と名称を、第2引数で期間を基準に新しいファイルを作ってくれるようになります。

  • ‘daily’は1日ごと
  • ‘weekly’は1週間ごと
  • ‘monthly’は1ヵ月ごと

となっています。
※サーバーを起動した際の翌日の0時がトリガーとなっているようで、サーバーを起動している状態で日付を跨がないと新しいファイルが作成されないのでlocal環境で作成している人は注意が必要です。
うまく作成された場合は

custom.log
custom.log.20170620
custom.log.20170621
custom.log.20170622
・
・
・

という感じで.logの後に年月日が付いて作られていきます。今日作られたばかりのファイルには後ろに何も付きません。
 
 ちなみに、第2引数に整数、第3引数にサイズを指定することで、第3引数で指定したファイルサイズごとにファイルが作成され、第2引数で指定した数を超えた場合は古いファイルから削除させていくことができます。

config.contact_logger = logger.new('public/contact_log/contact.log', 4, 10 * 1024 * 1024)

今回の場合は日付ごとに管理したいという要望があったため、日にち指定の’daily’で実装していきますが、こちらには古いファイルを削除していく機能はないので後で別で実装する必要があります。自分またはチームが管理しやすい方法で実装してください。

2.Logへの出力方法

 Logに出力するにはcontrollerなどに以下の記述をします。

Rails.application.config.custom_logger.info("ここの内容をLogに出力します")

.info()は表示したいLogのレベルを表しており、

enter image description here

の5つに分類されています。指定したレベル以上のログを出力するようになります。debugを指定した場合はすべての情報が表示されるようになります。
.info()の中身はブロックや文字列が指定でき、その値がメッセージとして使用されます。

3.Logのフォーマットを変更する

 ここまでくれば希望した出力先にLogが吐き出せるようになっていると思います。
public/custom_log/custom.logを見に行くと下図のように出力できています。
enter image description here
しかし今のままだとLogの先頭に色々書いてあって少し見づらいですね。

ここで使えるのがFormatterです。
FormatterはLoggerのフォーマット文字列を扱うクラスです。

call(severity, time, progname, msg) -> String
ログ情報をフォーマットして返します。
[PARAM] severity:
  ログレベル。
[PARAM] time:
  時間。Time クラスのオブジェクト。
[PARAM] progname:
  プログラム名
[PARAM] msg:
  メッセージ。

 https://docs.ruby-lang.org/ja/latest/class/Logger=3a=3aFormatter.html

ドキュメントにある様にcallメソッドの4つの引数によってフォーマットを変えられます。今回はserverity, time, prognameは必要なく、msgだけあればいいので

#config/environment.rb
# Load the Rails application.
require File.expand_path('../application', __FILE__)

#ここから記述
class CustomLogger
  class Formatter
    def call(_severity, _time, _progname, msg)
      "#{msg}\n"
    end
  end
end
#ここまで記述

# Initialize the Rails application.
Rails.application.initialize!

と書き込めばmsgだけが表示されるようになります。
あとはこれをcustom_loggerにセットします。

#config/environments/development.rb

config.custom_logger.formatter = CustomLogger::Formatter.new

こうすることでLogのフォーマットが変更されているはずです。実際に確かめてみましょう。
enter image description here
ちょっと画像が見づらいですが、前についていたものがなくなって変わっていることが確認できました。

4.古いLogを削除させる

 上記までの方法でLogを出力する機能の実装は完了しました。
「1.CustomLoggerの作成」の部分で触れましたが、’daily’等の日付を引数にした場合はローテーションで削除していく機能はありません。なのでcronを使用して自動的に古いファイルを削除していく機能を最後に実装していきます。
 いきなりcronという言葉が出てきましたが、知らない人のために説明しておくと(自分も知りませんでしたが)、UNIX系システムの常駐プログラム(デーモンの一種)で、ユーザーが設定したスケジュールに基づいてコマンドやスクリプトを自動で実行してくれるすごいやつらしいです。起動や設定方法まで書くと長くなってしまうので各自で調べてください。
 とりあえず今回はlib/tasks/にlog_rotate.rbを作成してそこに削除用のスクリプトを書き込んでいきます。

#lib/tasks/log_rotate.rb
module Tasks
  module LogRotate
    require 'fileutils'
    require 'active_support'
    class << self
      def rotate
        time = Time.current.months_ago(3).strftime('%Y%m%d%H%M%S')
        log_all = Dir.glob("#{Rails.root}/public/contact_log/*")
        log_all.each do |i|
          if File.stat(i).mtime.strftime('%Y%m%d%H%M%S') < time
            FileUtils.rm_f(i)
          end
        end
      end
    end
  end
end

他にもっと簡潔な書き方があるとは思いますが、自分はこのような感じで書きました。

  1. 3ヵ月前の年月日時分秒を取得してtimeに入れます(例:20170322155030)
  2. 作成されたLogファイルすべてを配列にしてlog_allに入れます
  3. そのファイルを1つずつ最終更新時間を年月日時分秒で取得してtimeと比較します
  4. timeよりも値が小さい(古い)場合はそのファイルを削除させます

これでこのスクリプトを呼べば3ヵ月前より古いファイルを削除できるようになりました。

5.crontabの設定

 さて、これで最後の実装です。cronに先ほどのスクリプトを動かしてもらうためにcrontabに設定を書いていきます。
 毎月1日に1度先ほどのスクリプトを走らせます。時間は0時ちょうどだと他のものが走っていたりした場合にサイトが重くなってしまう可能性があるので深夜3時5分頃に走らせるようにします。

% crontab -e

でエディタが起動して設定を書き込むことができます。

% crontab -r

としてしまうと確認もなく今まで設定していたものがすべて消去されるので注意が必要です!
‘e’と’r’はキーボードで隣り合わせなのでうっかり押し間違えないようにしましょう(っていうのがどこのサイトにも書いてあったので自分も言ってみたかった)

*/5 03 1 * * /bin/bash -lc 'cd /アプリケーションのディレクトリ && bundle exec rails runner Tasks::LogRotate.rotate'

分 時 日 月 曜日 で並んでおり*/5とすると5分おきとなります。曜日は0-7で設定でき、0と7が日曜日で1=月曜, 2=火曜…と続いていきます。
その後ろで自分が作っているアプリケーションのディレクトリまで移動し、runnnerでスクリプトを起動します。
すぐに確認したい場合は

*/1 * * * *

とすることで1分おきに起動させられます。

これで、Logの出力とローテーションでの削除が実装できました!

おわりに

 今更ですが自分の環境でのことを書いたので環境次第では動作が上手くいかない等あるかもしれません。それでも誰かの助けになっていれば幸いです。
 コードの細かいところとか全然理解できてないことだらけですがこれからも実際に使ったことを備忘録兼、復習として書いていきたいと思います。ここまでご覧いただきありがとうございました。
 さて、1行前に言ったことは忘れて、次は息抜き的なことを書こうかな(。・ ω<)ゞ

ELBでSSLオフロードしている場合のhttpアクセスをlocalhostで偽装する

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

ELBでSSLオフロードする構成を組んでいる状態で配下のEC2インスタンス自身からlocalhostのhttpを叩きたい場合のTipsです。

前提

以下の記事のように、ELBでSSLオフロードして、配下のEC2インスタンスへは常にhttpでアクセスされる構成にしている。

http://qiita.com/snoguchi/items/f5ccb67592f87942480d

問題

ELB配下のEC2インスタンスにcurlでhttpアクセスしたいけど、nginxの設定でhttpでアクセスされたらhttpsにリダイレクトする設定してるため、自分自身のlocalhostに対してhttpのurlを叩けなくて困ったりする。

たとえば、railsのインスタンスが稼働しているか単純に確認したくてヘルスチェックを叩いてみたくても

$ curl http://localhost/healthcheck
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>

のようにリダイレクトされてしまう。

対処方法

ELBでSSLオフロード済みのhttpはヘッダに X-Forwarded-Proto: https がついてくるのでこれを明示的につけてあげれば良い。

$ curl -H "X-Forwarded-Proto: https" -v http://localhost/healthcheck

参考

pythonで梅雨対策

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

pythonで梅雨対策をします。
技術力が低いので、役に立つ技術記事はかけません。
その代わり、ちょっとだけ便利なものを手軽に作ります。

ざっくり概要

  1. APIから天気情報を取得
  2. いろいろする
  3. slackに投げる

結果

一時間後の天気がザーザー降り以上ならslackに通知するbotができました。
enter image description here

ちなみに、強さレベルで言うと
ザーザー<土砂<バケツ<滝<恐怖
となっています。恐怖が最強です。

APIから天気を取得

お天気APIは色々あって、OpenWeatherMapやDark Sky APIなど海外のものも触ってみたのですが、日本の詳細な天気が時間単位で取れなかったり、SSHがうんたらで怒られたりしたので、結局Yahoo! JAPANさんのYOLP 気象情報APIを使います。
ちなみに緯度経度が使えるので、大雑把に会社の近くの緯度経度にしました。
安心です。

色々する

APIから天気情報を取得して色々します。
簡単に言うと、APIからrainfallを抜いてきます。
rainfallは、どうやら降水強度という指標らしいです。
降水強度では分かりやすい目安がすぐに見当たらなかったので、似たような概念の時間降水量を参考に、rainfallをわかりやすくします。

気象庁に分かりやすい指標がありました。
上に書いた雨の強さレベルもこれに基づいてます。
http://www.jma.go.jp/jma/kishou/know/yougo_hp/amehyo.html

slackに投げます

Incoming Webhookというものを使います。

雑記

コード自体は単純ですが、APIの選定が地味に面倒でした。
せっかく作ったので、cronで回して、折りたたみ傘でも買って会社内でレンタル傘屋でもやろうかと思ったのですが、YOLPさんは商用利用に申請が必要そうなのでやめました。
では、良き梅雨を。

以下コード

メイン

# get_rainfall.py
import requests
import slack_post


def main():
    url = build_url()
    json_data = request_json(url)
    in_one_hour_rainfall = extract_rainfall(json_data)

    if in_one_hour_rainfall >= 10:
        rainfall_notice = notification_level(in_one_hour_rainfall)
        slack_post.post(rainfall_notice)


# url組み立て
def build_url():
    APP_ID = "YOLPのAPIキー"
    BASE_URL = "http://weather.olp.yahooapis.jp/v1/place"
    COORDINATES = "139.709008,35.669968"  # 緯度経度
    OUTPUT = "json"

    url = BASE_URL + "?appid=%s&coordinates=%s&output=%s" % (APP_ID, COORDINATES, OUTPUT)

    return url


# リクエスト
def request_json(url):
    req = requests.get(url)
    json_data = req.json()

    return json_data


# 降水強度の取得
def extract_rainfall(json_data):
    weather = json_data['Feature'][0]['Property']['WeatherList']['Weather']
    in_one_hour_rainfall = weather[1]['Rainfall']

    return in_one_hour_rainfall


# 降水レベル
def notification_level(in_one_hour_rainfall):
    if in_one_hour_rainfall >= 80:
        return "恐怖"
    elif 50 <= in_one_hour_rainfall < 80:
        return "滝"
    elif 30 <= in_one_hour_rainfall < 50:
        return "バケツ"
    elif 20 <= in_one_hour_rainfall < 30:
        return "どしゃ"
    elif 10 <= in_one_hour_rainfall < 20:
        return "ザーザー"


if __name__ == "__main__":
    main()

スラックになげる処理

import requests
import json


# slsckにpostするスクリプト
def post(text):
    requests.post('slackのAPI関連', data=json.dumps({
        'text': "一時間後に " + text + "降りの雨が降ります",  # 投稿するテキスト
        'username': 'baguette',  # ユーザー名
        'icon_url': 'http://2.bp.blogspot.com/-mhOboAyB0eA/VfS6MnLrttI/AAAAAAAAxOM/rqBqjtoezJ4/s800/fashion_ame_zubunure.png',  # プロフィール画像
        'link_names': 1,  # メンションを有効にする
        })
    )

フリップフロップと聞いてRubyを思い浮かべる方法

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

フリップフロップと聞いて、いきなりRubyやPerlの話を始める人はいないと思います が、今回の記事はRubyのフリップフロップのお話です。 論理回路のフリップフロップもRubyのフリップフロップも一度に確認できちゃうお得な記事にしたいと思います。

はじめに

みなさん初めまして、新卒エンジニアのくろすです。
今回の話、決してFlip Flopやフリップフラッパーズ、RWBYの話ではございませんのでご注意を。
個人的には3Dモデリングとかやってる人にRWBYの話とかして欲しかったりしますが。

そもそも フリップフロップ とは

flipflop とは (洗濯物・旗・サンダルなど)パタパタなる音、とんぼ返り、宙返り、(意見などの)急変、豹変(ひょうへん)、フリップフラップ [出典:Weblio]

なんのこっちゃわかりませんね。
とりあえず今回は普通の人(?)ならまず思い浮かべるであろうフリップフロップ回路の話から始めたいと思います。
要するにフリップフロップを使うと電源がある間は情報の保持が可能であるって話。
いきなり回路の話ですので、興味ない方は読み飛ばしておいていただけると。

メモリ って?

まずはエンジニアでない方でも聞いたことがあるであろうメモリの話から始めたいと思います。
メモリとはなんぞ?って質問にはとりあえずパソコンに入ってる4GBとか8GBとかの方のやつ。
くらいに思っておいてもらえればいいかと思います。

ざっくり言うとメモリには2通りの種類があり揮発性メモリと不揮発性メモリに分けることが可能です。

  • 不揮発性メモリ 電源の供給がなくても情報の保持が可能であるメモリ
  • 揮発性メモリ 電源の供給がないと情報の保持ができないメモリ

この揮発性メモリにはまた種類がありその中にはDRAMとSRAMと呼ばれる種類のものがあります。
DRAMは今回の話にあまり関係ないのでざっくりとしか紹介しませんが、
DRAMとはDynamic Random Access Memoryの略でコンデンサに電荷を蓄え、その電荷の有無で1bitの情報を記憶する半導体メモリです。この電荷をリフレッシュと言う作業で蓄え続けることによって情報を維持しています。
よくパソコンに刺すメモリなんかはこちらが多いかと思います。
そしてSRAMですがDRAMと比較して、回路が複雑でコストが高いがリフレッシュ作業がない分高速で消費電力が小さいと言う特徴を持っています。
SRAMとはStatic Random Access Memoryの略で、リフレッシュ作業がないことからStaticとの名前がついています。

フリップフロップ

さてこのSRAMの記憶部にはフリップフロップ回路というものが使われています。
ようやく出ましたね、フリップフロップくん。
最も基本的なフリップフロップはRSFFと呼ばれるもので以下の回路図で表されます。

enter image description here

Sがセット、Rがリセットで各入力に対する結果は以下のようになります。

SRQ¬Q
00前の状態を保持前の状態を保持
0101
1010
11禁止禁止

上の結果を見てもらえればわかりますが、セットSが立ち上がると無条件で出力は1に、リセットRが立ち上がると無条件で出力は0になります。出力の状態により(0, 0)を入力した際の状態が変わりますが、出力は直前の出力を保持します。
これがフリップフロップ回路が1bitの情報を記憶するメカニズムです。
一瞬の電気信号を回路自身がデータとして保持し続けるということなのですね。
※ ちなみにSRFFで(1, 1)入力は禁止です。これは入力を(1, 1)から(0, 0)に変化させた場合に、出力が(1, 0)で安定するか(0, 1)で安定するかが定まってないため禁止となっています。

Rubyのフリップフロップ

文字数稼ぎのはずが筆が乗りました。
ようやく本題です、むしろ本題の方がしょっぱい気さえします。

とりあえず、以下のコードを見てください。

string = "これからもよかったらかくりよの門をよろしくお願いします"
string.each_char do |char|
  if (char ==  'よ')..(char == 'よ')
    print char
  end
end

このコード実行するとこんな結果が帰ってきます。

よよよ

まぁ、見た感じそうなるでしょうって結果ですね。
次に上のコードそっくりだけどドットの数が違うだけの以下のコードを実行してみます。

string = "これからもよかったらかくりよの門をよろしくお願いします"
string.each_char do |char|
  if (char ==  'よ')...(char == 'よ')
    print char
  end
end

すると結果はこうなります

よかったらかくりよよろしくお願いします

ややっ、これは由々しき事態です。
どうしてこうなるのか、というのはだいたいリファレンスに書いてありますが説明していきます。

範囲式とは

リファレンスを読む限りではRangeクラスのインスタンスを生成する式のことを範囲式と言っているように思えます。

(a) 式1 .. 式2
(b) 式1 ... 式2

条件式の外側で使うと式1から式2までの範囲を表すオブジェクトを返してくれます。
また、(b)の書き方をすると範囲オブジェクトは式2の値を含みません。
Rangeクラスのリファレンスを見てもらえるとわかりますが、上の2つはRangeクラスのインスタンスとして宣言することも可能です。

(a) Range.new(式1, 式2, false) # default値がfalseなので実際はfalseいらない
(b) Range.new(式1, 式2, true )

ここで覚えておいて欲しいのは(b)式の場合は範囲オブジェクトが終端を含まないという点です。

条件式として範囲式を使う

さて、今回問題としているのは条件式として範囲式を使った場合です。
先に説明した、フリップフロップ回路の特性である「回路自身が状態を記憶する」ことと、範囲オブジェクトの終端の話を念頭に置くと理解しやすいかと思います。
少なくとも私は理解しやすかったです。
先ほども登場した範囲式についてのリファレンスには以下のように書いてあります。

「..」の場合:
1. 初期状態では式1だけを評価し、式1が真を返すまでは false を返します。
2. 式1が真を返すと true を返します。式2が真なら初期状態に戻ります。
3. この後は式2だけを評価し、式2が真を返すまで true を返します。
4. 式2が真を返すと true を返したあと、初期状態に戻ります。

「…」の場合:
1. 初期状態では式1だけを評価し、式1が真を返すまでは false を返します。
2. 式1が真を返すと true を返します。
3. この後は式2だけを評価し、式2が真を返すまで true を返します。
4. 式2が真を返すと true を返したあと、初期状態に戻ります。

つまりこの2つの違いは式1が真を返した時式2をその場で評価するかにあります。

(b)式の場合は終端である式2をその場で評価しないのですね。
そして、式2がtrueを返すまでの間は範囲式自身がtrueであるという状態を記憶してtrueを返します。
RSFFでいうなら、式1が入力S、式2が入力Rと考えながら見ると入力が(1, 0)
Rubyだとnilとfalse以外は全てtrueなのでこれはマズイですね。
入力が(true, *)の時に出力はtrueとなり範囲式としてはtrueを維持するようになります。
次からは式2を使い値を評価した結果、入力が(*, true)ならリセットが立ち上がり、
その場では範囲式の出力としてtrueを返した後に、範囲式の出力をfalseとして保持する
と言った具合です。

まとめ

(a) 式1 .. 式2
(b) 式1 ... 式2

今回の話は結局RSFFで禁止されていた(1, 1)入力、つまり(true, true)に対する出力とその時保持する値をどう定義したか?
っていうのに繋がる話なんですよね。

  • (a)式の場合 trueを返しfasleを保持している だから次に評価されるのはセットである式1
  • (b)式の場合 trueを返しtrueを保持している だから次に評価されるのはリセットである式2

以上のように定義されているのがrubyのフリップフロップというわけです。

ここまで読んでいただけたら、フリップフロップからRubyを連想できるようになり、かつ「式」という漢字がゲシュタルト崩壊を起こしていることでしょう。

BoxのAPIを使って見よう。(その1) ~概要とAPIのことについて

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Box API を使う上でのポイント4つ

  1. RESTful API
  2. JSON
  3. OAuth2.0
  4. Box Developer アカウント

1.RESTful API とは

ウェブシステムのHTTPでの呼び出しインターフェース
GET、POST、PUT、DELETE等のHTTP標準のメソッドを使い、「何を」「どうする」というようにシンプルな表現されのが特徴です。

a.URL

https://api.box.com/2.0/files/123456789
  files の中の ID:123456789 のファイルを取得
https://api.box.com/2.0/files/123456789/versions
  files の中の ID:123456789 のファイルのバージョンを取得

b.HTTPメソッド(他にもありますが、今回は以下の4つ)

GET
  リソースの獲得
POST
  リソースの作成
PUT
  リソースの更新(状態変更)
DELETE
  リソースの削除

c.curl(データを転送するライブラリ) を使った例

$ curl -X GET https://api.box.com/2.0/files/123456789 

curl については、こちら 見て下さい。

2.JSON とは

JSONとはJavaScript Object Notationの略で、XMLなどと同様のテキストベースのデータフォーマットです。
{} (カッコ)で括られている文字で、整形すると下記のようになります。

  {
      "entries" : [
          {
              "created_at": "2012-08-20T10:20:30-07:00",
              "id": "672259576",
              "modified_at": "2012-11-28T13:14:58-08:00",
              "modified_by": {
                  "id": "183732129",
                  "login": "sean+apitest@box.com",
                  "name": "sean rose",
                  "type": "user"
              },
              "name": "Dragons.js",
              "sha1": "359c6c1ed98081b9a69eb3513b9deced59c957f9",
              "size": 92556,
              "type": "file_version"
          }
      ],
      "total_count": 1
  }

3.OAuth2.0 とは

a.概要

HTTP上で認可を行うためのプロトコル
通常、ログインが必要なサービスを利用する際はログインID/パスワードの情報が必要になります。
下図のようなサイトの場合、あまり問題にはなりませんが、

enter image description here

下図のようにウェブサーバ経由で、BOXへの操作を行う際、
ウェブサーバにBOXのID/パスワードを格納してしまうのは、セキュアな状態とは言えません。
それを解決するための仕組みとして使われるのが OAuth2.0 です。

enter image description here

b.一般的なフロー

利用者によって、BOXのログイン認証を行い、そこで得られるアクセストークンを使用して、
BOX のAPIを使って、各種操作を実行することで、ウェブサーバにID/パスワードを格納する必要がないのです。

enter image description here

4.Box Developer アカウント

Boxの開発を行う上で、デベロッパーサイトよりアカウントを作成して、アプリケーションを作成するため初期設定を行いましょう。

(1)Box Developers サイトより、アカウントを作成して下さい。

enter image description here

(2)マイアプリより、アプリの新規作成を選択

enter image description here

(3)アプリの種類を選択(ここでは、企業統合を選択しておきます)

enter image description here

(4)認証方法を選択(ここでは、標準OAuth2.0(ユーザー認証)を選択しておきます)

enter image description here

(5)アプリの名前をつけて、完了(あとで変更も可能です)

enter image description here

アクセストークン取得に必要な情報

構成情報から、クライアントID、クライアント秘密コード、リダイレクトURLをコピーして下さい。

enter image description here

BOX API reference

BOXでは、下図のようなリファレンスサイトが用意されています。

enter image description here

まとめ

次回は、BOXのAPIを使って、実際に簡単な情報取得処理を作成していきます。

キーフレームアニメーションに触れて

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

はじめに

初めてまして、新卒で2DCGのモーションを勉強中の初心者です。
現在使用しているSpriteStudioを使い、自分が分からなかった点、興味深かったことなど復習も兼ねてまとめていきます。

キーフレームアニメーションについて

一般的な手描きアニメーションとは異なり
手足や顔、胴体など各パーツごとにキャラクターを制作しボーンとして繋ぎ合わせ動かしていきます。
味のあるイラストが感情を持って動くと見栄えが豪華にみえ、
可愛らしい動きから、凝ったエフェクト効果など様々な表現ができます。

キャラクターを動かす点で意識すること

しかしいざ動かしてみると、イメージしていても流れるような動作がでず
ペラペラした動きになってしまったため先輩からアドバイスをいただきました。
【キャラの溜め】
人の動きを表現するにあたって重要になってくるのが「重力」
次のアクションへの溜めが必要になってきます。

例えば、ジャンプをさせる場合、
アクションゲームには欠かせない動きの一つです。

構えから、しゃがみ込み、足に力を入れ、地を蹴る

その際、キャラクターの足にも気を付ける必要があります。地から離れる動作は着地場所に
もっていく工程も作っていきます。

空中で飛んでいる瞬間、地に足がつく、足元へ体重がかかる

ジャンプという動作から流れをイメージし、コマ割りのように分けていきます。

まとめ

実際に自身で動いたり、動画などを見ながら細かな流れを観察していくことが重要でした。
自分自身未熟なのでこれからも精進していきます。

参考URL:http://photoshopvip.net/75555

文章で感情を表現する

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

株式会社アピリッツにてゲームシナリオを書いている者です。
エンジニアの方々が技術的な記事を書いている中で恐縮ですが、私はシナリオ関連の話をさせていただきます。
今回のお題は、とても初歩的な感情の表現方法です。
少しゲームシナリオ寄りのお話になります。

はじめに

皆さんは普段、何気なく「楽しいな」、「悲しい……」などと感じていると思います。
(ここで「そんなの感じたことないよ……」と思った場合はブラウザを閉じて回れ右しましょう。)
皆さんがそういった気持ちを感じるということは、物語の中で生きているキャラクターにもその感情がある、ということですね。
ですが、自分の感情をわざわざ声に出して言うものでしょうか?
パッと思いつく個人的な例になりますが、自覚した瞬間に声に出してしまうのは「痛い!」「かゆい!」くらい。
たまに「嬉しい~!」と言うこともありますが、これは相手に「いま嬉しいと思ってるぞ」ということを伝えるために”わざと”言っているので、もしかしたら本心ではあまり嬉しいと思っていないかもしれません。
少なくとも、「悲しい……」「いま怒ってます」等を口に出すことは滅多にないかと。
人間同士の対面会話であれば、表情や声のトーンでその時々の気持ちを判断することもできますが……
感情を文字のみで表すとき、どのようにすればいいのでしょうか?

行動や仕草・状況を書く

人間が何かを感じたときの行動・仕草は、ほぼ普遍的です。
よく言われているのは、「嘘をついている時に目が泳ぐ」や、「何かを考えている時に視線が上を向く」などですね。
目の動きを文章化するだけでも、感情を表せるのです。
人間の体の部位はたくさんありますから、これらを活用した特徴的な仕草を地の文に入れるだけで、そのキャラクターが今何を思っているのか、スマートに表現できます。

……といっても、過剰に地の文だらけのお話というのは、よほど文章が上手でない限り、冗長になってしまい面白みに欠けてしまいます。
ノベル形式のゲームシナリオの場合は尚更ですね。
むしろゲームのシナリオでは、地の文がなく会話文だけで進行するものも多いですが……
二つが混合している形式の場合、大切なのは地の文と会話文のバランスです。
両者のバランスをよく考えて、気持ちよく読める文章になるように私も日々勉強しています。
地の文をどのようにするかで物語全体の雰囲気も左右されるので、作品に合った文体になるよう心がけるのも重要です。

「怒り」の感情を例にして、文章を書いてみます。

~例~
「もういいよ……」
少年は、眉間に皺を寄せたまま俯いた。
渾身の励ましが逆効果となっていたことに狼狽える。
その反応が、更に少年の機嫌を損ねてしまったらしい。
恐る恐る肩に伸ばした手は、無慈悲にもぴしゃりと跳ね除けられた。

突貫工事の拙い文章ではありますが、少年が静かに怒っていること、もう相手と会話をしたくないと拒絶している様子を表しています。
更に、『相手に自分の気持ちを察してほしかった。けれど相手は鈍感なので狼狽しているだけであり、それに呆れてしまった』というニュアンスもなんとなく含んでいます。
控えめな子供は感情を口に出せない傾向があるので、仕草の描写で表現します。

快活で幼いキャラクターであれば、あえて感情を言葉にさせることで、幼さ・未熟さを表現できます。

~例~
「もぉ~、怒ったー!ぜったいぜーったい、許さないから!」

幼女キャラクターにありがちですね。

怒りにも様々な種類がありますから、キャラクターによって「怒鳴る」「黙る」「暴れる」など、たくさんの怒りを使い分けられます。

ゲームならではの表現方法

少しお題から逸れてしまいますが……
先ほど「ゲームでは地の文なしで会話文だけで進行するものが多い」と述べました。
通常の小説であれば、会話文だけで進行する文章は、よほど魅力的な見せ方をしていない限り、あまり推奨されません。
ですが、ゲームでは演出次第で地の文がなくとも何の違和感もなく進行させることが出来るのです。
例えば、「立ち絵」です。
キャラクターが口角を上げて目を細めている立ち絵を表示するだけで、わざわざ文字にしなくても「笑っている」ということを表現できてしまうのです。
普遍的な感情を表す表情イラストを予め数パターン用意しておけば、その分の感情表現は文字にする必要がなくなります。
地の文有りの作品の場合でも、会話の応酬のシーンではテンポを崩さないためにあえて地の文を削り、立ち絵で細かな表情の変化を見せることができます。
これは、立ち絵を使用できるゲームシナリオならではの表現方法です。

例えば、「そうなんだ」という台詞の場合
enter image description here enter image description here
この二つの表情では、「そうなんだ」というセリフに含まれる意味が全く異なってきますね。
左の表情では同意やこちらの話への興味が見て取れますが、
右の表情では疑念、または話にそれほど興味がない……といった様子になる、といった感じです。
これを応用することで、例えば”口では納得しているけれど、本心はあまり乗り気ではないので表情が暗い”などの描写を簡単に示すことができます。
ゲームならではの表現方法に、もう一つ「選択肢」がありますが、これ以上脱線するわけにもいかないので、またの機会にお話ししたいと思います。

キャラクターごとの感情

感情というのは十人十色なので、そのキャラクターの個性によって抱く感情は変わります。
ですが、物語を書いている私は一人しかいないので、私が表現し得る感情には限界がありますね。
では、どうやってその様々なキャラクターの感情を表現すればいいのでしょうか?

自分自身とは全く違う常識や価値観、信念を持つキャラクターを表現する時に、経験、知識、想像力が生きてくるのだと思っています。
ここでいう経験とは、今までの人生の中で出会ってきたバリエーション豊かな人々のこと。
よく「人間観察」などと言いますが、まさしくそれですね。
自分の身の回りにいる人々が、意外なことに創作のヒントになったりすることがあります。

次に、知識とは、数多ある作品に触れて新たに出会ったキャラクターや世界などのことです。
幼いころから自由帳に自分の世界を書きなぐっていた人などであれば分かるかと思いますが、幼稚園生~小学生の頃に考えたキャラクターなどは、経験も知識もないまま作ったキャラクターなので、悪く言ってしまえばお粗末なものですね。
小学校高学年~中学生あたりになると、自由帳の中のキャラクターに悪魔の角やら天使の羽やらが生えてくる頃合いかと思います。色々な作品を見て、知識を得たからこそ生み出せたキャラクターですね。

そして、想像力とは、いかにして「自分ではない誰か」を想像し、その者の心を想像することが出来るのか・自分が経験したことのない空想の世界をどこまで広げられるのか、という力です。
例えば、善良な一般人A(……?)である私は、猟奇的なキャラクターを物語に出す時、どのような人物にさせるか非常に迷います。
このキャラクターにとって何が快楽であり、何が嫌悪の対象なのか……普段はどういった生活をしているのか、などをイメージします。
更に、とある一つの事象を前にした時、そのキャラクターはいったいどのような反応をするのか……とにかく、とことん考えます。
考えても考えても分からない場合がほとんどなので、ここでテンプレート化された「猟奇的なヤツ」を参考にします。
色々な作品に、たくさんいますよね。
その後、自己流のアレンジを加えて、個性あふれるキャラクターになればそれで良いのです。
そういった意味では、想像力は、経験と知識を積み重ねた先にあるのかもしれません。

終わりに

私自身はキャラクターに感情移入をして書くタイプなので、想像力がとても重要です。
文章を書く人の中にも色々なタイプの人がいると思いますので、より良く表現できる方法を模索していきましょう。

オススメの書籍

感情類語辞典
アンジェラ・アッカーマン、ベッカ・パグリッシ 著 / 滝本杏奈 訳
発売日:2015年12月25日
http://filmart.co.jp/books/playbook_tech/emotion-thesaurus/

この記事を最後まで読んでいる人の中には既にご存知の方もいらっしゃるでしょうが、シナリオを書く際に非常に役立つ一冊です。
感情に付随する仕草や感覚、サインなどが多く掲載されています。
「○○の感情を表したいけど、いつも同じような表現になってしまう……」という悩みがある方は、是非どうぞ。

小さなテクスチャ領域でも見た目に説得力を与える!UV展開のポイント

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

はじめに

2017年新卒で3Dのデザイナーをやっています、SYです。
アピリッツでは入社する前から内定者インターンとして実際に業務を経験できる環境が設けられています。私は昨年の9月中旬からインターンとしてチームに配属され、3DCGを扱うチームの一員として様々な事を先輩社員の方々から教えていただきました。
今回はそのインターンを通して教わってきた事の中でもUV展開のお話をしたいと思います。

UV展開とは

簡単にUV展開とは何ぞやという説明をさせていただきます。

立体的なモデルに模様などのテクスチャを表示させるにはまずUV展開という作業を行い3Dを2Dへと展開していきます。
これで立体に対して、展開された平面が張り付けられている状態になりました。
あとはフォトショップなどのペイントソフトなどを用いテクスチャを書き込んでいき、画像を参照することで2Dで描いた具体的な模様などが立体上に乗るという仕組みです。

enter image description here
私は画像にある網目状のテクスチャを張り付けた状態でUVに歪みがないかなど確認をしながら作業を行っています。こうすることで2Dで描いた模様を3Dに張り付けた際も歪まないようになります。

細い線を入れる部分はUVをなるべく直線に

私がインターンを始めてから一番最初に作ったモデルのUV展開を行った際指摘を頂いたポイントです。
なぜ、ローポリモデリングにおいてUVはなるべく直線を心がけるべきなのでしょうか。
理由の一つは、
無駄なくスッキリとUVの配置がしやすいというメリットがあるからです。

しかしもう一つ、
テクスチャに書き込んだ直線が綺麗に表現できるという利点があります。

テクスチャに描いた直線が、モデルに貼り付けた際にしっかりと直線として表現されてほしい理由としては

・形状の縁に沿って入る細いハイライト
enter image description here

・パーツが重なった部分や溝などに必然的に入る一段暗い影
enter image description here
などを綺麗に見せたいからです。

なるべくデータを軽く押さえてゲームを作る時、ポリゴン数だけでなく、一つのモデルに使われるテクスチャサイズもそこまで大きいものではありません。現在私がプロジェクトで制作しているモデルも顔以外のパーツを一枚のUVに収め512px × 512pxの大きさで作っています。同じ太さの直線を一本書くにしても真っ直ぐか斜めに書くかでは大きく見た目が変わってきます。
実際にハイライトが入る部分のUVを直線にしてテクスチャを描いた際と直線にはせず展開ツールを使っただけの状態で描いた物の仕上がりを見てください。

enter image description here

enter image description here
いかがでしょうか。
こうして比較してみると、ハイライト部分を斜めに展開してしまった方はテクスチャのドットが目立ってしまい汚いハイライトになってしまいました。
一方、直線を心がけて展開した方はギザギザしていない綺麗なハイライトを表現する事ができました。

恥ずかしながらインターンに参加したばかりの自分は知りもしなかったポイントでした。

少ないテクスチャ領域でも展開時のひと工夫でこれだけ見た目に差が出てきます。
特にツルツルとした質感のものに入るハイライトや影がざらざらとしてしまっていては説得力に欠けてしまいますね。

(※ただ今回は単色の扇子でしたが、複雑な模様やロゴが描かれている場合、UVは少なからず歪んでおり元の模様をそのまま乗せてしまうと変形してしまいます。ロゴなんかは変形してしまうとマズいですよね。そんな時はテクスチャ上で変形させるなどして調整する必要が出てくると思います。)

終わりに

今回は少ないテクスチャ領域でも意識することで見た目に説得力を持たせられるポイントを紹介しました。
今後もこのように備忘録も兼ねた気づきや学んだことを書いて、これから3DCGに挑戦してみたい!という方のお役に立てれば幸いです。

Linuxでファイルやプログラムコードを検索する ~findコマンド~

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

こんにちは、新卒のプログラマーです。

初歩的な話ではありますが、findコマンドを利用することで簡単にファイルやディレクトリ、ソースコードを検索出来るようになったので備忘録も兼ねて共有したいと思います。

findコマンド

findコマンドは、findは、ファイルやディレクトリを検索するコマンドです。

ファイル名だけでなく、ファイルサイズやタイムスタンプなどでも検索をすることが可能です。

findの記法は、以下のようになっています。

find [検索開始ディレクトリ] [オプション] [検索したいファイル名]

オプションや開始ディレクトリを省略すると、カレントディレクトリを検索します。

$ find sample1.rb  
  find: 'sample1.rb' そのようなファイルやディレクトリはありません
$ find hogehoge/sample1.rb
  hogehoge/sample1.rb 

オプションの利用

findコマンドには、多くのオプションがありますが、自分はよくnameオプションを利用しています。

ワイルドカードを利用できるので、ファイル名が正確に分かっていなくても検索をすることが可能です。

$ find ./hogehoge/ -name "*"  
  ./hogehoge/
  ./hogehoge/sample2.rb
  ./hogehoge/sample3.rb
  ./hogehoge/sample1.rb  

また、typeオプションを利用することで、検索対象をファイルかディレクトリか指定することが出来ます。

find -type f: ファイルを検索

find -type d: ディレクトリを検索

$ find ./hogehoge/ -name "*" -type f 
  ./hogehoge/sample2.rb
  ./hogehoge/sample3.rb
  ./hogehoge/sample1.rb
$ find ./hogehoge/ -name "*" -type d
  ./hogehoge/

その他にも多くのオプションがあるので、findのマニュアルをご覧ください。

xargs,grepコマンドとの組み合わせ

findコマンドは他のコマンドと組み合わせることで、より便利に扱うことが出来ます。

自分はプログラムコードを検索する時などに、よくxargsとgrepコマンドを組み合わせて利用しています。

xargsコマンドは、ファイル名の一覧を標準入力として受け取って任意のコマンドに引数として渡すコマンドです。

また、grepコマンドは、ファイル名を与えることでファイル内を指定文字列で検索するコマンドです。

そのため、findで得られたファイル名のリストをgrepに渡すようにコマンドを書いてあげると、ファイル内の記述も簡単に検索することが出来るようになります。

$ find ./hogehoge/ -name "*" -type f | xargs grep "Hello"
 ./hogehoge/sample1.rb:print "Hello, World!\n"

終わりに

初歩的な話ではありますが、findコマンドについて普段自分が利用している方法をまとめました。  

まだまだ有効活用できていないコマンドやオプションも多いので、日々精進していきたいと思います。

初心者がRailsのマイグレーション作成でやりがちな3つの失敗

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

マイグレーション作成時にやりがちな失敗について

最近、自室用にHHKB pro2をまた買ったよ。オフィスで使ってるTypeSとは違いノーマルの方だけど。TypeSに比べると少し音が煩い代わりに打鍵感はほぼ同じでとても良い。新卒のみんなも初任給で10個くらい買おう。

はい、というわけで今日は マイグレーション作成時にやりがちな失敗 についての話。

RDBMSの予約語をカラム名にしてしまう

気づきにくい、発覚しにくい、忘れやすい。三拍子揃ったうっかりポイント。
DBにはシステム上で識別子として使われるいくつかの単語がある。これらは予約語とされており原則としてカラム名やテーブル名として使うのを避ける必要があるが、案外うっかりカラム名として使ってしまうことがある。

そんな単語は使わないって? ところが予約語はDBの種類によって差がある上にその数も多い。例えばMySQLなら予約語は 231個 ある。23個じゃないよ。(mysql 5.6)

しかも結構使いたくなってしまうような語が多い。 interval、option、key、usage、release、condition ……全部ダメだ。(意外なことにcountは予約語ではない)

それならマイグレーション生成する時に警告でも出してくれればいいが残念ながらそんなものは出ない。ご不満なら自分でissueでもプルリクでも立てよう、今日から君もOSSコミッターだ。

で、結局これをやってしまうと何が起こるんだ? 答えは何も起こらない。 少なくとも普通にRailsアプリケーションで使っていく上ではまず問題にならない。が、例えばMySQLコンソールでこんなSQLを書けばエラーが返る。

mysql> SELECT key FROM nekos;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'key from nekos' at line 1

なんで? Railsでは動くよ?
その理由はActiveRecordが発行してくれるSQLは全部テーブル名まで指定した上で引用府で囲まれるため。こうしてやることで予約語であってもSQLは無事に通る。

SELECT `nekos`.`key` FROM `nekos`;

Railsで無事に使えるならいいじゃん? 良くないよ! ActiveRecordだけがそのデータベースを使うとは限らないし単純にDB設計として推奨されない。一度作成して使い始めてしまったカラム名を後から変更するのは非常に困難だ。作成時に避けよう。

デフォルト値や制約を設定しない

さて、nekosテーブルのbrushing_flagというブーリアン型(true/false)のカラムについて考えてみよう。

SELECT COUNT(*) FROM nekos;
=> 3

SELECT COUNT(*) FROM nekos WHERE brushing_flag = true;
=> 1

SELECT COUNT(*) FROM nekos WHERE brushing_flag != true;
=> ?

?の部分はどうなるかな。正解は、 わからない。
いや、ふざけている訳ではなくて「わからない」というのが正解だ。
何故ならSQLのWHEREではbrushing_flagにnullが入っている場合、trueともfalseともしない。それどころか brushing_flag != trueという条件にも引っかからないからだ。論理的に考えるとなるほど正しい。

だからbrushing_flagがnilであるレコードの数に応じて結果は0から2まで不定だ。nullの値を条件の対象に出来るのは IS NULLの構文だけであり、ガス室に入った猫ちゃんよろしく 「trueであるともfalseであるとも言えない」 のだ。

このため、既に稼働しているアプリでブーリアン型のカラムを追加してrailsのコードを書いていると面食らうことがある。rubyの感覚ではnilであればfalseだからだ。しかし、Neko.not.where(brushing_flag: true)と書いても期待している結果にはならない。直感的じゃないなぁ…。

期待する挙動を得るためにはNeko.where(brushing_flag: [false, nil])と書く必要がある。しかし、これはあんまりイケてない。 そもそもnilをfalse扱いにしたいならカラムの初期値をfalseにすべきだからだ。

初期値が設定できない理由やnullを許可する明確な理由がなければ可能な限り入れて行きたい。特にブーリアン型は必須と言えるかも知れない。新しいカラムを追加したりテーブル構成を弄る時には既存データとの整合性を慎重に考慮する必要があるが、それも初期値設定を活用したい。

これをモデルのvalidateではなくマイグレーションで行う意味は、前述したようにDBをRailsアプリだけが使うとは限らないからだ。仮に別のRailsアプリが使ったとしてもモデルが一致するとは限らない。DBレベルで避けるのが安全だ。

さもなければ思いがけないところで条件漏れが起きたり突然 undifined method error for nil:NilClass と怒られてしまう。

既存マイグレーションを書き換える

やるべきではない。既に保守フェイズに入っているアプリでこれをやるのは考えただけでもクラっとする。

ただ例外として初期の開発フェイズにおいては話が変わる。データベースの仕様変更が頻繁でマイグレーションで愚直に管理して行くことが却って混乱を招くため、単一の初期マイグレーションファイルとしてまとめて、変更が生じる度に書き換えてDBをリセットしていくやり方もある。

整合性を保持しなければいけないデータもまだないのでこれで良い。万事、状況に応じてベストプラクティスは変わる。

その他

他にもいくつか思うことがあるが、それらについては賛否両論あるため省略する。例えばserialize/storeの是非やインデックスの付与タイミングなど。

railsのマイグレーションに限らずSQLのDB設計アンチパターン(不適切なやり方)については 『SQLアンチパターン』 などの書籍で詳しく扱っているので未読なら読むと良いです。この本に書かれている内容に比べるとこの記事の話は局所的で瑣末なこと。

最後に強調しておきたいのが 「アンチパターンの回避や正規化は未然・早めに行うこと」 。既に数十万件以上のものレコードが積み上がって複雑に関係しあった状況からシステムを止めずに正規化したり改修するコストは半端じゃない。わずかな手間を嫌がると驚きの複利で返済不可能な負債が積み上がる。

他の初心者向け記事

エンジニア見習いが最初に覚えるべき4つの習慣

キーボードだけで生きて行く

UnityでゲームのUI作りたい! 〜 物並べ編①

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

17新卒エンジニアがUnity関係で学んだことの備忘録を書きます。

はじめに

お初にお目にかかります、17新卒エンジニアの HN:inoooooocchi と申します。
私は4月からエンジニアとして入社し、とあるゲームプロジェクトに配属され、サーバー側(Ruby及びRuby on Rails)とクライアント側(Unity(使用言語はC#))の両方の実装を担当させて頂いております。

ところが私は、RubyもC#もUnityも、入社するまで(正確には3月にインターンシップで配属されるまで)一切触ったことがありませんでした。
そんな中、ここ2、3ヶ月で様々なことを学び、そろそろ整理しておきたいな、と思った矢先にDorubyに記事を書くことになりました。
従って私の記事では、私が仕事をしていて最も楽しい瞬間である「UnityでのUI制作」について、今まで学んだことの備忘録としての意味合いを兼ねてご紹介させて頂きます。

ご注意

本記事では、前章で述べた通りのUnity初心者中の初心者が試行錯誤して覚えた内容を載せています。
従って、凄腕Unityユーザーの方々の中には、「もっと効率的な方法があるのに…」「本当にユーザーの事考えてる?」「え?入社してから今まで何やってたの?w」と思われる方がいらっしゃるかもしれません。
優しい目で見守って頂けると幸いです。

前書き

  • Unityって?
    それでは、早速本題に入っていきましょう。…と言いたいところですが、「そもそもUnityってよく聞くけど、どういうもんなの?」という方がいらっしゃるかもしれません。(私も1年ぐらい前までそうでした。)
    なので、かるーく説明したいと思います。
    Unityとは、ユニティ・テクノロジーズという会社が開発した、ゲームエンジン及びゲーム開発用プラットフォームのことです。
    とっても簡単に言えば、ゲームを作るための基盤を提供してくれる便利なツールってことです。
    GUI(マウスなどを用いて操作可能な直感的インターフェース)によって、ゲームを構成するオブジェクトの配置やオブジェクトを動かすためのスクリプトの設定が可能で、なんならプログラミングが一切出来なくてもゲームが作れてしまうという話もあります。
    (もちろん、自作のスクリプトを用いることでさらにゲームの幅が広がります)
    PC(Windows / Mac / Linux)、スマートフォン(iOS / Android)、さらにはPS4などのゲーム機、(Unityのプラグインを搭載した)Webブラウザなど、様々なプラットフォームに対応しているのも大きな魅力です。
  • UIについて
    ゲームを遊ぶためには、ユーザー(プレイヤー)が操作をする必要があります。
    もちろん、ユーザーがゲームを遊びやすくするために、開発側はなるべく見やすく・分かりやすく・操作しやすいようなUIを用意してあげなくてはなりません。
    例えば、1つのゲーム画面に全部で50個のボタンを配置する必要がある場合、「うまく入りきらないからめちゃくちゃ重なってるけど、頑張ってタップしてくれよな!」なんてUIは、「本当に遊んでもらう気があるのか?」と疑いたくなります。
    そこで、今回の記事では、そのようなふざけた画面を作らないために、「たくさんのオブジェクトを並べる」UIの作り方を書いていきます。

1. SceneとCanvasの作成

まず最初に、Unityでオブジェクトを配置するためには、SceneとCanvasが必要になります。

用語解説

Scene: 「.unity」という拡張子のファイルで、これが1つの画面に相当します。
     たくさんのScene(画面)遷移を繰り返し、ゲームが進行していきます。
     (例:タイトル→メニュー→ステージ選択→ステージ→リザルト→ステージ選択…)

Canvas: Scene上にUIオブジェクトを配置するための、地盤となるオブジェクト。

まずはSceneを作ります。Unityを開いたら、File -> New Sceneで、Untitledという無名のSceneが作られます。
New Sceneでシーン作成
作ったばかりの新しいSceneには、Main Cameraというカメラオブジェクトのみ存在します。

次に、Canvasを作ります。Hierarchyの上で右クリックし、UI -> Canvasを選択します。
Canvasを作成

すると、Canvas(とEventSystem)が生成されます。EventSystemはUIの動作を管理する偉いオブジェクトで、これが無いとクリックや文字入力、タップ操作などが反応しなくなってしまいます。消さないようにしましょう。

さて、このCanvasには、いろいろな仕組みが備わっています。Inspectorウィンドウで、選択したオブジェクトの情報を確認することができます。

Inspectorウィンドウでオブジェクトの詳細情報を確認

最初の設定として、カメラから見える位置にCanvas及びCanvas上のオブジェクトが来るようにします。

Canvas という機能のRender Modeという設定を選択し、デフォルトの「Screen Space – Overlay」から「Screen Space -Camera」にします。

Render Modeを変更
すると、カメラを指定する部分(Render Camera)が現れます。

Render CameraがNoneのままでは意味がないので、Sceneにもともと存在していたMainCameraをアタッチします。
アタッチとは、スクリプトやオブジェクトを別のスクリプトやオブジェクトの構成要素に追加し、アタッチされた側から干渉できるようにするための行為です。
今回の場合、MainCameraをCanvasにアタッチすることで、CanvasはMainCameraを認識し、使うことが出来ます。
ドラッグ&ドロップで、HierarchyウィンドウにあるMainCameraを、InspectorウィンドウにあるRender CameraのNoneの部分に持って行きます。

すると、無事カメラの設定が出来ました。
これで、Sceneの作成とCanvasの作成は完了です。ようやくUIを作っていけます。

2. オブジェクトを並べる領域を作る

それでは、オブジェクトを並べる領域をUnity上で作成します。

早速、先ほど作成したSceneのCanvasに、「オブジェクトを並べる領域」のオブジェクトを作ります。
Canvasの上で右クリックし、Create Emptyを選択します。

Create Emptyで空のオブジェクトを作成
すると、Canvasの下に、GameObject(デフォルト名)が子オブジェクトとして生成されます。
今回は、オブジェクトを並べる領域ということで、ObjectAreaなどの名前にしようと思いましたが、後々スクロール機能を追加したいので、InspectorウィンドウでScrollAreaという名前に変更します。
ScrollAreaがCanvasの子オブジェクトとして存在
生成されたGameObjectはデフォルトでは100×100pixelの小さな正方形なので、好きな大きさに変更します。サイズや位置の調整もInspectorウィンドウで行うことが出来ます。(マウスで掴んでびよーんと伸ばしたりも出来ますが、きっちりした値にするならInspectorがいいでしょう)
ScrollAreaのサイズを変更
今回は300×300の正方形にし、位置を左にずらしてみました。(x座標:0 → -160)
ここで、Inspectorの座標値の左側に、四角形の記号のようなものが見えると思います。
これは、Anchor(アンカー)といい、親オブジェクト(Canvas)に対して子オブジェクト(ScrollArea)の基準点がどこなのかを表しています。
現在は中央に設定されているため、ScrollAreaに取っての基準点(0 , 0)が、Canvasの中央座標になっていました。それを左にずらしたので、x座標が-160という値になったわけです。
本来ならプラットフォームごとの画面サイズの差を考え、このAnchorを調整しx,y座標が基準点から大きくずれないようにするべきですが、今回は省きます。
このAnchorはUIのレイアウトを決める上で非常に大事なものなので、詳細は別の記事を設けて書きたいと思います。

さて、これから、この300×300の領域にオブジェクトを並べていきます。

3. ScrollAreaの中身を作る

並べる領域が出来たので、今度はその中身を作ります。
今回は例として、何らかのステージを選択する画面を想定し、各ステージの名前が書いてあるボタンを作ります。
ボタンを作成するには、ScrollAreaの上で右クリックし、UI -> Buttonを選びます。
Button作成

SceneウィンドウでButtonが確認出来た

はい、ボタンが出来ました。Buttonって書いてありますし誰がどう見てもボタンですね。
本来なら、このボタンをクリックした時に別のSceneに遷移するなどのスクリプトを書いてアタッチするのですが、今回は省略します。
ちなみに生成直後のButtonには「Image」「Button」の二つの機能が最初から搭載されています。画像を変えたい時はImageのSourceImageに画像をアタッチすれば変更できます。(今回は省きます)

名前が「Button」じゃ寂しいので、適当に「StageButton」にしておきます。
同様に、ボタンに書かれている文章も「Button」じゃ何のボタンかさっぱりわからないので、適当にステージ名を入れてみます。

HierarchyのStageButtonの横に、▶︎があるのが確認できますよね。ここをクリックすると、Buttonの子オブジェクトを確認できます。

▶︎ をクリックして子オブジェクトを確認
UI -> Buttonオブジェクトは生成されると同時にTextという子オブジェクトを持っています。このTextにInspectorウィンドウで文章を入れてあげれば、お好みの文字列をボタンに表示できます。
また、領域の横幅が300pixelなので、違和感がないようにボタンの横幅も280pixel程度にしておきます。
ボタンのサイズを調整

これで、押してもうんともすんとも言わないボタンが出来ました。
今回の趣旨はボタンを押すことでは無く、ボタンを並べ(て、スクロールさせ)ることなので、並べるためにボタンを大量生産しましょう。

StageButtonの上で右クリックし、Duplicate(複製する)を選ぶと、ボタンが複製されます。
もちろん、CopyしてPasteしても問題ありません。何度もやるのが面倒な人はCtrl + C -> Ctrl + Vしまくるといいでしょう。

StageButtonを複製
10個まで増やしてみた

というわけで、StageButtonを9個増やして合計10個にしてみました。

10個あるはずなのに1個しか表示されない

…が、何故か表示されているボタンは1個だけです。何故でしょう?
答えは簡単、「元のStageButtonの座標まで丸ごとコピーしてるから」ですね。つまり、1個にしか見えないStageButtonには10個のStageButtonが重なってしまっています。

「え、じゃあオブジェクトを複製するたびに手入力で座標をずらしていかなきゃいけないの!?」

もちろん、Unityには便利な機能があるのです。先輩に教えて頂いて、Unityの力ってスゲー!ってなりました。次の章でご紹介します。

4. Vertical Layout Groupを使ってみよう

その便利な機能とは、「Vertical Layout Group」という機能です。
どんな機能か説明する前に、まずは試しに使ってみましょう。
…と、その前に、機能の効果を体感しやすくするために一度複製したボタンを全て削除してください。
複数選択して右クリックでDeleteすれば一発です。

さて、StageButtonの親オブジェクトであるScrollAreaオブジェクトのInspectorをご覧ください。
見事に何もないですね。そりゃそうです、Create Emptyで空のオブジェクトを作りましたから。
オブジェクトに新たな機能を追加する場合、Add Componentをクリックします。Add Componentでは、Unityに標準で備わっている機能や、自作したスクリプトなど、様々な構成要素(Component)を追加できます。

Add Componentで機能を追加
早速、Vertical Layout Groupを追加してみましょう。
Vertical Layout Groupを追加

何故か大きくなりました。

これはVertical Layout Groupの仕様であり、本記事の目的として不適切な動作なので、元に戻しましょう。
InspectorのVertical Layout Groupで、Child Force ExpandのWidth、Heightのチェックを外しましょう。

Child Force Expandのチェックを外した結果

何故か小さくなりました。(左上)

焦らないでください、これもそういう仕様なのです。
Vertical Layout Groupは、子オブジェクトのサイズを自動で調整してしまうのです。
もともとのサイズを維持したい場合、子オブジェクトに手を加える必要があります。

Layout Elementを選択
子オブジェクトのStageButtonのInspectorでAddComponentをクリックし、今度は「Layout Element」を選択します。
すると、このようなものが追加されます。
Layout Element設定
詳細はここでは省きますが、ひとまず「Preferred Width」「Preferred Height」にチェックを入れ、現れたテキストボックスに、維持したい縦幅・横幅を入力します。
280 x 30を記入

すると…

サイズが元通り

あれほど縮こまっていたStageButtonが、Layout Elementの力により、本来のサイズ(=先ほど設定したサイズ)を取り戻しました。
Layout Elementは、Vertical Layout Groupや、後述するHorizontal Layout Groupなど、
「子オブジェクトのサイズを自動で調整してしまう機能」に対し、「このサイズにしろ!」と強制できる機能なのです。

ちなみに、StageButtonが左上に寄ってしまっているのは、ScrollAreaのVertical Layout GroupのChild AlignmentをUpper Centerにすれば中央に戻せます。

Upper LeftからUpper Centerに

さらに、ScrollAreaに、「Content Size Fitter」という機能を追加します。

その後、Vertical Fitの部分をPreferred Sizeに設定してください。

Content Size Fitter導入

Content Size Fitterは、そのオブジェクトのサイズを、全ての子オブジェクトのサイズに合わせて自動で変化させてくれる機能です。これが無いと、子オブジェクトを複製しすぎた場合、ぎゅうぎゅう詰めになって子オブジェクトが潰れて表示されてしまいます。

さて、これで準備は整いました。Vertical Layout Groupは、ただ単に「子オブジェクトのサイズを勝手に変えてめちゃくちゃにする機能」ではなく、ここから彼(?)の本領が発揮されます。
先ほどと同じように、StageButtonを10個ほど複製してみてください。

StageButtonが並ぶ

Vertical Layout Groupは、子オブジェクトを縦方向に自動で整列させる機能です。
同様に、Horizontal Layout Groupは、子オブジェクトを横方向に自動で整列させてくれます。
このようにして、無事に(?)ボタンを縦にたくさん並べることが出来ました!

ただし、この状態で複製し続けると…
はみ出る

はみ出ます。(※Unity上のGameウィンドウです)
ここで、スクロール機能が必要になってきますね。
しかし、今回の記事がかなり長くなってしまうため、それはまたの機会にご説明いたします。

5. 今後の課題&まとめ

今回は、オブジェクトを並べる際の基礎の基礎をまとめてみました。
今回作った機能を実際のゲームで運用させるためには、まだまだ課題があります。

  • スクロールして、はみ出た部分をクリックできるようにする
  • 「Stage1」の文字列を、Stage2、3、4…のように自動で変えたい(Prefab、スクリプトの使用)
  • StageButtonをクリックした時に、何らかの処理を発生させる(スクリプトの使用)

次回からは、これらの課題を解決していきたいと思います。

このように、私の記事ではUnityによるUI作成をまとめて行きたいと考えていますので、
今回の記事を読んでUnityに興味が沸いた方、分からないことが解決した方(いるかな?)などなど、今後ともよろしくお願いします。

以上、17新卒エンジニアのinoooooocchiでした。

情報共有ならデータポータルがおすすめ!マイレポートと比較してみた

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Googleアナリティクスで定点観測や社内共有をするためのレポート作成はできるだけ時間短縮したい。そんな方におすすめなのが、Googleデータポータルです。今回は、Googleデータポータルとマイレポートとの比較を交えて紹介していきます。

この記事でまとめられていること

こんにちは。株式会社アピリッツでアナリストをしているssekiです。
Googleアナリティクスを使ってアクセス解析レポートの作成をしていると、「いつも同じ作業だから自動化したいなぁ」と思う反面、「APIとかは複雑で敷居が高いなぁ…」と結局断念してしまうことありますよね。

そんなアナリストのためにGoogleアナリティクスにはマイレポートという機能があります。
組織内での情報共有のためにマイレポート機能を常用されている方も多いかもしれませんね。
ただ、マイレポート機能にも難点が多く、自由度の低いレポートになってしまうことがしばしば。

そうした弱点から、私はマイレポート機能をあまり活用していなかったのですが、最近になって、Googleが新しいサービスを提供してくれるようになりました。
そのサービスがGoogleデータポータルです。

今回は、マイレポートより優れている(と私は思っている)ダッシュボードツールのGoogleデータポータルについて、マイレポートとの比較を交えてまとめてみました。

Googleアナリティクスのマイレポートとは

enter image description here
↑※画像はGoogleアナリティクスのデモデータを用いて作成しました。

マイレポートは、Googleアナリティクスの”自分専用”サマリです。
Googleアナリティクス上で見ることのできる表やグラフを1画面にまとめて閲覧できるようにすることがマイレポートの大きな役割といえます。
マイレポートの便利な点をいくつかまとめると、以下のようになります。

  1. Googleアナリティクス上の好きな表・グラフをマイレポートに”直観的に”追加できる
  2. どんなレポートにすればいいかわからなくても、”おすすめを”ギャラリーからインポートできる
  3. 一度マイレポートに保存すれば、期間を変えて再計測が”簡単に”できる

ある程度Googleアナリティクスを使っており、定点観測的なアクセス解析を行っている人にとって、マイレポート機能はとても優れた効果を発揮します。
しかし、冒頭で述べたようにデメリットも多く存在します。特に私が困っていたのは以下の点です。

  1. ウィジェットの大きさやスタイルを変更できない
  2. ウィジェット(表・グラフのこと)が1つのマイレポートに12個までしか配置できない
  3. コメントが追加できない
  4. 他のデータソースをインポートすることができない

総じて、マイレポートのカスタマイズ性が低いことによって、社内共有できるほどのレポートにならないのが難点です。
自分だけでサイトを運営している場合や、アクシデントが生じていないかのアラートとして利用する場合など、誰かと共有する必要が無いときは非常に使いやすいツールですが、企業でサイトを運営していると、レポートの提出や提案資料の作成などを行うことが多くあります。
そうした共有の場面では、マイレポートのレイアウトとデザインはカスタマイズ性が低いため、Googleデータポータルの方がいいんじゃないかなと思います。

Googleデータポータルとは

enter image description here
↑※画像はGoogleデータポータルのサンプルを使用しています。

Googleデータポータルは様々なデータを視覚化し、共有を促進するツールです。
BIツールとも呼ばれていますが、現段階で分析に使えるほどの性能はないため、一度に大勢にが同じ情報を共有できるダッシュボードツールと呼んだ方がしっくりくると個人的には思っています。
ダッシュボードツールという意味ではマイレポートと同じ土俵のツールですね。

元々、Googleデータスタジオ 360として有償版が提供されていましたが、最近になって無償版としてリリースされました。
現在はまだベータ版ですが、共有用として実用に足るレベルの機能を備えています。
少なくとも、私がマイレポ―トに抱いていた欠点を次のように補填することができています。

  1. ウィジェットの大きさ・スタイル・数などのカスタマイズが自由
  2. コメント追加可能
  3. 同じシート内で複数のページを作成可能
  4. 他のデータソース(Adwordsやスプレッドシートなど)も同時に使える

Googleデータポータルを使ってみて、まず最初に感動したのは自由度の高さです。
マイレポートがドキュメントレベルだとすると、Googleデータポータルはほぼパワポレベルです。
つまり、Googleデータポータルを使うことで、これまで一度Googleアナリティクスのデータをダウンロードしてエクセルで作業していた時間を短縮でき、かつパワポレベルの資料が作成できます。

多くの共有資料はパワポやPDFで作成されると思うので、ビジネスユーザーにとってとても利用しやすいツールになっています。

また、標準ではPDF化できないという欠点もありますが、Chromeの拡張機能を用いることでPDFにも対応可能です。

まとめ:Googleデータポータルはどんな人におすすめか

enter image description here

Google アナリティクスのマイレポート機能は、定点観測など決まったデータを取得してアラートのために閲覧したい人向けでした。
それに対し、Googleデータポータルはさらに共有できるレベルまでデータをきれいにまとめたい人向けです。

「これまでマイレポート機能を使わずわざわざエクセルで集計しパワポでレポートを作成していた人」はもちろんのこと、「マイレポート機能を使い慣れていて、共有する必要がある人」にとっても有用なツールといえます。

ちなみに、私はGoogleデータポータルを使って新卒の書いた記事のページビュー数を逐次集計し、新卒内で共有しています。
Googleアナリティクスに詳しくない人とも数値の共有をすることで、より見てもらえる記事の作成につながっていると感じています。
個人的には、こうした非アナリストとの情報共有に重きを置いているのがGoogleデータポータルなのだと思います。

ただし、Googleデータポータルは分析にはあまり向いていません。
なぜなら、Googleデータポータル上で四則演算など計算する機能がついていないためです。

そのため、もしGoogleアナリティクスから次の施策のための本格的な分析をしたかったり、さらに何をすべきかを洗い出したい場合はGoogleデータポータルではなく、TableauなどのBIツールを使うことをおすすめします。

【VBA】エクセルで指定列ごとに改行したデータを作成するマクロ

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

横に長いデータを指定した列数ごとに改行して縦長のデータに整理するマクロを(エクセル初心者に向けて)紹介します。

はじめに

 初めまして、新卒でゲームプランナーをやっている者です。プランナー職ではゲーム内のデータをエクセルで管理・編集するため、エクセルに慣れていないとつまずくことが多々あります。本記事では、エクセルをあまり使ったことがない人に向けて、検索しても出てこなかったエクセルの簡単なマクロを紹介したいと思います。

前置き

 ゲーム内の種々のデータ、例えばキャラやエネミーのパラメータ等の多くは、プランナーがエクセルで管理しています(マスターデータと言います)。スマホ向けゲームでもそのデータ量は膨大で、作業の多くはエクセルの関数などで機械的に行わないと、とてつもない時間が掛かってしまいます。これが、そもそも私がエクセルのマクロを使い始めた理由です。

エクセルのマクロ機能の紹介

 今回は私のような初心者の方を想定して、エクセルのマクロとは何なのか、というところから記しておこうと思います。
 エクセルには様々な機能がまとまっていますが、それらの機能を人が動かすのではなく、プログラムで動かしてやることができます。それがマクロです。正しく使えれば、人間では膨大な時間がかかるような作業を瞬時に行うことが可能です。
 エクセルのタブに開発というタブがあれば、すでにマクロが使える状態になっています。
enter image description here
出てない方は【ファイル】→【オプション】→【セキュリティーセンター】と進み、ここで設定を変更すれば表示されるようになります。
 マクロを組むということは、エクセルにどのような手順で作業をしてほしいかを指定することです。難しく感じるかも知れませんが、エクセルでは人の行動を記録してマクロを作ることも可能です。プログラムなんて書けないっていう方でも、開発からマクロの記録を選択すると、そこからの動作をマクロとして記録してくれます。
enter image description here
これを用いれば、単純な反復作業をボタンぽちっとすればエクセルがやってくれるようになるわけです。
開発タブから【Visual Basic】を押せば、行動記録ではなく、自分でプログラムしてマクロを組むことができる画面になります。ここで紹介するコードは、この画面で作ったものです。

指定列ごとに改行したデータを作成するマクロ

 前置きが長くなりましたが、本題に入ります。私が直面したのは、横長のデータを4列ごとで改行して縦長にして整理したい、という状況です。エクセルには、行から列へ、列から行へ変換する機能は元々備わっていますが、4列ごとに行へ変換することは(おそらく)できません。
 エクセルの関数だけを用いてやろうとすると、今の場合4列ごとと決まっているので、コピーしたいセルの指定をOFFSET関数やMOD関数などを組み合わせてやればできるかもしれませんが、ちょっと難しくて分かりません。
 前述の行動記録マクロを作ろうにも、対象とするセルが毎回変わってしまうので、どうにも上手くいきません。そこで、マクロに挑戦してみました。さっそくコードです。

Sub 複数列コピペ()

Dim ds As Worksheet, ad As Worksheet
Dim MaxRow As String, MaxRow_ad As String, MaxColumn As String
Dim i As Integer, INP As Integer

Set ds = Sheets("元データ")
Set ad = Sheets("整形後データ")

MaxRow = ds.Cells(Rows.Count, 1).End(xlUp).Row
MaxColumn = ds.Cells(1, Columns.Count).End(xlToLeft).Column

For i = 1 To MaxRow
    For INP = 1 To MaxColumn Step 4

        ds.Range(Cells(i, INP), Cells(i, INP + 3)).Copy
        MaxRow_ad = ad.Cells(Rows.Count, 1).End(xlUp).Row
        ad.Cells(MaxRow_ad + 1, 1).Insert
        Application.CutCopyMode = False    

     Next INP
Next i

End Sub

 プログラミング経験がほぼないので、見る人が見たら鼻で笑われるコードかもしれませんし、不要なことをしているかもしれませんが、求めていた動作はしてくれました。
 タイトルでは改行と書いてありますが、その実態は”元データ”シートから4列ずつコピーして”整形後データ”シートに貼り付けるということをしています。つまり、

元データ
このようなデータを別のシートに
整形後データ
という形にして貼り付けします。
 種々の関数の説明は省略しますが、僭越ながら軽く動作の説明をしたいと思います。
 最初に、使う変数の定義をし、そのあとにエクセルのシート名を変数に入れています。
次に、コピーしたいデータの最終行と最終列の情報を次の2文で持ってきています。

MaxRow = ds.Cells(Rows.Count, 1).End(xlUp).Row
MaxColumn = ds.Cells(1, Columns.Count).End(xlToLeft).Column

次に、For文で今持ってきた行数分だけ同じ動作を繰り返します。
その動作が、
・1列目から4列目までをコピー(INP=1のとき)

ds.Range(Cells(i, INP), Cells(i, INP + 3)).Copy

・貼り付け対象シートのデータが入っている最後の行を取得

MaxRow_ad = ad.Cells(Rows.Count, 1).End(xlUp).Row

・その次の行にコピーしたデータを貼り付ける

ad.Cells(MaxRow_ad + 1, 1).Insert

・コピペモードを終了し、次のINPに4を足して次のループへ
という流れになっています。

終わりに

 本職エンジニアの方々が難しそうな記事を投稿している中、初心者が簡単なコードを投稿するという恐れ多い記事ですが、お役に立てたら幸いです。マクロをまだまだ理解できていないので、他の方の環境でも動作するのか分かりませんが、ご了承ください。

※2017/06/13 記事をより分かりやすくするため、編集しました。

ActiveRecord::Relationとは一体なんなのか

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

ActiveRecord::Relation まわりのことを、ソースコードを読んで調べてまとめました。

はじめに

Ruby on Railsを使い始めて2ヶ月と少しの初心者ですが、最近はなんとなくわかったような気になってrailsを使っています。
つまりわかっていないということなので、これもいい機会だと思って ActiveRecord::Relation について調べてみました(ソースコードを読んでみました)。

この記事の内容はざっくりいうと ActiveRecord::Relation とは一体何で、何をしているのか…という話(の一部分)です。
特に、どういうタイミングでどういったSQLクエリが発行されるか、といったことに注目しています。

これを決める前に最初に持っていた疑問は

  • 関連付けで作られたメソッドは一体何を返しているの?
  • eachって一体何に対してeachを使っているの?
  • find はArrayのようにコードブロックもとれるらしいけれど、一体どうやってるの?
  • どのメソッドを使うとどういうクエリが何回発行されるの?

などでした(記事中で解決するものも、しないものもあります)。

以下では記事を書いた時点でのrailsソースコード(5.1.0 相当)を参考にしていますが、おそらく5系統の中ではそれほど違うことはないかと思います。

そもそもActiveRecord::Relationとは?

ActiveRecord::Relationは

  • クエリを生成するための条件を持っておいて、必要に応じて適切なSQLクエリを生成・発行してくれる
  • その結果からオブジェクトを作って返したり保持したりしてくれる

感じのものです。つい最近知ったのですが、こういったものをO/Rマッパーというそうです。

ActiveRecord::Relationがどこで出てくるかというと、たとえばUserなるモデルがあったとすると User.all や User.where(name: "hoge") などで返ってくるものが ActiveRecord::Relation のインスタンスです。
また、has_many関連で作られたメソッドは ActiveRecord::CollectionProxy のインスタンスを返しますが、この ActiveRecord::CollectionProxy は ActiveRecord::Relationを継承しています。

初心者が ActiveRecord::Relation について知るには、ひとまず以下のインスタンス変数に注目するのがよさそうです。

  • @values: SQLクエリを作るための条件
  • @loaded: SQLクエリを発行し、 オブジェクトを取得したことがあるかのフラグ
    • (ソースコード中では loaded? という名前で参照されています)
  • @records: 条件に合うオブジェクトの配列

@recordsにアクセスするための records というメソッドがあります。
これは、 loaded? がfalseのとき(=まだオブジェクトを取得していないとき)はクエリを発行して@records を取得して返し、loaded? が trueのとき(=すでにオブジェクトを取得しているとき)は @records をそのまま返します、

# activerecord/lib/active_record/relation.rb

def records # :nodoc:
  load
  @records
end

def load(&block)
  exec_queries(&block) unless loaded?

  self
end

loadする前は @records がないので、だいたい loaded?のtrue/false = @records の有無です。

各メソッドはこの records を使ったり使わなかったりします。知る限りではだいたい3種類です。

  • recordsを使うもの
  • recordsを使わないもの
  • その他

records を使うメソッド

recordsを使うメソッドは、loaded? がtrueならクエリを発行しないメソッドでもあります。

records に delegateされているメソッド

ActiveRecord::Relation のいくつかのメソッドは records に delegate されています。

# activerecord/lib/active_record/relation/delegation.rb

delegate :to_xml, :encode_with, :length, :each, :uniq, :to_ary, :join,
         :[], :&, :|, :+, :-, :sample, :reverse, :compact, :in_groups, :in_groups_of,
         :to_sentence, :to_formatted_s, :as_json,
         :shuffle, :split, :index, to: :records

つまり records(Array) に対してメソッドを呼び出すもので、すでに @records があればSQLクエリを発行しません。

また、ActiveRecord::Relation は Enumerableをインクルードしています。
delegateされていなくても、Enumerableのメソッド (例えば map, collect など)は each を使って定義されているので、他のメソッドと同様 @records のメソッドを呼び出すことになります。

5.0.3では map,collect などもdelegate されているようですが、recordsに対してArrayのメソッドが呼ばれることに変わりはありません。

pluck

pluck は各レコードを丸ごとオブジェクトとしてとってくるのではなく、引数で指定したカラムのみの配列で返すメソッドです。
pluck はdelegateされているわけではないですが、 @records があればそちらからとってきます。

# activerecord/lib/active_record/relation/calculations.rb

def pluck(*column_names)
  if loaded? && (column_names.map(&:to_s) - @klass.attribute_names - @klass.attribute_aliases.keys).empty?
    return records.pluck(*column_names)
  end

  if has_include?(column_names.first)
    construct_relation_for_association_calculations.pluck(*column_names)
  else
    relation = spawn
    relation.select_values = column_names.map { |cn|
      @klass.has_attribute?(cn) || @klass.attribute_alias?(cn) ? arel_attribute(cn) : cn
    }
    result = klass.connection.select_all(relation.arel, nil, bound_attributes)
    result.cast_values(klass.attribute_types)
  end
end

size

size は、 @records があればArray#lengthでサイズを取得します。
@records がない場合DB内でサイズを計算してしまうので、 @records は更新されません。

# activerecord/lib/active_record/relation.rb

def size
  loaded? ? @records.length : count(:all)
end

recordsを使わないメソッド

@records があってもそれを使わずに、SQLクエリを使って計算を行うメソッドがあります。
rails ガイドで列挙されているこのあたりがそうです。
https://railsguides.jp/active_record_querying.html#%E8%A8%88%E7%AE%97

  • count
  • sum
  • average
  • minimum
  • maximum

この5つは activerecord/lib/active_record/relation/calculations.rb で定義されています。

count, sum は Array にもあるメソッドなのでややこしいですが、 ActiveRecord::Relation のcountやsumはコードブロックを無視します。
Arrayのcountやsumを使いたい時はrecords、to_aなどでArrayに変換する必要があります。

その他のややこしいメソッド

教えてもらうまで全く知らなかったのですが、コードブロックを渡すかどうかで
SQLクエリとしてそれを処理するかArrayとして処理するかが変わるメソッドがあるそうです。

find

findは引数を渡すかコードブロックを渡すかで挙動が変わります。

引数を渡したときは引数を渡したときはSQLを発行し、idが引数と一致するものをひとつ探してきます。

コードブロックを渡したときはEnumerable(というかArray)のfindが呼ばれます。

# activerecord/lib/active_record/relation/finder_methods.rb

def find(*args)
  return super if block_given?
  find_with_ids(*args)
end

select

selectもfindと同じように、引数を渡すかコードブロックを渡すか挙動が変わります。

引数(カラム名)を渡した時のselectは、引数のカラムの値だけを取ってきて、その値のみが入ったオブジェクトを返すものです。
( SQLクエリは “SELECT `args` FROM table_name …” のようになります)。

コードブロックを渡した時のselectは、Arrayのselectです。コードブロックに渡したときtrueを返すものの配列を返します。

これはそもそも用途が違うので、どちらを使うか迷うことはなさそうですが…

# activerecord/lib/active_record/relation/finder_methods.rb

def select(*fields)
  if block_given?
    if fields.any?
      raise ArgumentError, "`select' with block doesn't take arguments."
    end

    return super()
  end

  raise ArgumentError, "Call `select' with at least one field" if fields.empty?
  spawn._select!(*fields)
end

まとめ

ここまで出てきたメソッドをもう一度おさらいしておきます。

  • 条件にあう配列 records がすでにあればそれを使うもの
    • each, Enumerableのメソッド
    • [], length, uniq, sample, reverse, compact などのdelegateされているメソッド
    • pluck
    • size
  • recordsがあってもなくてもクエリで計算を行うもの
    • count
    • sum
    • minimum
    • average
    • maximum
  • その他
    • find
    • select

ここで列挙したのは個人的に使うメソッドだけなのですが、同じように見ていけば他のメソッドもどうなっているかわかるはずです。

なんとなくで使えてしまうのでなんとなく使ってしまいがちなActiveRecordですが、なんとなくでも何が起こっているのか知っておくと後々役に立ちそうです。
findの使い分けやcount,size,lengthの使い分けはDBでやるのが速いか、rails上でやるのが速いかは場合によったりもしますし、違いを知って使い分けていければいいなと思っています。

参考:

最近人気な記事