split casing and fill onto separate levels
[potlatch2.git] / org / as3yaml / YAML.as
1 /*
2  * Copyright (c) 2007 Derek Wischusen
3  * 
4  * Permission is hereby granted, free of charge, to any person obtaining a copy of 
5  * this software and associated documentation files (the "Software"), to deal in 
6  * the Software without restriction, including without limitation the rights to 
7  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
8  * of the Software, and to permit persons to whom the Software is furnished to do
9  * so, subject to the following conditions:
10  * 
11  * The above copyright notice and this permission notice shall be included in all
12  * copies or substantial portions of the Software.
13  * 
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
20  * SOFTWARE.
21  */
22
23
24 package org.as3yaml {
25
26
27 import org.idmedia.as3commons.util.ArrayList;
28 import org.idmedia.as3commons.util.Iterator;
29 import org.idmedia.as3commons.util.List;
30 import org.rxr.actionscript.io.*;
31
32 /**
33  * 
34  * This all static class provides methods for encoding and decoding YAML.  The primary methods are YAML.encode()
35  * and YAML.decode().  YAML.load() and YAML.Dump() are for advanced users.
36  * 
37  * @author wischusen
38  * 
39  */
40 public class YAML {
41     public static const DEFAULT_SCALAR_TAG : String = "tag:yaml.org,2002:str";
42     public static const DEFAULT_SEQUENCE_TAG : String = "tag:yaml.org,2002:seq";
43     public static const DEFAULT_MAPPING_TAG : String = "tag:yaml.org,2002:map";
44
45     /**
46      * @private
47      */    
48     public static var ESCAPE_REPLACEMENTS : Object = new Object();
49     
50     static: {
51     ESCAPE_REPLACEMENTS['\x00'] = "0";
52     ESCAPE_REPLACEMENTS['\u0007'] = "a";
53     ESCAPE_REPLACEMENTS['\u0008'] = "b";
54     ESCAPE_REPLACEMENTS['\u0009'] = "t";
55     ESCAPE_REPLACEMENTS['\n'] = "n";
56     ESCAPE_REPLACEMENTS['\u000B'] = "v";
57     ESCAPE_REPLACEMENTS['\u000C'] = "f";
58     ESCAPE_REPLACEMENTS['\r'] = "r";
59     ESCAPE_REPLACEMENTS['\u001B'] = "e";
60     ESCAPE_REPLACEMENTS['"'] = "\"";
61     ESCAPE_REPLACEMENTS['\\'] = "\\";
62     ESCAPE_REPLACEMENTS['\u0085'] = "N";
63     ESCAPE_REPLACEMENTS['\u00A0'] = "_";
64     }
65         
66         /**
67          * Takes an object and converts it to a YAML encoded string.
68          * 
69          * @example 
70          * 
71          * 
72          * <listing version="3.0"> 
73          * 
74          * var map : Map = new HashMap();
75          * map.put("a","1");
76          * map.put("b","2");
77          * map.put("c","3");
78          * trace(YAML.encode(map));
79          * -->
80          *   ---
81          *   a: 1
82          *   b: 2
83          *   c: 3
84          * 
85          * 
86          * var list : Array = new Array("a","b","c");
87          * trace(YAML.encode(ex));
88          * -->
89          *    --- 
90          *    - a
91          *    - b
92          *    - c
93          *
94          * 
95          * var customers : Map = new HashMap();
96          * var customer : Map = new HashMap();
97          * customers.put("customer", customer);
98          * customer.put("firstname", "Derek");
99          * customer.put("lastname", "Wischusen");
100          * customer.put("items", ["skis", "boots", "jacket"]);
101          * trace(YAML.encode(customers));
102          * --> 
103          *   --- 
104          *   customer: 
105          *     firstname: Derek
106          *     lastname: Wischusen
107          *     items: 
108          *       - skis
109          *       - boots
110          *       - jacket
111          * 
112          * // The following is an example of encoding a custom ActionScript class.
113          * 
114          * package org.as3yaml.test
115          * {
116          *              [Bindable]
117          *              public class TestActionScriptObject
118          *              {
119          *                      public var firstname : String;
120          *                      public var lastname : String;
121          *                      public var birthday : Date;
122          *                      
123          *              }
124          *      }
125          * 
126          * var testObj : TestActionScriptObject =  new TestActionScriptObject();
127          * testObj.firstname = "Derek";
128          * testObj.lastname = "Wischusen";
129          * testObj.birthday = new Date(1979, 11, 25);
130          * 
131          * trace(YAML.encode(testObj));
132          * -->
133          *   --- !actionscript/object:org.as3yaml.test.TestActionScriptObject
134          *   birthday: 1979-12-25 24:00:00 -05:00
135          *   firstname: Derek
136          *   lastname: Wischusen
137          * 
138          * </listing>
139          * 
140          * 
141          * 
142          * @param obj the object to be encoded as a YAML string.
143          * @return a YAML encoded String.
144          * 
145          */     
146         
147         public static function encode(obj : Object) : String
148         {
149                 var lst : List = new ArrayList();
150                 lst.add(obj);
151                 var yamlStr : StringWriter = new StringWriter();
152                 YAML.dump(lst, yamlStr, new DefaultYAMLFactory(), new DefaultYAMLConfig());
153                 return yamlStr.toString();
154         }
155
156     /**
157      * 
158      * Takes a YAML string an converts it to an ActionScript Object.
159          * 
160          * @example 
161          * 
162          * With the following YAML is stored in a file called myYaml.yaml
163          * 
164          * <listing version="3.0">
165          * 
166          * ---
167          *      Date: 2001-11-23 15:03:17 -5
168          *      User: ed
169          *      Fatal:
170          *        Unknown variable "bar"
171          *      Stack:
172          *        - file: TopClass.py
173          *          line: 23
174          *          code: |
175          *            x = MoreObject("345\n")
176          *        - file: MoreClass.py
177          *          line: 58
178          *          code: |-
179          *            foo = bar 
180      *
181          * 
182          * </listing>
183          * 
184          * You can load then load the YAML and decode it as follows.
185          * 
186          * <listing version="3.0">
187          *      public function loadYaml() : void
188          *  {
189          *              var loader : URLLoader =  new URLLoader();
190          *              loader.load(new URLRequest('myYaml.yaml'));
191          *              loader.addEventListener(Event.COMPLETE, onYamlLoad);
192          *  }
193          *              
194          *      public function onYamlLoad(event : Event) : void
195          *      {
196          *              var yamlMap : Dictionary = YAML.decode(event.target.data) as Dictionary; // returns a Dictionary                
197          *              
198          *      trace(yamlMap.Date);  // returns a Date object and prints: Fri Nov 23 15:03:17 GMT-0500 2001
199          *      trace(yamlMap.User);  // returns a String and prints: ed
200          *      trace(yamlMap.Fatal); // returns a String and prints: Unknown variable "bar"
201          *      trace(yamlMap.Stack); // returns an Array and prints: [object Dictionary],[object Dictionary]
202          *      trace(yamlMap.Stack[0].line);  // returns an Int and prints: 23
203          *      trace(yamlMap.Stack[0].code);  // returns a String and prints: x = MoreObject("345\n")      
204          *      }
205          *  </listing>
206          *  
207          * AS3YAML defines one custom tag: !actionscript/object:path.to.Class. This tag can be used to create custom
208          * actionscript classes from YAML. For example, if you have the following class:
209          * 
210          * <listing version="3.0">
211          * package org.as3yaml.test
212          * {
213          *              [Bindable]
214          *              public class TestActionScriptObject
215          *              {
216          *                      public var firstname : String;
217          *                      public var lastname : String;
218          *                      public var birthday : Date;
219          *                      
220          *              }
221          *      }
222          * </listing>
223          * 
224          * You can instruct AS3YAML to create an instance of this class as follows:
225          * 
226          * <listing version="3.0">
227          * var yamlObj : TestActionScriptObject = YAML.decode("--- !actionscript/object:org.as3yaml.test.TestActionScriptObject\nfirstname: Derek\nlastname: Wischusen\nbirthday: 1979-12-25\n") as TestActionScriptObject;
228          * 
229          * trace(yamlObj.firstname); // prints: Derek
230          * trace(yamlObj.lastname);  // prints: Wischusen
231          * trace(yamlObj.birthday);  // prints: Tue Dec 25 00:00:00 GMT-0500 1979
232          * </listing>
233          * 
234      * @param yaml a YAML string.
235      * @return an actionscript object. The object type will depend on the YAML. 
236      *            The most common return types are Dictionary or Array.
237      * 
238      */    
239     public static function decode (yaml : String) : Object
240     {
241         
242         var cfg: DefaultYAMLConfig = new DefaultYAMLConfig();
243                 var obj : Object = YAML.load(yaml, 
244                                                                          new DefaultYAMLFactory(),
245                                                                          cfg);
246                 return obj;
247     }
248
249     public static function dump (data : List, output : StringWriter, fact : YAMLFactory, cfg : YAMLConfig) : void 
250     {
251         var serializer : Serializer = fact.createSerializer(fact.createEmitter(output,cfg),fact.createResolver(),cfg);
252         try {
253             serializer.open();
254             var r : Representer = fact.createRepresenter(serializer,cfg);
255             for(var iter : Iterator = data.iterator(); iter.hasNext();) {
256                 r.represent(iter.next());
257             }
258         } catch(e : Error) {
259             throw new YAMLException(e.getStackTrace());
260         } finally {
261             try { 
262                 serializer.close(); 
263             } catch(e : Error) {/*Nothing to do in this situation*/}
264         }
265     }
266
267     public static function load(io : String, fact : YAMLFactory, cfg : YAMLConfig) : Object 
268     {
269         var ctor : Constructor = fact.createConstructor(fact.createComposer(fact.createParser(fact.createScanner(io),cfg),fact.createResolver()));
270         if(ctor.checkData()) {
271             return ctor.getData();
272         } else {
273             return null;
274         }
275     }
276     
277 }
278 }