クロコめも2。

ただのめもー

Swift2とSwift3の違いメモ

ほんきで学ぶSwift+iOSアプリ開発入門 写経中メモ

この本はSwift2で書かれているのでSwift3の環境だとそのまま動かない。

URLを使って画像を表示する

Swift2

let url = NSURL(string: "http://hogehoge.png")!
let imageData:NSData = NSData(contentsOfURL: url!)!
let image2 = UIImage(data:imageData);

Swift3

let url = URL(string: "http://hogehoge.png")!
let imageData = try? Data(contentsOf: url)
let image2 = UIImage(data:imageData!)

NSURLがURL、NSDataがDataに変わった模様。そしてtry-catch使わないと怒られるようになった模様

CGRectMakeが無くなっている

// CGRectMake関数を用意してSwift2と同じように呼べるようにする
func CGRectMake(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) -> CGRect {
    return CGRect(x: x, y: y, width: width, height: height)
}
var button = UIButton(frame: CGRectMake(0,0,100,50))

// CGRectを使う。
var button2 = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))

XCPlaygroundが無くなっている

Swift3

import UIKit
import PlaygroundSupport

let datePicker = UIDatePicker()
datePicker.datePickerMode = UIDatePickerMode.date
datePicker.backgroundColor = UIColor.white
PlaygroundPage.current.liveView = datePicker

Vue2 + TypeScript2 を使ったサンプル

やりたいこと

vue.js2ではTypeScriptに対応したらしいのでどんなもんなのかを試したい。

試すものたち

  • vue.js 2.0.3
  • vuex
  • typescript 2.0.3
  • vue-ts-loader
  • av-ts
  • kilimanjaro

参考サイト

http://herringtondarkholme.github.io/2016/10/03/vue2-ts2/

作ってく

プロジェクトの作成

mkdir vue-ts-test
cd vue-ts-test
npm init -y
npm i -S vue typescript

ここまででpackage.jsonとnode_modulesが出来ている

STEP1:テンプレートのindex.htmlとちっちゃいVue

index.html

<div id="app"></div>
<script src="node_modules/vue/dist/vue.js"></script>
<script src="app.js"></script>

app.ts

declare var Vue: any
new Vue({
    el: '#app',
    render(h) {
        return h('h1', 'hello world')
    }
})

app.tsをコンパイルする

./node_modules/.bin/tsc app.ts

ブラウザでindex.htmlを開き"hello world"が表示されることを確認する

STEP2: webpack使って.vueファイルでコンポーネントを作る

npm i -D webpack vue-loader css-loader
npm i -D vue-ts-loader

webpack.config.js

module.exports = {
    entry: { app: './app.ts', },
    output: { filename: 'app.js' },

    // resolve TypeScript and Vue file
    resolve: {
        extensions: ['', '.ts', '.vue', '.js']
    },

    module: {
        loaders: [
            { test: /\.vue$/, loader: 'vue' },
            { test: /\.ts$/, loader: 'vue-ts' }
        ],
    },
    vue: {
        // instruct vue-loader to load TypeScript
        loaders: { js: 'vue-ts-loader', },
        // make TS' generated code cooperate with vue-loader
        esModule: true
    },
}

app.vue

<template>
<h1 @click="hello">hello world</h1>
</template>

<script>
export default {
    methods: {
        // type annotation!
        hello(): void {
            alert('hello world')
        }
    }
}
</script>

app.ts

declare var require: any

import Vue = require('vue')
var App = require('./app.vue').default

new Vue({
    el: '#app',
    components: { App },
    render: h => h('app')
})

ここでwebpackコマンドでコンパイルしてindex.htmlを表示したときにhello worldをクリックしてアラートが出ればOK

STEP3:もっと型を

npm i -S av-ts

app.vueを改造

<template>
<h1 @click="hello">hello {{name}}</h1>
</template>

<script>
// av-tsからVue関連のインポート
import {Vue, Component} from 'av-ts'

@Component
export default class App extends Vue {
name = 'kuroko'
// type annotation!
hello(): void {
    alert('hello ' + this.name)
}
}
</script>

ここでwebpackコマンドを叩いて動作確認

STEP4:Vuex導入

npm i -S kilimanjaro

store.tsの追加

import { create } from 'kilimanjaro'

var store = 
create({count: 0})
.getter('count', s => s.count)
.mutation('increment', s => () => s.count++)
.mutation('decrement', s => () => s.count--)
.done()

export default store

app.vue修正

<template>
<h1 @click="hello">hello {{name}} now count is {{count}}
<button @click.stop="add">+</button>
<button @click.stop="sub">-</button>
</h1>
</template>

<script>
// av-tsからVue関連のインポート
import {Vue, Component} from 'av-ts'
import {Vuex, getHelper} from 'kilimanjaro'
import store from './store'

const { getters, commit } = getHelper(store)

@Component
export default class App extends Vue {
@Vuex count: number = getters('count')
@Vuex add:Function = commit('increment')
@Vuex sub:Function = commit('decrement')
name = 'kuroko'
// type annotation!
hello(): void {
    alert('hello ' + this.name)
}
}
</script>

webpackコマンドを叩いて動作を確認する。

webpackコマンドを叩くとerror TS2304: Cannot find name 'Promise'.というエラーがいくつがでる。

単純にこのエラーを消したい場合はtsconfig.jsonのcompilerOptions.targetをes6に変えればエラーは出なくなる。

しかし、それが根本的な解決なのかはわからない。

次に確認したいこと

vue-cliのwebpack相当の構成でnpm run devデバッグしながらリアルタイムにプレビューできるようにするにはどうすればよいのかを調べたい。

が・・・ちょっとvue-cliで生成したプロジェクトを使って改造していくのは僕には歩幅が大きすぎて挫折したので小さくすすめる。

  • フォルダ構成を./srcとか./src/componentsとか./src/storeとかにわけれるようにしたい
  • sass使えるようにしたい
  • TypeScript -> ES5じゃなくてTypeScript -> ES6 (babelで) -> ES5にしたい。TypeScriptでES6チックにかければ不要か?
  • propなど今回使用していないvueの機能はどうやって書くのかを調べたい

今回のサンプルを作ってみてまだわからないこと

  • webpack.config.jsにあるvue:の指定は一体なんなのか?
  • vuexのgitterとかあんまり馴染みがない(ただの勉強不足)
  • tsconfig.jsonの中身全般。そもそもTypeScriptに関する知識が殆ど無い。

最近やったことやら色々メモ

  • haskell挫折中。タイミングを見てまた集中して学習したい。
  • やりたいこととに対してSpring batchはtoo much だったので素のSpringを使うことにした。
  • Springのトランザクション周り(requires_newしたときのテストの書き方とか)いろいろ面倒だった。
  • ラムダ乱用は良くないと思うけど、まず乱用できるほどラムダの使い方わかってない
  • Doma2良かった。
  • Gradleでマルチプロジェクトできたけどプロダクトのバージョン管理とかよくわからん。
  • githubとgitに関して簡単な操作はできるようになったけどまだあまり理解できていない
  • java8っぽい書き方をなんとなくわかるようになってきた。がまだまだ。
  • 年内はSwiftやiOS関係の開発についてお勉強することにした。
  • Dockerをちゃんと理解して開発時のDBとかそのた環境まわりとかをスマートに準備したいなぁ
    • Docker for mac発表されてからだいぶ経ったけど全然さわれてないわ
    • Docker上にCI環境作っておいてgithubにPushしたらテスト動いてくれるようになんないかな
  • Typescript2がリリースされたけど全然チェックできてないわ
  • Vue.jsの2が発表リリースされたけど全然チェックできてないわ
  • 軽度肥満から標準体型になったぞー

jacksonでunix timeをparse

どうやるんだろ?

文字列としてparseしてLocalDateTimeに変換してくれるgetterを作るぐらいしかパッと作れない。

yyyy-mm-ddとかそういうフォーマット指定する例はいろいろ出ててわかるんだけど、unix timeの10桁の数字をLocalDateTimeに変換する方法がわからないーーー

吸収中めも。

Spring Batchの日本語の情報すくないなー。軽い紹介ならいくつかあって参考になって嬉しいんだけど、踏み込んだものがないなー。

本家の英語ドキュメントがなかなかしっかりしてそうなんだけど、英語読むの遅い&読み間違いしそうでツライ。

あんまり実戦投入されてないのかなぁ?

 

Doma2との連携はなんとかできた。

トランザクション管理は今はSpring任せにしてるけど、doma側でもローカルトランザクションのマネージャーとか存在するみたいだし、どうすべきなのか?

データを書き込むときにdb見て重複チェックしたいときはどうすればいいんだろう?

ファイルの存在チェックはreaderのリスナーで前処理でやるべきか?それともタスクレットでやるべきか

 

DBと受領ファイル内容の突き合わせチェックをするバッチはどうつくるのか?これはタスクレットで良さそうな気がしてきた。

入力ファイルの項目レベルのバリデーションをアノテーションで実装するには?apt?googleさんのauto-common?勉強不足。これは後で

 

常駐バッチやら、1日1回のバッチやらいっぱいを1個のプロジェクトで作りたいんだけどmainがあるクラスいっぱいつくればいいのかな?共通的なものはどう定義するんだろな?

 

 

今日わかったこと

  •  CommandLineJobRunnerにconfigのクラスを渡して実行できる 
  • そのとき各jobのconfigクラスはコンポーネントスキャンからはずさないと面倒
  • Domaでinsertは比較的簡単だったけどselectが面倒くさい
  • DomaにStream<T> selectが用意されていたけどどう利用していいかわからん・・・

 

ただのメモ

  • intellij::lombok→Annotation Processorsのチェックをつける
  • intellij::javadocの追加を⌘+Shift+JでやりたいときはKeymapのfix doc commentに設定
  • gradle::domaでcompileJavaが走る前にresourcesにコピーする設定が必要
  • intellij::インポートの整理はcontrol+alt+o

 

最近のことめも

  • haskellのお勉強を始めました。
  • Springの再入門とか最近のjavaについていろいろお勉強をしている
  • Spring BatchでDomaを利用する方法を調査中。
  • Spring Batchで○○ファイルが存在するときは処理をする。みたいなことをどうやって実現するのか調査中
  • Spring で@Autowiredとかつかわずに@Injectとか書いてインジェクトするためには?
  • Spring Batchでlog4j2を使うためにはどうすれば?
  • Gradleでマルチプロジェクトの設定方法?
  • GradleでCIの設定どうやるの?
  • Bean Validation? アノテーションだけでバリデーションかける方法とバリデーションエラー時の挙動の設定は?

その他

  • コミュ症を脱出するぞー
  • 軽度肥満体型から標準体型になるぞー

vueプロジェクトセットアップ2016/4/14版

2ヶ月も前のやり方でbuildが通るわけないじゃない。

javascriptおそるべし

今回の改良ポイント

  • 以前のままだとbuildできない箇所の修正
  • vueの公式でおすすめのテスト構成(karma,jasmine)でテストを作る
  • ちょっとまともなtestを用意する 簡易コンポーネントを用意してそのテストをする

各モジュールバージョン

  • node: v5.10.1
  • npm:3.8.6
  • babel-core:6.7.6
  • vue:1.0.21

まずテストを作る前準備(小さいvueプロジェクト)

setup directory and node_modules

mkdir -p {build,test/{unit,e2e},src/{components,views/app,filters,directives,assets/{js,style,images,html}}}
npm init -y
npm i -g webpack webpack-dev-server babel-core babel-loader node-sass
npm i -S vue vuex
npm i -D babel-core babel-loader webpack style-loader css-loader node-sass sass-loader html-loader babel-plugin-add-module-exports babel-plugin-transform-runtime babel-polyfill babel-preset-es2015 babel-preset-stage-2 babel-runtime file-loader url-loader lodash
npm i -D extract-text-webpack-plugin html-webpack-plugin@2
npm i -D node-bourbon node-neat

.babelrc

{
  "presets": ["es2015", "stage-2"]
}

webpack.config.js

var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');

var bourbon = require('node-bourbon').includePaths;
var neat = require('node-neat').includePaths;

var contentBase = __dirname + '/build';
var cssLoader = ExtractTextPlugin.extract('style', 'css?sourceMap!sass')

var htmlWebpackPlugin = new HtmlWebpackPlugin({
    filename: 'index.html',
    template: 'src/assets/html/index.template.html'
});

var pkg = require('./package.json');
var vendor = Object.keys(pkg.dependencies);

var options = {
    sassLoader: {
        includePaths: [bourbon, neat]
    },
    entry: {
        app: ["./src/assets/js/app.js", "./src/assets/style/app.scss"],
        vendor: vendor,
    },
    output: {
        path: contentBase + '/',
        filename: "js/[name].js",
        contentBase: contentBase + '/build'
    },
    resolve: {
        alias: {
            vue: "vue/dist/vue",
            lodash: "lodash"
        },
        modulesDirectories: ['node_modules', 'src/', 'src/assets/js/', 'src/assets/style/', 'src/views/', 'src/directives/', 'src/filters/', 'src/components/'],
        // require()するときに拡張子を省略可能にします
        extensions: ['', '.webpack.js', '.web.js', '.js']
    },
    devServer: {
        contentBase: "./build",
    },
    module: {
        preloaders: [],
        loaders: [
            {
                test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
                loader: "url-loader?limit=10000&minetype=application/font-woff"
            },
            {
                test: /\.png$/,
                loader: "url-loader?limit=100000"
            },
            {
                test: /\.jpg$/,
                loader: "file-loader"
            },
            {
                test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
                loader: "file-loader"
            },
            {
                test: /\.scss$/,
                loader: ExtractTextPlugin.extract('style', 'css?sourceMap!sass')
            },
            {
                test: /\.html$/,
                loader: "html"
            },
            {
                test: /\.js(x?)$/,
                loader: 'babel-loader?sourceMaps=true'
            }
        ]
    },
    plugins: [
        htmlWebpackPlugin,
        new ExtractTextPlugin('./css/app.css', {disable: false}),
        new webpack.optimize.CommonsChunkPlugin('vendor', 'js/vendor.js')
    ]
};

if (process.env.NODE_ENV === 'production') {
    var defplugin = new webpack.DefinePlugin({
        'process.env': {
            NODE_ENV: '"production"'
        }
    });
    var minplugin = new webpack.optimize.UglifyJsPlugin({
        compress: {
            warnings: false
        }
    });
    options.plugins.push(defplugin);
    options.plugins.push(minplugin);
    options.plugins.push(new webpack.optimize.OccurenceOrderPlugin());
}

module.exports = options;

package.json(script property)

  "scripts": {
    "hot": "webpack-dev-server -d --inline",
    "build": "NODE_ENV=production webpack --progress --hide-modules",
    "test": "karma start karma.conf.js",
  },

src/assets/html/index.template.html

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>タイトルを入れてね</title>
</head>
<body>
<app><!-- ここにAPPが入ります --></app>
</body>
</html>

src/assets/js/app.js

import Vue from 'vue';
import App from '../../views/app'

require('../style/app.scss');

new Vue({
    el:'body',
    components: {App}
});

src/assets/style/app.scss

@import "~bourbon/app/assets/stylesheets/bourbon";
@import "~bourbon-neat/app/assets/stylesheets/neat";


body {
  @include outer-container();
  background-color: #000000;
  color: yellow;
  .header {
    @include span-columns(12);
    background-color: #999999;
  }
  .navigator {
    @include span-columns(5);
    background-color: #333333;
  }
  .footer {
    @include span-columns(12);
    background-color: #666666;
  }
}

src/views/app/index.js

export default {
    template: require("./template.html")
}

src/views/app/template.html

<div class="header">ヘッダー</div>
<div class="navigator">ナビゲーター</div>
<div class="contents">コンテンツ</div>
<div class="footer">フッター</div>

ここでnpm run hotを実行してみる。

ログを見てエラーが出ずにwebpack: bundle is now VALID.と表示されたら↓URLで確認

http://localhost:8080/

CSSが効いてれば多分問題なし。

停止するときはctrl+c

ついでにnpm run buildでビルドして、buildディレクトリに吐き出されるソースもちょろっと確認

テストを作る

npmまわり準備

npm i -D function-bind jasmine-core karma karma-jasmine karma-phantomjs-launcher karma-spec-reporter karma-webpack phantomjs phantomjs-polyfill phantomjs-prebuilt

やろうとしていること

components/navigator/index.js

export default {
    template: require("./template.html"),
    data() {
        return {
            'calcResult': 0,
            'value1': 0,
            'value2': 0
        }
    },
    methods: {
        init(value1, value2) {
            this.value1 = value1;
            this.value2 = value2;
        },
        doCalc() {
            this.calcResult = Number(this.value1) + Number(this.value2);
        }
    }
}

components/navigator/template.html

<div class="navigator">
    <input type="number" v-model="value1" />
    <span> + </span>
    <input type="number" v-model="value2" />
    <button @click="doCalc">calc</button>
    <span class="result" v-text="calcResult"></span>
</div>

views/app/index.js 書き換え

import Navigator from '../../components/navigator'
export default {
    template: require("./template.html"),
    components: {
        Navigator
    }
}

views/app/template.html 書き換え

<div class="header">ヘッダー</div>
<navigator></navigator>
<div class="contents">コンテンツ</div>
<div class="footer">フッター</div>

karma.conf.js

// webpackの設定でテストするのに都合の悪い部分を上書き ここから
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var htmlWebpackPlugin = new HtmlWebpackPlugin({
    filename: 'index.html',
    template: 'src/assets/html/index.template.html'
});

var webpackConf = require('./webpack.config.js');
delete webpackConf.entry;
webpackConf.plugins =  [
    htmlWebpackPlugin,
    new ExtractTextPlugin('./css/app.css', {disable: false})
];
// webpackの設定でテストするのに都合の悪い部分を上書き ここまで

module.exports = function(config) {
    config.set({

        // base path that will be used to resolve all patterns (eg. files, exclude)
        basePath: './',


        // frameworks to use
        // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
        frameworks: ['jasmine'],


        // list of files / patterns to load in the browser
        files: [
            './test/unit/index.js'
        ],

        proxies: {
            // 静的なファイルで必要なものはここに登録
            //'/assets/images/hoge.svg': './src/assets/images/hoge.svg'
        },

        // list of files to exclude
        exclude: [
        ],


        // preprocess matching files before serving them to the browser
        // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
        preprocessors: {
            'test/unit/index.js': ['webpack'],
            'src/**/*.js': ['webpack'],
        },

        webpack: webpackConf,

        webpackMiddleware: {
            noInfo: true
        },

        // test results reporter to use
        // possible values: 'dots', 'progress'
        // available reporters: https://npmjs.org/browse/keyword/karma-reporter
        reporters: ['spec'],


        // web server port
        port: 9876,


        // enable / disable colors in the output (reporters and logs)
        colors: true,


        // level of logging
        // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
        logLevel: config.LOG_INFO,


        // enable / disable watching file and executing tests whenever any file changes
        autoWatch: true,


        // start these browsers
        // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
        browsers: ['PhantomJS'],


        // Continuous Integration mode
        // if true, Karma captures browsers, runs the tests and exits
        singleRun: true,

        // Concurrency level
        // how many browser should be started simultaneous
        concurrency: Infinity

    })
};

webpackの設定の書き換えはpluginsのCommonsChunkPluginが絡んでくるとkarmaちゃんが動いてくれなくなっちゃうから

何かもっと良い解決方法があるといいな

test/unit/index.js

Function.prototype.bind = require('function-bind');

var testsContext = require.context('.', true, /\.spec$/);
testsContext.keys().forEach(testsContext);

test/unit/navigator.spec.js

import Vue from 'vue';
import Navigator from 'components/navigator';


describe('navigatorのテスト', () => {

    Vue.config.debug = true;
    Vue.options.replace = false;

    const vm = new Vue({
        template: '<div><navigator></navigator></div>',
        components: { Navigator }
    }).$mount();

    it('test sample', () => {
        expect(vm.$el.querySelector('.result').textContent).toBe('0');
    });

    it ('calc test', (done) => {
        vm.$children[0].init(100, 50);
        vm.$children[0].doCalc();
        expect(vm.$children[0].$data.calcResult).toBe(150);
        // まだ反映していないはず
        expect(vm.$el.querySelector('.result').textContent).toBe('0');
        vm.$nextTick(() => {
            // 反映されるはず
            expect(vm.$el.querySelector('.result').textContent).toBe('150');
            done();
        })
    });

});

ここで、npm run testもしくはnpm testを実行してみる。

navigatorのテスト
    ✓ test sample
    ✓ calc test

PhantomJS 2.1.1 (Mac OS X 0.0.0): Executed 2 of 2 SUCCESS (0.003 secs / 0.003 secs)

このようなログがでたら成功。