From fbc962623d56d2cad7e8fa7671507fea40308176 Mon Sep 17 00:00:00 2001 From: Ferdinand Majerech Date: Thu, 17 Nov 2011 23:53:24 +0100 Subject: [PATCH] Simplified the Constructor API. --- doc/doctrees/environment.pickle | Bin 12705 -> 12705 bytes doc/doctrees/tutorials/custom_types.doctree | Bin 47085 -> 46989 bytes doc/html/_sources/tutorials/custom_types.txt | 51 +++-- doc/html/api/dyaml.constructor.html | 81 +++----- 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 | 52 +++-- doc/html/tutorials/getting_started.html | 2 +- doc/html/tutorials/yaml_syntax.html | 2 +- docsrc/tutorials/custom_types.rst | 51 +++-- dyaml/constructor.d | 207 ++++++++----------- examples/constructor/main.d | 23 +-- examples/resolver/main.d | 23 +-- test/src/constructor.d | 14 +- 16 files changed, 217 insertions(+), 297 deletions(-) diff --git a/doc/doctrees/environment.pickle b/doc/doctrees/environment.pickle index 9894b7d00b6ff975046591a9b15a1635930d29a6..5abd626d2511e19827e35b507d2010d071007127 100644 GIT binary patch delta 62 zcmZ3OyfAq~o4#T4t2+C68OrXCmp3NAD&tt4p#x!7$IQzxg)l2EGc)X<3ZA!Z-md?O F5dfW99xVU> delta 62 zcmZ3OyfAq~o4z57?1ygs3}tu6%Nto_pZo60(19@D@)=~9LYS|1ZOX8NFkd*gZr-l{ GiV*-KeHtSG diff --git a/doc/doctrees/tutorials/custom_types.doctree b/doc/doctrees/tutorials/custom_types.doctree index 3fe2c1cf915cec62babd894da06437bd29315317..7518da8275eec601c0a29c08fc8cebd63af49377 100644 GIT binary patch delta 6153 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 diff --git a/doc/html/_sources/tutorials/custom_types.txt b/doc/html/_sources/tutorials/custom_types.txt index 9b3eaf5..65853ee 100644 --- a/doc/html/_sources/tutorials/custom_types.txt +++ b/doc/html/_sources/tutorials/custom_types.txt @@ -3,13 +3,13 @@ Custom YAML data types ====================== Sometimes you need to serialize complex data types such as classes. To do this -you could use plain nodes such as mappings with class data members. However, -YAML supports custom types with identifiers called *tags*. That is the topic of -this tutorial. +you could use plain nodes such as mappings with class data members. YAML also +supports custom types with identifiers called *tags*. That is the topic of this +tutorial. Each YAML node has a tag specifying its type. For instance: strings use the tag ``tag:yaml.org,2002:str``. Tags of most default types are *implicitly resolved* -during parsing, so you don't need to specify tag for each float, integer, etc. +during parsing - you don't need to specify tag for each float, integer, etc. D:YAML can also implicitly resolve custom tags, as we will show later. @@ -24,7 +24,7 @@ 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 +define the *opEquals()* operator - this is used in equality comparisons of nodes. Default class *opEquals()* compares references, which means two identical objects might be considered unequal. (Default struct *opEquals()* compares byte-by-byte, sometimes you might want to override that as well.) @@ -41,24 +41,26 @@ following struct: ubyte blue; } -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 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: +First, we need a function to construct our data type. The function will take 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. +If this function throws any exception, D:YAML handles it and adds its message +to a *YAMLException* that will be thrown when loading the file. + +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, ref Node node) + Color constructColorScalar(ref Node node) { string value = node.as!string; if(value.length != 6) { - throw new ConstructorException("Invalid color: " ~ value, start, end); + throw new Exception("Invalid color: " ~ value); } //We don't need to check for uppercase chars this way. value = value.toLower(); @@ -68,7 +70,7 @@ of these functions: { if(!std.ascii.isHexDigit(c)) { - throw new ConstructorException("Invalid color: " ~ value, start, end); + throw new Exception("Invalid color: " ~ value); } if(std.ascii.isDigit(c)) @@ -86,21 +88,16 @@ of these functions: return result; } - Color constructColorMapping(Mark start, Mark end, ref Node node) + Color constructColorMapping(ref Node node) { ubyte r,g,b; //Might throw if a value is missing is not an integer, or is out of range. - try - { - r = node["r"].as!ubyte; - g = node["g"].as!ubyte; - b = node["b"].as!ubyte; - } - catch(NodeException e) - { - throw new ConstructorException("Invalid color: " ~ e.msg, start, end); - } + //If this happens, D:YAML will handle the exception and use its message + //in a YAMLException thrown when loading. + r = node["r"].as!ubyte; + g = node["g"].as!ubyte; + b = node["b"].as!ubyte; return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b); } diff --git a/doc/html/api/dyaml.constructor.html b/doc/html/api/dyaml.constructor.html index b81d239..f05fd59 100644 --- a/doc/html/api/dyaml.constructor.html +++ b/doc/html/api/dyaml.constructor.html @@ -95,14 +95,20 @@ -
void addConstructorScalar(T)(in string tag, T function(Mark, Mark, ref Node) ctor); +
void addConstructorScalar(T)(in string tag, T function(ref Node) ctor);

Add a constructor function from scalar.

-

The function must take two Marks (start and end positions of - the node in file) and a reference to Node to construct from. +

The function must take a reference to Node to construct from. The node contains a string for scalars, Node[] for sequences and Node.Pair[] for mappings. +
+ + Any exception thrown by this function will be caught by D:YAML and + its message will be added to a YAMLException that will also tell the + user which type failed to construct, and position in the file. +
+ The value returned by this function will be stored in the resulting node.
@@ -124,20 +130,13 @@ int x, y, z; } - MyStruct constructMyStructScalar(Mark start, Mark end, ref Node node) + MyStruct constructMyStructScalar(ref Node node) { //Guaranteed to be string as we construct from scalar. //!mystruct x:y:z auto parts = node.as!string().split(":"); - try - { - return MyStruct(to!int(parts[0]), to!int(parts[1]), to!int(parts[2])); - } - catch(Exception e) - { - throw new ConstructorException("Could not construct MyStruct: " ~ e.msg, - start, end); - } + //If this throws, the D:YAML will handle it and throw a YAMLException. + return MyStruct(to!int(parts[0]), to!int(parts[1]), to!int(parts[2])); } void main() @@ -152,7 +151,7 @@

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

Add a constructor function from sequence.

@@ -169,19 +168,11 @@ int x, y, z; } - MyStruct constructMyStructSequence(Mark start, Mark end, ref Node node) + MyStruct constructMyStructSequence(ref Node node) { //node is guaranteed to be sequence. //!mystruct [x, y, z] - try - { - return MyStruct(node[0].as!int, node[1].as!int, node[2].as!int); - } - catch(NodeException e) - { - throw new ConstructorException("Could not construct MyStruct: " ~ e.msg, - start, end); - } + return MyStruct(node[0].as!int, node[1].as!int, node[2].as!int); } void main() @@ -196,7 +187,7 @@

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

Add a constructor function from a mapping.

@@ -213,19 +204,11 @@ int x, y, z; } - MyStruct constructMyStructMapping(Mark start, Mark end, ref Node node) + MyStruct constructMyStructMapping(ref Node node) { //node is guaranteed to be mapping. //!mystruct {"x": x, "y": y, "z": z} - try - { - return MyStruct(node["x"].as!int, node["y"].as!int, node["z"].as!int); - } - catch(NodeException e) - { - throw new ConstructorException("Could not construct MyStruct: " ~ e.msg, - start, end); - } + return MyStruct(node["x"].as!int, node["y"].as!int, node["z"].as!int); } void main() @@ -242,72 +225,72 @@
-
YAMLNull constructNull(Mark start, Mark end, ref Node node); +
YAMLNull constructNull(ref Node node);

Construct a null node.

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

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

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

Construct a boolean node.

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

Construct an integer (long) node.

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

Construct a floating point (real) node.

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

Construct a binary (base64) node.

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

Construct a timestamp (SysTime) node.

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

Construct a string node.

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

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

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

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

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

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

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

Construct a set node.

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

Construct a sequence (array) node.

-
Pair[] constructMap(Mark start, Mark end, ref Node node); +
Pair[] constructMap(ref Node 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 c859c39..eaff95f 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 3fc1aac..e50c9f3 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 ca5873c..bd5a860 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 2e381bc..8b3e9d3 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: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,implicit:[0,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],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],good:3,"return":[3,4],thei:[0,1,3,4],python:0,auto:3,now:[1,3,4],introduct:[0,4],name:0,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,3],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,3],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],rang:3,onc:[0,1],arrai:[0,1,3,4],sometim:3,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,"float":[0,3],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,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],color:[0,3],hyphen:0,loader:[3,4],colon:0,suppli:3,respect:3,addconstructorscalar:3,bbb:3,empti:0,sinc: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:4,anchor:[0,1,2],readi:3,non:[0,3],archiv:4,tediou:3,ascii:[1,3],dumper:[3,4],disabl:3,clearli:1,make:3,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,linux:[0,4],some:[0,1,3,4],guarante:3,ubyt:[0,3],librari:4,representcolor:3,lead:1,though:4,per:3,unord:1,condit:3,either:[0,3,4],object:3,run:4,acronym:0,usag:4,immut:3,rrggbb: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,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,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,bool:0,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 +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,veri:1,implicitli:[0,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: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,implicit:[0,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],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],first:[0,2,3,4],order:[1,4],over:4,move:4,orang:3,becaus:1,yamlexcept:[3,4],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],good:3,"return":[3,4],thei:[0,1,3,4],python:0,auto:3,now:[1,3,4],introduct:[0,4],name:0,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],happen:3,extract:4,out:[0,3],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,3],thrown:[3,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],rang:3,onc:[0,1],arrai:[0,1,3,4],sometim:3,restrict:1,unlik:0,alreadi:[3,4],done:3,construct:[0,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],messag: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,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,"float":[0,3],see:[0,1,3],result:3,fail:1,close:1,athlon:0,representscalar:3,wikipedia:0,written:4,between:[0,1,2],"import":4,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],color:[0,3],hyphen:0,loader:[3,4],colon:0,suppli:3,respect:3,addconstructorscalar:3,rgb:3,empti:0,sinc: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:4,anchor:[0,1,2],readi:3,non:[0,3],archiv:4,tediou:3,ascii:[1,3],dumper:[3,4],disabl:3,clearli:1,make:3,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],implement:[1,3],markup:0,well: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:[3,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,linux:[0,4],some:[0,1,3,4],guarante:3,ubyt:[0,3],librari:4,representcolor:3,lead:1,though:4,per:3,unord:1,condit:3,either:[0,3,4],object:3,run:4,acronym:0,usag:4,immut:3,rrggbb: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,bbb:3,bsd:0,mark:[0,1],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,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,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,bool:0,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 e70c374..ebf6387 100644 --- a/doc/html/tutorials/custom_types.html +++ b/doc/html/tutorials/custom_types.html @@ -48,12 +48,12 @@

Custom YAML data types

Sometimes you need to serialize complex data types such as classes. To do this -you could use plain nodes such as mappings with class data members. However, -YAML supports custom types with identifiers called tags. That is the topic of -this tutorial.

+you could use plain nodes such as mappings with class data members. YAML also +supports custom types with identifiers called tags. That is the topic of this +tutorial.

Each YAML node has a tag specifying its type. For instance: strings use the tag tag:yaml.org,2002:str. Tags of most default types are implicitly resolved -during parsing, so you don’t need to specify tag for each float, integer, etc. +during parsing - you don’t need to specify tag for each float, integer, etc. D:YAML can also implicitly resolve custom tags, as we will show later.

Constructor

@@ -63,7 +63,7 @@ functions to process each supported tag. These are supplied by 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 +define the opEquals() operator - this is used in equality comparisons of nodes. Default class opEquals() compares references, which means two identical objects might be considered unequal. (Default struct opEquals() compares byte-by-byte, sometimes you might want to override that as well.)

@@ -77,21 +77,22 @@ 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 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)
+

First, we need a function to construct our data type. The function will take 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. +If this function throws any exception, D:YAML handles it and adds its message +to a YAMLException that will be thrown when loading the file.

+

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(ref Node node)
 {
     string value = node.as!string;
 
     if(value.length != 6)
     {
-        throw new ConstructorException("Invalid color: " ~ value, start, end);
+        throw new Exception("Invalid color: " ~ value);
     }
     //We don't need to check for uppercase chars this way.
     value = value.toLower();
@@ -101,7 +102,7 @@ of these functions:

{ if(!std.ascii.isHexDigit(c)) { - throw new ConstructorException("Invalid color: " ~ value, start, end); + throw new Exception("Invalid color: " ~ value); } if(std.ascii.isDigit(c)) @@ -119,21 +120,16 @@ of these functions:

return result; } -Color constructColorMapping(Mark start, Mark end, ref Node node) +Color constructColorMapping(ref Node node) { ubyte r,g,b; //Might throw if a value is missing is not an integer, or is out of range. - try - { - r = node["r"].as!ubyte; - g = node["g"].as!ubyte; - b = node["b"].as!ubyte; - } - catch(NodeException e) - { - throw new ConstructorException("Invalid color: " ~ e.msg, start, end); - } + //If this happens, D:YAML will handle the exception and use its message + //in a YAMLException thrown when loading. + r = node["r"].as!ubyte; + g = node["g"].as!ubyte; + b = node["b"].as!ubyte; return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b); } @@ -368,7 +364,7 @@ directory of the D:YAML package.

diff --git a/doc/html/tutorials/getting_started.html b/doc/html/tutorials/getting_started.html index a6e63b4..8358077 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 564a9f1..14f48a9 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 9b3eaf5..65853ee 100644 --- a/docsrc/tutorials/custom_types.rst +++ b/docsrc/tutorials/custom_types.rst @@ -3,13 +3,13 @@ Custom YAML data types ====================== Sometimes you need to serialize complex data types such as classes. To do this -you could use plain nodes such as mappings with class data members. However, -YAML supports custom types with identifiers called *tags*. That is the topic of -this tutorial. +you could use plain nodes such as mappings with class data members. YAML also +supports custom types with identifiers called *tags*. That is the topic of this +tutorial. Each YAML node has a tag specifying its type. For instance: strings use the tag ``tag:yaml.org,2002:str``. Tags of most default types are *implicitly resolved* -during parsing, so you don't need to specify tag for each float, integer, etc. +during parsing - you don't need to specify tag for each float, integer, etc. D:YAML can also implicitly resolve custom tags, as we will show later. @@ -24,7 +24,7 @@ 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 +define the *opEquals()* operator - this is used in equality comparisons of nodes. Default class *opEquals()* compares references, which means two identical objects might be considered unequal. (Default struct *opEquals()* compares byte-by-byte, sometimes you might want to override that as well.) @@ -41,24 +41,26 @@ following struct: ubyte blue; } -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 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: +First, we need a function to construct our data type. The function will take 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. +If this function throws any exception, D:YAML handles it and adds its message +to a *YAMLException* that will be thrown when loading the file. + +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, ref Node node) + Color constructColorScalar(ref Node node) { string value = node.as!string; if(value.length != 6) { - throw new ConstructorException("Invalid color: " ~ value, start, end); + throw new Exception("Invalid color: " ~ value); } //We don't need to check for uppercase chars this way. value = value.toLower(); @@ -68,7 +70,7 @@ of these functions: { if(!std.ascii.isHexDigit(c)) { - throw new ConstructorException("Invalid color: " ~ value, start, end); + throw new Exception("Invalid color: " ~ value); } if(std.ascii.isDigit(c)) @@ -86,21 +88,16 @@ of these functions: return result; } - Color constructColorMapping(Mark start, Mark end, ref Node node) + Color constructColorMapping(ref Node node) { ubyte r,g,b; //Might throw if a value is missing is not an integer, or is out of range. - try - { - r = node["r"].as!ubyte; - g = node["g"].as!ubyte; - b = node["b"].as!ubyte; - } - catch(NodeException e) - { - throw new ConstructorException("Invalid color: " ~ e.msg, start, end); - } + //If this happens, D:YAML will handle the exception and use its message + //in a YAMLException thrown when loading. + r = node["r"].as!ubyte; + g = node["g"].as!ubyte; + b = node["b"].as!ubyte; return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b); } diff --git a/dyaml/constructor.d b/dyaml/constructor.d index e0d883e..fbaaa03 100644 --- a/dyaml/constructor.d +++ b/dyaml/constructor.d @@ -34,7 +34,7 @@ import dyaml.style; * * Can be thrown by custom constructor functions. */ -class ConstructorException : YAMLException +package class ConstructorException : YAMLException { /** * Construct a ConstructorException. @@ -70,11 +70,11 @@ final class Constructor { private: ///Constructor functions from scalars. - Node.Value delegate(Mark, Mark, ref Node)[Tag] fromScalar_; + Node.Value delegate(ref Node)[Tag] fromScalar_; ///Constructor functions from sequences. - Node.Value delegate(Mark, Mark, ref Node)[Tag] fromSequence_; + Node.Value delegate(ref Node)[Tag] fromSequence_; ///Constructor functions from mappings. - Node.Value delegate(Mark, Mark, ref Node)[Tag] fromMapping_; + Node.Value delegate(ref Node)[Tag] fromMapping_; public: /** @@ -122,10 +122,14 @@ final class Constructor /** * Add a constructor function from scalar. * - * The function must take two Marks (start and end positions of - * the node in file) and a reference to Node to construct from. + * The function must take a reference to Node to construct from. * The node contains a string for scalars, Node[] for sequences and - * Node.Pair[] for mappings. + * Node.Pair[] for mappings. + * + * Any exception thrown by this function will be caught by D:YAML and + * its message will be added to a YAMLException that will also tell the + * user which type failed to construct, and position in the file. + * * The value returned by this function will be stored in the resulting node. * * Only one constructor function can be set for one tag. @@ -145,20 +149,13 @@ final class Constructor * int x, y, z; * } * - * MyStruct constructMyStructScalar(Mark start, Mark end, ref Node node) + * MyStruct constructMyStructScalar(ref Node node) * { * //Guaranteed to be string as we construct from scalar. * //!mystruct x:y:z * auto parts = node.as!string().split(":"); - * try - * { - * return MyStruct(to!int(parts[0]), to!int(parts[1]), to!int(parts[2])); - * } - * catch(Exception e) - * { - * throw new ConstructorException("Could not construct MyStruct: " ~ e.msg, - * start, end); - * } + * //If this throws, the D:YAML will handle it and throw a YAMLException. + * return MyStruct(to!int(parts[0]), to!int(parts[1]), to!int(parts[2])); * } * * void main() @@ -171,7 +168,7 @@ final class Constructor * } * -------------------- */ - void addConstructorScalar(T)(in string tag, T function(Mark, Mark, ref Node) ctor) + void addConstructorScalar(T)(in string tag, T function(ref Node) ctor) { const t = Tag(tag); auto deleg = addConstructor!T(t, ctor); @@ -195,19 +192,11 @@ final class Constructor * int x, y, z; * } * - * MyStruct constructMyStructSequence(Mark start, Mark end, ref Node node) + * MyStruct constructMyStructSequence(ref Node node) * { * //node is guaranteed to be sequence. * //!mystruct [x, y, z] - * try - * { - * return MyStruct(node[0].as!int, node[1].as!int, node[2].as!int); - * } - * catch(NodeException e) - * { - * throw new ConstructorException("Could not construct MyStruct: " ~ e.msg, - * start, end); - * } + * return MyStruct(node[0].as!int, node[1].as!int, node[2].as!int); * } * * void main() @@ -220,7 +209,7 @@ final class Constructor * } * -------------------- */ - void addConstructorSequence(T)(in string tag, T function(Mark, Mark, ref Node) ctor) + void addConstructorSequence(T)(in string tag, T function(ref Node) ctor) { const t = Tag(tag); auto deleg = addConstructor!T(t, ctor); @@ -244,19 +233,11 @@ final class Constructor * int x, y, z; * } * - * MyStruct constructMyStructMapping(Mark start, Mark end, ref Node node) + * MyStruct constructMyStructMapping(ref Node node) * { * //node is guaranteed to be mapping. * //!mystruct {"x": x, "y": y, "z": z} - * try - * { - * return MyStruct(node["x"].as!int, node["y"].as!int, node["z"].as!int); - * } - * catch(NodeException e) - * { - * throw new ConstructorException("Could not construct MyStruct: " ~ e.msg, - * start, end); - * } + * return MyStruct(node["x"].as!int, node["y"].as!int, node["z"].as!int); * } * * void main() @@ -269,7 +250,7 @@ final class Constructor * } * -------------------- */ - void addConstructorMapping(T)(in string tag, T function(Mark, Mark, ref Node) ctor) + void addConstructorMapping(T)(in string tag, T function(ref Node) ctor) { const t = Tag(tag); auto deleg = addConstructor!T(t, ctor); @@ -295,17 +276,25 @@ final class Constructor enforce((tag in *delegates!T) !is null, new Error("No constructor function for tag " ~ tag.get(), start, end)); Node node = Node(value); - static if(is(U : ScalarStyle)) + try { - return Node.rawNode((*delegates!T)[tag](start, end, node), start, tag, - style, CollectionStyle.Invalid); + static if(is(U : ScalarStyle)) + { + return Node.rawNode((*delegates!T)[tag](node), start, tag, + style, CollectionStyle.Invalid); + } + else static if(is(U : CollectionStyle)) + { + return Node.rawNode((*delegates!T)[tag](node), start, tag, + ScalarStyle.Invalid, style); + } + else static assert(false); } - else static if(is(U : CollectionStyle)) + catch(Exception e) { - return Node.rawNode((*delegates!T)[tag](start, end, node), start, tag, - ScalarStyle.Invalid, style); + throw new Error("Error constructing " ~ typeid(T).toString() + ~ ":\n" ~ e.msg, start, end); } - else static assert(false); } private: @@ -315,7 +304,7 @@ final class Constructor * Params: tag = Tag for the function to handle. * ctor = Constructor function. */ - auto addConstructor(T)(in Tag tag, T function(Mark, Mark, ref Node) ctor) + auto addConstructor(T)(in Tag tag, T function(ref Node) ctor) { assert((tag in fromScalar_) is null && (tag in fromSequence_) is null && @@ -323,10 +312,10 @@ final class Constructor "Constructor function for tag " ~ tag.get ~ " is already " "specified. Can't specify another one."); - return (Mark s, Mark e, ref Node n) + return (ref Node n) { - static if(Node.Value.allowed!T){return Node.Value(ctor(s,e,n));} - else {return Node.userValue(ctor(s,e,n));} + static if(Node.Value.allowed!T){return Node.Value(ctor(n));} + else {return Node.userValue(ctor(n));} }; } @@ -342,30 +331,30 @@ final class Constructor ///Construct a null node. -YAMLNull constructNull(Mark start, Mark end, ref Node node) +YAMLNull constructNull(ref Node node) { return YAMLNull(); } ///Construct a merge node - a node that merges another node into a mapping. -YAMLMerge constructMerge(Mark start, Mark end, ref Node node) +YAMLMerge constructMerge(ref Node node) { return YAMLMerge(); } ///Construct a boolean node. -bool constructBool(Mark start, Mark end, ref Node node) +bool constructBool(ref Node node) { static yes = ["yes", "true", "on"]; static no = ["no", "false", "off"]; string value = node.as!string().toLower(); if(yes.canFind(value)){return true;} if(no.canFind(value)) {return false;} - throw new Error("Unable to parse boolean value: " ~ value, start, end); + throw new Exception("Unable to parse boolean value: " ~ value); } ///Construct an integer (long) node. -long constructLong(Mark start, Mark end, ref Node node) +long constructLong(ref Node node) { string value = node.as!string().replace("_", ""); const char c = value[0]; @@ -375,7 +364,7 @@ long constructLong(Mark start, Mark end, ref Node node) value = value[1 .. $]; } - enforce(value != "", new Error("Unable to parse float value: " ~ value, start, end)); + enforce(value != "", new Exception("Unable to parse float value: " ~ value)); long result; try @@ -405,7 +394,7 @@ long constructLong(Mark start, Mark end, ref Node node) } catch(ConvException e) { - throw new Error("Unable to parse integer value: " ~ value, start, end); + throw new Exception("Unable to parse integer value: " ~ value); } return result; @@ -414,7 +403,7 @@ unittest { long getLong(string str) { - return constructLong(Mark(), Mark(), Node(str)); + return constructLong(Node(str)); } string canonical = "685230"; @@ -433,7 +422,7 @@ unittest } ///Construct a floating point (real) node. -real constructReal(Mark start, Mark end, ref Node node) +real constructReal(ref Node node) { string value = node.as!string().replace("_", "").toLower(); const char c = value[0]; @@ -444,7 +433,7 @@ real constructReal(Mark start, Mark end, ref Node node) } enforce(value != "" && value != "nan" && value != "inf" && value != "-inf", - new Error("Unable to parse float value: " ~ value, start, end)); + new Exception("Unable to parse float value: " ~ value)); real result; try @@ -470,7 +459,7 @@ real constructReal(Mark start, Mark end, ref Node node) } catch(ConvException e) { - throw new Error("Unable to parse float value: " ~ value, start, end); + throw new Exception("Unable to parse float value: " ~ value); } return result; @@ -484,7 +473,7 @@ unittest real getReal(string str) { - return constructReal(Mark(), Mark(), Node(str)); + return constructReal(Node(str)); } string canonical = "6.8523015e+5"; @@ -503,7 +492,7 @@ unittest } ///Construct a binary (base64) node. -ubyte[] constructBinary(Mark start, Mark end, ref Node node) +ubyte[] constructBinary(ref Node node) { string value = node.as!string; //For an unknown reason, this must be nested to work (compiler bug?). @@ -512,12 +501,12 @@ ubyte[] constructBinary(Mark start, Mark end, ref Node node) try{return Base64.decode(value.removechars("\n"));} catch(Exception e) { - throw new Error("Unable to decode base64 value: " ~ e.msg, start, end); + throw new Exception("Unable to decode base64 value: " ~ e.msg); } } catch(UtfException e) { - throw new Error("Unable to decode base64 value: " ~ e.msg, start, end); + throw new Exception("Unable to decode base64 value: " ~ e.msg); } } unittest @@ -526,12 +515,12 @@ unittest char[] buffer; buffer.length = 256; string input = cast(string)Base64.encode(test, buffer); - auto value = constructBinary(Mark(), Mark(), Node(input)); + auto value = constructBinary(Node(input)); assert(value == test); } ///Construct a timestamp (SysTime) node. -SysTime constructTimestamp(Mark start, Mark end, ref Node node) +SysTime constructTimestamp(ref Node node) { string value = node.as!string; @@ -545,7 +534,7 @@ SysTime constructTimestamp(Mark start, Mark end, ref Node node) auto matches = match(value, YMDRegexp); enforce(!matches.empty, - new Error("Unable to parse timestamp value: " ~ value, start, end)); + new Exception("Unable to parse timestamp value: " ~ value)); auto captures = matches.front.captures; const year = to!int(captures[1]); @@ -592,11 +581,11 @@ SysTime constructTimestamp(Mark start, Mark end, ref Node node) } catch(ConvException e) { - throw new Error("Unable to parse timestamp value " ~ value ~ " : " ~ e.msg, start, end); + throw new Exception("Unable to parse timestamp value " ~ value ~ " : " ~ e.msg); } catch(DateTimeException e) { - throw new Error("Invalid timestamp value " ~ value ~ " : " ~ e.msg, start, end); + throw new Exception("Invalid timestamp value " ~ value ~ " : " ~ e.msg); } assert(false, "This code should never be reached"); @@ -607,7 +596,7 @@ unittest string timestamp(string value) { - return constructTimestamp(Mark(), Mark(), Node(value)).toISOString(); + return constructTimestamp(Node(value)).toISOString(); } string canonical = "2001-12-15T02:59:43.1Z"; @@ -630,21 +619,21 @@ unittest } ///Construct a string node. -string constructString(Mark start, Mark end, ref Node node) +string constructString(ref Node node) { return node.as!string; } ///Convert a sequence of single-element mappings into a sequence of pairs. -Node.Pair[] getPairs(string type, Mark start, Mark end, Node[] nodes) +Node.Pair[] getPairs(string type, Node[] nodes) { Node.Pair[] pairs; foreach(ref node; nodes) { enforce(node.isMapping && node.length == 1, - new Error("While constructing " ~ type ~ - ", expected a mapping with single element", start, end)); + new Exception("While constructing " ~ type ~ + ", expected a mapping with single element")); pairs ~= node.as!(Node.Pair[]); } @@ -653,9 +642,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, ref Node node) +Node.Pair[] constructOrderedMap(ref Node node) { - auto pairs = getPairs("ordered map", start, end, node.as!(Node[])); + auto pairs = getPairs("ordered map", node.as!(Node[])); //TODO: the map here should be replaced with something with deterministic //memory allocation if possible. @@ -664,7 +653,7 @@ Node.Pair[] constructOrderedMap(Mark start, Mark end, ref Node node) foreach(ref pair; pairs) { enforce((pair.key in map) is null, - new Error("Duplicate entry in an ordered map", start, end)); + new Exception("Duplicate entry in an ordered map")); map[pair.key] = true; } clear(map); @@ -701,7 +690,7 @@ unittest bool hasDuplicates(Node[] nodes) { - return null !is collectException(constructOrderedMap(Mark(), Mark(), Node(nodes))); + return null !is collectException(constructOrderedMap(Node(nodes))); } assert(hasDuplicates(alternateTypes(8) ~ alternateTypes(2))); @@ -713,13 +702,13 @@ unittest } ///Construct a pairs (ordered sequence of key: value pairs allowing duplicates) node. -Node.Pair[] constructPairs(Mark start, Mark end, ref Node node) +Node.Pair[] constructPairs(ref Node node) { - return getPairs("pairs", start, end, node.as!(Node[])); + return getPairs("pairs", node.as!(Node[])); } ///Construct a set node. -Node[] constructSet(Mark start, Mark end, ref Node node) +Node[] constructSet(ref Node node) { auto pairs = node.as!(Node.Pair[]); @@ -732,7 +721,7 @@ Node[] constructSet(Mark start, Mark end, ref Node node) foreach(ref pair; pairs) { enforce((pair.key in map) is null, - new Error("Duplicate entry in a set", start, end)); + new Exception("Duplicate entry in a set")); map[pair.key] = 0; nodes ~= pair.key; } @@ -773,23 +762,23 @@ unittest } assert(null !is collectException - (constructSet(Mark(), Mark(), Node(DuplicatesShort.dup)))); + (constructSet(Node(DuplicatesShort.dup)))); assert(null is collectException - (constructSet(Mark(), Mark(), Node(noDuplicatesShort.dup)))); + (constructSet(Node(noDuplicatesShort.dup)))); assert(null !is collectException - (constructSet(Mark(), Mark(), Node(DuplicatesLong.dup)))); + (constructSet(Node(DuplicatesLong.dup)))); assert(null is collectException - (constructSet(Mark(), Mark(), Node(noDuplicatesLong.dup)))); + (constructSet(Node(noDuplicatesLong.dup)))); } ///Construct a sequence (array) node. -Node[] constructSequence(Mark start, Mark end, ref Node node) +Node[] constructSequence(ref Node node) { return node.as!(Node[]); } ///Construct an unordered map (unordered set of key: value _pairs without duplicates) node. -Node.Pair[] constructMap(Mark start, Mark end, ref Node node) +Node.Pair[] constructMap(ref Node node) { auto pairs = node.as!(Node.Pair[]); //TODO: the map here should be replaced with something with deterministic @@ -800,7 +789,7 @@ Node.Pair[] constructMap(Mark start, Mark end, ref Node node) foreach(ref pair; pairs) { enforce((pair.key in map) is null, - new Error("Duplicate entry in a map", start, end)); + new Exception("Duplicate entry in a map")); map[pair.key] = true; } return pairs; @@ -818,47 +807,23 @@ struct MyStruct int x, y, z; } -MyStruct constructMyStructScalar(Mark start, Mark end, ref Node node) +MyStruct constructMyStructScalar(ref Node node) { //Guaranteed to be string as we construct from scalar. auto parts = node.as!string().split(":"); - try - { - return MyStruct(to!int(parts[0]), to!int(parts[1]), to!int(parts[2])); - } - catch(Exception e) - { - throw new ConstructorException("Could not construct MyStruct: " ~ e.msg, - start, end); - } + return MyStruct(to!int(parts[0]), to!int(parts[1]), to!int(parts[2])); } -MyStruct constructMyStructSequence(Mark start, Mark end, ref Node node) +MyStruct constructMyStructSequence(ref Node node) { //node is guaranteed to be sequence. - try - { - return MyStruct(node[0].as!int, node[1].as!int, node[2].as!int); - } - catch(NodeException e) - { - throw new ConstructorException("Could not construct MyStruct: " ~ e.msg, - start, end); - } + return MyStruct(node[0].as!int, node[1].as!int, node[2].as!int); } -MyStruct constructMyStructMapping(Mark start, Mark end, ref Node node) +MyStruct constructMyStructMapping(ref Node node) { //node is guaranteed to be mapping. - try - { - return MyStruct(node["x"].as!int, node["y"].as!int, node["z"].as!int); - } - catch(NodeException e) - { - throw new ConstructorException("Could not construct MyStruct: " ~ e.msg, - start, end); - } + return MyStruct(node["x"].as!int, node["y"].as!int, node["z"].as!int); } unittest diff --git a/examples/constructor/main.d b/examples/constructor/main.d index 4c3d8ea..486e29e 100644 --- a/examples/constructor/main.d +++ b/examples/constructor/main.d @@ -10,13 +10,13 @@ struct Color ubyte blue; } -Color constructColorScalar(Mark start, Mark end, ref Node node) +Color constructColorScalar(ref Node node) { string value = node.as!string; if(value.length != 6) { - throw new ConstructorException("Invalid color: " ~ value, start, end); + throw new Exception("Invalid color: " ~ value); } //We don't need to check for uppercase chars this way. value = value.toLower(); @@ -26,7 +26,7 @@ Color constructColorScalar(Mark start, Mark end, ref Node node) { if(!std.ascii.isHexDigit(c)) { - throw new ConstructorException("Invalid color: " ~ value, start, end); + throw new Exception("Invalid color: " ~ value); } if(std.ascii.isDigit(c)) @@ -44,21 +44,16 @@ Color constructColorScalar(Mark start, Mark end, ref Node node) return result; } -Color constructColorMapping(Mark start, Mark end, ref Node node) +Color constructColorMapping(ref Node node) { ubyte r,g,b; //Might throw if a value is missing is not an integer, or is out of range. - try - { - r = node["r"].as!ubyte; - g = node["g"].as!ubyte; - b = node["b"].as!ubyte; - } - catch(NodeException e) - { - throw new ConstructorException("Invalid color: " ~ e.msg, start, end); - } + //If this happens, D:YAML will handle the exception and use its message + //in a YAMLException thrown when loading. + r = node["r"].as!ubyte; + g = node["g"].as!ubyte; + b = node["b"].as!ubyte; return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b); } diff --git a/examples/resolver/main.d b/examples/resolver/main.d index efbd333..65a3683 100644 --- a/examples/resolver/main.d +++ b/examples/resolver/main.d @@ -10,13 +10,13 @@ struct Color ubyte blue; } -Color constructColorScalar(Mark start, Mark end, ref Node node) +Color constructColorScalar(ref Node node) { string value = node.as!string; if(value.length != 6) { - throw new ConstructorException("Invalid color: " ~ value, start, end); + throw new Exception("Invalid color: " ~ value); } //We don't need to check for uppercase chars this way. value = value.toLower(); @@ -26,7 +26,7 @@ Color constructColorScalar(Mark start, Mark end, ref Node node) { if(!std.ascii.isHexDigit(c)) { - throw new ConstructorException("Invalid color: " ~ value, start, end); + throw new Exception("Invalid color: " ~ value); } if(std.ascii.isDigit(c)) @@ -44,21 +44,16 @@ Color constructColorScalar(Mark start, Mark end, ref Node node) return result; } -Color constructColorMapping(Mark start, Mark end, ref Node node) +Color constructColorMapping(ref Node node) { ubyte r,g,b; //Might throw if a value is missing is not an integer, or is out of range. - try - { - r = node["r"].as!ubyte; - g = node["g"].as!ubyte; - b = node["b"].as!ubyte; - } - catch(NodeException e) - { - throw new ConstructorException("Invalid color: " ~ e.msg, start, end); - } + //If this happens, D:YAML will handle the exception and use its message + //in a YAMLException thrown when loading. + r = node["r"].as!ubyte; + g = node["g"].as!ubyte; + b = node["b"].as!ubyte; return Color(cast(ubyte)r, cast(ubyte)g, cast(ubyte)b); } diff --git a/test/src/constructor.d b/test/src/constructor.d index ce2b076..97ee866 100644 --- a/test/src/constructor.d +++ b/test/src/constructor.d @@ -337,17 +337,9 @@ struct TestStruct } ///Constructor function for TestClass. -TestClass constructClass(Mark start, Mark end, ref Node node) +TestClass constructClass(ref Node node) { - try - { - return new TestClass(node["x"].as!int, node["y"].as!int, node["z"].as!int); - } - catch(NodeException e) - { - throw new ConstructorException("Error constructing TestClass (missing data members?) " - ~ e.msg, start, end); - } + return new TestClass(node["x"].as!int, node["y"].as!int, node["z"].as!int); } Node representClass(ref Node node, Representer representer) @@ -362,7 +354,7 @@ Node representClass(ref Node node, Representer representer) } ///Constructor function for TestStruct. -TestStruct constructStruct(Mark start, Mark end, ref Node node) +TestStruct constructStruct(ref Node node) { return TestStruct(to!int(node.as!string)); }