のらねこの気まま暮らし

技術系だけど、Qiita向きではないポエムとかを書くめったに更新されないヤツ

formizeっていうjquery用のpluginを書いた

description

formにデータと突っ込んだり、データを取得するときに、$('#form').find('[name]').val()みたいなコードを毎回毎回書くのが面倒だったのでplugin化しました。

getValue(s)で取得、setValue(s)で設定できます。エラーがあった時とか入力にバインドしてごにょごにょしたいときように、getControl(s)で対象要素のjqueryオブジェクトを取得できるようにしてあります。 取得は$form.find('[name]')で取れるようにしてあり、name属性にサーバー側で受け取りたかったりロジック的に管理したい名前を振ればシームレスにデータ処理ができます。便利ぃ。

Heimdallに同梱しようと思ってた機能なんですけど、こっちのほうが汎用性たかそうだなって思ったので分離して別のpluginにしました。

examples

<form id="example">
  <input type="hidden" name="id">
  <input type="text" name="title">
  <input type="text" name="author">
  <textarea name="body" rows="4"></textarea>
  <select name="publish_state">
    <option value="publish">公開</option>
    <option value="unpublish">非公開</option>
  </select>
  <button type="submit">登録</button>
</form>

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script src="/js/formize.js"></script>
<script>
  $(function () {
    var $form = $('#example');
    var form = $.formize($form);

    $.getJSON('/api/memo/' + url.param('id'))
      .done(function (data) {
        form.setValues({
          id: data.id,
          title: data.title,
          author: data.author,
          body: data.body,
          publish_state: data.publish_state
        });
      });

    $form.on('click', function () {
       var data = form.getValues();
       $.post('/api/memo', data).done(function () { alert('登録したよ'); });
    });
  });
</script>

todo

  • checkboxやradioのデータを取れるようにする

repository

jquery-formize

requirejsで管理してるjsのキャッシュを管理する方法

requirejsはいいツールなんだが初めてjsがキャッシュに残ってしまって更新されなくてどうしたもんかと調べたので記録。

urlArgs

requirejsのconfigにurlArgsというのがある。 読んで字の通り、requirejsで読み込んだjavascriptファイルのurlのクエリパラメーターに適当なパラメーターを設定できるというもの。

require.config({
  urlArgs: 'v=2',
  paths: {
    ...

これでファイル更新にともなうcacheの更新が簡単になった。

今後の展望

package.jsonとかのversionみてリリースのタイミングでまとめてversionアップとかできたら、それはとっても素敵だなって

# 参考にしたサイト

http://www.inazumatv.com/contents/archives/8149

HeimdallというjQuery/Zeptoで使えるFormValidatorを書いた話

温泉発火村#2に参加しましたという記事で紹介したライブラリの話をもうちょっと突っ込んで話します。

Synopsis

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script src="/js/heimdal.min.js"></script>
<script>
// validatorのインスタンスを生成
var heimdall = $.heimdall({
    "name"    : ["required", ["length", [1,  32]]],
    "age"     : ["required", "int"],
    "gender"  : ["required", ["select", ["male", "female"],
    "message" : [            ["length", [0, 256]]]
});

$('.form')
  .on('submit', function () {
    var result = heimdall.validate({
      "name": $('#input-name').val(), // みたいな感じでフォームのデータを{name: value, }でvalidateに渡す
      ...
    });
  
    if (result.has_error()) { // エラーがあったら ...
      $(this).trigger('invalid', [result]); // エラーだよってイベントのトリガ発火するとか。
    }
  })
  .on('invalid', function (e, result) {
    // エラーを表示するなり、アラートを出すなり、リダイレクトするなり。
  });

Heimdallがやること

  • データの制約(ルール)の定義と保持
  • 与えられたデータが制約に基づくものかの検証
  • すべてのデータが制約通りのものかどうかの判定

制約(ルール)の定義

言わずもがな、必須入力、数値入力、E-mail、電話番号その他もろもろ、入力フォームに応じ仕様と照合して「何が正しいデータなのか」を定義するもの。

この制約は、formのnameアトリビュート毎にArrayで制約を定義する。 制約は独自のものを定義することもできる。

heimdal.load_constraints('my_rule', function (value) {
  // `tamanegi`以外の入力は受け付けない
  return value === 'tamanegi' ? true : false;
});

より柔軟に仕様に対応することができ、またheimdallの拡張も可能。

デフォルトでは、

  • requires: 必須入力
  • length: 入力文字列の上限・下限を設定できる
  • select: 文字列の集合の中に含まれている文字列である
  • int: 整数値である

が定義されている。

与えられたデータが制約に基づくものかを検証

いわゆるバリデーションの機能。 与えるデータは、formのnameアトリビュートをキーとしたオブジェクトを期待する。

すべてのデータが制約通りのものかどうかの判定

バリデーションはその結果をResultのオブジェクトとして返す。 これはエラーの有無/エラーの内容を取得することができる。

これは主にForm上でユーザにエラーの内容を表示するために利用する、ことを想定している。

Heimdallの背景

そもそもなんで「ヘイムダル」なのか。北欧神話の神が由来で、巨人の軍勢がビフレストを渡ってアースガルズへ侵攻するのを知らせる、という門番の役割を持ってる、ということから。

WEBサイトのフォームは、CGIの時代から多くのパターンが考慮され、またサイトの仕様に密接に関連している。使い勝手もサイトによって千差万別。

「サーバ側で不適切なデータであれば弾けばいい」というものから、「よりユーザにわかりやすいように」と考慮されたリッチなフォームまで存在する。

2013年において、入力フォームはJavaScriptを用いて多くの場合において逐一サーバーにリクエストを投げなくても正しい/正しくないの判定を行うことができ、かつ柔軟に表示を切り替えるようになっている。それも、端末にさほど負荷をかけずに。(例外はあるけれど

しかし、その実装は非情に面倒でありバリデーションようにライブラリは多くあるけれど、なかなか僕の好みに合うライブラリがなかった。

  1. バリデーションの制約を拡張できる
  2. エラーが出た時にその事由を取得し、シームレスにUIへ伝達できる
  3. jQuery, Zeptoのどちらでもつかえること
  4. (僕個人としての)直感的なインターフェース

4つめは、単純に気持よくかけるかどうかなんですが・・・

Heimdallはこの辺を指標として実装しました。

Heimdallの目指すトコロ

正直、Heimdallには足りない機能がある。

  • formに入力されているデータの取得する機能
  • formにエラーを伝達しUIを更新する機能
  • 単体のinputに対するバリデーション

formとの連携は、悩んだ結果、Heimdallから外すことにした。formの構造や取得方法は、Heimdallに依存してしまう。汎用性を求めようとすれば、その分ソースが膨らむ。メンテナンスコストも。

なので、それは(formaize)https://github.com/rymizuki/jquery-formizeというライブラリに委譲した。

formizeの構造・機能を許容できるのなら、それによって簡単にデータの取得/更新が可能になる。

単体のinputに対するバリデーションは、今後の課題として今もなお検討中。 なかなか良いアイディが浮かばず悶々としている。

あとがきてきな

さて、なんでこんな記事を書いているかというと、@karupanerura に触発されたというのが一番の理由なんだけれど。

jQueryHTML5の登場で、リッチなUIの実装はそのハードルは大分下がった。 しかし、それでもまだ「全角数字のみを受け入れるフォーム」「どのinputが間違っているのかわからないエラー」等の実にイケてないフォームは未だ多くある。

わざわざサーバにリクエストしてページを遷移しなくても、そのフォーム、そのページ内でエラーをハンドルできるんだから、通信とか無駄に時間を取って、ユーザ体験を損ねているだけじゃね? って思うことは多々ある。

多々あるが、それでも「じゃあJSで書きなヨー」とは言えない。それなりにコストがかかるし、僕もやっぱりPerlで書いたほうが早いし楽だって思うから。

Heimdallしかり、formizeしかり、僕はそういうハードルを下げたいと思ってる。もっとお手軽に、もっと少ないコードで、もっと素早く実装できるようにしたい。

これらのライブラリは少なくとも僕がストレスに思っていた、あるいはコピペで済ませていたやつを集約して汎用化したものなので、まだまだ至らない点は多くあると思う。 それでも、こうして公開して、自分だったり自分以外の誰かに使ってもらって、コードに対する知見をためて、改善していくことができるのも、いまのWEBがあってこそ。Github万歳ヽ(^o^)丿

何が言いたいかというと、全角数字入力のフォームとかうざいし通信の待ち時間とかストレスでそういうフォームを撃滅したいので簡単に実装にできるようなプラグインのために試してIssueとかぷるりくとか投げたり投げられたりしてだせーWEBサイトを減らしていこうぜ!!!

Heimdall、よろしくお願いします。

――と、SYNOPSIS以降はガリレイドンナ見ながら書いてたのでおかしな文章になってるかもしれないけど、がんばって明日はfromizeの記事を書きたいな! サムライフラメンコ見て寝よう。

Text::Xslateにis_array_ref, is_hash_refはビルトインで入ってる

月一でとあるチャンネルでぼやいてるきがするのでそろそろメモることにした。

$ perldoc Text::Xslate::Manual::Builtin
: if is_array_ref(hoge) {
<p>arrayref</p>
:}

そんな僕を見た某かるぴす先生から適切なアドバイスを受けた。

$MODULE::Manual 以下はひと通り眺めてからつかうといいよ!

おっしゃるとおりで・・・だが、 忘 れ て し ま え ば 、な ん の 意 味 も な い

ので、日々記録を大切にね。

grunt-init で jquery-plugin を作って travisCIに上げるまでのメモ

準備

以下をインストール

$ npm install -g grunt-init
$ git clone https://github.com/gruntjs/grunt-init-jquery.git ~/.grunt-init/jquery

プロジェクトの作成

grunt-init jqueryをプロジェクトディレクトリで走らせるとplugin用のアセットを生成してくれる。 なお、既にルートディレクトリにpackage.jsonが存在するとエラーになる模。様l

$ mkdir eg-grunt-init
$ cd eg-grunt-init
$ grunt-init jquery

生成されたコード

.
├── CONTRIBUTING.md
├── Gruntfile.js
├── LICENSE-MIT
├── README.md
├── eg-grunt-init.jquery.json
├── libs
│   ├── jquery
│   │   └── jquery.js
│   ├── jquery-loader.js
│   └── qunit
│       ├── qunit.css
│       └── qunit.js
├── package.json
├── src
│   └── eg-grunt-init.js
└── test
    ├── eg-grunt-init.html
    └── eg-grunt-init_test.js

とりあえず動かす

なにもオリジナルなコードは書かずに、そのまま動かす。

$ npm install
$ npm test

すでにもうテストが動くという親切っぷり。 テストはqunitを使っている。そのまま使うか、mochaでも入れるか、は各自の自由なのかな。 また、jshintも設定されてるので、これに従えばjqueryの規約に沿ったコードになる様子。

サンプルコードは2indentで書かれているが、jshint的には特に規定はなく、そのまま4indentで書いてしまったが、好きに設定して良いのかもしれない。 まあ、minifyするか

pluginを実装する

かく。 テスト通らせる

travisCIに上げる

ここでちょっとあれこれしたのでメモ。

  • grunt-cliをinstallする
    • デフォルトではgrunt-cliが無いので、npm install --save-dev grunt-cliした
  • vesionかえる
    • package.jsonに定義されているversionが0.0.0-ignoredだったので、npmとれなかった気配
    • versionやnpmの流儀についてはちゃんと調べずここまで来ているので、なんか勘違いしてるきもするけど、とりあえず動いたので。

おしまい

grunt-initはべんりだなーって思った。 でもqunitは使いにくい。

あ、あと。jquery-formize on Githubというpluginを書きました。form要素にデータ入れたりデータ取ったりエラーのスタイル当てるのにいい感じにしてくれる子がほしかった。 この子を書くときにgrunt-initに入門したので、色々勉強になった。まる。

plenv install-cpanmをすると~/perl5にcpanmをインストールして困った話

App::cpanminusはインストールディレクトリの決定にオプションとしてのlocal_lib環境変数PERL_LOCAL_LIB_ROOTPERL_MM_OPTを参照して決定するようになっている。

僕のMac Book Airさんはたぶん昔にlocal::libをインストールしたりした経緯からか、PERL_LOCAL_LIB_ROOT及びPERL_MM_OPT/User/$user/perl5になっており、cpanmのインストールがPLENV_ROOTよりも優先されてしまっていたため、何をどうしても、/User/$user/perl5にcpanmがインストールされ、plenvからcpanmがたたけ無いというこまった事態におちいったのでした。

どこでPERL_LOCAL_LIB_ROOTPERL_MM_OPTがセットされたのかは謎・・・とりあえず、こいつら消したらちゃんとplenvのversionにinstallできたので備忘録として。

追記

Cartonをinstallしたつもりが、また~/perl5にインストールされた。

$ plenv exec cpanm Carton
$ plenv exec carton install
plenv: carton: command not found
$ plenv exec perldoc -l Carton
/User/mizuki/perl5/lib/Carton.pm

で、まだなにかあるのかと、環境変数をあさったらPERL_MB_OPTというのがございましてですね。。。 これもどうやらlocal::lib系の何からしい。 こいつも潰して、もうないはず。。。

温泉発火村 #2 に参加しました #発火村

概要っぽいの

温泉発火村とは

温泉発火村 #2 : ATNDより抜粋。

温泉発火村とは 温泉でハッカソンしようぜという企画です。まーまー普通のハッカソンです。 ノートPCが持参出来ればだれでも参加出来ます。

温泉でゆったりしつつ美味しいものを食べつつわいわいもくもくハックしようぜ!ってイベントです。

会場について

今回の会場は山木旅館(静岡県熱海) という旅館で、なかなか良い感じでした。あとご飯が美味しかった。ご飯が美味しかった。(大事なことなの(ry

ふりかえり

ご飯美味しかったなぁ・・・お昼ごはんに食べた「あじなどんぶり」。味のぬかづけ?だったろうか、臭みもなくてでも鯵の味がしてて、程よい香りがついてて、一杯では物足りない感じだった。

・・・って考えてるとご飯が美味しかったコトだけで記事埋めちゃうのでこの辺はコンテンツ力ある方々におまかせして。 僕は淡々と作ったものの話をしますよ。

成果物

https://github.com/rymizuki/Heimdall

Heimdal!! キラキラネームを採用したjQuery,Zeptoで使えるFormValidatorモジュールを作りました。 もともとbackbone-validatorというBackbonejs用のValidator書いてたんですけど、弊社開発二部のチャンネル内にて「それBackboneに依存しなくてよくね」ってツッコミもらったので、underscorejsの依存を外して$系とネイティブコードを使ったValidatorに書き換えました。

SYNOPSISとしてはこんな感じ。

// validatorのインスタンスを生成
var heimdall = $.heimdall({
    "name"    : ["required", ["length", [1,  32]]],
    "age"     : ["required", "int"],
    "gender"  : ["required", ["select", ["male", "female"],
    "message" : [            ["length", [0, 256]]]
});

$('.form')
  .on('submit', function () {
    var result = heimdall.validate({
      "name": $('#input-name').val(), // みたいな感じでフォームのデータを{name: value, }でvalidateに渡す
      ...
    });
  
    if (result.has_error()) { // エラーがあったら ...
      $(this).trigger('invalid', [result]); // エラーだよってイベントのトリガ発火するとか。
    }
  })
  .on('invalid', function (e, result) {
    // エラーを表示するなり、アラートを出すなり、リダイレクトするなり。
  });

みたいな感じでバリデーションに特化したモジュールになっております。 ちょっとJSの流儀であるところの命名規則とか、jQueryの公式が出してるpluginのフォーマットに沿ってない、とかもろもろ後になってから気づいたんだけど。

特にdisが飛んでこなければ僕の好みのままで放置しようかなと。

今後の予定

  • ・・・とは言うものの、jQueryのフォーマットには沿わせようかなと。配布の仕組みとかよくしらないし。
  • @gfx さんより「キーアップ等のイベントに連動して特定のinputだけvalidationしたいケース」という宿題を提示してもらったので直近のTODOにする。

今回の困ったこと

  • 唐突に僕のpocketWifiが初期化されパスワードがわからず @kfly8 の無線LANを借りる事になった。事故にも程がある
  • 電源コンセントが辛かったのでタコ足持って行くと良い。
  • testemをgrunt-testemからではなく直接叩きたかったがディレクトリ構造の解決がうまくいかず数時間testemの調査で終わってしまった。
  • 温泉が気持ちよすぎて、ご飯が美味しすぎて、満足感に浸りすぎて作業にならない

今回の学び

  • 熱海素晴らしい
  • 熱海のご飯は実に美味しい
    • 山木旅館さんは山木茶屋という食事処を併設してて(そこでお昼食べた)そこのご飯も実に、実に美味しかった。   * またいきたい
  • grunt-init jquery jsプロジェクトのひな形はコピペで済ましていたんだけど、やっぱりジェネレーター使うべきだなって思った。
  • $.expr[':'].heimdall jQueryの拡張セレクタは、実は好きに定義することが可能。
  • Zeptojsには拡張セレクタが無いので、DOM操作周り気をつけないとjQueryでは動くけど、Zeptoだと動かないプロダクトが出来上がる。
    • 拡張セレクタが使えないのは結構大きい気もするけど、Form操作がそんなに無いなら大体querySelect系でなんとかなる気もする。
  • 海楽しい

まとめ

  • Heimdallというバリデーション特化ライブラリを書きました。
  • 熱海最高
  • 山木旅館飯が美味い
  • 温泉発火村はやっぱり最高だぜ!