Articles on this Page
- 01/27/12--04:00:_Vim...
- 02/07/12--23:24:_Vimで編集中のMarkdow...
- 02/09/12--05:21:_Vim で XML Reformat
- 02/14/12--00:43:_VimでMessagePack/RPC
- 02/15/12--16:38:_THE GO TOOL
More Channels
- Dec 14: john oates | Keyword Feed
- Feb 14: ruff for sheriff | Keyword Feed
- Feb 5: jewish feasts | Keyword Feed
- Dec 20: john mccaine | Keyword Feed
- Dec 24: karel murray | Keyword Feed
- Jan 30: rti | Keyword Feed
- Feb 18: jeff zeleny | Keyword Feed
- Jan 16: jesus spirit holy spirit |...
- Dec 9: j. michael tatum | Keyword Feed
- Dec 20: john laird | Keyword Feed
- Jan 6: joy giovanni | Keyword Feed
- Jan 29: kamen rider | Keyword Feed
- Nov 26: ron rondon and the nfl | Keyword...
- Feb 23: roy miller | Keyword Feed
- Dec 9: free radio anna voci | Keyword Feed
- Feb 4: jeff witzke | Keyword Feed
- Dec 14: jerilynn knight | Keyword Feed
- Feb 22: jessica alba | Keyword Feed
- Feb 18: jim harrison | Keyword Feed
- Jan 7: j. julia rahn | Keyword Feed
- Nov 26: joe rubino | Keyword Feed
- Dec 24: john krauser | Keyword Feed
- Feb 17: joseph immel | Keyword Feed
- Nov 26: journey paranormal society |...
- Jan 11: julie bauke | Keyword Feed
- Nov 26: kamehameha | Keyword Feed
- Dec 10: roni graham | Keyword Feed
- Feb 23: ron pobuda | Keyword Feed
- Nov 26: rookie | Keyword Feed
- Nov 26: rothstein | Keyword Feed
- Nov 26: flipdatradio | Keyword Feed
- Jan 6: fork to fork | Keyword Feed
- Dec 9: jeff lister | Keyword Feed
- Dec 14: jeffrey zucker | Keyword Feed
- Feb 4: jennifer farmer | Keyword Feed
- Jan 27: j eric miller | Keyword Feed
- Feb 13: jerry cherry | Keyword Feed
- Feb 22: jesse campbell | Keyword Feed
- Nov 26: jhgjgh | Keyword Feed
- Dec 31: jill foster | Keyword Feed
- Dec 14: jim mcgreevey | Keyword Feed
- Feb 22: j.j | Keyword Feed
- Feb 6: joan jackson | Keyword Feed
- Feb 4: jocelynn drake | Keyword Feed
- Dec 31: john becca | Keyword Feed
- Nov 26: john heerhold | Keyword Feed
- Nov 26: jon lester | Keyword Feed
- Jan 15: joseph domingo | Keyword Feed
- Jan 4: josh flagg | Keyword Feed
- Jan 6: josh temple | Keyword Feed
|
|
Are you the publisher? Claim this channel |
|
Channel Description:
Latest Articles in this Channel:
- 01/27/12--04:00: Vim scriptはウェブアプリケーション記述言語やったんやー (chan 1718684)
- 02/07/12--23:24: Vimで編集中のMarkdownをプレビュー出来るプラグイン書いた (chan 1718684)
- python (2.7 or later) http://python.org/
- PyQt4 http://www.riverbankcomputing.co.uk/software/pyqt/download
- curl command http://curl.haxx.se/libcurl/
- webapi-vim http://github.com/mattn/webapi-vim
markdown-js https://github.com/evilstreak/markdown-js- 02/09/12--05:21: Vim で XML Reformat (chan 1718684)
- 02/14/12--00:43: VimでMessagePack/RPC (chan 1718684)
- 02/15/12--16:38: THE GO TOOL (chan 1718684)
-
go build- パッケージのビルド -
go get- 依存の解決とインストール -
go test- テストスーツの実行とベンチマーク -
go install- パッケージのインストール -
go doc- ドキュメントの生成 -
go fmt- コードの整形 -
go run- アプリケーションのビルドと実行 -
go tool- その他ツールの呼び出し - その他...
- マスターブランチを常にグリーンにしとけよ!バカ
- 新機能は別ブランチでやれ!ボケ
- 一度コード公開しといて誰かが使ってるのにAPI変えるなクソがぁ!
- API変えたいとか、どうして変える必要があるならメジャーバージョンで変えろよ。んでもってオリジナルブランチから派生ブランチに分けて作業しろよ!カス
- もしどうしても、どうしても特別なタグやブランチ、もしくは依存としてコミットする必要があるなら、デフォルトに指定したリポジトリを自分でforkしてコミットに使えよ!このウンコが!
- おいおい...笑顔でいろよ マザコン!
こんにちわ。昨今、ウェブ開発の進化はすざましいですね。PythonやPerlやJava、色んな言語で書かれていると思います。
もちろん編集にはVimを使っているかと思います。
でも編集だけ?
違うよね!
Vim scriptはウェブアプリケーション記述言語なんだよ!
Plack::App::Vim
package Plack::App::Vim;
use strict;
use warnings;
use parent qw/Plack::Component/;
use Plack::Request;
use Encode;
use JSON::PP;
sub prepare_app {
my $self = shift;
$self->{vim} ||= 'vim';
if (!$self->{server}) {
open(my $f, "vim --serverlist|");
my $server = <$f>;
close($f);
chomp $server;
$self->{server} = $server;
}
if (!$self->{encoding}) {
open(my $f, sprintf("%s --servername %s --remote-expr \"&encoding\"|",
$self->{vim}, $self->{server}));
my $encoding = <$f>;
close($f);
chomp $encoding;
$self->{encoding} = $encoding;
}
$self;
}
sub call {
my ($self, $env) = @_;
my $req = Plack::Request->new($env);
my $json = JSON::PP->new->ascii
->allow_singlequote->allow_blessed->allow_nonref;
my $str = $json->encode({
uri => $env->{PATH_INFO}||'',
method => $req->method,
headers => [split( /\n/, $req->headers->as_string)],
content => $req->content,
});
$str =~ s!"!\\x22!g;
my $command;
if ($^O eq 'MSWin32') {
$command = sprintf(
'%s --servername %s --remote-expr "vimplack#handle("""%s""")"',
$self->{vim}, $self->{server},
encode($self->{encoding} || 'utf8', $str));
} else {
$command = sprintf(
"%s --servername %s --remote-expr 'vimplack#handle(\"%s\")'",
$self->{vim}, $self->{server},
encode($self->{encoding} || 'utf8', $str));
}
open(my $f, "$command|");
binmode $f, ':utf8';
my $out = <$f>;
close $f;
my $res = $json->decode($out);
$res->[2][0] = encode_utf8 $res->[2][0] if $res;
$res || [500, ['Content-Type' => 'text/plain'], ['Internal Server Error']];
}
1;
__END__
=head1 NAME
Plack::App::Vim - The Vim App in Plack
=head1 SYNOPSIS
use Plack::Builder;
use Plack::App::Vim;
builder {
mount "/" => Plack::App::Vim->new(server => 'VIM');
};
=head1 DESCRIPTION
Plack::App::Vim allows you to write web application with Vim script.
=head1 AUTHOR
Yasuhiro Matsumoto
=head1 SEE ALSO
L<Plack>
=cut
Plack::Appのアプリケーションハンドラを書いたよ。これを起動するpsgiファイルを用意するよ!app.psgi
#!perl引数の
use lib qw/lib/;
use Plack::Builder;
use Plack::App::Vim;
builder {
mount "/" => Plack::App::Vim->new(server => 'VIM');
};
serverにはclientserver機能が使えるVimを立ち上げ、そのサーバIDを指定しておく必要があるよ!そしてVim側にハンドラを書くよ!
autoload/vimplack.vim
scriptencoding utf-8PSGIプロトコルそのままですね!便利!
function! vimplack#handle(req)
let req = json#decode(a:req)
let res = [200, [], ["hello world"]]
return json#encode(res)
endfunction
起動しよう!
# plackup app.psgiブラウザで
HTTP::Server::PSGI: Accepting connections at http://0:5000/
http://localhost:5000を開こう!やたー!![]()
あとはアプリケーション書き放題ですね!
試しに掲示板書いてみるよ!
autoload/vimplack.vim
scriptencoding utf-8アプリケーションの更新はVimを再起動するか
let s:comments = get(s:, 'comments', [])
function! vimplack#handle(req)
let req = json#decode(a:req)
if req.uri == "/"
let res = [200, ["Content-Type", "text/html; charset=utf-8"], [""
\."<html>"
\."<body>"
\."<form action='/regist' method='post'>"
\."コメント:<input type='text' name='comment' value='' /><br />"
\."<input type='submit' value='登録' />"
\."</form>"
\.join(map(copy(s:comments), 'html#encodeEntityReference(v:val)'), '<br />')
\."</body>"
\."</html>"
\]]
elseif req.uri == '/regist' && req.method == 'POST'
let params = {}
for _ in map(split(req.content, '&'), 'split(v:val,"=")')
let params[_[0]] = iconv(http#decodeURI(_[1]), 'utf-8', &encoding)
endfor
if has_key(params, 'comment')
call add(s:comments, params['comment'])
endif
let res = [302, ["Location", "/"], [""]]
else
let res = [404, [], ["404 Dan Not Found"]]
endif
return json#encode(res)
endfunction
autoload/vimplack.vimを開いている常態なら
:so %で行けるよ!
知らんかったー
Vim scriptはウェブアプリケーション記述言語やったんやー
mattn/p5-Plack-App-Vim - GitHub
Vim Application Handler for PSGI
https://github.com/mattn/p5-Plack-App-Vim
Vimが良くも悪くも「エディタだ」と言われる要因として「画像や異なるグリフのフォントを同時に出せない」ことを上げられます。つまりVimはHTMLやマークダウン等のプレビューを確認する為にいちいちブラウザを起動して確認し、ファイルを更新した際には読み込み直すという面倒な手間が掛かる事を意味しています。
まぁ専用ブラウザを作ればいいんだけど面倒で腰が重かったんだけど、ちょいと作ってみました。
mattn/mkdpreview-vim - GitHubファイルタイプがmarkdownなバッファで
MkdPreview Markdown previewer for vimmer
https://github.com/mattn/mkdpreview-vim
:MkdPreview!と実行するとプレビューワが起動します。
プレビューワが一度起動している状態なら、以後は他のVimからでも![]()
:MkdPreviewでプレビューが表示される様になっています。
MkdPreview!を実行したVimに関してはBufWritePostに
対してプレビュー更新が行われる様になっているので:wで自動更新されます。この辺は使い勝手で変えていくかも知れない。仕組みはpythonスクリプトで書かれたウェブサーバ兼Qt4を使ったプレビューワになっていて POSTを受けたらそれをmarkdown-jsを使ってQtWebkitに反映させています。 複数起動とかうっとおしいだろうなと思ったので、ポートは固定にしています。 起動に必要な物としては
#!/usr/bin/env python良かったら使ってみて下さい。 なお、ベースとなるHTMLはstaticフォルダにあるのでスタイル等をカスタマイズしたい人はじゃんじゃんやっちゃって下さい。 こうすればもっと使い勝手が良くなるよなどあればpull requestお願いします。
# -*- coding: utf-8 -*-
import os
import sys
import json
import cgi
from threading import Thread
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtWebKit import *
from PyQt4.QtNetwork import *
from BaseHTTPServer import HTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
os.chdir(os.path.dirname(__file__))
port = int(os.getenv("mkdpreview_port") or "8081")
QNetworkProxyFactory.setUseSystemConfiguration(True)
app = QApplication(sys.argv)
webview = QWebView()
webview.setWindowTitle('Markdown Previewer')
webview.load(QUrl("http://localhost:8081"))
def do_eval(js):
webview.page().mainFrame().evaluateJavaScript(
"preview(%s)" % json.dumps(unicode(js, 'utf-8')))
QObject.connect(webview, SIGNAL("preview(QString)"), do_eval)
webview.show()
class PreviewHandler(SimpleHTTPRequestHandler):
def do_POST(self):
s = self.rfile.read(int(self.headers.getheader('content-length')))
p = cgi.parse_qs(s)
webview.emit(SIGNAL("preview(QString)"), p["data"][0])
self.wfile.write("")
class WebServer(QThread):
def __init__(self):
QThread.__init__(self)
self.server = HTTPServer(("", port), PreviewHandler)
def run(self):
self.server.serve_forever()
server = WebServer()
server.start()
sys.exit(app.exec_())
# vim:set et sw=2 ts=2:
追記
Windowsじゃない人はstatic/mkdpreview.pyに実行権限与えて下さい。
markdown-jsじゃなくpython側でparseする様にしました。
たとえばこういう XML があったとして、
<status><created_at>Mon Feb 06 21:07:52 +0000 2012</created_at><id>166629198054690816</id><text>Post-Bowl Twitter analysis http://t.co/OYYSRSew http://t.co/M0AtLQVd</text><source>web</source><truncated>false</truncated><favorited>false</favorited><in_reply_to_status_id></in_reply_to_status_id><in_reply_to_user_id></in_reply_to_user_id><in_reply_to_screen_name></in_reply_to_screen_name><retweet_count>454</retweet_count><retweeted>false</retweeted><user><id>783214</id><name>Twitter</name><screen_name>twitter</screen_name><location>San Francisco, CA</location><description>Always wondering what's happening. </description><profile_image_url>http://a0.twimg.com/profile_images/1124040897/at-twitter_normal.png</profile_image_url><profile_image_url_https>https://si0.twimg.com/profile_images/1124040897/at-twitter_normal.png</profile_image_url_https><url>http://blog.twitter.com/</url><protected>false</protected><followers_count>7625563</followers_count><profile_background_color>ACDED6</profile_background_color><profile_text_color>333333</profile_text_color><profile_link_color>038543</profile_link_color><profile_sidebar_fill_color>F6F6F6</profile_sidebar_fill_color><profile_sidebar_border_color>EEEEEE</profile_sidebar_border_color><friends_count>822</friends_count><created_at>Tue Feb 20 14:35:54 +0000 2007</created_at><favourites_count>16</favourites_count><utc_offset>-28800</utc_offset><time_zone>Pacific Time (US & Canada)</time_zone><profile_background_image_url>http://a1.twimg.com/profile_background_images/378245879/Twitter_1544x2000.png</profile_background_image_url><profile_background_image_url_https>https://si0.twimg.com/profile_background_images/378245879/Twitter_1544x2000.png</profile_background_image_url_https><profile_background_tile>true</profile_background_tile><profile_use_background_image>true</profile_use_background_image><notifications>false</notifications><geo_enabled>true</geo_enabled><verified>true</verified><following>true</following><statuses_count>1266</statuses_count><lang>en</lang><contributors_enabled>true</contributors_enabled><follow_request_sent>false</follow_request_sent><listed_count>68708</listed_count><show_all_inline_media>true</show_all_inline_media><default_profile>false</default_profile><default_profile_image>false</default_profile_image><is_translator>false</is_translator></user><geo/><coordinates/><place/><possibly_sensitive>false</possibly_sensitive><contributors><user_id>7694352</user_id></contributors></status>見づらいので vimrc に1行書いてあげると、
map <Leader>x !python -m BeautifulSoup<CR>範囲選択してから <Leader> x でキレイに整形してくれます。
<status>ネタ元: http://wozozo.hatenablog.com/entry/2012/02/08/121504
<created_at>
Mon Feb 06 21:07:52 +0000 2012
</created_at>
<id>
166629198054690816
</id>
<text>
Post-Bowl Twitter analysis http://t.co/OYYSRSew http://t.co/M0AtLQVd
</text>
<source>
web
</source>
<truncated>
false
</truncated>
<favorited>
false
</favorited>
<in_reply_to_status_id>
</in_reply_to_status_id>
<in_reply_to_user_id>
</in_reply_to_user_id>
<in_reply_to_screen_name>
</in_reply_to_screen_name>
<retweet_count>
454
</retweet_count>
<retweeted>
false
</retweeted>
<user>
<id>
783214
</id>
<name>
</name>
<screen_name>
</screen_name>
<location>
San Francisco, CA
</location>
<description>
Always wondering what's happening.
</description>
<profile_image_url>
http://a0.twimg.com/profile_images/1124040897/at-twitter_normal.png
</profile_image_url>
<profile_image_url_https>
https://si0.twimg.com/profile_images/1124040897/at-twitter_normal.png
</profile_image_url_https>
<url>
http://blog.twitter.com/
</url>
<protected>
false
</protected>
<followers_count>
7625563
</followers_count>
<profile_background_color>
ACDED6
</profile_background_color>
<profile_text_color>
333333
</profile_text_color>
<profile_link_color>
038543
</profile_link_color>
<profile_sidebar_fill_color>
F6F6F6
</profile_sidebar_fill_color>
<profile_sidebar_border_color>
EEEEEE
</profile_sidebar_border_color>
<friends_count>
822
</friends_count>
<created_at>
Tue Feb 20 14:35:54 +0000 2007
</created_at>
<favourites_count>
16
</favourites_count>
<utc_offset>
-28800
</utc_offset>
<time_zone>
Pacific Time (US & Canada)
</time_zone>
<profile_background_image_url>
http://a1.twimg.com/profile_background_images/378245879/Twitter_1544x2000.png
</profile_background_image_url>
<profile_background_image_url_https>
https://si0.twimg.com/profile_background_images/378245879/Twitter_1544x2000.png
</profile_background_image_url_https>
<profile_background_tile>
true
</profile_background_tile>
<profile_use_background_image>
true
</profile_use_background_image>
<notifications>
false
</notifications>
<geo_enabled>
true
</geo_enabled>
<verified>
true
</verified>
<following>
true
</following>
<statuses_count>
1266
</statuses_count>
<lang>
en
</lang>
<contributors_enabled>
true
</contributors_enabled>
<follow_request_sent>
false
</follow_request_sent>
<listed_count>
68708
</listed_count>
<show_all_inline_media>
true
</show_all_inline_media>
<default_profile>
false
</default_profile>
<default_profile_image>
false
</default_profile_image>
<is_translator>
false
</is_translator>
</user>
<geo>
<coordinates>
<place>
<possibly_sensitive>
false
</possibly_sensitive>
<contributors>
<user_id>
7694352
</user_id>
</contributors>
</place>
</coordinates>
</geo>
</status>
ちなみに
-mだけでやる場合は細かい制御はできなさそう。
Vimが無いと夜も安心して眠れないVimキチガイの皆さんこんにちわ。
![]()
そういえば、VimもMessagePackで通信できると面白いのではないか。
https://twitter.com/#!/ShougoMatsu/statuses/168691297601863681
mattn/msgpack-vim - GitHubVim scriptは型が豊富ではないので、可逆圧縮ではありませんが簡単な物ならば動きます。
MessagePack implements for vim
https://github.com/mattn/msgpack-vim
# -*- coding: utf-8 -*-こんなサーバを走らせておき
require 'msgpack/rpc'
class MyHandler
def add(x,y) x+y end
end
svr = MessagePack::RPC::Server.new
svr.listen('0.0.0.0', 18800, MyHandler.new)
svr.run
let mp = msgpack#client("127.0.0.1", 18800)Vimからこのように実行します。すると
echo mp.call("add", 1, 2)
call mp.close()
3おぉ... もちろん配列、ディクショナリ、浮動小数点、文字列、整数は当たり前で扱えます。
# -*- coding: utf-8 -*-こんなコードなら
require 'msgpack/rpc'
class MyHandler
def get_dict()
{:foo => "ばー"}
end
end
svr = MessagePack::RPC::Server.new
svr.listen('0.0.0.0', 18800, MyHandler.new)
svr.run
let mp = msgpack#client("127.0.0.1", 18800)で
echo mp.call("get_dict")
call mp.close()
{'foo': 'ばー'}と表示されます。日本語もバッチリですね!
msgpack#client に関しては通信に vimproc を使ってますが、ここはちょっと弄れば nc でも通信可能ですし、xxd なんかを使えばバイナリファイルとしても保存可能です。
また msgpack#pack と msgpack#unpack は単体関数として使えるのでいろんな物に利用出切るかと思います。誰得度がかなり高いですが、よろしければどうぞ。
先日、Go言語開発チームはリポジトリ内にあった殆どのMakefileを削除した。私(訳者)は混乱したし不安にもなった。しかしそれは私がこれまでの習慣と異なる場面に遭遇した事による物だと気付いた。その事を色濃く書かれたいる記事があったので紹介したい。Go言語を知らない人でも面白く読めると思います。
Are You Fuckign Coding Me!? - The go tool本訳を許諾してくれたnu7hatchに感謝したい。(Thanks to nu7hatch)
http://areyoufuckingcoding.me/2012/02/14/the-go-tool/
THE GO TOOL
毎週リリースされる最新版に新しいgoコマンドが導入され話題になっていたので、ちょっとこれについて書くことにした。 私は初め、このgo toolを統一しようというアイデアを聞いた時、少し懐疑的になり不安でいっぱいになった事を認めざるを得ない。 それが他の言語固有のパッケージマネージャの様にめちゃくちゃになるのではないかと心配した。 それらパッケージマネージャのほとんどは私の知る限り車輪の再発明であり、そのオペレーティングシステム上のPMがコーディングする事でシステム管理者を生活苦にしているのだ。 さらに言うと、私はmakefileが好きだった。本当に好きだった。単純明快だったしうまく動いた。 幸運にも新しいのgo toolが私の恐怖の全てを拭い去った!
繰り返すな...
新しいgo toolに関する情報の多くはgo nutsメーリングリストに流れている。 公式のgoのドキュメントにも現在、go toolを使ってのコードの書き方が短めの記事となって幾らか含まれている。
現時点ではドキュメントとのギャップがかなりあると思うので、新しいgo toolの採用と幾らかの便利なトリックを逸早く書くことが合理的だと思う。
設定よりも取り決め
私の最大の恐怖の源、その理由はRuby on Railsの経験によるものだ。 Railsをよく理解しる開発者は、ちょっとしたハックや、言ってしまえばルールに沿わないちょっとしたトリッキーな何かをしようとする場合、その全ての時間を費やす事に同意しなければならない。
しかし良い練習について説明して行こう。まず第一にgo toolの各々は一つの物事だけを行う。そしてそれは正しい。あるべき物はそこにある:
Goのパッケージはビルドの設定といった物を全く持っていない。
makefileもない。その他、依存性の記述も無い。
じゃぁどの様になるのか。全てはソースコードから検索される。
マジックを起こすには、最初に行わなければならない事が一つある。
goのスタッフがどこにあるのかを明示する必要がある。
GOPATH環境変数でgoのツリーへのパスを定義する。
例えば、~/.bashrcの中での以下の様に:
GOPATH="/home/nu7/gocode"
...はgoのツリーが指定した場所に存在する事をgo toolに教えているのだ。 goのツリーって実際なに?と聞くかもしれない。簡単に言うと 君のソース、パッケージ、コマンドの全てが格納される場所だと答えておこう。 まぁ見なさい:
$ ls /home/nu7/gocode/
bin pkg src
全てのソースはsrcフォルダーの中に位置するであろう。これはアプリケーション、パッケージ、そして依存している物、全てのソースという意味だ。
pkgフォルダーはコンパイルされてインストールされたパッケージが含まれ、cmdにはコマンドがインストールされる。
GOPATH変数はPATHに非常に似ており、必要なだけ多数のgoパスを設定出来る。
君はそれらの内、最初の一つをメインである覚えておかなけいけない。なぜならgo installでインストールされる全てはそこに入るからだ。
依存の解決
依存を明示する設定ファイルは無い... じゃぁどうやってgo toolはそれをどこからダウンロードして、どこにインストールしているのかを知り得るんだよ! リポジトリだろって思った?ノー、そんな物は無い。 Goはimportpathと呼ばれる物を導入している。 まぁ見なさい:
import "github.com/nu7hatch/gouuid"
import pathはツーインワンだ。
リポジトリURLでもあり、パッケージがローカルにインストールされる場所へのパスでもある。
go getツールはどこにフェッチすべき依存物があるかをimport pathを見て知る。
またgo buildはローカルにあるそれらをインポートする場所を知る。
システムに依存している物をインストールするには次のようにgo getツールを使う必要がある:
$ go get package-name
待った待った、ちょっと待った... このパッケージ名って何?
これはインストールしたい依存物のパッケージ名だ。
例えばgoのソースとしてfooという名前のパッケージがあった場合、go get fooを呼び出す事で全ての依存物がインストールされる。
パッケージから直接このツールを使う事も出来る:
$ cd ~/gocode/src/foo
$ go get .
その他の全てのgo toolは同じ様に動作し、パッケージ、あるいはそのimport pathの指定から直接呼び出せる。
また ... ワイルドカード(3つのドット)を使ってネストされたパッケージのグループにおいても使う事ができ、fooパッケージがいくつかの入れ子のパッケージを含んでいる場合、それら依存する全てはこれをやるだけで同時にインストールすることが出来る:
$ go get ./...
goのツリーに指定した依存物が既にインストールされている場合、明示的に要求しない限り更新されない。
依存しているパッケージを更新するにはgo getに-uフラグを付ける:
$ go get -u package-name
簡単でしょ?
依存地獄!
go toolを好きであると同時に恐れている、もう一つの取り決めがある。 Go toolはリポジトリのHEADバージョンをチェックして依存を解決する。 これはパッケージメンテナに後方互換性を維持する事を強要する。
グリーンマスターポリシーは私が仕事で常に主張していた事だった。 デフォルトブランチは人々がまず最初にチェックする物であり、したがってそれはグリーン(テストが全てパスした状態)であるべきで、それを動作させる為には少なくとも最新でなければならない! 一度公けに公開した、もしくは十分開発した段階ならば、後方互換性を持つべきだ。 我々は何かを廃止したり、パッチやマイナーバージョンである中でAPIの変更をする事は出来ない。
でも我々は練習の中でそれがどの様になるのかの全てを得て知る。 多くの人々は後方互換性なんて糞の様な物は提供しないし、彼らは遊び場としてデフォルトブランチを使う。 彼らの為に、そして新しいgo toolで平穏に暮らしたい開発者の為に、この取り決めのセットを
君がプログラマ人生を送る中で守るべきバカバカしいルール:
エルサレムの本を思い出しちゃうから何度も言わせないでくれ...
ビルドとインストール
Ok。goコマンドに話を戻そう。go buildコマンドはパッケージをコンパイルするのに使われる。
パッケージをビルドするだけでインストールはしない。
重要なのはパッケージはローカルソースツリーの中でチェックされなければならないという事。
代わりにリモートパッケージのインストールにはgo getが使われる:
$ go get github.com/nu7hatch/gouuid
ローカルのパッケージをインストールするためにはgo installツールが使われる。
これは最初にパッケージをビルドし(必要な場合)、$GOPATH/pkg、あるいは$GOPATH/cmd配下の物をインストールする。
go toolはフラグや特別な設定をしない限り特定のファイルをビルドから除外する事も出来る。 無視する為にやるべき事は、名前の先頭にアンダースコアを付けるだけ:
$ ls
_bar.go foo.go
$ go build .
上の例の_bar.goのはビルドからは無視される。
ふむ。この通り。これに関して言う事は何もない。先に進もう。
CGOによるC言語拡張
cgoコマンドによるC言語拡張の作成はかなり素晴らしい。
実際にC言語アプリケーションの殆どをビルドするのにcgoについてもっと知っておく必要は無く、go buildツールで十分なのだ。
素直に言うとcgoに関してはあまり言うことは無く、それらの殆どはだいたいドキュメント、そしてgo users wikiにある記事の中に記述されている。
まず言っておくべき事として私がそれが好きではない。オフィシャルの殆どの例で示される様にコメントの中にC言語のソースコードをそのまま配置している。
マジで本当に好きになれない。
主としてコードの量を最小化し、かつ単一のファイルで各例を示すために、サンプルがこの方法で提供されている事を知っておくべきだ。
現実のアプリケーションではC言語のコードはコメントブロックに配置すべきじゃない!
go buildツールはパッケージ内の.hや.cといったファイルをちゃんとスマートに扱ってくれるんだ。
例がいる? stdio.hにある関数printfを使って引数を画面に表示する単純なechoコマンドを書こう。
wikiページで言及されている様に、goはC言語の可変長引数の関数を呼び出す事は許していない。
よってprintf関数の小さなラッパを書かなければならない。
コードはgithubにある物の様になるだろう:
echo.h:
#ifndef _ECHO_H_
#define _ECHO_H_
#include <stdio.h>
void echo(char*);
#endif /* _ECHO_H_ */
echo.c:
#include "echo.h"
void echo(char* s)
{
printf("%s\n", s);
}
echo.go:
package main
/*
#include <stdlib.h>
#include "echo.h"
*/
import "C"
import (
"flag"
"unsafe"
"strings"
)
func main() {
flag.Parse()
cs := C.CString(strings.Join(flag.Args(), " "))
C.echo(cs)
C.free(unsafe.Pointer(cs))
}
これで君もgo buildツールでシームレスにビルド出来る様になる。
パッケージにある全てのC言語ファイルを認識し、コンパイルする。
つまりはこれだけでいいんだ!
プラットフォーム固有のビルド
もう一つ素晴らしく興味深い事にgo buildはプラットフォーム固有のファイルについてのコンパイルをハンドリング出来る事だ。ファイルを名前から解析している。(こんな感じ: file_GOOS_GOARCH.go もしくは file_GOARCH.go):
foo_darwin_amd64.go
foo_386.go
foo.go
この機能はC言語のファイルでもちゃんと動く:
foo_amd64.c
foo_386.c
foo.h
foo.go
ドキュメントの中で言われている通り、これらの機能は必要ない。しかし go toolが単純なわりに如何に柔軟なのかを色濃く表している事を言及しておきたい。
Ok。でも君はきっとこう聞くだろう。もしコンパイラのフラグや幾つかの設定など、何かトリッキーな事が必要な場合は?と
救うべきMakefile!
そう、makefileを使う事を恐れてはいけない! これは拡張設定による取り決めや、先行条件等に対処する為の、最も簡単で全く便利な方法だ。 Makefileは、C言語の拡張にだけ役立つ物ではなく、色んなパッケージにおいても同様に適用出来る(例えばwebrocketのトップレベルでは作業を楽にする為にmakefileを使っている)。
より明示的な例... それをベースとしているコアパッケージやコマンドラインツー ルを含んでいるアプリケーションを想像してみて欲しい。 このechoの例だとモジュールが多くてもやり遂げられるだろう:
echo/
pkg/
echo/
echo.c
echo.h
echo.go
cmd/
echo/
echo.go
pkg/echoパッケージはC言語のprintf関数を再利用出
来る様にラップし、そのソースは前述の例と殆ど同じであるとしよう。
cmd/echoコマンドはコアパッケージを使って画面に何かを出力する実行モジュールとしよう。
cmd/echoコマンドはこんな感じになるだろう:
package main
import (
"github.com/nu7hatch/cgoecho2/pkg/echo"
"flag"
)
func main() {
flag.Parse()
echo.Echo(flag.Args()...)
}
Note: slice... の意味を知らない人々のために言うと、引数の数に相当する変数へsliceをマップする物だ。Rubyで言うと*argsの様な物だ。
話を戻そう。Makefileが必要なパッケージの為に私達が用意しなければならない簡単な物、それは以下の様な物だ:
all: echo-pkg echo-cmd
echo-pkg:
go build ./pkg/echo
echo-cmd:
go build ./cmd/echo
これによりmakeを呼び出すだけで両方を瞬時にコンパイルでき、もっと重要な事を言うとリモートからそれらをインストールするのにもgoコマンドを使う事が出来るんだ。:
$ go get github.com/nu7hatch/cgoecho2/cmd/echo
もちろんこれは非常に単純な例だ。ソースの全てを俊敏にビルドするにはワイルドカード使う事も出来る。慌てずに:
$ go build ./...
しかし、多くのパッケージおよび(または)コマンドを含む巨大なアプリケーションを配布するのはトリッキーになりがちだ。
その際makefileやシェルスクリプト、君の好きな他のビルドツールを使うのは妥当な事なのだ。
まとめ
ハッキリと言おう。私は新しいgo toolをマジで愛してやまない。! 初め、それを触って遊んでいる間に山の様に問題に遭遇した。 しかしほとんどの問題は、他のパッケージマネージャ/ツールを使用する間に、私が得てきた幾つかの悪い習慣によって引き起こされた物だった。 はぁ...最近、go-nutsのIRCチャネルで愚かな質問を沢山してしまったよ。 そして私が得る答えは馬鹿らしく明白で単純だった...
以前使っていたeasy_installやrubygems、builderといったこれまでのツールを担う物と考えていている。
私の心の中に一枚だけ写真がある... あぁ、でも嫌いになられそうなので公開しない方がよさそうだ。 :)
代わりといってはなんだが、新しいgo toolを私がどの様に感じているかをお見せしよう...
私はgoが正しい向に向かっている事を見る事が出来てとてもうれしい。今日はこの辺にしておく。ごきげんよう。Gophers!