From 210091a75fd6de2f565286ff16555fbaae8b19a2 Mon Sep 17 00:00:00 2001 From: Ferdinand Majerech Date: Sat, 15 Oct 2011 16:31:23 +0200 Subject: [PATCH] Fixed a bug which prevented dumping to file. Updated tutorials and example with new information. --- doc/doctrees/environment.pickle | Bin 12384 -> 12705 bytes doc/doctrees/tutorials/custom_types.doctree | Bin 25570 -> 46858 bytes .../tutorials/getting_started.doctree | Bin 32261 -> 35418 bytes doc/html/_sources/tutorials/custom_types.txt | 142 ++++++++++++++++-- .../_sources/tutorials/getting_started.txt | 21 ++- doc/html/api/dyaml.representer.html | 3 +- doc/html/articles/spec_differences.html | 2 +- doc/html/index.html | 3 +- doc/html/search.html | 2 +- doc/html/searchindex.js | 2 +- doc/html/tutorials/custom_types.html | 130 +++++++++++++--- doc/html/tutorials/getting_started.html | 21 ++- doc/html/tutorials/yaml_syntax.html | 2 +- docsrc/tutorials/custom_types.rst | 142 ++++++++++++++++-- docsrc/tutorials/getting_started.rst | 21 ++- dyaml/dumper.d | 2 +- dyaml/representer.d | 3 +- examples/getting_started/main.d | 8 +- examples/representer/Makefile | 2 + examples/representer/main.d | 55 +++++++ 20 files changed, 493 insertions(+), 68 deletions(-) create mode 100644 examples/representer/Makefile create mode 100644 examples/representer/main.d diff --git a/doc/doctrees/environment.pickle b/doc/doctrees/environment.pickle index 9ea0e9f19d8aec42c8c660d7361683d86436ff09..e329ca1ba75be7eda37af0a04c2b9c33504ce951 100644 GIT binary patch delta 964 zcmZ8eOHUI~6mCZoC|1M=1d2SGLV?nUi6JpA05`HA>4IbuT-0GYz2&yH(|TrxhdM$P zs)*v_`hFuy;>MWx2UuZ@iHRX0(MW$vX;OSy*QXAqf?wet1xRbE-; zr|a4rk9^a-B|W)S3Ig+1dsv~p!NnW#)*5@+-tN&c!wn3pWXLX|M{(vn&RpZ6-?87Y zbva^R+Cz_8)~*ffQ>;5!UwaxAC_iJ#&8_mYtT)tCH^!+b{ZfQ+L{a*w2n7o)72zCP z3D!B!v){qm4(^8&Qm1@2IO5veF$F2WQ7nSBk` z_%0!$%d%LSl}8dJuhU+^!1Xpg(h~xkX{=_Fzl{9}Rg_Gl-h|7nGTb0uvG5F@t#oJ4 zk)?Su@nPW`_1SQ7ZjlCU_=5r5Zx6yV=Hz+l2dt}Y#xK}{N}0*^3_ zYH@KJQHS6$CR7mJkW~JeJYk gb;}&@QWBf&gXdNe{-dN3MKy3G(BK7re+bR42AFE3Eej?!F-*HDG<@?{_BzBVF zkU}uNLcR|B&YQ(AI-c)FYlSqT}h~Uxd zvJQ-aL6T9Z_Bu3)wPAtc<{~Y#gMX2v9N*}|Y5bHL89zgmZ%Bf-Cbf#Jq4R?-gI3tA zUo~8~Ha3i6)Q{Qpfak1Lw~a^Aqry20pQjk(Tjut!Kl=OgT} z8X4#(R_SQNb<^!#kU%XNstjvHb6P=gGqnjfh;WzC2PIi7NE#CjP~awpc174NGp)a( zHVj>4s$4J9B5>OjeTH62?oMizG9Yn77*q`!7ii$#e`#>XEbPfIABMYD9l8)TCfi00 K?vdCw3aNiAwCAS) diff --git a/doc/doctrees/tutorials/custom_types.doctree b/doc/doctrees/tutorials/custom_types.doctree index 4d8a875564a3d668213a85500debe5c3e9dd5040..5f0a4562a8d58a78eec846a8539c3bae406e5241 100644 GIT binary patch literal 46858 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 CwsO`0 literal 25570 zcmeHQ349yH)i;48jzU5R2?Ynr#)U*Nw(JBj;1D1;sS`t!EQkhIUP&wMI+9j1yNYdK zTWCw$^uFlb(z~Viec$(e-}imr_ucRR-pooX$;#0$ZE2hQKr8LMdGp?zH*em&c{9Fc zPA>1|YJpqwQxz|7`w9A4wkttGoUrCrF((u!Cd~yEt851|RofRQg<@_py|AmRE9X`G zK-O}BC&j$6bT?i}+xJQbY$@iCrB5f2njd&&W5z0%jJy?ChQiT3Rx?laYgs>V12pYb zGI_h;iv^)bn2W2H^zBU9_I;~}_7;wdlg-7snv|d^<9jukv&Et@Gm*D*p0ud8SUhGf zwQ7M^@Vubn1$M>{EE$MXMo%#36XkB+7fV8MYSNi!E{v1C)R}K~*NHyO={8SSBo7eD z14QzGB6(TO?9MrEDGxHl@^Nu`tJr)yN3a(t{XT5zBPD_^or6dm)%NnaLb@wDY_MV zFi-RjqU(H_8-z?f=~^X!P%)EX7E;m=#NBVZRh$zFBWunNtRl%qtTg9q+C{IKu!2Ck z*;)X}-y;;~Ce7}Atx9mdIB(pXpDS6ukMFC-&F-v~+b^l#R*#z}l8BSzVvV!RGUqDz zzHxEB({0tvlS&{_^pBnhWLmkzfHTK|7*oks0YD{6V0{o$916wSq|?Kiv{`A=^&5BX zjBC<5XN7ZybCz?Cv(lW)RmBAk2){7toHy>Q8h2KYJIQgUZ@lK9eMh%?QEQ`n?P=)y z@S$3|7?Qgr6qkY^hguz~WvyDa6%o4FLhn?agctz_>qBuFaj^1)uCA*Kfn70XyqZyV zi%wunS(U&DJj1uCuiP7LBj=T?C3`x?pW)YXj$!$RmV3&$9`$opB~kNjqfo1`&iRC< zD!m-WjKPDrUe7YhR<#OM0rE;T(nts5>v8tvlyN-FZdQ8BYHWBjtZn#NtY*=EhKLB2D|> z6$8{~efxm4%T>qnT|XfJEaM@@*)S{Cr<0se^eUF-zHU7;8wijKIJV$()bWMHli#Whs@G8mYx z7HkC%RI&jE*fucXT1CUJ+Bvr{Lqp%i=%v{pWo+}L;bH=}Dmi<^z(kH>ALAIqlZL2O zOiWDRbA%?AlqZY*>xPEbjR0<90^C6!G=R&V9~hXsty&4TjQj%wbDYuV!jQQ+Sn?S| z&#w8tM7~CC7&O1**>CtBTf@9pSsfS^8^(gHp`w-PE`UUvm@1S!E9eKgfnBs^zhMWt zRAL9)6U=h3eV*^T*%Db6qrK_KT!9eGKl1JItU+XqR>g$%4xLR<@#x-JxHYW_^{*HHy% z*j(Q(BVeatb8m=exf(X@`Xly%#~VU1jz)MKU8ly;d`*S84-cc2Y8V|_(L@HgCPHBm z!ADd>3BVy^kPStS>Jg>0YAi9C@5rPLCQn1vc7@A}0>~K- zR@cLvZy8}*4vVb3roI>%eaaz>`+aOE+3>>%I$kN?a3d2~D8UR@y-J=8Fd0dj2CQPr zXhw>~8sIQ%M4qKlH^JKXv-1hmi?{0rG}+lr?kLRxRH5W5my%`_@FA6(NE1w=&&uax z3?>m&^u$c5Z~;kukY76!#~vMZnV}RMNc%w6~9% zWGNpwi+%f|d@3;-N(Nu|yn`%fmwP@Q!kML`S(i zau&Hf3e-M26pxAI^02sEN+g$mq5g`;f||#L;_<}Xzq;|5d~XlM6NrSRq<3v&ij?n( z9fkZPt@o|f#FN3>Q$q37NYb~*CB1+o9gS7-G=M%m6we?Uno43c-VustQu(Z7<5?Za zd-g0k@EkPv+)z9(qU?@1Wi%V>HD=sii07ly3qtWiqM-v!jM_Ux@gjnxcvfU;NRBV= zNa#yID6J@zT@o)vb1w_U%Oe`^jMLZyxXy-4yaIJ!8H!gC0fz=v6i4fTSBK&?RA(R1 zU#Hz$a!hQBpl?LH z7R@%9*4MR5rGK<1GOe$NWd7MCy#XS7V<_GP_8lVc)ev__7dMkFdAa=w@n)Fpw}j%Y zB(p0aGsT~=nWU1qDPiDWEjts~Sia=f$9@*2ZCBzivZb26J`py=VlL8ttZGWUjdbVj zNfYjE#jbe1c*jAryJS_0HH0_CJJXoyyYl9O>2hhruUd$0zRT>cVivaL0b9JAf>#J( zsaTeZVx1ic_dO8qv7lYN7ZQA5DBcfY@PzXgmLNMM9|*+K*+^U1PcAFXZj2 zt$ZLfG3CJD0GcU#HQbdt{iN++A#uP$&l&}Z@U><5h-O(>c>1=e*;p|56LuY0>!&3y zR;?;j28M~;SX_%FmT;^CE%CZ~gFvqaV@q2cQZugFyKCn_$%X9Tij}bnPVC;jefy?O zOo6UZCj=~k6?9OvjBgBJReL0HlN{N-dw0K49NE5od%uw#*|cd>Xr!R|kTi$nnq0Y& zhGMIQ@rPy`@2et}{4lvv+o93NNLR#1pqd{I#m7hok0D-g^#Sd;eLNJOAnY6xV%4Mp z`^k1TQH4CVPk}=U2@$CHG|2l*C_WpFoR7y%{Z>F76Ezo~Lo=Tb#TSUqV}>;*gD-~S zON5)JJUymJ3SaIhg|9#gBrydnz6t`r7K*P&a`<9g4vPWTJVM1c0RPQUe2W@wFOE_6 z?NEG&fVg*fToYa2?MT=6bng(T_&!?sK`4G0QT6RORr5iWwh`h-0Q_+%enKt9-pA

k~`=U$=5%cqo#QXxpkWWO!FueFB8v0czejQQt(>O&J!Nwl9QNhvMDDfMJ z^|zt;9re(0De^pV^iovXP7WnGN52onA4r_;(S24i>)dsfQbB9|+0BqFjEdkWK0eQ$Z|bk44l zQ;_W4Q2`1!ujb1Uqu02vYJ*y2643e@<(-9$dTY>$2+6p6m(!V%_wc0q}SUVJT3JXW+6TBwu8mI#GJq2eQ)i+@8&<~RAf3Hcd9X9${ zlH4KthQ`+bAxT#KUOT=<_qfKv9{QnitZTt>K`Rb&>JLN5g)KNPVjRq#WKnOqxOv6vPN!&k+sPm<^is}aWzoXo^}LKp}m^^ z7!GXGMC%4xEY!zffNkMASRiNW-x~xF5&o1LfK-x1YQH^`D%t_Y5BdI$;X-iDwdf6x z?_SwEVnnh?F~N)iM6Nfo5W{{YH>wc*Qx%J-NYdq&kEUW46{$;(qN3hM8!_r#hwK_G zE+dNQsmxmQx12??A&seNuT$0tHc?m9jZMpN(ci4Yc} zF$e$KCqnUOESCQgioZrNh~Fayfkhu>6a6g|f2Tzs?PrZ4C9)Ch^^tKj#q`VBe`-6HQiu}p;2aglt#2wI1d5c%z#oxa2z_Av8Q)ou zC*WOsXr+Ht>RDONp-RL5dSXvRySLpcPr@UVbD7GXNzK9ElrXV^mh-rLzA8`O36ZKO z@&HyjBgV=cZ@_HZHiUl(U4ne(N)g#u^+GC6=8X8O3vrAqwXjLt(vw zM#qkmLK)Rlz7$vGuc!?y{FP9|x`Lb~+09I_zeJ%=>dy`?Q!VP81*n3~`Hx~-CO|ZL zb|D_2Jeis19g#`u%la^pi@1ETDo;;AB04J<`va6dhfG(ssi1}lB}`0As1BHz;LwBW zZxzR&oU}?F*>=rcq#;>Ne8ZlmJt0bfz}B4Ze7`l%L7u`SwI@E`67|Xw1{mg4sl(DN zPX#o@u@sL`p2k&GmepaaIx8kgNH8nND3i+=!E%it0eMBtPE3$`oz5k#WGfU1xy!qu z9J)j?U?n4Y2Ht?OGw}#z4_8+mMNO%gs>&ie19dt{T&_@9&SETQD=g_l)o5nx?p*I2 zU5_^4BetSprr0wWqBDCdQ4aPf4&JN+vKJ*_^B#DF@?1uv*rcZ8Z1zTM9#UQ8c?#bu z#WEuzA(K*It;}y%JMeDD8MLy7{xjoo&i^^ z?+SA0rX>>E2n7rdW<5-&QJR*IWZz1j@?Rl&ANl(lT zCGit$In|O7(yP=G%kouqC}v&-fi>eth9nvq?Z|eifLJ6TLdPOO?k}>vAWM~Ak?d_a z6}_>h6$ilc`W|!h=B<17#D&SsaGbZH zb5V?l%2ddSGVagkhnS+G-fbIq>@;_8rM6o`G;$q}#luEvZi@`W z1%QWvI6ib6dnd``LsuTnI6OXdX>=P#G(L}X=*kN*_At-V=4&X2dEhEfg{IYp=X^1j zU!uy>ntjDK-M@vjJAA zQDz^qdr*lRpvkkT?F1U4^k!5=S%v2co?a>?jK4R$FK zeQzxn}dHTORn8Xx-+tYBMhJpCd?vQ zNr~m?Cps<^$_)&xaw2B|hRa9&rSfFt3y)BaadpKiH5GU0=fa<6b(UAFD%Wt8d#NhvdT}$s zyBTPY2I{;b*~<`}2{%y=!e?2LT#FJga2+0@q})XvMVh3h;|$QDnpp>)yk4QWH>236 zP^3G8HyA{gy}W@djq6J1qKzXN$F#h-57+6;at7sKnN&>qnSF<_3~~a{5QBwBD6@=O z^&=4&SJ_eO$75$kWKK1l=Z0<7Fdq^>hK)3fyueKrbyJibrEM8W)#2BjrRt&_QYCd| z11Kl)0)pF*M<`2NTM3Sui3@HBRdkm55nD@HR@f_y-BZ}p{|KhK2%^<)l~D?favH=% zF%TGjW$)FAezowWV>44a4ur%{WT0SO<{1U#f~ag(gnR61ixRYPNWbB)VY14*61Lxy zGg02FK9z#p;Qh!LZkrM$)707p{i837rUah>hSOL4|B03XaH0EZc!cr*BknmCh#_y1 zu#Oi^G5TqZo&qwRq(wS7!*HzvPzY((xe?{i!DT=*o5Ck51xsA^pZP&(2(9A}faGMf7tujA%>&rXjL8`c7lG=`)bdwKd*jQuw zuv;DZ!>GbAXOY%%Jsj^Kjz{1T%11JWo=M#RkpKaMRct=UM={8w6-b(5b9)-+mMMlx zgUZI`A~P6cba+7}p5QVB%1ME@|t){xsB zMOcw%1|)kafgAtP0paH3&H6$HT$q5M7MwPX7{}J&CGx4_DEGQAl0odS9s(bDr@1EC1eg9Yn7*4+pdiSKA#*P|`&%b-f*zv6+H2oeky_HW_1U!QYxI+<;{wFn77iTn!Ka*R1 zmTvXOU=f41K3>7(4t;MyW9X`bZhVrY{<5Ffi*!(g#w&&~9RXo0lF<7!bcBV$v~}CDQu+IFG4x=nojb~fNEI)`hAofFeg!02&T@gzS#finwt`s0Y!jK-#_~H$liX6>J6v=yM*y+Fa@3X3?8BU zEQ_FLQcH-G01Bj+0H0%!&npmKS8jyEtWHz%WkKj5y{`l$Z!Sn?ZO(#o7dLG$M~QLe|g+Srxf!W$6#Z9GEx9j>m%H#Mckw@RnLPafajWytR- z$olwJG}8E{{HO0T%nvloE<6Vj>cHsbQ>)}1A*JO2E!wd5;!sE`l}aRd&o>(X*r267 z@ZEZ4x;|RRN!p@rb=G2=U38uWE}1>8K9jxsh6XOR1_~PowvFF39QHPjCK$8*>m6FV z?t%+18ov0FOD$aSXBReZ+Pr1!wq81Fq6k#m#vM1M6RP}ByU`jV#%c5wZ5)B5nzfqK zw0_94KJ13+dm|XGfB|-$;3gmJK8F7pT{)1U$$5lF_w}{{GR= zM7{nisyBSp&HWnHz|(K=2<30Nk)BCS12Ll5qJjTA2Kl`LNk0{A>GTFpe4IVwaU1^q zn^GO)vosH*KQQG-lI{4pNTz>870C21&a3&8(% zO!HXgPSJfOaIm5+P~7^5`%4_Jh6}B5H!j^`f)E_tbefWX2ZghYfUY^SCk}rz>a7z1 zfZn?6GByVUqMuI0Ba|mGJ3W({Tk4!fSIuRRc?u+b1G=hhUqam~3(uM-UwxTIETA6Q zwu$z=heX@nLwvBXxtY&Rx0{>qM8fW7fZ_D2Bc@F*Kozi`z$26kxqi=4)Q3utShTlv zGGke!u~6V)R^BP_u$X~bc~RKNaXJO%(3?|%qrQ_6Nlz|8A&5Q|k5DdUOloWq0q8Ji zrPH|Bux%TmRnqb_g>D(6TdvThSEA*^R;{xSM@;=^(Y-F_!T{OjK8265iaH$_$IM0b z3$y7SXL&bn>S}^|(BX3Qr}+Eh@<{zO%XX z?o_(0rK$orhXD)%Sb*C?`7&=`uH?79_#_=NPmb>XrVDiBJ@6X0eb;%ZUlcCSEh^7sZM7Ws<9|p{k1_IuwO{c!%6nDp`V!KHi(lAS8#~ zOkehMwE-&Z_U(YebiPdCXY5jIIJ zzc1IJ1azK;y+BXqaXmU+T!WiuT-%oyplr-MSr&4cEKaXyYO*9R#5;3^69m zfBlqe2L-ygbWbFRl7>8ViAmcZG3q#BVSDG+G+--gYJ*= z`DTgYcA6CsoTiqMuKxL7&Fh}gR2>^ z;?Y%y8TC^o3rV>NVCE8Hz(+*~?Ux`8xtU(i&D+^pQEnkj<`TLUn^a~7`?HR12XZUk zA2iSQY5@|OJK^6(h~^P#xj=5GAB*T_^-8UrnWk|kufjX@>M8kJxtgh~urGJuJw_uk zirh-U)4=ysz>B9WNw;=`8l)DL09O!mAY>;Baeb6s9XN03!o1u? zKTox%U0j@x(N*)c6vqhlTyq}0-hx|{S2IfP^IVWQ;NlJ@To`!`zg?cgLS=u(Mjmu2 zgGCqY9WGmx_d?-A%(KC2xo!>`YLwxdtmJM09W+n0D+lBrMy43A`gSc3F3TmkmtQZz zWbZ+dv8P6Nj+cCC^82MEJ^YyfzSmt#n?z$ z!LqjCPRk5|(U7yUnJG7qgI^PPGumw~ZdOuh5#U^N?>3N>rSJ3gpE-~@`ZanC@Bf#1 z!nmMl!;)Im$u@qEnTuH=8{#kU+mlJh>K3L*HP6u&W@>6GRh_|gofWn)dHcX1fc-(~ z5Y$=C0&E$DE71rqre*ju1xuY$&0N~_cQ4c&TVwbG_=J}* zK(5FX*M%#>_rFDdE&_k%0DsZ|*T9(zqB+Bt(*PZpGx#*;k>=%nc_V&=@+N%NvZ?@wchj*9XVYXMov4PGDli5|MiB6YBSc82yOs9jE84ermKCx|AR&Q- z^j=8sq=)q0doQH-MhfY@egFTP*}c7H%ft}!CH#!$cFLRA=DjzwGqVqyo6A>nwQ8a0 zr^=PQ<0tr7a>~_&cfiK$yt#oluRFb@oGm%knJLHj<_F$_?##+LbLLDq)oP(Uk@Txs zsXBRY;ZWufWapDpQkjr!sl>u!wmebGPB`A8!2>dfp}0^+{bDg$b)96sluza=rKv*E z5pVHOW**9O`JA@|bq~dFXZIA^XRC!uIawLkCOP2fC5AFfSXG;%7jNlMWq}{9cRvd}X>^tYq`aY&k+Dncu8!R}EznsN!2PYg69p zq0HfgT&YQNydZwnRwc!gPOj>$8Op3ih3r%z8M0Ba_YOpV1eU9mbH$nug1m!b%!Ri_lzNqC1tT1N!l zT1ZQ>(>`#_IbK(KPI@7LL7v{a76?EY{U*F4(e$XmOLn`c@2+$Cygu+Y#Gj82yko-W zx#@)#{;|z4#hH>?xj-=`yyG%Mpt;|zl$`#Zg+kTs^RxYz)wQF4OTSZ|D3qQ4JUQME zp81mN2RkZK$QJ#6t70Qo#Zq9ocl-_4dEJ4xaV)*4nw_9xdOhhyzM;iCA)Uxpt5O)N zRl&F3!0YQyFV5GdSkL!T!|6r2V%GQZyMH*ncr2USDdhTz!|8d2yziYf?46umX}j$U zHT#rodVv9O>acg3yD(cz&o2UPZ`0sBK(_BU%(>leYS`@`c2693Pa1Yl9j>`R z!9~X|x;wAAw;j%I4C8^eU7Qa#UJ!U&fP%~J&a91PYh%q2pgLKMTLbY9z#lo0mWhOaZ5svl5=$5voBm$c6i&>h!(9#e*fTof=Tp$waQewIQ zqoW3;P)@p)Y2uBc9pYS@QWH?~on)b!L=_$6c3k_Zm^_w5Jn=53Ot!U?$%0TO_w9BE zGDq#5UEUz%u|4oEA$w<09|&!26&G|FCa|1?iVZQtgm(h^-v@b+s{3`P=Tqg? zlu}OVg#ccYf_HglJ;3c%uHF^YQ0S>qSgI;erkd^mM`)l4)k}ly`v=~YKvPZ6rBFjC z{gQ|hFVjjU91ezP!n+DIJ|OU}CXL4cVx$>+P&X3y!0wP5msonk>G^8$ugS&{_D0<0 z*$`{sw9s_xjn>9M0ex8~#r3kFYAo<_L~KtLjTBwVDj#?btDgP?9^DK~|rViGwNDtQIXd1X9NrQs};VTMa4 z_9_)7+-fpg6epXXA?%%H#7%4pE161OS}r0t>lbp#8sil@fLvu4EKxpYI9;`t)9tKf zBD9vfX)QTmIuYc}fWr?8ylYAMo+^S@wN}I7gYfc1!h10I7X;oz2<2dO*OpHlNDpmA z7l3KS9tKPq>$Nc0yACK`A9xQ3a5ZUxF=-1;=iVdKe3a1i9uqD@HfXO)*<=K zb`+l*a`Ranl9$~L7<8&Q9Sg1OZEhfC@LPwq#c+Y3|D?nc( z2dRrMXk`pQa`3+pJmGY%&U5cYpytJa_Y#29QU5$M>KEDmyqD^*Ux!9}6pr^YzT!Mx4n*x6)U-&3GbDl_13_96@i`z6fSn470D|rQp_heCzANDFR6L< zx0WOZ%Ko$?o0F%WTvwU&@&?e}tI4R>bf-aQ*(q0i@3l9j7l)y^_qu2%o?f!MRNU-O zWicszeR}bfIKCsh9PbS+(Z#00^F!TxBiMXb(DiNu6WGm*+bOu6`;q1=ReWtv()j44N*xOrmW7FWa5b<{a@qO#yoxu2Af%k5p z=CZT5)G>Zf;Jud^4+G;NOkAd&WZ7}@biX=r!h|K2jOl^-2VB`?cj zxd4RK%>icUhy*IeOu&@17>4(?qj4~#@%=OmseQ)D`v55YVBmd-B<*{1u;x7&NgTW% z4!n;L2nS-FQtIPJTMdHDcXmC{s2s#sUcr|^HFa%RHj(72zONbIT<@<~$A zy)kjEj@bVG%MqHXB#lYZ+#xK&B&AZRCeKc8$0C;_-5cr_Ys1DASH8M80wOIyfB%+( zkM*`01(VNKvq{E#DJ?`S=wx$lH)0t2lIe=%&s5M?Z;08F4Z|C?wn2(Orv>J=Sng&6 zbi}Mc|Aqw{b|6g6s-a=nxS`iVHMVENa0(N>^-$9ombKE9qDbs948r9Xj)zLE8ahFP z_ZCzp*|7r9okwmr83U+6Y-Fo3`+T?i+MC?hWgv(-dH3~hI}0@w4uUU0pZ+H@vhwN; z_ngSQFJi!bDe%4=j@!=~Ysq!X+XL?_VRjhUX=M4;2BYA8Eq!QgdAYAL-iHZOpDr(d zUE|7cxCxCb$3t0v)5MkE3cPP~q;i4!!VU}6-+@xy9*-)&+t9ggBI-x-1kB5 z4+8Ip=+-6ZZ`GZ{j{@(<#O5);W-FJZd+8snz0fHjjYdzhgb5!UnOPLWKx0vb^EOk! ziCpAWOzQ;36PLqmz}&}mu`E_*IVWV$Ib(alVjou4=#elO4K!UZ3+dMw^C#`-cSFwJ zL07_gSX&CbpMw0K1>Vm|XUAG#%a2;)Ag46tVq)qiyk9^!?hL$N5(qs&kMf1y;#aM> z0T#W*uYp$dD&aT4;*RKlV!q-+kP6Un=X7~H z9mlvs8>=#iHER<1l?YdTxDL}WAphE`^qU5Eh6D0%9FR$9^4`Sf{T-V3kHGsUPY0zXRUO zQ3$+gh78`a0y#i*I>n1aFBvK*n(3Q z*uh5@9HRLhSa2u`EelK&ISe^q!Qn^(IYQeS7OK+$>>f+D_c#@Ln(cmz2|BMIafZD`104~87G5~!$k zG(~c(fpeU~Io`lAN%%j<*S$o~fuD*cAy6P4nV48@uMFVq>Ou`XOrRvJ&SG;)U1!`WmHri8k5gLOo> zWo{UuGs-r)(o}L=73-2^dP4Ya$E)#`WU@OelAYPunVM6hQ{VRaPsM^Um&M1v9@aR#xdH zF^f!MuLYa>X8moaGlS`7eDa#$9*}SrlS*C*I9w`(W9GXI1+2@^=nm^dcuB00iKWiq zU=c_tvp98)#Ua?kLfo)Xp@M!aP6hB$sU%Er3^QG4!jWcoEvKp^nuqA7L9rfNPSXl> ztDEpEkkj?qhPo;`j`TCyf>}37anqsRhpCBq*+w?w8DsoRB!QfTzwp!yeka*Ue2mjD z{ZBVI``W8+$l2f(n0gM9K+eTqhClyfpxIG13kE{{sINAPJWts;VA;5g4x6fL2OpLG zd@XApJ9VYM0Oe46E+f`k$`<58N*5vtWUGQOs?QGNs(%{V+4vAa{XUFwxyW>Jv39Y| zbdkBs;3Bq!HvGN{chJJU1!&?mnA+tAyOzaLqOr#?m65Tg8jsV;O&h}$H`SHfkXeX1LbXl#WV`Q zk^3VF@YFfJYrS!eVd0#i<|Fg}A_5C|raS&tjAjgmXa@VeH#eQ~q9u%c$y$5gi)*T>-K z5ja#6c0lCokT6Pgvaj$l&Z23$33U+4SS%FB9<%D+V{lCP6RQ^~Cr!RsXKm_(?jD`-Q0Qqug+ zqUWp&qNl!?R#HI@gg=EO5Ko&M;j^Q-@UN%v)uR17t%Zoe*H?V22H(uR1Gh#&)fB^B z7Q+tCZ(55x%WF5v+d97)6hLebLK4We3dM+x-Nwb%L$S@;rpkj2+(6+z#K6t$8;nLa zJX9e)%tBfKY}9U3S+CQ~&ct7jau7ccZD8u<;dlhek3bU04cgX_%r4?250YdqYVRMv zAdfU1KT12k(R7^I&z(d}3j>jxw6{mw-aY}6b|83&&qKlq0)(qCG3@l;O#R`Oqcx8* z<}UDs;VzA8B@smeh(#Ks4I6KZQ>}@ec$kF~HT%>fjcKe8<%&yTJYinc^%}p;yrwvu zVShX%Xo<@oqhvN~!luE8hpzT!tzcFW$Om~WGN25PLlVg2wX{p$tFaW!B>SwZe1g__ zqOH?zHuoegYwq3vp~HMK%Atr&v$>}r7brXxNgz*C5Jn%_VO$@dO?@;kp*RxnZNieL z8$zC;ggny_lDU^7-6-N`DeBL*sCTfn&(Y$}QoaS{ZEfvyQ2;?d4@n@;S13l%>^3fF z?%i$Cb$Nkl{z7g3BGX*A`Ln*4@0q>;XAe+@4P{8U1X5=&yMlDZGa z*SC?F`;@TFCweOh`+--G`ogwuE)s3bMHR!i^&Kc7W5X$cw3v{WDwCR}yJ_%Ip$U1J zRv5_iK}h?=MR_?|LjJEn638nROxM1Hfp95K7$s~plUo(ot1K{TY?H9)AYZM;%`_P} zv`eo+IW%@DTE_$}uSGWSeI1fOUav5WzOqxJuVyzI4O+BwG$C&=?cS*EZZqxF=+*1g ziQuyEo3!SeZA~3^jfzDg-lD~wiFhl@?XYWTEN?>r$ap)FK;EHH3>oY;KI|G_xW3ag zdzUtQw`tb=!ZnlxiFl7ze6Ovj0ky$H-?_d|^E+ezev|`y2GpjNd;mE>`-4aV`H(g@ zXtSd@+T5sU7yNZA!rlj(eAvMLh{FD;fvp=J_YF>?6hEfWK5n5Y1M+4-Q+%J${LT#c zB+4xVOe^^ma=?I3BMIa)+T1XJ9mN@NA2PuD#eKFJ@>$c(=d_#8n{G1y639ljd_e(! z(E{$^Q@*6dow@U6lw0L)eA9V53c#eVAPMBF3dJyq-Nu>3y`OXxdo_siH3RbN3i2BU zq;4IZRr84W(D!^(;e5-&VE}4ZrMUfsn@Pg`)>!|U!J&cp;U2ud3!ReRo5bRhvx`>S zt<)x594m+!EA>iP!9_r+TUkh^k28Wv-7JcrvvCW(F8P|HLt{?DoF?MRS-vo?rxdXZ z2K$yPB_1}%%P)8yjXUkm@O*F5!6Ak=@4~*VWH!rj)8Nga_xO%h7|2|-|M(!^1x)C` z_mBkgeeIxYe|7+oQi#^${6M?;q3x!F$N7;KH}k>3p~v|#%AwEA9_J^>1|@eO3FM~= z!)P-*HQH=E4o{()CHsy7m!BD6KUZMCFu?Tq>RuW)l6$8%|D|o-_ArM0N=rLa`)ibg zTDr;l9%uOtazX5Gkp%KP1!0I~mvLe*M!Wr`u=0D;>mRh&Kbl@M`?H6LeJ}vD0oeE| zf70ImY<o%)v8j?7M!JLR*m|){x~v=V6LwRp?lPdwv**-PNiGHBnu1ESa~6Bui(FPm;0%83G_ja5#b$G&-C7%+ z=1Tgov)DIi&udz%jZ-o^d5$uwX1d~*if}amokW``VWs=F!8liRyCPTlL6_+-JW?M) zigh@xdkJSi1CP9rFw3%h!r~DTdTBYCE*Ez9Z!eT+CC= z$K(rF4NPTuUXJfBF(E6O9VvKJrqqPjXT*fjsNvk-EK5}PS~dKs;rK~tg@MeS7%xEY zzeqV{DM-gSUWO!)<;sVy|3W@MYiOsehhL%GSZTSzDTx`xRHjv$+pJ8cIUW0Il*3x$ z@0`AEvIZ&GdmxfP4#MAXj}E(tySPW9{=LIS$iW8ZLloyj4bGW+4}OiJI!v)V++xW& zS7_rXtRpnPv#{2p9Kzx;0vbl?!ZXCR4oM(KYGV_Tu$#EJy6fWFs}Yr>4Ai7TU2mXf z_60&C$r}{T(H2fbGR!ndK1TC9lYA`7>m(QDI6Q;o?Tg~t#y+B6a0W| zG=%jiVJ8^EGXG&jM1l|JlD$ezpQYvwhy<_p!;`T3W}hJgj&%qQGGICvyE!W#Zic{| za&*+(`?P!aZgacS=%_|tlCa13xeU^-UUY{UcgxMnjBz{W#Yb?hnSL$j`L8hmc(*!#7@fbQG6ON^2e0Rh9~ zBqV{Htl+xtIylfk30gOEiUK{=0zDAIY$F$r>C?1IGo1z&eaVRxEAkI_}XBiNB)T?dvMiS4~M(5Z@ywt6Q#JWn6)N{3J zXHw5YIY{M!ye3jZI5L1LAo+YGfn1>Q49P?$PBIT;-P39;TMTv=Dt229c6u!Ap2j2+ z6m1JmIm<&i9-)&7v~3&SCL zUsQrX_q972L_0`%JCZ;y(VmQyNd}~BXP-k_eyJ(X90{TZxWOA1sD9eMKJnPRSuR7> zMq1R=+)p7i>*c1w7l(9Q&UOQOE5sgqkSkCTi0?oWNLs;~%Ov*L3@DKlLl~uXe{FxI zZGS?mv_eVsV-BW*O5sOmVKHLu?r@^|r6G}5p%RGP$KK=tXab~G z*9HQ)#*}An21)fhAmA@>DH2bk!@D`S6ElnJlI;B|aA!Pl&uOaI-zikWGn^4Tl+>LO zP7b(OK&9KlO^BFL>avoZ=ZAeXX@?$LZ|i?X6xCLxczMXLQLQkLIezxENEU6ttT7~k z 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 diff --git a/doc/html/_sources/tutorials/custom_types.txt b/doc/html/_sources/tutorials/custom_types.txt index 1a22ebe..7137f07 100644 --- a/doc/html/_sources/tutorials/custom_types.txt +++ b/doc/html/_sources/tutorials/custom_types.txt @@ -17,11 +17,16 @@ It is also possible to implicitly resolve custom tags, as we will show later. Constructor ----------- -D:YAML uses the *Constructor* class to process each node to hold data type -corresponding to its tag. *Constructor* stores a function for each supported -tag to process it. These functions are supplied by the user using the -*addConstructor()* method. *Constructor* is then passed to *Loader*, which -parses YAML input. +D:YAML uses the `Constructor <../api/dyaml.constructor.html>`_ class to process +each node to hold data type corresponding to its tag. *Constructor* stores a +function for each supported tag to process it. These functions are supplied by +the user using the *addConstructor()* method. *Constructor* is then passed to +*Loader*, which parses YAML input. + +Struct types have no specific requirements for YAML support. Class types should +define the *opEquals()* operator, as this is used in equality comparisons of +nodes. Default class *opEquals()* compares references, which means two identical +objects might be considered unequal. We will implement support for an RGB color type. It is implemented as the following struct: @@ -111,8 +116,8 @@ RRGGBB, or from a mapping, where we use the following format: return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b); } -Next, we need some YAML data using our new tag. Create a file called input.yaml -with the following contents: +Next, we need some YAML data using our new tag. Create a file called +``input.yaml`` with the following contents: .. code-block:: yaml @@ -167,7 +172,7 @@ Finally, the code to put it all together: } First, we create a *Constructor* and pass functions to handle the ``!color`` -and ``!color-mapping`` tag. We construct a *Loader*m and pass the *Constructor* +and ``!color-mapping`` tag. We construct a *Loader* and pass the *Constructor* to it. We then load the YAML document, and finally, read the colors using *get()* method to test if they were loaded as expected. @@ -181,12 +186,13 @@ Resolver Specifying tag for every color value can be tedious. D:YAML can implicitly resolve scalar tags using regular expressions. This is how default types such as -int are resolved. We will use the *Resolver* class to add implicit tag -resolution for the Color data type (in its scalar form). +int are resolved. We will use the `Resolver <../api/dyaml.resolver.html>`_ class +to add implicit tag resolution for the Color data type (in its scalar form). -We use the *addImplicitResolver* method of *Resolver*, passing the tag, regular -expression the value must match to resolve to this tag, and a string of possible -starting characters of the value. Then we pass the *Resolver* to *Loader*. +We use the *addImplicitResolver()* method of *Resolver*, passing the tag, +regular expression the scalar must match to resolve to this tag, and a string of +possible starting characters of the scalar. Then we pass the *Resolver* to +*Loader*. Note that resolvers added first override ones added later. If no resolver matches a scalar, YAML string tag is used. Therefore our custom values must not @@ -199,8 +205,8 @@ Add this to your code to add implicit resolution of ``!color``. //code from the previous example... auto resolver = new Resolver; - resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}", - "0123456789abcdefABCDEF")); + resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"), + "0123456789abcdefABCDEF"); auto loader = Loader("input.yaml"); @@ -209,7 +215,7 @@ Add this to your code to add implicit resolution of ``!color``. //code from the previous example... -Now, change contents of input.yaml to this: +Now, change contents of ``input.yaml`` to this: .. code-block:: yaml @@ -227,3 +233,107 @@ the example. If everything went as expected, it should report success. You can find the complete code in the ``examples/resolver`` directory in the D:YAML package. + + +----------- +Representer +----------- + +Now that you know how to load custom data types, it might also be useful to know +how to dump them. D:YAML uses the `Representer <../api/dyaml.representer.html>`_ +class for this purpose. + +*Representer* processes YAML nodes into plain mapping, sequence or scalar nodes +ready for output. Just like with *Constructor*, this is done by user specified +functions. These functions take references to a node to process and to the +*Representer*, and return the processed node. + +Representer functions can be added with the *addRepresenter()* method. The +*Representer* is then passed to *Dumper*, which dumps YAML documents. Only one +representer can be added for a type. This is asserted in *addRepresenter()* +preconditions. By default, the default YAML types already have representer +functions, but you can disable them by constructing *Representer* with the +*useDefaultRepresenters* parameter set to false. + +By default, tags are explicitly specified for all non-default types. If you +want the tags to be implicit, you can pass a *Resolver* that will resolve them +implicitly. Of course, you will then need to use an identical *Resolver* when +loading the output. + +With the following code, we will add support for dumping the our Color type. + +.. code-block:: d + + Node representColor(ref Node node, Representer representer) + { + //The node is guaranteed to be Color as we add representer for Color. + Color color = node.get!Color; + + static immutable hex = "0123456789ABCDEF"; + + //Using the color format from the Constructor example. + string scalar; + foreach(channel; [color.red, color.green, color.blue]) + { + scalar ~= hex[channel / 16]; + scalar ~= hex[channel % 16]; + } + + //Representing as a scalar, with custom tag to specify this data type. + return representer.representScalar("!color", scalar); + } + +First we get the *Color* from the node. Then we convert it to a string with the +HTML-like format we've used before. Finally, we use the *representScalar()* +method of *Representer* to get a scalar node ready for output. +There are corresponding *representMapping()* and *representSequence()* methods +as well, with examples in the +`Resolver API documentation <../api/dyaml.resolver.html>`_. + +Since a type can only have one representer function, we don't dump *Color* both +in the scalar and mapping formats we've used before. However, you can decide to +dump the node with different formats/tags in the representer function itself. +E.g. you could dump the Color as a mapping based on some arbitrary condition, +such as the color being white. + +.. code-block:: d + + void main() + { + try + { + auto representer = new Representer; + representer.addRepresenter!Color(&representColor); + + auto resolver = new Resolver; + resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"), + "0123456789abcdefABCDEF"); + + auto dumper = Dumper("output.yaml"); + dumper.representer = representer; + dumper.resolver = resolver; + + auto document = Node([Color(255, 0, 0), + Color(0, 255, 0), + Color(0, 0, 255)]); + + dumper.dump(document); + } + catch(YAMLException e) + { + writeln(e.msg); + } + } + +We construct a new *Representer*, and specify a representer function for the +*Color* (the template argument) type. We also construct a *Resolver*, same as in +the previous section, so the ``!color`` tag will be implicit. Of course, +identical *Resolver* would then have to be used when loading the file. +You don't need to do this if you want the tag to be explicit. + +We construct a *Dumper* to file ``output.yaml`` and pass the *Representer* and +*Resolver* to it. Then, we create a simple node containing a sequence of colors +and finally, we dump it. + +Source code for this section can be found in the ``examples/representer`` +directory of the D:YAML package. diff --git a/doc/html/_sources/tutorials/getting_started.txt b/doc/html/_sources/tutorials/getting_started.txt index 73bd3b0..8e4c7cd 100644 --- a/doc/html/_sources/tutorials/getting_started.txt +++ b/doc/html/_sources/tutorials/getting_started.txt @@ -72,7 +72,7 @@ Create a directory for your project and in that directory, create a file called This will serve as input for our example. -Now we need to parse it. Create a file called "main.d". Paste following code +Now we need to parse it. Create a file called ``main.d``. Paste following code into the file: .. code-block:: d @@ -82,12 +82,18 @@ into the file: void main() { + //Read the input. Node root = Loader("input.yaml").load(); + + //Display the data read. foreach(string word; root["Hello World"]) { writeln(word); } writeln("The answer is ", root["Answer"].get!int); + + //Dump the loaded document to output.yaml. + Dumper("output.yaml").dump(root); } @@ -98,8 +104,8 @@ Explanation of the code First, we import the *yaml* module. This is the only module you need to import to use D:YAML - it automatically imports all needed modules. -Next we load the file using the *Loader.load()* method. *Loader* is the struct -used for parsing YAML documents, and *load()* is a method that loads the file as +Next we load the file using the *Loader.load()* method. *Loader* is a struct +used for parsing YAML documents. The *load()* method loads the file as **one** YAML document, or throws *YAMLException*, D:YAML exception type, if the file could not be parsed or does not contain exactly one document. Note that we don't do any error checking here in order to keep the example as simple as @@ -126,6 +132,15 @@ The *Node.get()* method is used to get value of a scalar node, allowing to specify type. D:YAML will try to return the scalar as this type, converting if needed, throwing *YAMLException* if not possible. +Finally we dump the document we just read to ``output.yaml`` with the +*Dumper.dump()* method. *Dumper* is a struct used to dump YAML documents. +The *dump()* method writes one or more documents to a file, throwing +*YAMLException* if the file could not be written to. + +D:YAML doesn't preserve style information in documents, so even though +``output.yaml`` will contain the same data as ``input.yaml``, it might be +formatted differently. Comments are not preserved, either. + ^^^^^^^^^ Compiling diff --git a/doc/html/api/dyaml.representer.html b/doc/html/api/dyaml.representer.html index 593dcd0..ec00226 100644 --- a/doc/html/api/dyaml.representer.html +++ b/doc/html/api/dyaml.representer.html @@ -39,7 +39,8 @@

dyaml.representer

-

YAML node representer. +

YAML node representer. Prepares YAML nodes for output. A tutorial can be + found here.

Code based on PyYAML.

diff --git a/doc/html/articles/spec_differences.html b/doc/html/articles/spec_differences.html index d8947b6..cff7ce6 100644 --- a/doc/html/articles/spec_differences.html +++ b/doc/html/articles/spec_differences.html @@ -138,7 +138,7 @@ struct appears in Phobos.

diff --git a/doc/html/index.html b/doc/html/index.html index 1d94b8c..5ab4bc5 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -55,6 +55,7 @@
  • Custom YAML data types
  • YAML syntax
      @@ -103,7 +104,7 @@ diff --git a/doc/html/search.html b/doc/html/search.html index f28945f..06a731d 100644 --- a/doc/html/search.html +++ b/doc/html/search.html @@ -87,7 +87,7 @@ diff --git a/doc/html/searchindex.js b/doc/html/searchindex.js index 3d6710f..5059339 100644 --- a/doc/html/searchindex.js +++ b/doc/html/searchindex.js @@ -1 +1 @@ -Search.setIndex({objects:{},terms:{all:[1,3,4],code:[0,1,3,4],scalar:[0,1,2,3,4],follow:[3,4],depend:[0,3],show:[0,3],readabl:0,specif:[0,1,2],articl:[0,2],program:4,digit:[3,4],sourc:[3,4],everi:3,string:[0,3,4],powervr:0,"void":[3,4],phobo:1,failur:3,yamlexcept:[3,4],implicitli:[0,3],tri:1,gender:0,list:[0,1,2],iter:4,"try":[3,4],item:0,slower:0,past:4,fold:0,second:[0,4],design:0,pass:3,download:4,rrr:3,even:1,index:[3,4],what:3,appear:1,defin:0,current:4,version:4,"new":3,method:[3,4],usag:4,never:1,here:4,ggg:3,ldyaml:4,path:4,modifi:4,implicit:[0,3],valu:[0,1,3,4],convert:[0,4],anchor:[0,1,2],datetim:0,omap:0,implement:[1,3],commonli:4,modul:4,unix:4,subnod:4,instal:4,regex:3,from:3,would:4,doubl:0,two:[0,1,3],next:[3,4],few:1,call:[3,4],handl:[1,3],msg:3,type:[0,1,2,3,4],tell:4,more:[0,4],phone:0,known:[1,2,4],hold:3,must:[3,4],word:4,alia:[0,1],work:1,paragraph:0,can:[0,1,3,4],learn:4,male:0,root:[3,4],overrid:3,want:3,stream:[0,1],give:4,process:3,topic:3,tag:[0,1,3,2],tab:1,serial:[0,3],multipl:[0,1],newlin:0,quot:[0,1],getting_start:4,how:[3,4],foreach:[3,4],answer:[0,4],instead:0,simpl:[0,4],map:[0,1,2,3,4],mar:4,clone:0,variant:1,ff0000:3,uint:3,mai:1,end:[0,1,3],data:[0,1,3,2],read:[0,3],stdio:4,explicit:0,correspond:3,ambigu:1,caus:1,alias:[0,1,2],"switch":3,green:[0,3],allow:[0,1,4],first:[0,2,3,4],order:[1,4],over:4,move:4,orang:3,becaus:1,veri:1,hierarchi:0,still:[0,1],style:0,yaml:[0,1,2,3,4],window:4,html:3,therefor:[1,3],might:[0,1,3,4],easier:0,them:[0,1,4],"float":[0,3],"return":[3,4],thei:[0,1,3,4],python:0,auto:3,"break":3,now:[1,3,4],introduct:[0,4],name:[0,3],separ:0,each:[0,3],found:4,went:3,complet:3,mean:1,compil:[3,4],unequ:1,idea:4,expect:[3,4],our:[3,4],extract:4,out:0,space:0,content:[1,3,4],rel:4,"0123456789abcdefabcdef":3,ref:3,red:[0,3],difficulti:1,advanc:0,base:0,dictionari:0,put:[3,4],org:[1,3],"byte":1,thrown:4,pyyaml:[0,1],indent:[0,1],could:4,keep:4,length:3,yamlcoloninflowcontext:1,confus:1,assign:0,radeon:0,oper:[0,4],onc:[0,1],arrai:[0,1,3,4],restrict:1,unlik:0,alreadi:4,done:3,stabl:4,size:0,differ:[1,2],script:4,associ:[0,1,4],addimplicitresolv:3,system:[0,4],construct:[0,3],nodeexcept:3,gpu:0,conveni:0,"final":3,store:[0,3],adher:1,consol:4,option:[0,4],especi:0,ishexdigit:3,specifi:[0,3,4],pars:[0,3,4],somewhat:0,exactli:4,than:1,std:[3,4],instanc:[1,3,4],remov:0,structur:[0,1],charact:[0,1,3],project:[2,4],str:[0,3],were:3,posit:3,clearli:1,packag:[3,4],have:[0,3,4],tabl:0,need:[0,1,3,4],"null":0,lib:4,inform:[0,4],constructcolormap:3,note:[3,4],also:[0,3,4],take:3,which:[0,1,3],brace:0,singl:[0,1],uppercas:3,blue:[0,3],begin:[0,1],normal:4,previou:3,most:[0,3,4],regular:3,pair:[0,3],"class":[1,3],don:[1,3,4],later:3,cover:4,doe:[0,1,4],bracket:0,cortex:0,fact:0,ldc:4,cdc:4,alphanumer:1,syntax:[0,2],identifi:[0,3],find:[3,4],onli:4,explicitli:0,just:4,explain:4,should:[1,3,4],meant:4,serv:4,get:[2,3,4],express:3,cannot:[1,4],report:3,whether:3,common:0,contain:[0,1,3,4],where:[0,3,4],wiki:1,set:[0,2,4],seq:0,see:[0,1,3],result:3,fail:1,close:1,athlon:0,wikipedia:0,between:[0,1,2],"import":4,altern:3,accord:1,kei:[0,1,3,4],both:3,last:0,howev:0,comment:0,etc:3,tutori:[2,3,4],context:[0,1],load:[1,3,4],color:[0,3],hyphen:0,loader:[3,4],colon:0,addconstructor:3,linux:[0,4],respect:3,rgb:3,empti:0,mark:[0,1,3],json:0,basic:4,resolut:[0,3],ani:[0,3,4],togeth:3,input:[3,4],"catch":3,"case":3,multi:0,main:[3,4],look:4,plain:[0,1],ffff00:3,cast:3,ain:0,error:[3,4],loos:1,non:[0,3],archiv:4,tediou:3,ascii:[1,3],welcom:[2,4],same:[0,1,3],member:3,binari:0,complex:[0,3],timestamp:0,android:0,document:[0,1,2,3,4],difficult:0,http:1,nest:0,user:[0,3],chang:[0,1,3],markup:0,constructorexcept:3,person:0,exampl:[3,4],command:4,thi:[0,1,3,4],everyth:3,left:0,explan:4,systim:0,newest:4,execut:4,less:1,gdc:4,human:0,yet:4,languag:[0,4],struct:[1,3,4],libdyaml:4,interptet:1,except:4,constructcolorscalar:3,add:[3,4],other:[1,4],els:0,match:3,build:4,real:0,format:[0,3],preserv:0,world:4,recurs:[0,1],tolow:3,like:3,success:3,resolv:[0,2,3],integ:[0,3,4],arthur:0,api:[2,4],either:[0,3,4],output:4,unnecessari:1,right:1,often:3,suppli:3,some:[0,1,3,4],home:4,ubyt:[0,3],librari:4,lead:1,unord:1,refer:0,run:4,acronym:0,dyaml:[1,4],unicod:1,chapter:0,about:[1,4],simplest:4,rare:1,page:0,constructor:[2,3],produc:4,block:0,subset:0,within:1,encod:1,automat:4,bbb:3,bsd:0,bool:[0,3],your:[2,3,4],wai:[1,3],support:[0,1,3],question:0,"long":0,custom:[0,2,3],writeln:[3,4],start:[0,2,3,4],"function":3,form:3,continu:0,link:4,line:0,"true":3,conclus:4,"throw":[3,4],dmd:4,consist:0,possibl:[0,1,3,4],"default":[0,3],until:0,directori:[3,4],problem:1,similar:[0,4],featur:[0,1],creat:[0,3,4],"int":[0,3,4],flow:[0,1],dure:3,parser:[0,4],repres:[0,4],"char":3,exist:4,file:[1,3,4],yamlnul:0,isdigit:3,dent:0,check:[3,4],probabl:0,hex:3,when:4,detail:[0,1],invalid:3,valid:1,rrggbb:3,futur:[0,1],test:3,you:[0,3,4],node:[0,3,4],xxx:4,sequenc:[0,2,3,4],consid:1,debian:0,reduc:0,longer:3,anywher:0,rule:1,hello:4,ignor:1,far:3,escap:0,cpu:0},objtypes:{},titles:["YAML syntax","Differences between D:YAML and the YAML specification","Welcome to D:YAML documentation!","Custom YAML data types","Getting started"],objnames:{},filenames:["tutorials/yaml_syntax","articles/spec_differences","index","tutorials/custom_types","tutorials/getting_started"]}) \ No newline at end of file +Search.setIndex({objects:{},terms:{represent:[2,3],all:[1,3,4],code:[0,1,3,4],representmap:3,scalar:[0,1,2,3,4],follow:[3,4],decid:3,depend:[0,3],show:[0,3],readabl:0,specif:[0,1,3,2],representsequ:3,program:4,digit:[3,4],sourc:[3,4],everi:3,string:[0,3,4],powervr:0,"void":[3,4],phobo:1,ident:3,failur:3,yamlexcept:[3,4],implicitli:[0,3],implement:[1,3],tri:1,gender:0,list:[0,1,2],iter:4,"try":[3,4],item:0,refer:[0,3],slower:0,past:4,fold:0,second:[0,4],design:0,pass:3,download:4,rrr:3,even:[1,4],index:[3,4],what:3,appear:1,compar:3,cast:3,preserv:[0,4],section:3,current:4,version:4,"new":3,method:[3,4],complex:[0,3],dyaml:[1,4],never:1,here:4,ggg:3,ldyaml:4,path:4,modifi:4,sinc:3,valu:[0,1,3,4],convert:[0,3,4],male:0,loos:1,datetim:0,omap:0,chang:[0,1,3],commonli:4,modul:4,unix:4,subnod:4,instal:4,articl:[0,2],regex:3,from:3,would:[3,4],doubl:0,two:[0,1,3],next:[3,4],few:1,call:[3,4],msg:3,type:[0,1,2,3,4],tell:4,more:[0,4],phone:0,known:[1,2,4],hold:3,must:[3,4],addrepresent:3,word:4,alia:[0,1],work:1,itself:3,can:[0,1,3,4],learn:4,purpos:3,root:[3,4],overrid:3,want:3,stream:[0,1],give:4,process:3,templat:3,topic:3,tag:[0,1,3,2],tab:1,serial:[0,3],cours:3,multipl:[0,1],newlin:0,quot:[0,1],getting_start:4,how:[3,4],foreach:[3,4],answer:[0,4],instead:0,simpl:[0,3,4],map:[0,1,2,3,4],mar:4,clone:0,variant:1,befor:3,ff0000:3,uint:3,mai:1,end:[0,1,3],data:[0,1,2,3,4],welcom:[2,4],ani:[0,3,4],stdio:4,explicit:[0,3],correspond:3,ambigu:1,caus:1,inform:[0,4],"switch":3,green:[0,3],allow:[0,1,4],first:[0,2,3,4],order:[1,4],over:4,move:4,orang:3,becaus:1,veri:1,hierarchi:0,still:[0,1],paramet:3,write:4,style:[0,4],precondit:3,yaml:[0,1,2,3,4],window:4,html:3,main:[3,4],might:[0,1,3,4],easier:0,them:[0,1,3,4],"float":[0,3],"return":[3,4],thei:[0,1,3,4],python:0,auto:3,"break":3,now:[1,3,4],introduct:[0,4],name:[0,3],separ:0,each:[0,3],found:[3,4],went:3,complet:3,mean:[1,3],compil:[3,4],unequ:[1,3],idea:4,"static":3,expect:[3,4],our:[3,4],extract:4,out:0,space:0,content:[1,3,4],rel:4,"0123456789abcdefabcdef":3,ref:3,red:[0,3],difficulti:1,advanc:0,"0123456789abcdef":3,base:[0,3],dictionari:0,put:[3,4],org:[1,3],"byte":1,thrown:4,pyyaml:[0,1],indent:[0,1],could:[3,4],keep:4,length:3,yamlcoloninflowcontext:1,confus:1,assign:0,radeon:0,oper:[0,3,4],onc:[0,1],arrai:[0,1,3,4],restrict:1,unlik:0,alreadi:[3,4],done:3,stabl:4,size:0,differ:[1,2,3,4],dump:[3,4],script:4,associ:[0,1,4],addimplicitresolv:3,system:[0,4],construct:[0,3],gpu:0,white:3,conveni:0,"final":[3,4],store:[0,3],adher:1,consol:4,option:[0,4],especi:0,ishexdigit:3,specifi:[0,3,4],pars:[0,3,4],somewhat:0,exactli:4,than:1,serv:4,remov:0,structur:[0,1],charact:[0,1,3],project:[2,4],str:[0,3],were:3,posit:3,argument:3,packag:[3,4],have:[0,3,4],tabl:0,need:[0,1,3,4],"null":0,lib:4,alias:[0,1,2],constructcolormap:3,note:[3,4],also:[0,3,4],read:[0,3,4],take:3,which:[0,1,3],brace:0,channel:3,uppercas:3,blue:[0,3],begin:[0,1],normal:4,previou:3,most:[0,3,4],regular:3,pair:[0,3],"class":[1,3],opequ:3,don:[1,3,4],later:3,flow:[0,1],doe:[0,1,4],bracket:0,cortex:0,fact:0,ldc:4,cdc:4,alphanumer:1,syntax:[0,2],identifi:[0,3],find:[3,4],onli:[3,4],explicitli:[0,3],just:[3,4],explain:4,should:[1,3,4],meant:4,std:[3,4],get:[2,3,4],express:3,cannot:[1,4],report:3,requir:3,whether:3,common:0,contain:[0,1,3,4],where:[0,3,4],wiki:1,set:[0,2,3,4],seq:0,see:[0,1,3],rgb:3,result:3,fail:1,close:1,athlon:0,representscalar:3,wikipedia:0,written:4,between:[0,1,2],"import":4,altern:3,accord:1,kei:[0,1,3,4],both:3,last:0,howev:[0,3],equal:3,comment:[0,4],etc:3,tutori:[2,3,4],context:[0,1],load:[1,3,4],bool:[0,3],color:[0,3],hyphen:0,loader:[3,4],colon:0,addconstructor:3,suppli:3,respect:3,bbb:3,empti:0,implicit:[0,3],json:0,basic:4,resolut:[0,3],anywher:0,assert:3,togeth:3,input:[3,4],"catch":3,"case":3,multi:0,therefor:[1,3],look:4,plain:[0,1,3],ffff00:3,defin:[0,3],ain:0,error:[3,4],anchor:[0,1,2],readi:3,non:[0,3],archiv:4,tediou:3,ascii:[1,3],dumper:[3,4],disabl:3,clearli:1,same:[0,1,3,4],check:[3,4],member:3,binari:0,instanc:[1,3,4],timestamp:0,android:0,document:[0,1,2,3,4],difficult:0,http:1,nest:0,user:[0,3],nodeexcept:3,markup:0,well:3,constructorexcept:3,person:0,exampl:[3,4],command:4,thi:[0,1,3,4],everyth:3,left:0,explan:4,systim:0,newest:4,execut:4,less:1,paragraph:0,gdc:4,human:0,yet:4,languag:[0,4],struct:[1,3,4],libdyaml:4,interptet:1,except:4,constructcolorscalar:3,add:[3,4],other:[1,4],els:0,match:3,build:4,real:0,format:[0,3,4],handl:[1,3],know:3,world:4,recurs:[0,1],tolow:3,like:3,success:3,arbitrari:3,resolv:[0,2,3],integ:[0,3,4],arthur:0,api:[2,3,4],singl:[0,1],output:[3,4],unnecessari:1,right:1,often:3,linux:[0,4],some:[0,1,3,4],guarante:3,ubyt:[0,3],librari:4,representcolor:3,lead:1,though:4,unord:1,condit:3,either:[0,3,4],object:3,run:4,acronym:0,usag:4,immut:3,unicod:1,chapter:0,comparison:3,about:[1,4],rare:1,usedefaultrepresent:3,page:0,constructor:[2,3],fals:3,produc:4,block:0,subset:0,within:1,encod:1,automat:4,bsd:0,mark:[0,1,3],your:[2,3,4],wai:[1,3],support:[0,1,3],question:0,"long":0,custom:[0,2,3],writeln:[3,4],start:[0,2,3,4],"function":3,form:3,continu:0,link:4,line:0,"true":3,conclus:4,"throw":[3,4],dmd:4,consist:0,possibl:[0,1,3,4],"default":[0,3],displai:4,until:0,directori:[3,4],problem:1,similar:[0,4],featur:[0,1],creat:[0,3,4],"int":[0,3,4],cover:4,dure:3,parser:[0,4],doesn:4,repres:[0,3,4],"char":3,exist:4,file:[1,3,4],yamlnul:0,isdigit:3,dent:0,simplest:4,probabl:0,hex:3,when:[3,4],detail:[0,1],invalid:3,valid:1,rrggbb:3,futur:[0,1],test:3,you:[0,3,4],node:[0,3,4],xxx:4,sequenc:[0,2,3,4],consid:[1,3],debian:0,reduc:0,longer:3,home:4,rule:1,hello:4,ignor:1,far:3,escap:0,cpu:0},objtypes:{},titles:["YAML syntax","Differences between D:YAML and the YAML specification","Welcome to D:YAML documentation!","Custom YAML data types","Getting started"],objnames:{},filenames:["tutorials/yaml_syntax","articles/spec_differences","index","tutorials/custom_types","tutorials/getting_started"]}) \ No newline at end of file diff --git a/doc/html/tutorials/custom_types.html b/doc/html/tutorials/custom_types.html index 64ff2b8..a8a86ea 100644 --- a/doc/html/tutorials/custom_types.html +++ b/doc/html/tutorials/custom_types.html @@ -57,11 +57,15 @@ during parsing, so you don’t need to specify tag for each float, integer, It is also possible to implicitly resolve custom tags, as we will show later.

      Constructor

      -

      D:YAML uses the Constructor class to process each node to hold data type -corresponding to its tag. Constructor stores a function for each supported -tag to process it. These functions are supplied by the user using the -addConstructor() method. Constructor is then passed to Loader, which -parses YAML input.

      +

      D:YAML uses the Constructor class to process +each node to hold data type corresponding to its tag. Constructor stores a +function for each supported tag to process it. These functions are supplied by +the user using the addConstructor() method. Constructor is then passed to +Loader, which parses YAML input.

      +

      Struct types have no specific requirements for YAML support. Class types should +define the opEquals() operator, as this is used in equality comparisons of +nodes. Default class opEquals() compares references, which means two identical +objects might be considered unequal.

      We will implement support for an RGB color type. It is implemented as the following struct:

      struct Color
      @@ -146,8 +150,8 @@ RRGGBB, or from a mapping, where we use the following format:
       }
       
      -

      Next, we need some YAML data using our new tag. Create a file called input.yaml -with the following contents:

      +

      Next, we need some YAML data using our new tag. Create a file called +input.yaml with the following contents:

      scalar-red: !color FF0000
       scalar-orange: !color FFFF00
       mapping-red: !color-mapping {r: 255, g: 0, b: 0}
      @@ -197,7 +201,7 @@ with the following contents:

      First, we create a Constructor and pass functions to handle the !color -and !color-mapping tag. We construct a Loader*m and pass the *Constructor +and !color-mapping tag. We construct a Loader and pass the Constructor to it. We then load the YAML document, and finally, read the colors using get() method to test if they were loaded as expected.

      You can find the source code for what we’ve done so far in the @@ -207,11 +211,12 @@ to it. We then load the YAML document, and finally, read the colors using

      Resolver

      Specifying tag for every color value can be tedious. D:YAML can implicitly resolve scalar tags using regular expressions. This is how default types such as -int are resolved. We will use the Resolver class to add implicit tag -resolution for the Color data type (in its scalar form).

      -

      We use the addImplicitResolver method of Resolver, passing the tag, regular -expression the value must match to resolve to this tag, and a string of possible -starting characters of the value. Then we pass the Resolver to Loader.

      +int are resolved. We will use the Resolver class +to add implicit tag resolution for the Color data type (in its scalar form).

      +

      We use the addImplicitResolver() method of Resolver, passing the tag, +regular expression the scalar must match to resolve to this tag, and a string of +possible starting characters of the scalar. Then we pass the Resolver to +Loader.

      Note that resolvers added first override ones added later. If no resolver matches a scalar, YAML string tag is used. Therefore our custom values must not be resolvable as any non-string YAML data type.

      @@ -219,8 +224,8 @@ be resolvable as any non-string YAML data type.

      //code from the previous example...
       
       auto resolver = new Resolver;
      -resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}",
      -                             "0123456789abcdefABCDEF"));
      +resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"),
      +                             "0123456789abcdefABCDEF");
       
       auto loader = Loader("input.yaml");
       
      @@ -230,7 +235,7 @@ be resolvable as any non-string YAML data type.

      //code from the previous example...
      -

      Now, change contents of input.yaml to this:

      +

      Now, change contents of input.yaml to this:

      scalar-red: FF0000
       scalar-orange: FFFF00
       mapping-red: !color-mapping {r: 255, g: 0, b: 0}
      @@ -246,6 +251,96 @@ the example. If everything went as expected, it should report success.

      You can find the complete code in the examples/resolver directory in the D:YAML package.

      +
      +

      Representer

      +

      Now that you know how to load custom data types, it might also be useful to know +how to dump them. D:YAML uses the Representer +class for this purpose.

      +

      Representer processes YAML nodes into plain mapping, sequence or scalar nodes +ready for output. Just like with Constructor, this is done by user specified +functions. These functions take references to a node to process and to the +Representer, and return the processed node.

      +

      Representer functions can be added with the addRepresenter() method. The +Representer is then passed to Dumper, which dumps YAML documents. Only one +representer can be added for a type. This is asserted in addRepresenter() +preconditions. By default, the default YAML types already have representer +functions, but you can disable them by constructing Representer with the +useDefaultRepresenters parameter set to false.

      +

      By default, tags are explicitly specified for all non-default types. If you +want the tags to be implicit, you can pass a Resolver that will resolve them +implicitly. Of course, you will then need to use an identical Resolver when +loading the output.

      +

      With the following code, we will add support for dumping the our Color type.

      +
      Node representColor(ref Node node, Representer representer)
      +{
      +    //The node is guaranteed to be Color as we add representer for Color.
      +    Color color = node.get!Color;
      +
      +    static immutable hex = "0123456789ABCDEF";
      +
      +    //Using the color format from the Constructor example.
      +    string scalar;
      +    foreach(channel; [color.red, color.green, color.blue])
      +    {
      +        scalar ~= hex[channel / 16];
      +        scalar ~= hex[channel % 16];
      +    }
      +
      +    //Representing as a scalar, with custom tag to specify this data type.
      +    return representer.representScalar("!color", scalar);
      +}
      +
      +
      +

      First we get the Color from the node. Then we convert it to a string with the +HTML-like format we’ve used before. Finally, we use the representScalar() +method of Representer to get a scalar node ready for output. +There are corresponding representMapping() and representSequence() methods +as well, with examples in the +Resolver API documentation.

      +

      Since a type can only have one representer function, we don’t dump Color both +in the scalar and mapping formats we’ve used before. However, you can decide to +dump the node with different formats/tags in the representer function itself. +E.g. you could dump the Color as a mapping based on some arbitrary condition, +such as the color being white.

      +
      void main()
      +{
      +    try
      +    {
      +        auto representer = new Representer;
      +        representer.addRepresenter!Color(&representColor);
      +
      +        auto resolver = new Resolver;
      +        resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"),
      +                                     "0123456789abcdefABCDEF");
      +
      +        auto dumper = Dumper("output.yaml");
      +        dumper.representer = representer;
      +        dumper.resolver    = resolver;
      +
      +        auto document = Node([Color(255, 0, 0),
      +                              Color(0, 255, 0),
      +                              Color(0, 0, 255)]);
      +
      +        dumper.dump(document);
      +    }
      +    catch(YAMLException e)
      +    {
      +        writeln(e.msg);
      +    }
      +}
      +
      +
      +

      We construct a new Representer, and specify a representer function for the +Color (the template argument) type. We also construct a Resolver, same as in +the previous section, so the !color tag will be implicit. Of course, +identical Resolver would then have to be used when loading the file. +You don’t need to do this if you want the tag to be explicit.

      +

      We construct a Dumper to file output.yaml and pass the Representer and +Resolver to it. Then, we create a simple node containing a sequence of colors +and finally, we dump it.

      +

      Source code for this section can be found in the examples/representer +directory of the D:YAML package.

      +
      @@ -262,6 +357,7 @@ D:YAML package.

    • Custom YAML data types
    @@ -284,7 +380,7 @@ D:YAML package.

    diff --git a/doc/html/tutorials/getting_started.html b/doc/html/tutorials/getting_started.html index 5b8b649..ea39080 100644 --- a/doc/html/tutorials/getting_started.html +++ b/doc/html/tutorials/getting_started.html @@ -101,19 +101,25 @@ To do this on Unix/Linux, use the following command:

    This will serve as input for our example.

    -

    Now we need to parse it. Create a file called “main.d”. Paste following code +

    Now we need to parse it. Create a file called main.d. Paste following code into the file:

    import std.stdio;
     import yaml;
     
     void main()
     {
    +    //Read the input.
         Node root = Loader("input.yaml").load();
    +
    +    //Display the data read.
         foreach(string word; root["Hello World"])
         {
             writeln(word);
         }
         writeln("The answer is ", root["Answer"].get!int);
    +
    +    //Dump the loaded document to output.yaml.
    +    Dumper("output.yaml").dump(root);
     }
     
    @@ -121,8 +127,8 @@ into the file:

    Explanation of the code

    First, we import the yaml module. This is the only module you need to import to use D:YAML - it automatically imports all needed modules.

    -

    Next we load the file using the Loader.load() method. Loader is the struct -used for parsing YAML documents, and load() is a method that loads the file as +

    Next we load the file using the Loader.load() method. Loader is a struct +used for parsing YAML documents. The load() method loads the file as one YAML document, or throws YAMLException, D:YAML exception type, if the file could not be parsed or does not contain exactly one document. Note that we don’t do any error checking here in order to keep the example as simple as @@ -144,6 +150,13 @@ cannot be converted to an integer.

    The Node.get() method is used to get value of a scalar node, allowing to specify type. D:YAML will try to return the scalar as this type, converting if needed, throwing YAMLException if not possible.

    +

    Finally we dump the document we just read to output.yaml with the +Dumper.dump() method. Dumper is a struct used to dump YAML documents. +The dump() method writes one or more documents to a file, throwing +YAMLException if the file could not be written to.

    +

    D:YAML doesn’t preserve style information in documents, so even though +output.yaml will contain the same data as input.yaml, it might be +formatted differently. Comments are not preserved, either.

    Compiling

    @@ -224,7 +237,7 @@ example in the example/getting_st
    diff --git a/doc/html/tutorials/yaml_syntax.html b/doc/html/tutorials/yaml_syntax.html index 98bc68f..71a9377 100644 --- a/doc/html/tutorials/yaml_syntax.html +++ b/doc/html/tutorials/yaml_syntax.html @@ -330,7 +330,7 @@ Some of these might change in the future (especially !!map and !!set).

    diff --git a/docsrc/tutorials/custom_types.rst b/docsrc/tutorials/custom_types.rst index 1a22ebe..7137f07 100644 --- a/docsrc/tutorials/custom_types.rst +++ b/docsrc/tutorials/custom_types.rst @@ -17,11 +17,16 @@ It is also possible to implicitly resolve custom tags, as we will show later. Constructor ----------- -D:YAML uses the *Constructor* class to process each node to hold data type -corresponding to its tag. *Constructor* stores a function for each supported -tag to process it. These functions are supplied by the user using the -*addConstructor()* method. *Constructor* is then passed to *Loader*, which -parses YAML input. +D:YAML uses the `Constructor <../api/dyaml.constructor.html>`_ class to process +each node to hold data type corresponding to its tag. *Constructor* stores a +function for each supported tag to process it. These functions are supplied by +the user using the *addConstructor()* method. *Constructor* is then passed to +*Loader*, which parses YAML input. + +Struct types have no specific requirements for YAML support. Class types should +define the *opEquals()* operator, as this is used in equality comparisons of +nodes. Default class *opEquals()* compares references, which means two identical +objects might be considered unequal. We will implement support for an RGB color type. It is implemented as the following struct: @@ -111,8 +116,8 @@ RRGGBB, or from a mapping, where we use the following format: return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b); } -Next, we need some YAML data using our new tag. Create a file called input.yaml -with the following contents: +Next, we need some YAML data using our new tag. Create a file called +``input.yaml`` with the following contents: .. code-block:: yaml @@ -167,7 +172,7 @@ Finally, the code to put it all together: } First, we create a *Constructor* and pass functions to handle the ``!color`` -and ``!color-mapping`` tag. We construct a *Loader*m and pass the *Constructor* +and ``!color-mapping`` tag. We construct a *Loader* and pass the *Constructor* to it. We then load the YAML document, and finally, read the colors using *get()* method to test if they were loaded as expected. @@ -181,12 +186,13 @@ Resolver Specifying tag for every color value can be tedious. D:YAML can implicitly resolve scalar tags using regular expressions. This is how default types such as -int are resolved. We will use the *Resolver* class to add implicit tag -resolution for the Color data type (in its scalar form). +int are resolved. We will use the `Resolver <../api/dyaml.resolver.html>`_ class +to add implicit tag resolution for the Color data type (in its scalar form). -We use the *addImplicitResolver* method of *Resolver*, passing the tag, regular -expression the value must match to resolve to this tag, and a string of possible -starting characters of the value. Then we pass the *Resolver* to *Loader*. +We use the *addImplicitResolver()* method of *Resolver*, passing the tag, +regular expression the scalar must match to resolve to this tag, and a string of +possible starting characters of the scalar. Then we pass the *Resolver* to +*Loader*. Note that resolvers added first override ones added later. If no resolver matches a scalar, YAML string tag is used. Therefore our custom values must not @@ -199,8 +205,8 @@ Add this to your code to add implicit resolution of ``!color``. //code from the previous example... auto resolver = new Resolver; - resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}", - "0123456789abcdefABCDEF")); + resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"), + "0123456789abcdefABCDEF"); auto loader = Loader("input.yaml"); @@ -209,7 +215,7 @@ Add this to your code to add implicit resolution of ``!color``. //code from the previous example... -Now, change contents of input.yaml to this: +Now, change contents of ``input.yaml`` to this: .. code-block:: yaml @@ -227,3 +233,107 @@ the example. If everything went as expected, it should report success. You can find the complete code in the ``examples/resolver`` directory in the D:YAML package. + + +----------- +Representer +----------- + +Now that you know how to load custom data types, it might also be useful to know +how to dump them. D:YAML uses the `Representer <../api/dyaml.representer.html>`_ +class for this purpose. + +*Representer* processes YAML nodes into plain mapping, sequence or scalar nodes +ready for output. Just like with *Constructor*, this is done by user specified +functions. These functions take references to a node to process and to the +*Representer*, and return the processed node. + +Representer functions can be added with the *addRepresenter()* method. The +*Representer* is then passed to *Dumper*, which dumps YAML documents. Only one +representer can be added for a type. This is asserted in *addRepresenter()* +preconditions. By default, the default YAML types already have representer +functions, but you can disable them by constructing *Representer* with the +*useDefaultRepresenters* parameter set to false. + +By default, tags are explicitly specified for all non-default types. If you +want the tags to be implicit, you can pass a *Resolver* that will resolve them +implicitly. Of course, you will then need to use an identical *Resolver* when +loading the output. + +With the following code, we will add support for dumping the our Color type. + +.. code-block:: d + + Node representColor(ref Node node, Representer representer) + { + //The node is guaranteed to be Color as we add representer for Color. + Color color = node.get!Color; + + static immutable hex = "0123456789ABCDEF"; + + //Using the color format from the Constructor example. + string scalar; + foreach(channel; [color.red, color.green, color.blue]) + { + scalar ~= hex[channel / 16]; + scalar ~= hex[channel % 16]; + } + + //Representing as a scalar, with custom tag to specify this data type. + return representer.representScalar("!color", scalar); + } + +First we get the *Color* from the node. Then we convert it to a string with the +HTML-like format we've used before. Finally, we use the *representScalar()* +method of *Representer* to get a scalar node ready for output. +There are corresponding *representMapping()* and *representSequence()* methods +as well, with examples in the +`Resolver API documentation <../api/dyaml.resolver.html>`_. + +Since a type can only have one representer function, we don't dump *Color* both +in the scalar and mapping formats we've used before. However, you can decide to +dump the node with different formats/tags in the representer function itself. +E.g. you could dump the Color as a mapping based on some arbitrary condition, +such as the color being white. + +.. code-block:: d + + void main() + { + try + { + auto representer = new Representer; + representer.addRepresenter!Color(&representColor); + + auto resolver = new Resolver; + resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"), + "0123456789abcdefABCDEF"); + + auto dumper = Dumper("output.yaml"); + dumper.representer = representer; + dumper.resolver = resolver; + + auto document = Node([Color(255, 0, 0), + Color(0, 255, 0), + Color(0, 0, 255)]); + + dumper.dump(document); + } + catch(YAMLException e) + { + writeln(e.msg); + } + } + +We construct a new *Representer*, and specify a representer function for the +*Color* (the template argument) type. We also construct a *Resolver*, same as in +the previous section, so the ``!color`` tag will be implicit. Of course, +identical *Resolver* would then have to be used when loading the file. +You don't need to do this if you want the tag to be explicit. + +We construct a *Dumper* to file ``output.yaml`` and pass the *Representer* and +*Resolver* to it. Then, we create a simple node containing a sequence of colors +and finally, we dump it. + +Source code for this section can be found in the ``examples/representer`` +directory of the D:YAML package. diff --git a/docsrc/tutorials/getting_started.rst b/docsrc/tutorials/getting_started.rst index 73bd3b0..8e4c7cd 100644 --- a/docsrc/tutorials/getting_started.rst +++ b/docsrc/tutorials/getting_started.rst @@ -72,7 +72,7 @@ Create a directory for your project and in that directory, create a file called This will serve as input for our example. -Now we need to parse it. Create a file called "main.d". Paste following code +Now we need to parse it. Create a file called ``main.d``. Paste following code into the file: .. code-block:: d @@ -82,12 +82,18 @@ into the file: void main() { + //Read the input. Node root = Loader("input.yaml").load(); + + //Display the data read. foreach(string word; root["Hello World"]) { writeln(word); } writeln("The answer is ", root["Answer"].get!int); + + //Dump the loaded document to output.yaml. + Dumper("output.yaml").dump(root); } @@ -98,8 +104,8 @@ Explanation of the code First, we import the *yaml* module. This is the only module you need to import to use D:YAML - it automatically imports all needed modules. -Next we load the file using the *Loader.load()* method. *Loader* is the struct -used for parsing YAML documents, and *load()* is a method that loads the file as +Next we load the file using the *Loader.load()* method. *Loader* is a struct +used for parsing YAML documents. The *load()* method loads the file as **one** YAML document, or throws *YAMLException*, D:YAML exception type, if the file could not be parsed or does not contain exactly one document. Note that we don't do any error checking here in order to keep the example as simple as @@ -126,6 +132,15 @@ The *Node.get()* method is used to get value of a scalar node, allowing to specify type. D:YAML will try to return the scalar as this type, converting if needed, throwing *YAMLException* if not possible. +Finally we dump the document we just read to ``output.yaml`` with the +*Dumper.dump()* method. *Dumper* is a struct used to dump YAML documents. +The *dump()* method writes one or more documents to a file, throwing +*YAMLException* if the file could not be written to. + +D:YAML doesn't preserve style information in documents, so even though +``output.yaml`` will contain the same data as ``input.yaml``, it might be +formatted differently. Comments are not preserved, either. + ^^^^^^^^^ Compiling diff --git a/dyaml/dumper.d b/dyaml/dumper.d index bfd59e1..f0e9109 100644 --- a/dyaml/dumper.d +++ b/dyaml/dumper.d @@ -152,7 +152,7 @@ struct Dumper */ this(string filename) { - try{this(new File(filename));} + try{this(new File(filename, FileMode.OutNew));} catch(StreamException e) { throw new YAMLException("Unable to use file for YAML dumping " ~ filename ~ " : " ~ e.msg); diff --git a/dyaml/representer.d b/dyaml/representer.d index 0defeb4..f6a3f71 100644 --- a/dyaml/representer.d +++ b/dyaml/representer.d @@ -5,7 +5,8 @@ // http://www.boost.org/LICENSE_1_0.txt) /** - * YAML node _representer. + * YAML node _representer. Prepares YAML nodes for output. A tutorial can be + * found $(LINK2 ../tutorials/custom_types.html, here). * * Code based on $(LINK2 http://www.pyyaml.org, PyYAML). */ diff --git a/examples/getting_started/main.d b/examples/getting_started/main.d index eb0567b..26cd944 100644 --- a/examples/getting_started/main.d +++ b/examples/getting_started/main.d @@ -3,10 +3,16 @@ import yaml; void main() { - yaml.Node root = Loader("input.yaml").load(); + //Read the input. + Node root = Loader("input.yaml").load(); + + //Display the data read. foreach(string word; root["Hello World"]) { writeln(word); } writeln("The answer is ", root["Answer"].get!int); + + //Dump the loaded document to output.yaml. + Dumper("output.yaml").dump(root); } diff --git a/examples/representer/Makefile b/examples/representer/Makefile new file mode 100644 index 0000000..55dfe3d --- /dev/null +++ b/examples/representer/Makefile @@ -0,0 +1,2 @@ +main: + dmd -w -I../../ -L-L../../ -L-ldyaml main.d diff --git a/examples/representer/main.d b/examples/representer/main.d new file mode 100644 index 0000000..7c30007 --- /dev/null +++ b/examples/representer/main.d @@ -0,0 +1,55 @@ +import std.stdio; +import yaml; + +struct Color +{ + ubyte red; + ubyte green; + ubyte blue; +} + +Node representColor(ref Node node, Representer representer) +{ + //The node is guaranteed to be Color as we add representer for Color. + Color color = node.get!Color; + + static immutable hex = "0123456789ABCDEF"; + + //Using the color format from the Constructor example. + string scalar; + foreach(channel; [color.red, color.green, color.blue]) + { + scalar ~= hex[channel / 16]; + scalar ~= hex[channel % 16]; + } + + //Representing as a scalar, with custom tag to specify this data type. + return representer.representScalar("!color", scalar); +} + +void main() +{ + try + { + auto representer = new Representer; + representer.addRepresenter!Color(&representColor); + + auto resolver = new Resolver; + resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"), + "0123456789abcdefABCDEF"); + + auto dumper = Dumper("output.yaml"); + dumper.representer = representer; + dumper.resolver = resolver; + + auto document = Node([Color(255, 0, 0), + Color(0, 255, 0), + Color(0, 0, 255)]); + + dumper.dump(document); + } + catch(YAMLException e) + { + writeln(e.msg); + } +}