Validation Night で focuslight-validator の紹介をしてきたよ
良いイベントでございました。
LT の機会をいただきありがとうございました。
しゃべったこと
focuslight-validator という、おもに HTTP リクエストパラメタのヴァリデーションのために使うモジュールの紹介をしました。
LT なのに 40p 超のスライド作っちゃって、ガーッと駆け足でやったけど 90s くらいオーバーして迷惑をかけてしまった。
focuslight-validator
focuslight/focuslight-validator · GitHub
スライドにも書いたけど、汎用的に使えるヴァリデーションモジュールです。
名前から察すると、Focuslight 専用なの?って思わなくもない*1けど、Rails でも Padrino でも使える(と思う。使ったことはない。)汎用的なヴァリデーションモジュールなのです。
もともと Focuslight に含まれていたものを切り出してもらったという感じでございます。
focuslight の validator を他のアプリで使いたいな。切り出してはくれないかしら。 https://t.co/9NuBRXFRMZ
— Satoshi SUZUKI (@studio3104) 2014, 4月 22
@studio3104 Focuslight::Validator とかでよさそうな気がするけど、近くのサトシ氏と最初に意識合わせしてもらえるとよさそう^ ^
— そのっつ (SEO Naotoshi) (@sonots) 2014, 4月 22
I've just released "focuslight-validator" v0.0.1 gem!
— tagomoris (@tagomoris) 2014, 4月 22
focuslight-validator (0.0.1): http://t.co/zEK80ueMer Validate http request parameters (or others) by defined rule, without models.
— RubyGems (@rubygems) 2014, 4月 22
あれ、focuslight-validator gem 出てた
— そのっつ (SEO Naotoshi) (@sonots) 2014, 4月 22
要望をぺろっとつぶやいてたら音速で切りだされてリリースされてた。
で、
@tagomoris 拝承
— Satoshi SUZUKI (@studio3104) 2014, 4月 22
というやりとりがあったのにもかかわらずずっと放置してた README の p-r を昨日の深夜に出して、さっき無事に取り込んでもらいました。
update README.md by studio3104 · Pull Request #3 · focuslight/focuslight-validator · GitHub
半年以上やるやる詐欺して放置してたのに即日対応してもらって泣いてる
— Satoshi SUZUKI (@studio3104) 2014, 12月 5
使い方がわかったらあとは使うだけだよ!!!!!
便利なのでぜひ使ったらいいと思う。
感想とか
なんか Java とか Rails の人はコントローラ層でのヴァリデーションをあまりしない人が多いという話をちらほら聞いた。
自分は Sinatra でしかウェブアプリケーションを書いたことがないので、そこらへんの文化とかよく知らないけど、自分の常識、認識との乖離を感じた。
これについては気持ちが乗ったら別のエントリで私見を述べたい。気持ちが乗ったらね。
まぁとりあえず Sinatra でなんか作ることがあって、コントローラ層でのヴァリデーションをしたくなったら focuslight-validator を使ってみたらいいのではないかと思う。
スライド
こちらのいけてるスライドは Deckset で作りました。
*1:実際に懇親会で聞かれたし
sinatra ですぐにアプリケーションの実装に入れるようにするための準備
背景
自分が仕事で書く WEB アプリケーションは多くの場合が小粒で、何か書く場合には sinatra
を使っています。
さらにテンプレートエンジンは slim
で、ビューが必要な場合は twitter bootstrap
を使って書きます。
で、新規で何か書き始める時に、それっぽいディレクトリ構成を作って、twitter bootstrap
とか jquery
とかをダウンロードして解凍してそれっぽいところに設置してー(もしくは既存プロジェクトをディレクトリごとコピーしてきて要らないファイル消してネームスペース変更してー)、とかっていうローテクな感じのことを毎回手動で行っていて、すっと実装に入れない!めんどくせー!ってなることが多いので、いったん整備してみました。
studio3104/ore-no-sinatra-skelton · GitHub
構成
javascript/css ライブラリ群は bower
で管理して、自分で書く javascript/css は coffee/sass で assets 配下に記述し、grunt
によって自動コンパイルされます。
いずれも public
配下に勝手に設置されます。
ore-no-sinatra-skelton ├── Gemfile ├── Gemfile.lock ├── Gruntfile.coffee ├── Procfile ├── assets │ ├── application.coffee │ └── application.scss ├── bower.json ├── config.ru ├── lib │ ├── skelton │ │ └── app.rb │ └── skelton.rb ├── package.json └── views ├── index.slim └── layout.slim
とりあえず試すだけならこんな感じでやればすぐに sinatra
まわりの実装に入れるでしょう
$ git clone https://github.com/studio3104/ore-no-sinatra-skelton.git $ cd ore-no-sinatra-skelton $ npm install -g grunt-cli $ npm install $ bundle $ bundle exec foreman start
これで、localhost:9292
でアプリケーションが起動します。
あとは lib
, views
, assets
配下のファイルを編集して開発していくだけです。
少し詳しく解説
bower
bower は javascript/css ライブラリ群 のパッケージマネージャで、bower.json
に記述されたパッケージを Search Bower packages から取得してきて bower_components
ディレクトリ配下にインストールして管理してくれます。
しかしただそれだけであって、例えば javascript のファイルを public/js
配下に、css のファイルを public/css
に設置するなど、そういったことを柔軟にやってくれるわけではありません。
そういったことは、後述する grunt
によって解決します。
bower.json 全体
dependencies
に必要なライブラリ名とバージョンを記述します。
exportsOverride
は、後述する grunt
の grunt-bower-task
から利用する場合に、dependencies
に記述されたそれぞれのライブラリの中からどのファイルが必要なのか明示するために記述します。
{ "name": "ore no sinatra skelton", "version": "0.0.1", "dependencies": { "vue": "latest", "underscore": "latest", "jquery": "latest", "bootstrap": "latest", "bootswatch": "latest", "Font-Awesome": "latest" }, "exportsOverride": { "jquery": { "js": "dist/*" }, "underscore": { "js": [ "underscore-min.js", "underscore-min.map" ] }, "vue": { "js": "dist/vue.min.js" }, "bootstrap": { "js": "dist/js/bootstrap.min.js", "css": [ "dist/css/*.min.css", "dist/css/*.map" ], "fonts": "dist/fonts/*" }, "bootswatch": { "css": "journal/bootstrap.min.css" }, "Font-Awesome": { "css": "css/font-awesome.min.css", "fonts": "fonts/*" } } }
bower 単体での利用
後述する grunt
などと組み合わせてではなく、単体で利用する場合は、上記のような bower.json
を用意するか、 bower init
コマンドによって対話的に bower.json
を作成した後、 bower install
コマンドを実行します。
bower install [package name]
コマンドを実行すると、[package name]
のみインストールすることも出来ます。
また、 bower install [package name] --save
コマンドを実行することで、[package name]
の情報が bower.json
に記述されます。
今回は単体利用の目的ではないので、詳しく知りたい場合は後述の参考リンクを参照してください。
grunt
grunt は javascript で振る舞いを記述するタスクランナーで、プラグインとの組み合わせによって、例えば指定したディレクトリ配下の css ファイルを minify したり結合したり、 例えば altJS で書かれたファイルをコンパイルして指定ディレクトリに設置したりなどが出来ます。
Gruntfile.coffee 全体
この Gruntfile.coffee
を設置して grunt
コマンドを実行すると以下の様になります。
(npm install -g grunt-cli
と、リポジトリ内の package.json
を設置しての npm install
も必要です)
bower install
を実行し、必要なファイルを適切にpublic
配下に設置assets
配下にあるassets
配下を監視し、ファイルの変更を検知したらコンパイルして適切に配置
module.exports = (grunt) -> grunt.initConfig coffee: compile: options: bara: true files: [ expand: true cwd: 'assets' src: [ '**/*.coffee' ] dest: 'public/js/' ext: '.js' ] compass: dist: options: sassDir: 'assets' cssDir: 'public/css/' cssmin: my_target: files: [ expand: true, cwd: 'public/css', src: [ '*.css', '!*.min.css' ], dest: 'public/css/', ext: '.min.css' ] bower: install: options: targetDir: 'public' layout: (type, component, bower_path) -> path = if component == 'bootswatch' && type == 'css' "#{type}/#{component}" else if component == 'bootstrap' && type == 'fonts' "css/#{type}" else type path install: true cleanTargetDir: true cleanBowerDir: false esteWatch: options: dirs: [ 'assets' ] 'coffee': (path) -> [ 'coffee' ] 'scss': (path) -> [ 'compass', 'cssmin' ] grunt.loadNpmTasks 'grunt-bower-task' grunt.loadNpmTasks 'grunt-contrib-coffee' grunt.loadNpmTasks 'grunt-contrib-compass' grunt.loadNpmTasks 'grunt-contrib-cssmin' grunt.loadNpmTasks 'grunt-este-watch' grunt.registerTask 'make', [ 'bower', 'coffee', 'compass', 'cssmin' ] grunt.registerTask 'default', [ 'make', 'esteWatch' ]
grunt-bower-task
Gruntfile.coffee
の bower
の部分だけ抜粋。
bower: install: options: targetDir: 'public' layout: (type, component, bower_path) -> path = if component == 'bootswatch' && type == 'css' "#{type}/#{component}" else if component == 'bootstrap' && type == 'fonts' "css/#{type}" else type path install: true cleanTargetDir: true cleanBowerDir: false
targetDir
bower install
したファイルをどこに設置するか指定。
layout
どのようなレイアウトで targetDir
配下に設置するか指定。
byType
, byComponent
から選ぶか、自前で定義する。
- byType で実行した場合のレイアウトの例
public ├── css │ ├── Font-Awesome │ │ └── font-awesome.min.css │ ├── application.css │ ├── bootstrap │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap.css.map │ │ └── bootstrap.min.css │ └── bootswatch │ └── bootstrap.min.css ├── fonts │ ├── Font-Awesome │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ └── fontawesome-webfont.woff │ └── bootstrap │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff └── js ├── application.js ├── bootstrap │ └── bootstrap.min.js ├── jquery │ ├── jquery.js │ ├── jquery.min.js │ └── jquery.min.map ├── underscore │ ├── underscore-min.js │ └── underscore-min.map └── vue └── vue.min.js
- byComponent で実行した場合のレイアウトの例
public ├── Font-Awesome │ ├── css │ │ └── font-awesome.min.css │ └── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ └── fontawesome-webfont.woff ├── bootstrap │ ├── css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap.css.map │ │ └── bootstrap.min.css │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ └── js │ └── bootstrap.min.js ├── bootswatch │ └── css │ └── bootstrap.min.css ├── css │ └── application.css ├── jquery │ └── js │ ├── jquery.js │ ├── jquery.min.js │ └── jquery.min.map ├── js │ └── application.js ├── underscore │ └── js │ ├── underscore-min.js │ └── underscore-min.map └── vue └── js └── vue.min.js
- 自前で定義する場合
上述の2例では、vue/js/vue.min.js
か js/vue/vue.min.js
というようなスタイルになり、少々冗長な感じになってしまうので、自前で無名関数を定義してあげ、パスを返すようにしてあげれば、そのとおりの場所に設置してもらえる。
javascript ファイルは public/js
配下にフラットに並べたいし、css ファイルは public/css
配下にフラットに並べたいことが多いと思う。
例えば、このように定義してあげると、
layout: (type, component, bower_path) -> path = if component == 'bootswatch' && type == 'css' "#{type}/#{component}" else if component == 'bootstrap' && type == 'fonts' "css/#{type}" else type path
(bootswatch
に含まれる css ファイルは bootstrap.min.css
というファイル名で、bootstrap
のそれとカブってしまっていて上書きされてしまうので、byType
のレイアウトで設置)
(bootstrap
の bootstrap.min.css
は ../fonts/
でフォントファイルを参照しているので、public/css/fonts
配下に設置)
このようになる
public ├── css │ ├── application.css │ ├── bootstrap-theme.css.map │ ├── bootstrap-theme.min.css │ ├── bootstrap.css.map │ ├── bootstrap.min.css │ ├── bootswatch │ │ └── bootstrap.min.css │ ├── font-awesome.min.css │ └── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ └── fontawesome-webfont.woff └── js ├── application.js ├── bootstrap.min.js ├── jquery.js ├── jquery.min.js ├── jquery.min.map ├── underscore-min.js ├── underscore-min.map └── vue.min.js
cleanTargetDir
targetDir
を初期化してからタスクを実行するかどうか指定。
上記の例だと、public
ディレクトリが実行前に削除され、再作成されます。
(これめっちゃコワイんだけど、targetDir
に '.' を指定して cleanTargetDir
を true にして実行するとプロジェクトがディレクトリごと消滅します。.git
とかも全部消える。コワイ。)
cleanBowerDir
特に指定のない場合は bower install
によって bower_components
ディレクトリにインストールされますが、そこを実行時に初期化するかどうかを指定する。
foreman
grunt-este-watch
を実行するようにした状態で grunt
コマンドを実行すると、フォアグラウンドで grunt
が起動しっぱなしになってしまうので、rack
アプリケーションを起動するために別のコンソールを起動しなくてはならなくなってしまいます。
そうしなくてよいように、以下のような Procfile
を用意して、bundle exec foreman start
します。
application: bundle exec rackup grunt: grunt
これであとはもう lib
, views
, assets
配下のファイルを編集して開発していくだけ。
やろうとしてやめたこととか
最初は、 views/layout.slim
に js/application.js
と css/application.min.css
だけ読み込ませるように記述して、requirejs
や browserify
などを利用して自前で書いた javascript と bower
でインストールしたライブラリをいい感じにガッチャンコしたひとつのファイルを作成する、わざわざ scss ファイルをインストールして compass
を利用して自前で書いた css と bower
でインストールしたライブラリをいい感じにガッチャンコしたひとつのファイルを作成する、などということを試みました。
が、やめました。
意図しない挙動などのトラブルに対処するにあたり、ガッチャンコされて minify されてしまっていると、どのライブラリ起因の問題なのか切り分けるときに一個ずつ読み込ませないようにして探るとか出来なくてとても大変です。
使うライブラリを link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css"
だったり script src="/js/vue.min.js"
みたいにそれぞれ書けばいいじゃん。
javascript/css のファイルをテンプレートでそれぞれ一つずつ読み込ませたいというだけのために頑張ることじゃないよなぁ。ということで。
あと、「requirejs
は オワコンなんで browserify
使いましょう」とか突然若者に言われたので、両方それなりに調べて使えるようにしたけど、いずれを使うにしても目的と天秤にかけたらとにかくコストが高すぎると感じた。
現在ナウいものを選択したとしても、来年にはそれがオワコン化してるかもしれないし、本業の領域ではない分野のトレンドを追いかけ続けてオワコンじゃないものに切り替えていくのは、やはり今回の目的からすると異常な高コストでしかなかった。
なぜ今 coffee script
なのか
「coffee script
はオワコン。本命 TypeScript
, 対抗は Haxe
, Dreamy だけどおもしろいのが Dart
だ。」
みたいな意見を数人から頂戴した。
coffee script
は利用者が減ってきていて、コミュニティも以前のような活発さがなくなっているとのことだが、それは現状自分にとってはあまりリスクではなく、解説記事やサンプルコードなど、そんなに古くないものがまだまだいくらでもインターネット上に存在しているので、困難に対処しやすいという観点でもまだまだメリットが多い。
それに自分としては「文字列内での変数展開、簡潔なイテレーション記法、省略記法が使える」など、「簡潔な記述が出来る」ということだけ求めているので、情報の多さ(特に母国語での)という観点から coffee script
でとりあえず書いてみようということにした。
もしメンテを継続していくプロジェクトにおいて coffee script
を使わなくなったとしても、ゴリゴリ javascript を書いてるわけではないので他の altjs で書き換えるのはさほどコストをかけずに出来るだろうし、変換されたナマの javascript をベースにして開発を継続すれば良いのかなと思っております。
参考
昨今の自分用Webアプリケーションひな形 - naoyaのはてなダイアリー
昨今のWebアプリケーションのひな形その2 - Grunt - naoyaのはてなダイアリー
Bower入門(基礎編) - from scratch
Bower入門(応用編) - from scratch
jade, sass/compass, coffeescript, bowerで静的Webサイトを作るGrunt.js秘伝のタレ - Qiita
vue.js でチェックボックスによってセレクトボックスの enabled/disabled を切り替える
タイトル通りの挙動を、このエントリを書いている現在で javascript がまったく得意ではない自分が jquery
で書くとこんな感じになります。
きっともっとまともな書き方があるんでしょうけども、非常に冗長な感じですね。
vue.js
で書いてみた
めっちゃスッキリした。
el
で指定したセレクタの配下がスコープになるので、上記の jquery
のように挙動ごとにセレクタを指定しなくて良くて(きっともっとまともな書き方があるんでしょうけども)スッキリ書けて良い。
vue.js でチェックボックスによって表示/非表示を切り替える
タイトル通りの挙動を、このエントリを書いている現在で javascript がまったく得意ではない自分が jquery
で書くとこんな感じになります。
きっともっとまともな書き方があるんでしょうけども、非常に冗長な感じですね。
vue.js
で書いてみた
めっちゃスッキリした。
el
で指定したセレクタの配下がスコープになるので、上記の jquery
のように挙動ごとにセレクタを指定しなくて良くて(きっともっとまともな書き方があるんでしょうけども)スッキリ書けて良い。
tmux 1.9 でペイン分割時にカレントディレクトリを維持
tmux 1.8 (それ以前のバージョンは知らない) では、ペイン分割時に現在フォーカスのあるペインのカレントディレクトリで新しいペインを作ってくれたが、どうやら 1.9 からはそうではなくなった模様。
だいぶ不便なので、.tmux.conf
をこのようにした。
( | や - での分割はデフォルトではないので注意です )
# ペインを縦分割 unbind % bind | split-window -h -c "#{pane_current_path}" if-shell '[[ "`tmux -V`" =~ 1\.8 ]]' 'bind | split-window -h' # ペインを横分割 unbind '"' bind - split-window -v -c "#{pane_current_path}" if-shell '[[ "`tmux -V`" =~ 1\.8 ]]' 'bind - split-window -v'
split-window
コマンドのオプション -c
に #{pane_current_path}
を渡してあげるようにする。
1.8 でこの設定を食わすと、逆にカレントディレクトリを維持してくれなくなるので、if-shell
でバージョンを確認して -c
以降を渡さないようにしている。