まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

2018年06月

GitHub で作成してしばらく使っていたリポジトリが、当初の想定以上に盛り上がったりすると、最初に適当に付けたリポジトリ名からちゃんとした正式名称のリポジトリに変更したくなる(というか、した)、という経験をしました。その時の作業手順メモです。

まず最初の注意点として、GitHub リポジトリのリネームは GitHub サーバー側と、そのクローンを保持するローカル側の両方で行う必要があります。クローンを保持するローカルが複数ある場合は、その全てのローカル側で対応が必要になります。

今回は
 https://github.com/dotnsf/old_app.git

 https://github.com/dotnsf/new_app.git
にリネームする想定で以下を説明します。

【GitHub サーバー側】
サーバー側の変更は GitHub のリポジトリ画面内から行います。まずブラウザでリポジトリページを開き、"Settings" メニューを選択します:
2018061401


"Settings" メニューのすぐ下に "Repository name" フィールドがあり、ここに変更前のリポジトリ名(今回であれば "old_app")が入力されています:
2018061402


ここを新しいリポジトリ名称(今回であれば "new_app")に変更し、"Rename" ボタンをクリックして確定させます:
2018061403


サーバー側の変更はこれだけです。この時点で名称変更前の URL にアクセスしても自動的に新しい URL にフォワードされて、新しい名前のリポジトリが表示されます:
2018061404



【ローカル側】
クローンしたローカルリポジトリ内の .git/config ファイルを編集します:
  :
  :

[remote "origin"]
        url = https://github.com/dotnsf/new_app
        fetch = +refs/heads/*:refs/remotes/origin/*

  :
  :

[remote "origin"] 項目内の url の値を新しいリポジトリの URL に変更して保存します。ローカル側の変更もこれだけですが、複数のマシンにローカルリポジトリが存在する場合は全てのローカルリポジトリを変更します。



ここまでの作業でサーバー側&リモート側ともリポジトリのリネーム作業が完了しました。当然ですが、中身は変わってない(リネーム前のまま)ので、改めてリネーム後に変更が必要なファイル(README.md とか)を更新してください:
2018061405


 

Chart.js を使って円グラフを描くときによく悩まされることがあります。

「AとBの2つの値の比率を視覚的に比べる」ことを目的に円グラフを使うことがあるのですが、これを Chart.js で描こうとすると、以下のような感じになります:
  :
  :
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.4/Chart.min.js"></script>

  :
  :

<canvas id="myChart"></canvas>

<script>
var ctx = document.getElementById( 'myChart' ).getContext( '2d' );
var chart = new Chart( ctx, {
  type: 'pie',
  data: {
    labels: [ 'A', 'B' ],  //. ラベルは A, B の順
    datasets: [ {
      data: [ 10, 20 ],    //. A の値が10Bの値が 20 であるとする
      backgroundColor: [ '#ff0000', '#0000ff' ]
    } ]
  }
});
</script>


  :
  :

↑この例では A と B という2つの値を円グラフで表示しようとしています。A の値を 10 、B の値を 20 とした上で、 A を赤に、B を青で指定しています。

これをブラウザで表示するとこうなります:
2018060501


・・・違う、惜しい。そうじゃないんだ!

ラベル部分が左A右Bになっているので、円グラフも左側に赤いA右側に青いBを持ってきたい。。。 でもこれが難しい(苦笑)。

Chart.js の円グラフの場合、円の頂点を始点として時計回りにデータが描画されるので、どうしても右側に最初のデータ(A)が描かれてしまい、左側には2つ目のデータ(B)が描画されます。つまり円グラフとしてはラベルとは逆に右に赤いA左側に青いBが表示されてしまうのです。

ここ、なんとかして逆にできないかなあ・・・ と色々工夫しているのですが、これというアイデアが浮かばず、諦めています。

残念・・・  Chart.js 以外のグラフ描画ライブラリだとなんとかなるのかなあ・・・



最近気になっているプログラミング言語の1つが Julia です:
Julia_prog_language.svg



高速で、使いやすくて(これは意見が分かれると思うけど、確かに if elseif などのコードを短く書けることは事実)、最近流行りの Python の関数を呼び出して使えるので機械学習ライブラリが豊富に使える、とのこと。インデントを使ったコード記述も Python っぽくて、なかなかに魅力を感じます。

なお高速性については公式サイトにベンチマークの比較が載っていたのでここにも載せておきます。このベンチマークによるとたしかに C 並のパフォーマンスを叩き出していて、Java や JavaScript、Python などよりは速そう・・・:
2018060601


Julia のインストール方法は様々用意されていますが、最新バージョンのインストールは公式サイトからの command line version ダウンロードが確実なようです(Ubuntu の場合、 $ sudo apt-get install julia でも導入できましたがバージョンが古く、後述のウェブフレームワークが使えなかったりする問題がありました):
2018060602


↑上記表から自分の環境にあったものを選択してダウンロード&インストールします。自分は Ubuntu 環境で試したので、"Generic Linux Binaries for x86 - 64-bit" から tar.gz ファイルをダウンロードし、展開してパスを通しました:
$ wget https://julialang-s3.julialang.org/bin/linux/x64/0.6/julia-0.6.3-linux-x86_64.tar.gz
$ tar xzvf julia-0.6.3-linux-x86_64.tar.gz
$ echo export PATH="$PATH:~/julia-d55cadc350/bin" >> ~/.bashrc
$ source ~/.bashrc
$ julia -v
julia version 0.6.3

これで Julia は使えるようになりました。ついでに Julia のウェブフレームワークである Genie も導入してしまいましょう:
2018060604


まずは対話モードで Julia を起動します:
$ julia

2018060603


julia> というプロンプトが表示されれば、Julia を対話モードで起動できました。ここに Julia の構文を入力して実行することもできますが、今回はこの対話モードを使って Genie を導入していきます。

まず、最初の一回目だけはパッケージの更新を行っておきます:
julia> Pkg.update()

次に Genie の前提動作に必要な Flex パッケージを導入します:
julia> Pkg.add( "Flex" )

そして改めて Genie を以下のコマンドで導入します:
julia> Pkg.clone( "https://github.com/essenciary/Genie.jl" )

ここまでの作業で Genie が導入できました! では実際に Genie を使ってウェブアプリケーションを作ってみます。まずはこの対話モードのまま Genie を有効にします:
julia> using Genie

そしてアプリケーション名(以下では "my_genie")を指定して Genie アプリケーションを作成します:
julia> Genie.REPL.new_app( "my_genie" );

このコマンドを実行して成功すると、プロンプトが genie> に変わり、julia コマンドを実行した時のフォルダに my_genie フォルダが作られ、その中に Genie フレームワークに必要な一通りのファイルやコマンドが生成されます:
2018060607


そのファイルを確認する前にまず一回このまま実行してみます。プロンプトから以下のように入力してアプリケーションサーバーを起動します:
genie> AppServer.start()

これで 8000 番ポートでアプリケーションが起動します。ウェブブラウザからこのホストの 8000 番ポートを指定して HTTP リクエストし、ここまでの作業が成功してデフォルトの初期画面が表示されることを確認します:
2018060605


とりあえず動いているようです。では最後にちょっとしたカスタマイズを加えます。そのためには一度コマンドラインに戻る必要があるため、Genie と Julia の対話モードを終了します。いずれも quit() で終了します(Genie と Julia 両方の対話モードを終了するので2度実行する必要があります):
genie> quit()

julia> quit()

$

元のプロンプトに戻ったら Genie が生成したファイルを改良します。元のフォルダから my_genie/config/routes.jl ファイルをエディタで開き、以下の赤字部分を追加します:
using Router

route("/") do
  Router.serve_static_file("/welcome.html")
end

route("/hello") do
  "Hello Julia - Welcome to Genie!"
end

ルート( "/" )にアクセスした場合は上記の初期画面(/welcome.html)が表示されるよう設定されていますが、その下に "/hello" にアクセスがあった場合の処理を加えました。この例では "Hello Julia - Welcome to Genie!" という文字列が表示されるようにしています。

改めてカスタマイズしたアプリケーションを実行します。アプリケーションフォルダ(my_genie/)に移動して、今度は対話モードではなく直接アプリケーションサーバーを起動します:
$ cd my_genie
$ bin/server

2018060608


そしてウェブブラウザで、今度は /hello パスを指定して読み込みます。期待通りのメッセージが表示されれば成功です:
2018060606


テンプレートエンジンとか、ファイルアップロードをどう処理するかとか、データベース連携とか、まだ調べないといけないことはあるけど、ウェブフレームワークとしては使えそうです。


いくつか heroku 用の Julia ビルドパックが見つかる(Julia のバージョンは低そうだけど)ので、次はこいつを IBM Cloud 上で動かすことに挑戦予定です。


Python の代表的なウェブアプリケーションフレームワークの1つに Flask があります:
2018053101


「マイクロフレームワーク」と称されるほどの計量な設計になっており、個人的にも Python でウェブアプリ開発する時のフレームワークとして使っています。この Flask でルーティング処理を行う場合は以下のように記述します:
  :
from flask import Flask
  :

app = Flask(__name__)

@app.route('/hello')
def hello():
  return "Hello!"

  :
  :

↑この例では GET /hello というリクエストに対して hello() 関数を割り当て、実行結果として "Hello!" という文字列を返すようにしています。


この "/hello" の部分を正規表現にして、例えば GET /(数字).xxx という形でリクエストを受け取って処理を行いたいのですが、どうすればよいか? というのが本エントリのテーマです。

答えはこんな感じになります:
  :
from flask import Flask
from werkzeug.routing import BaseConverter
  :

app = Flask(__name__)

class RegexConverter(BaseConverter):
  def __init__(self, url_map, *items):
    super(RegexConverter, self).__init__(url_map)
    self.regex = items[0]

app.url_map.converters['regex'] = RegexConverter

@app.route('/hello')
def hello():
  return "Hello!"

@app.route('/<regex("[0-9]*"):id>.xxx')
def xxx(id):
    return ( "id = %s" % (id) )

  :
  :

まず正規表現でパスを解釈するためのコンバータークラス: RegexConverter を定義し、
 <regex( XXX ):v>
という形で正規表現を処理できるようにします( XXX 部分の正規表現にマッチしたら、その結果を v という変数に代入する)。

その上で
 @app.route('/<regex("[0-9]*"):id>.xxx')
 def xxx(id):
  :

の定義によって、/(数字).xxx というパスへの GET リクエストを受け取り、この(数字)の部分を id 変数に代入した上で xxx( id ) 関数が呼び出される、という形で実現しています。

なので、例えば /123.xxx に GET リクエストを行うと、id = 123 が代入された状態で xxx( id ) 関数が実行されます。



(参考)



このページのトップヘ