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で作成しています)


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

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

2017年7月8日土曜日

【Docker】DockerでWEBフロント開発の環境を構築

  • 公開日:2017年07月08日

記事概要

今はjavascriptやcssの開発でもコンパイル環境が必要になってきました。

この記事は、Dockerでフロント開発の環境を構築する方法を記載しました。webpackとbabel(とreactやvueやbackborn)を使って開発することを前提に構築します。
汎用性は求めていないので、dockerファイルは使いません。あくまでメインマシンを汚さないために、dockerで開発環境を用意します。

環境

  • macOS Sierra
  • docker 17.06.0-ce
  • Ubuntu 16.04.2 LTS
  • nvm 0.33.2
  • node v8.1.3
  • webpack 3.1.0

前提

  • dockerをインストール済み
  • webpackやbabelなどのライブラリの多少の知識がある

工数

blogを書きながらでも2時間くらいで構築できました。
私はAndroidとRailsアプリをメインで開発しているのでフロントは専門ではありませんが、慣れている人ならあっという間に終わると思います。

dockerコンテナ起動

利用するdockerイメージを確認します。

terminal(mac)

// フォルダ移動
cd /Users/dameotoko/workspace/docker

// dockerイメージの確認
docker images

ubuntu                    latest              d355ed3537e9        2 weeks ago         119MB

ubuntuのイメージを使います。
ttyでdockerを起動します。

terminal(mac)

// ttyで起動
docker run -v /Users/dameotoko/workspace/docker/react:/var/www -i -t ubuntu /bin/bash

オプション -v はVOLUME命令です。

Dockerコンテナ内の指定したパスをマウントできるように命令します。

ここではmacの/Users/dameotoko/workspace/docker/reactフォルダ配下と、dockerコンテナの/var/www配下を共有して開発するように指定しています。

共有できているか試してみます。

terminal(mac)

// mac
cd /Users/dameotoko/workspace/docker/react
touch index.html

// docker
cd cd var/www
ls -l
total 0
-rw-r--r-- 1 root root 0 Jul  8 06:07 index.html

macとdockerコンテナでファイルが連携されました。

nvmインストール

最新のnode.jsを使えるように、nvmをインストールします。
nvmは、rubyのrbenvとか、pythonのcondaと同じバージョン管理ツールです。 まずはsudoを利用可能にします。

terminal(docker)

apt-get update
apt-get install -y sudo

ソースパッケージをビルドするために必要なパッケージを事前にインストールします。

terminal(docker)

sudo apt-get install build-essential libssl-dev

curlをインストールします。

terminal(docker)

sudo apt-get install curl

nvmをインストールします。

terminal(docker)

// https://github.com/creationix/nvm
// DL
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.2/install.sh | bash

// shellを反映
source ~/.bashrc

nvm --version
0.33.2

nvmが正常にインストールされました。

nodeインストール

nodeをインストールします。

terminal(docker)

// 利用可能なバージョン確認
nvm ls-remote

v8.1.3

// install
nvm install 8.1.3

~/.nvm ディレクトリ配下に、指定したバージョンのnode.jsがインストールされます。

terminal(docker)

ls -l ~/.nvm/versions/node/
total 4
drwxr-xr-x 7 root root 4096 Jul  8 06:45 v8.1.3

デフォルトに設定されていることを確認します。

terminal(docker)

nvm ls
->       v8.1.3
default -> 8.1.3 (-> v8.1.3)
node -> stable (-> v8.1.3) (default)
stable -> 8.1 (-> v8.1.3) (default)


node -v
v8.1.3

npm -v
5.0.3

準備完了です。

プロジェクトHello world作成

サンプルとしてjsプロジェクを作成します。

terminal(docker)

// プロジェクトフォルダ
cd /var/www 

npm init -y

npm install --save-dev webpack babel-loader babel-core babel-preset-env babel-preset-react babel-preset-es2015

プロジェクトが作成されます。バージョン指定していないのでwebpackは3.1.0がインストールされました。
webpack.config.jsは自動作成されないので、生成します。

terminal(docker)

// 生成
touch webpack.config.js

設定を記載します。

root/webpack.config.js

module.exports = {
    // エントリポイント(最初に読まれるjs)
    entry: "./entry.js",
    // バンドルされたjsファイル(成果物)
    output: {
        // 出力先のパスを指定
        path: __dirname,
        // ビルド後のファイル名を指定
        filename: "bundle.js"
    },
    module: {
      loaders: [
        { 
          test: /\.js$/, 
          exclude: /node_modules/, 
          loader: "babel-loader", 
          query:{
            presets: ['react', 'es2015']
          }
        }
      ]
    }
};


webpack3だとloader: "babel-loader"になっているので注意してください。具体的な設定はここが参考になります。

簡単なHello worldアプリを作成します。
まずはエントリーポイントを作成します。

terminal(docker)

// 生成
touch entry.js

entry.jsを作成します。

続けてindex.htmlを作成します。

terminal(docker)

// 生成
touch index.html

htmlタグを記載します。

root/index.html

<!doctype html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <title>webpack tutorial</title>
    </head>
    <body>
        <div id="myapp"></div>
        <script src="bundle.js"></script>
    </body>
</html>

ビルドします。

terminal(docker)

npm run build

> www@1.0.0 build /var/www
> webpack

Hash: cc0f9a75acd498c84298
Version: webpack 3.1.0
Time: 2287ms
    Asset     Size  Chunks             Chunk Names
bundle.js  2.51 kB       0  [emitted]  main
   [0] ./entry.js 13 bytes {0} [built]

babelを使ってMessageクラスを作成します。

terminal(docker)

// 生成
touch message.js

コードを記載します。

message.js

class Message {
    constructor(msg) {
        this.msg = msg;
    }
}
export default Message;

エントリーポイントで利用します。

entry.js

import Message from './message';

var message = new Message('Hello world');
console.log(message);

htmlをブラウザで開いてコンソールログを確認します。

console

Message {msg: "Hello world"}
msg
:
"Hello world"
__proto__
:
Object

うまくいきました。あとはアプリの開発をするだけです。

まとめ

webpackやbabelを使った開発ができるフロントエンジニアはまだ少ないみたいです。フロントができるといいながら、jqueryしかできない人を未だによく見かけます。時代をちゃんと追いかけましょう。

今後は他の言語と同じように開発環境の構築が求められていくはずです。複雑そうに見えますが、実際に触ってみるとそれほど難しくないので、定期的にキャッチアップしていくといいと思います。
今から学習するなら、TypeScriptとReactの組み合わせが、一番良い選択だと思います。

また、開発環境はdockerじゃなくてvagrantでも良いと思います。ただ、dockerの方が簡単だと(個人的に)思います。

また、サーバーエンジニアやスマホのネイティブエンジニアもフロントを触ってみてください。色々と知識を応用できるようになってきているので、定期的に簡単なアプリを作ると良いと思います。

以上です。

PICK UP オススメ書籍

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


参考記事

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

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

2017年6月16日金曜日

[js] webpack webpack2をインストールする

  • 公開日:2016年06月16日

記事概要

ついにrailsでもwebpackが導入されました。この記事はwebpack2のインストール方法を記載した記事です。
ここではgemを使わずに導入する方法を説明します。最初はgemを利用しない使い方を覚えた方が、長い目で見て良いと思います。
環境はcentos6.5です。

環境

  • centos6.5

webpackとは

webpackは、アプリケーションでJavaScriptモジュールをビルドするためのツールです。

nodeのインストール

まずはnode.jsをインストールします。ここでは最新版を導入します。
centos6.5はデフォルトだと古いバージョンのnode.jsをインストールしてしまうので、curlで最新のnodeを取得可能にしておく必要があります。

terminal

sudo curl --silent --location https://rpm.nodesource.com/setup_8.x | bash -

sudo yum install nodejs

node -v
v8.1.0

npmのインストール

npmをインストールします。同じく最新版を導入します。

terminal

sudo yum install npm
sudo rpm -ivh http://ftp.iij.ad.jp/pub/linux/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm
sudo yum -y install nodejs npm --enablerepo=epel
sudo npm install -g npm

npm -v
5.0.3

以上でwebpackを導入する準備は終了です。

プロジェクトの作成とwebpackのインストール

プロジェクトを作成します。

terminal

mkdir study2
cd study2
// -yはpackage.jsonのデフォルトのみが使用されて、オプション入力プロンプトは表示されない
npm init -y
// webpackとローカルサーバー
npm install --save-dev webpack webpack-dev-server

モジュールはグローバルでなく、--save-devをつけてプロジェクト別に管理することが推奨されています。

package.json

package.jsonにはビルドコマンドだけ追記します。

study2/package.json

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },

npm run buildコマンドでビルドが可能になります。

webpack.config.js

最後にwebpack設定ファイルのwebpack.config.jsを作成します。

terminal

touch webpack.config.js

module.exports = {
    // エントリポイント(最初に読まれるjs)
    entry: "./entry.js",
    // バンドルされたjsファイル(成果物)
    output: {
        path: __dirname,
        filename: "bundle.js"
    }
};

touch entry.js

以上でwebpack2の導入は完了です。あとはプロジェクトに応じたライブラリを導入して素敵なJavaScriptライフを送ってください。

まとめ

webpack2はとても便利なjsの管理ツールです。
初めての使用でも、2-3時間で最低限の機能くらいは使えるようになるので、ぜひ導入してみてください。

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

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

2017年5月27日土曜日

【Android7.1】Architecture componentsの調査。AppCompatActivityでLifecycleを利用する

  • 公開日:2017年05月27日

記事概要

Google I/O 2017でandroid-architecture-componentsが発表されました。
なかなか良さそうなライブラリだったので、導入して動かしてみました。

この記事は、android-architecture-componentsを触って感じたことを記載した記事です。

環境

  • buildToolsVersion 25.0.3
  • android.arch.lifecycle 1.0.0-alpha1

lifecycleとは

ActivityやFragmentのライフサイクルに合わせてデータを管理できるライブラリです。
ドキュメントを読んでgoogle code labのサンプルを実装した感じでは、以下のような感想を持ちました。

良い点
  • オブジェクトをActivityやFragmentのライフサイクルに関連づけられるのが良い。onDestory()等の処理が楽になりそう。アプリの停止や生存チェックが減りそう。
  • SNSや通知アプリなどのpub, subを利用するアプリが作りやすくなりそう。RxJavaのFlowableを使うとよりよくなりそう。
  • 縦画面と横画面の作り分けが楽になる。これが一番大きい。
  • Roomは、ibatisに似ている。経験者はすぐに使いこなせるのではないだろうか。RxJavaと連携もできる。
悪い点
  • Observerクラス増えすぎ。どのライブラリもObserverとSubscribeで溢れている。可読性がさらにひどくなる。。
  • 開発者に要求されるハードルがまた上がる。

触った印象では、難しくはないので、考え方に慣れることが大事なのかなと思いました。

実装

1.0.0-alpha1のLifecycleActivityはFragmentActivityを継承しているクラスなので、AppCompatActivityクラスを継承したActivityクラスでは利用できません。かといってLifecycleActivityをそのまま利用するのは機能不足すぎで話になりません。しかも、This class is a temporary implementation detail until Lifecycles are integrated with support library.とあるように、LifecycleActivityは一時的な実装なので利用する意味がありません。
なので、以下のように改造します。

変更前
{project_folder}/MainActivity.java

public class MainActivity extends AppCompatActivity implements HomeFragment.OnFragmentInteractionListener, {

    public static final String TAB_HOME = "TAB_HOME";
    public static final String TAB_COLLECTION = "TAB_COLLECTION";
    public static final String TAB_NOTICE = "TAB_NOTICE";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    // something...
}

変更後
{project_folder}/MainActivity.java
public class MainActivity extends AppCompatActivity implements LifecycleRegistryOwner, HomeFragment.OnFragmentInteractionListener, {
    private final LifecycleRegistry mRegistry = new LifecycleRegistry(this);

    @Override
    public LifecycleRegistry getLifecycle() {
        return mRegistry;
    }

    public static final String TAB_HOME = "TAB_HOME";
    public static final String TAB_COLLECTION = "TAB_COLLECTION";
    public static final String TAB_NOTICE = "TAB_NOTICE";

    public static final String TAB_HOME = "TAB_HOME";
    public static final String TAB_COLLECTION = "TAB_COLLECTION";
    public static final String TAB_NOTICE = "TAB_NOTICE";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    // something...
}

LifecycleRegistryOwnerをimplementsしてLifecycleRegistryのインスタンスをもたせます。これで、AppCompatActivityでも利用可能になります。
あとはViewModelProvidersを使えば、ViewModelのオブジェクトを管理できます。

Activityに付加したFragmentでViewModelを管理する場合は、以下のように実装します。

{project_folder}/HomeFragment.java
public class HomeFragment extends Fragment {
    public static final String TAG = "HomeFragment";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        homeModel = ViewModelProviders.of(getActivity()).get(HomeModel.class);
    }

    // something...
}

これにより、画面の回転などでonCreate()の再呼び出しをしてもViewModelを継承したモデルから値を取得することが可能になります。

結論

android-architecture-componentsはsupport libraryと同様、デファクトのライブラリになりそうな気がします。

この他にも、通知やDBでも活躍できそうなので、色々と試していきたいですね。

PICK UP

運営サイト


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

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

2017年5月20日土曜日

[git] squashでコミットをまとめる

  • 公開日:2017年05月20日
  • 最終更新日:2017年11月29日

記事概要

gitのsquashを使ってコミットをまとめる時のやり方。ターミナルコマンドを使います。

環境

  • git version 2.6.4

やりたいタスク

直近4つのコミットを一つにまとめます。
対象は色々な修正を加えたsample.txtです。

terminal

// コマンド
git log --oneline

a108a12 sample/feature completed.
ba18359 deleted comment.
a7711e0 updasted comment.
adf6be6 added comment.
2ca3f88 first commit

直近a108a12からadf6be6までの4つのコミットをまとめて、直近a108a12のコメントに変更します。
開発現場でよくあるパターンです。

順序

rebaseコマンドで直近の4つのコミットを選択します。

terminal

// コマンド
git rebase -i HEAD~4

pick adf6be6 added comment.
pick a7711e0 updasted comment.
pick ba18359 deleted comment.
pick a108a12 sample/feature completed.

# Rebase 2ca3f88..a108a12 onto 2ca3f88 (4 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

古いコミット順で表示されるので、注意してください。一番古いコミット以外をsに変更します。

terminal

pick adf6be6 added comment.
s a7711e0 updasted comment.
s ba18359 deleted comment.
s a108a12 sample/feature completed.

一番古いコミット以外をsに変更します。最初(一番古い)のコミットはsにしてはいけません。sを指定したコミットの内容が、前のコミットに統合(melt)されるイメージです。時系列が逆なので最初は理解しにくいですが、仕様なので慣れてください。
修正したら:wqで上書き保存します。

コミット内容が表示されます。

terminal

# This is a combination of 4 commits.
# The first commit's message is:
added comment.

# This is the 2nd commit message:

updasted comment.

# This is the 3rd commit message:

deleted comment.

# This is the 4th commit message:

sample/feature completed.

残したいコミットメッセージ以外を削除します。もちろんメッセージを変更しても問題ありません。

terminal

# This is a combination of 4 commits.
# The first commit's message is:

# This is the 2nd commit message:


# This is the 3rd commit message:


# This is the 4th commit message:

sample/feature completed.

変更したら:wqで上書き保存します。

terminal

Successfully rebased and updated refs/heads/master.

成功です。ログを確認します。

terminal

// コマンド
git log --oneline

4a709e3 sample/feature completed.
2ca3f88 first commit

綺麗にログがまとまりました。

ログの内容をすでにpull requestしている場合は、force pushすれば強制的に上書きできます。(他の人がファイルをいじってないことを確認しましょう)

取り消し

rebaseで間違ってしまった場合は、以下のように修正します。

terminal

git rebase --abort

例えば、merge conflictで修正箇所をまとめる時に、最初のmergeまで入れてrebaseしてしまったとか。。。ですかね。
これで元どおりになります。

サーバーのbranchを消す

terminal

// ローカルbranchを削除
git branch -D branchName

// サーバーに反映
git push origin :branchName

まとめ

gitはとても便利なのですが、ググっても間違った情報が引っかかるケースが多いと思います。
周りの人に聞いたり、公式サイトを利用して正しく効率的なやり方を身につけてください。

PICK UP オススメ書籍

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

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

2017年5月6日土曜日

【Unity5.6.0f3】error CS0234: The type or namespace name `CrossPlatformInput' does not exist in the namespace.

  • 公開日:2017年05月06日

記事概要

Unityの学習中に発生したエラーの解決メモ。

環境

  • macOS Sierra
  • Unity5.6.0f3

発生

Unityのチュートリアルでキャラクターを配置したらerror CS0234: The type or namespace name `CrossPlatformInput' does not exist in the namespaceが発生しました。

原因

エラーの通りCrossPlatformInputがインポートされていないためです。

修正方法

AssetsにCrossPlatformInputを追加します。

fig1:CrossPlatformInputを追加

AssetsにCrossPlatformInputが追加されていることを確認します。

コンパイルが可能になり、動作が確認できるようになります。

fig3:play

動作が確認できました。

PICK UP オススメ書籍

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


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

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

2017年5月5日金曜日

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

  • 公開日:2017年05月05日

記事概要

ようやくRails5.1.0がリリースされたのでアップグレードしました。まとめ記事です。

環境

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

はじめに

Rails5.1.0は、Rails5.0.x系と比較すると変更点が多いです。以前の記事で5.0.x系との差異を記載しているのでそちらを参考にしてください。

移行用の作業branchの作成

以前の記事で記載しているように、2ヶ月ほど前にRails5.1.0 beta1で、移行テスト済みなので一気に作業をやっていきます。
Railsのバージョンアップをする場合は、betaの段階で1度テストをしておくことをお勧めします。

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

terminal

cd {project_folder}
git branch feature/rails5.1.0

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

terminal

git checkout feature/rails5.1.0

準備完了です。

Gemfile修正

まずGemfileを修正します。

{project_folder}/Gemfile

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

↓

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

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

terminal

// update
bundle update 

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

Bundle updated!が表示されれば成功です。5.0.1に対応してあれば、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でファイルを比較して必要な設定だけ元に戻します。

config/environments/production.rb

Rails5.1.0では、config.read_encrypted_secrets = trueが追加されました。
暗号の管理方法が変わりました。

既存のsecrets.ymlでも動くので、Encrypted secretsの導入は少し待ってからの方が良いかもしれません。これだと管理が煩雑になって、まだデメリットの方が多い気がします。

Rails5.1.0 Encrypted secretsの対応

暗号の管理方法が変更されたので対応します。terminalを開きます。

terminal
bin/rails secrets:setup

config/secrets.yml.key
append  .gitignore
create  config/secrets.yml.enc

You can edit encrypted secrets with `bin/rails secrets:edit`.
Add this to your config/environments/production.rb:
config.read_encrypted_secrets = true

これだけです。パスワードの入ったsecrets.yml.keyファイルは、.gitignoreに自動で追加されます。 config/secrets.yml.encはgitで管理可能です。pushしてもOKです。

また、config/environments/production.rbにconfig.read_encrypted_secrets = trueが追加されていることも確認してください。
あとは、本番でconfig/secrets.yml.keyのuploadを忘れないようにしましょう。開発環境で有効にする必要はないとは思いますが、本番と同じにしたい人はconfig.read_encrypted_secrets = trueを追加しても良いと思います。

secrets.yml.keyは紛失しないように忘れずに別管理にします。(この辺がセキュリティのためとはいえ納得いかないとこですね。面倒くさい。)

Rails5.1.0 rails-ujs対応

rails-ujsを導入すれば、jquery_ujsが不要になります。jqueryの処理に依存している人は、jqueryの処理も書き換える必要があります。時間をとって乗り換えましょう。

config/environments/development.rb
# Use jquery as the JavaScript library
#gem 'jquery-rails'

gem 'rails-ujs'

インストールします。

terminal

// update
bundle update 

Installing rails-ujs 0.1.0

インストールしたら、application.jsを修正します。

assets/javascript/application.js

//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require_tree .

↓

//= require rails-ujs
//= require turbolinks
//= require_tree .

せっかく書き換えるなら、今だとTypeScriptに変更するのがいいのではないでしょうか。

Rails5.1.0起動

アプリを起動します。

terminal

rbenv exec bundle exec rails s -b 0.0.0.0
=> Booting WEBrick
=> Rails 5.1.0.beta1 application starting in development on http://0.0.0.0:3000
=> Run `rails server -h` for more startup options
[2017-03-20 14:24:05] INFO  WEBrick 1.3.1
[2017-03-20 14:24:05] INFO  ruby 2.3.0 (2015-12-25) [x86_64-linux]
[2017-03-20 14:24:05] INFO  WEBrick::HTTPServer#start: pid=10639 port=3000

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

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

terminal

bundle exec rspec

Finished in 1 minute 58.72 seconds (files took 7.84 seconds to load)
230 examples, 0 failures, 14 pending

問題ありませんでした。DEPRECATION WARNINGで修正可能なエラーは今のうちに修正します。Rails5.2.0の対応も済ませてしまいましょう。

capistrano

capistranoも修正します。config/secrets.yml.keyにもSymbolic linkが作成されるようにします。

config/deploy.rb

set :linked_files, %w{config/database.yml}

↓

# Default value for :linked_files is []
set :linked_files, %w{config/database.yml config/secrets.yml.key}

ググるとupload処理をconfig/deploy.rbに記述しているケースをちょくちょく見かけます。この場合、ファイルがないとdeploy:checkが通らなくなるので、やらない方が良いと思います。ファイルは直接アップロードしておくのがcapistranoの仕様になってます。フォルダは自動生成してくれますが、ファイルはしてくれません。

リリース

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

まとめ

Rails5.0.1からRails5.1.0のアップデートは、それなりに手間がかかると思います。特にフロントエンドが複雑なWEBアプリだと苦戦するかもしれません。
私は既にRails5.1.0にアップロードしましたが、Fix版が出て安定してからでも良いかなと思いました。

あとはそろそろ、Ruby2.4.0への更新とリファクタリングも済ませてしまうと良いでしょう。

あとはdockerがいい感じに枯れてきたので、そろそろ本番で使っても良いかもしれないですね。

以上です。

PICK UP オススメ書籍

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


関連記事

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

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