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 (è¥å¤§å) ã¸ï¼ï¼ï¼ å¿ããæ¥ããå¿ããæ¥ããå¿ããæ¥ããï¼