2016/03/09


コマンドラインから JSON を扱うツールとしては jq が一般的ですが、例えば ls を実行した結果を JSON の Array にしたいであったり、コマンドライン引数から簡単に Object を作りたいといった場合には一旦考え込まないといけないくらい使い方が難しかったりします。そんな中でひょいと現れたのが jo です。

GitHub - jpmens/jo: JSON output from a shell

JSON output from a shell

https://github.com/jpmens/jo

作者である jpmens さんがなぜ jo を作るに至ったかをブログに書いています。

Jan-Piet Mens :: A shell command to create JSON: jo

A shell command to create JSON: jo

http://jpmens.net/2016/03/05/a-shell-command-to-create-json-jo/

JSON を書くという行為は、プレースホルダ的に考えないといけなかったり、エスケープを気にしないといけなかったりと実は色々と思考停止要素を含んでいます。しかし jo であればとても直観的に JSON を生成する事が出来ます。

まずは引数から簡単に Object を作ります。

$ jo name=Jane
{"name":"Jane"}

シェルの引数で変数やコマンド展開を使うとエスケープを気にせず JSON を出力出来ます。

$ jo time=$(date +%s) dir=$HOME
{"time":1457195712,"dir":"/Users/jpm"}

配列も簡単

$ jo -p -a spring summer winter
[
 "spring",
 "summer",
 "winter"
]

-p オプションを付与すると pretty print になります。shell に慣れている人であれば複雑な JSON でも割と簡単に出力出来ます。

$ jo -p name=JP object=$(jo fruit=Orange hungry@0 point=$(jo x=10 y=20) number=17) sunday@0
{
 "name": "JP",
 "object": {
  "fruit": "Orange",
  "hungry": false,
  "point": {
   "x": 10,
   "y": 20
  },
  "number": 17
 },
 "sunday": false
}

引数を与えない場合、標準入力を読み込むのでコマンドの出力結果から配列を作るのも簡単。

$ seq 1 10 | jo -a
[1,2,3,4,5,6,7,8,9,10]

使い方はマニュアルに書かれています。

jo/jo.md at master · jpmens/jo · GitHub

NAME jo - JSON output from a shell SYNOPSIS jo [-p] [-a] [word ...] DESCRIPTION jo creates a JSON st...

https://github.com/jpmens/jo/blob/master/jo.md

ちなみに jo は Windows でもきちんと動作して、コマンドラインからマルチバイトを与えられても化けずに出力されます。

jq

入力元がストリームの場合は utf-8 として扱い、画面からの入力であった場合には自動的に utf-8 へ変換されます。出力も同様です。ログから必要な部分のみを grep して sed で加工して別の処理に JSON として渡したい、そんなニーズに簡単に答えられそうなツールです。

Posted at by



2016/02/24


golang で Web アプリを作ってると画像のアップロード処理を書くことって意外と多くて、その度にググったり過去の自分の実装を調べたりして、みたいな事を繰り返してましたが go-imageupload を使うとかなり端折れる事になりそうです。

GitHub - olahol/go-imageupload: Gracefully handle image uploading and thumbnail creation.
https://github.com/olahol/go-imageupload

実装は簡素ですが、毎回自分でこれを書いてたと思うと時間が勿体ないですね。使い方も簡単で README.md から転用すると 300x300 のサムネイル画像を生成するのはこれだけになります。

package main

import (
    "github.com/gin-gonic/gin"
    "github.com/olahol/go-imageupload"
)

func main() {
    r := gin.Default()

    r.GET("/"func(c *gin.Context) {
        c.File("index.html")
    })

    r.POST("/upload"func(c *gin.Context) {
        img, err := imageupload.Process(c.Request, "file")

        if err != nil {
            panic(err)
        }

        thumb, err := imageupload.ThumbnailPNG(img, 300300)

        if err != nil {
            panic(err)
        }

        thumb.Write(c.Writer)
    })

    r.Run(":5000")
}

サムネイルとは書いてますが、サイズが指定出来るので例えばアップロード画像のサイズを均一にしたい場合にも使えます。ブラウザ側の処理も dropzone.js を使えば簡単にアップロード画面が出来上がります。

まずはサーバ側のコード。

package main

import (
    "crypto/sha1"
    "fmt"
    "time"

    "github.com/gin-gonic/contrib/static"
    "github.com/gin-gonic/gin"
    "github.com/mattn/go-colorable"
    "github.com/olahol/go-imageupload"
)

func main() {
    gin.DefaultWriter = colorable.NewColorableStdout()
    r := gin.Default()

    r.Use(static.Serve("/", static.LocalFile("./assets"true)))

    r.POST("/upload"func(c *gin.Context) {
        img, err := imageupload.Process(c.Request, "file")
        if err != nil {
            panic(err)
        }
        thumb, err := imageupload.ThumbnailPNG(img, 300300)
        if err != nil {
            panic(err)
        }
        h := sha1.Sum(thumb.Data)
        thumb.Save(fmt.Sprintf("files/%s_%x.png",
            time.Now().Format("20060102150405"), h[:4]))
    })

    r.Run(":5000")
}

アップロードされた画像を 300x300 にリサイズして、日付と sha1 のファイル名付けて保存しているだけです。files というディレクトリに保存されます。クライアント側も dropzone.js 様様です。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>あぷろだ</title>
    <link rel="stylesheet" href="dropzone.css" media="all">
    <link rel="stylesheet" href="app.css" media="all">
    <script src="dropzone.js"></script>
</head>
<body>
<form action="/upload" class="dropzone" id="dropzone"></form>
</body>
</html>

一応、マウスホバーで色変えちゃうよ的な。

#dropzone {
  background-color#afa;
  bordersolid 3px #5a5;
  color#585;
  padding20px;
}

#dropzone.dropover {
  background-color#cfc;
  color#9c9;
}
upload

便利。

Posted at by



2016/02/15



先日、GitHub Pages が Jekyll 3.0 になりました。

GitHub Pages now faster and simpler with Jekyll 3.0 · GitHub

GitHub Pages is now running the latest major version of Jekyll, Jekyll 3.0 , and with it, many of th...

https://github.com/blog/2100-github-pages-now-faster-and-simpler-with-jekyll-3-0

速くなったという事でとても喜ばしいのですが、良い事はそれだけではなかった。GitHub Pages を使ってのブログ作成方法については、これまでこのブログでも幾つか紹介して来ました。

Big Sky :: Jekyllで始める簡単ブログ

GithubのユーザページでJekyllが使われる様になりました。 GitHub Pages Upgraded to Jekyll 0.5.0 - GitHub I just released Jek...

http://mattn.kaoriya.net/software/lang/ruby/20090409185248.htm
Big Sky :: githubとjekyllとoctopressで作る簡単でモダンなブログ

以前、「jekyllで始める簡単ブログ」という記事を書いたのですが Big Sky :: Jekyllで始める簡単ブログ GithubのユーザページでJekyllが使われる様になりました。 GitHu...

http://mattn.kaoriya.net/software/lang/ruby/20111017205717.htm

でも作った後でコードハイライトを導入したりフィードを吐いたりしようと思うと若干手間でしたし、最初は綺麗だったフォルダ構成もだんだんとグチャグチャとして来ていました。でも Jekyll 3.0 になった事でその殆どが解決してしまいました。以前は jekyll-bootstrap を使って https://mattn.github.io を作っていましたが、これを期に全部消し去って一から作り直しました。大変かなーと思ったけど、何も大変な事が無かった。

以下、その手順をご紹介します。既にリポジトリがある方は適当に読み飛ばして下さい。

リポジトリを作る

まず GitHub でリポジトリを作ります。名称は

create repository
USERNAME.github.io

という名前で作ります。ちなみに昔は

USERNAME.github.com

だった為、リポジトリ名も com で作ったよという方が多いと思いますが、Settings のページで名前を変えても動作する事を確認しました。

rename repository

Jekyll でサイトを生成する

ruby をインストールしたあと

$ gem install jekyll

とすれば2016年2月現時点ではバージョン3が入ります。でも「Jekyll のサイトを準備する為だけに ruby を入れて、Jekyll を入れるってちょっと面倒!Golang 使わせろよ!」って人は Jedie を使うといいです。

Big Sky :: Golang で Jekyll のクローン作った。

普段 vim-jp や色んな所で jekyll を使っているのだけど、どうも遅くて困っていました。 Windows だと ruby 本体の起動も重いのに、たかだか数十ページの生成に十数秒、PCの負荷が...

http://mattn.kaoriya.net/software/lang/go/20131128182642.htm

Jedie は Jekyll と互換性がある為、Jedie を使って生成したサイトはそのまま GitHub Pages に push する事が出来ます。

※ここ重要です。

サイトの生成方法は

$ jedie new /path/to/root

の様に実行して下さい。あとは

$ git add .
$ git commit -a
$ git remote add origin git@github.com:USERNAME/USERNAME.github.io.git
$ git push origin master

USERNAME 部分はご自分のアカウントで差し替えて下さい。

とすれば簡単なサイトが出来上がります。僕もデフォルトのサイトから若干デザインに手をいれて以下のサイトを作りました。

Screw It!

jekyll-bootstrap を使ってたのだけど新規投稿が反映されない問題があったので、一旦全部消して作り直した。使ったのはお手製の jekyll clone、jedie1 jedie new ....

https://mattn.github.io/

なお、ちまちまと Jekyll を使ってマニュアル通り設定したいよ!という方は以下を参照下さい。

Using Jekyll with Pages - User Documentation

Bundler - Bundler is a package manager that makes versioning Ruby software like Jekyll a lot easier ...

https://help.github.com/articles/using-jekyll-with-pages/

Jekyll の拡張を有効にする

Jekyll 3.0 になった一番の良さはこれだと思っています。

Using Jekyll Plugins with GitHub Pages - User Documentation

GitHub Pages currently supports several Jekyll plugins: Jemoji - provides support for emoji within J...

https://help.github.com/articles/using-jekyll-plugins-with-github-pages/

_config.yml に以下の様に追加します。

gems:
    jemoji
    jekyll-mentions
    jekyll-redirect-from
    jekyll-sitemap
    jekyll-feed

Jemoji

拡張子が md (markdown) の場合、GitHub 上で使える絵文字が使える様になります。例えば :+1: であれば :+1: という画像に置き換わります。以下はその例

Jedieでサイトを作り直した。 - Screw It!

Screw It! Jedieでサイトを作り直した。 jekyll-bootstrap を使ってたのだけど新規投稿が反映されない問題があったので、一旦全部消して作り直した。 使ったのはお手製の jek...

http://mattn.github.io/2016/02/14/site-with-jedie.html

jekyll-mentions

記事内で @mattn という表記を使うと、GitHub アカウントへのリンクが作られます。上記の記事内で @mattn がリンクになっているのを確認下さい。

jekyll-redirect-from

GitHub Pages は markdown で書くのですが、デフォルトではファイル名がタイトルになります。もちろん以下の様に書くことでタイトルは置き換えられるのですが

---
layout: post
title:  Jedieでサイトを作り直した。
---
jekyll-bootstrap を使ってたのだけど新規投稿が反映されない問題があったので、一旦全部消して作り直した。

使ったのはお手製の jekyll clone、[jedie](https://github.com/mattn/jedie)

```shell
$ jedie new .
$ vim _posts/2016-02-15-rebuild-site-with-jedie.md
$ git add .
$ git commit -a
$ git push origin master
```

jedie 便利。 :+1:

@mattn ++

ファイル名の先頭に付く日付を変えてしまったり、ファイル名そのものを変えてしまうと URL が変わってしまいます。この拡張を有効にしておくと、そういった場合でも古い URL から新しい URL の自動転送が有効になります。

jekyll-sitemap

この拡張を導入すると、それだけでサイトマップが自動生成されます。

jekyll-feed

これも以前は無かった機能です。以前は RSS フィードを吐き出すのに以下の様なファイルを自前で作る必要がありましたが

---
layout: nil
---
<?xml version="1.0" encoding="utf-8" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>{{ site.title | xml_escape }}</title>
    <link>{{ site.baseurl | xml_escape }}</link>
    <atom:link rel="self" type="application/rss+xml" href="{{ page.url | xml_escape}}" />
    <pubDate>{{ site.time | date: "%a, %d %b %Y %H:%M:%S +0900" }}</pubDate>
    <lastBuildDate>{{ site.time | date: "%a, %d %b %Y %H:%M:%S +0900" }}</lastBuildDate>
    {% for post in site.posts %}
    <item>
      <title>{{ post.title | xml_escape }}</title>
      <link>{{ post.url | xml_escape }}</link>
      <guid isPermaLink="false">tag:mattn,{{ post.date | date: "%Y/%m/%d" }}:{{ post.url | xml_escape }},rev:1</guid>
      <pubDate>{{ post.date | date: "%a, %d %b %Y %H:%M:%S +0900" }}</pubDate>
      <author>mattn.jp@gmail.com (mattn)</author>
      <description>{{ post.content | xml_escape }}</description>
    </item>
    {% endfor %}
  </channel> 
</rss>

この拡張を入れるだけでフィードが自動生成されます。何それすげー便利じゃん。

あとはレイアウトファイルの head 部分を以下の様に書くだけで link タグが生成されます。

<head>
  <meta charset="UTF-8">
  <title>{{ site.title }}</title>
  {% feed_meta %}
</head>

Jekyll 3.0 でコードハイライトがデフォルトになった

以前はコードをハイライトさせる為には Google Code Prettify を使うハックが必要でした。しかし Jekyll 3.0 では rouge という highlighter がデフォルトになった為、ユーザは css ファイルだけ用意すれば良くなりました。以下は僕が使っているハイライト用の css です。

.highlight { 
  background-color#efefef;
  padding7px 7px 7px 10px;
  border1px solid #ddd;
  -moz-box-shadow3px 3px rgba(0,0,0,0.1);
  -webkit-box-shadow3px 3px rgba(0,0,0,0.1);
  box-shadow3px 3px rgba(0,0,0,0.1);
  margin20px 0 20px 0;
  overflowhidden;
}
 
code {
  font-family:'Bitstream Vera Sans Mono','Courier', monospace;
}
 
.highlight .c { color#586E75 } /* Comment */
.highlight .err { color#93A1A1 } /* Error */
.highlight .g { color#93A1A1 } /* Generic */
.highlight .k { color#859900 } /* Keyword */
.highlight .l { color#93A1A1 } /* Literal */
.highlight .n { color#93A1A1 } /* Name */
.highlight .o { color#859900 } /* Operator */
.highlight .x { color#CB4B16 } /* Other */
.highlight .p { color#93A1A1 } /* Punctuation */
.highlight .cm { color#586E75 } /* Comment.Multiline */
.highlight .cp { color#859900 } /* Comment.Preproc */
.highlight .c1 { color#586E75 } /* Comment.Single */
.highlight .cs { color#859900 } /* Comment.Special */
.highlight .gd { color#2AA198 } /* Generic.Deleted */
.highlight .ge { color#93A1A1font-styleitalic } /* Generic.Emph */
.highlight .gr { color#DC322F } /* Generic.Error */
.highlight .gh { color#CB4B16 } /* Generic.Heading */
.highlight .gi { color#859900 } /* Generic.Inserted */
.highlight .go { color#93A1A1 } /* Generic.Output */
.highlight .gp { color#93A1A1 } /* Generic.Prompt */
.highlight .gs { color#93A1A1font-weightbold } /* Generic.Strong */
.highlight .gu { color#CB4B16 } /* Generic.Subheading */
.highlight .gt { color#93A1A1 } /* Generic.Traceback */
.highlight .kc { color#CB4B16 } /* Keyword.Constant */
.highlight .kd { color#268BD2 } /* Keyword.Declaration */
.highlight .kn { color#859900 } /* Keyword.Namespace */
.highlight .kp { color#859900 } /* Keyword.Pseudo */
.highlight .kr { color#268BD2 } /* Keyword.Reserved */
.highlight .kt { color#DC322F } /* Keyword.Type */
.highlight .ld { color#93A1A1 } /* Literal.Date */
.highlight .m { color#2AA198 } /* Literal.Number */
.highlight .s { color#2AA198 } /* Literal.String */
.highlight .na { color#93A1A1 } /* Name.Attribute */
.highlight .nb { color#B58900 } /* Name.Builtin */
.highlight .nc { color#268BD2 } /* Name.Class */
.highlight .no { color#CB4B16 } /* Name.Constant */
.highlight .nd { color#268BD2 } /* Name.Decorator */
.highlight .ni { color#CB4B16 } /* Name.Entity */
.highlight .ne { color#CB4B16 } /* Name.Exception */
.highlight .nf { color#268BD2 } /* Name.Function */
.highlight .nl { color#93A1A1 } /* Name.Label */
.highlight .nn { color#93A1A1 } /* Name.Namespace */
.highlight .nx { color#555 } /* Name.Other */
.highlight .py { color#93A1A1 } /* Name.Property */
.highlight .nt { color#268BD2 } /* Name.Tag */
.highlight .nv { color#268BD2 } /* Name.Variable */
.highlight .ow { color#859900 } /* Operator.Word */
.highlight .w { color#93A1A1 } /* Text.Whitespace */
.highlight .mf { color#2AA198 } /* Literal.Number.Float */
.highlight .mh { color#2AA198 } /* Literal.Number.Hex */
.highlight .mi { color#2AA198 } /* Literal.Number.Integer */
.highlight .mo { color#2AA198 } /* Literal.Number.Oct */
.highlight .sb { color#586E75 } /* Literal.String.Backtick */
.highlight .sc { color#2AA198 } /* Literal.String.Char */
.highlight .sd { color#93A1A1 } /* Literal.String.Doc */
.highlight .s2 { color#2AA198 } /* Literal.String.Double */
.highlight .se { color#CB4B16 } /* Literal.String.Escape */
.highlight .sh { color#93A1A1 } /* Literal.String.Heredoc */
.highlight .si { color#2AA198 } /* Literal.String.Interpol */
.highlight .sx { color#2AA198 } /* Literal.String.Other */
.highlight .sr { color#DC322F } /* Literal.String.Regex */
.highlight .s1 { color#2AA198 } /* Literal.String.Single */
.highlight .ss { color#2AA198 } /* Literal.String.Symbol */
.highlight .bp { color#268BD2 } /* Name.Builtin.Pseudo */
.highlight .vc { color#268BD2 } /* Name.Variable.Class */
.highlight .vg { color#268BD2 } /* Name.Variable.Global */
.highlight .vi { color#268BD2 } /* Name.Variable.Instance */
.highlight .il { color#2AA198 } /* Literal.Number.Integer.Long */

見た目はこんな感じになります。

以前はハックを行う為にいろいろなファイルを assets に入れていましたが、Jekyll 3.0 対応を行った後はめちゃくちゃシンプルになってとても見通しが良くなりました。

GitHub - mattn/mattn.github.io: mattn.github.io

You signed in with another tab or window. Reload to refresh your session. You signed out in another ...

https://github.com/mattn/mattn.github.io

皆さんもぜひ、Jekyll 3.0 対応を行ってみてはどうでしょうか。

Posted at by