Rendrå¾ç¶
ããã¯ãNode.js Advent Calendarã7æ¥ç®ã®è¨äºã§ãã
å»å¹´ã®ã¢ãã«ã¬ (æ±äº¬Nodeå¦åç¥ç¨ã§12æãããªãã£ããã©) 以æ¥ããªãªã¼ã¹ã®åç¥ã¨ã³ããªä¸ã¤ããæ¸ãã¦ãªãã£ãããããã°ã ããããªãTwitterããããã¦ã¤ã¶ããã¦ãªããããããããã®ãã§ã¼ãã¢ã¦ããé²ãã§ããã¾ããããã¼ããªã«ãæ®ããæ¶ããããã«æ»ãããããã®ã«ãå®éã«ã¯ä»æ»ã¬ã¨è¨å¤§ãªã´ã (大åã¯æ¸ç±ã¨éèªã ãã©) ãæ®ãã®ã§æ©ãå¦åããªãã¨æ»ã¬ã«æ»ããªãã
ã¨ããã (JW)ãä»åã¯Rendrã«ã¤ãã¦ãã©ãã©ã¨æ¸ãã¾ããã¾ã¨ã¾ããªãã¦ããããªããã§ãã
èªåãRendrãç¥ã£ãã®ã¯ã@mshkããã«ããQiitaã®è¨äºããã§ããã
- Rendrå ¥é(1): Node.js + Backbone.jsã§ãµã¼ã & ã¯ã©ã¤ã¢ã³ããæ§ç¯ãã"Rendr"ã®ç´¹ä»
- Rendrå ¥é(2): ãªã¯ã¨ã¹ãå¦çã®æµãï¼Router, ControllerãViewãTemplateï¼
- Rendrå ¥é(3): CoffeeScriptã§Rendrã¢ããªãæ¸ã
åãã@mshkããã«ããæ±äº¬Nodeå¦åç¥ã®Rendrç´¹ä»ã»ãã·ã§ã³ã®è³æã¯ãã¡ãã
Qiitaã®æåã®è¨äºã¯çµæ§æ³¨ç®ãéããããã§ãèªåããããè¦ã¦å®éã«Rendrã触ã£ã¦ã¿ã¦ãããã¯ããã¨æã宿¦æå
¥ãããªã©ããã®ã§ããããã®å¾ãã¾ãRendrã®æ
å ±ãå¢ããªãã¦æ®å¿µãªæãã§ãããã§ã¼ãã¢ã¦ãä¸ã®ãåãè¨ããªã£ã¦æãã§ããããããªããã§ (ã©ããªããã§ï¼)ãå§ãã¾ãã
Rendrã®MV*çãªæ§é
åè¿°ã®ãªã³ã¯å çã§ç´¹ä»ããã¦ããããã«ãRendrã¯Backboneãã¯ã©ã¤ã¢ã³ãã®ã¿ãªãããµã¼ãã§ãåããããã®ã©ã¤ãã©ãªã§ããBackboneã¯ããããMVCãã¬ã¼ã ã¯ã¼ã¯ã§ã¯ãããã®ã®ãå¤å ¸çãªMVCãã®ãã®ã§ã¯ãªããDOMã¤ãã³ãã®ãã³ããªã³ã°ãViewã§è¡ã (ViewãControllerãå ¼åãã) 䏿¹ãControllerãã®ãã®ã«è©²å½ãããã®ã¯ããã¾ãããã¾ããViewã¯Viewã§ã©ãä½ããã¯ã¢ããªã±ã¼ã·ã§ã³ã®éçºè ã«ä¸¸æãæãããã¾ããBackboneã¯æåéãè骨ã ããéª¨æ ¼ã®ä¸é¨ã ããæä¾ããèããã¬ã¼ã ã¯ã¼ã¯ãªã®ã§ããã
Rendrã¯ãã®èãBackboneããã®ã¾ã¾ãµã¼ãã§ãåããã¨ããããã§ã¯ãªããããã¤ã追å ã®æ§é ãä¸ãã¾ããå ·ä½çã«ã¯ã
- Controllerãããã
- ã¬ã³ããªã³ã°ã«ã¯ãã³ãã¬ã¼ãã¨ã³ã¸ã³ (ããã©ã«ãã¯Handlebars) ã使ãã
Controllerãããã¨ãã£ã¦ããBackboneã®Viewã§è¡ãDOMã¤ãã³ãã®ãã³ããªã³ã°ãæ
ããã®ã§ã¯ããã¾ãããããã§ã¯ãªããURLã®å¤åã仿ã®ãã©ã¦ã¶ã 㨠popstate ã¤ãã³ãã«åå¿ãã¦ã次ã«è¡¨ç¤ºããããã®Modelãç¨æããã®ãRendrã®Controllerã§ãã
å³ã«ããã¨ãããªæã (ã¹ããã¨ãç»é¢ã®å¹ ãçãã¨ã¾ã¨ãã«è¦ããªãããããããã¡ãã)ã
+-----+ popstate +------------+ create +-------+
| BOM |----------->| Controller |--------->| |
+-----+ +------------+ | |
| |
+-----+ event +------------+ update | |
| |----------->| View |--------->| Model |
| | +------------+ | |
| DOM | | |
| | render +------------+ read | |
| |<-----------| Template |<---------| |
+-----+ +------------+ +-------+Backboneã§popstateã¤ãã³ããæ±ã£ã¦ããã®ã¯Routerã§ãããããã¯æ (v0.5ããå) Controllerã¨ããååã ã£ãã¨ããRendrã®Controllerã¯Routerã®å
ã§å¼ã³åºããã (ã¨ããããã¯ã©ã¤ã¢ã³ããµã¤ãã§ã¯Controllerã® this ã¯Routerã§ãw) ã®ã§ãå
ç¥è¿ãã¨ãã£ãè¶£ã§ããã
URLã«ã©ã®Controllerã対å¿ãããã¯ãapp/routes.jsã§å®ç¾©ãã¾ãããã¨ãã°ãµã³ãã«ã®å ´åã¯ãããªæãã
module.exports = function(match) { match('', 'home#index'); match('repos', 'repos#index'); match('repos/:owner/:name', 'repos#show'); match('users' , 'users#index'); match('users/:login', 'users#show'); match('users_lazy/:login', 'users#show_lazy'); };
ã¾ãã§ãµã¼ããµã¤ãã®Webãã¬ã¼ã ã¯ã¼ã¯ã§ã³ã³ããã¼ã©ï¼ã¢ã¯ã·ã§ã³ãå®ç¾©ãã¦ããã¿ããã§ãããå®éãRendrã®Controllerã¯ã¾ãã«ãµã¼ããµã¤ãã®Webãã¬ã¼ã ã¯ã¼ã¯ã«ãããControllerãã®ãã®ã§ãããªããç¾å¨ã®Rendrã¯ã¢ã¸ã¥ã¼ã«ã·ã¹ãã ã¨ãã¦CommonJSã使ãã¾ã (RequireJS対å¿ã®ãã«ãªã¯ãé²è¡ä¸)ãããã¦ããã®é
ç½®ãå½åã«å°ãã°ããè¦åãããã¾ãããã¨ãã° 'users#show' ã®å ´åã¯ãapp/controllers/users.js ã¨ããã¢ã¸ã¥ã¼ã«ã§å®ç¾©ããã¦ããControllerã®ãshow() ã¡ã½ãããå¼ã³åºããã¾ããã¾ããããã«å¯¾å¿ããViewã¯app/views/users/show.jsããã³ãã¬ã¼ãã¯app/templates/users/show.hbsã®ããã«ãªãã¾ãã
ãµã¼ããµã¤ãã§åãæã®Rendrã¯ãããªæãã«ãªãã¾ãã
+-----+ GET +------------+ create +-------+ | |=========>| Controller |--------->| | | B | +------------+ | | | r | | | | o | +------------+ | | | w | | View | | Model | | s | +------------+ | | | e | | | | r | HTML +------------+ read | | | |<=========| Template |<---------| | +-----+ +------------+ +-------+
Controllerããµã¼ããµã¤ãWebãã¬ã¼ã ã¯ã¼ã¯ã®Controllerãã®ã¾ã¾ã ã¨ãããã¨ãä¸ç®çç¶ã§ãããããã®æ¸ãæ¹ã ã¨Viewãå®ã¶ããããªæãã§ãããå®éã¯ä½¿ç¨ãããã³ãã¬ã¼ããæ±ºãããããã³ãã¬ã¼ãã«æ¸¡ããã¼ã¿ (Model) ãæ´ããããã¾ããViewã®ã¡ã½ããã¯ãããã®ããã«ã¯ã©ãµã両æ¹ã§å®è¡ããããã® (DOMã«ä¾åããªã) ã¨ãã¯ã©ã¤ã¢ã³ãã§ã®ã¿å®è¡ããããã® (DOMã«ä¾åã§ãã) ãããã®ã§ã@mashkããã®ãRendrå ¥é(1)ããGitHubã®ããã¥ã¡ã³ãã¨ãããreadmeãè¦ã¦ããã¨ããã§ãããã
ãã³ãã¬ã¼ãããµã¼ããµã¤ãã§å®è¡ãããå ´åã¯ããã®æã®ModelãViewãã¯ã©ã¤ã¢ã³ããµã¤ãã§å¾©å
ããããã®æ
å ±ãä¸ç·ã«ã¬ã³ããªã³ã°ãã¾ããããã«ãã£ã¦ããã©ã¦ã¶ã§ã¯ããããæåããããã§åãã¦ãããã®ããã«Backboneã¢ããªãåä½ãããã¨ãã§ããã®ã§ãããã ãããã®é¨å (ã¨ãModelã®ãã£ãã·ã¥) ã¯ã·ã³ãã«ãªRendrã®ä¸ã§ã¯ã¡ãã£ã¨ã°ããããªããã¼ãªã¨ããã§ããã©ãã«ã®å
ã«ãªããããå°è±¡ã§ããã¢ããªå
ã§ç»é¢é·ç§» (Router.navigate()) ããå¾ã¯ãã¾ãåãã®ã«ããªãã¼ãããã¨ãã¾ãåããªãããªãã¦å ´åã¯ããã辺ã§ã¯ã¾ã£ã¦ãå¯è½æ§ãããã¾ãã
ãªãããµã¼ããµã¤ãã§Backboneãåãæã¨ããã®ã¯ã(ããã¯ãã¼ã¯çãã) URLãç´æ¥å©ãããå ´åã (F5çã§) ãªãã¼ããããå ´åãªã©ã§ãHTTPã¡ã½ããã¨ãã¦ã¯GETã®ã¿ã¨ãªãã¾ãããªã®ã§ãapp/routes.js ã§å®ç¾©ããã®ãGETã¡ã½ããã§ã¢ã¯ã»ã¹ãããURLã ãã§ãã
Rendrã¯UI層
Rendrã¯Backboneãã¯ã©ã¤ã¢ã³ãã§ããµã¼ãã§ãå®è¡ããããã®ã©ã¤ãã©ãªã§ãããããã§ã®ãµã¼ãã¯ãµã¼ãã¨ãã£ã¦ããåºæ¬çã«UI層ã§ããã¤ã¾ããBackboneã使ã£ãã·ã³ã°ã«ãã¼ã¸ã¢ããªã±ã¼ã·ã§ã³ã®å ¸åçãªã·ã¹ãã æ§æããããªæãã ã¨ãã¦ã
client server ========== ============== +---------+ HTTP +------------+ | Browser |<======>| API server | +---------+ +------------+
Rendrãå°å ¥ããã¨ãããªãã¨ãããã¨ã§ãã
client server
========== ======================================
UI層 ãµã¼ãã¹å±¤
=================================== ==============
+---------+ HTTP +--------------+ HTTP +------------+
| Browser |<======>| Rendr server |<======>| API server |
+---------+ +--------------+ +------------+Rendrã¯åºæ¬çã«ãããã¯ã¨ã³ãã®ãµã¼ãã¹å±¤ã§Backboneã使ã (Backbone.Modelã«ãã¸ãã¹ãã¸ãã¯ãå®è£ ãããªã©) ãã¨ãæå³ããã©ã¤ãã©ãªã§ã¯ãªãã¨ãããã¨ã§ããããã¯ãRendréçºå ã®Airbnbãå ã Railsã§å®è£ ããããµã¼ããæã£ã¦ãã¦ãã¢ãã¤ã«ç¨ã®ããã³ãã¨ã³ããæ§ç¯ããéãã·ã³ã°ã«ãã¼ã¸ã¢ããªã±ã¼ã·ã§ã³ã®åæè¡¨ç¤ºãæ¹åããããã«Rendrãéçºããã¨ããçµç·¯ãããããã§ãããã
Rendrã使ãããã§ã¯ãªãã¦ãããã®ããã«ãµã¼ãã¹å±¤ãå°ããåå²ãã¦APIåããUI層ã§ããã·ã¥ã¢ããããçãªã¢ã¼ããã¯ãã£ã¯ãç¹ã«ã¦ã¼ã¶æ°ã®å¤ããµã¼ãã¹ã§é »ç¹ã«è¦ããã¾ããããã®UI層ã¨ãã¦ãè¤æ°ã®APIã並è¡ã«å¼ã³åºãã®ãç°¡åã¨ãã£ãçç±ã§Node.jsãé¸ã°ããã±ã¼ã¹ãå¤ãè¦ãããããã«ãªã£ã¦ãã¦ãæè¿ãWalmartã¨ãGrouponã¨ããããã£ã½ãæãã§ãããããªã¢ã¼ããã¯ãã£ã§ã·ã³ã°ã«ãã¼ã¸ã¢ããªãã¯ã©ã¤ã¢ã³ãã®ä¸ã¤ã¨ãã¦æä¾ãããªããRendrã¯ããã¿ãªã¨ãããããã§ãããã
Rendrã¨ããã¯ã¨ã³ããµã¼ãã¹
Rendrãããã¯ã¨ã³ãã®ãµã¼ãã¹ã¨ã©ã®ããã«ã³ãã¥ãã±ã¼ãããããBackboneããµã¼ããµã¤ãã§å®è¡ãããå ´åã¨ã¯ã©ã¤ã¢ã³ããµã¤ãã§å®è¡ãããå ´åãããããã§è¦ã¦ã¿ã¾ããããã¾ãã¯ãµã¼ããµã¤ãã®å ´åã
Browser Rendr server Backend ======= ====================================================== =========== +-----+ GET +------------+ +-------+ +------+ +---------+ +---------+ | |=========>| Controller |--->| | | | | | | | | B | +------------+ | | | | | | | | | r | | | | | | | | | | o | +------------+ | | | | | | HTTP | | | w | | View | | Model |<-->| Sync |<-->| Data |<======>| Backend | | s | +------------+ | | | | | Adapter | | | | e | | | | | | | | | | r | HTML +------------+ | | | | | | | | | |<=========| Template |<---| | | | | | | | +-----+ +------------+ +-------+ +------+ +---------+ +---------+
Backboneã®Model㯠fetch() ã save() ãå¼ã°ããã¨ãSyncã¨ãããªãã¸ã§ã¯ããçµç±ãã¦ããã¯ã¨ã³ãã¨Modelã®å
容ãããåããã¾ããBackboneæ¨æºã§ã¯XHRçµç±ã§RestfulãªWeb APIã¨ããåãããããSyncã®å®è£
ãæä¾ããã¦ãã¾ãã
Rendrã¯ãã®Syncãç½®ãæãã¾ãããµã¼ããµã¤ãã§ã¯ãRendrã®Syncã¯DataAdapterã¨å¼ã°ãããªãã¸ã§ã¯ããç´æ¥å¼ã³åºãã¾ããDataAdapterã¯ãµã¼ããµã¤ãçXHRã¨ãã£ãæãã®ã¢ã¸ã¥ã¼ã«ã§ãæ¨æºã§ã¯Request (mikeal/request)ã使ã£ã¦RestfulãªWeb APIã¨ããåãããããã®RestAdapterã¨ããå®è£ ãç¨æããã¦ãã¾ãã
Backboneãã¯ã©ã¤ã¢ã³ããµã¤ãã§å®è¡ãããå ´åã¯ããå°ãè¤éã«ãªãã¾ããããã®ããã«ãªãã¾ãã
Browser Rendr server Backend
================================================== =========================== ===========
+-----+ +------------+ +-------+ +------+ +----------+ +---------+ +---------+
| BOM |--->| Controller |--->| | | | | | | | | |
+-----+ +------------+ | | | | | | | | | |
| | | | | | | | | |
+-----+ +------------+ | | | | HTTP | | | | HTTP | |
| | | View |<-->| Model |<-->| Sync |<======>| ApiProxy |<-->| Data |<======>| Backend |
| | +------------+ | | | | | | | Adapter | | |
| DOM | | | | | | | | | | |
| | +------------+ | | | | | | | | | |
| |<---| Template |<---| | | | | | | | | |
+-----+ +------------+ +-------+ +------+ +----------+ +---------+ +---------+ã¯ã©ã¤ã¢ã³ããµã¤ãã§ã¯ãRendrã®Syncã¯æ¨æºã®Backbone.Syncçµç±ã§XHRã使ã£ã¦ãµã¼ãã¨ããåããã¾ãããã®éããã¨ãã°Modelãè¦æ±ããURLã /users ã ã¨ããã¨ã/api/-/users ã®ããã«å¤å½¢ããURLããªã¯ã¨ã¹ããã¾ãããã®ãããªURLã¯ãRendrãµã¼ã (ããã¯Expressã¢ããªã§ã) ã§ã¯ApiProxyã¨ããããã«ã¦ã§ã¢ã«ã«ã¼ãã£ã³ã°ããã¾ããããã¯ååã®éãAPIå¼ã³åºãã®ããã®ãããã·ã§ãåç´ã«DataAdapterã«å§è²ããã ãã§ããããã¦DataAdapterãããã¯ã¨ã³ãã®ãµã¼ãã¹ã¨ããåããã¾ãã
éè¦ãªãã¤ã³ãã¨ãã¦ã
- ãã©ã¦ã¶ããç´æ¥ããã¯ã¨ã³ãã®ãµã¼ãã¹ã¨ããåããããã¨ã¯ããã¾ãããRendrãµã¼ããä»ãã¾ãã
- Backboneã¢ããªããã©ã¦ã¶ä¸ã§åä½ãã¦ããå ´åããµã¼ãå´ã§ã¯Backboneã¢ããªã¯å¼ã³åºããã¾ããã
åè ã«é¢ãã¦ã¯å¥½é½åãªãã¨ãå¤ããRendrãµã¼ãä¸ã§HTTPã»ãã·ã§ã³ãç¶æãã¦èªè¨¼ãªã©ã«ä½¿ããã¨ãåºæ¥ãããAPIãµã¼ãã¨ã®éä¿¡ã«å¿ è¦ãªAPIãã¼ãã¯ã©ã¤ã¢ã³ããµã¤ãã«é²åºãããã¨ãªãDataAdapterã®ã¨ããã§è¨å®åºæ¥ãããã¾ãã
å¾è ã«é¢ãã¦ã§ãããRendrã¯Backboneãã¯ã©ã¤ã¢ã³ããµã¤ãã§ããµã¼ããµã¤ãã§ãåããããã®ã©ã¤ãã©ãªãªã®ã§ãããã©ã¡ããã¨ããã¨ãã¯ã©ã¤ã¢ã³ãããµã¼ãã§ãåããã¨èªèãã¦ãããæ¹ãå®éã®åä½ã«è¿ãã§ãããã©ã¦ã¶å´ã§Backboneãåãã¦ãæã®HTTPãªã¯ã¨ã¹ãã§ã¯ãµã¼ãå´ã§Backboneã¯åããããµã¼ãå´ã§Backboneãåãæã¯URLç´å©ããªã®ã§ãã©ã¦ã¶å´ã§ã¯Backboneã¯åãã¦ãªãã¨ãããã¨ãªã®ã§ãã
ãµã¼ããµã¤ãJavaScriptã®ã¡ãªããã¨ãã¦ã¯ã©ã¤ã¢ã³ãã¨ãµã¼ãã§ã³ã¼ããå ±æã§ããã¨ããæå¾ ãèªãããããå®éã«ã¯ããªãã¼ã·ã§ã³ãããããå ±æåºæ¥ãªãã¨ããç¾å®ãèªãããããã¾ããRendrã ã¨ããããBackboneã®Model (é常ããªãã¼ã·ã§ã³ã¯ããã§è¡ã) ãå«ãã¦ã¯ã©ãµãã§ã®å ±æãããé²ã¿ãããªå°è±¡ãæã¤äººãããããç¥ãã¾ãããå®éãModelãViewãControllerã (ãã³ãã¬ã¼ãã) ã¯ã©ãµãã§å ±æãããã®ã§ãããããã¯ããã¾ã§ãã¬ã³ããªã³ã°ã®ããã§ãã
ç¹ã«ããªãã¼ã·ã§ã³ã«ã¤ãã¦ã¯ããµã¼ããµã¤ãã§ã¯åºæ¬çã«å®è¡ããã¾ããããµã¼ããµã¤ãã§Backboneãå®è¡ãããæã¨ããã®ã¯ãåè¿°ã®ããã«URLç´å©ãããªãã¼ãæã§ãããGETã¡ã½ããã«ãããªã¯ã¨ã¹ãã®æã ãã§ãããã®å ´åãé常ã®Backboneã¢ããªã§ã¯ Model.fetch() ãå¼ã°ãããã¨ã¯ãã£ã¦ã Model.save() ãå¼ã°ãããã¨ã¯ãªããå¾ã£ã¦ããªãã¼ã·ã§ã³ãå®è¡ããããã¨ãããã¾ãã (å¤ãã£ãå®è£
ããã¦ããªãéã)ã
ã¡ãªã¿ã«ãRendrã§ã¯ã¯ã©ã¤ã¢ã³ããµã¤ãã®Syncã¯ãªã¯ã¨ã¹ãã«emulateJSONã使ãã¾ããã¤ã¾ãããã©ã¦ã¶ããRendrãµã¼ãã¸ã®ãªã¯ã¨ã¹ãã§ã¯ã³ã³ãã³ãã¿ã¤ã㯠application/json ã§ã¯ãªããapplication/x-www-form-urlencoded ã«ãªãã¾ããçç±ã¯ä¸æã§ãããAribnbããµãã¼ããã¦ããããã¤ã¹ã®é½åã§ããããï¼
ãµããã³Rendrã¯UI層ï¼
ãã®ããã«ãRendrã¨ããã®ã¯ååã®éããµã¼ããµã¤ãã§ãã¬ã³ããªã³ã°ãè¡ãããã®ã©ã¤ãã©ãªã§ãããã®ãããRendrã®æ¨æºçãªæ§æã§ã¯DataAdapter (RestAdapter) ãéãã¦ããã¯ã¨ã³ãã®ãµã¼ãã¹ãå©ç¨ãããã¨ã«ãªãã¾ãã
ããããåé ã§ãç´¹ä»ãããRendrå ¥éãã® @mshk ããã¯ãDataAdapterã®ã¨ããã§MySQLã¸ã®ã¢ã¯ã»ã¹ãå«ãããããããã¸ãã¹ãã¸ãã¯ãå®è£ ãã¦ããããã§ããAirbnbã®ããã«Rendr以åããããã¯ã¨ã³ãã®ãµã¼ããåå¨ãã¦ããå ´åã¯ã¨ããããå ¨é¨æ°è¦ã®ãµã¼ãã¹ã ã¨ããããHTTPã¢ã¯ã»ã¹ãæãã§ã¬ã¤ãã³ã·ãå¢ããã¦ã¾ã§UI層ã¨ãµã¼ãã¹å±¤ããããçç±ããªãã¨ãããã¨ã§ãããããããå°ãªãã¨ãç¾æç¹ã§ã¯ãDataAdapterã®å ã§ãã¼ã¿ãã¼ã¹ã¢ã¯ã»ã¹ãå«ããã¸ãã¹ãã¸ãã¯ãå®è£ ããã®ã¯Rendrã®ã¦ã¼ã¹ã±ã¼ã¹ããå¤ãã¦ãã¦è¦å´ãã¦ããããã§ããããã¨ãã°DataAdapterã§URLãè¦ã¦èªåã§ã«ã¼ãã£ã³ã°çãªãã¨ãããªãã¨ãããªããªã©ãªã©ã
ã¾ããRendrã®GitHubãªãã¸ããªã«æ©ãææãããã«ãªã¯ã¨ã¹ããªã©ãã¦ããã¢ã¼ãªã¼ã¢ããã¿ã¼ã®ä¸äºº @tak0303 (GitHubã§ã¯ @takashi) ããããåãããã«å°ã£ã¦ããæ¨¡æ§ãã¾ããDataAdapterã®ã¨ãããããã¼ã¿ãã¼ã¹ (MongoDB) ã¸ã¢ã¯ã»ã¹ãã¦ãããããã§ããMongoDBã®ããã«HTTPã§ã¢ã¯ã»ã¹å¯è½ãªDBã¯DataAdapterçµç±ã§ã¢ã¯ã»ã¹ãããã¨ã容æã§ããããã®å ´åã¯Modelã«ãã¸ãã¹ãã¸ãã¯ãå®è£
ãããã¨ã«ãªãã®ã§ãããããé常ã®Backboneã¢ã㪠(ãã©ã¦ã¶ã®ã¿ã§å®è¡ããã) ããç´æ¥MongoDBã«ã¢ã¯ã»ã¹ãããããªæãï¼ ã¯ã©ã¤ã¢ã³ããµã¤ãã¯ããããããããã®ã§èªè¨¼ã»èªå¯ã¨ããã£ãããã¦ããªãã¨æãæ°ããã¾ãããDynamoDBãªããããã©ã¦ã¶ããç´æ¥ã¢ã¯ã»ã¹ã§ããããã«ãªã£ã¦ãã¦ãã (ããã¨ããã)ããã®æ¹åããããªã®ããããã¾ãããã
ãµã¼ããµã¤ãã§ãã®å çãã®ããã«ã¯ï¼
æãè¿ãã°ãNode.jsã¯å½åããµã¼ããµã¤ãJavaScriptãã¨ãã¦æ³¨ç®ãéããã®ã§ãããããããæ°å¹´ãçµéããä»ã®Node.jsã¯ãµã¼ããµã¤ãã§ã¯ãªãå°ãã³ãã³ãã©ã¤ã³ã®ä¸çã§ä½¿ããã¦ãã¾ããç¹ã«Gruntã®æ®åãããã¾ããããã®ãããnpmã¬ã¸ã¹ããªã®è² è·ããã®ä¸å¹´ã§åçã«å¢å ãã¦ããããã§ãã䏿¹ãµã¼ããµã¤ãã§ã¯ã主ãªç¨éã¨ãã¦æå¾ ãããWebSocketã®ä½¿ãéãä»ã²ã¨ã¤è¦ã¤ãããããã¨ãã£ã¦å ¸åç㪠(RDBã«ã¢ã¯ã»ã¹ãã¦HTMLãè¿ã) Webã¢ããªã§ã¯å¤§ããªã¡ãªãããè¦ãã ãããã¨ãã£ãç¶æ³ã§ããã
ãããªä¸ãRendrã¯ãµã¼ããµã¤ãã§Node.jsã使ãã¡ãªãããé®®ããã«è¦ãã¦ããã¾ãããç¾å¨ã®Rendrã¯Backboneã¹ã£ãããªä½ãã§ãããéè¦ãªã®ã¯Backboneãã©ããã§ã¯ãªããåããã¬ã¼ã ã¯ã¼ã¯ã使ã£ã¦ã¯ã©ã¤ã¢ã³ãã¨ãµã¼ãã®ä¸¡æ¹ã§ã¬ã³ããªã³ã°ããã¨ããã¢ã¼ããã¯ãã£ã®æ¹ã§ããå®éãRendrã®ä½è Spike Brehmã®ãã¬ã¼ã³è³æãGeneral Assembly Workshop: Advanced JavaScriptãã§ã¯ãBackboneã使ããã«RendrçãIsomorphicããªã¢ã¼ããã¯ãã£ã解説ãã¦ãã¾ã (ãã¥ã¼ããªã¢ã«ããã)ãã¤ã¾ããAngularJSçãEmber.jsçã®Rendrããã£ã¦ãããããã§ãããå®ç¾æ§ã¯æªããã§ãããRendrèªä½ã«ãBackboneä¾åãç¡ããã¦AngularJSãªã©ã¸å¯¾å¿ããããããã¨ããIssueããã£ãããã¾ãã
Rendrãåãããã«Isomorphicãªã¢ã¼ããã¯ãã£ã®ã¯ã©ã¤ã¢ã³ããµã¤ãMV*ãªãã¬ã¼ã ã¯ã¼ã¯ãæ®åããã°ãå¤§è¦æ¨¡ãªãµã¼ãã¹ã«ããããµã¼ããµã¤ãã®UI層ã¨ãã¦ããããã¯ããå°è¦æ¨¡ãªç°å¢ã§ã®thinãµã¼ãã¨ãã¦ãNode.jsã使ãããæ©ä¼ãå¢ããããªã¨æå¾ ãã¦ãã¾ããããã·ã³ã°ã«ãã¼ã¸ã¢ããªèªä½ã話é¡ã®å²ã«ä»ã²ã¨ã¤åºã¾ããªã (ã¹ããããã¤ãã£ãã¢ããªä¸è¾ºåã«ãªã£ã¦ãã) å°è±¡ããããæããã¦ãµã¼ããµã¤ãJavaScriptã¨ãã¦ã®Node.jsããã®å çãã®ãããã¨ãã§ããã®ããå¿é ã§å¤ãç ããªãæ¥ã ãéããã¦ãã¾ã(æ¥ä¸ã¯ããç ãã¦ãã¾ãã®ã§åºå¤æéçã«é常ã«ã¾ããã§ã)ã
ææ¥ã¯id:mizchiããã§ãã
P.S.
- ã¯ã¦ãªè¨æ³ãå¿ãã¦ã¦æ¸ãã®ã大å¤ã ã£ãã
- Cacooã§å³ãæ¸ãå§ãããã©å¿ è¦ä»¥ä¸ã«åãããã«ãªã£ã¦ä»æ¥ä¸ã«çµãããªããªãããã ã£ãã®ã§ãããã
P.P.S
ä»ã®ã¢ãã«ã¬ãã¾ãã¦Rendrã«éã£ããã«ãªã¯ãã¾ã¨ãã¦ã¿ãããã¨ãã£ã¦ã4ã¤ãããªããã©ã
- #111 Better support for multiple models/collections
- #115 Handle status code 204 properly
- #142 Better handling of error in Fetcher
- #143 Small changes for .npmignore and .gitignore
#111ã¯ãã®ä¸ã§ä¸çªå½¹ã«ç«ã£ããã«ãªã¯ã ã¨æãã彿ã®Rendrã¯ãµã¼ããµã¤ãã®Controllerã§è¤æ°ã®Model/Collectionãç¨æãã¦ããã¬ã³ããªã³ã°å¾ã«ã¯ã©ã¤ã¢ã³ãå´ã§å¾©å ãããModel/Collectionã¯ä¸ã¤ã ãã§ããã#111ã¯ãããä¿®æ£ãã¦è¤æ°ã®Model/Collectionã復å åºæ¥ãããã«ãããã®ããã¼ã¸ãããéã«ã¯Rendrã®å ¬å¼ã¢ã«ã¦ã³ãã§ãã¤ã¼ãããã¦å¬ããã£ãã§ãã
#115ã¯ããã¯ã¨ã³ãããã®HTTPã¹ãã¼ã¿ã¹ããã©ã¦ã¶ã«è¿ãããªã㦠(ã¹ãã¼ã¿ã¹200ã«ãªã£ã¦ãã¾ã)ãã¹ãã¼ã¿ã¹204ãªã©ã¬ã¹ãã³ã¹ããã£ããªãå ´åã«jQueryã®Xhrã§ã¨ã©ã¼æ±ãããã¦ãã¾ãã®ãä¿®æ£ãããã®ãRendrã宿¦æå ¥ããæ¡ä»¶ã§ã¯ã¹ãã¼ã¿ã¹204ã使ããã¨ã«ãªã£ã¦ããã®ã§ããã¼ã¸ãã¦ãããã¦ããã£ãã§ãã
#142ã¯Model.fetch()ã§ã¨ã©ã¼ã¨ãªã£ãå ´åã®è©³ç´°æ
å ±ãContollerããåå¾ããããããã«ãããã®ãããã§å¥ã® (ã¨ã©ã¼ç¨ã®) ç»é¢ã«é·ç§»ãããªã©ã®ãã³ããªã³ã°ããããããªãã¾ããã
æå¾ã®#143ã¯ã©ãã§ãããäºç´°ãªãã®ã§ãããRendrã®ä¸ã®äºº (Spike) ã¯å²ã¨ãã«ãªã¯ããã¼ã¸ãã¦ãããã®ã§ (åãå ¥ãéããããªããã¨æãããã)ãã¿ããªãã©ãã©ããã«ãªã¯ãããããã¨æããï¼ï¼
æåã«ãã«ãªã¯ãã彿ã¯Rendrã®GitHub issueã¯éããªãã®ã ã£ãã®ã§ãããæè¿ã¯é£æ¥ããããã®Issueã³ã¡ã³ããä»ãã¦ãã¹ã¿ã¼ãã¦ãã¨é£ãã§ããã¡ã¼ã«ãçµæ§ãªéã«ãªãã¾ããã¨ãã£ã¦ã1æ¥10éåå¾ããªï¼ Node.jsã¿ããã«ããã ãã§æ¯æ¥æ°åéã¨ãããã¨ã¯ãªãããã©ãçµæ§ãªäººæ°ã¶ãã§ããå½å ã§ããã£ã¨Rendrã®è©±é¡ãçãä¸ããã¨ããã§ããã
Seasar2.4.47 ãªãªã¼ã¹
ãã¾ããï¼
ã½ã¼ã¹ã³ã¼ããªãã¸ããªãGitHubã«ç§»è¡ãã¦ãã¾ãã
â 夿´ç¹
Seasar2.4.46 ããã®å¤æ´ç¹ã¯æ¬¡ã®ã¨ããã§ãï¼
- Bug
- [CONTAINER-443] - [S2JDBC-Gen] TIMEåã®ãã¼ã¿ãdump-dataã¨load-dataã§å¾©å ã§ããªãåé¡ã解決ãã¾ãã
- [CONTAINER-444] - [S2DBCP] ã³ãã¯ã·ã§ã³ãã¼ã«ã¸ã®è¿å´å¦çä¸ã«ç©çã³ãã¯ã·ã§ã³ã®setAutoCommitã¡ã½ããããä¾å¤ãã¹ãã¼ãããã¨è¿å´å¦çãé©åã«è¡ãããªãåé¡ã«å¯¾å¿ãã¾ããã
- [CONTAINER-445] - [S2JDBC-Gen] Gen-Ddlã¿ã¹ã¯ãçæããCREATE TABLEæã®ã«ã©ã ã®ä¸¦ã³é ãJava 6ã¨7ã§ç°ãªãåé¡ã«å¯¾å¿ãã¾ãã
- [CONTAINER-447] - [S2JDBC] Jenkins 1.500ã§ãã¹ãã失æããã®ãä¿®æ£ãã¾ããã[operation:2694]
- [< href='https://github.com/seasarorg/seasar2/pull/3'>GH-3] - [S2Container] æ£è¦è¡¨ç¾ã¨ãã¦æ±ãããæååå ã«ããããªãªããã¨ã¹ã±ã¼ããã¾ããã
- New Feature
- [CONTAINER-446] - [S2JDBC] AutoSelect ã§åå¾ããã«ã©ã ãæå®ã§ããããã«ãã¾ããã[Seasar-user:21654]
- [GH-1] - [S2-Tiger] DBã®4æ¡ã®ã«ã©ã ã«5æ¡ã®ãã¹ããã¼ã¿ãæå ¥ãã¦ããç®æãä¿®æ£ãã¾ãã
- [GH-2] - [S2JDBC-Gen] éçºéä¸ã§æ¢ã¾ã£ã¦ãã£ã¨æ¾ç½®ããã¦ãã maven-s2jdbc-gen-plugin ããã¸ã§ã¯ããåé¤ãã¾ãã
â ç§»è¡ã®æ³¨æç¹ (ä»åã¯ããã¾ãã)
â ãã¦ã³ãã¼ãã¯ãã¡ãããã©ããï¼
â Maven2ããã®ãå©ç¨ã¯ãã¡ããåç
§ãã ããï¼
æåã¹ããªã¼ã 㨠StringDecoder
ãã®è¨äºã¯ãæ±äº¬ Node å¦åç¥ 2012 ã¢ããã³ãã«ã¬ã³ãã¼ãã® 15 æ¥ç®ã®è¨äºã§ãã
id:jovi0608 ã«ãããã®ã¢ãã«ã¬ 13æ¥ç®ã®ã¨ã³ããªãNode API ã®ã¯ã©ã¹å³ãå ¬éãã¾ããããã§ãæãããªããã«ãNode ã®éè¦ãªã³ã³ã»ããã®ä¸ã¤ãã¹ããªã¼ã ã§ããã¹ããªã¼ã ã«ã¤ãã¦ã¯ id:Jxck ã«ããæ±äº¬ Node å¦åã®çºè¡¨è³æ ãNode Academy 7 | âStream Stream Stream !!!âããåèã«ã©ãã¼ã
ãã®ã¹ããªã¼ã ã§ããã大éæã«ã¯å ¥åã¹ããªã¼ã (Readable Stream) ã¨åºåã¹ããªã¼ã (Writable Stream) ãããããã®ä¸¡æ¹ã§ããããã£ã«ã¿ã¹ããªã¼ã (Filter Stream) ã åæ¹åã¹ããªã¼ã (Duplex Stream) ãããããã ãªãã¦è©±ãä¸è¨ã® id:Jxck ã«ããè³æã«ã¯æ¸ãã¦ãã£ãããã¾ããããã¨ã¯å¥ã®è¦³ç¹ã§ã®åé¡ã¨ãã¦ãã¹ããªã¼ã ã«ã¯ãã¤ãã¹ããªã¼ã ã¨æåã¹ããªã¼ã ãããã¨èãããã¨ãã§ãã¾ããã¨ãã£ã¦ããå®è£ ã¯ã©ã¹ã¨ãã¦åé¡ã§ããã¨ããããã§ã¯ããã¾ãããåã«ãã¹ããªã¼ã ãæµãããã¼ã¿ããã¤ãåãæååããã¨ããã ãã§ã (ä»ã«ãä»»æã® JavaScript ãªãã¸ã§ã¯ããæµãããªãã¸ã§ã¯ãã¹ããªã¼ã ãªãããããã¾ããããã®ã¨ã³ããªã§ã¯æ±ãã¾ãã)ã
åºåã¹ããªã¼ã ãæåã¹ããªã¼ã ã¨ãã¦æ±ãã«ã¯ãwrite() ã¡ã½ããã« string ã®å¤ã渡ãã¾ããåæã«ã¨ã³ã³ã¼ãã£ã³ã°ã渡ããã¨ãã§ãã¦ãããã©ã«ã㯠UTF-8 ã§ãã
os.write('hoge hoge', 'utf8');
åºåã¹ããªã¼ã ã®å ´åãwrite() ã®ãã³ã« Buffer ãæ¸¡ããã¨ãæååãæ¸¡ããã¨ãã§ãã¾ããã¤ã¾ãããã¤ãã¹ããªã¼ã ãæåã¹ããªã¼ã ãã¨ããæç¢ºãªç¶æ
ã¯æããªãã¨ãããã¨ã«ãªãã¾ãã
䏿¹ãå
¥åã¹ããªã¼ã ãæåã¹ããªã¼ã ã¨ãã¦æ±ãã«ã¯ãsetEncoding() ã¡ã½ããã§ã¨ã³ã³ã¼ãã£ã³ã°æ¹å¼ãæå®ãã¾ããã¨ã³ã³ã¼ãã£ã³ã°æ¹å¼ãçç¥ããå ´å㯠UTF-8 ã«ãªãã¾ãã
is.setEncoding('utf8');
ä¸åº¦ setEncoding() ãå¼ã³åºãã¦æåã¹ããªã¼ã ã¨ããã¨ãããããã¤ãã¹ããªã¼ã ã«æ»ã API ã¯æä¾ããã¦ãã¾ããã弿°ç¡ãã§ setEncoding() ãå¼ã³åºããã¨ã§ãã¤ãã¹ããªã¼ã ã«ãªãããã«ãããã¨ããææ¡ (#3643) ãããã¦ãã¦ãHTTP ã¢ã¸ã¥ã¼ã«ã® API ããã¥ã¡ã³ãã«ã¯ (ééã£ã¦) ããæ¸ããã¦ãããã¨ãããã®ã§ãããä»ã®ã¨ãããã¼ã¸ããã¦ãã¾ãã (ã¤ã¼ããã¹ããªã¼ã ã¯ããããããã®ã« net.Socket ã ãç´ãã£ã¦ã©ãã ãã¼)ãå¿
è¦ã ã¨æã人㯠@isaacs ã® Streams2 ã master ã«ãã¼ã¸ãããåå¾ã大ãã£ã³ã¹ãªã®ã§ (ãã¶ã)ããã«ãªã¯ã¨ã¹ããããªã #3643 ã«ã³ã¡ã³ããããªããã¾ããã
ãªããå
¨ã¦ã®å
¥åã¹ããªã¼ã ãæåã¹ããªã¼ã ã«ãªããããã§ã¯ããã¾ããããã¨ãã° zlib ã¢ã¸ã¥ã¼ã«ã¯ç¾å¨ã®ã¨ããæåå
¥åã¹ããªã¼ã ã«å¯¾å¿ãã¦ãã¾ããããã ããç¾å¨éçºä¸ã® Streams2 ã§ã¯å
¥åã¹ããªã¼ã ã®ãã¼ã¹ã¯ã©ã¹ã setEncoding() ã¡ã½ãããæã£ã¦ããã®ã§ãããã㯠zlib ãæåå
¥åã¹ããªã¼ã ã¨ãã¦ä½¿ããããã«ãªãã¨æããã¾ãã
ãã®ã¨ã³ããªã§ã¯ãã£ã±ãæåå ¥åã¹ããªã¼ã ã«ã¤ãã¦æ¸ãã¦ããã¾ãã
ã¾ãããªãæåã¹ããªã¼ã ãã¨ãããæåå ¥åã¹ããªã¼ã ãå¿ è¦ãªã®ã§ããããï¼ ããã¯ãæåå ¥åã¹ããªã¼ã ããªãã¨ä¸ä¾¿ã§ããã°ã®å ã«ãªããããããã§ãããã¨ãã°ãåä¿¡ãããã¤ãåãæååã«å¤æãã¦ãã°åºåããä¾:
is.on('data', function(buf) { console.log('åä¿¡ãã¼ã¿ : ' + buf.toString()); });
ãã®ã³ã¼ãã¯åä¿¡ãããã¼ã¿ã ASCII ã®ããã«ã䏿åã 1 ãã¤ãã«ã¨ã³ã³ã¼ãããããã¤ãåã®å ´åã¯ãã¾ãåãã¾ããããããUTF-8 ã®ããã«è¤æ°ãã¤ãã«ã¨ã³ã³ã¼ãããã¦ããå ´åãããã¦ãããè¤æ°ã®ãã£ã³ã¯ã«åå²ããã¦ããå ´åã«ã¯ããã¾ãåããªãå ´åãããã¾ãããã¨ãã° 'ããã' ã¨ããæååã¯ãUTF-8 ã§ã¯
| ã | ã | ã |
E38182 |
E38184 |
E38186 |
ã¨ãã 9 ãã¤ãã«ã¨ã³ã³ã¼ãããã¾ãããããå
é ãã 4 ãã¤ãã¨æ®ã 5 ãã¤ãã®äºã¤ã®ãã£ã³ã¯ã«åå²ãããå ´åã'ã' ãæ£ããæåååãããã¨ãã§ãã¾ããã
åãç¶æ³ã REPL ã§ç°¡åã«è©¦ãã¨:
> buf = new Buffer('ããã')
> console.log('åä¿¡ãã¼ã¿ : ' + buf.slice(0, 4).toString())
åä¿¡ãã¼ã¿ : ã�
> console.log('åä¿¡ãã¼ã¿ : ' + buf.slice(4, 9).toString())
åä¿¡ãã¼ã¿ : ��ã
ãã®ããã«ãã¾ãã§æååããããããªåºåã«ãªã£ã¦ãã¾ãã¾ããNode ã®åæã®å®è£ (0.1.95 ã¾ã§) ã§ã¯ãå ¥åã¹ããªã¼ã ã¯ä¸è¨ã®ãããªå®è£ ã«ãªã£ã¦ãããããUTF-8 ã§ã¨ã³ã³ã¼ãã£ã³ã°ãããæååãæ£ããæ±ããã¨ãã§ãã¾ããã§ããã
ããã§å¿
è¦ã«ãªãã®ãæåã¹ããªã¼ã ã§ããã®ããã«ä½¿ãããã®ã string_decoder ã¢ã¸ã¥ã¼ã«ã® StringDecoder ã¯ã©ã¹ã¨ããããã§ããStringDecoder ã¯ãUTF-8 ã®ããã«è¤æ°ãã¤ãã§ã¨ã³ã³ã¼ãã£ã³ã°ããããã¤ãåãåãåãã¨ããããæåã®å¢çã§åå²ããã¦ããªãããã§ãã¯ããããåå²ããã¦ä¸å®å
¨ãªãã¤ãåã§çµãã£ã¦ããã¨ããã®æåã® (æåã¨ãã¦å®å
¨ãª) ãã¤ãåã¾ã§ãæååã«å¤æãã¾ããããã¦æ®ãã®ãã¤ãåãè¦ãã¦ããã¦ã次ã«åä¿¡ãããã¤ãåã¨é£çµãããã¨ã§ãæ£ããæååã«å¤æãã¾ãã
REPL ã§ç°¡åã«è©¦ãã¨:
> decoder = new string_decoder.StringDecoder('utf8')
> console.log('åä¿¡ãã¼ã¿ : ' + decoder.write(buf.slice(0, 4)))
åä¿¡ãã¼ã¿ :ã
> console.log('åä¿¡ãã¼ã¿ : ' + decoder.write(buf.slice(4, 9)))
åä¿¡ãã¼ã¿ :ãã
ãã®ããã«ãæåã®å¼ã³åºãã§ 4 ãã¤ããæ¸¡ãã¦ããå
é ã® 3 ãã¤ãã§ãã 'ã' ã ããæååã«å¤æããã¦ãæ®ãã® 1 ãã¤ãã¯æ¬¡ã®å¼ã³åºãã§æ¸¡ãã 5 ãã¤ãã¨é£çµãã㦠'ãã' ã«å¤æããããã¨ããããã¾ããããã«ãããåè¿°ã®ã³ã¼ãçã
var data = ''; is.setEncoding('utf8'); is.on('data', function(str) { data += str; });
ã®ããã«åä¿¡ããæååãå
¨é¨é£çµãã¦ã'end' ã¤ãã³ãã§ã¾ã¨ãã¦æ±ããããªã³ã¼ãã UTF-8 ã§ãå®å
¨ã«åä½ããããã«ãªãã¾ããã
StringDecoder ã¯æå Utf8Decoder ã¨ããååã§ãå¾ã®ã³ã¢ã¡ã³ãã¼ã§ãã Felix Geisendörfer ã«ãã£ã¦å®è£
ãã㦠0.1.96 ã«ãã¼ã¸ããã¾ãããååã®ããã« UTF-8 å°ç¨ã ã£ãã®ã§ããã0.1.99 ã§ç¾å¨ã® StringDecoder ã«å¤æ´ããã¦ãã®ä»ã®ã¨ã³ã³ã¼ãã£ã³ã°ã«å¯¾å¿ãã¾ãããã¨ãã£ã¦ããå½æã® Node ã UTF-8 以å¤ã«ãµãã¼ããã¦ããã¨ã³ã³ã¼ãã£ã³ã°æ¹å¼ã¯ãASCII ('ascii') ã¨ç¾å¨ã¯ deprecated ã¨ãããã¨ã«ãªã£ã¦ãã (ã§ãç¡ãããªãã§ããã¨ããè¦æãæ ¹å¼·ã) ãã¤ã㪠('binary') ã¨ããã1 ãã¤ãã¸ã®ã¨ã³ã³ã¼ãã£ã³ã°æ¹å¼ã ãã ã£ãã®ã§ããã
ãã®å¾ãv0.4.0 ã§ Node 㯠UCS-2 ããµãã¼ãããããã«ãªãã¾ãããããããã¤ãã®æ¹ã®è²¢ç®ã«ããã®ã§ããããã®ãããã«å«ã¾ãã¦ããã®ã¯ Buffer ã®å¯¾å¿ã ãã§ãStringDecoder ã¯å¤æ´ããã¾ããã§ããããã®ãããsetEncoding('ucs2') ã¯ãã¾ãåãã¾ããã§ããã
v0.6.21 ã® REPL ã§è©¦ãã¨:
> buf = new Buffer('ããã', 'ucs2')
> decoder = new string_decoder.StringDecoder('ucs2')
{ encoding: 'ucs2' }
> console.log(decoder.write(buf.slice(0, 3)))
ã
> console.log(decoder.write(buf.slice(3, 6)))
䘰
ã¾ã¨ãã«ãã³ã¼ãã§ãã¾ãããããããå°ãªãã¨ããã¼ã¿äº¤æã§ä½¿ãããã¨ã³ã³ã¼ãã£ã³ã°æ¹å¼ã¨ãã¦ç¾å¨ã¯ UTF-8 ãããã¡ã¯ãã§ãããUCS-2 ã使ããããã¨ã¯ã»ã¨ãã©ãªãã£ãã®ã§ããããNode ã® issue ã§ãè¦æããããã¨ã¯ãªãã£ããããªæ°ããã¾ãã
ãããã 1 年以ä¸ãçµéãã¦ãv0.8.0 ãã Node ã¯ãµãã²ã¼ããã¢ãå«ã UTF-16 ã«å¯¾å¿ããããã«ãªãã¾ãããç¾å¨ã® Node ã§ã¯ãUCS-2 㯠UTF-16LE ã®ã¨ã¤ãªã¢ã¹ã¨ããæ±ãã«ãªã£ã¦ãã¾ãããã®ã¨ãã«ãããããStringDecoder 㯠UCS-2/UTF-16LE ã«å¯¾å¿ãã¾ãããéè¦ããã£ãã®ãã©ããã¯ä¸æã§ããããã
v0.8.14 ã® REPL ã§è©¦ãã¨:
> decoder = new string_decoder.StringDecoder('ucs2')
> console.log(decoder.write(buf.slice(0, 3)))
ã
> console.log(decoder.write(buf.slice(3, 6)))
ãã
ãã¡ãããUTF-16 ã«å¯¾å¿ãã¦ããã®ã§ããµãã²ã¼ããã¢ã®éä¸ã§éåãããã£ã³ã¯ã§ã大ä¸å¤«ã§ãã
> buf = new Buffer('ã𠮟ã', 'utf16le')
> decoder = new string_decoder.StringDecoder('utf16le')
> console.log(decoder.write(buf.slice(0, 4)))
ã
> console.log(decoder.write(buf.slice(4, 8)))
𠮟ã
ã¨ããã§ãUTF-8 ã«ãµãã²ã¼ããã¢ã¯ãªããBMP (åºæ¬å¤è¨èªé¢ãU+0000ãU+FFFF) ã«å«ã¾ããªãæå㯠4 ãã¤ãã§ã¨ã³ã³ã¼ãã£ã³ã°ãããã¨ã«ãªã£ã¦ããã®ã§ãããä¸ã®ä¸ã«ã¯ UTF-8 ã®æå㯠3 ãã¤ãã¾ã§ã¨ãããã¨ã«ä¾åãã¦ãããããã®ããUTF-16 ã«ããããµãã²ã¼ããã¢ã®ä¸ä½ã»ä¸ä½ã®å 16bit ããããã 3 ãã¤ããè¨ 6 ãã¤ãã§è¡¨ç¾ãã CESU-8 ã¨å¼ã°ããã¨ã³ã³ã¼ãã£ã³ã°æ¹å¼ããããããã§ããOracle ã¨ã Oracle ã¨ã Oracle ã§ä½¿ããã¦ãã㨠Wikipedia ã«æ¸ãã¦ããã¾ãããUTF-8 ã¨ãã¦ã¯ RFC éåãªããã§ããããµãã²ã¼ããã¢ã«å¯¾å¿ãã¦ããªã UCS-2 -> UTF-8 夿ãã¼ã«ã使ã£ã¦ UTF-16 ã夿ãã¡ãã£ããããã¨ãCESU-8 ãªãã¤ãåãã§ãããã£ã¡ããã¾ãããã§ããªãã Node ã§å©ç¨ããã¦ãã JavaScript ã¨ã³ã¸ã³ãV8 㯠CESU-8 ãªãã¤ãåã§ã (å
é¨å½¢å¼ã§ãã) UTF-16LE ã«å¤æãã¦ãããã®ã§ãNode ã® StringDecoder ã§ã UTF-8 ã¨ãããªãã CESU-8 ãªãã¤ãåã䏿å (æé· 6ãã¤ã) ã®éä¸ã§åæããã¦ã大ä¸å¤«ãªããã«ãªã£ã¦ãã¾ãã
> buf = new Buffer('eda182edbe9f', 'hex')
> decoder = new string_decoder.StringDecoder('utf8')
> console.log(decoder.write(buf.slice(0, 3)))
> console.log(decoder.write(buf.slice(3, 6)))
𠮟
ããããæåã³ã¼ãã§ã¯ãªãããã©ãBuffer ããµãã¼ããã¦ããã¨ã³ã³ã¼ãã£ã³ã°æ¹å¼ã¨ãã¦ã¯ä»ã« HEX ('hex') 㨠BASE64 ('base64') ãããã¾ããHEX 㯠1 ãã¤ã (ãã¨ãã° 0x30) ã 2æå (ãã¨ãã° '30') ã§è¡¨ç¾ããã®ã§ãåæããã® StringDecoder ã§ãé©åã«æ±ããã¨ãã§ãã¾ããã
ãããã3 ãã¤ããã¨ã®ãã¼ã¿ã 4 æåã§è¡¨ç¾ãã BASE64 ã®å ´åã¯ãé©åã«ãã¤ãå¢çãæ±ããªãã¨æ£ããã¨ã³ã³ã¼ã (æåã³ã¼ãã®å ´åã¯æåããã¤ãåã«ã¨ã³ã³ã¼ããã¦ããããæååã«ãã³ã¼ãããã®ã§ãããBASE64 ã®å ´åã¯ãã¤ãåããæååã«ããæ¹åãã¨ã³ã³ã¼ããªã®ã ) ãããã¨ãã§ãã¾ãããããã ããªã UTF-8 ãªã©ã¨åãããã«ããã°ããã ããªã®ã§ãããBASE64 ã§ã¯ããã«ããã£ã³ã°ã¨ãããã®ããããä¸çªæå¾ã« 3 ãã¤ãæªæºã®ãã¼ã¿ãæ®ã£ãå ´åãèæ
®ããå¿
è¦ãããã¾ãããããã徿¥ã® StringDecoder ã«ã¯ã¡ã½ããã write() ãããªããã¹ããªã¼ã ã®çµç«¯ã§å¼ã³åºãããã¤ã³ã¿ãã§ã¼ã¹ãããã¾ããã§ããããã®ãããStringDecoder ã§ã¯ BASE64 ããµãã¼ããã¦ããªãã£ãã®ã§ãããæè¿ãªãªã¼ã¹ãããã°ããã® v0.9.3 ãã㯠StringDecoder ã« end() ã¡ã½ããã追å ãã (å½ç¶ãnet.Socket ãªã©ã®æ¢åã¹ããªã¼ã ã¯ãããå¼ã³åºãããã«å¤æ´ããã¦ãã¾ã)ãBASE64 ã«ã対å¿ãã¾ããã
v0.9.3 ã® REPL ã§è©¦ãã¨:
S2Util 0.0.1 ãªãªã¼ã¹
ãã¾ããï¼
â 夿´ç¹
S2Util 0.0.0 ããã®å¤æ´ç¹ã¯æ¬¡ã®ã¨ããã§ãï¼
- Bug
- [UTIL-1] - CopyUtil#copy() ã§ï¼ãã¡ã¤ã«ä»¥å¤ã®å ¥åã¹ããªã¼ã ãããã¡ã¤ã«åºåã¹ããªã¼ã ã¸ã³ãã¼ããã¨ï¼åºåãã¡ã¤ã«ã 4KB ã®æ´æ°åã«ããã£ã³ã°ããã¦ãã¾ãåé¡ãä¿®æ£ãã¾ããï¼[Seasar-user:21260]
- [UTIL-2] - MessageFormatter ãç¹°ãè¿ã使ç¨ããã¨ï¼ãã®ãã³ã« DisposableUtil ã« Disposable ãªãã¸ã§ã¯ããç»é²ããã¦ãã¾ãåé¡ãä¿®æ£ãã¾ããï¼[Seasar-user:21338]
â ãã¦ã³ãã¼ãã¯ãã¡ãããã©ããï¼
â Maven2ããã®ãå©ç¨ã¯ãã¡ããåç
§ãã ããï¼
Seasar2.4.46 ãªãªã¼ã¹
ãã¾ããï¼
â 夿´ç¹
Seasar2.4.45 ããã®å¤æ´ç¹ã¯æ¬¡ã®ã¨ããã§ãï¼
- Bug
- [CONTAINER-442] - [S2JDBC] SQL ãã¡ã¤ã«ã®ãã¹ã« DBMS åãå«ã¾ãã¦ããªãå ´åãåã SQL ãã¡ã¤ã«ã使ã£ãæä½ãè¡ããã³ã« DBMS åãå«ã SQL ãã¡ã¤ã«ããã¡ã¤ã«ã·ã¹ãã ã«ã¢ã¯ã»ã¹ãã¦æ¢ãã¦ãã¾ãåé¡ãä¿®æ£ãã¾ããï¼
- Improvement
- [CONTAINER-441] - [DbSession] ã»ãã·ã§ã³ ID ãä¿æããã¯ããã¼ã®æå¹æéãè¨å®ã§ããããã«ãã¾ããï¼[Seasar-user:21244]
â ç§»è¡ã®æ³¨æç¹ (ä»åã¯ããã¾ãã)
â ãã¦ã³ãã¼ãã¯ãã¡ãããã©ããï¼
â Maven2ããã®ãå©ç¨ã¯ãã¡ããåç
§ãã ããï¼
node-flowless v0.0.2 ãªãªã¼ã¹
ãã¾ããï¼
npm install flowlessã§ã¤ã³ã¹ãã¼ã«ãããã¨ãã§ãã¾ãï¼
v0.0.1 ããã®ä¸»ãªå¤æ´ç¹ã¯æ¬¡ã®ã¨ããã§ãï¼
- Bug
- core:
seq()ãpar()ã®functionsãï¼map()ã®arrayã空ã ã£ãå ´åã®ãã°ãä¿®æ£ãã¾ããï¼
- core:
- Improvement
- core:
map()/runMap()ãå¼ã³åºãéåæé¢æ°ã®å¼æ°ä¸¦ã³ãArray.map()ã«è¿ã¥ãã¾ããï¼ - extras:
extrasåå空éã«åé¢ãã¾ããï¼
- core:
- New Features
- core: ãããã°ãã°ãåºåã§ããããã«ãã¾ããï¼
- core: ã¨ã©ã¼ãä¾å¤ãç¬èªã®
Errorãªãã¸ã§ã¯ãã§ã©ããããããã«ãã¾ããï¼ - extras:
flattenFirst(),flattenSecond(),flattenThird()ã追å ãã¾ããï¼
map()/runMap() ã¯å¾æ¥ï¼é
åã®è¦ç´ ã¨ã³ã¼ã«ããã¯é¢æ°ã弿°ã¨ãã¦éåæé¢æ° function(value, cb) ãå¼ã³åºãã¦ããã®ã§ããï¼id:taedium ããã® nue åæ§ï¼Array.map() ã«è¿ã¥ãã¦ä»¥ä¸ã®ããã«ãã¾ããï¼
function(value, cb)(弿°ã 2 ã¤ã®å ´åï¼å¾æ¥ã¨åã)function(value, index, cb)(弿°ã 3 ã¤ã®å ´å)function(value, index, array, cb)(ãã®ä»ã®å ´å)
extras ã® API ã¯å¾æ¥ï¼require('flowless') ã§è¿ã£ã¦ãããªãã¸ã§ã¯ãã« core ã¨åã¬ãã«ã§å
¬éãã¦ããã®ã§ããï¼ããã extras ãªãã¸ã§ã¯ãã«ã¾ã¨ãã¾ããï¼ãªã®ã§ï¼ä½¿ç¨ããã«ã¯
var extras = require('flowless').extras;
ãªã©ã¨ããå¿ è¦ãããã¾ãï¼
flattenFirst() ã¯æåã®å¼æ° (大æµã¯ç´åã®ã³ã¼ã«ããã¯é¢æ°ã® 2 çªç®ï¼ã¨ã©ã¼ã®æ¬¡ã«æ¸¡ããã弿°) ã¨ãã¦æ¸¡ãããé
åããã©ããã«å±éãã¦ã³ã¼ã«ããã¯ãå¼ã³åºãã¦ã¼ãã£ãªãã£ã§ãï¼ã§ãããã¾ãå½¹ã«ç«ããªãããï¼
ãã§ï¼æ®ãã®æ°æ©è½äºã¤ã以ä¸ã«ï¼
ãããã°ãã°åºå
å
ã
Node ã®ã³ã¢ã©ã¤ãã©ãªã¯ NODE_DEBUG ã¨ããç°å¢å¤æ°ã«ã¢ã¸ã¥ã¼ã«åãæå®ãããã¨ã§ãããã°ãã°ãåºåããããã«ãªã£ã¦ãã¾ãï¼flowless ã§ãåãããã«ã¨ãããï¼NODE_DEBUG ããã®ã¾ãã¾å©ç¨ããã¦ããã£ã¦ï¼ãããã°ãã°ãåºåããããã«ãã¾ãã (å®ã¯ node-tunnel ãæ¢ã«ãããã¦ãã)ï¼
ããªãã¿ã®ãµã³ãã«:
var fs = require('fs'); var flowless = require('flowless'); var extras = flowless.extras; flowless.runSeq([ [fs.readdir, __dirname], extras.array.filter(function(filename) { return /\.txt$/.test(filename); }), extras.array.map(function(filename) { return __dirname + '/' + filename; }), flowless.map([fs.readFile, flowless.first, 'utf8']) ], function(err, files) { if (err) throw err; files.forEach(function(file) { console.log('-----'); console.log(file); }); });
ãããæ®éã«å®è¡ããã¨
$ node ex.js ----- FILE1 ----- FILE2
ã¨ãªãã¾ããï¼NODE_DEBUG=flowless ãæå®ããã¨ãããªãã¾ã (æ¨æºã¢ã¸ã¥ã¼ã«ã¨åæã«ãã°åºåããå ´å㯠NODE_DEBUG=http,flowless ãªã©ã¨æå®ãããã¨ãã§ãã¾ã)ï¼
$ NODE_DEBUG=flowless node ex.js
FLOWLESS: BEGIN runSeq at (/tmp/ex.js:5)
FLOWLESS: begin runSeq[0] at (/tmp/ex.js:5) with: [ [Function: next] ]
FLOWLESS: end runSeq[0] at (/tmp/ex.js:5) with: [ null,
[ 'ssh-eOFQSasB1028',
'.ICE-unix',
'file1.txt',
'.esd-1000',
'orbit-koichik',
'file2.txt',
'keyring-reWKfY',
'virtual-koichik.eMDJCS',
'.X0-lock',
'.X11-unix',
'ex.js',
'pulse-dawZJKwGK88U',
'pulse-PKdhtXMmr18n',
'node_modules' ] ]
FLOWLESS: begin runSeq[1] at (/tmp/ex.js:5) with: [ [ 'ssh-eOFQSasB1028',
'.ICE-unix',
'file1.txt',
'.esd-1000',
'orbit-koichik',
'file2.txt',
'keyring-reWKfY',
'virtual-koichik.eMDJCS',
'.X0-lock',
'.X11-unix',
'ex.js',
'pulse-dawZJKwGK88U',
'pulse-PKdhtXMmr18n',
'node_modules' ],
[Function: next] ]
FLOWLESS: end runSeq[1] at (/tmp/ex.js:5) with: [ null, [ 'file1.txt', 'file2.txt' ] ]
FLOWLESS: begin runSeq[2] at (/tmp/ex.js:5) with: [ [ 'file1.txt', 'file2.txt' ], [Function: next] ]
FLOWLESS: end runSeq[2] at (/tmp/ex.js:5) with: [ null, [ '/tmp/file1.txt', '/tmp/file2.txt' ] ]
FLOWLESS: begin runSeq[3] at (/tmp/ex.js:5) with: [ [ '/tmp/file1.txt', '/tmp/file2.txt' ], [Function: next] ]
FLOWLESS: BEGIN map at (/tmp/ex.js:13)
FLOWLESS: begin map[0] at (/tmp/ex.js:13) with: [ '/tmp/file1.txt',
0,
[ '/tmp/file1.txt', '/tmp/file2.txt' ],
[Function: next] ]
FLOWLESS: begin map[1] at (/tmp/ex.js:13) with: [ '/tmp/file2.txt',
1,
[ '/tmp/file1.txt', '/tmp/file2.txt' ],
[Function: next] ]
FLOWLESS: end map[0] at (/tmp/ex.js:13) with: [ null, 'FILE1\n' ]
FLOWLESS: end map[1] at (/tmp/ex.js:13) with: [ null, 'FILE2\n' ]
FLOWLESS: END map at (/tmp/ex.js:13) with: [ null, [ 'FILE1\n', 'FILE2\n' ] ]
FLOWLESS: end runSeq[3] at (/tmp/ex.js:5) with: [ null, [ 'FILE1\n', 'FILE2\n' ] ]
FLOWLESS: END runSeq at (/tmp/ex.js:5) with: [ null, [ 'FILE1\n', 'FILE2\n' ] ]
-----
FILE1
-----
FILE2
runSeq() ãªã©ï¼flowless ãæä¾ãã颿°ã®éå§æã¨çµäºæã«ã¯å¤§æåã§ BEGIN/END ãåºåããã¾ãï¼ãã®ä¸ããéåæé¢æ°ãå¼ã³åºãããåå¾ã«ã¯å°æåã§ begin/end/failed ãåºåããã¾ãï¼
runSeq[n] ãªã©ã®æ·»ãåã¯ï¼runSeq çã«æ¸¡ãããéåæé¢æ°ã® n çªç®ãå®è¡ãã¦ãããã¨ã表ãã¦ãã¾ãï¼ã¾ãï¼ãã®æã® runSeq() çã®ä½ç½®ã at (file:line) ã§è¡¨ç¤ºãã¦ãã¾ãï¼æ®å¿µãªããï¼ããã§è¡¨ç¤ºãããä½ç½®ã¯å¼ã³åºãããéåæé¢æ°ã®è¨è¿°ä½ç½®ã§ã¯ããã¾ããï¼ãããã§ãããæé«ãªãã§ããã©ãã¼ï¼
nue ã®ããã« runSeq() ã«ååãæ¸¡ããããã«ããããã¨ãæã£ãã®ã§ããï¼ãããå¿
é ã«ã¯ããããªããï¼ã¨ãã£ã¦ãªãã·ã§ã³ã«ããã¨ãã®å¦çã§ã³ã¼ããæ¿ããè¥å¤§åãã¦ãã¾ã£ãã®ã§ï¼ã²ã¨ã¾ãååã¯ç¡ãã«ãã¾ããï¼
ãã®ãã°ãè¦ãã¨ï¼runSeq() ã«æ¸¡ããã颿°ã¯ãããã begin, end, begin, end... ã¨é次çã«å®è¡ããã¦ããã®ã«å¯¾ãã¦ï¼map() ã«æ¸¡ããã颿°ã¯ begin, begin, end, end ã¨ï¼äºã¤ã®å¼æ°ã«å¯¾ãã¦ä¸¦è¡ã«å¼ã³åºããã¦ãããã¨ãåããã¾ãï¼
ã¾ãï¼
FLOWLESS: begin map[0] at (/tmp/ex.js:13) with: [ '/tmp/file1.txt', 0, [ '/tmp/file1.txt', '/tmp/file2.txt' ], [Function: next] ]
ãè¦ãã¨ï¼å
ã«æ¸ããããã« map() ã«æ¸¡ãã颿°ã«ã¯ Array.map() ã¨åæ§ã®å¼æ° (value, index, array ã«å ãã¦ã³ã¼ã«ããã¯) ãæ¸¡ããã¦ãããã¨ã確èªã§ãã¾ãï¼
ãã¾ãè¦ããããã°ã¨ããæ°ã¯æ£ç´ããªãã®ã§ããï¼ååå½¹ã«ç«ã¤æ
å ±ã«ã¯ãªã£ã¦ããããããªãããªã¨æãã¾ãï¼
ã¨ã©ã¼ãªãã¸ã§ã¯ã
flowless ã§ã¯éåæé¢æ°ããæ¸¡ãããã¨ã©ã¼ (Error ã®ã¤ã³ã¹ã¿ã³ã¹ã«éããªã) ã¯ãã®ã¾ã¾ã³ã¼ã«ããã¯ã«æ¸¡ãã¦ãã¾ãããï¼æ°ãã Error ãªãã¸ã§ã¯ãã§ã©ãã (ã£ã¦ããã®ï¼) ããããã«ãã¾ããï¼
æå㯠nue ã®ããã« (ã¨ãããããèªä½ã nue ã®ãããªãã§ãã) å°ç¨ã®ã¨ã©ã¼ã¯ã©ã¹ (ã£ã¦ããã®ï¼) ãä½ãããã¨æã£ãã®ã§ããï¼Error ãç¶æ¿ãã (ã£ã¦ããã®ï¼ ãããã¿ã¤ããã¤ãªãã ) ã¯ã©ã¹ãä½ã£ã¦ãï¼[[ Class ]] å
é¨ããããã£ã¯ Error ã«ã¯ãªããªãã®ã§ããï¼
ããã§ä¸é½åããããã¨ããã¨ããåãããªãã®ã§ããï¼ãªãã¨ãªããã㯠Error ãããªã (Node ã® util.isError() 㯠Object.prototype.toString() çµç±ã§ãããè¦ãã®ã§ false ã«ãªã) æ°ãããã®ã§ï¼ç¬èªã®ã¨ã©ã¼ã¯ã©ã¹ãä½ãã®ã¯ããã¾ããï¼
ãã®ä¸ã§ï¼Error ãªãã¸ã§ã¯ãã«ããã¤ãã®ããããã£ãè¶³ãã¦ãã¾ãï¼nue ãã®ã¾ã¾ã« history ããããã£ã«ã¨ã©ã¼ãçºçããã¨ããããã³ã¼ã«ããã¯ã®ãã§ã¼ã³ããã©ããæ
å ±ãæããã¦ãã¾ãï¼
ä¾:
var flowless = require('flowless'); flowless.runSeq([ function foo(cb) {cb(null)}, flowless.par([ function bar(cb) {cb(null)}, flowless.seq([ function hoge(cb) {cb(null)}, function moge(cb) {cb('ERROR')} ]) ]) ], function(err) { console.log(err); });
runSeq() ã®ä¸ã® par() ã®ä¸ã® seq() ã®ä¸ã® moge() ã¯ã³ã¼ã«ããã¯ã«ã¨ã©ã¼ ('ERROR') ãæ¸¡ãã¦ãã¾ãï¼
å®è¡ããã¨:
$ node err.js
{ [Error: seq[1] at (/tmp/err.js:7) failed: ERROR]
cause: 'ERROR',
history:
[ { operator: 'seq',
index: 1,
location: '(/tmp/err.js:7)',
reason: 'failed' },
{ operator: 'par',
index: 1,
location: '(/tmp/err.js:5)',
reason: 'failed' },
{ operator: 'runSeq',
index: 1,
location: '(/tmp/err.js:3)',
reason: 'failed' } ] }ã¨ãããã¨ã§ï¼err.js ã® 7 è¡ç®ã«ãã seq ãå¼ã³åºãã 1 çªç® (0 ãªãªã¸ã³ãªã®ã§äºã¤ç®ã§ãã) ã®é¢æ°ãã³ã¼ã«ããã¯ã«ã¨ã©ã¼ã渡ãããã¨ãåããã¾ã (ã¡ãªã¿ã«ä¾å¤ãã¹ãã¼ããã㨠failed ã®ã¨ããã thrown ã«ãªãã¾ã)ï¼ãã㯠cause ãã 'ERROR' ã¨ããæååã§ãããã¨ï¼history ãã seq() 㯠par() ããï¼ãã㯠runSeq() ããå¼ã³åºããããã¨ãåããã¾ã (ã¹ã¿ãã¯ãã¬ã¼ã¹ã¨åãããã«ä¸ããä¸ã¸åãã£ã¦å¼ã³åºãå
ã¸é¡ãã¾ã)ï¼
ã¡ãªã¿ã«ï¼ãããã°ãã°ãåºåããã¨ãããªãã¾ãï¼
$ NODE_DEBUG=flowless node err.js
FLOWLESS: BEGIN runSeq at (/tmp/err.js:3)
FLOWLESS: begin runSeq[0] at (/tmp/err.js:3) with: [ [Function: next] ]
FLOWLESS: end runSeq[0] at (/tmp/err.js:3) with: [ null ]
FLOWLESS: begin runSeq[1] at (/tmp/err.js:3) with: [ [Function: next] ]
FLOWLESS: BEGIN par at (/tmp/err.js:5)
FLOWLESS: begin par[0] at (/tmp/err.js:5) with: [ [Function: next] ]
FLOWLESS: end par[0] at (/tmp/err.js:5) with: [ null ]
FLOWLESS: begin par[1] at (/tmp/err.js:5) with: [ [Function: next] ]
FLOWLESS: BEGIN seq at (/tmp/err.js:7)
FLOWLESS: begin seq[0] at (/tmp/err.js:7) with: [ [Function: next] ]
FLOWLESS: end seq[0] at (/tmp/err.js:7) with: [ null ]
FLOWLESS: begin seq[1] at (/tmp/err.js:7) with: [ [Function: next] ]
FLOWLESS: failed seq[1] at (/tmp/err.js:7) with: ERROR
FLOWLESS: failed par[1] at (/tmp/err.js:5) with: seq[1] at (/tmp/err.js:7) failed: ERROR
FLOWLESS: failed runSeq[1] at (/tmp/err.js:3) with: seq[1] at (/tmp/err.js:7) failed: ERROR
{ [Error: seq[1] at (/tmp/err.js:7) failed: ERROR]
cause: 'ERROR',
history:
[ { operator: 'seq',
index: 1,
location: '(/tmp/err.js:7)',
reason: 'failed' },
{ operator: 'par',
index: 1,
location: '(/tmp/err.js:5)',
reason: 'failed' },
{ operator: 'runSeq',
index: 1,
location: '(/tmp/err.js:3)',
reason: 'failed' } ] }ã¨ãããã¨ã§ï¼çµæ§ä¾¿å©ã«ãªã£ãæ°ããã¾ãï¼
ãï¼ãããâ¦
ã¾ãã¾ã less ã«åã㦠more (è¥å¤§å) ã¸ã®éãã¾ã£ãããï¼ï¼ï¼
$ wc lib/* 119 309 2779 lib/extras.js 255 805 7042 lib/flowless.js 90 278 2533 lib/utils.js 464 1392 12354 åè¨
ãããã⦠ã¡ãã£ã¨ãã¤ã¨ãããå¿
è¦ã ãªãï¼
core (flowless.js) ã¯ããã¦åãã¼ã¸ã§ã³ã® 150 è¡ãç¶æï¼ã§ããã° 100 è¡ãããã«ç¸®å°ãããã£ããã ãã©ãªãï¼ãããã°ã¨ãã¨ã©ã¼ã¨ãèãå§ããã¨æ¿ããè¥å¤§åããã®ã¯ã©ããªè¨èªã§ãåãã§ããï¼ï¼ï¼ ç¡å¿µã ï¼
次ã¯ãã¤ã¨ãããæåªå
ã«ï¼ãã¹ããããã¡ãã£ã¨ã¡ããã¨ãããããªï¼è¥å¤§åããã³ã¼ãã«ãã¹ãã追ãã¤ãã¦ãªãã®ã§å質ã«èªä¿¡ãæã¦ãªãç¶æ³ãªã®ã§ï¼
ãããã extras ã®æ´çã¾ãã¯å»æ¢ãªã©â¦ ã¨ããã¤ã¤ï¼Stream ãªã© EventEmitter ç³»ãæ··ãã¦æ±ããããã«ããã便å©ããªã¨ãï¼ã¤ãã¤ãè¥å¤§åè·¯ç·ã§èãã¦ãã¾ãç½ ï¼
node-flowless v0.0.1 ãªãªã¼ã¹
ãã¾ããï¼
npm install flowlessã§ã¤ã³ã¹ãã¼ã«ãããã¨ãã§ãã¾ãï¼
v0.0.0 ããã®ä¸»ãªå¤æ´ç¹ã¯æ¬¡ã®ã¨ããã§ãï¼
series()ã¯runSeq()ã«å¤ããã¾ããï¼makeSeries()ã¯seq()ã«å¤ããã¾ããï¼parallel()ã¯runPar()ã«å¤ããã¾ããï¼makeParallel()ã¯par()ã«å¤ããã¾ããï¼map()ããã³runMap()ã追å ãã¾ããï¼- Extra APIs ã追å ãã¾ããï¼
API ãå¤ãã£ã¦ããã v0.1.0 ã«ããããã¨æã£ããã©ï¼ãã®ææãªãã¦æ¯å API å¤ããã«æ±ºã¾ã£ã¦ãããæ°ã«ããªããã¨ã«ãã¾ããï¼
å ã®ã¨ã³ããªã§ã¯
ä¸è¨ã®é¢æ°ã¯å¼ã³åºãããã¨å³åº§ã«
functionsã§ä¸ãããã颿° (series()ã®å ´åã¯functionsã®å é è¦ç´ ã®ã¿ï¼parallel()ã¯å ¨é¨) ãå®è¡ãã¾ãï¼ãããï¼ããã ã¨ä¸ä¾¿ãªå ´åãããã®ã§ï¼éåæé¢æ°ãããã¼å¶å¾¡ã®å ã§å®è¡ãã颿°ãè¿ã颿°ãæä¾ãã¦ãã¾ã (æ¥æ¬èªãå¤ï¼)ï¼
ãªãã¦ãããã¨æ¸ãã¦ãã¾ãã¾ãããï¼Async ã®ããã«æ©è½çã«å®åãããã©ã¤ãã©ãªãããã«ãé¢ãããï¼å£åçãµãã»ããã®ãããªã¢ã¸ã¥ã¼ã«ãæ¸ãã主ãªçç±ãããã ã£ãã®ã§ï¼ããããã£ã¡ãã¡ã¤ã³ã«æ®ããæ¹ãå·®å¥åãããããããªã¨ãããã¨ã§ï¼é¢æ°ãè¿ãæ¹ã seq(), par(), map() ã¨ç°¡æ½ãªååã«ï¼ããã¦ãããã®ã©ããã§ãããã¨ãåæ ãã¦ï¼å³æå®è¡ã®æ¹ã runSeq(), runPar(), runMap() ã¨ããååã«ãã¾ããï¼
ããã«å®è¡ããªãã§é¢æ°ãè¿ãã¨ä½ãå¬ãããã¨ããã¨ï¼ãã¹ããããããã®ã§ãï¼ãããªæãã§èªç±ã«ãã¹ãã§ãã¾ãï¼
var flowless = require('flowless'); flowless.runSeq([ function one() {...}, function two() {...}, flowless.par([ flowless.seq([ function three() {...}, function four() {...}, ]), flowless.seq([ function five() {...}, function six() {...}, ]) ]), flowless.map( function seven() {...} ), function eight() {...} ], function allDone() {...} );
ããã¦ï¼ãã®å
¥ãåã«ãªã£ãããã°ã©ã ã®æ§é ã¯ï¼ããã¼å¶å¾¡ã®æµããç´æ¥çã«è¡¨ç¾ãã¾ãï¼one() ãªã©ã®ä¸ãè¦ãªãã¦ãï¼ä¸è¨ã®ã³ã¼ããæ¬¡ã®ããã«ããã¼å¶å¾¡ããããã¨ãä¸ç®çç¶ã§ã¯ãªãã§ããããï¼
+-> seven -+
+-> three --> four -+ +-> seven -+
one --> two -+ +--+-> seven -+-> eight --> allDone
+-> five --> six -+ +-> seven -+
...éåæã¨ãé¢ä¿ãªãï¼æ®é (ã£ã¦ãªã«ï¼) ã®ã³ã¼ãã§ãåã ã®è©³ç´°ãæ°ã«ããªãã§å ¨ä½ã®æµããè¦ããããã«ãªã£ã¦ããã¨ããã§ãããï¼éåæãªã³ã¼ãã§ãå ¨ä½ã®æµãã表ãã³ã¼ããæ¸ãããï¼ããã flowless ã®ã¢ããã¼ã·ã§ã³ã®ä¸ã¤ã§ãï¼Slide è²ãã®é¢æ°ãã³ãã¬ã¼ããå¿å颿°ã®ãã¤ãºãæ¸ããã¦å ¨ä½åãæµ®ãã³ä¸ãããããããªã®ã ï¼
ããã¦ï¼ç°¡åã«ãã¹ãã§ããã¨ãããã¨ã¯ï¼ç°¡åã«çµã¿åããããã¨ãåºæ¥ãã¨ãããã¨ã§ãããã¾ãï¼ä¸è¨ã®ä¾ã® one() ã¨ã two() ããã®å ´ã§ã¤ã³ã©ã¤ã³ã«æ¸ãã®ã§ã¯ãªãï¼å¥ã®æã§å®ç¾©ãã¦å¼ã³åºãã®ã ã¨ããã¨ï¼ãããã¯æ¬¡ã®ããã«æ¸ããã¨ãã§ãã¾ãï¼
function one() { return flowless.seq() {[ ... ]); }
ãªã®ã§ï¼Node ã®ã³ã¢ API ããããããªã¢ã¸ã¥ã¼ã«ãæä¾ãã使°´æºãª API ãå¼ã³åºã颿°ã flowless ã§æ¸ãã¦ï¼ãããã flowless ã§ã¤ãªãã¦è¥å¹²é«æ°´æºãª API ãä½ã£ã¦ï¼ããã«ãããã flowless ã§ã¤ãªãã¦é«æ°´æºãªã¢ããªã±ã¼ã·ã§ã³ãä½ãï¼ãªãã¦ãã¨ãç°¡åã«ã§ããããããªãããªã¼ã¨æã£ã¦ã¾ããï¼å®è·µã§ä½¿ã£ã¦ãªããããªã¼ï¼çµµã«æããé¤
ããããã¾ããï¼
map() & runMap()
ååã¯ã©ãããããã¨æ¸ãã Map ç³»ã§ããï¼çµå±ã³ã¢ API ã¨ãã¦åãå
¥ãã¾ããï¼æ§é åããã°ã©ãã³ã°ã®åºæ¬ä¸æ§é ã§ããé æ¬¡ã»åå²ã»å復ã«å¯¾æãã¦ï¼seq(), par(), map() ã flowless ã®åºæ¬ä¸æ§é ã¨ãã¾ã (ãªãã®ãã£ã¡ã)ï¼
æå㯠parallelMap() ã£ã¦ååã«ãã¦ãã¦ï¼å°æ¥ sequentialMap() ã¨ã追å ã§ããä½å°ãæ®ãã¦ããã®ã§ããï¼å·¨å¤§ãªé
åã«å¯¾ãã¦ä¸æã«éåæé¢æ°ãå¼ã³åºãã®ã£ã¦ãã¾ããããããã¨ã§ã¯ãªãã®ã§ï¼ä¸¦è¡ã«å®è¡ããæ°ãæå®ã§ããããã«ããã¨ããï¼ããã 1 ã«ããã° sequentialMap() ã«ãªããã¨ã«æ°ã¥ããã®ã§ï¼ååãã·ã³ãã«ã« map() ã¨ãªãã¾ããï¼API çã«ã¯
map([concurrency,] array, fn)runMap([concurrency,] array, fn, cb)
ã¨ãªãã¾ãï¼concurrency ã®ããã©ã«ã㯠10 ã§ãï¼array ã®è¦ç´ æ°ã concurrency ãã大ããå ´åã¯ï¼ã¾ã concurrency ã¾ã§ã®è¦ç´ ã弿°ã¨ã㦠fn ã䏿ã«å¼ã°ãï¼ãããããçµããã¨æ¬¡ã®è¦ç´ ã弿°ã« fn ãå¼ã°ãã¾ãï¼
Extra API
å°ã㪠(less) ããã¼å¶å¾¡ (control-flow) ã¢ã¸ã¥ã¼ã«ã§ flowlessï¼ã®ã¯ãã ã£ãã®ã§ããï¼ãã£ã±ããã£ãæ¹ã便å©ãããªãã®ã¨ããã®ãããããããããã§ï¼ãããã Extra API ã¨ããå½¢ã§å®è£ ãã¡ããã¾ããï¼ã©ãã less ãããï¼å¿ããæ¥ããï¼
Extra API ã¨ãã£ã¦ãå
é¨çã«ãã¡ã¤ã«ãåããã¦ããã ãã§ï¼Core API ã¨åæ§ require('flowless') ã§ä½¿ããã¨ãã§ãã¾ãï¼åã®ã¨ã³ããªã«è¿½è¨ããéï¼ããã£ã¨åºã¦ãã makeAsync() ããã®ä¸ã¤ï¼
ä»ã«ã¯ï¼Array ã String ã®ã¡ã½ããã®ã©ããã¼ãéãã array ããã³ string ã¨ããããããã£ãããã¾ãï¼
åã®ã¨ã³ããªã§è¿½è¨ãããµã³ãã«ã¯æ¬¡ã®ããã«æ¸ããã¨ãã§ãã¾ãï¼
var fs = require('fs'); var flowless = require('flowless'); flowless.runSeq([ [fs.readdir, __dirname], flowless.array.filter(function(filename) { return /\.txt$/.test(filename); }), flowless.array.map(function(filename) { return __dirname + '/' + filename; }), flowless.map([fs.readFile, flowless.first, 'utf8']) ], function(err, files) { if (err) throw err; files.forEach(function(file) { console.log('-----'); console.log(file); }); });
flowless.array.filter() ã¯ï¼åã®é¢æ° (fs.readdir() ã§ãã) ãã³ã¼ã«ããã¯ã«æ¸¡ããå¤ (ãã¡ã¤ã«åã®é
åã§ã) ã this ã¨ãã¦ï¼Array.prototype.filter() ãå¼ã³åºãã¾ãï¼æ¬¡ã® flowless.array.map() ãåæ§ï¼
ãã¨ï¼generate() ã£ã¦ã®ãç¨æãã¾ããï¼ãã㯠runSeq() ã®æåã map() ã®å ´åã«ä½¿ããã¨ãæ³å®ãã¦ãã¾ãï¼map() ã¯åã®éåæé¢æ°ãã³ã¼ã«ããã¯ã«æ¸¡ããé
åã弿°ã¨ãã¦åãåã颿°ãè¿ãã®ã§ããï¼å
é ã§ä½¿ãããã¨é
åãæ¸¡ã£ã¦ããªãã®ã§ããï¼
flowless.runSeq([ flowless.map(function() { // ãã¯ã㣠... }), ... ], function(err, result) { ... });
runSeq() ã®ä»£ããã« seq() ã使ãã°
flowless.seq([ flowless.map(function() { ... }), ... ])([1, 2, 3, 4, 5], function(err, result) { ... });
ã®ããã«åæå¤ãä¸ããããã®ã§ããï¼æåã®é¢æ°ã«æ¸¡ãããå¤ãæå¾ã«åºã¦ããã®ãããã¼ããªã®ã§ï¼
flowless.runSeq([ flowless.generate([1, 2, 3, 4, 5]), flowless.map(function() { ... }), ... ], function(err, result) { ... });
ã¨æ¸ããããã«ããã®ã generate() ã§ãï¼ã©ãã less ãããï¼
ãã㦠bindFirst() ã¨ãã®ä»²ééï¼
bindFirst(target, propertyName)bindSecond(target, propertyName)bindSecond(target, propertyName)
ãããã¯ããããï¼ç¬¬ 1ã»ç¬¬ 2ã»ç¬¬ 3 弿°ã target ã®ããããã£ã«è¨å®ãã颿°ãè¿ãã¾ãï¼seq() ã§ã¯éåæé¢æ°ãå¼ã°ãããã³ã«å¤ã夿ããã¦ããå½¢ã«ãªãã®ã§ï¼ãã®éä¸ã§ä½ãããå¤ãå¾ã§ä½¿ãããå ´åï¼ã©ããã¸ä¿åãã¦ãããªãã¨ããã¾ããï¼ãããæè»½ã«ããããã®ãã®ããããã§ãï¼ã©ãã less ãããï¼
ããããé§ä½¿ããã¨ï¼ååã®ã¨ã³ããªã§ãæ¸ãã asyncblock ã®ãµã³ãã«ã¯ãããªãã¾ãï¼
var fs = require('fs'); var path = require('path'); var flowless = require('flowless'); flowless.runSeq([ flowless.generate(['path1', 'path2']), flowless.map([fs.readFile, flowless.first, 'utf8']), flowless.array.join(''), [fs.writeFile, path3, flowless.first], [fs.readFile, path3, 'utf8'] ], function(err, result) { if (err) throw err; console.log(result); console.log('all done'); });
ããâ¦ï¼ ãªããå¨ã£ã½ããï¼
ãªããï¼Lisp 㨠Perl ã®æªãã¨ãããéãã¦ãããããªï¼ï¼ï¼
ããï¼ã¾ãï¼ããéãã«ã¯æ³¨æããã£ã¦ãã£ãï¼
æ°ãåãç´ãã¦ï¼id:taedium ããã® ã¨ã³ã㪠ã§ç´¹ä»ããã¦ããï¼node-seq ã®ãµã³ãã« flowless çãã£ã¦ã¿ã¾ããï¼
- stat_all.js
var fs = require('fs'); var flowless = require('flowless'); var context = {}; flowless.runSeq([ [fs.readdir, __dirname], flowless.bindFirst(context, 'fileNames'), flowless.map(function(file, cb) { fs.stat(__dirname + '/' + file, cb); }), flowless.array.reduce(function(sizes, stat, i) { sizes[context.fileNames[i]] = stat.size; return sizes; }, {}) ], function(err, sizes) { if (err) throw err; console.dir(sizes); });
node-seq ã«è² ãã¦ãæããããã©ï¼ããã¯ããã¼å¶å¾¡ã¨ã¯é¢ä¿ãªãï¼Hashish ã¨ããã¦ã¼ãã£ãªãã£ã«ããå·®ã ã¨æãï¼flowless.array.reduce() ã®ã¨ããã¯éåæã§ãä½ã§ããªãããï¼ããã¼å¶å¾¡ã¢ã¸ã¥ã¼ã«ã ãã§å
¨ã¦ã解決ãããããããªãã¨ããå½ããåã®è©±ã§ããï¼ãããèããã¨ï¼Extra API ã£ã¦å¿
è¦ãªã®ãã©ããçåããï¼æ¬¡ã®ãã¼ã¸ã§ã³ã§æ´çããããï¼ããï¼
- parseq.js
var fs = require('fs'); var exec = require('child_process').exec; var flowless = require('flowless'); flowless.runSeq([ [exec, 'whoami'], flowless.par([ [exec, 'groups', flowless.first], [fs.readFile, __filename, 'utf8'] ]) ], function(err, results) { if (err) throw err; console.log('Groups: ' + results[0][0].trim()); console.log('This file has ' + results[1].length + ' bytes'); });
ç°¡æ½ã§ã¯ãããã©ï¼æå¾ã®æ¹ã§ results[0][0] ã£ã¦åºã¦ããã®ãå¾®å¦ããªãï¼child_process.exec() ã£ã¦ï¼ã³ã¼ã«ããã¯ã« (err ãé¤ãã¦) 2 ã¤å¼æ°ã渡ããã§ãããï¼stdout 㨠stderrï¼ãããã¨æãã° exec() ã®å¾ã«æåã®å¼æ°ã ãè¿ããããªé¢æ°ã seq() ã§ã¤ãªãã§ãããã°ããã ããªãã ãã©ï¼
- join.js
var flowless = require('flowless'); flowless.runPar([ function(cb) { setTimeout(cb.bind(null, null, 'a'), 300); }, function(cb) { setTimeout(cb.bind(null, null, 'b'), 200); }, function(cb) { setTimeout(cb.bind(null, null, 'c'), 100); } ], function(err, results) { if (err) throw err; console.dir(results); });
ãã㯠nue ã«ããªãã¾ãããï¼bind() ãªãã¦ä½¿ã£ã¦ããã¨ããã®ã«ï¼ ç¡çç¢çã³ã³ãã¯ãã«æ¸ãã°ï¼
var flowless = require('flowless'); flowless.runPar([ function(cb) { setTimeout(cb.bind(null, null, 'a'), 300) }, function(cb) { setTimeout(cb.bind(null, null, 'b'), 200) }, function(cb) { setTimeout(cb.bind(null, null, 'c'), 100) } ], function(err, results) { if (err) throw err; console.dir(results); });
ã£ã¦æ¸ãããã©ï¼ï¼ï¼ ããï¼ä»æ¥ã®æã¯å¼ãåãã£ã¦ãã¨ã«ãã¨ãã¡ããï¼
æ¯è¼ã¯ã¨ããã (JW)ï¼ã©ããååç°¡æ½ã«æ¸ãã¦ã¯ããããªãï¼æ¸ãã¦ã¯ãããã©â¦ å¾ã§èªãã æã«åãããããã³ã¼ãã«ã¯ãªã£ã¦ãªãããï¼ããï¼ããï¼
ã¡ãªã¿ã«ï¼ç¾å¨ã®è¡æ°ï¼
85 229 2126 lib/extras.js 148 390 3372 lib/flowless.js 52 179 1389 lib/utils.js 285 798 6887 åè¨
ããï¼nue (å·çæç¹ã® nue.js 㯠262 è¡) ããã§ãããªã£ã¦ãï¼ï¼ï¼ ã©ãã less ãããï¼
次ã®ãã¼ã¸ã§ã³ã§ã¯ nue v0.2.0 ã®ããããã¦ï¼ã¨ã©ã¼ãã³ããªã³ã°ã®å¼·åããããã°ã§å½¹ç«ã¤ãã°åºåãªã©ãããããªã¨æã£ã¦ã¾ãï¼ã¾ãã¾ã more (è¥å¤§å) ã¸ï¼ï¼ï¼ å¿ããæ¥ããå¿ããæ¥ããå¿ããæ¥ããï¼