i++

プログラム系のメモ書きなど

Angular2 : [ts] Property 'map' does not exist on type 'Observable<Response>'

http.get(url).map(...) を試みたところ発生。

[ts] Property 'map' does not exist on type 'Observable<Response>'

import rxjs/add/operator/map を追加することで解決。

import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';

catch には import 'rxjs/add/operator/catch'; が必要になる。 一括でインポートするには import 'rxjs/Rx';

golang : template の range で index を使う

以下の様なデータを template.Execute のデータに渡したとすると

type data struct {
    Values      []string
    OtherValues []string
}

テンプレートで

<ul>
    {{range $i, $v := .Values}}
    <li>{{index $.OtherValues $i}} のようにするとインデックスでアクセスできる( OtherValues[i]の値)。{{$v}} はもちろん Values[i]</li>
    {{end}}
</ul>

のようにすれば、Values にループをかけている最中にインデックスを使って他の配列やスライスの特定の値にアクセスできる

template - The Go Programming Language に書いている通り、テンプレート中の {{index スライスや配列の変数 インデックス値}}ソースコード中のスライスや配列の変数[インデックス値] に対応する。

index
    Returns the result of indexing its first argument by the
    following arguments. Thus "index x 1 2 3" is, in Go syntax,
    x[1][2][3]. Each indexed item must be a map, slice, or array.

また、$ が Execution に渡されたデータを指すので、range 中にデータの他の変数にアクセスするには $.変数名 となる。

golang : コミット時に gofmt を実行する(pre-commit hook)

misc/git/pre-commit - The Go Programming Language を参考に作成しました。

オリジナルではフォーマットされていないコードがある場合にコミットを中断していますが、以下のスクリプトでは gofmt を実行して git add するところまでやっています。

#!/bin/sh

gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '.go$')
[ -z "$gofiles" ] && exit 0

unformatted=$(gofmt -l $gofiles)
[ -z "$unformatted" ] && exit 0

echo >&2 "Info: Running gofmt as some Go files are not formatted with gofmt."
for fn in $unformatted; do
    gofmt.exe -s -w $fn
    echo >&2 "gofmt -s -w $fn"
    git add $fn
done

exit 0

リンク先は、gofmt に加えて、gocyclo によるCyclomatic complexity のチェック(見るだけ)と goimports の実行も合わせたものになります。

github.com

Google App Engine : appcfg.py update 時の HTTP Error 403: Forbidden Unexpected HTTP status 403.

エラーの全文は以下の通り。

久々に GAE のプロジェクトを作成してデプロイしようと思ったら発生しました。

python appcfg.py -A YOUR_APP_ID -V v1 update src/
06:44 PM Application: YOUR_APP_ID (was: None); version: v1 (was: None)
06:44 PM Host: appengine.google.com
06:44 PM Starting update of app: YOUR_APP_ID, version: v1
06:44 PM Getting current resource limits.
2016-04-23 18:44:08,184 ERROR appcfg.py:2402 An error occurred processing file '': HTTP Error 403: Forbidden Unexpected HTTP status 403. Aborting.
Error 403: --- begin server output ---
You do not have permission to modify this app (app_id=u's~YOUR_APP_ID').
--- end server output ---

python - Google App Engine app deployment - Stack Overflow に書かれている通り、%ユーザディレクトリ%/.appcfg_oauth2_tokens を削除してから再実行することで、ブラウザで認証画面が開いてアップロードできました。

golang : URL短縮サービス goo.gl を使う

URL Shortener API の使い方はこちら → URL Shortener

ここでは API Key を使った方法を載せています。

type responseParam struct {
    Kind    string `json:"kind"`
    Id      string `json:"id"`
    LongUrl string `json:"longUrl"`
}

func GetShortenedUrlImpl(longUrl string) (string, error) {

    values := url.Values{}
    values.Add("key", GoogleApiKey) // パッケージの変数として定義し、この関数を呼ぶ前にセットしておきます。

    url := "https://www.googleapis.com/urlshortener/v1/url" + "?" + values.Encode()

    param := fmt.Sprintf(`{"longUrl":"%s"}`, longUrl);
    req, err := http.NewRequest("POST", url, bytes.NewBuffer([]byte(param)))
    if err != nil {
        return "", err
    }
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return "", err
    }
    defer resp.Body.Close()
    respBody, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return "", err
    }
    var respParam responseParam
    err = json.Unmarshal(respBody, &respParam)
    if err != nil {
        return "", err
    }
    return respParam.Id, nil
}

golang : 日本語(マルチバイト)文字を含む string の substring

go では string のスライスは byte として扱われるので、日本語のようにマルチバイト文字を含んだ文字列 str に対して str[start:start+length] のようなことをすると、思わぬ場所が切り取られてしまいます。

この問題を回避するために、一旦 rune にキャストしてから string に戻します。

func substring(str string, start, length int) string {
    if start < 0 || length <= 0 {
        // 明らかに不正な値なので、チェックせずに進んで panic を起こしても良さそうです。
        return str
    }
    r := []rune(str)
    if start + length > len(r) {
        return string(r[start:])
    } else {
        return string(r[start:start + length])
    }
}

TypeScript : typings による Chrome Extension 用型定義のインストール

typings で型定義ファイルの管理を行うので、未インストールの場合はインストールします。

npm install -g typings

拡張機能のプロジェクトのディレクトリに移動し、typings init コマンドで初期化します(typings.json ファイルが作成されます)。 その後、install コマンドで Chrome Extension 用の 型定義ファイル(.d.ts)をインストールします。

typings install chrome --ambient --save
typings install filesystem --ambient --save
typings install filewriter --ambient --save
typings install webrtc/mediastream --ambient --save
typings install es6-shim --ambient --save

chromeChrome Extension 用の型定義の本体ですが、これをインストールするだけ使えず、chrome が依存している他の型定義もインストールする必要があります。 typings でインストールしたときに、Stripped reference というメッセージが表示された場合、それらを手動でインストールする、と覚えておけば良さそうです。

> typings install chrome --ambient --save
typings INFO reference Stripped reference "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/7de6c3dd94feaeb21f20054b9f30d5dabc5efabd/webrtc/MediaStream.d.ts" during installation from "chrome"
typings INFO reference Stripped reference "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/7de6c3dd94feaeb21f20054b9f30d5dabc5efabd/filesystem/filesystem.d.ts" during installation from "chrome"
chrome
└── (No dependencies)

--ambient って何者?など typings についてより詳しく知りたい場合は TypeScriptの型定義管理ツールTypingsについて - Qiita が参考になります。