2019年1月21日月曜日

【機械学習】設計と実装まとめ

  • 公開日:2019年01月20日
  • 最終更新日:2019年01月20日

記事概要

機械学習でデータ分析をするときに気が付いたこと、得た知見のまとめ

記事の対象者

  • 機械学習の基礎を理解している
  • 実務で機械学習を利用している
  • kaggleで機械学習を利用している

記事で使うデータ

Categoricalデータ取得

Categoricalデータを取得するとき、pandas_profilingでEDA(探索的データ解析)でデータを見ながら、必要な変数名をコピペしながら配列に設定していくことが多々あります。

Categoricalデータはone_hot_encode化して分類器にかけることがほとんどだと思うので(特にkaggleとか)、以下のようにdtype=objectのデータを取ってきてしまうと便利です。

terminal

categorical_train = df.select_dtypes(include=object)

Categoricalデータは、dtype=objectであることが多いので、とても役に立ちます。

当然データによっては不要なカラムもあるので、その場合、不要なカラムはdropで消しましょう。

terminal

extracted_categorical_train = categorical_train.drop(['customerID', 'TotalCharges', 'Churn'],  axis=1)

命名する変数名は、実装時にきちんと考えましょう。地雷化したコードが多すます。

モデル実装

モデルをチューニングしてモデルの性能検証をする場合は、以下の流れで行います。

  • GridSearchCVでモデルのハイパーパラメータを測定
  • 交差検証でモデルの性能を測定

モデルの汎化性能を測定するには、交差検証だけでなく、k分割を使うとさらに良いです。

まずはGridSearchCVを使ってハイパーパラメーターを決定します。

terminal

from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import KFold
from sklearn.ensemble import RandomForestClassifier

clf = RandomForestClassifier()

# 試行するパラメータを羅列する
params = {
    'max_depth': list(range(1, 20)),
    'criterion': ['gini', 'entropy']
}

# KFoldクラスで分割数を指定する
kFold = KFold(n_splits=5, shuffle=True, random_state=0)


grid_search = GridSearchCV(clf,  # 分類器を渡す
    param_grid=params,  # 試行してほしいパラメータを渡す
    cv=kFold,  # KFoldで汎化性能を調べる
)

# グリッドサーチで優れたハイパーパラメータを探す
grid_search.fit(X, y)

# 最も良かったスコア
print(grid_search.best_score_)
# 上記を記録したパラメータの組み合わせ
print(grid_search.best_params_)

上記を実行します。

terminal

0.8036348147096408
{'criterion': 'entropy', 'max_depth': 8}

accuracyとハイパーパラメーターが出力されました。

上記のハイパーパラメーターを使って交差検証でモデルの性能を測定します。

terminal

from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score

# 引数はdictで渡せないので注意。
clf = RandomForestClassifier(criterion= 'entropy', 
                             max_depth=8)

scores = cross_val_score(clf, X, y, scoring='accuracy', cv=kFold)

print(scores)
print(scores.mean())

実行します。

terminal

[0.7920511  0.80624556 0.79418027 0.79545455 0.81676136]
0.8009385686173301

これでGridSearchCVでモデルのハイパーパラメータを測定して、交差検証でモデルの性能を測定できました。

まとめ

機械学習は慣れるまで大変ですが、素晴らしい技術なので頑張って身につけてください。

機械学習エンジニアは不要になるとか、クラウドで全部できるようになるとか言う人がいますが、真に受けて学習を怠ってはいけません。
プログラマーは不要になるとか、大企業は潰れないとか、世の中に流れている通説はほとんど嘘です。
リターンの大きい技術なので、是非頑張ってください。

以上です。

参照サイト


この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2018年12月2日日曜日

【python】PyCharm CEでAWS Toolkits for PyCharmを使う

  • 公開日:2018年12月02日
  • 最終更新日:2018年12月05日

記事概要

PyCharm CEでAWS Toolkits for PyCharmを使ってAws lambdaをlocalで動かす方法を記載した記事です。

記事の対象者

  • Aws lambdaにpythonアプリをdeployしたことがある
  • PyCharmを使ってAws lambdaをアプリを実装したい

記事で学べること

  • PyCharmでAws lambdaの開発環境を構築する

環境

  • macOS Mojavve10.14
  • Python 3.6.3
  • aws lambda
  • Docker Desktop version2.0.0.0-mac81

PyCharmインストール

公式サイトからPyCharm Communityをダウンロード します。もちろん、Professionalでも問題ありません。

PyCharm CEを立ち上げて適当なプロジェクトを作成します。

Pluginインストール

PluginでAWS Toolkitをインストールします。操作手順は以下の通り。

  • Preference選択
  • Plugins選択
  • AWSで検索
  • AWS Toolkitをインストール

AWS Toolkitのインストールが完了したら、次の作業に進みます。

AWS SAM CLI を導入

AWS SAM CLIが必要になります。
公式サイトに記載してある手順を実行します。

AWS SAM CLIの導入ついでに、aws-cliも最新にしておくとさらに良いです。

terminal

// 現在バージョン確認
$ aws --version
aws-cli/1.16.47 Python/3.6.3 Darwin/18.0.0 botocore/1.12.37

// AWS CLI を最新バージョンに更新
pip install awscli --upgrade --user

// 更新後のバージョン確認
$ aws --version
aws-cli/1.16.67 Python/3.6.3 Darwin/18.0.0 botocore/1.12.57

// aws-sam-cli install
pip install aws-sam-cli

公式サイトだとbrewのコマンドが記載されていますが、brewでpythonを導入していない場合、brewだとインストールに失敗しました。
なので、私はpipで導入しました。
自分の環境に合わせてaws-sam-cliを導入してください。

プロジェクト作成

準備が完了したので、プロジェクトを作成しましょう。

NewProjectを選択すると、AWS Serverless Applicationが出現しています。

択しプロジェクト名、SAM Templateから「AWS SAM Hello World」を選んで作成します。

*注意点1.pythonをVirtualenv環境で利用している場合は、Virtualenv Environmentを選択するようにします。公式サイトに詳しい説明が記載されています。

*注意点2.aws-sam-cliをpipで入れた場合は、pathを自分で設定する必要があります。
pathはwhichコマンドで確認できます。

terminal

which sam

/Users/{username}/.pyenv/shims/sam

上記のpathをCIのpathに設定してください。

lambdaをdockerで動かす。

プロジェクト作成すると、デフォルトでlambdaプロジェクトが作成されています。

テスト環境で動かす場合はλマークをクリックします。[Run local app]でlambdaをdocker環境で動かすことができます。

terminal

2018-12-02 22:05:01 Found credentials in environment variables.
2018-12-02 22:05:01 Invoking app.lambda_handler (python3.6)
2018-12-02 22:05:01 Decompressing /var/folders/_k/82kvh_6s4bz0w8j8lhkp674c0000gn/T/2220729341239739084.zip

Fetching lambci/lambda:python3.6 Docker container image...................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
2018-12-02 22:17:48 Mounting /private/var/folders/_k/82kvh_6s4bz0w8j8lhkp674c0000gn/T/tmpco54kn1p as /var/task:ro inside runtime container
START RequestId: c4106c2a-a762-4881-90c1-d3abf01a9a96 Version: $LATEST
END RequestId: c4106c2a-a762-4881-90c1-d3abf01a9a96
REPORT RequestId: c4106c2a-a762-4881-90c1-d3abf01a9a96 Duration: 1444 ms Billed Duration: 1500 ms Memory Size: 128 MB Max Memory Used: 26 MB

{"statusCode": 200, "body": "{\"message\": \"hello world\", \"location\": \"61.12.128.21\"}"}


jsonが取得できています。初回はdockerのイメージを取得してくるので、かなり時間がかかります。気長に待ちましょう。

virtualenvに対応

プロジェクト毎に使用パッケージをvirtualenvで隔離します。lambdaAPIは量を作るケースが多いので、virtualenvは必須です。

ターミナルで作業します。

terminal

// プロジェクトルートへ
cd project_root

// 仮想環境(virtualenv)の構築
$ virtualenv --python="`which python`" virtualenv

// virtualenvのactivate
source virtualenv/bin/activate

(virtualenv)$

コマンドをvirtualenv name のようにして名称をつけても問題ありません。

あとは、PyCharm → Preferences → Project Interpreterでaddボタンを押して作った仮想環境を設定すればOKです。

まとめ

AWS Toolkitを使うと、間違いなく生産性は上がります。
一日で設定可能なので、是非利用しましょう。 WEB開発者はもちろん、機械学習開発者にもおすすめです。

次は、testコードと本番deployと機械学習のmodel APIを試してみようと思います。

以上です。

参照サイト


この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2018年11月25日日曜日

【flask】Aws lambda上にflaskをdeployする

  • 公開日:2018年11月25日
  • 最終更新日:2018年11月25日

記事概要

Aws lambdaでflaskアプリをdeployする方法を記載した記事です。

記事の対象者

  • Aws lambdaでflaskをdeployしたい
  • flaskを使った実装を理解している

環境

  • flask
  • python3.6
  • aws lambda
  • zappa
  • doorkeeper 16.1.0

flaskアプリ作成の準備

アプリ構築用のフォルダを作成します。

terminal

mkdir flask-app

続いて仮想環境を構築します。Zappaを使ってbuildとdeployをするので、仮想環境の構築が必須になります。

仮想環境の構築には、virtualenvを使います。virtualenvはPythonの仮想的な環境を作ることができます。
Zappaがpyenvでdeployできるかどうかは確認していません。

virtualenvは、プロジェクトごとにPythonのバージョンを変えたり、必要なパッケージを分けてインストールして動かす事もできます。

terminal

cd flask-app/

$ virtualenv .env
Using base prefix '/Users/{user_name}/.pyenv/versions/3.6.3'
New python executable in /Users/{user_name}/workspace/flask-app/.env/bin/python3.6
Also creating executable in /Users/{user_name}/workspace/flask-app/.env/bin/python
Installing setuptools, pip, wheel...
done.

仮想環境に入ります。

terminal

source .env/bin/activate

(.env) 

terminalのプロンプトの最初が(.env)に変わってれば入れています。

確認のために仮想環境を出ます。

terminal

deactivate

terminalのプロンプトから(.env)が消えていれば、仮想環境を出ています。

flaskアプリの作成

アプリを作成します。requirements.txtを作成します。

terminal

// 仮想環境に入る
source .env/bin/activate

touch requirements.txt

requirements.txtに必要なパッケージを記載します。

flask-app/requirements.txt

flask
zappa

ライブラリをpipでinstallします。

terminal

pip install -r requirements.txt

Hello worldのアプリを作成します。

flask-app/app.py

from flask import Flask, jsonify

app = Flask(__name__)

@app.route('/')
def hello_world():
    return jsonify({"message": "Hello World!"})

if __name__ == '__main__':
 app.run()

ローカルで動作することを確認します。
http://localhost:5000/でブラウザにアクセスします。

ブラウザ

{"message":"Hello World!"}

問題ありませんね。

flaskアプリをlambdaにdeploy

ZAPPAを使います。

terminal

$ zappa init

// 全てデフォルト

zappa_settings.jsonが作成されていることを確認します。

terminal

$ ls -l
total 24
-rw-r--r--@ 1 edy  staff  178 11 24 21:57 app.py
-rw-r--r--  1 edy  staff   11 11 24 21:49 requirements.txt
-rw-r--r--  1 edy  staff  240 11 24 23:09 zappa_settings.json

内容を確認すると、色々と設定が記載されているはずです。

deployします。

terminal

zappa deploy dev

deployします。
The role defined for the function cannot be assumed by Lambdaというエラーが表示されて deployに失敗することがありますが、何回か叩くとうまくいくはずです。

URLが返却されたらURLをブラウザで叩いてみてください。

ブラウザ

{"message":"Hello World!"}

上手くいきました。

flaskアプリをlambdaから削除

削除もコマンドで行えます。

terminal

zappa undeploy

これで削除されます。便利ですね。

まとめ

lambdaを使うと低コストでサーバーを利用することができます。
シンプルなAPIを作成するなら、これで十分です。機械学習のAPIとかなら、十分ですね。いやー、凄い時代になりました。

以上です。

参照サイト


この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2018年7月15日日曜日

【Compose and Rails】 新規プロジェクト構築でハマった箇所

  • 公開日:2018年07月15日
  • 最終更新日:2018年07月15日

記事概要

Compose and Railsを使った新規プロジェクトでdocker-composeとrailsを利用したら構築でハマりました。
なので以下にメモ。

環境

  • Engine: 18.03.1-ce
  • Rails5.2
  • ruby2.5.1

公式サイト通りにやったのに、色々と修正が必要になり無駄な時間がかかってしまいました。なので、修正点をまとめておきます。

GemfileとGemfile.lock

公式に通りにやると

terminal

docker-compose run web rails new . --force --database=postgresql

の後に、ローカルに生成されたGemfileとGemfile.lockを、webフォルダの中のGemfileとGemfile.lockと入れ替えることが書いてありません。 コードを読むまで気づきませんでした。なんのためのチュートリアルなのか。

DB作成

公式だとDBの作成が、docker-compose upの起動後になっています。
これだとDBがないので、当たり前ですが、railsが起動しません。

terminal

docker-compose logs

でも理由が出てないので焦りました。ちゃんと書いて欲しいですね。

pidの削除処理

docker-compose startでpumaを起動していると、docker-compose stopを実行しても、PIDファイルが残ってしまうことがあります。

PIDファイルは、長時間動作し続けるプロセス(例えば MySQL デーモンなど)を、自身のPIDをファイルに書いておき、他のプロセスが参照できるようにしているファイルです。

このPIDファイルを削除する処理を記載します。

docker-compose.yml

    command: bash -c 'rm -f tmp/pids/server.pid && bundle exec rails s -p 3001 -b "0.0.0.0"'

上記のようにすることで、docker-compose startのたびにserver.pidが削除されるようになります。

まとめ

公式の通りにやっても、railsの未経験者だと多分すんなりとは立ち上がりません。でも、某キー○の古い情報よりはマシかな。。。という感じです。
結局最後はコードとログを読むしかないという結論でした。AI時代 or 自動化時代はさらに原因究明が大変になるんだろうなあ。あーイヤダイヤダ。
あと、dockerのログは、もう少し詳細にして欲しいですね。

以上です。

PICK UP オススメ書籍

運営サイト


この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2018年5月17日木曜日

【ethereum】開発前の知識整理

  • 公開日:2018年05月17日

記事概要

2018年のGoogle I/Oが残念すぎた(もうスマホは進化しないのでしょうか。新しいライブラリで誤魔化しているだけですね。イノベーションゼロ)ので、コントラクト開発をしようと考えています。ということで、開発に最低限必要なethereumの用語をまとめた記事です。
gethでの環境構築や仮想通貨の技術的な仕組みは知っている前提です。まだメモ書きの段階です。徐々に増やしていきます。

環境

  • ubuntu-17.10
  • ethereum Geth/v1.7.3

DApps

「Decentralized Applications(非中央集権・分散型のアプリケーション)」の略です。

METAMASK

MetaMaskはChromeの拡張機能として使用するウォレットです。ICOに参加する時やDAppsのオンラインゲームで遊ぶ時、DEXの取引所を使う時に必要になります。git Hubでソースが公開されています。

DEX

DEXは分散型取引所のことです。分散型取引所とは、中央管理者がいなくても仮想通貨の取引が可能な取引所の事です。逆に、中央集権型取引所は、日本ではcoincheckやbitFlyer、海外ではpoloniexやbittrexのような中央管理者に仮想通貨を預けて取引を行う取引所のことです。しかし、中央集権型取引所では、秘密鍵の管理を取引所に委任している形になっているため、取引所の内部の人間が顧客の資金を不正に引き出すことが出来てしまう上、秘密鍵を持っている中央管理者へのハッキングリスクがあります。なので、特定の仮想通貨を購入した後は取引所から対応したウォレットに移すことが推奨されています。

ERC20

イーサリアムベースのトークンです。トークンに対する技術的に統一された仕様になります。また、ERC20トークンはERC20トークン対応のウォレットでないと管理できません。
ERC とは「Ethereum RFC (Request for Comment)」の意味で、その20番目だったために「ERC20」と呼ばれているそうです。

Solidityの学習

SolidityはEthereum(イーサリアム)上で動くスマートコントラクト開発の言語です。
まずはローカルに環境を整える前に、CryptoZombiesで実装するとスマートコントラクトの理解ができるでしょう。
また、開発前にMETAMASKをChromeにインストールしましょう。章を進めると、Rewardがもらえます。

Contracts

コントラクトをイーサリアム上にデプロイすると、イミュータブルになる。つまり編集も更新もできなくなる。コントラクトに何か欠陥があっても、それをあとで修正する方法はない。

solidity

msg.value

msg.valueは、コントラクトにどのくらいEtherが送られたかを見る。external payable修飾詞を使う

ECDSA

デジタル署名アルゴリズム。楕円曲線暗号を使った公開鍵のアルゴリズムで、RSAよりも短い鍵長で安全性を担保できる。
openSSLのバージョンを確認する。


$ openssl version
OpenSSL 1.0.2g  1 Mar 2016

まとめ

まだ未完成です。

続きます。

運営サイト


参考記事

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2018年4月15日日曜日

【Rails】きれいなRubyコードは好きですか? Rubocop. Clean Code

  • 公開日:2018年04月15日
  • 最終更新日:2018年04月21日

記事概要

プロジェクトへRubocopを導入する記事です。

環境

  • centos6.5
  • Rails5.2
  • ruby2.5.1
  • rbenv

Rubocop

Rubocopはコード解析ツールです。
デフォルトでは Ruby Style Guideで示されているガイドラインが適用されます。

実績

Ruby on RailsでもRubocopでコードチェックを実行しています。

Gemfile修正

Gemfileにrubocopを追記します。

{project_folder}/Gemfile

group :development do
  gem 'rubocop', require: false
end

インストールします。

terminal

cd {project_root}
bundle install

Fetching rainbow 3.0.0
Installing rainbow 3.0.0
Fetching parallel 1.12.1
Installing parallel 1.12.1
Fetching parser 2.5.1.0
Installing parser 2.5.1.0
Fetching powerpack 0.1.1
Installing powerpack 0.1.1
Fetching ruby-progressbar 1.9.0
Installing ruby-progressbar 1.9.0
Fetching unicode-display_width 1.3.0
Installing unicode-display_width 1.3.0
Fetching rubocop 0.54.0
Installing rubocop 0.54.0

.rubocop.yml

プロジェクト直下に.rubocop.ymlファイルを作成します。 .rubocop.ymlはRuboCopの挙動をコントロールできます。

terminal

cd ${project_root}

$ touch .rubocop.yml

作成した.rubocop.ymlは空なので、railsの.rubocop.ymlの内容をコピーして貼り付けます。
特別な理由がない限り、基本はRailsと同じ設定にすると良いでしょう。

.rubocop.ymlはRuby2.5.1とRails5.2の環境に合わせます。

{project_folder}/.rubocop.yml

// .ruby-version ファイルからRubyのバージョンは読み込む。
#TargetRubyVersion: 2.5 → 削除

Layout/** → Style/**に置換

Style/SpaceBeforeFirstArg: → Lint/SpaceBeforeFirstArg:

// コメントアウト
#CustomCops/RefuteNot 

// コメントアウト
#Style/EmptyLineAfterMagicComment:
#  Enabled: true

// コメントアウト
#Style/SpaceAroundKeyword
#  Enabled: true

// コメントアウト
#Style/FrozenStringLiteralComment

// コメントアウト
// http://www.rubydoc.info/github/bbatsov/RuboCop/RuboCop/Cop/Lint/BlockAlignment
#EnforcedStyleAlignWith

rubocopコマンドの実行で出力されたエラーを修正します。
シングルクォーテーションをダブルクォーテーションへ変換する必要があるので、以下のコマンドを実行します。

terminal

$ rubocop -a

上記のコマンドを実行すると他のエラーも修正されるので、実行前にgitで状態を保存しておきましょう。

速度改善

上記で設定したrailsの.rubocop.ymlの設定だと、rubocopコマンドの実行に時間がかかるので改善します。
.rubocop.ymlのExcludeの設定を変更します。

{project_folder}/.rubocop.yml

  DisabledByDefault: true
  Exclude:
    - 'tmp/**/*'
    - 'public/**/*'
    - 'vendor/**/*'
    - 'log/**/*'
    - 'actionpack/lib/action_dispatch/journey/parser.rb'

rubocopで検査非対象フォルダの配下を/**/*と設定するのがポイントです。
実行して確認します。

{project_folder}/.rubocop.yml

$ rubocop
warning: parser/current is loading parser/ruby21, which recognizes
warning: 2.1.7-compliant syntax, but you are running 2.1.6.
warning: please see https://github.com/whitequark/parser#compatibility-with-ruby-mri.
Inspecting 48 files
................................................

48 files inspected, no offenses detected

完了です。

まとめ

Railsは開発速度に優れたフレームワークですが、ソースコードがカオスになりやすい欠点があります。プロジェクト立ち上げ時は良いのですが、プロジェクトが長くなればなるほどコードを読むのがきつくなります。Rubocopを導入して、ソースコードの可読性を保つようにしましょう。
長い目で見ると、Rubocopを使った方が開発速度は上がるはずです。

以上です。

PICK UP オススメ書籍

運営サイト


この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2018年2月24日土曜日

【Android】ViewPager

  • 公開日:2018年02月23日

記事概要

java-programming向けの詳細な記事を書く時間が取れないので、ざっくりとこちらに情報を載せます。
ViewPagerアニメーションの学習と研究をしていたので、そのまとめ記事です。

環境

  • Android Studio 3.0.1

概要

ViewPagerはよく使いますが、きちんと内部コードを追って学習したことはほとんどありませんでした。
記事の内容は、この公式ドキュメントがベースです。さらに深掘りしています。

ViewPagerとPageTransformer

ViewPagerのアニメーション方法を変更するには、ViewPager.PageTransformerを使います。ViewPager.PageTransformerはtransformPageが宣言されているInterfaceです。

ViewPager.java

    public interface PageTransformer {
        /**
         * Apply a property transformation to the given page.
         *
         * @param page Apply the transformation to this page
         * @param position Position of page relative to the current front-and-center
         *                 position of the pager. 0 is front and center. 1 is one full
         *                 page position to the right, and -1 is one page position to the left.
         */
        void transformPage(@NonNull View page, float position);
    }

画面切り替え時にtransformPageメソッドが呼び出されます。

PageTransformerで実装した内容を有効にするには、setPageTransformerメソッドを使います。

ViewPager.java

mPager.setPageTransformer(true, new SamplePageTransformer());

上記のように設定すると、実装した具体的なPageTransformerクラスがmPageTransformer変数に設定され、onPageScrolledメソッドで呼び出されます。

ViewPager.java

        if (mPageTransformer != null) {
            final int scrollX = getScrollX();
            final int childCount = getChildCount();
            for (int i = 0; i < childCount; i++) {
                final View child = getChildAt(i);
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();

                if (lp.isDecor) continue;
                final float transformPos = (float) (child.getLeft() - scrollX) / getClientWidth();
                mPageTransformer.transformPage(child, transformPos);
            }
        }

PageTransformerクラスの実装

具体的なPageTransformerクラスは、PageTransformerをimplementsして実装します。サンプルとしてZoomOutPageTransformerクラスを実装してみます。

{project_folder}/ZoomOutPageTransformer.java

public class ZoomOutPageTransformer implements ViewPager.PageTransformer {
    private static final float MIN_SCALE = 0.85f;
    private static final float MIN_ALPHA = 0.5f;

    @Override
    public void transformPage(@NonNull View page, float position) {
        int pageWidth = page.getWidth();
        int pageHeight = page.getHeight();

        Log.d("ZoomOutPage", "position :" + position + ", view id : " + page.getId());
        Log.d("ZoomOutPage", "pageWidth :" + pageWidth + ", view id : " + page.getId());
        Log.d("ZoomOutPage", "pageWidth :" + pageHeight + ", view id : " + page.getId());

        if (position  < -1) {
            // 透明にする
            page.setAlpha(0.0f);
        } else if (position <= 1) {
            // -1 < posiiton < 1
            // 多分、徐々に小さくするため
            float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
            // margin 黒枠のところ
            // 縦 top bottomやな
            float vertMargin = pageHeight * (1 - scaleFactor) / 2;
            // 水平 名前が left rightだと
            float horzMargin = pageWidth * (1 - scaleFactor) / 2;
//            if (position < 0) {
//                // 相対的に動かす。これが無いと画像が動かないのでおかしくなるはず。
//                page.setTranslationX(horzMargin - vertMargin / 2);
//            } else {
//                page.setTranslationX(-horzMargin + vertMargin / 2);
//            }

            // Scale the page down (between MIN_SCALE and 1)
            page.setScaleX(scaleFactor);
            page.setScaleY(scaleFactor);

            // Fade the page relative to its size.
            page.setAlpha(MIN_ALPHA +
                    (scaleFactor - MIN_SCALE) /
                            (1 - MIN_SCALE) * (1 - MIN_ALPHA));

        } else {
            // 透明にする
            page.setAlpha(0.0f);
        }


    }
}

positionはページ数でなく、引数のページの相対的な位置です。-1 < x < 1までの範囲の値をとり、0が中央, -1が左, 1が右となります。

vertMarginとhorzMarginはページ切り替え時に、ページ間のviewの距離を詰めるための計算に使っています。setTranslationXでviewの位置をずらすことで、ページ移動のアニメーションをスムーズに見せています。名称がわかりにくいので、topBottomMarginとleftRightMarginで実装した方がわかりやすいと思います。

続いて、DepthPageTransformerを実装してみます。

{project_folder}/DepthPageTransformer.java

public class DepthPageTransformer implements ViewPager.PageTransformer {
    private static final float MIN_SCALE = 0.75f;
    @Override
    public void transformPage(@NonNull View page, float position) {
        int pageWidth = page.getWidth();

        if (position < -1) {
            // 透明にする
            page.setAlpha(0.0f);
        } else if (position <= 0) {
            // [-1 : 0]
            // Use the default slide transition when moving to the left page
            page.setAlpha(1);
            page.setTranslationX(0);
            page.setScaleX(1);
            page.setScaleY(1);

        } else if (position <= 1) {
            // [0 : 1]
            // Fade the page out.
            page.setAlpha(1 - position);

            // Counteract the default slide transition
            page.setTranslationX(pageWidth * -position);

            // Scale the page down (between MIN_SCALE and 1)
            float scaleFactor = MIN_SCALE
                    + (1 - MIN_SCALE) * (1 - Math.abs(position));
            page.setScaleX(scaleFactor);
            page.setScaleY(scaleFactor);
        } else {
            // 透明にする
            page.setAlpha(0.0f);
        }
    }
}

こちらの方が理解しやすですね。左と右で綺麗に処理が分割されています。position <= 0, つまり左側はただスライドするだけです。

page.setAlphaで透過状態を管理しています。徐々に薄くなったり、濃くなったりしています。
ズームも同じで、大から小, 小から大へとviewを変化させています。setScaleX, setScaleYで拡大縮小をしています。

page.setTranslationX(pageWidth * -position);で画面が停止しているように見えるようにしています。

結論

ViewPager.PageTransformerを使うことで、アニメーションを実装できます。色々とやってみようと思います。

PICK UP

運営サイト


参考


この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2017年11月19日日曜日

【Android Studio 3.0】既存アプリをAndroid Studio 3.0に対応させる。

  • 公開日:2017年11月18日

記事概要

kotlinとJavaの混じったアプリを2.3.x系でビルドすると、制約がひどく、ビルドも遅いのでAndroid Studio 3.0に移行しました.
結構色々なエラーと修正が発生したので、今後移行する人の役に立つように作業メモを記載して残しておきます。

環境

  • Android Studio 2.3.1 → Android Studio 3.0

Android Studio 3.0に対応

ダイアログで表示されるgradleのversionにアップデートします。ダイアログでOKを押下します。
自動的にbuild.gradleと/gradle/wrapper/gradle-wrapper.propertiesが上書きされます。

{project_folder}/build.gradle

     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.3'
+        classpath 'com.android.tools.build:gradle:3.0.0'
         classpath 'com.google.gms:google-services:3.0.0'
     }

{project_folder}/gradle/wrapper/gradle-wrapper.properties

-#Fri Jul 28 22:16:36 JST 2017
+#Sat Nov 18 19:40:49 JST 2017
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip

jackOptionsを無効化

gradleの変更だけだと、おそらくビルドに失敗します。jackOptionsが有効だと以下のエラーが出力されます。

Event Log

Warning:The Jack toolchain is deprecated and will not run. To enable support for Java 8 language features built into the plugin, remove 'jackOptions { ... }' from your build.gradle file, and add

android.compileOptions.sourceCompatibility 1.8
android.compileOptions.targetCompatibility 1.8

Future versions of the plugin will not support usage of 'jackOptions' in build.gradle.
To learn more, go to https://d.android.com/r/tools/java-8-support-message.html

エラーの内容は、jackOptionsはもうすぐサポート終わるから使わないでってことです。
なので、以下のように変更します。

{project_folder}/app/build.gradle

    defaultConfig {
         // something...
         vectorDrawables.useSupportLibrary = true
-        jackOptions {
-            enabled true
-        }
         multiDexEnabled true
         // something...
    }

jackOptionsを削除するだけです。sourceCompatibilityとtargetCompatibilityは残しておきます。

flavor dimensionsの設定

Android Studio 3.0からは、単一のflavor dimensionを使用する場合でも、すべてのflavorが名前付きflavor dimensionに属している必要があります。でないと、以下のようなエラーが発生します。

Event Log

All flavors must now belong to a named flavor dimension. Learn more at https://d.android.com/r/tools/flavorDimensions-missing-error-message.html

つまり、dimensionを定義してね。ってことです。正直、ダメな仕様だと思います。大規模なプロジェクトには便利な機能ですが、必須である理由がわかりません。大抵のアプリは小さいアプリなはずです。いずれ元に戻ると思いたいですね。
ビルド周りは大きく変わっているので、面倒でもサンプルプロジェクトを作成して仕様を確認することをお勧めします。ドキュメントを読むだけだと、ピンと来ないと思います。

私の環境は分ける必要がないので、以下のように名前を一つ追加しただけです。

{project_folder}/app/build.gradle

+    flavorDimensions 'normal'
     productFlavors {
         dev {
+            dimension 'normal'
         }
         prod {
+            dimension 'normal'
         }
     }

kotlinのバージョンアップ

jackOptionsが不要になったので、kotlinのバージョン縛りがなくなりました。なので、このままだと以下のエラーが発生します。

Event Log

Unable to find method 'com.android.build.gradle.internal.variant.BaseVariantData.getOutputs()Ljava/util/List;'. Possible causes for this unexpected error include:
Gradle's dependency cache may be corrupt (this sometimes occurs after a network connection timeout.) Re-download dependencies and sync project (requires network)
The state of a Gradle build process (daemon) may be corrupt. Stopping all Gradle daemons may solve this problem. Stop Gradle build processes (requires restart)
Your project may be using a third-party plugin which is not compatible with the other plugins in the project or the version of Gradle requested by the project.
In the case of corrupt Gradle processes, you can also try closing the IDE and then killing all Java processes.

エラーにkotlinの文字が出ないのは良くないですね。いずれは改善して欲しいですね。
kotlinのアップデートはgradleの記載を変更するだけです。

{project_folder}/app/build.gradle

 buildscript {
     ext {
-        kotlin_version = '1.1.1'
+        kotlin_version = '1.1.51'
     }

buildToolのバージョンアップ

buildToolも更新が必要です。buildToolのバージョンが古いと以下の警告メッセージが表示されます。

Event Log

Error:The specified Android SDK Build Tools version (26.0.1) is ignored, as it is below the minimum supported version (26.0.2) for Android Gradle Plugin 3.0.0.
Android SDK Build Tools 26.0.2 will be used.
To suppress this warning, remove "buildToolsVersion '26.0.1'" from your build.gradle file, as each version of the Android Gradle Plugin now has a default version of the build tools.

gradleを更新します。

{project_folder}/app/build.gradle

 android {
-    compileSdkVersion 26
+    compileSdkVersion 27
     buildToolsVersion rootProject.buildToolsVersion

{project_folder}/build.gradle

 allprojects {
     repositories {
+        google()
         mavenCentral()
-        maven { url 'https://maven.google.com' }
     }
 }

 ext {
-    buildToolsVersion = "26.0.1"
-    supportLibVersion = "26.1.0"
+    buildToolsVersion = "27.0.1"
+    supportLibVersion = "27.0.1"
     multidexVersion = "1.0.0"
-    constraintLayoutVersion = "1.0.2"
+    constraintLayoutVersion = "1.1.0-beta3"
     rxandroidVersion = "2.0.1"
     rxjavaVersion = "2.1.3"

maven { url 'https://maven.google.com' } を google() に書き換えできるようになりました。

また、Android Studio 3.0だと、constraintLayoutが安定してIDEで表示されるようになりました。ConstraintLayoutを使うとviewの入れ子を少なくできて、描写が高速になるので、積極的に利用していきましょう。beta版が嫌な人は1.0.2でも良いと思います。サポートライブラリとArchitecture Componentsの更新も忘れずに。

コード修正

最後にkotlinのアップデートとsdk27のアップデートのコード対応を行います。
私の環境で発生したエラーと修正方法を記載しておきます。

Error: style attribute '@android:attr/windowEnterAnimation' not found.

@が不要になりました。

{project_folder}/app/src/main/res/values/styles.xml

     <style name="Animations.GrowFromBottom">
-        <item name="@android:windowEnterAnimation">@anim/grow_from_bottom</item>
-        <item name="@android:windowExitAnimation">@anim/shrink_from_top</item>
+        <item name="android:windowEnterAnimation">@anim/grow_from_bottom</item>
+        <item name="android:windowExitAnimation">@anim/shrink_from_top</item>
     </style>
 
     <style name="Animations.GrowFromTop">
-        <item name="@android:windowEnterAnimation">@anim/grow_from_top</item>
-        <item name="@android:windowExitAnimation">@anim/shrink_from_bottom</item>
+        <item name="android:windowEnterAnimation">@anim/grow_from_top</item>
+        <item name="android:windowExitAnimation">@anim/shrink_from_bottom</item>
     </style>
 
     <style name="Animations.PopDownMenu">
-        <item name="@android:windowEnterAnimation">@anim/grow_from_topleft_to_bottomright</item>
-        <item name="@android:windowExitAnimation">@anim/shrink_from_bottomright_to_topleft</item>
+        <item name="android:windowEnterAnimation">@anim/grow_from_topleft_to_bottomright</item>
+        <item name="android:windowExitAnimation">@anim/shrink_from_bottomright_to_topleft</item>
     </style>

Android3.0からは、デフォルトでAAPT2が有効になったことの影響です。

Error: Smart cast to 'Bundle' is impossible, because 'arguments' is a mutable property that could have been changed by this time

getArguments()のSmart castができなくなりました。コードを見ると、sdk27(サポートライブラリ)では以下のように実装されています。

android.support.v4.app.Fragment

    /**
     * Return the arguments supplied when the fragment was instantiated,
     * if any.
     */
    @Nullable
    final public Bundle getArguments() {
        return mArguments;
    }

sdk26(26.1.0)では以下のような実装でした。

android.support.v4.app.Fragment

    /**
     * Return the arguments supplied when the fragment was instantiated,
     * if any.
     */
    final public Bundle getArguments() {
        return mArguments;
    }

@Nullableが追加されています。ブロックの引数を指定する必要があります。

{project_folder}/MainActivity.java

-        arguments?.let {
+        arguments?.let { it ->


というかこれは既存コードに潜在的なバグが含まれていたっぽいです。。。letのブロック内の変数はなるべくitに置き換えるか、名称を変更するべきですね。

Error: Class 'XYZPagerAdapter' is not abstract and does not implement abstract base class member public abstract fun isViewFromObject(@NonNull p0: View, @NonNull p1: Any): Boolean defined in android.support.v4.view.PagerAdapter

PagerAdapterにも変更が入ったようです。コードを見ると、sdk27(サポートライブラリ)では以下のように実装されています。

android.support.v4.app.Fragment

    public abstract boolean isViewFromObject(@NonNull View view, @NonNull Object object);

sdk26(26.1.0)では以下のような実装でした。

android.support.v4.app.Fragment

    public abstract boolean isViewFromObject(View view, Object object);

これも同じように@Nullableが追加されています。?を削除します。

{project_folder}/MainActivity.java

-        override fun isViewFromObject(view: View?, `object`: Any?): Boolean {
+        override fun isViewFromObject(view: View, obj: Any): Boolean {

isViewFromObjectの引数って@NonNullだったんですね。チェックしてコード書いてた時期があったような。

Error: Fragment

Fragmentも変更されてますね。これもsdk27で@Nullableのアノテーションが追加されたのではないでしょうか。

android.support.v4.app.Fragment

    @Nullable
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        return null;
    }

sdk26(26.1.0)では以下のような実装でした。

android.support.v4.app.Fragment

    @Nullable
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        return null;
    }

LayoutInflaterが@NonNullになっています。これは良い修正ですね。以下のように修正します。

{project_folder}/MainActivity.java

-    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
+    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,

-        val view = inflater!!.inflate(R.layout.fragment_floating_action, container, false)
+        val view = inflater.inflate(R.layout.fragment_floating_action, container, false)

Error: Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type FragmentActivity?

FragmentActivityも変更されてますね。これも@Nullableのアノテーションが追加されたのではないでしょうか。

android.support.v4.app.Fragment

    final public FragmentActivity getActivity() {
        return mHost == null ? null : (FragmentActivity) mHost.getActivity();
    }

    public Context getContext() {
        return mHost == null ? null : mHost.getContext();
    }

sdk26(26.1.0)では以下のような実装でした。

android.support.v4.app.Fragment

    @Nullable
    final public FragmentActivity getActivity() {
        return mHost == null ? null : (FragmentActivity) mHost.getActivity();
    }

    /**
     * Return the {@link Context} this fragment is currently associated with.
     */
    @Nullable
    public Context getContext() {
        return mHost == null ? null : mHost.getContext();
    }

Safe-call演算子を使って書き換えます。

色々

-            activity.supportFragmentManager.popBackStack()
+            activity?.supportFragmentManager?.popBackStack()

-            Toast.makeText(context, context.getString(R.string.sample), Toast.LENGTH_SHORT).show()
+            Toast.makeText(context, context?.getString(R.string.sample), Toast.LENGTH_SHORT).show()

gradle修正

gradleを変更します。

compileをimplementationに変更します。

implementationにするとビルドが早くなります。
なぜなら、implementationは、コンパイルする必要がある依存ライブラリだけをコンパイルします。

{project_folder}/build.gradle

-    compile 'com.android.support:multidex:' + rootProject.multidexVersion
-    compile 'com.android.support:appcompat-v7:' + rootProject.supportLibVersion
-    compile 'com.android.support:design:' + rootProject.supportLibVersion
-    compile 'com.android.support:support-v4:' + rootProject.supportLibVersion
-    compile 'com.android.support.constraint:constraint-layout:' + rootProject.constraintLayoutVersion
-    compile 'com.android.support:recyclerview-v7:' + rootProject.supportLibVersion
-    compile 'com.android.support:cardview-v7:' + rootProject.supportLibVersion
+    implementation 'com.android.support:multidex:' + rootProject.multidexVersion
+    implementation 'com.android.support:appcompat-v7:' + rootProject.supportLibVersion
+    implementation 'com.android.support:design:' + rootProject.supportLibVersion
+    implementation 'com.android.support:support-v4:' + rootProject.supportLibVersion
+    implementation 'com.android.support.constraint:constraint-layout:' + rootProject.constraintLayoutVersion
+    implementation 'com.android.support:recyclerview-v7:' + rootProject.supportLibVersion
+    implementation 'com.android.support:cardview-v7:' + rootProject.supportLibVersion

以上で終了です。お疲れさまでした。
コンパイルが随分と高速化されました。

結論

kotlinのNull Safety機能は強力ですね。小さいアプリだとAndroid Architecture Componentsは不要ですね。導入すると無駄にコードも増えますし。

kotlinの導入とconstraintLayoutの導入は本当にお勧めです。8.1のリリースも近いので、そろそろ既存アプリのandroid studio3.0の対応は終了させておきたいですね。

PICK UP

運営サイト


この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2017年11月13日月曜日

【書評】Kotlinイン・アクション

  • 公開日:2017年11月13日
  • 最終更新日:2017年11月29日
  • 学習期間:2017年11月06日 - 途中
  • 学習期間:705minites[途中]

初めに

本格的にkotlinを利用するようになってきたので、詳細な仕様を把握するために本書を購入しました。
この記事は感想とまとめを兼ねています。

本の評価には色々な視点がありますが、私はjavaのサーバーサイド、android, kotlinの開発経験があるので、その視点で本書を評価しています。

また、まとめの量が多くなってきたので、更新しながら感想を書いていきます。つまり、途中の殴り書きです。。。
良書だし、ちゃんと最後にまとめます。

紙 or 電子書籍

頻繁に持ち運ぶなら電子書籍。職場や家置いとくなら紙で良いと思います。私はkindleで買いました。kindleだと容量を70Mくらい使うので、空容量に注意しましょう。

本書の対象者

Javaの実装経験と、簡単なkotlinの実装経験がある人が読む本です。javaやkotlinの実装経験がない人が読む本ではありません。

kotlinの実装経験がない場合は、「Kotlinスタートブック」から読みましょう。

章別感想とまとめ

後々開発や復習で見返すようためのメモ書き。気になった事項の調査等。結構無駄に深く読み込んでいる箇所もあるので、そこは無視してください。

1章

kotlinは実用主義。アイデアを探求する言語ではない。
多重配列が使いにくいのはそれでかな?
もしくは、 Effective Javaの項目25「 配列よりリストを好む 」が適用されているか。。。

2章

if文(p23 - p24)

ifは式なので、値を返す。

ブロック本体と式本体で記述可能

{project_folder}/inaction/If.kt

fun max (a : Int = 0, b : Int = 0) : Int {
  return if a > b : a ? b
}

{}で囲むことを「ブロック本体を持つ」という。
return文が必要。

式本体だけで書く

{project_folder}/inaction/If.kt

fun max (a : Int = 0, b : Int = 0) : Int = if a > b : a ? b

直接返す場合は「式本体を持つ」という。

式本体の関数の場合は、戻り値も省略可能

{project_folder}/inaction/If.kt

fun max (a : Int = 0, b : Int = 0) = if a > b : a ? b

変数

なるべくval(イミュータブル(不変))で宣言するべき。

クラス

valはイミュータブル(不変)なのでgetterのみ

varはミュータブル(可変)なのでgetterとsetterの両方作成

プロパティを呼び出すとき、実際はgetterを利用している。

greteな仕様だ。

カスタムアクセサ

使ったことない。p33

enum

私は、Android開発ではenumは使わないで、Support Annotationを使う派です。でも、Android Architecture Componentsでは普通に使われていますね。Lifecycleのpublic enum Stateとか。。。proguardで難読化すれば問題はないのですが。。。

Androidの神と呼ばれているJakeWhartonさんはenum使うべき派だそうです。参考
理由は、我々は組み込みエンジニアではなく、Webエンジニアである。との理由だそうです。AndroidエンジニアはWebエンジニアではなく、組み込みエンジニアであるじゃないのかな???よくわかりません。。。

when

whenは式なので値を返す。当然、ブロックを使うこともできます。
javaと異なり、オブジェクトも利用可能。本書では、setOfでSetオブジェクトを作成して比較している。

setOfはkotlinで以下のように実装されている。

{project_folder}/inaction/If.java

public fun <T> setOf(vararg elements: T): Set<T> = if (elements.size > 0) elements.toSet() else emptySet()

Setオブジェクトを返していますね。toSetはkotlin.collectionsパッケージで実装されています。

{project_folder}/inaction/If.java

/**
 * Returns a [Set] of all elements.
 *
 * The returned set preserves the element iteration order of the original array.
 */
public fun <T> Array<out T>.toSet(): Set<T> {
  return when (size) {
  0 -> emptySet()
  1 -> setOf(this[0])
  else -> toCollection(LinkedHashSet<T>(mapCapacity(size)))
  }
}

ここでもwhenを使ってますね。out Tのout 修飾子を利用しています。分散アノテーションともいいます。つまりクラスC は T の プロデューサ であり、 T の コンシューマ ではない、と考えます。

スマートキャスト

kotlinの地雷ですね、これ。ネットにもあまり良い説明が載ってない。どうしても好きになれない仕様。

isでチェックとキャストを両方やる。

valで宣言されている必要がある。

3章

トップレベル関数(p64 - 66)

説明がわかりにくいです。要は、javaのようにクラス宣言をしなくてもメソッドを作成できるし、呼び出せるってことですね。

まずはjavaで乗数を計算するクラスと実行クラスを実装してみます。

{project_folder}/inaction/Top.java

package inaction;

public class Top {
    public static Double topFunction() {
        double  a = 2.0;
        return Math.pow(a, 2.0);
    }
}

{project_folder}/Jikko.java

import inaction.Top;

public class Jikko {
    public static void main(String []args) {
        System.out.println(Top.topFunction());
    }
}

実行結果は[4]です。両方ともclassを宣言して、メソッドにstatic宣言をしています。
kotlinの場合は、classとstatic宣言が不要になります。

{project_folder}/Jikko.kt

import inaction.topFunction

fun main(args : Array) {
    System.out.println(topFunction())
}

{project_folder}/inaction/Top.java

package inaction

fun topFunction() : Int {
    val a = 2.0
    return Math.pow(a, 2.0).toInt()
}

結果は同じように4になります。javaクラスにコンパイルされる時に勝手にクラスが作成されて、メソッドがstaticになります。
さらに、ファイルクラスの名前も変更できます。

{project_folder}/inaction/Top.java

@file:JvmName("AnotherTop")
package inaction

fun topFunction() : Int {
    val a = 2.0
    return Math.pow(a, 2.0).toInt()
}


@file:JvmNameアノテーションでファイル名を変更できます。

呼び出してみます。

{project_folder}/inaction/Top.java

import inaction.AnotherTop;

public class Jikko {
    public static void main(String []args) {
        System.out.println(AnotherTop.topFunction());
    }
}

別名AnotherTopで呼び出せています。

拡張関数

これはkotlinを使っている人はみんな知っていますね。

拡張関数はオーバーライドは無理なことを覚えておきましょう。静的関数だから、当たり前ですね。

可変長引数

使うケースは、まずない気がしますが、忘備録的に記載しておきます。

{project_folder}/inaction/Kahen.kt

fun main(args : Array<String>) {
    accept("test1",  "test2", "test3")
}

fun accept(vararg msg: String) {
    System.out.println(listOf(*msg))
}

可変長引数は、スプレッド演算子「*」を使います。

to

mapOfで利用するtoは関数です。中置呼び出しと呼びます。toはPairクラスを返します。ScalaのTupleと同じ機能です。

{project_folder}/inaction/To.kt

    val map = mapOf(1 to "one", 2 to "two")
    for ((key, value) in map.iterator().withIndex()) {
        System.out.println("key:${key}, valu:${value}")
    }

key:0, valu:1=one
key:1, valu:2=two

トリプルクヴォート

あまり使い道がなさそう

ローカル関数

関数の中で関数の宣言をすることです。javaScriptのような記載が可能です。無駄な宣言を減らせます。

4章

kotlinのクラスやメソッドはデフォルトでfinal。継承可能なクラスはopenをつける必要がある。

{project_folder}/inaction/test.kt

class Button {
    fun disable() {}
    open fun amimate() {}
    fun click() {}
}

// finalエラーが出る。
class TextButton : Button() {

}

openを追加します。

{project_folder}/inaction/test.kt

open class Button {
    fun disable() {}
    open fun amimate() {}
    fun click() {}
}

class TextButton : Button() {
    override fun amimate() {
        super.amimate()
    }

    // これはfinalエラー
    override fun click() {}
    
}

デフォルトがfinalの利点は、スマートキャストが可能になることです。

ただし、abstractクラスのメソッドは継承前提なので、openは不要。

sealed class

暗黙的にopenのついているクラス。クラスの継承を制限するために使います。インタフェースにはsealedがつけられません。子クラスにdataクラスを持つこともできます。
whenでelse文で使うとelseが必要なくなります。まだあまり使い道が理解できてません。

クラス移譲 byキーワード

説明がわかりにくいです。記載してあるコードも動かないし。移譲に関しては、公式サイトを読みましょう。クラス移譲は、インターフェースの実装を他のクラスに委譲できます。
デザインパターンのデリゲートパターンですね。

{project_folder}/inaction/test.kt

interface Base {
    fun onClick()
}

class BaseImpl() : Base {
    override fun onClick() {
        System.out.println("clicked!!")
    }
}

class Application(base: Base) : Base by base

fun main(args: Array) {
    val b = Application(BaseImpl())
    Application(b).onClick()
}

オブジェクト宣言

シングルトンを作成する

5章

コレクション操作

mapは集約

filterはフィルタリング

遅延コレクション操作

一時オブジェクトを生成しないコレクションチェーンです。

mapは集約

SAM

関数が一つのjava interfaceはラムダで代用できる。

匿名objectでも代用できるが、呼び出しごとにインスタンスを生成する。

インスタンスを何度も生成しないで利用する場合は、以下のように実装する(p168)

{project_folder}/inaction/test.kt

vae listener = OnClickListener { view - >
  // something

}

ラムダ内でthisは使えない。なぜならコードブロックだから。

with

最初の引数を、二番目の引数のラムダレシーバに変換する。

{project_folder}/inaction/test.kt

fun alphabet = with(StirngBuilder()) {
  // something
toString
}

上記のような書き方も可能。。。

ラムダの実行結果を返す。
レシーバ(引数)を返したい場合は、applyを使う

apply

レシーバ(引数)を返したい場合に使う。TextViewで複数の値を設定する場合に利用する。(p172)

6章

エルビス演算子

監獄ロックだろ。知ってるよ。

null値の代わりにデフォルトを返す演算子です。

{project_folder}/inaction/test.kt

fun alphabet = with(aaa :Stvring?) {
  val msg: String? = aaa ?: "hello"
}

as?

null値の代わりにデフォルトを返す演算子です。

let

型のチェック

{project_folder}/inaction/test.kt

if (aaa != null) {
  mesoddo(aaa)
}

{project_folder}/inaction/test.kt

aaa?.let { mesoddo(it)}

関連記事

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2017年11月8日水曜日

【ethereum】ethereumのインストールと動作の確認

  • 公開日:2017年10月26日
  • 実施日:2017年10月26日 - 2017年11月08日

記事概要

仮想通貨の仕組みを理解するために、ethereumをインストールして色々と試してみたので、その作業記録です。
この記事を使って開発環境を構築しました。
現在利用できない箇所や足りない部分を記事で補完しています。

環境

  • Ubuntu 16.04.3 LTS
  • ethereum Geth/v1.7.2

ethereumのインストール

デフォルトのdockerを使う場合は、curlをインストールします。

terminal

apt-get install curl

ethereum公式のWikiに記載されている通りにethereumをインストールします。

terminal

apt-get install software-properties-common
add-apt-repository -y ppa:ethereum/ethereum
apt-get update
apt-get install ethereum

gethコマンドでinstallが成功されたことを確認します。

terminal

geth help

NAME:
   geth - the go-ethereum command line interface

   Copyright 2013-2017 The go-ethereum Authors

USAGE:
   geth [options] command [command options] [arguments...]
   
VERSION:
   1.7.2-stable-1db4ecdc

// something

プライベート・ネットに接続

開発で使うので、プライベート・ネットで動作させます。まずは、ディレクトリを作成します。

terminal

cd /home
mkdir -p test_u/eth_private_net

myGenesis.jsonを作成します。Genesisは、初期データのことです。つまり、myGenesis.jsonは初期データファイルです。

terminal

apt-get install vi

cd /home/test_u/eth_private_net

vi myGenesis.json

{
  "nonce": "0x0000000000000042",
  "timestamp": "0x0",
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "extraData": "0x",
  "gasLimit": "0x8000000",
  "difficulty": "0x4000",
  "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "coinbase": "0x3333333333333333333333333333333333333333",
  "alloc": {}
}

// https://qiita.com/oggata/items/eea4d5e37f38785f6079

データ内容はまだ触れないでおきます。gasLimitやcoinbaseの意味は、最初はわからないと思います。

myGenesis.jsonファイルで初期化します。

terminal

geth --datadir /home/test_u/eth_private_net2 init /home/test_u/eth_private_net2/myGenesis.json

指定オプションの意味はhelpで確認しましょう。

terminal

--datadir "/root/.ethereum"  Data directory for the databases and keystore
init        Bootstrap and initialize a new genesis block

Genesis Block = 一番初めのブロックのことです。

つまり、上記は、一番初めのブロックを初期化していることを示しています。実際に実行します。

terminal

geth --datadir /home/test_u/eth_private_net2 init /home/test_u/eth_private_net2/myGenesis.json
WARN [10-25|23:04:56] No etherbase set and no accounts found as default 
INFO [10-25|23:04:56] Allocated cache and file handles         database=/home/test_u/eth_private_net/geth/chaindata cache=16 handles=16
Fatal: Failed to write genesis block: genesis has no chain configuration

chaindataディレクトリが新しく作成されて、その中にgenesisブロックのブロックチェーン情報が保存されていることを確認します。

terminal

ls -l geth/chaindata
total 12
-rw-r--r-- 1 root root   0 Oct 25 23:04 000001.log
-rw-r--r-- 1 root root  16 Oct 25 23:04 CURRENT
-rw-r--r-- 1 root root   0 Oct 25 23:04 LOCK
-rw-r--r-- 1 root root 361 Oct 25 23:04 LOG
-rw-r--r-- 1 root root  54 Oct 25 23:04 MANIFEST-000000


初期化に成功しました。

gethの起動

terminal

geth --dev --networkid "10" --datadir "/home/test_u/eth_private_net2" console 2>> /home/test_u/eth_private_net2/geth_err.log

テストネットで起動するときは、--networkid を付加します。--networkidオプションで任意の正の整数のIDを指定することで、ライブ・ネットとは異なるネットワークを立ち上げることが可能です。

また、--dev を付加して開発用途のプライベートチェーン設定で起動しましょう。--devをつけることで素早く採掘ができます。

terminal

Welcome to the Geth JavaScript console!

instance: Geth/v1.7.2-stable-1db4ecdc/linux-amd64/go1.9
 modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0

> 

起動に成功しました。

データの確認

まずは、対話型で動きと仕様を理解していきます。

eth.getBlock(0)で登録データを確認できます。

terminal

> eth.getBlock(0)
{
  difficulty: 17179869184,
  extraData: "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
  gasLimit: 5000,
  gasUsed: 0,
  hash: "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3",
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  miner: "0x0000000000000000000000000000000000000000",
  mixHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
  nonce: "0x0000000000000042",
  number: 0,
  parentHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
  receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  size: 540,
  stateRoot: "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544",
  timestamp: 0,
  totalDifficulty: 17179869184,
  transactions: [],
  transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  uncles: []
}

eth.getBlock(0)は初期データです。

exitコマンドで退出できます。

terminal

> exit
root@04a2878d5ace:/home/test_u/eth_private_net#

採掘

次は採掘してみましょう。ビットコインでいう、マイニングです。

ビットコインは平均10分ごとにブロックを生成しますが、イーサリアムは15秒です。

まず、ノードに登録されたアカウント(EOA)を表示します。

terminal

> eth.accounts
[]

最初は上記のように空です。

EOA(Externally Owned Account)を作成します。
personal.newAccount("passwd")コマンドを使います。

terminal

> personal.newAccount("passwd")
"0xe1a9e49ee272e6ab971b5f6160d8157ff9fe412b"

passwdは、本番は実際のパスワードを入力してください。これでEOA(Externally Owned Account)を作成できます。
実行すると、作成されたEOAの20バイトのアドレスが表示されます。

頭に「0x」が付加されているので16進数のハッシュですね。

もう一つアカウントを作成します。

terminal

> personal.newAccount("passwd2")
"0x0f8669608765e4df02f2a348d11954696ae5698d"

ノードに登録されたアカウント(EOA)を表示します。

terminal

> eth.accounts
["0xe1a9e49ee272e6ab971b5f6160d8157ff9fe412b", "0x0f8669608765e4df02f2a348d11954696ae5698d"]

ノードに登録されたアカウント(EOA)が表示されました。

etherbase

etherbaseとは、各ノードで採掘を行う際にその報酬を紐づけるEOAのアドレスを示します。

terminal

> eth.coinbase
"0xe1a9e49ee272e6ab971b5f6160d8157ff9fe412b"

etherの採掘

作成したEOAのアドレスがetherbaseとしてセットされていれば、etherの採掘が可能です。 etherの採掘はminer.start(thread_num)コマンドで開始します。

terminal

> miner.start()
null

nullが表示されていますが、採掘は実行されています。これは少しわかりにくい仕様ですね。以前はtrueが返される仕様だったのですが、なぜ変更したのでしょうか?

採掘が実行されてるかを確認するには、eth.hashrateコマンドで、現在の採掘処理のハッシュ・レートを確認します。

terminal

> eth.hashrate
2096

> eth.hashrate
66704

ハッシュ・レートがゼロよりも大きければ、採掘処理が行われていると考えます。続ければ続けるほど数値はどんどん上がっていきます。

採掘は時間がかかります。しかし、この記事ではdev環境で動かしているので、次々と採掘されます。

また、ログで確認する方法もあります。ログ出力フォルダの指定は起動時に行っておきましょう。dockerの場合は、terminalでps接続で確認できます。

terminal

docker exec -it {name} /bin/sh

採掘状況の確認

ブロックは次々と採掘されていきます。ブロックチェーンに何番目のブロックまで連なっているのか(=ブロック高)を確認するには、eth.blockNumberコマンドを用います。

terminal

> eth.blockNumber
65
> eth.blockNumber
68
> eth.blockNumber
81
> eth.blockNumber
117

> eth.blockNumber
123

必要な数のブロックを採掘したら、採掘を停止します。

terminal

> miner.stop()
true

採掘したブロックの情報を確認します。

123のブロックを採掘したので、123番目のブロックを確認します。

terminal

> eth.getBlock(123)
{
  difficulty: 139055,
  extraData: "0xd583010702846765746885676f312e39856c696e7578",
  gasLimit: 4712388,
  gasUsed: 0,
  hash: "0x8409ba210cf0a933321c9fc9b1d54dd4b39d98833fa412417ab88c6336603be0",
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  miner: "0x7a05d8030738af4ffe794d8b3d3b86ee28e11318",
  mixHash: "0xb090804669ad4b7922f63f4ed91c05f1dabb29ff609695bd6018de2002a01f05",
  nonce: "0x584cd0329f0dd51d",
  number: 123,
  parentHash: "0x07599d3aeb1dd4f9fb322326e68f89e5bc2cb6a260a82a504ee74929a2f86fab",
  receiptsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  size: 533,
  stateRoot: "0x4eab6ed2c31249285c576d0d79bf629bb811750f31e671f71ff0937a2da29aef",
  timestamp: 1509576985,
  totalDifficulty: 16739304,
  transactions: [],
  transactionsRoot: "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  uncles: []
}

まだ採掘されていない124番目のブロックを確認してみます。

terminal

> eth.getBlock(124)
null

報酬の確認

採掘した報酬を確認します。

terminal

> eth.getBalance(eth.accounts[0])
369000000000000000000

eth.getBalance(address)は「wei」の単位で出力します。単位をethに変換してみましょう。

terminal

> web3.fromWei(eth.getBalance(eth.accounts[0]),"ether")
369

送金

送金の仕組みを理解します。
各アカウントの残高を確認します。

terminal

> eth.getBalance(eth.accounts[0])
369000000000000000000
> eth.getBalance(eth.accounts[1])
0

eth.accounts[0]からeth.accounts[1]に2ether送金してみます。
eth.sendTransactionコマンドを用います

送金の際は、採掘処理をバックグラウンドで実行しておく必要があります。また、ロックの解除も必要です。

terminal

// 採掘
miner.start()

// ロック解除 パスワードが必要
personal.unlockAccount(eth.accounts[0])

// 送金の実行。 パスワードは不要
eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(4, "ether")})

// 確認
eth.getBalance(eth.accounts[1])

4000000000000000000

今度は逆にaccounts[1]からaccounts[0]に送金します。

terminal

// 採掘
> miner.start()
null

// ロック解除 パスワードが必要
> personal.unlockAccount(eth.accounts[1])
Passphrase: 
true

// 送金の実行。 パスワードは不要
> eth.sendTransaction({from: eth.accounts[1], to: eth.accounts[0], value: web3.toWei(2, "ether")})
"0xa0f782ee4245e886f9d79cf682006ac479857b8f43bba3d5b3df022f18cecc30"

// 確認
> eth.getBalance(eth.accounts[1])
2000000000000000000

トランザクションを調べます。sendTransaction時に発行されたハッシュを使います。

terminal

> eth.getTransaction("0xa0f782ee4245e886f9d79cf682006ac479857b8f43bba3d5b3df022f18cecc30")
{
  blockHash: "0x2756e0ac42054df3f792b6861f16a9b19392c66b149d6a54dee56eee3ca5eeda",
  blockNumber: 315,
  from: "0xd286d2666015e7a36d5826bd49f83af4ea922f52",
  gas: 90000,
  gasPrice: 0,
  hash: "0xa0f782ee4245e886f9d79cf682006ac479857b8f43bba3d5b3df022f18cecc30",
  input: "0x",
  nonce: 0,
  r: "0xbba0222bb19a7ad54cb5fd0f9512f256285caeaa98ddb396ed1b256b0e8dab54",
  s: "0x2d5329ce25e69ad94709f302c972071cab2a5363bdffacdb19fdb11986ddda71",
  to: "0x7a05d8030738af4ffe794d8b3d3b86ee28e11318",
  transactionIndex: 0,
  v: "0xa95",
  value: 2000000000000000000
}

トランザクションが表示されました。gasPriceが0なので、トランザクションを生成した際に採掘者に対して支払うトランザクション手数料は無料になっていますね。

Contract

やってみたけど、情報が古くてうまくいかないので、penddingします。今はSolcが使えなくなっているので、情報を集める時は注意してください。

まとめ

実際に手を動かすと、ethereumの基本が理解できました。
とはいえ、騒がれているほどの凄さは感じなかったので、これからも少しづつブロックチェーンの学習を進めていきたいと思います。
railsやスマホのように化けて役立ってくれるかもしれないので。。。

以上。

PICK UP オススメ書籍

運営サイト


参考記事

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2017年8月13日日曜日

【機械学習】AnacondaでOpenCVをinstallする

  • 公開日:2017年08月13日

記事概要

機械学習の環境をdockerで生成して、opencvをinstallする方法を記載した記事です。

環境

  • Docker version 17.06.0-ce
  • ubuntu 16.04.2 LTS
  • Python 3.6.1 :: Anaconda custom (64-bit)

opencvインストール

opencvをAnacondaでインストールします。

terminal

conda install -c https://conda.anaconda.org/menpo opencv3

これだけでopencvを実行しようとすると

terminal

ImportError: libgtk-x11-2.0.so.0: cannot open shared object file: No such file or directory

が発生しました。
なので、以下のように対応します。

terminal

apt-get update
apt-get install libgtk2.0-0

これでopencvが動きます。

サンプルのopencv.pyファイルを作成して実行します。

opencv.py
# -*- coding: utf-8 -*-
import cv2

def main():
  print(cv2.__version__)

if __name__ == "__main__":
  main()

terminal

python opencv.py
3.1.0

opencvが動作しました。

PS : apt-get install libgtk2.0-0を実行してもdbusのエラーは残ります。conda install dbusしても修正されません。。。調べてみると、ubuntuでは色々と問題があるみたいですね。apt-get updateを実行しても問題ないようなので、このまま利用します。

まとめ

opencvをdockerとubuntuで利用するのは、あまり相性が良くないようです。opencvが古いバージョンだとうまくいくという情報もあるみたいなので、そちらを利用してもいいでしょう。
しかし、pythonの環境構築はRubyよりひどい気がします。定期的なライブラリの更新とかできるのでしょうか。

PICK UP オススメ本

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2017年7月30日日曜日

【Docker】UnicodeEncodeError: 'ascii' codec can't encode characters in position. Dockerのターミナルで日本語を使う

  • 公開日:2017年07月30日

記事概要

機械学習の環境をdockerで生成して、ターミナルに日本語を出力処理するとエラーが発生します。
この記事はdockerで日本語を出力する方法を記載した記事です。

環境

  • Docker version 17.06.0-ce
  • ubuntu 16.04.2 LTS
  • Python 3.6.1 :: Anaconda custom (64-bit)

ターミナル

dockerのubuntu環境だと、デフォルトでターミネルの日本語の出力ができません。
MeCabなどを使ってprintで文字を出力しようとすると、
'ascii' codec can't encode characters in position
が発生します。

これだと使いにくいので、dockerのターミネルで日本語を利用できるようにします。

locale変更

localeを日本語に変更します。

terminal

locale

LANG=
LANGUAGE=
LC_CTYPE="POSIX"
LC_NUMERIC="POSIX"
LC_TIME="POSIX"
LC_COLLATE="POSIX"
LC_MONETARY="POSIX"
LC_MESSAGES="POSIX"
LC_PAPER="POSIX"
LC_NAME="POSIX"
LC_ADDRESS="POSIX"
LC_TELEPHONE="POSIX"
LC_MEASUREMENT="POSIX"
LC_IDENTIFICATION="POSIX"
LC_ALL=

dockerのデフォルトは、POSIXです。なので、日本語にします。

terminal

export LC_ALL=ja_JP.UTF-8

変更を確認します。

terminal

locale
LANG=
LANGUAGE=
LC_CTYPE="ja_JP.UTF-8"
LC_NUMERIC="ja_JP.UTF-8"
LC_TIME="ja_JP.UTF-8"
LC_COLLATE="ja_JP.UTF-8"
LC_MONETARY="ja_JP.UTF-8"
LC_MESSAGES="ja_JP.UTF-8"
LC_PAPER="ja_JP.UTF-8"
LC_NAME="ja_JP.UTF-8"
LC_ADDRESS="ja_JP.UTF-8"
LC_TELEPHONE="ja_JP.UTF-8"
LC_MEASUREMENT="ja_JP.UTF-8"
LC_IDENTIFICATION="ja_JP.UTF-8"
LC_ALL=ja_JP.UTF-8


これで完了です。pythonのMecabを実行して確認します。

terminal

python tolenize_ja.py
第 9 9 回 全国 高校 野球 選手権 埼玉 大会 は 、 花咲 徳 栄 が 3 年 連続 5 回 目 の 優勝 を 果たし 、 県内 1 5 6 チーム ( 1 6 1 校 ) の 頂点 に 立っ た 。 

正常に日本語が出力されました、

まとめ

機械学習の環境にDockerを使うのは、とても良い選択です。Dockerの学習は慣れるまで大変ですが、使えば使うほど生産性も向上するので、ぜひ利用してください。

PICK UP オススメ本

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2017年7月9日日曜日

【Rails5.1.2】 Rails5.1.0からRails5.1.2にアップグレードする。

  • 公開日:2017年07月09日

記事概要

気づいたらRails5.1.2がリリースされたのでアップグレードしました。まとめ記事です。

環境

  • centos6.5
  • Rails5.1.0 → Rails5.1.2
  • ruby2.3.0
  • rbenv
  • unicorn
  • whenever

移行用の作業branchの作成

gitでrails5.1.2移行用の作業ブランチを作成します。

terminal

cd {project_folder}
git branch feature/rails5.1.2

checkoutでブランチを切り替えます。

terminal

git checkout feature/rails5.1.2

準備完了です。

Gemfile修正

まずGemfileを修正します。

{project_folder}/Gemfile

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '5.1.0'

↓

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '5.1.2'

gem 'rails', '5.1.2'に修正し、updateします。

terminal

// update
bundle update 

bundle updateは、全ての依存関係をインストール・ダウンロードし直すことができます。

Bundle updated!が表示されれば成功です。5.1.0に対応してあれば、bundle updateはひっかからないはずです。

Upgrade 設定ファイル

Gemファイルの導入が完了したら、rails app:updateで設定ファイルを更新します。

terminal

bundle exec rails app:update

ファイル更新の有無を聞かれるので、更新が必要なファイルのみ変更します。
私の環境では以下のようにしました。

  • config/routes.rb → 更新しない
  • config/application.rb → 更新しない
  • config/secrets.yml → 更新しない
  • config/cable.yml → 更新する
  • config/puma.rb → 更新する
  • config/environments/development.rb → 更新しない
  • config/environments/production.rb → 更新しない
  • config/environments/test.rb → 更新しない
  • config/initializers/assets.rb → 更新しない
  • config/initializers/new_framework_defaults.rb → 更新しない
  • bin/setup → 更新する
  • bin/update → 更新する

更新後は、git diffでファイルを比較して必要な設定だけ元に戻します。
5.1.2は5.1.0とほとんど差異がありません。更新の目的はセキュリティアップデートとなります。

Rails5.1.2起動

アプリを起動します。

terminal

rbenv exec bundle exec rails s -b 0.0.0.0
=> Booting WEBrick
=> Rails 5.1.2 application starting in development on http://0.0.0.0:3000
=> Run `rails server -h` for more startup options
[2017-07-09 02:44:22] INFO  WEBrick 1.3.1
[2017-07-09 02:44:22] INFO  ruby 2.3.0 (2015-12-25) [x86_64-linux]
[2017-07-09 02:44:22] INFO  WEBrick::HTTPServer#start: pid=23651 port=3000

コンソールにRails 5.1.2 applicationが表示され、画面が表示されれば成功です。

だいたいここまでで10分くらいです。あとは、テストコードを実行してデグレを確認します。

terminal

bundle exec rspec

Finished in 2 minutes 4.6 seconds (files took 7.11 seconds to load)
237 examples, 0 failures, 15 pending

問題ありませんでした。DEPRECATION WARNINGも発生せず。

リリース

capistrano3を使っていつも通りリリースすればOKです。少し時間がかかります。一通りの動作確認はしておきましょう。

まとめ

Rails5.1.0からRails5.1.2のアップデートは、20分もあれば完了します。
さっさと更新しておきましょう。

以上です。

PICK UP オススメ書籍

運営サイト(railsで作成しています)


この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加
Related Posts Plugin for WordPress, Blogger...