From 548480b06b668a860a8818390ee2c3d3c3c291d3 Mon Sep 17 00:00:00 2001 From: Ferdinand Majerech Date: Mon, 17 Oct 2011 12:53:38 +0200 Subject: [PATCH] Changed the Constructor API (for loading of custom types) to make it easier to load custom classes/structs. Updated API docs, tutorials and examples accordingly. --- doc/doctrees/environment.pickle | Bin 12705 -> 12705 bytes doc/doctrees/tutorials/custom_types.doctree | Bin 46858 -> 47409 bytes doc/html/_sources/tutorials/custom_types.txt | 61 +++-- doc/html/api/dyaml.constructor.html | 79 +++--- doc/html/articles/spec_differences.html | 2 +- doc/html/index.html | 2 +- doc/html/search.html | 2 +- doc/html/searchindex.js | 2 +- doc/html/tutorials/custom_types.html | 63 +++-- doc/html/tutorials/getting_started.html | 2 +- doc/html/tutorials/yaml_syntax.html | 2 +- docsrc/tutorials/custom_types.rst | 61 +++-- dyaml/constructor.d | 245 +++++++++---------- dyaml/node.d | 3 +- examples/constructor/main.d | 103 ++++---- examples/resolver/main.d | 103 ++++---- test/data/construct-custom.data | 2 - test/src/constructor.d | 31 +-- test/src/representer.d | 4 +- 19 files changed, 371 insertions(+), 396 deletions(-) diff --git a/doc/doctrees/environment.pickle b/doc/doctrees/environment.pickle index b0bf0109b44443d19c3c0f979e740ee2f2eae1b0..a65f29ac86f28b20fbb4959739081a1f807368f1 100644 GIT binary patch delta 63 zcmZ3OyfAq~tG>~4CMBbJQ!|v^9WMi!S}i>pIuNG*$?qAa5T@?hTN!o`rgog^=I#2g F7y%wX80Y{1 delta 63 zcmZ3OyfAq~tG>~)oZr1x*D{pd9WMi!E!UYcbRf(wuXP!w5N3zW>-=I#2g F7y;=#AH@Iw diff --git a/doc/doctrees/tutorials/custom_types.doctree b/doc/doctrees/tutorials/custom_types.doctree index 5f0a4562a8d58a78eec846a8539c3bae406e5241..46a4fd0d1e78349547482f92e4382279b8e7a92d 100644 GIT binary patch delta 7788 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 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. +the user using the *addConstructorXXX()* methods, where *XXX* is *Scalar*, +*Sequence* or *Mapping*. *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 @@ -41,17 +42,20 @@ following struct: } First, we need a function to construct our data type. It must take two *Mark* -structs, which store position of the node in the file, and either a *string*, an -array of *Node* or of *Node.Pair*, depending on whether we're constructing our -value from a scalar, sequence, or mapping, respectively. In this tutorial, we -have functions to construct a color from a scalar, using HTML-like format, -RRGGBB, or from a mapping, where we use the following format: -{r:RRR, g:GGG, b:BBB} . Code of these functions: +structs, which store position of the node in the file, and a reference to *Node* +to construct from. The node is guaranteed to contain either a *string*, an array +of *Node* or of *Node.Pair*, depending on whether we're constructing our value +from a scalar, sequence, or mapping, respectively. In this tutorial, we have +functions to construct a color from a scalar, using CSS-like format, RRGGBB, or +from a mapping, where we use the following format: {r:RRR, g:GGG, b:BBB} . Code +of these functions: .. code-block:: d - Color constructColorScalar(Mark start, Mark end, string value) + Color constructColorScalar(Mark start, Mark end, ref Node node) { + string value = node.get!string; + if(value.length != 6) { throw new ConstructorException("Invalid color: " ~ value, start, end); @@ -82,30 +86,21 @@ RRGGBB, or from a mapping, where we use the following format: return result; } - Color constructColorMapping(Mark start, Mark end, Node.Pair[] pairs) + Color constructColorMapping(Mark start, Mark end, ref Node node) { - int r, g, b; - r = g = b = -1; - bool error = pairs.length != 3; + int r,g,b; + bool error = false; - foreach(ref pair; pairs) + //Might throw if a value is missing or is not an integer. + try { - //Key might not be a string, and value might not be an int, - //so we need to check for that - try - { - switch(pair.key.get!string) - { - case "r": r = pair.value.get!int; break; - case "g": g = pair.value.get!int; break; - case "b": b = pair.value.get!int; break; - default: error = true; - } - } - catch(NodeException e) - { - error = true; - } + r = node["r"].get!int; + g = node["g"].get!int; + b = node["b"].get!int; + } + catch(NodeException e) + { + error = true; } if(error || r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) @@ -146,8 +141,8 @@ Finally, the code to put it all together: { auto constructor = new Constructor; //both functions handle the same tag, but one handles scalar, one mapping. - constructor.addConstructor("!color", &constructColorScalar); - constructor.addConstructor("!color-mapping", &constructColorMapping); + constructor.addConstructorScalar("!color", &constructColorScalar); + constructor.addConstructorMapping("!color-mapping", &constructColorMapping); auto loader = Loader("input.yaml"); loader.constructor = constructor; @@ -284,7 +279,7 @@ With the following code, we will add support for dumping the our Color type. } 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()* +CSS-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 diff --git a/doc/html/api/dyaml.constructor.html b/doc/html/api/dyaml.constructor.html index 697ca19..27b96d6 100644 --- a/doc/html/api/dyaml.constructor.html +++ b/doc/html/api/dyaml.constructor.html @@ -94,14 +94,15 @@ -
void addConstructor(T, U)(in string tag, T function(Mark, Mark, U) ctor); +
void addConstructorScalar(T)(in string tag, T function(Mark, Mark, ref Node) ctor);
-

Add a constructor function. +

Add a constructor function from scalar.

-

The function passed must two Marks (determining start and end positions of - the node in file) and either a string (if constructing from scalar), - an array of Nodes (from sequence) or an array of Node.Pair (from mapping). - The value returned by this function will be stored in the resulring node. +

The function must take two Marks (start and end positions of + the node in file) and a reference to Node to construct from. + The node contains a string for scalars, Node[] for sequences and + Node.Pair[] for mappings. + The value returned by this function will be stored in the resulting node.
Only one constructor function can be set for one tag. @@ -113,47 +114,61 @@ Constructor function. +

+
void addConstructorSequence(T)(in string tag, T function(Mark, Mark, ref Node) ctor); +
+

Add a constructor function from sequence. +

+See Also:
addConstructorScalar
+ +
+
void addConstructorMapping(T)(in string tag, T function(Mark, Mark, ref Node) ctor); +
+

Add a constructor function from a mapping. +

+See Also:
addConstructorScalar
+
-
YAMLNull constructNull(Mark start, Mark end, string value); +
YAMLNull constructNull(Mark start, Mark end, ref Node node);
-

Construct a null node.

+

Construct a null node.

-
YAMLMerge constructMerge(Mark start, Mark end, string value); +
YAMLMerge constructMerge(Mark start, Mark end, ref Node node);
-

Construct a merge node - a node that merges another node into a mapping.

+

Construct a merge node - a node that merges another node into a mapping.

-
bool constructBool(Mark start, Mark end, string value); +
bool constructBool(Mark start, Mark end, ref Node node);
-

Construct a boolean node.

+

Construct a boolean node.

-
long constructLong(Mark start, Mark end, string value); +
long constructLong(Mark start, Mark end, ref Node node);
-

Construct an integer (long) node.

+

Construct an integer (long) node.

-
real constructReal(Mark start, Mark end, string value); +
real constructReal(Mark start, Mark end, ref Node node);
-

Construct a floating point (real) node.

+

Construct a floating point (real) node.

-
ubyte[] constructBinary(Mark start, Mark end, string value); +
ubyte[] constructBinary(Mark start, Mark end, ref Node node);
-

Construct a binary (base64) node.

+

Construct a binary (base64) node.

-
SysTime constructTimestamp(Mark start, Mark end, string value); +
SysTime constructTimestamp(Mark start, Mark end, ref Node node);
-

Construct a timestamp (SysTime) node.

+

Construct a timestamp (SysTime) node.

-
string constructString(Mark start, Mark end, string value); +
string constructString(Mark start, Mark end, ref Node node);
-

Construct a string node.

+

Construct a string node.

Pair[] getPairs(string type, Mark start, Mark end, Node[] nodes); @@ -161,29 +176,29 @@

Convert a sequence of single-element mappings into a sequence of pairs.

-
Pair[] constructOrderedMap(Mark start, Mark end, Node[] nodes); +
Pair[] constructOrderedMap(Mark start, Mark end, ref Node node);
-

Construct an ordered map (ordered sequence of key:value pairs without duplicates) node.

+

Construct an ordered map (ordered sequence of key:value pairs without duplicates) node.

-
Pair[] constructPairs(Mark start, Mark end, Node[] nodes); +
Pair[] constructPairs(Mark start, Mark end, ref Node node);
-

Construct a pairs (ordered sequence of key: value pairs allowing duplicates) node.

+

Construct a pairs (ordered sequence of key: value pairs allowing duplicates) node.

-
Node[] constructSet(Mark start, Mark end, Pair[] pairs); +
Node[] constructSet(Mark start, Mark end, ref Node node);
-

Construct a set node.

+

Construct a set node.

-
Node[] constructSequence(Mark start, Mark end, Node[] nodes); +
Node[] constructSequence(Mark start, Mark end, ref Node node);
-

Construct a sequence (array) node.

+

Construct a sequence (array) node.

-
Pair[] constructMap(Mark start, Mark end, Pair[] pairs); +
Pair[] constructMap(Mark start, Mark end, ref Node node);
-

Construct an unordered map (unordered set of key: value pairs without duplicates) node.

+

Construct an unordered map (unordered set of key: value pairs without duplicates) node.

diff --git a/doc/html/articles/spec_differences.html b/doc/html/articles/spec_differences.html index e0b8e1f..dd6c7fb 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 4e17f43..b18e041 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -104,7 +104,7 @@ diff --git a/doc/html/search.html b/doc/html/search.html index af67bf2..15d9548 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 5059339..c856169 100644 --- a/doc/html/searchindex.js +++ b/doc/html/searchindex.js @@ -1 +1 @@ -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 +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],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],addconstructorxxx: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],css:3,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],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,complex:[0,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,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,miss:3,addconstructormap:3,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,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,suppli:3,respect:3,addconstructorscalar:3,bbb:3,empti:0,implicit:[0,3],json:0,basic:4,xxx:[3,4],anywher:0,assert:3,togeth:3,input:[3,4],"catch":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],resolut:[0,3],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 2c51903..f83e737 100644 --- a/doc/html/tutorials/custom_types.html +++ b/doc/html/tutorials/custom_types.html @@ -60,8 +60,9 @@ It is also possible to implicitly resolve custom tags, as we will show later.

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.

+the user using the addConstructorXXX() methods, where XXX is Scalar, +Sequence or Mapping. 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 @@ -77,14 +78,17 @@ following struct:

First, we need a function to construct our data type. It must take two Mark -structs, which store position of the node in the file, and either a string, an -array of Node or of Node.Pair, depending on whether we’re constructing our -value from a scalar, sequence, or mapping, respectively. In this tutorial, we -have functions to construct a color from a scalar, using HTML-like format, -RRGGBB, or from a mapping, where we use the following format: -{r:RRR, g:GGG, b:BBB} . Code of these functions:

-
Color constructColorScalar(Mark start, Mark end, string value)
+structs, which store position of the node in the file, and a reference to Node
+to construct from. The node is guaranteed to contain either a string, an array
+of Node or of Node.Pair, depending on whether we’re constructing our value
+from a scalar, sequence, or mapping, respectively. In this tutorial, we have
+functions to construct a color from a scalar, using CSS-like format, RRGGBB, or
+from a mapping, where we use the following format: {r:RRR, g:GGG, b:BBB} . Code
+of these functions:

+
Color constructColorScalar(Mark start, Mark end, ref Node node)
 {
+    string value = node.get!string;
+
     if(value.length != 6)
     {
         throw new ConstructorException("Invalid color: " ~ value, start, end);
@@ -115,30 +119,21 @@ RRGGBB, or from a mapping, where we use the following format:
     return result;
 }
 
-Color constructColorMapping(Mark start, Mark end, Node.Pair[] pairs)
+Color constructColorMapping(Mark start, Mark end, ref Node node)
 {
-    int r, g, b;
-    r = g = b = -1;
-    bool error = pairs.length != 3;
+    int r,g,b;
+    bool error = false;
 
-    foreach(ref pair; pairs)
+    //Might throw if a value is missing or is not an integer.
+    try
     {
-        //Key might not be a string, and value might not be an int,
-        //so we need to check for that
-        try
-        {
-            switch(pair.key.get!string)
-            {
-                case "r": r = pair.value.get!int; break;
-                case "g": g = pair.value.get!int; break;
-                case "b": b = pair.value.get!int; break;
-                default:  error = true;
-            }
-        }
-        catch(NodeException e)
-        {
-            error = true;
-        }
+        r = node["r"].get!int;
+        g = node["g"].get!int;
+        b = node["b"].get!int;
+    }
+    catch(NodeException e)
+    {
+        error = true;
     }
 
     if(error || r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255)
@@ -174,8 +169,8 @@ RRGGBB, or from a mapping, where we use the following format:
     {
         auto constructor = new Constructor;
         //both functions handle the same tag, but one handles scalar, one mapping.
-        constructor.addConstructor("!color", &constructColorScalar);
-        constructor.addConstructor("!color-mapping", &constructColorMapping);
+        constructor.addConstructorScalar("!color", &constructColorScalar);
+        constructor.addConstructorMapping("!color-mapping", &constructColorMapping);
 
         auto loader = Loader("input.yaml");
         loader.constructor = constructor;
@@ -292,7 +287,7 @@ loading the output.

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() +CSS-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 @@ -380,7 +375,7 @@ directory of the D:YAML package.

diff --git a/doc/html/tutorials/getting_started.html b/doc/html/tutorials/getting_started.html index 77c5422..530bd27 100644 --- a/doc/html/tutorials/getting_started.html +++ b/doc/html/tutorials/getting_started.html @@ -237,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 83da594..f3d0827 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 7137f07..da62c91 100644 --- a/docsrc/tutorials/custom_types.rst +++ b/docsrc/tutorials/custom_types.rst @@ -20,8 +20,9 @@ Constructor 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. +the user using the *addConstructorXXX()* methods, where *XXX* is *Scalar*, +*Sequence* or *Mapping*. *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 @@ -41,17 +42,20 @@ following struct: } First, we need a function to construct our data type. It must take two *Mark* -structs, which store position of the node in the file, and either a *string*, an -array of *Node* or of *Node.Pair*, depending on whether we're constructing our -value from a scalar, sequence, or mapping, respectively. In this tutorial, we -have functions to construct a color from a scalar, using HTML-like format, -RRGGBB, or from a mapping, where we use the following format: -{r:RRR, g:GGG, b:BBB} . Code of these functions: +structs, which store position of the node in the file, and a reference to *Node* +to construct from. The node is guaranteed to contain either a *string*, an array +of *Node* or of *Node.Pair*, depending on whether we're constructing our value +from a scalar, sequence, or mapping, respectively. In this tutorial, we have +functions to construct a color from a scalar, using CSS-like format, RRGGBB, or +from a mapping, where we use the following format: {r:RRR, g:GGG, b:BBB} . Code +of these functions: .. code-block:: d - Color constructColorScalar(Mark start, Mark end, string value) + Color constructColorScalar(Mark start, Mark end, ref Node node) { + string value = node.get!string; + if(value.length != 6) { throw new ConstructorException("Invalid color: " ~ value, start, end); @@ -82,30 +86,21 @@ RRGGBB, or from a mapping, where we use the following format: return result; } - Color constructColorMapping(Mark start, Mark end, Node.Pair[] pairs) + Color constructColorMapping(Mark start, Mark end, ref Node node) { - int r, g, b; - r = g = b = -1; - bool error = pairs.length != 3; + int r,g,b; + bool error = false; - foreach(ref pair; pairs) + //Might throw if a value is missing or is not an integer. + try { - //Key might not be a string, and value might not be an int, - //so we need to check for that - try - { - switch(pair.key.get!string) - { - case "r": r = pair.value.get!int; break; - case "g": g = pair.value.get!int; break; - case "b": b = pair.value.get!int; break; - default: error = true; - } - } - catch(NodeException e) - { - error = true; - } + r = node["r"].get!int; + g = node["g"].get!int; + b = node["b"].get!int; + } + catch(NodeException e) + { + error = true; } if(error || r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) @@ -146,8 +141,8 @@ Finally, the code to put it all together: { auto constructor = new Constructor; //both functions handle the same tag, but one handles scalar, one mapping. - constructor.addConstructor("!color", &constructColorScalar); - constructor.addConstructor("!color-mapping", &constructColorMapping); + constructor.addConstructorScalar("!color", &constructColorScalar); + constructor.addConstructorMapping("!color-mapping", &constructColorMapping); auto loader = Loader("input.yaml"); loader.constructor = constructor; @@ -284,7 +279,7 @@ With the following code, we will add support for dumping the our Color type. } 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()* +CSS-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 diff --git a/dyaml/constructor.d b/dyaml/constructor.d index d8fa438..f19202a 100644 --- a/dyaml/constructor.d +++ b/dyaml/constructor.d @@ -68,11 +68,11 @@ final class Constructor { private: ///Constructor functions from scalars. - Node.Value delegate(Mark, Mark, string) [Tag] fromScalar_; + Node.Value delegate(Mark, Mark, ref Node)[Tag] fromScalar_; ///Constructor functions from sequences. - Node.Value delegate(Mark, Mark, Node[]) [Tag] fromSequence_; + Node.Value delegate(Mark, Mark, ref Node)[Tag] fromSequence_; ///Constructor functions from mappings. - Node.Value delegate (Mark, Mark, Node.Pair[])[Tag] fromMapping_; + Node.Value delegate(Mark, Mark, ref Node)[Tag] fromMapping_; public: /** @@ -85,26 +85,25 @@ final class Constructor */ this(in bool defaultConstructors = true) { - if(defaultConstructors) - { - addConstructor("tag:yaml.org,2002:null", &constructNull); - addConstructor("tag:yaml.org,2002:bool", &constructBool); - addConstructor("tag:yaml.org,2002:int", &constructLong); - addConstructor("tag:yaml.org,2002:float", &constructReal); - addConstructor("tag:yaml.org,2002:binary", &constructBinary); - addConstructor("tag:yaml.org,2002:timestamp", &constructTimestamp); - addConstructor("tag:yaml.org,2002:str", &constructString); + if(!defaultConstructors){return;} - ///In a mapping, the default value is kept as an entry with the '=' key. - addConstructor("tag:yaml.org,2002:value", &constructString); + addConstructorScalar("tag:yaml.org,2002:null", &constructNull); + addConstructorScalar("tag:yaml.org,2002:bool", &constructBool); + addConstructorScalar("tag:yaml.org,2002:int", &constructLong); + addConstructorScalar("tag:yaml.org,2002:float", &constructReal); + addConstructorScalar("tag:yaml.org,2002:binary", &constructBinary); + addConstructorScalar("tag:yaml.org,2002:timestamp", &constructTimestamp); + addConstructorScalar("tag:yaml.org,2002:str", &constructString); - addConstructor("tag:yaml.org,2002:omap", &constructOrderedMap); - addConstructor("tag:yaml.org,2002:pairs", &constructPairs); - addConstructor("tag:yaml.org,2002:set", &constructSet); - addConstructor("tag:yaml.org,2002:seq", &constructSequence); - addConstructor("tag:yaml.org,2002:map", &constructMap); - addConstructor("tag:yaml.org,2002:merge", &constructMerge); - } + ///In a mapping, the default value is kept as an entry with the '=' key. + addConstructorScalar("tag:yaml.org,2002:value", &constructString); + + addConstructorSequence("tag:yaml.org,2002:omap", &constructOrderedMap); + addConstructorSequence("tag:yaml.org,2002:pairs", &constructPairs); + addConstructorMapping("tag:yaml.org,2002:set", &constructSet); + addConstructorSequence("tag:yaml.org,2002:seq", &constructSequence); + addConstructorMapping("tag:yaml.org,2002:map", &constructMap); + addConstructorScalar("tag:yaml.org,2002:merge", &constructMerge); } ///Destroy the constructor. @@ -119,139 +118,129 @@ final class Constructor } /** - * Add a constructor function. + * Add a constructor function from scalar. * - * The function passed must two Marks (determining start and end positions of - * the node in file) and either a string (if constructing from scalar), - * an array of Nodes (from sequence) or an array of Node.Pair (from mapping). - * The value returned by this function will be stored in the resulring node. + * The function must take two Marks (start and end positions of + * the node in file) and a reference to Node to construct from. + * The node contains a string for scalars, Node[] for sequences and + * Node.Pair[] for mappings. + * The value returned by this function will be stored in the resulting node. * * Only one constructor function can be set for one tag. * * Params: tag = Tag for the function to handle. * ctor = Constructor function. */ - void addConstructor(T, U)(in string tag, T function(Mark, Mark, U) ctor) - if(is(U == string) || is(U == Node[]) || is(U == Node.Pair[])) + void addConstructorScalar(T)(in string tag, T function(Mark, Mark, ref Node) ctor) { - Node.Value delegate(Mark, Mark, U) deleg; + const t = Tag(tag); + auto deleg = addConstructor!T(t, ctor); + (*delegates!string)[t] = deleg; + } - //Type that natively fits into Node.Value. - static if(Node.Value.allowed!T) - { - deleg = (Mark s, Mark e, U p){return Node.Value(ctor(s,e,p));}; - } - //User defined type. - else - { - deleg = (Mark s, Mark e, U p){return Node.userValue(ctor(s,e,p));}; - } + /** + * Add a constructor function from sequence. + * + * See_Also: addConstructorScalar + */ + void addConstructorSequence(T)(in string tag, T function(Mark, Mark, ref Node) ctor) + { + const t = Tag(tag); + auto deleg = addConstructor!T(t, ctor); + (*delegates!(Node[]))[t] = deleg; + } - const Tag t = Tag(tag); - - assert((t in fromScalar_) is null && - (t in fromSequence_) is null && - (t in fromMapping_) is null, - "Constructor function for tag " ~ tag ~ " is already " - "specified. Can't specify another one."); - - - static if(is(U == string)) - { - fromScalar_[t] = deleg; - } - else static if(is(U == Node[])) - { - fromSequence_[t] = deleg; - } - else static if(is(U == Node.Pair[])) - { - fromMapping_[t] = deleg; - } + /** + * Add a constructor function from a mapping. + * + * See_Also: addConstructorScalar + */ + void addConstructorMapping(T)(in string tag, T function(Mark, Mark, ref Node) ctor) + { + const t = Tag(tag); + auto deleg = addConstructor!T(t, ctor); + (*delegates!(Node.Pair[]))[t] = deleg; } package: /* - * Construct a node from scalar. + * Construct a node. * * Params: start = Start position of the node. * end = End position of the node. * tag = Tag (data type) of the node. - * value = String value of the node. + * value = Value to construct node from (string, nodes or pairs). * * Returns: Constructed node. */ - Node node(in Mark start, in Mark end, in Tag tag, string value) const + Node node(T)(in Mark start, in Mark end, in Tag tag, T value) + if(is(T : string) || is(T == Node[]) || is(T == Node.Pair[])) { - enforce((tag in fromScalar_) !is null, - new ConstructorException("Could not determine a constructor from " - "scalar for tag " ~ tag.get(), start, end)); - return Node.rawNode(fromScalar_[tag](start, end, value), start, tag); + enforce((tag in *delegates!T) !is null, + new ConstructorException("Could not determine a constructor for tag " + ~ tag.get(), start, end)); + Node node = Node(value); + return Node.rawNode((*delegates!T)[tag](start, end, node), start, tag); } - /* - * Construct a node from sequence. + private: + /* + * Add a constructor function. * - * Params: start = Start position of the node. - * end = End position of the node. - * tag = Tag (data type) of the node. - * value = Sequence to construct node from. - * - * Returns: Constructed node. - */ - Node node(in Mark start, in Mark end, in Tag tag, Node[] value) const + * Params: tag = Tag for the function to handle. + * ctor = Constructor function. + */ + auto addConstructor(T)(in Tag tag, T function(Mark, Mark, ref Node) ctor) { - enforce((tag in fromSequence_) !is null, - new ConstructorException("Could not determine a constructor from " - "sequence for tag " ~ tag.get(), start, end)); - return Node.rawNode(fromSequence_[tag](start, end, value), start, tag); + assert((tag in fromScalar_) is null && + (tag in fromSequence_) is null && + (tag in fromMapping_) is null, + "Constructor function for tag " ~ tag.get ~ " is already " + "specified. Can't specify another one."); + + return (Mark s, Mark e, ref Node n) + { + static if(Node.Value.allowed!T){return Node.Value(ctor(s,e,n));} + else {return Node.userValue(ctor(s,e,n));} + }; } - /* - * Construct a node from mapping. - * - * Params: start = Start position of the node. - * end = End position of the node. - * tag = Tag (data type) of the node. - * value = Mapping to construct node from. - * - * Returns: Constructed node. - */ - Node node(in Mark start, in Mark end, in Tag tag, Node.Pair[] value) const + //Get the array of constructor functions for scalar, sequence or mapping. + auto delegates(T)() { - enforce((tag in fromMapping_) !is null, - new ConstructorException("Could not determine a constructor from " - "mapping for tag " ~ tag.get(), start, end)); - return Node.rawNode(fromMapping_[tag](start, end, value), start, tag); + static if(is(T : string)) {return &fromScalar_;} + else static if(is(T : Node[])) {return &fromSequence_;} + else static if(is(T : Node.Pair[])){return &fromMapping_;} + else static assert(false); } } ///Construct a null node. -YAMLNull constructNull(Mark start, Mark end, string value) +YAMLNull constructNull(Mark start, Mark end, ref Node node) { return YAMLNull(); } ///Construct a merge node - a node that merges another node into a mapping. -YAMLMerge constructMerge(Mark start, Mark end, string value) +YAMLMerge constructMerge(Mark start, Mark end, ref Node node) { return YAMLMerge(); } ///Construct a boolean node. -bool constructBool(Mark start, Mark end, string value) +bool constructBool(Mark start, Mark end, ref Node node) { - value = value.toLower(); + string value = node.get!string().toLower(); if(["yes", "true", "on"].canFind(value)) {return true;} if(["no", "false", "off"].canFind(value)){return false;} throw new ConstructorException("Unable to parse boolean value: " ~ value, start, end); } ///Construct an integer (long) node. -long constructLong(Mark start, Mark end, string value) +long constructLong(Mark start, Mark end, ref Node node) { - value = value.replace("_", ""); + string value = node.get!string().replace("_", ""); const char c = value[0]; const long sign = c != '-' ? 1 : -1; if(c == '-' || c == '+') @@ -299,7 +288,7 @@ unittest { long getLong(string str) { - return constructLong(Mark(), Mark(), str); + return constructLong(Mark(), Mark(), Node(str)); } string canonical = "685230"; @@ -318,9 +307,9 @@ unittest } ///Construct a floating point (real) node. -real constructReal(Mark start, Mark end, string value) +real constructReal(Mark start, Mark end, ref Node node) { - value = value.replace("_", "").toLower(); + string value = node.get!string().replace("_", "").toLower(); const char c = value[0]; const real sign = c != '-' ? 1.0 : -1.0; if(c == '-' || c == '+') @@ -369,7 +358,7 @@ unittest real getReal(string str) { - return constructReal(Mark(), Mark(), str); + return constructReal(Mark(), Mark(), Node(str)); } string canonical = "6.8523015e+5"; @@ -388,8 +377,9 @@ unittest } ///Construct a binary (base64) node. -ubyte[] constructBinary(Mark start, Mark end, string value) +ubyte[] constructBinary(Mark start, Mark end, ref Node node) { + string value = node.get!string; //For an unknown reason, this must be nested to work (compiler bug?). try { @@ -411,13 +401,15 @@ unittest char[] buffer; buffer.length = 256; string input = cast(string)Base64.encode(test, buffer); - auto value = constructBinary(Mark(), Mark(), input); + auto value = constructBinary(Mark(), Mark(), Node(input)); assert(value == test); } ///Construct a timestamp (SysTime) node. -SysTime constructTimestamp(Mark start, Mark end, string value) +SysTime constructTimestamp(Mark start, Mark end, ref Node node) { + string value = node.get!string; + immutable YMDRegexp = regex("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)"); immutable HMSRegexp = regex("^[Tt \t]+([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(\\.[0-9]*)?"); immutable TZRegexp = regex("^[ \t]*Z|([-+][0-9][0-9]?)(:[0-9][0-9])?"); @@ -492,7 +484,7 @@ unittest string timestamp(string value) { - return constructTimestamp(Mark(), Mark(), value).toISOString(); + return constructTimestamp(Mark(), Mark(), Node(value)).toISOString(); } string canonical = "2001-12-15T02:59:43.1Z"; @@ -515,9 +507,9 @@ unittest } ///Construct a string node. -string constructString(Mark start, Mark end, string value) +string constructString(Mark start, Mark end, ref Node node) { - return value; + return node.get!string; } ///Convert a sequence of single-element mappings into a sequence of pairs. @@ -539,9 +531,9 @@ Node.Pair[] getPairs(string type, Mark start, Mark end, Node[] nodes) } ///Construct an ordered map (ordered sequence of key:value pairs without duplicates) node. -Node.Pair[] constructOrderedMap(Mark start, Mark end, Node[] nodes) +Node.Pair[] constructOrderedMap(Mark start, Mark end, ref Node node) { - auto pairs = getPairs("ordered map", start, end, nodes); + auto pairs = getPairs("ordered map", start, end, node.get!(Node[])); //TODO: the map here should be replaced with something with deterministic //memory allocation if possible. @@ -588,7 +580,7 @@ unittest bool hasDuplicates(Node[] nodes) { - return null !is collectException(constructOrderedMap(Mark(), Mark(), nodes)); + return null !is collectException(constructOrderedMap(Mark(), Mark(), Node(nodes))); } assert(hasDuplicates(alternateTypes(8) ~ alternateTypes(2))); @@ -600,14 +592,16 @@ unittest } ///Construct a pairs (ordered sequence of key: value pairs allowing duplicates) node. -Node.Pair[] constructPairs(Mark start, Mark end, Node[] nodes) +Node.Pair[] constructPairs(Mark start, Mark end, ref Node node) { - return getPairs("pairs", start, end, nodes); + return getPairs("pairs", start, end, node.get!(Node[])); } ///Construct a set node. -Node[] constructSet(Mark start, Mark end, Node.Pair[] pairs) +Node[] constructSet(Mark start, Mark end, ref Node node) { + auto pairs = node.get!(Node.Pair[]); + //In future, the map here should be replaced with something with deterministic //memory allocation if possible. //Detect duplicates. @@ -658,24 +652,25 @@ unittest } assert(null !is collectException - (constructSet(Mark(), Mark(), DuplicatesShort.dup))); + (constructSet(Mark(), Mark(), Node(DuplicatesShort.dup)))); assert(null is collectException - (constructSet(Mark(), Mark(), noDuplicatesShort.dup))); + (constructSet(Mark(), Mark(), Node(noDuplicatesShort.dup)))); assert(null !is collectException - (constructSet(Mark(), Mark(), DuplicatesLong.dup))); + (constructSet(Mark(), Mark(), Node(DuplicatesLong.dup)))); assert(null is collectException - (constructSet(Mark(), Mark(), noDuplicatesLong.dup))); + (constructSet(Mark(), Mark(), Node(noDuplicatesLong.dup)))); } ///Construct a sequence (array) node. -Node[] constructSequence(Mark start, Mark end, Node[] nodes) +Node[] constructSequence(Mark start, Mark end, ref Node node) { - return nodes; + return node.get!(Node[]); } ///Construct an unordered map (unordered set of key: value _pairs without duplicates) node. -Node.Pair[] constructMap(Mark start, Mark end, Node.Pair[] pairs) +Node.Pair[] constructMap(Mark start, Mark end, ref Node node) { + auto pairs = node.get!(Node.Pair[]); //TODO: the map here should be replaced with something with deterministic //memory allocation if possible. //Detect duplicates. diff --git a/dyaml/node.d b/dyaml/node.d index b47275e..f11b058 100644 --- a/dyaml/node.d +++ b/dyaml/node.d @@ -251,11 +251,12 @@ struct Node { tag_ = Tag(tag); + //Construction from raw node or pair array. static if(is(T == Node) || is(T == Node.Pair)) { value_ = Value(array); } - //Need to handle byte buffers separately + //Need to handle byte buffers separately. else static if(is(T == byte) || is(T == ubyte)) { value_ = Value(cast(ubyte[]) array); diff --git a/examples/constructor/main.d b/examples/constructor/main.d index 7cd5e2f..a80c0d7 100644 --- a/examples/constructor/main.d +++ b/examples/constructor/main.d @@ -10,70 +10,63 @@ struct Color ubyte blue; } -Color constructColorScalar(Mark start, Mark end, string value) +Color constructColorScalar(Mark start, Mark end, ref Node node) { - if(value.length != 6) - { - throw new ConstructorException("Invalid color: " ~ value, start, end); - } - //We don't need to check for uppercase chars this way. - value = value.toLower(); + string value = node.get!string; - //Get value of a hex digit. - uint hex(char c) - { - if(!std.ascii.isHexDigit(c)) - { - throw new ConstructorException("Invalid color: " ~ value, start, end); - } + if(value.length != 6) + { + throw new ConstructorException("Invalid color: " ~ value, start, end); + } + //We don't need to check for uppercase chars this way. + value = value.toLower(); - if(std.ascii.isDigit(c)) - { - return c - '0'; - } - return c - 'a' + 10; - } + //Get value of a hex digit. + uint hex(char c) + { + if(!std.ascii.isHexDigit(c)) + { + throw new ConstructorException("Invalid color: " ~ value, start, end); + } - Color result; - result.red = cast(ubyte)(16 * hex(value[0]) + hex(value[1])); - result.green = cast(ubyte)(16 * hex(value[2]) + hex(value[3])); - result.blue = cast(ubyte)(16 * hex(value[4]) + hex(value[5])); + if(std.ascii.isDigit(c)) + { + return c - '0'; + } + return c - 'a' + 10; + } - return result; + Color result; + result.red = cast(ubyte)(16 * hex(value[0]) + hex(value[1])); + result.green = cast(ubyte)(16 * hex(value[2]) + hex(value[3])); + result.blue = cast(ubyte)(16 * hex(value[4]) + hex(value[5])); + + return result; } -Color constructColorMapping(Mark start, Mark end, Node.Pair[] pairs) +Color constructColorMapping(Mark start, Mark end, ref Node node) { - int r, g, b; - r = g = b = -1; - bool error = pairs.length != 3; + int r,g,b; + bool error = false; - foreach(ref pair; pairs) - { - //Key might not be a string, and value might not be an int, - //so we need to check for that - try - { - switch(pair.key.get!string) - { - case "r": r = pair.value.get!int; break; - case "g": g = pair.value.get!int; break; - case "b": b = pair.value.get!int; break; - default: error = true; - } - } - catch(NodeException e) - { - error = true; - } - } + //Might throw if a value is missing or is not an integer. + try + { + r = node["r"].get!int; + g = node["g"].get!int; + b = node["b"].get!int; + } + catch(NodeException e) + { + error = true; + } - if(error || r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) - { - throw new ConstructorException("Invalid color", start, end); - } + if(error || r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) + { + throw new ConstructorException("Invalid color", start, end); + } - return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b); + return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b); } void main() @@ -85,8 +78,8 @@ void main() { auto constructor = new Constructor; //both functions handle the same tag, but one handles scalar, one mapping. - constructor.addConstructor("!color", &constructColorScalar); - constructor.addConstructor("!color-mapping", &constructColorMapping); + constructor.addConstructorScalar("!color", &constructColorScalar); + constructor.addConstructorMapping("!color-mapping", &constructColorMapping); auto loader = Loader("input.yaml"); loader.constructor = constructor; diff --git a/examples/resolver/main.d b/examples/resolver/main.d index fd06cb4..b80b1e4 100644 --- a/examples/resolver/main.d +++ b/examples/resolver/main.d @@ -10,70 +10,63 @@ struct Color ubyte blue; } -Color constructColorScalar(Mark start, Mark end, string value) +Color constructColorScalar(Mark start, Mark end, ref Node node) { - if(value.length != 6) - { - throw new ConstructorException("Invalid color: " ~ value, start, end); - } - //We don't need to check for uppercase chars this way. - value = value.toLower(); + string value = node.get!string; - //Get value of a hex digit. - uint hex(char c) - { - if(!std.ascii.isHexDigit(c)) - { - throw new ConstructorException("Invalid color: " ~ value, start, end); - } + if(value.length != 6) + { + throw new ConstructorException("Invalid color: " ~ value, start, end); + } + //We don't need to check for uppercase chars this way. + value = value.toLower(); - if(std.ascii.isDigit(c)) - { - return c - '0'; - } - return c - 'a' + 10; - } + //Get value of a hex digit. + uint hex(char c) + { + if(!std.ascii.isHexDigit(c)) + { + throw new ConstructorException("Invalid color: " ~ value, start, end); + } - Color result; - result.red = cast(ubyte)(16 * hex(value[0]) + hex(value[1])); - result.green = cast(ubyte)(16 * hex(value[2]) + hex(value[3])); - result.blue = cast(ubyte)(16 * hex(value[4]) + hex(value[5])); + if(std.ascii.isDigit(c)) + { + return c - '0'; + } + return c - 'a' + 10; + } - return result; + Color result; + result.red = cast(ubyte)(16 * hex(value[0]) + hex(value[1])); + result.green = cast(ubyte)(16 * hex(value[2]) + hex(value[3])); + result.blue = cast(ubyte)(16 * hex(value[4]) + hex(value[5])); + + return result; } -Color constructColorMapping(Mark start, Mark end, Node.Pair[] pairs) +Color constructColorMapping(Mark start, Mark end, ref Node node) { - int r, g, b; - r = g = b = -1; - bool error = pairs.length != 3; + int r,g,b; + bool error = false; - foreach(ref pair; pairs) - { - //Key might not be a string, and value might not be an int, - //so we need to check for that - try - { - switch(pair.key.get!string) - { - case "r": r = pair.value.get!int; break; - case "g": g = pair.value.get!int; break; - case "b": b = pair.value.get!int; break; - default: error = true; - } - } - catch(NodeException e) - { - error = true; - } - } + //Might throw if a value is missing or is not an integer. + try + { + r = node["r"].get!int; + g = node["g"].get!int; + b = node["b"].get!int; + } + catch(NodeException e) + { + error = true; + } - if(error || r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) - { - throw new ConstructorException("Invalid color", start, end); - } + if(error || r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) + { + throw new ConstructorException("Invalid color", start, end); + } - return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b); + return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b); } void main() @@ -85,8 +78,8 @@ void main() { auto constructor = new Constructor; //both functions handle the same tag, but one handles scalar, one mapping. - constructor.addConstructor("!color", &constructColorScalar); - constructor.addConstructor("!color-mapping", &constructColorMapping); + constructor.addConstructorScalar("!color", &constructColorScalar); + constructor.addConstructorMapping("!color-mapping", &constructColorMapping); auto resolver = new Resolver; resolver.addImplicitResolver("!color", std.regex.regex("[0-9a-fA-F]{6}"), diff --git a/test/data/construct-custom.data b/test/data/construct-custom.data index 4729be9..f17e4ed 100644 --- a/test/data/construct-custom.data +++ b/test/data/construct-custom.data @@ -1,6 +1,4 @@ --- -- !tag1 - x: 1 - !tag1 x: 1 'y': 2 diff --git a/test/src/constructor.d b/test/src/constructor.d index 2f97813..a8ba967 100644 --- a/test/src/constructor.d +++ b/test/src/constructor.d @@ -88,8 +88,7 @@ Node[] constructBool() Node[] constructCustom() { - return [Node([Node(new TestClass(1, 0, 0)), - Node(new TestClass(1, 2, 3)), + return [Node([Node(new TestClass(1, 2, 3)), Node(TestStruct(10))])]; } @@ -338,21 +337,17 @@ struct TestStruct } ///Constructor function for TestClass. -TestClass constructClass(Mark start, Mark end, Node.Pair[] pairs) +TestClass constructClass(Mark start, Mark end, ref Node node) { - int x, y, z; - foreach(ref pair; pairs) + try { - switch(pair.key.get!string) - { - case "x": x = pair.value.get!int; break; - case "y": y = pair.value.get!int; break; - case "z": z = pair.value.get!int; break; - default: break; - } + return new TestClass(node["x"].get!int, node["y"].get!int, node["z"].get!int); + } + catch(NodeException e) + { + throw new ConstructorException("Error constructing TestClass (missing data members?) " + ~ e.msg, start, end); } - - return new TestClass(x, y, z); } Node representClass(ref Node node, Representer representer) @@ -367,9 +362,9 @@ Node representClass(ref Node node, Representer representer) } ///Constructor function for TestStruct. -TestStruct constructStruct(Mark start, Mark end, string value) +TestStruct constructStruct(Mark start, Mark end, ref Node node) { - return TestStruct(to!int(value)); + return TestStruct(to!int(node.get!string)); } ///Representer function for TestStruct. @@ -395,8 +390,8 @@ void testConstructor(bool verbose, string dataFilename, string codeDummy) new Exception("Unimplemented constructor test: " ~ base)); auto constructor = new Constructor; - constructor.addConstructor("!tag1", &constructClass); - constructor.addConstructor("!tag2", &constructStruct); + constructor.addConstructorMapping("!tag1", &constructClass); + constructor.addConstructorScalar("!tag2", &constructStruct); auto loader = Loader(dataFilename); loader.constructor = constructor; diff --git a/test/src/representer.d b/test/src/representer.d index aa33889..5178611 100644 --- a/test/src/representer.d +++ b/test/src/representer.d @@ -58,8 +58,8 @@ void testRepresenterTypes(bool verbose, string codeFilename) output = cast(string)emitStream.data; auto loadStream = new MemoryStream(emitStream.data); auto constructor = new Constructor; - constructor.addConstructor("!tag1", &constructClass); - constructor.addConstructor("!tag2", &constructStruct); + constructor.addConstructorMapping("!tag1", &constructClass); + constructor.addConstructorScalar("!tag2", &constructStruct); auto loader = Loader(loadStream); loader.name = "TEST";