diff --git a/lib/yaml/ChangeLog.txt b/lib/yaml/ChangeLog.txt new file mode 100644 index 000000000..026f548a5 --- /dev/null +++ b/lib/yaml/ChangeLog.txt @@ -0,0 +1,47 @@ +--- 2009-10-04 Osamu TAKEUCHI +Alpha release of YamlSerializer as 0.9.0.2 + +* All "_"s in integer and floating point values are neglected + to accommodate the !!int and !!float encoding. +* YamlConfig.DontUseVerbatimTag is added but the default value is set false. + Note that ! is much human friendly than !System.Int32%5B%2C%5D. +* Equality of YamlNode with an unknown tag is evaluated by identity, + while that of !!map and !!seq node is still evaluated by YAML's standard. + Note that equality of !!map and !!seq are different from that of object[] + and Dictionary. +* YamlConfig.OmitTagForRootNode was added. Fixed issue #2850. +* Serialize Dictionary to !!map. Fixed #2891. +* Modified [126-130] ns-plain-???, [147] c-ns-flow-map-separate-value(n,c) + to accommodate revision 2009-10-01 +* Omit !< > if Tag contains only ns-tag-char, Fixed issue #2813 + +--- 2009-09-23 Osamu TAKEUCHI +Alpha release of YamlSerializer as 0.9.0.1 + +* Removed TODO's for reporting bugs in YAML spec that are done. +* Fixed assembly copyright. +* !!merge is supported. Fixed issue#2605. +* Read-only class-type member with no child members are omitted when + serializing. Fixed issue#2599. +* Culture for TypeConverter is set to be CultureInfo.InvariantCulture. + Fixed issue #2629. +* To fix Issue#2631 + * Field names and property names are always presented as simple texts. + * When deserializing, we can not avoid the parser parses some spacial + names to !!bool and !!null. Such non-text nodes are converted to + texts at construction stage. +* To fix issue#2663 + * Hash code stored in a mapping node is now updated when the a key node's + content is changed. + * Hash code and equality became independent on the order of keys in a + mapping node. + * A mapping node checks for duplicated keys every time the node content + is changed. + * Test results are changed because some of them are dependent on the hash + key order. +* The current equality evaluation is too strict, probably needs some adjustment. +* NativeObject property was added to YamlScalar. +* YamlScalar's equality is evaluated by comparing NativeObject. + +--- 2009-09-11 Osamu TAKEUCHI +First release of YamlSerializer as 0.9.0.0 diff --git a/lib/yaml/Readme.txt b/lib/yaml/Readme.txt new file mode 100644 index 000000000..e6152eb5e --- /dev/null +++ b/lib/yaml/Readme.txt @@ -0,0 +1,39 @@ +YamlSerializer 0.9.0.2 (2009-10-04) Osamu TAKEUCHI + +Description: + A library that serialize / deserialize C# native objects into YAML1.2 text. + +Development environment: + Visual C# 2008 Express Edition + Sandcastle (2008-05-29) + SandcastleBuilder 1.8.0.2 + HTML Help workshop 4.74.8702 + NUnit 2.5.0.9122 + TestDriven.NET 2.0 + +Support web page: + http://yamlserializer.codeplex.com/ + +License: + YamlSerializer is distributed under the MIT license as following: + +--- +The MIT License (MIT) +Copyright (c) 2009 Osamu TAKEUCHI + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in the +Software without restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/yaml/YAML Serializer.chm b/lib/yaml/YAML Serializer.chm new file mode 100644 index 000000000..34162f2e5 Binary files /dev/null and b/lib/yaml/YAML Serializer.chm differ diff --git a/lib/yaml/YamlSerializer.XML b/lib/yaml/YamlSerializer.XML new file mode 100644 index 000000000..c083f3957 --- /dev/null +++ b/lib/yaml/YamlSerializer.XML @@ -0,0 +1,3770 @@ + + + + YamlSerializer + + + + + Converts various types to / from string.
+ I don't remember why this class was needed.... +
+ + + object obj = GetObjectToConvert(); + + // Check if the type has [TypeConverter] attribute. + if( EasyTypeConverter.IsTypeConverterSpecified(type) ) { + + // Convert the object to string. + string s = EasyTypeConverter.ConvertToString(obj); + + // Convert the string to an object of the spific type. + object restored = EasyTypeConverter.ConvertFromString(s, type); + + Assert.AreEqual(obj, restored); + + } + + +
+ + + Converts C# object to YamlNode + + + + object obj; + YamlNode node = YamlRepresenter.ObjectToNode(obj); + + + + + + Implements utility functions to instantiating YamlNode's + + + + var node_tree = seq( + str("abc"), + str("def"), + map( + str("key"), str("value"), + str("key2"), seq( str("value2a"), str("value2b") ) + ), + str("2"), // !!str + str("!!int", "2") + ); + + string yaml = node_tree.ToYaml(); + + // %YAML 1.2 + // --- + // - abc + // - def + // - key: value + // key2: [ value2a, value2b ] + // - "2" # !!str + // - 2 # !!int + // ... + + + + + + Create a scalar node. Tag is set to be "!!str". + + + + var node_tree = seq( + str("abc"), + str("def"), + map( + str("key"), str("value"), + str("key2"), seq( str("value2a"), str("value2b") ) + ), + str("2"), // !!str + str("!!int", "2") + ); + + string yaml = node_tree.ToYaml(); + + // %YAML 1.2 + // --- + // - abc + // - def + // - key: value + // key2: [ value2a, value2b ] + // - "2" # !!str + // - 2 # !!int + // ... + + + Value for the scalar node. + Created scalar node. + + + + Create a scalar node. + + Tag for the scalar node. + Value for the scalar node. + Created scalar node. + + + + Create a sequence node. Tag is set to be "!!seq". + + Child nodes. + Created sequence node. + + + + Create a sequence node. + + Child nodes. + Tag for the seuqnce. + Created sequence node. + + + + Create a mapping node. Tag is set to be "!!map". + + Sequential list of key/value pairs. + Created mapping node. + + + + Create a mapping node. + + Sequential list of key/value pairs. + Tag for the mapping. + Created mapping node. + + + + When reports syntax error by exception, this class is thrown. + + Sytax errors can also be reported by simply returing false with giving some warnings. + + + + + Initialize an instance of + + Error message. + + + + Base class to implement a parser class. + + It allows not very efficient but easy implementation of a text parser along + with a parameterized BNF productions. + + Parser specific state structure. + + + + Parse the using the + as the starting rule. + + Starting rule. + Text to be parsed. + + + + + Gets / sets source text to be parsed. + While parsing, this variable will not be changed. + The current position to be read by parser is represented by the field . + Namely, the next character to be read is text[p]. + + + + + The current reading position. + + The next character to be read by the parser is text[p]. + + Increase to reduce some part of source text . + + The current position is automatically reverted at rewinding. + + + Example to show how to reduce BNF reduction rule of ( "t" "e" "x" "t" ). + + return RewindUnless(()=> + text[p++] == 't' && + text[p++] == 'e' && + text[p++] == 'x' && + text[p++] == 't' + ); + + + + + + Use this variable to build some string data from source text. + + It will be automatically reverted at rewinding. + + + + + Individual-parser-specific state object. + + It will be automatically reverted at rewinding. + + If some action, in addition to simply restore the value of the state object, + is needed to recover the previous state, override + method. + + + + + Initialize , which represents line number to + start position of each line list. + + + + + Line number to start position list. + + + + + Reporting syntax error by throwing . + + template for the error message. + parameters if required + Because it throw exception, nothing will be returned in reality. + + + + Give warning if is true. + + By default, the warning will not be shown / stored to anywhere. + To show or log the warning, override . + + + + return + SomeObsoleteReductionRule() && + WarningIf( + context != Context.IndeedObsolete, + "Obsolete"); + + + If true, warning is given; otherwize do nothing. + template for the warning message. + parameters if required + Always true. + + + + Give warning if is false. + + By default, the warning will not be shown / stored to anywhere. + To show or log the warning, override . + + + + return + SomeObsoleteReductionRule() && + WarningUnless( + context != Context.NotObsolete, + "Obsolete"); + + + If false, warning is given; otherwize do nothing. + template for the warning message. + parameters if required + Always true. + + + + Give warning. + + By default, the warning will not be shown / stored to anywhere. + To show or log the warning, override . + + + + return + SomeObsoleteReductionRule() && + Warning("Obsolete"); + + + template for the warning message. + parameters if required + Always true. + + + + Invoked when warning was given while parsing. + + Override this method to display / store the warning. + + Warning message. + + + + Represents EBNF operator of "join", i.e. serial appearence of several rules. + + + This recoveres , , + when does not return true. + + If any specific operation is needed for rewinding, in addition to simply + recover the value of , override . + + If false is returned, the parser status is rewound. + true if returned true; otherwise false. + + name ::= first-name middle-name? last-name + + bool Name() + { + return RewindUnless(()=> + FirstName() && + Optional(MiddleName) && + LastName() + ); + } + + + + + + This method is called just after recovers . + Override it to do any additional operation for rewinding. + + + + + Represents EBNF operator of "*". + + Reduction rule to be repeated. + Always true. + + lines-or-empty ::= line* + + bool LinesOrEmpty() + { + return + Repeat(Line); + } + + + lines-or-empty ::= (text line-break)* + Note: Do not forget if several + rules are sequentially appears in operator. + + bool LinesOrEmpty() + { + return + Repeat(()=> + RewindUnless(()=> + Text() && + LineBreak() + ) + ); + } + + + + + + Represents EBNF operator of "+". + + Reduction rule to be repeated. + true if the rule matches; otherwise false. + + lines ::= line+ + + bool Lines() + { + return + Repeat(Line); + } + + + + lines ::= (text line-break)+ + + Note: Do not forget RewindUnless in Repeat operator. + + bool Lines() + { + return + Repeat(()=> + RewindUnless(()=> + Text() && + LineBreak() + ) + ); + } + + + + + + Represents n times repeatition. + + + four-lines ::= (text line-break){4} + + Note: Do not forget if several + rules are sequentially appears in operator. + + bool FourLines() + { + return + Repeat(4, ()=> + RewindUnless(()=> + Text() && + LineBreak() + ) + ); + } + + + Repetition count. + Reduction rule to be repeated. + true if the rule matches; otherwise false. + + + + Represents at least , at most times repeatition. + + + google ::= "g" "o"{2,100} "g" "l" "e" + Note: Do not forget if several + rules are sequentially appears in operator. + + bool Google() + { + return + RewindUnless(()=> + text[p++] == 'g' && + Repeat(2, 100, + RewindUnless(()=> + text[p++] == 'o' + ) + ) + text[p++] == 'g' && + text[p++] == 'l' && + text[p++] == 'e' + ); + } + + + Minimum repetition count. Negative value is treated as 0. + Maximum repetition count. Negative value is treated as positive infinity. + Reduction rule to be repeated. + true if the rule matches; otherwise false. + + + + Represents BNF operator "?". + + + file ::= header? body footer? + + Note: Do not forget if several + rules are sequentially appears in operator. + + bool File() + { + return + Optional(Header()) && + Body() && + Optional(Footer()); + } + + + Reduction rule that is optional. + Always true. + + + + Represents BNF operator "?" (WITH rewinding wrap). + + + file = header? body footer? + + Note: Do not forget if several + rules are sequentially appears in operator. + + bool File() + { + return + Optional(Header) && + Body() && + Optional(Footer); + } + + + Reduction rule that is optional. + Always true. + + + + Reduce one character if it is a member of the specified character set. + + Acceptable character set. + true if the rule matches; otherwise false. + + alpha ::= [A-Z][a-z]
+ num ::= [0-9]
+ alpha-num :: alpha | num
+ word ::= alpha ( alpha-num )*
+ + Func<char,bool> Alpha = Charset( c => + ( 'A' <= c && c <= 'Z' ) || + ( 'a' <= c && c <= 'z' ) + ); + Func<char,bool> Num = Charset( c => + '0' <= c && c <= '9' + ); + Func<char,bool> AlphaNum = Charset( c => + Alpha(c) || Num(c) + ); + bool Word() + { + return + Accept(Alpha) && + Repeat(AlphaNum); + // No need for RewindUnless + } + +
+
+ + + Accepts a character 'c'. + + It can be also represented by text[p++] == c wrapped by . + + The character to be accepted. + true if the rule matches; otherwise false. + + YMCA ::= "Y" "M" "C" "A" + + bool YMCA() + { + return + RewindUnless(()=> + Accept('Y') && + Accept('M') && + Accept('C') && + Accept('A') + ); + } + + -or- + + bool YMCA() + { + return + RewindUnless(()=> + text[p++] == 'Y' && + text[p++] == 'M' && + text[p++] == 'C' && + text[p++] == 'A' + ); + } + + + + + + Accepts a sequence of characters. + + Sequence of characters to be accepted. + true if the rule matches; otherwise false. + + YMCA ::= "Y" "M" "C" "A" + + bool YMCA() + { + return + Accept("YMCA"); + } + + + + + + Represents sequence of characters. + + Sequence of characters to be accepted. + true if the rule matches; otherwise false. + + + + Represents BNF operator of "*". + + Character set to be accepted. + Always true. + + + + Represents BNF operator of "+". + + Character set to be accepted. + true if the rule matches; otherwise false. + + + + Represents n times repetition of characters. + + Character set to be accepted. + Repetition count. + true if the rule matches; otherwise false. + + + + Represents at least min times, at most max times + repetition of characters. + + Character set to be accepted. + Minimum repetition count. Negative value is treated as 0. + Maximum repetition count. Negative value is treated as positive infinity. + true if the rule matches; otherwise false. + + + + Represents BNF operator "?". + + Character set to be accepted. + Always true. + + + + Builds a performance-optimized table-based character set definition from a simple + but slow comparison-based definition. + + By default, the character table size is 0x100, namely only the characters of [\0-\xff] are + judged by using a character table and others are by the as-given slow comparisn-based definitions. + + To have maximized performance, locate the comparison for non-table based judgement first + in the definition as the example below. + + Use form to explicitly + specify the table size. + + This sample shows how to build a character set delegate. + + static class YamlCharsets: Charsets + { + Func<char, bool> cPrintable; + Func<char, bool> sWhite; + + static YamlCharsets() + { + cPrintable = CacheResult(c => + /* ( 0x10000 < c && c < 0x110000 ) || */ + ( 0xe000 <= c && c <= 0xfffd ) || + ( 0xa0 <= c && c <= 0xd7ff ) || + ( c < 0x100 && ( // to improve performance + c == 0x85 || + ( 0x20 <= c && c <= 0x7e ) || + c == 0x0d || + c == 0x0a || + c == 0x09 + ) ) + ); + sWhite = CacheResult(c => + c < 0x100 && ( // to improve performance + c == '\t' || + c == ' ' + ) + ); + } + } + + A simple but slow comparison-based definition of the charsert. + A performance-optimized table-based delegate built from the given . + + + + Builds a performance-optimized table-based character set definition from a simple + but slow comparison-based definition. + + Characters out of the table are judged by the as-given slow comparisn-based + definitions. + + So, to have maximized performance, locate the comparison for non-table based + judgement first in the definition as the example below. + + This sample shows how to build a character set delegate. + + static class YamlCharsets: Charsets + { + Func<char, bool> cPrintable; + Func<char, bool> sWhite; + + static YamlCharsets() + { + cPrintable = CacheResult(c => + /* ( 0x10000 < c && c < 0x110000 ) || */ + ( 0xe000 <= c && c <= 0xfffd ) || + ( 0xa0 <= c && c <= 0xd7ff ) || + ( c < 0x100 && ( // to improve performance + c == 0x85 || + ( 0x20 <= c && c <= 0x7e ) || + c == 0x0d || + c == 0x0a || + c == 0x09 + ) ) + ); + sWhite = CacheResult(c => + c < 0x100 && ( // to improve performance + c == '\t' || + c == ' ' + ) + ); + } + } + + Character table size. + A simple but slow comparison-based definition of the charsert. + A performance-optimized table-based delegate built from the given . + + + + Saves a part of the source text that is reduced in the . + If the rule does not match, nothing happends. + + Reduction rule to match. + If the matches, + the part of the source text reduced in the is set; + otherwise String.Empty is set. + true if matches; otherwise false. + + + + Saves a part of the source text that is reduced in the + and append it to . + If the rule does not match, nothing happends. + + Reduction rule to match. + true if matches; otherwise false. + + + + Saves a part of the source text that is reduced in the . + If the rule does not match, nothing happends. + + Reduction rule to match. + If matches, this delegate is invoked + with the part of the source text that is reduced in the + as the parameter. Do any action in the delegate. + true if matches; otherwise false. + + + bool SomeRule() + { + return + Save(()=> SubRule(), s => MessageBox.Show(s)); + } + + + + + Execute some action. + + Action to be done. + Always true. + + + bool SomeRule() + { + return + SubRule() && + Action(()=> do_some_action()); + } + + + + + Report error by throwing when the does not match. + + Some reduction rule that must match. + Error message as template + Parameters for template + Always true; otherwise an exception thrown. + + + + Report error by throwing when the does not match. + + Some reduction rule that must match. + Error message as template + Parameters for template + Always true; otherwise an exception is thrown. + + + + Report error by throwing when the does not match + and an additional condition is true. + + Some reduction rule that must match. + Additional condition: if this parameter is false, + rewinding occurs, instead of throwing exception. + Error message as template + Parameters for template + true if the reduction rule matches; otherwise false. + + + + Report error by throwing when is true. + + True to throw exception. + Error message as template + Parameters for template + Always true. + + + + Assign var = value and return true; + + Type of the variable and value. + Variable to be assigned. + Value to be assigned. + Always true. + + + + Get current position represented by raw and column. + + + + + Represents a position in a multiline text. + + + + + Raw in a text. + + + + + Column in a text. + + + + + Validates a text as a global tag in YAML. + + RFC4151 - The 'tag' URI Scheme> + + + + + Validates a text as a global tag in YAML. + + A candidate for a global tag in YAML. + True if is a valid global tag. + + + + Not used in this parser + + + + + Dictionary that automatically rehash when the content of a key is changed. + Keys of this dictionary must implement . + It also call back item addition and removal by and + events. + + Type of key. Must implements . + Type of value. + + + + A dictionary that returns or + from hash code. This is the main repository that stores the pairs. + If there are several entries that have same hash code for thir keys, + a is stored to hold all those entries. + Otherwise, a is stored. + + + + + A dictionary that returns hash code from the key reference. + The key must be the instance that + to one exsisting in the dictionary. + + + We store the hashes correspoinding to each key. So that when rehash, + we can find old hash code to quickly find the entry for the key. + It is also used to remember the number of keys exists in the dictionary. + + + + + Recalc hash key of the . + + The key to be rehash. The key must be the instance that + to one exsisting in the dictionary. + + + + Try to find entry for key (and value). + + key to find + if true, value matters + value to find + key not found + hash hit one entry and key found + hash hit several entries and key found + + + + Try to find entry for key (and value). + + key to find + if true, value matters + value to find + hash not found + hash hit one entry but key not found + hash hit one entry and key found + hash hit several entries but key not found + hash hit several entries and key found + + + + Collection that is readonly and invalidated when an item is + added to or removed from the dictionary. + + + + + A text parser for
+ YAML Ain’t Markup Language (YAML™) Version 1.2
+ 3rd Edition (2009-07-21)
+ http://yaml.org/spec/1.2/spec.html
+ + This class parse a YAML document and compose representing graph. +
+ + + string yaml = LoadYamlSource(); + YamlParser parser = new YamlParser(); + Node[] result = null; + try { + result = parser.Parse(yaml); + ... + // you can reuse parser as many times you want + ... + + } catch( ParseErrorException e ) { + MessageBox.Show(e.Message); + } + if(result != null) { + ... + + } + + + + Currently, this parser violates the YAML 1.2 specification in the following points. + - line breaks are not normalized. + - omission of the final line break is allowed in plain / literal / folded text. + - ':' followed by ns-indicator is excluded from ns-plain-char. + +
+ + + Initialize a YAML parser. + + + + + Parse YAML text and returns a list of . + + YAML text to be parsed. + A list of parsed from the given text + + + + Parse YAML text and returns a list of . + + YAML text to be parsed. + YAML Configuration to be used in parsing. + A list of parsed from the given text + + + + Add message in property. + + + + + + Invoked when unknown directive is found in YAML document. + + Name of the directive + Parameters for the directive + + + + Invoked when YAML directive is found in YAML document. + + Given version + + + + rewinding action + + + + + set status.tag with tag resolution + + + + + + + + set status.tag with verbatim tag value + + verbatim tag + + + + + Used when the parser resolves a tag for a scalar node from its value. + + New resolution rules can be add before calling method. + + + + + [105] + + + + + [106] + + + + + Warnings that are made while parsing a YAML text. + This property is cleared by new call for method. + + + + + additional fields to be rewound + + + + + tag for the next value (will be cleared when the next value is created) + + + + + anchor for the next value (will be cleared when the next value is created) + + + + + current value + + + + + anchor rewinding position + + + + + [22] + + + + + [23] + + + + + Construct YAML node tree that represents a given C# object. + + + + + Construct YAML node tree that represents a given C# object. + + to be converted to C# object. + to customize serialization. + + + + + Construct YAML node tree that represents a given C# object. + + to be converted to C# object. + Expected type for the root object. + to customize serialization. + + + + + Add string class two methods: .UriEscape(), .UriUnescape() + + Charset that is not escaped is represented NonUriChar member. + + NonUriChar = new Regex(@"[^0-9A-Za-z\-_.!~*'()\\;/?:@&=$,\[\]]"); + + + + + Escape the string in URI encoding format. + + String to be escaped. + Escaped string. + + + + Escape the string in URI encoding format. + + String to be escaped. + Escaped string. + + + + Unescape the string escaped in URI encoding format. + + String to be unescape. + Unescaped string. + + + + Escape / Unescape string in URI encoding format + + Charset that is not escaped is represented NonUriChar member. + + NonUriChar = new Regex(@"[^0-9A-Za-z\-_.!~*'()\\;/?:@&=$,\[\]]"); + + + + + Reset(); + SetupDefaultTagPrefixes(); + Add(tag_handle, tag_prefix); + verbatim_tag = Resolve(tag_handle, tag_name); + + + + + Converts YamlNode tree into yaml text. + + + + YamlNode node; + YamlPresenter.ToYaml(node); + + YamlNode node1; + YamlNode node2; + YamlNode node3; + YamlPresenter.ToYaml(node1, node2, node3); + + + + + + + object に代入されたクラスや構造体のメンバーに、リフレクションを + 解して簡単にアクセスできるようにしたクラス + + アクセス方法をキャッシュするので、繰り返し使用する場合に高速化が + 期待できる + + + + + Caches ObjectMemberAccessor instances for reuse. + + + + + + 指定した型へのアクセス方法を表すインスタンスを返す + キャッシュに存在すればそれを返す + キャッシュに存在しなければ新しく作って返す + 作った物はキャッシュされる + + クラスまたは構造体を表す型情報 + + + + + メンバ名と Accessor のペアを巡回する + + + + + + メンバへの読み書きを行うことができる + + オブジェクト + メンバの名前 + + + + + Configuration to customize YAML serialization. + An instance of this class can be passed to the serialization + methods, such as YamlNode.ToYaml(YamlConfig) and + YamlNode.FromYaml(Stream,YamlConfig) or + it can be assigned to YamlNode.DefaultConfig. + + + + + + If true, all line breaks in the node value are normalized into "\r\n" + (= ) when serialize and line breaks + that are not escaped in YAML stream are normalized into "\n" + (= . + If false, the line breaks are preserved. Setting this option false violates + the YAML specification but sometimes useful. The default is true. + + + The YAML sepcification requires a YAML parser to normalize every line break that + is not escaped in a YAML stream, into a single line feed "\n" when it parse a YAML stream. + But this is not convenient in some cases, especially under Windows environment, where + the system default line break + is "\r\n" instead of "\n". + + This library provides two workarounds for this problem. + One is setting false. It disables the line break + normalization. The line breaks are serialized into a YAML stream as is and + those in the YAML stream are deserialized as is. + Another is setting "\r\n". Then, the YAML parser + normalizes all line breaks into "\r\n" instead of "\n". + Note that although these two options are useful in some cases, + they makes the YAML parser violate the YAML specification. + + + + // A string containing line breaks "\n\r" and "\r". + YamlNode node = "a\r\n b\rcde"; + + // By default conversion, line breaks are escaped in a double quoted string. + var yaml = node.ToYaml(); + // %YAML 1.2 + // --- + // "a\r\n\ + // \ b\r\ + // cde" + // ... + + // "%YAML 1.2\r\n---\r\n\"a\\r\\n\\\r\n\ b\\r\\\r\ncde\"\r\n...\r\n" + + // Such a YAML stream is not pretty but is capable to preserve + // original line breaks even when the line breaks of the YAML stream + // are changed (for instance, by some editor) between serialization + // and deserialization. + var restored = YamlNode.FromYaml(yaml)[0]; + // "a\r\n b\rcde" // equivalent to the original + + yaml = yaml.Replace("\r\n", "\n").Replace("\r", "\n"); + var restored = YamlNode.FromYaml(yaml)[0]; + // "a\r\n b\rcde" // still equivalent to the original + + // By setting ExplicitlyPreserveLineBreaks false, the output becomes + // much prettier. + YamlNode.DefaultConfig.ExplicitlyPreserveLineBreaks = false; + yaml = node.ToYaml(); + // %YAML 1.2 + // --- + // |-2 + // a + // b + // cde + // ... + + // line breaks are nomalized to "\r\n" (= YamlNode.DefaultConfig.LineBreakForOutput) + // "%YAML 1.2\r\n---\r\n|-2\r\n a\r\n b\r\ncde\r\n...\r\n" + + // line breaks are nomalized to "\n" (= YamlNode.DefaultConfig.LineBreakForInput) + var restored = YamlNode.FromYaml(yaml)[0]; + // "a\n b\ncde" + + + // Disable line break normalization. + YamlNode.DefaultConfig.NormalizeLineBreaks = false; + yaml = node.ToYaml(); + + // line breaks are not nomalized + // "%YAML 1.2\r\n---\r\n|-2\r\n a\r\n b\rcde\r\n...\r\n" + + // Unless line breaks in YAML stream is preserved, original line + // breaks can be restored. + restored = YamlNode.FromYaml(yaml)[0]; + // "a\r\n b\rcde" // equivalent to the original + + yaml = yaml.Replace("\r\n", "\n").Replace("\r", "\n"); + restored = YamlNode.FromYaml(yaml)[0]; + // "a\n b\ncde" // original line breaks are lost + + + + + + If true, all s whose text expression contains line breaks + will be presented as double quoted texts, where the line break characters are escaped + by back slash as "\\n" and "\\r". The default is true. + + + The escaped line breaks makes the YAML stream hard to read, but is required to + prevent the line break characters be normalized by the YAML parser; the YAML + sepcification requires a YAML parser to normalize all line breaks that are not escaped + into a single line feed "\n" when it parse a YAML source. + + + If the preservation of line breaks are not required, set this value false. + + + Then, whenever it is possible, the s are presented + as literal style text, where the line breaks are not escaped. This results in + a much prettier output in the YAML stream. + + + + // A string containing line breaks "\n\r" and "\r". + YamlNode node = "a\r\n b\rcde"; + + // By default conversion, line breaks are escaped in a double quoted string. + var yaml = node.ToYaml(); + // %YAML 1.2 + // --- + // "a\r\n\ + // \ b\r\ + // cde" + // ... + + // "%YAML 1.2\r\n---\r\n\"a\\r\\n\\\r\n\ b\\r\\\r\ncde\"\r\n...\r\n" + + // Such a YAML stream is not pretty but is capable to preserve + // original line breaks even when the line breaks of the YAML stream + // are changed (for instance, by some editor) between serialization + // and deserialization. + var restored = YamlNode.FromYaml(yaml)[0]; + // "a\r\n b\rcde" // equivalent to the original + + yaml = yaml.Replace("\r\n", "\n").Replace("\r", "\n"); + var restored = YamlNode.FromYaml(yaml)[0]; + // "a\r\n b\rcde" // still equivalent to the original + + // By setting ExplicitlyPreserveLineBreaks false, the output becomes + // much prettier. + YamlNode.DefaultConfig.ExplicitlyPreserveLineBreaks = false; + yaml = node.ToYaml(); + // %YAML 1.2 + // --- + // |-2 + // a + // b + // cde + // ... + + // line breaks are nomalized to "\r\n" (= YamlNode.DefaultConfig.LineBreakForOutput) + // "%YAML 1.2\r\n---\r\n|-2\r\n a\r\n b\r\ncde\r\n...\r\n" + + // line breaks are nomalized to "\n" (= YamlNode.DefaultConfig.LineBreakForInput) + var restored = YamlNode.FromYaml(yaml)[0]; + // "a\n b\ncde" + + + // Disable line break normalization. + YamlNode.DefaultConfig.NormalizeLineBreaks = false; + yaml = node.ToYaml(); + + // line breaks are not nomalized + // "%YAML 1.2\r\n---\r\n|-2\r\n a\r\n b\rcde\r\n...\r\n" + + // Unless line breaks in YAML stream is preserved, original line + // breaks can be restored. + restored = YamlNode.FromYaml(yaml)[0]; + // "a\r\n b\rcde" // equivalent to the original + + yaml = yaml.Replace("\r\n", "\n").Replace("\r", "\n"); + restored = YamlNode.FromYaml(yaml)[0]; + // "a\n b\ncde" // original line breaks are lost + + + + + + Line break to be used when is presented in YAML stream. + "\r", "\r\n", "\n" are allowed. "\r\n" is defalut. + + + + // A string containing line breaks "\n\r" and "\r". + YamlNode node = "a\r\n b\rcde"; + + // By default conversion, line breaks are escaped in a double quoted string. + var yaml = node.ToYaml(); + // %YAML 1.2 + // --- + // "a\r\n\ + // \ b\r\ + // cde" + // ... + + // "%YAML 1.2\r\n---\r\n\"a\\r\\n\\\r\n\ b\\r\\\r\ncde\"\r\n...\r\n" + + // Such a YAML stream is not pretty but is capable to preserve + // original line breaks even when the line breaks of the YAML stream + // are changed (for instance, by some editor) between serialization + // and deserialization. + var restored = YamlNode.FromYaml(yaml)[0]; + // "a\r\n b\rcde" // equivalent to the original + + yaml = yaml.Replace("\r\n", "\n").Replace("\r", "\n"); + var restored = YamlNode.FromYaml(yaml)[0]; + // "a\r\n b\rcde" // still equivalent to the original + + // By setting ExplicitlyPreserveLineBreaks false, the output becomes + // much prettier. + YamlNode.DefaultConfig.ExplicitlyPreserveLineBreaks = false; + yaml = node.ToYaml(); + // %YAML 1.2 + // --- + // |-2 + // a + // b + // cde + // ... + + // line breaks are nomalized to "\r\n" (= YamlNode.DefaultConfig.LineBreakForOutput) + // "%YAML 1.2\r\n---\r\n|-2\r\n a\r\n b\r\ncde\r\n...\r\n" + + // line breaks are nomalized to "\n" (= YamlNode.DefaultConfig.LineBreakForInput) + var restored = YamlNode.FromYaml(yaml)[0]; + // "a\n b\ncde" + + + // Disable line break normalization. + YamlNode.DefaultConfig.NormalizeLineBreaks = false; + yaml = node.ToYaml(); + + // line breaks are not nomalized + // "%YAML 1.2\r\n---\r\n|-2\r\n a\r\n b\rcde\r\n...\r\n" + + // Unless line breaks in YAML stream is preserved, original line + // breaks can be restored. + restored = YamlNode.FromYaml(yaml)[0]; + // "a\r\n b\rcde" // equivalent to the original + + yaml = yaml.Replace("\r\n", "\n").Replace("\r", "\n"); + restored = YamlNode.FromYaml(yaml)[0]; + // "a\n b\ncde" // original line breaks are lost + + + + + + The YAML parser normalizes line breaks in a YAML stream to this value. + + "\n" is default, and is the only valid value in the YAML specification. "\r" and "\r\n" are + allowed in this library for convenience. + + To suppress normalization of line breaks by YAML parser, set + false, though it is also violate the YAML specification. + + + The YAML sepcification requires a YAML parser to normalize every line break that + is not escaped in a YAML stream, into a single line feed "\n" when it parse a YAML stream. + But this is not convenient in some cases, especially under Windows environment, where + the system default line break + is "\r\n" instead of "\n". + + This library provides two workarounds for this problem. + One is setting false. It disables the line break + normalization. The line breaks are serialized into a YAML stream as is and + those in the YAML stream are deserialized as is. + Another is setting "\r\n". Then, the YAML parser + normalizes all line breaks into "\r\n" instead of "\n". + Note that although these two options are useful in some cases, + they makes the YAML parser violate the YAML specification. + + + + // A string containing line breaks "\n\r" and "\r". + YamlNode node = "a\r\n b\rcde"; + + // By default conversion, line breaks are escaped in a double quoted string. + var yaml = node.ToYaml(); + // %YAML 1.2 + // --- + // "a\r\n\ + // \ b\r\ + // cde" + // ... + + // "%YAML 1.2\r\n---\r\n\"a\\r\\n\\\r\n\ b\\r\\\r\ncde\"\r\n...\r\n" + + // Such a YAML stream is not pretty but is capable to preserve + // original line breaks even when the line breaks of the YAML stream + // are changed (for instance, by some editor) between serialization + // and deserialization. + var restored = YamlNode.FromYaml(yaml)[0]; + // "a\r\n b\rcde" // equivalent to the original + + yaml = yaml.Replace("\r\n", "\n").Replace("\r", "\n"); + var restored = YamlNode.FromYaml(yaml)[0]; + // "a\r\n b\rcde" // still equivalent to the original + + // By setting ExplicitlyPreserveLineBreaks false, the output becomes + // much prettier. + YamlNode.DefaultConfig.ExplicitlyPreserveLineBreaks = false; + yaml = node.ToYaml(); + // %YAML 1.2 + // --- + // |-2 + // a + // b + // cde + // ... + + // line breaks are nomalized to "\r\n" (= YamlNode.DefaultConfig.LineBreakForOutput) + // "%YAML 1.2\r\n---\r\n|-2\r\n a\r\n b\r\ncde\r\n...\r\n" + + // line breaks are nomalized to "\n" (= YamlNode.DefaultConfig.LineBreakForInput) + var restored = YamlNode.FromYaml(yaml)[0]; + // "a\n b\ncde" + + + // Disable line break normalization. + YamlNode.DefaultConfig.NormalizeLineBreaks = false; + yaml = node.ToYaml(); + + // line breaks are not nomalized + // "%YAML 1.2\r\n---\r\n|-2\r\n a\r\n b\rcde\r\n...\r\n" + + // Unless line breaks in YAML stream is preserved, original line + // breaks can be restored. + restored = YamlNode.FromYaml(yaml)[0]; + // "a\r\n b\rcde" // equivalent to the original + + yaml = yaml.Replace("\r\n", "\n").Replace("\r", "\n"); + restored = YamlNode.FromYaml(yaml)[0]; + // "a\n b\ncde" // original line breaks are lost + + + + + + If true, tag for the root node is omitted by . + + + + + If true, the verbatim style of a tag, i.e. !< > is avoided as far as possible. + + + + + Add a custom tag resolution rule. + + + + + + + Type of value. + Tag for the value. + Pattern to match the value. + Method that decode value from + data after matching by . + Method that encode value to . + + + + Add an ability of instantiating an instance of a class that has no default constructer. + + Type of the object that is activated by this . + A delegate that creates an instance of . + + + var serializer= new YamlSerializer(); + + var yaml = + @"%YAML 1.2 + --- + !System.Drawing.SolidBrush + Color: Red + ... + "; + + SolidBrush b = null; + try { + b = (SolidBrush)serializer.Deserialize(yaml)[0]; + } catch(MissingMethodException) { + // SolidBrush has no default constructor! + } + + YamlNode.DefaultConfig.AddActivator<SolidBrush>(() => new SolidBrush(Color.Black)); + + // Now the serializer knows how to activate an instance of SolidBrush. + b = (SolidBrush)serializer.Deserialize(yaml)[0]; + + Assert.AreEqual(b.Color, Color.Red); + + + + + + Gets or sets CultureInfo with which the .NET native values are converted + to / from string. Currently, this is not to be changed from CultureInfo.InvariantCulture. + + + + + Abstract base class of YAML data nodes. + + See , and + for actual data classes. + + +

YAML data model

+ See http://yaml.org/ for the official definition of + Information Models of YAML. + + YAML data structure is defined as follows. + Note that this does not represents the text syntax of YAML text + but does logical data structure. + + + yaml-stream ::= yaml-document*
+ yaml-document ::= yaml-directive* yaml-node
+ yaml-directive ::= YAML-directive | TAG-directive | user-defined-directive
+ yaml-node ::= yaml-scalar | yaml-sequence | yaml-mapping
+ yaml-scalar ::= yaml-tag yaml-value
+ yaml-sequence ::= yaml-tag yaml-node*
+ yaml-mapping ::= yaml-tag ( yaml-node yaml-node )*
+ yaml-tag ::= yaml-global-tag yaml-local-tag
+ yaml-global-tag ::= "tag:" taggingEntity ":" specific [ "#" fragment ]
+ yaml-local-tag ::= "!" yaml-local-tag-name
+
+ + Namely, + + + A YAML stream consists of zero or more YAML documents.
+ A YAML documents have zero or more YAML directives and a root YAML node.
+ A YAML directive is either YAML-directive, TAG-directive or user-defined-directive.
+ A YAML node is either YAML scalar, YAML sequence or YAML mapping.
+ A YAML scalar consists of a YAML tag and a scalar value.
+ A YAML sequence consists of a YAML tag and zero or more child YAML nodes.
+ A YAML mapping cosists of a YAML tag and zero or more key/value pairs of YAML nodes.
+ A YAML tag is either a YAML global tag or a YAML local tag.
+ A YAML global tag starts with "tag:" and described in the "tag:" URI scheme defined in RFC4151.
+ A YAML local tag starts with "!" with a YAML local tag name
+
+ + + // Construct YAML node tree + YamlNode node = + new YamlSequence( // !!seq node + new YamlScalar("abc"), // !!str node + new YamlScalar("!!int", "123"), // !!int node + new YamlScalar("!!float", "1.23"), // !!float node + new YamlSequence( // nesting !!seq node + new YamlScalar("def"), + new YamlScalar("ghi") + ), + new YamlMapping( // !!map node + new YamlScalar("key1"), new YamlScalar("value1"), + new YamlScalar("key2"), new YamlScalar("value2"), + new YamlScalar("key3"), new YamlMapping( // nesting !!map node + new YamlScalar("value3key1"), new YamlScalar("value3value1") + ), + new YamlScalar("key4"), new YamlScalar("value4") + ) + ); + + // Convert it to YAML stream + string yaml = node.ToYaml(); + + // %YAML 1.2 + // --- + // - abc + // - 123 + // - 1.23 + // - - def + // - ghi + // - key1: value1 + // key2: value2 + // key3: + // value3key1: value3value1 + // key4: value4 + // ... + + // Load the YAML node from the YAML stream. + // Note that a YAML stream can contain several YAML documents each of which + // contains a root YAML node. + YamlNode[] nodes = YamlNode.FromYaml(yaml); + + // The only one node in the stream is the one we have presented above. + Assert.AreEqual(1, nodes.Length); + YamlNode resotred = nodes[0]; + + // Check if they are equal to each other. + Assert.AreEquel(node, restored); + + // Extract sub nodes. + var seq = (YamlSequence)restored; + var map = (YamlMapping)seq[4]; + var map2 = (YamlMapping)map[new YamlScalar("key3")]; + + // Modify the restored node tree + map2[new YamlScalar("value3key1")] = new YamlScalar("value3value1 modified"); + + // Now they are not equal to each other. + Assert.AreNotEquel(node, restored); + + +

YamlNode class

+ + is an abstract class that represents a YAML node. + + In reality, a is either , or + . + + All has property that denotes + the actual data type represented in the YAML node. + + Default Tag value for , or are + "tag:yaml.org,2002:str", "tag:yaml.org,2002:seq", "tag:yaml.org,2002:map". + + Global tags that starts with "tag:yaml.org,2002:" ( = + YamlNode.DefaultTagPrefix) are defined in the YAML tag repository at + http://yaml.org/type/. In this library, such a tags can be also + represented in a short form that starts with "!!", like "!!str", "!!seq" and "!!map". + Tags in the formal style and the shorthand form can be converted to each other by the static methods of + and . + In addition to these three basic tags, this library uses "!!null", "!!bool", "!!int", + "!!float" and "!!timestamp" tags, by default. + + s can be read from a YAML stream with , + , and + static methods. Since a YAML stream generally consist of multiple + YAML documents, each of which has a root YAML node, these methods return an array of + that is contained in the stream. + + s can be written to a YAML stream with , + , and + . + + The way of serialization can be configured in some aspects. The custom settings are specified + by an instance of class. The serialization methods introduced above has + overloaded styles that accepts instance to customize serialization. + It is also possible to change the default serialization method by modifying + YamlNode.DefaultConfig static property. + + A has property, which holds the string expression + of the node value. + + A implements IList<YamlNode> + interface to access the child nodes. + + implements + IDictionary<YamlNode,YamlNode> interface + to access the key/value pairs under the node. + +

Implicit conversion from C# native object to YamlScalar

+ + Implicit cast operators from , , , + and to is defined. Thus, anytime + is required in C# source, naked scalar value can be written. Namely, + methods of and accept such C# native types + as arguments in addition to types. + + + var map = new YamlMapping(); + map["Time"] = DateTime.Now; // implicitly converted to YamlScalar + Assert.IsTrue(map.ContainsKey(new YamlScalar("Time"))); + Assert.IsTrue(map.ContainsKey("Time")); // implicitly converted to YamlScalar + + +

Equality of YamlNodes

+ + Equality of s are evaluated on the content base. Different + objects that have the same content are evaluated to be equal. Use method for + equality evaluation. + + In detail, two s are logically equal to each other when the + and its child nodes have the same contents ( and ) + and their node graph topology is exactly same. + + + + YamlNode a1 = "a"; // implicit conversion + YamlNode a2 = "a"; // implicit conversion + YamlNode a3 = new YamlNode("!char", "a"); + YamlNode b = "b"; // implicit conversion + + Assert.IsTrue(a1 != a2); // different objects + Assert.IsTrue(a1.Equals(a2)); // different objects having same content + + Assert.IsFalse(a1.Equals(a3)); // Tag is different + Assert.IsFalse(a1.Equals(b)); // Value is different + + var s1 = new YamlMapping(a1, new YamlSequence(a1, a2)); + var s2 = new YamlMapping(a1, new YamlSequence(a2, a1)); + var s3 = new YamlMapping(a2, new YamlSequence(a1, a2)); + + Assert.IsFalse(s1.Equals(s2)); // node graph topology is different + Assert.IsFalse(s1.Equals(s3)); // node graph topology is different + Assert.IsTrue(s2.Equals(s3)); // different objects having same content and node graph topology + + +
+ + Example 2.27 in YAML 1.2 specification + + + // %YAML 1.2 + // --- + // !<tag:clarkevans.com,2002:invoice> + // invoice: 34843 + // date : 2001-01-23 + // bill-to: &id001 + // given : Chris + // family : Dumars + // address: + // lines: | + // 458 Walkman Dr. + // Suite #292 + // city : Royal Oak + // state : MI + // postal : 48046 + // ship-to: *id001 + // product: + // - sku : BL394D + // quantity : 4 + // description : Basketball + // price : 450.00 + // - sku : BL4438H + // quantity : 1 + // description : Super Hoop + // price : 2392.00 + // tax : 251.42 + // total: 4443.52 + // comments: + // Late afternoon is best. + // Backup contact is Nancy + // Billsmer @ 338-4338. + // ... + + var invoice = new YamlMapping( + "invoice", 34843, + "date", new DateTime(2001, 01, 23), + "bill-to", new YamlMapping( + "given", "Chris", + "family", "Dumars", + "address", new YamlMapping( + "lines", "458 Walkman Dr.\nSuite #292\n", + "city", "Royal Oak", + "state", "MI", + "postal", 48046 + ) + ), + "product", new YamlSequence( + new YamlMapping( + "sku", "BL394D", + "quantity", 4, + "description", "Basketball", + "price", 450.00 + ), + new YamlMapping( + "sku", "BL4438H", + "quantity", 1, + "description", "Super Hoop", + "price", 2392.00 + ) + ), + "tax", 251.42, + "total", 4443.52, + "comments", "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338." + ); + invoice["ship-to"] = invoice["bill-to"]; + invoice.Tag = "tag:clarkevans.com,2002:invoice"; + + invoice.ToYamlFile("invoice.yaml"); + // %YAML 1.2 + // --- + // !<tag:clarkevans.com,2002:invoice> + // invoice: 34843 + // date: 2001-01-23 + // bill-to: &A + // given: Chris + // family: Dumars + // address: + // lines: "458 Walkman Dr.\n\ + // Suite #292\n" + // city: Royal Oak + // state: MI + // postal: 48046 + // product: + // - sku: BL394D + // quantity: 4 + // description: Basketball + // price: !!float 450 + // - sku: BL4438H + // quantity: 1 + // description: Super Hoop + // price: !!float 2392 + // tax: 251.42 + // total: 4443.52 + // comments: Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338. + // ship-to: *A + // ... + + + +
+ + + Initialize a node. + + + + + YAML Tag for this node, which represents the type of node's value. + The property is returned in a shorthand style. + + + + + Serves as a hash function for a particular type. + Hash code is calculated using Tag and Value properties. + + Hash code + + + + Return the hash code. + The returned value will be cached until is called. + + Hash code + + + + Call this function when the content of the node is changed. + + + + + Returns true if is of same type as the and + its content is also logically same. + + + Two 's are logically equal when the and its child nodes + have the same contents ( and ) + and their node graph topology is exactly same as the other. + + + + var a1 = new YamlNode("a"); + var a2 = new YamlNode("a"); + var a3 = new YamlNode("!char", "a"); + var b = new YamlNode("b"); + + Assert.IsTrue(a1 != a2); // different objects + Assert.IsTrue(a1.Equals(a2)); // different objects having same content + + Assert.IsFalse(a1.Equals(a3)); // Tag is different + Assert.IsFalse(a1.Equals(b)); // Value is different + + var s1 = new YamlMapping(a1, new YamlSequence(a1, a2)); + var s2 = new YamlMapping(a1, new YamlSequence(a2, a1)); + var s3 = new YamlMapping(a2, new YamlSequence(a1, a2)); + + Assert.IsFalse(s1.Equals(s2)); // node graph topology is different + Assert.IsFalse(s1.Equals(s3)); // node graph topology is different + Assert.IsTrue(s2.Equals(s3)); // different objects having same content and node graph topology + + + Object to be compared. + True if the logically equals to the ; otherwise false. + + + + Returns true if is of same type as the and + its content is also logically same. + + Node to be compared. + Node repository holds the nodes that already appeared and + the corresponding node in the other node tree. + true if they are equal to each other. + + + + Returns true if is of same type as the and + its Tag is same as the node. It returns true for if they + both already appeared in the node trees and were compared. + + Node to be compared. + Node repository holds the nodes that already appeared and + the corresponding node in the other node tree. + true if they already appeared in the node tree and were compared. + true if they are equal to each other. + + + + Returns a that represents the current . + + A that represents the current + + + + Convert to a YAML text. + + YAML stream. + + + + Convert to a YAML text. + + YAML stream. + YAML configuration to customize serialization. + + + + Convert to a YAML text and save it to . + + to output. + + + + Convert to a YAML text and save it to . + + to output. + YAML configuration to customize serialization. + + + + Convert to a YAML text and save it to . + + to output. + + + + Convert to a YAML text and save it to . + + to output. + YAML configuration to customize serialization. + + + + Convert to a YAML text and save it to the file. + + Name of the file to output + + + + Convert to a YAML text and save it to the file. + + Name of the file to output + YAML configuration to customize serialization. + + + + Convert YAML text to a list of . + + YAML text + YAML nodes + + + + Convert YAML text to a list of . + + YAML text + YAML nodes + YAML configuration to customize serialization. + + + + Convert YAML text to a list of . + + from which YAML document is read. + YAML nodes + + + + Convert YAML text to a list of . + + from which YAML document is read. + YAML nodes + YAML configuration to customize serialization. + + + + Convert YAML text to a list of . + + from which YAML document is read. + YAML nodes + + + + Convert YAML text to a list of . + + from which YAML document is read. + YAML nodes + YAML configuration to customize serialization. + + + + Convert YAML text to a list of . + + YAML File Name + YAML nodes + + + + Convert YAML text to a list of . + + YAML File Name + YAML nodes + YAML configuration to customize serialization. + + + + Implicit conversion from string to . + + Value to be converted. + Conversion result. + + + + Implicit conversion from string to . + + Value to be converted. + Conversion result. + + + + Implicit conversion from string to . + + Value to be converted. + Conversion result. + + + + Implicit conversion from string to . + + Value to be converted. + Conversion result. + + + + Implicit conversion from to . + + Value to be converted. + Conversion result. + + + + Convert shorthand tag starting with "!!" to the formal style that starts with "tag:yaml.org,2002:". + + + When starts with "!!", it is converted into formal style. + Otherwise, is returned as is. + + + + var tag = YamlNode.DefaultTagPrefix + "int"; // -> "tag:yaml.org,2002:int" + tag = YamlNode.ShorthandTag(tag); // -> "!!int" + tag = YamlNode.ExpandTag(tag); // -> "tag:yaml.org,2002:int" + + + Tag in the shorthand style. + Tag in formal style. + + + + Convert a formal style tag that starts with "tag:yaml.org,2002:" to + the shorthand style that starts with "!!". + + + When contains YAML standard types, it is converted into !!xxx style. + Otherwise, is returned as is. + + + + var tag = YamlNode.DefaultTagPrefix + "int"; // -> "tag:yaml.org,2002:int" + tag = YamlNode.ShorthandTag(tag); // -> "!!int" + tag = YamlNode.ExpandTag(tag); // -> "tag:yaml.org,2002:int" + + + Tag in formal style. + Tag in compact style. + + + + Position in a YAML document, where the node appears. + Both and sets this property. + When the node appeared multiple times in the document, this property returns the position + where it appeared for the first time. + + + + + Position in a YAML document, where the node appears. + Both and sets this property. + When the node appeared multiple times in the document, this property returns the position + where it appeared for the first time. + + + + + Temporary data, transfering information between YamlRepresenter and YamlPresenter. + + + + + YAML Tag for this node, which represents the type of node's value. + + + + YAML standard types has tags in a form of "tag:yaml.org,2002:???". Well known tags are + tag:yaml.org,2002:null, tag:yaml.org,2002:bool, tag:yaml.org,2002:int, tag:yaml.org,2002:str, + tag:yaml.org,2002:map, tag:yaml.org,2002:seq, tag:yaml.org,2002:float and tag:yaml.org,2002:timestamp. + + + + + + Invoked when the node's content or its childrens' content was changed. + + + + + Gets YAML's default tag prefix. + + "tag:yaml.org,2002:" + + + + Gets or sets the default configuration to customize serialization of . + + + + + Remember the order of appearance of nodes. It also has ability of rewinding. + + + + + Represents a scalar node in a YAML document. + + + + var string_node = new YamlNode("abc"); + Assert.AreEqual("!!str", string_node.ShorthandTag()); + + var int_node1= new YamlNode(YamlNode.DefaultTagPrefix + "int", "1"); + Assert.AreEqual("!!int", int_node1.ShorthandTag()); + + // shorthand tag style can be specified + var int_node2= new YamlNode("!!int", "1"); + Assert.AreEqual(YamlNode.DefaultTagPrefix + "int", int_node1.Tag); + Assert.AreEqual("!!int", int_node1.ShorthandTag()); + + // or use implicit conversion + YamlNode int_node3 = 1; + + // YamlNodes Equals to another node when their values are equal. + Assert.AreEqual(int_node1, int_node2); + + // Of course, they are different if compaired by references. + Assert.IsTrue(int_node1 != int_node2); + + + + + + Create empty string node. + + + + + Initialize string node that has as its content. + + Value of the node. + + + + Create a scalar node with arbitral tag. + + Tag to the node. + Value of the node. + + + + Initialize an integer node that has as its content. + + + + + Initialize a float node that has as its content. + + + + + Initialize a bool node that has as its content. + + + + + Initialize a timestamp node that has as its content. + + + + + Implicit conversion from string to . + + Value to be converted. + Conversion result. + + + + Implicit conversion from string to . + + Value to be converted. + Conversion result. + + + + Implicit conversion from string to . + + Value to be converted. + Conversion result. + + + + Implicit conversion from string to . + + Value to be converted. + Conversion result. + + + + Implicit conversion from to . + + Value to be converted. + Conversion result. + + + + Call this function when the content of the node is changed. + + + + + Returns the hash code. + The returned value will be cached until is called. + + Hash code + + + + String expression of the node value. + + + + + When the node has YAML's standard scalar type, the native object corresponding to + it can be got from this property. To see if this property contains a valid data, + refer to . + + This property is not available. See . + + This property is available when . contains + an entry for the nodes tag and defines how to decode the property into native objects. + When this property is available, equality of the scalar node is evaluated by comparing the + properties by the language default equality operator. + + + + + Gets if contains a valid content. + + + + + Abstract base class of that have child nodes. + + and inherites from this class. + + + + + Calculate hash code from property and all child nodes. + The result is cached. + + Hash value for the object. + + + + Calculates the hash code for a collection object. This function is called recursively + on the child objects with the sub cache code repository for the nodes already appeared + in the node tree. + + The cache code for the path where this node was found. + Repository of the nodes that already appeared in the node tree. + Sub hash code for the nodes can be refered to from this dictionary. + + + + + Represents a mapping node in a YAML document. + Use IDictionary<YamlNode,YamlNode> interface to + manipulate child key/value pairs. + + + Child items can be accessed via IDictionary<YamlNode, YamlNode> interface. + + Note that mapping object can not contain multiple keys with same value. + + + + // Create a mapping. + var map1 = new YamlMapping( + // (key, value) pairs should be written sequential + new YamlScalar("key1"), new YamlScalar("value1"), + "key2", "value2" // implicitely converted to YamlScalar + ); + + // Refer to the mapping. + Assert.AreEqual( map1[new Scalar("key1")], new YamlScalar("value1") ); + Assert.AreEqual( map1["key1"], "value1" ); + + // Add an entry. + map1.Add( "key3", new YamlSequence( "value3a", "value3b" ) ); + + // Create another mapping. + var map2 = new YamlMapping( + "key1", "value1", + "key2", "value2", + "key3", new YamlSequence( "value3a", "value3b" ) + ); + + // Mappings are equal when they have objects that are equal to each other. + Assert.IsTrue( map1.Equals( map2 ) ); + + + + + + Calculates the hash code for a collection object. This function is called recursively + on the child objects with the sub cache code repository for the nodes already appeared + in the node tree. + + The cache code for the path where this node was found. + Repository of the nodes that already appeared in the node tree. + Sub hash code for the nodes can be refered to from this dictionary. + + + + + Create a YamlMapping that contains in it. + + + + // Create a mapping. + var map1 = new YamlMapping( + // (key, value) pairs should be written sequential + new YamlScalar("key1"), new YamlScalar("value1"), + new YamlScalar("key2"), new YamlScalar("value2") + ); + + + Even number of arguments are expected. + (key, value) pairs are written sequential. + + + + Enumerate child nodes. + + Inumerator that iterates child nodes + + + + Adds an element with the provided key and value. + + or is a null reference. + An element with the same key already exists. + The node to use as the key of the element to add. + The node to use as the value of the element to add. + + + + Determines whether the contains an element with the specified key. + + The key to locate in the . + is a null reference + true if the contains an element with the key that is equal to the specified value; otherwise, false. + + + + Removes the element with the specified key from the . + + The key of the element to remove. + true if the element is successfully removed; otherwise, false. This method also returns false if key was not found in the original . + + + + Gets the value associated with the specified key. + + The key whose value to get. + When this method returns, the value associated with the specified key, if the key is found; + otherwise, the default value for the type of the value parameter. This parameter is passed uninitialized. + true if the object that implements contains an element with the specified key; otherwise, false. + + + + Removes all entries from the . + + + + + Determines whether the contains a specific value. + + The object to locate in the . + true if item is found in the otherwise, false. + + + + Returns an enumerator that iterates through the . + + An enumerator that iterates through the . + + + + Gets an ICollection<YamlNode> containing the keys of the . + + + + + Gets an ICollection<YamlNode> containing the values of the . + + + + + Gets or sets the element with the specified key. + + The key of the element to get or set. + The element with the specified key. + key is a null reference + The property is retrieved and key is not found. + + + + Returns the number of entries in a . + + + + + Represents a sequence node in a YAML document. + Use IList<YamlNode> interface + to manipulate child nodes. + + + + + Create a sequence node that has as its child. + + Child nodes of the sequence. + + + + Performs application-defined tasks associated with freeing, releasing, or + resetting unmanaged resources. + + + + + Calculates the hash code for a collection object. This function is called recursively + on the child objects with the sub cache code repository for the nodes already appeared + in the node tree. + + The cache code for the path where this node was found. + Repository of the nodes that already appeared in the node tree. + Sub hash code for the nodes can be refered to from this dictionary. + + + + + Determines the index of a specific child node in the . + + + If an node appears multiple times in the sequence, the IndexOf method always returns the first instance found. + + The child node to locate in the . + The index of if found in the sequence; otherwise, -1. + + + + Inserts an item to the at the specified . + + The zero-based index at which should be inserted. + The node to insert into the . + is not a valid index in the + . + + If equals the number of items in the , + then is appended to the sequence. + The nodes that follow the insertion point move down to accommodate the new node. + + + + + Removes the item at the specified index. + + The zero-based index of the node to remove. + is not a valid index in the . + + The nodes that follow the removed node move up to occupy the vacated spot. + + + + + Adds an item to the . + + The node to add to the . + + + + Removes all nodes from the . + + + + + Determines whether a sequence contains a child node that equals to the specified + by using the default equality comparer. + + The node value to locate in the sequence. + true If the sequence contains an node that has the specified value; otherwise, false. + + + var seq = new YamlSequence(new YamlScalar("a")); + + // different object that has same value + Assert.IsTrue(seq.Contains(new YamlScalar("a"))); + + // different value + Assert.IsFalse(s.Contains(str("b"))); + + + + + + Copies the child nodes of the to an , starting at a particular index. + + The one-dimensional that is the destination of the elements copied from . + The zero-based index in at which copying begins. + is a null reference. + is less than 0. + + array is multidimensional. + -or- + The number of elements in the source is greater than the available space from + to the end of the destination array. + + + + + Removes the first occurrence of a specific node from the . + + The node to remove from the . + true if was successfully removed from the ; otherwise, false. + This method also returns false if is not found in the original . + + + + + Returns an enumerator that iterates through the all child nodes. + + An enumerator that iterates through the all child nodes. + + + + Gets or sets the node at the specified index. + + The zero-based index of the node to get or set. + The node at the specified index. + is not a valid index in the ). + + This property provides the ability to access a specific node in the sequence by using the following syntax: mySequence[index]. + + + + + Gets the number of child nodes of the . + + The number of child nodes of the sequence. + + + + class has instance methods and , + with which C# native objects can be converted into / from YAML text without any preparations. + + var serializer = new YamlSerializer(); + object obj = GetObjectToSerialize(); + string yaml = serializer.Serialize(obj); + object restored = serializer.Deserialize(yaml); + Assert.AreEqual(obj, restored); + + + + +

What kind of objects can be serialized?

+ + can serialize / deserialize native C# objects of primitive types + (bool, char, int,...), enums, built-in non-primitive types (string, decimal), structures, + classes and arrays of these types. + + + On the other hand, it does not deal with IntPtr (which is a primitive type, though) and + pointer types (void*, int*, ...) because these types are, by their nature, not persistent. + + + + Classes without a default constructor can be deserialized only when the way of activating an instance + is explicitly specified by . + + + + object obj = new object[]{ + null, + "abc", + true, + 1, + (Byte)1, + 1.0, + "1", + new double[]{ 1.1, 2, -3 }, + new string[]{ "def", "ghi", "1" }, + new System.Drawing.Point(1,3), + new System.Drawing.SolidBrush(Color.Blue) + }; + + var serializer = new YamlSerializer(); + string yaml = serializer.Serialize(obj); + // %YAML 1.2 + // --- + // - null + // - abc + // - True + // - 1 + // - !System.Byte 1 + // - !!float 1 + // - "1" + // - !<!System.Double[]%gt; [1.1, 2, -3] + // - !<!System.String[]%gt; + // - def + // - ghi + // - !System.Drawing.Point 1, 3 + // - !System.Drawing.SolidBrush + // Color: Blue + // ... + + object restored; + try { + restored = YamlSerializer.Deserialize(yaml)[0]; + } catch(MissingMethodException) { + // default constructor is missing for SolidBrush + } + + // Let the library know how to activate an instance of SolidBrush. + YamlNode.DefaultConfig.AddActivator<System.Drawing.SolidBrush>( + () => new System.Drawing.SolidBrush(Color.Black /* dummy */)); + + // Then, all the objects can be restored correctly. + restored = serializer.Deserialize(yaml)[0]; + + + A YAML document generated by always have a %YAML directive and + explicit document start ("---") and end ("...") marks. + This allows several documents to be written in a single YAML stream. + + + var yaml = ""; + var serializer = new YamlSerializer(); + yaml += serializer.Serialize("a"); + yaml += serializer.Serialize(1); + yaml += serializer.Serialize(1.1); + // %YAML 1.2 + // --- + // a + // ... + // %YAML 1.2 + // --- + // 1 + // ... + // %YAML 1.2 + // --- + // 1.1 + // ... + + object[] objects = serializer.Deserialize(yaml); + // objects[0] == "a" + // objects[1] == 1 + // objects[2] == 1.1 + + + Since a YAML stream can consist of multiple YAML documents as above, + returns an array of . + + +

Serializing structures and classes

+ + For structures and classes, by default, all public fields and public properties are + serialized. Note that protected / private members are always ignored. + +

Serialization methods

+ + Readonly value-type members are also ignored because there is no way to + assign a new value to them on deserialization, while readonly class-type members + are serialized. When deserializing, instead of creating a new object and assigning it + to the member, the child members of such class instance are restored independently. + Such a deserializing method is refered to + YamlSerializeMethod.Content. + + + On the other hand, when writeable fields/properties are deserialized, new objects are + created by using the parameters in the YAML description and assiend to the fields/properties. + Such a deserializing method is refered to + YamlSerializeMethod.Assign. Writeable properties can be explicitly specified to use + YamlSerializeMethod.Content method for + deserialization, by adding to its definition. + + + Another type of serializing method is + YamlSerializeMethod.Binary. + This method is only applicable to an array-type field / property that contains + only value-type members. + + If serializing method is specified, + the member is never serialized nor deserialized. + + + public class Test1 + { + public int PublicProp { get; set; } // processed (by assign) + protected int ProtectedProp { get; set; } // Ignored + private int PrivateProp { get; set; } // Ignored + internal int InternalProp { get; set; } // Ignored + + public int PublicField; // processed (by assign) + protected int ProtectedField; // Ignored + private int PrivateField; // Ignored + internal int InternalField; // Ignored + + public List<string> ClassPropByAssign // processed (by assign) + { get; set; } + + public int ReadOnlyValueProp { get; private set; } // Ignored + public List<string> ReadOnlyClassProp // processed (by content) + { get; private set; } + + [YamlSerialize(YamlSerializeMethod.Content)] + public List<string> ClassPropByContent// processed (by content) + { get; set; } + + public int[] IntArrayField = // processed (by assign) + new int[10]; + + [YamlSerialize(YamlSerializeMethod.Binary)] + public int[] IntArrayFieldBinary = // processed (as binary) + new int[100]; + + [YamlSerialize(YamlSerializeMethod.Never)] + public int PublicPropHidden; // Ignored + + public Test1() + { + ClassPropByAssign = new List<string>(); + ReadOnlyClassProp = new List<string>(); + ClassPropByContent = new List<string>(); + } + } + + public void TestPropertiesAndFields1() + { + var test1 = new Test1(); + test1.ClassPropByAssign.Add("abc"); + test1.ReadOnlyClassProp.Add("def"); + test1.ClassPropByContent.Add("ghi"); + var rand = new Random(0); + for ( int i = 0; i < test1.IntArrayFieldBinary.Length; i++ ) + test1.IntArrayFieldBinary[i] = rand.Next(); + + var serializer = new YamlSerializer(); + string yaml = serializer.Serialize(test1); + // %YAML 1.2 + // --- + // !YamlSerializerTest.Test1 + // PublicProp: 0 + // ClassPropByAssign: + // Capacity: 4 + // ICollection.Items: + // - abc + // ReadOnlyClassProp: + // Capacity: 4 + // ICollection.Items: + // - def + // ClassPropByContent: + // Capacity: 4 + // ICollection.Items: + // - ghi + // PublicField: 0 + // IntArrayField: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + // IntArrayFieldBinary: |+2 + // Gor1XAwenmhGkU5ib9NxR11LXxp1iYlH5LH4c9hImTitWSB9Z78II2UvXSXV99A79fj6UBn3GDzbIbd9 + // yBDjAyslYm58iGd/NN+tVjuLRCg3cJBo+PWMbIWm9n4AEC0E7LKXWV5HXUNk7I13APEDWFMM/kWTz2EK + // s7LzFw2gBjpKugkmQJqIfinpQ1J1yqhhz/XjA3TBxDBsEuwrD+SNevQSqEC+/KRbwgE6D011ACMeyRt0 + // BOG6ZesRKCtL0YU6tSnLEpgKVBz+R300qD3/W0aZVk+1vHU+auzyGCGUaHCGd6dpRoEhXoIg2m3+AwJX + // EJ37T+TA9BuEPJtyGoq+crQMFQtXj1Zriz3HFbReclLvDdVpZlcOHPga/3+3Y509EHZ7UyT7H1xGeJxn + // eXPrDDb0Ul04MfZb4UYREOfR3HNzNTUYGRsIPUvHOEW7AaoplIfkVQp19DvGBrBqlP2TZ9atlWUHVdth + // 7lIBeIh0wiXxoOpCbQ7qVP9GkioQUrMkOcAJaad3exyZaOsXxznFCA== + // ... + } + + +

Default values of fields and properties

+ + is aware of + System.ComponentModel.DefaultValueAttribute. + So, when a member of a structure / class instance has a value that equals to the default value, + the member will not be written in the YAML text. + + It also checkes for the result of ShouldSerializeXXX method. For instance, just before serializing Font + property of some type, bool ShouldSerializeFont() method is called if exists. If the method returns false, + Font property will not be written in the YAML text. ShouldSerializeXXX method can be non-public. + + + using System.ComponentModel; + + public class Test2 + { + [DefaultValue(0)] + public int Default0 = 0; + + [DefaultValue("a")] + public string Defaulta = "a"; + + public int DynamicDefault = 0; + + bool ShouldSerializeDynamicDefault() + { + return Default0 != DynamicDefault; + } + } + + public void TestDefaultValue() + { + var test2 = new Test2(); + var serializer = new YamlSerializer(); + + // All properties have defalut values. + var yaml = serializer.Serialize(test2); + // %YAML 1.2 + // --- + // !YamlSerializerTest.Test2 {} + // ... + + test2.Defaulta = "b"; + yaml = serializer.Serialize(test2); + // %YAML 1.2 + // --- + // !YamlSerializerTest.Test2 + // Defaulta: b + // ... + + test2.Defaulta = "a"; + var yaml = serializer.Serialize(test2); + // %YAML 1.2 + // --- + // !YamlSerializerTest.Test2 {} + // ... + + test2.DynamicDefault = 1; + yaml = serializer.Serialize(test2); + // %YAML 1.2 + // --- + // !YamlSerializerTest.Test2 + // DynamicDefault: 1 + // ... + + test2.Default0 = 1; + yaml = serializer.Serialize(test2); + // %YAML 1.2 + // --- + // !YamlSerializerTest.Test2 + // Default0: 1 + // ... + } + + +

Collection classes

+ + If an object implements , or + the child objects are serialized as well its other public members. + Pseudproperty ICollection.Items or IDictionary.Entries appears to hold the child objects. + +

Multitime appearance of a same object

+ + preserve C# objects' graph structure. Namely, when a same objects are refered to + from several points in the object graph, the structure is correctly described in YAML text and restored objects + preserve the structure. can safely manipulate directly / indirectly self refering + objects, too. + + + public class TestClass + { + public List<TestClass> list = + new List<TestClass>(); + } + + public class ChildClass: TestClass + { + } + + void RecursiveObjectsTest() + { + var a = new TestClass(); + var b = new ChildClass(); + a.list.Add(a); + a.list.Add(a); + a.list.Add(b); + a.list.Add(a); + a.list.Add(b); + b.list.Add(a); + var serializer = new YamlSerializer(); + string yaml = serializer.Serialize(a); + // %YAML 1.2 + // --- + // &A !TestClass + // list: + // Capacity: 8 + // ICollection.Items: + // - *A + // - *A + // - &B !ChildClass + // list: + // Capacity: 4 + // ICollection.Items: + // - *A + // - *A + // - *B + // ... + + var restored = (TestClass)serializer.Deserialize(yaml)[0]; + Assert.IsTrue(restored == restored.list[0]); + Assert.IsTrue(restored == restored.list[1]); + Assert.IsTrue(restored == restored.list[3]); + Assert.IsTrue(restored == restored.list[5]); + Assert.IsTrue(restored.list[2] == restored.list[4]); + } + + + This is not the case if the object is . Same instances of + are repeatedly written in a YAML text and restored as different + instance of when deserialized, unless the content of the string + is extremely long (longer than 999 chars). + + + // 1000 chars + string long_str = + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" + + "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"; + string short_str = "12345"; + object obj = new object[] { long_str, long_str, short_str, short_str }; + var serializer = new YamlSerializer(); + string yaml = serializer.Serialize(obj); + // %YAML 1.2 + // --- + // - &A 01234567890123456789012345678901234567890123456789 ... (snip) ... 789 + // - *A + // - "12345" + // - "12345" + // ... + + +

YAML text written / read by

+ + When serializing, intelligently uses various YAML 1.2 styles, + namely the block style, flow style, explicit mapping and implicit mapping, to maximize readability + of the YAML stream. + + + [Flags] + enum TestEnum: uint + { + abc = 1, + あいう = 2 + } + + public void TestVariousFormats() + { + var dict = new Dictionary<object, object>(); + dict.Add(new object[] { 1, "a" }, new object()); + object obj = new object[]{ + dict, + null, + "abc", + "1", + "a ", + "- a", + "abc\n", + "abc\ndef\n", + "abc\ndef\nghi", + new double[]{ 1.1, 2, -3, 3.12, 13.2 }, + new int[,] { { 1, 3}, {4, 5}, {10, 1} }, + new string[]{ "jkl", "mno\npqr" }, + new System.Drawing.Point(1,3), + TestEnum.abc, + TestEnum.abc | TestEnum.あいう, + }; + var config = new YamlConfig(); + config.ExplicitlyPreserveLineBreaks = false; + var serializer = new YamlSerializer(config); + string yaml = serializer.Serialize(obj); + + // %YAML 1.2 + // --- + // - !<!System.Collections.Generic.Dictionary%602[[System.Object,...],[System.Object,...]]> + // Keys: {} + // Values: {} + // IDictionary.Entries: + // ? - 1 + // - a + // : !System.Object {} + // - null + // - abc + // - "1" + // - "a " + // - "- a" + // - "abc\n" + // - |+2 + // abc + // def + // - |-2 + // abc + // def + // ghi + // - !<!System.Double[]> [1.1, 2, -3, 3.12, 13.2] + // - !<!System.Int32[,]> [[1, 3], [4, 5], [10, 1]] + // - !<!System.String[]> + // - jkl + // - |-2 + // mno + // pqr + // - !System.Drawing.Point 1, 3 + // - !TestEnum abc + // - !TestEnum abc, あいう + // ... + } + + + When deserializing, accepts any valid YAML 1.2 documents. + TAG directives, comments, flow / block styles, implicit / explicit mappings can be freely used + to express valid C# objects. Namely, the members of the array can be given eighter in a flow style + or in a block style. + + + By default, outputs a YAML stream with line break of "\r\n". + This can be customized either by setting YamlNode.DefaultConfig.LineBreakForOutput or + by giving an instance of to the + constructor. + + + + var serializer = new YamlSerializer(); + var yaml = serializer.Serialize("abc"); + // %YAML 1.2\r\n // line breaks are explicitly shown in this example + // ---\r\n + // abc\r\n + // ...\r\n + + var config = new YamlConfig(); + config.LineBreakForOutput = "\n"; + serializer = new YamlSerializer(config); + var yaml = serializer.Serialize("abc"); + // %YAML 1.2\n + // ---\n + // abc\n + // ...\n + + YamlNode.DefaultConfig.LineBreakForOutput = "\n"; + + var serializer = new YamlSerializer(); + serializer = new YamlSerializer(); + var yaml = serializer.Serialize("abc"); + // %YAML 1.2\n + // ---\n + // abc\n + // ...\n + + +

Line breaks in YAML text

+ + By default, line breaks in multi line values are explicitly presented as escaped style. + Although, this makes the resulting YAML stream hard to read, it is necessary to preserve + the exact content of the string because the YAML specification requires that a YAML parser + must normalize evely line break that is not escaped in a YAML document to be a single line + feed "\n" when deserializing. + + In order to have the YAML documents easy to be read, set + YamlConfig.ExplicitlyPreserveLineBreaks + false. Then, the multiline values of will be written in literal style. + + Of course, it makes all the line breaks to be normalized into a single line feeds "\n". + + + var serializer = new YamlSerializer(); + var text = "abc\r\n def\r\nghi\r\n"; + // abc + // def + // ghi + + // By default, line breaks explicitly appears in escaped form. + var yaml = serializer.Serialize(text); + // %YAML 1.2 + // --- + // "abc\r\n\ + // \ def\r\n\ + // ghi\r\n" + // ... + + // Original line breaks are preserved + var restored = (string)serializer.Deserialize(yaml)[0]; + // "abc\r\n def\r\nghi\r\n" + + + YamlNode.DefaultConfig.ExplicitlyPreserveLineBreaks = false; + + // Literal style is easier to be read. + var yaml = serializer.Serialize(text); + // %YAML 1.2 + // --- + // |+2 + // abc + // def + // ghi + // ... + + // Original line breaks are lost. + var restored = (string)serializer.Deserialize(yaml)[0]; + // "abc\n def\nghi\n" + + + This library offers two work arounds for this problem, although both of which + violates the official behavior of a YAML parser defined in the YAML specification. + + One is to set YamlConfig.LineBreakForInput + to be "\r\n". Then, the YAML parser normalizes all line breaks into "\r\n" instead of "\n". + + The other is to set YamlConfig.NormalizeLineBreaks + false. It disables the line break normalization both at output and at input. Namely, the line breaks are + written and read as-is when serialized / deserialized. + + + var serializer = new YamlSerializer(); + + // text with mixed line breaks + var text = "abc\r def\nghi\r\n"; + // abc\r // line breaks are explicitly shown in this example + // def\n + // ghi\r\n + + YamlNode.DefaultConfig.ExplicitlyPreserveLineBreaks = false; + + // By default, all line breaks are normalized to "\r\n" when serialized. + var yaml = serializer.Serialize(text); + // %YAML 1.2\r\n + // ---\r\n + // |+2\r\n + // abc\r\n + // def\r\n + // ghi\r\n + // ...\r\n + + // When deserialized, line breaks are normalized into "\n". + var restored = (string)serializer.Deserialize(yaml)[0]; + // "abc\n def\nghi\n" + + // Line breaks are normalized into "\r\n" instead of "\n". + YamlNode.DefaultConfig.LineBreakForInput = "\r\n"; + restored = (string)serializer.Deserialize(yaml)[0]; + // "abc\r\n def\r\nghi\r\n" + + // Line breaks are written as is, + YamlNode.DefaultConfig.NormalizeLineBreaks = false; + var yaml = serializer.Serialize(text); + // %YAML 1.2\r\n + // ---\r\n + // |+2\r\n + // abc\r + // def\n + // ghi\r\n + // ...\r\n + + // and are read as is. + restored = (string)serializer.Deserialize(yaml)[0]; + // "abc\r def\nghi\r\n" + + // Note that when the line breaks of YAML stream is changed + // between serialization and deserialization, the original + // line breaks are lost. + yaml = yaml.Replace("\r\n", "\n").Replace("\r", "\n"); + restored = (string)serializer.Deserialize(yaml)[0]; + // "abc\n def\nghi\n" + + + It is repeatedly stated that although these two options are useful in many situation, + they makes the YAML parser violate the YAML specification. + +
+
+ + + Initialize an instance of that obeys + . + + + + + Initialize an instance of with custom . + + Custom to customize serialization. + + + + Serialize C# object into YAML text. + + Object to be serialized. + YAML text. + + + + Serialize C# object into YAML text and write it into a . + + A to which the YAML text is written. + Object to be serialized. + + + + Serialize C# object into YAML text and write it into a . + + A to which the YAML text is written. + Object to be serialized. + + + + Serialize C# object into YAML text and save it into a file named as . + + A file name to which the YAML text is written. + Object to be serialized. + + + + Deserialize C# object(s) from a YAML text. Since a YAML text can contain multiple YAML documents, each of which + represents a C# object, the result is returned as an array of . + + A YAML text from which C# objects are deserialized. + Expected type(s) of the root object(s) in the YAML stream. + C# object(s) deserialized from YAML text. + + + + Deserialize C# object(s) from a YAML text in a . + Since a YAML text can contain multiple YAML documents, each of which + represents a C# object, the result is returned as an array of . + + A that contains YAML text from which C# objects are deserialized. + Expected type(s) of the root object(s) in the YAML stream. + C# object(s) deserialized from YAML text. + + + + Deserialize C# object(s) from a YAML text in a . + Since a YAML text can contain multiple YAML documents, each of which + represents a C# object, the result is returned as an array of . + + A that contains YAML text from which C# objects are deserialized. + Expected type(s) of the root object(s) in the YAML stream. + C# object(s) deserialized from YAML text. + + + + Deserialize C# object(s) from a YAML text in a file named as . + Since a YAML text can contain multiple YAML documents, each of which + represents a C# object, the result is returned as an array of . + + The name of a file that contains YAML text from which C# objects are deserialized. + Expected type(s) of the root object(s) in the YAML stream. + C# object(s) deserialized from YAML text. + + + + Add .DoFunction method to string + + + + + Short expression of string.Format(XXX, arg1, arg2, ...) + + + + + + + + Specify the way to store a property or field of some class or structure. + See for detail. + + + + + + + The property / field will not be stored. + + + + + When restored, new object is created by using the parameters in + the YAML data and assigned to the property / field. When the + property / filed is writeable, this is the default. + + + + + Only valid for a property / field that has a class or struct type. + When restored, instead of recreating the whole class or struct, + the members are independently restored. When the property / field + is not writeable this is the default. + + + + + Only valid for a property / field that has an array type of a + some value type. The content of the array is stored in a binary + format encoded in base64 style. + + + + + Specify the way to store a property or field of some class or structure. + + See for detail. + + + + + + + Specify the way to store a property or field of some class or structure. + + See for detail. + + + + + + - Never: The property / field will not be stored. + + + - Assign: When restored, new object is created by using the parameters in + the YAML data and assigned to the property / field. When the + property / filed is writeable, this is the default. + + + - Content: Only valid for a property / field that has a class or struct type. + When restored, instead of recreating the whole class or struct, + the members are independently restored. When the property / field + is not writeable this is the default. + + + - Binary: Only valid for a property / field that has an array type of a + some value type. The content of the array is stored in a binary + format encoded in base64 style. + + + + + + Type 関連のユーティリティメソッド + + + + Type type; + AttributeType attr = type.GetAttribute<AttributeType>(); + + PropertyInfo propInfo; + AttributeType attr = propInfo.GetAttribute<AttributeType>(); + + string name; + Type type = TypeUtils.GetType(name); // search from all assembly loaded + + + + + + + + Type や PropertyInfo, FieldInfo から指定された型の属性を取り出して返す + 複数存在した場合には最後の値を返す + 存在しなければ null を返す + + 取り出したい属性の型 + 取り出した属性値 + + + + 現在ロードされているすべてのアセンブリから name という名の型を探して返す + + + + + + + Check if the type is a ValueType and does not contain any non ValueType members. + + + + + + + Returnes true if the specified is a struct type. + + to be analyzed. + true if the specified is a struct type; otehrwise false. + + + + Compare two objects to see if they are equal or not. Null is acceptable. + + + + + + + + Return if an object is a numeric value. + + Any object to be tested. + True if object is a numeric value. + + + + Cast an object to a specified numeric type. + + Any object + Numric type + Numeric value or null if the object is not a numeric value. + + + + Cast boxed numeric value to double + + boxed numeric value + Numeric value in double. Double.Nan if obj is not a numeric value. + + + + Check if type is fully public or not. + Nested class is checked if all declared types are public. + + + + + + + Equality comparer that uses Object.ReferenceEquals(x, y) to compare class values. + + + + + + Determines whether two objects of type T are equal by calling Object.ReferenceEquals(x, y). + + The first object to compare. + The second object to compare. + true if the specified objects are equal; otherwise, false. + + + + Serves as a hash function for the specified object for hashing algorithms and + data structures, such as a hash table. + + The object for which to get a hash code. + A hash code for the specified object. + is null. + + + + Returns a default equality comparer for the type specified by the generic argument. + + The default instance of the System.Collections.Generic.EqualityComparer<T> + class for type T. + + + + Calculate hash code by reference. + + + + + + Initializes a new instance of the HashCodeByRef<T> class. + + + + + Calculate hash code by reference. + + + + + Represents the way to automatically resolve Tag from the Value of a YamlScalar. + + + + + Create TagResolver with default resolution rules. + + + + + Add default tag resolution rules to the rule list. + + + + + List of tag resolution rules. + + + + + Add a tag resolution rule that is invoked when matches + the Value of a node. + + The tag is resolved to and is + invoked when actual value of type is extracted from + the node text. + + + Surround sequential calls of this function by / + pair to avoid invoking slow internal calculation method many times. + + + + BeginUpdate(); // to avoid invoking slow internal calculation method many times. + Add( ... ); + Add( ... ); + Add( ... ); + Add( ... ); + EndUpdate(); // automaticall invoke internal calculation method + + + + + + + + + Supress invoking slow internal calculation method when + called. + + BeginUpdate / can be called nestedly. + + + + + Quit to supress invoking slow internal calculation method when + called. + + + + + Execute tag resolution and returns automatically determined tag value from . + + Node text with which automatic tag resolution is done. + Automatically determined tag value . + + + + Decode and returns actual value in C# object. + + Node to be decoded. + Decoded value. + True if decoded successfully. + + + + Extend string object to have .DoubleQuoteEscape() / .DoubleQuoteUnescape(). + + + + + Escape control codes with YAML double quoted string format. + + + + + + + Unescape control codes escaped with YAML double quoted string format. + + + + + + + YAML style double quoted string escape / unescape. + + + + + Initialize tables + + + + + Escape control codes, double quotations, backslashes in the YAML double quoted string format + + + + + Unescape control codes, double quotations, backslashes escape in the YAML double quoted string format + + +
+
diff --git a/lib/yaml/YamlSerializer.dll b/lib/yaml/YamlSerializer.dll new file mode 100644 index 000000000..057f2c4e6 Binary files /dev/null and b/lib/yaml/YamlSerializer.dll differ diff --git a/src/Orchard.Tests.Modules/Setup/SetupControllerTests.cs b/src/Orchard.Tests.Modules/Setup/SetupControllerTests.cs index 372bbb731..f8124f950 100644 --- a/src/Orchard.Tests.Modules/Setup/SetupControllerTests.cs +++ b/src/Orchard.Tests.Modules/Setup/SetupControllerTests.cs @@ -43,7 +43,7 @@ namespace Orchard.Tests.Modules.Setup { //builder.Register().As(); //builder.Register().As(); //builder.Register().As(); - //builder.Register().As(); + //builder.Register().As(); //builder.Register().As(); //_container = builder.Build(); } diff --git a/src/Orchard.Tests/Environment/Configuration/AppDataFolderTests.cs b/src/Orchard.Tests/Environment/Configuration/AppDataFolderTests.cs index d2895ed73..bbde69cee 100644 --- a/src/Orchard.Tests/Environment/Configuration/AppDataFolderTests.cs +++ b/src/Orchard.Tests/Environment/Configuration/AppDataFolderTests.cs @@ -77,5 +77,19 @@ namespace Orchard.Tests.Environment.Configuration { _appDataFolder.CreateFile("alpha\\omega\\foo\\bar.txt", "quux"); Assert.That(Directory.Exists(Path.Combine(_tempFolder, "alpha\\omega\\foo")), Is.True); } + + + [Test] + public void FilesCanBeReadBack() { + _appDataFolder.CreateFile("alpha\\gamma\\foo\\bar.txt", @" +this is +a +test"); + var text = _appDataFolder.ReadFile("alpha\\gamma\\foo\\bar.txt"); + Assert.That(text, Is.EqualTo(@" +this is +a +test")); + } } } diff --git a/src/Orchard.Tests/Environment/Configuration/DefaultTenantManagerTests.cs b/src/Orchard.Tests/Environment/Configuration/DefaultTenantManagerTests.cs new file mode 100644 index 000000000..650dab337 --- /dev/null +++ b/src/Orchard.Tests/Environment/Configuration/DefaultTenantManagerTests.cs @@ -0,0 +1,76 @@ +using System.IO; +using System.Linq; +using NUnit.Framework; +using Orchard.Environment.Configuration; + +namespace Orchard.Tests.Environment.Configuration { + [TestFixture] + public class DefaultTenantManagerTests { + private string _tempFolder; + private AppDataFolder _appData; + + [SetUp] + public void Init() { + _appData = new AppDataFolder(); + _tempFolder = Path.GetTempFileName(); + File.Delete(_tempFolder); + _appData.SetBasePath(_tempFolder); + } + [TearDown] + public void Term() { + Directory.Delete(_tempFolder, true); + } + + [Test] + public void SingleSettingsFileShouldComeBackAsExpected() { + + _appData.CreateFile("Sites\\Default\\Settings.txt", "Name: Default\r\nDataProvider: SQLite\r\nDataConnectionString: something else"); + + ITenantManager loader = new DefaultTenantManager(_appData); + var settings = loader.LoadSettings().Single(); + Assert.That(settings, Is.Not.Null); + Assert.That(settings.Name, Is.EqualTo("Default")); + Assert.That(settings.DataProvider, Is.EqualTo("SQLite")); + Assert.That(settings.DataConnectionString, Is.EqualTo("something else")); + } + + + [Test] + public void MultipleFilesCanBeDetected() { + + _appData.CreateFile("Sites\\Default\\Settings.txt", "Name: Default\r\nDataProvider: SQLite\r\nDataConnectionString: something else"); + _appData.CreateFile("Sites\\Another\\Settings.txt", "Name: Another\r\nDataProvider: SQLite2\r\nDataConnectionString: something else2"); + + ITenantManager loader = new DefaultTenantManager(_appData); + var settings = loader.LoadSettings(); + Assert.That(settings.Count(), Is.EqualTo(2)); + + var def = settings.Single(x => x.Name == "Default"); + Assert.That(def.Name, Is.EqualTo("Default")); + Assert.That(def.DataProvider, Is.EqualTo("SQLite")); + Assert.That(def.DataConnectionString, Is.EqualTo("something else")); + + var alt = settings.Single(x => x.Name == "Another"); + Assert.That(alt.Name, Is.EqualTo("Another")); + Assert.That(alt.DataProvider, Is.EqualTo("SQLite2")); + Assert.That(alt.DataConnectionString, Is.EqualTo("something else2")); + } + + [Test] + public void NewSettingsCanBeStored() { + _appData.CreateFile("Sites\\Default\\Settings.txt", "Name: Default\r\nDataProvider: SQLite\r\nDataConnectionString: something else"); + + ITenantManager loader = new DefaultTenantManager(_appData); + var foo = new ShellSettings {Name = "Foo", DataProvider = "Bar", DataConnectionString = "Quux"}; + + Assert.That(loader.LoadSettings().Count(), Is.EqualTo(1)); + loader.SaveSettings(foo); + Assert.That(loader.LoadSettings().Count(), Is.EqualTo(2)); + + var text = File.ReadAllText(_appData.MapPath("Sites\\Foo\\Settings.txt")); + Assert.That(text, Is.StringContaining("Foo")); + Assert.That(text, Is.StringContaining("Bar")); + Assert.That(text, Is.StringContaining("Quux")); + } + } +} diff --git a/src/Orchard.Tests/Environment/DefaultOrchardHostTests.cs b/src/Orchard.Tests/Environment/DefaultOrchardHostTests.cs index f3b18cabe..bd92425da 100644 --- a/src/Orchard.Tests/Environment/DefaultOrchardHostTests.cs +++ b/src/Orchard.Tests/Environment/DefaultOrchardHostTests.cs @@ -47,7 +47,7 @@ namespace Orchard.Tests.Environment { builder.RegisterInstance(new ViewEngineCollection { new WebFormViewEngine() }); builder.RegisterInstance(new StuExtensionManager()).As(); builder.RegisterInstance(new Mock().Object); - builder.RegisterInstance(new StubShellSettingsLoader()).As(); + builder.RegisterInstance(new StubShellSettingsLoader()).As(); }); _lifetime = _container.BeginLifetimeScope(); var updater = new ContainerUpdater(); @@ -55,7 +55,7 @@ namespace Orchard.Tests.Environment { updater.Update(_lifetime); } - public class StubShellSettingsLoader : IShellSettingsLoader { + public class StubShellSettingsLoader : ITenantManager { private readonly List _shellSettings = new List {new ShellSettings {Name = "testing"}}; @@ -77,7 +77,7 @@ namespace Orchard.Tests.Environment { return Enumerable.Empty(); } - public IEnumerable GetExtensionsTopology() { + public ShellTopology GetExtensionsTopology() { throw new NotImplementedException(); } diff --git a/src/Orchard.Tests/Extensions/ExtensionManagerTests.cs b/src/Orchard.Tests/Extensions/ExtensionManagerTests.cs index b16bf13f1..a92225d89 100644 --- a/src/Orchard.Tests/Extensions/ExtensionManagerTests.cs +++ b/src/Orchard.Tests/Extensions/ExtensionManagerTests.cs @@ -178,14 +178,14 @@ features: public void ExtensionManagerShouldReturnTopology() { var topology = _manager.GetExtensionsTopology(); - Assert.That(topology.Count(), Is.Not.EqualTo(0)); + Assert.That(topology.Types.Count(), Is.Not.EqualTo(0)); } [Test] public void ExtensionManagerTopologyShouldContainNonAbstractClasses() { var topology = _manager.GetExtensionsTopology(); - foreach (var type in topology) { + foreach (var type in topology.Types) { Assert.That(type.IsClass); Assert.That(!type.IsAbstract); } diff --git a/src/Orchard.Tests/Mvc/Routes/StandardExtensionRouteProviderTests.cs b/src/Orchard.Tests/Mvc/Routes/StandardExtensionRouteProviderTests.cs index 0ce1436e8..a61b70ad7 100644 --- a/src/Orchard.Tests/Mvc/Routes/StandardExtensionRouteProviderTests.cs +++ b/src/Orchard.Tests/Mvc/Routes/StandardExtensionRouteProviderTests.cs @@ -54,7 +54,7 @@ namespace Orchard.Tests.Mvc.Routes { }; } - public IEnumerable GetExtensionsTopology() { + public ShellTopology GetExtensionsTopology() { throw new NotImplementedException(); } diff --git a/src/Orchard.Tests/Orchard.Framework.Tests.csproj b/src/Orchard.Tests/Orchard.Framework.Tests.csproj index 3fa6deb18..c633ce04e 100644 --- a/src/Orchard.Tests/Orchard.Framework.Tests.csproj +++ b/src/Orchard.Tests/Orchard.Framework.Tests.csproj @@ -153,6 +153,7 @@ + diff --git a/src/Orchard.Web/Config/Sample.Host.config b/src/Orchard.Web/Config/Sample.Host.config new file mode 100644 index 000000000..acce66e1a --- /dev/null +++ b/src/Orchard.Web/Config/Sample.Host.config @@ -0,0 +1,25 @@ + + + + +
+ + + + + + + + + + + + + + + + + + diff --git a/src/Orchard.Web/Modules/Orchard.Setup/Controllers/SetupController.cs b/src/Orchard.Web/Modules/Orchard.Setup/Controllers/SetupController.cs index db96e7b85..d6a7be770 100644 --- a/src/Orchard.Web/Modules/Orchard.Setup/Controllers/SetupController.cs +++ b/src/Orchard.Web/Modules/Orchard.Setup/Controllers/SetupController.cs @@ -21,17 +21,17 @@ namespace Orchard.Setup.Controllers { public class SetupController : Controller { private readonly INotifier _notifier; private readonly IOrchardHost _orchardHost; - private readonly IShellSettingsLoader _shellSettingsLoader; + private readonly ITenantManager _tenantManager; private readonly IAppDataFolder _appDataFolder; public SetupController( INotifier notifier, IOrchardHost orchardHost, - IShellSettingsLoader shellSettingsLoader, + ITenantManager tenantManager, IAppDataFolder appDataFolder) { _notifier = notifier; _orchardHost = orchardHost; - _shellSettingsLoader = shellSettingsLoader; + _tenantManager = tenantManager; _appDataFolder = appDataFolder; T = NullLocalizer.Instance; } @@ -134,7 +134,7 @@ namespace Orchard.Setup.Controllers { } } - _shellSettingsLoader.SaveSettings(shellSettings); + _tenantManager.SaveSettings(shellSettings); _orchardHost.Reinitialize(); diff --git a/src/Orchard.Web/Orchard.Web.csproj b/src/Orchard.Web/Orchard.Web.csproj index 743a29cca..5128a4a58 100644 --- a/src/Orchard.Web/Orchard.Web.csproj +++ b/src/Orchard.Web/Orchard.Web.csproj @@ -164,6 +164,7 @@ + diff --git a/src/Orchard.Web/Web.config b/src/Orchard.Web/Web.config index f773df541..f1524c319 100644 --- a/src/Orchard.Web/Web.config +++ b/src/Orchard.Web/Web.config @@ -25,7 +25,7 @@ - + - @@ -102,7 +102,7 @@ - + diff --git a/src/Orchard/Environment/Configuration/AppDataFolder.cs b/src/Orchard/Environment/Configuration/AppDataFolder.cs index fd235f784..529790164 100644 --- a/src/Orchard/Environment/Configuration/AppDataFolder.cs +++ b/src/Orchard/Environment/Configuration/AppDataFolder.cs @@ -15,6 +15,7 @@ namespace Orchard.Environment.Configuration { IEnumerable ListDirectories(string path); void CreateFile(string path, string content); + string ReadFile(string path); void DeleteFile(string path); string CreateDirectory(string path); @@ -26,7 +27,6 @@ namespace Orchard.Environment.Configuration { /// void SetBasePath(string basePath); string MapPath(string path); - } public class AppDataFolder : IAppDataFolder { @@ -44,6 +44,10 @@ namespace Orchard.Environment.Configuration { File.WriteAllText(filePath, content); } + public string ReadFile(string path) { + return File.ReadAllText(Path.Combine(_basePath, path)); + } + public void DeleteFile(string path) { File.Delete(Path.Combine(_basePath, path)); } diff --git a/src/Orchard/Environment/Configuration/AzureBlobTenantManager.cs b/src/Orchard/Environment/Configuration/AzureBlobTenantManager.cs new file mode 100644 index 000000000..778339afd --- /dev/null +++ b/src/Orchard/Environment/Configuration/AzureBlobTenantManager.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; + +namespace Orchard.Environment.Configuration { + public class AzureBlobTenantManager : ITenantManager{ + public AzureBlobTenantManager(string foo) { + int x = 5; + } + + public string Foo { get; set; } + + public IEnumerable LoadSettings() { + throw new NotImplementedException(); + } + + public void SaveSettings(IShellSettings settings) { + throw new NotImplementedException(); + } + } +} diff --git a/src/Orchard/Environment/Configuration/DefaultTenantManager.cs b/src/Orchard/Environment/Configuration/DefaultTenantManager.cs new file mode 100644 index 000000000..05e4b61f0 --- /dev/null +++ b/src/Orchard/Environment/Configuration/DefaultTenantManager.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Yaml.Serialization; +using Orchard.Localization; + +namespace Orchard.Environment.Configuration { + public class DefaultTenantManager : ITenantManager { + private readonly IAppDataFolder _appDataFolder; + Localizer T { get; set; } + + public DefaultTenantManager(IAppDataFolder appDataFolder) { + _appDataFolder = appDataFolder; + T = NullLocalizer.Instance; + } + + IEnumerable ITenantManager.LoadSettings() { + return LoadSettings().ToArray(); + } + + void ITenantManager.SaveSettings(IShellSettings settings) { + if (settings == null) + throw new ArgumentException(T("There are no settings to save.").ToString()); + if (string.IsNullOrEmpty(settings.Name)) + throw new ArgumentException(T("Settings \"Name\" is not set.").ToString()); + + var filePath = Path.Combine(Path.Combine("Sites", settings.Name), "Settings.txt"); + _appDataFolder.CreateFile(filePath, ComposeSettings(settings)); + } + + IEnumerable LoadSettings() { + var filePaths = _appDataFolder + .ListDirectories("Sites") + .SelectMany(path => _appDataFolder.ListFiles(path)) + .Where(path => string.Equals(Path.GetFileName(path), "Settings.txt", StringComparison.OrdinalIgnoreCase)); + + foreach (var filePath in filePaths) { + yield return ParseSettings(_appDataFolder.ReadFile(filePath)); + } + } + + class Content { + public string Name { get; set; } + public string DataProvider { get; set; } + public string DataConnectionString { get; set; } + public string DataPrefix { get; set; } + } + + static IShellSettings ParseSettings(string text) { + var ser = new YamlSerializer(); + var content = ser.Deserialize(text, typeof(Content)).Cast().Single(); + return new ShellSettings { + Name = content.Name, + DataProvider = content.DataProvider, + DataConnectionString = content.DataConnectionString, + DataPrefix = content.DataPrefix, + }; + } + + static string ComposeSettings(IShellSettings settings) { + if (settings == null) + return ""; + + var ser = new YamlSerializer(); + return ser.Serialize(new Content { + Name = settings.Name, + DataProvider = settings.DataProvider, + DataConnectionString = settings.DataConnectionString, + DataPrefix = settings.DataPrefix, + }); + } + } +} diff --git a/src/Orchard/Environment/Configuration/ITenantManager.cs b/src/Orchard/Environment/Configuration/ITenantManager.cs new file mode 100644 index 000000000..67da12e5b --- /dev/null +++ b/src/Orchard/Environment/Configuration/ITenantManager.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Orchard.Environment.Configuration { + public interface ITenantManager { + IEnumerable LoadSettings(); + void SaveSettings(IShellSettings settings); + } +} \ No newline at end of file diff --git a/src/Orchard/Environment/Configuration/ShellSettings.cs b/src/Orchard/Environment/Configuration/ShellSettings.cs index fc84ab2d7..342aef8b5 100644 --- a/src/Orchard/Environment/Configuration/ShellSettings.cs +++ b/src/Orchard/Environment/Configuration/ShellSettings.cs @@ -1,13 +1,15 @@ namespace Orchard.Environment.Configuration { public interface IShellSettings { - string Name { get; set; } - string DataProvider { get; set; } - string DataConnectionString { get; set; } + string Name { get; } + string DataProvider { get; } + string DataConnectionString { get; } + string DataPrefix { get; } } public class ShellSettings : IShellSettings { public string Name { get; set; } public string DataProvider { get; set; } public string DataConnectionString { get; set; } + public string DataPrefix { get; set; } } } diff --git a/src/Orchard/Environment/Configuration/ShellSettingsLoader.cs b/src/Orchard/Environment/Configuration/ShellSettingsLoader.cs deleted file mode 100644 index 81a7a8091..000000000 --- a/src/Orchard/Environment/Configuration/ShellSettingsLoader.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Web.Hosting; -using Orchard.Localization; -using Yaml.Grammar; - -namespace Orchard.Environment.Configuration { - public interface IShellSettingsLoader { - IEnumerable LoadSettings(); - void SaveSettings(IShellSettings settings); - } - - public class ShellSettingsLoader : IShellSettingsLoader { - private readonly IAppDataFolder _appDataFolder; - Localizer T { get; set; } - - public ShellSettingsLoader(IAppDataFolder appDataFolder) { - _appDataFolder = appDataFolder; - T = NullLocalizer.Instance; - } - - IEnumerable IShellSettingsLoader.LoadSettings() { - return LoadSettings().ToArray(); - } - - public void SaveSettings(IShellSettings settings) { - if (settings == null) - throw new ArgumentException(T("There are no settings to save.").ToString()); - if (string.IsNullOrEmpty(settings.Name)) - throw new ArgumentException(T("Settings \"Name\" is not set.").ToString()); - - var settingsFile = Path.Combine(Path.Combine("Sites", settings.Name), "Settings.txt"); - _appDataFolder.CreateFile(settingsFile, ComposeSettings(settings)); - } - - IEnumerable LoadSettings() { - foreach (var yamlDocument in LoadFiles()) { - yield return ParseSettings(yamlDocument); - } - } - - IEnumerable LoadFiles() { - var sitePaths = _appDataFolder - .ListDirectories("Sites") - .SelectMany(path => _appDataFolder.ListFiles(path)) - .Where(path => string.Equals(Path.GetFileName(path), "Settings.txt", StringComparison.OrdinalIgnoreCase)); - - foreach (var sitePath in sitePaths) { - var yamlStream = YamlParser.Load(_appDataFolder.MapPath(sitePath)); - yield return yamlStream.Documents.Single(); - } - } - - static IShellSettings ParseSettings(YamlDocument document) { - var mapping = (Mapping)document.Root; - var fields = mapping.Entities - .Where(x => x.Key is Scalar) - .ToDictionary(x => ((Scalar)x.Key).Text, x => x.Value); - - return new ShellSettings { - Name = GetValue(fields, "Name"), - DataProvider = GetValue(fields, "DataProvider"), - DataConnectionString = GetValue(fields, "DataConnectionString") - }; - } - - static string GetValue( - IDictionary fields, - string key) { - - DataItem value; - return fields.TryGetValue(key, out value) ? value.ToString() : null; - } - - static string ComposeSettings(IShellSettings shellSettings) { - if (shellSettings == null) - return ""; - - var settingsBuilder = new StringBuilder(); - - settingsBuilder.AppendLine(string.Format("Name: {0}", shellSettings.Name)); - settingsBuilder.AppendLine(string.Format("DataProvider: {0}", shellSettings.DataProvider)); - - if (!string.IsNullOrEmpty(shellSettings.DataConnectionString)) - settingsBuilder.AppendLine(string.Format("DataConnectionString: {0}", shellSettings.DataConnectionString)); - - return settingsBuilder.ToString(); - } - } -} diff --git a/src/Orchard/Environment/DefaultCompositionStrategy.cs b/src/Orchard/Environment/DefaultCompositionStrategy.cs index c36de5e0f..230f279b8 100644 --- a/src/Orchard/Environment/DefaultCompositionStrategy.cs +++ b/src/Orchard/Environment/DefaultCompositionStrategy.cs @@ -7,6 +7,7 @@ using Orchard.ContentManagement; using Orchard.ContentManagement.Records; using Orchard.Extensions; using Orchard.Utility.Extensions; +using Orchard.Extensions.Records; namespace Orchard.Environment { //TEMP: This will be replaced by packaging system @@ -30,11 +31,11 @@ namespace Orchard.Environment { } public IEnumerable GetModuleTypes() { - return _extensionManager.GetExtensionsTopology().Where(t => typeof(IModule).IsAssignableFrom(t)); + return _extensionManager.GetExtensionsTopology().Types.Where(t => typeof(IModule).IsAssignableFrom(t)); } public IEnumerable GetDependencyTypes() { - return _extensionManager.GetExtensionsTopology().Where(t => typeof(IDependency).IsAssignableFrom(t)); + return _extensionManager.GetExtensionsTopology().Types.Where(t => typeof(IDependency).IsAssignableFrom(t)); } public IEnumerable GetRecordDescriptors() { @@ -42,6 +43,7 @@ namespace Orchard.Environment { new RecordDescriptor { Prefix = "Core", Type = typeof (ContentTypeRecord)}, new RecordDescriptor { Prefix = "Core", Type = typeof (ContentItemRecord)}, new RecordDescriptor { Prefix = "Core", Type = typeof (ContentItemVersionRecord)}, + new RecordDescriptor { Prefix = "Core", Type = typeof (ExtensionRecord)}, }; foreach (var extension in _extensionManager.ActiveExtensions()) { diff --git a/src/Orchard/Environment/DefaultOrchardHost.cs b/src/Orchard/Environment/DefaultOrchardHost.cs index b90bf77fd..0dd3e0f90 100644 --- a/src/Orchard/Environment/DefaultOrchardHost.cs +++ b/src/Orchard/Environment/DefaultOrchardHost.cs @@ -15,17 +15,17 @@ namespace Orchard.Environment { private readonly ControllerBuilder _controllerBuilder; private readonly IEnumerable _shellContainerFactories; - private readonly IShellSettingsLoader _shellSettingsLoader; + private readonly ITenantManager _tenantManager; private IOrchardShell _current; public DefaultOrchardHost( IContainerProvider containerProvider, - IShellSettingsLoader shellSettingsLoader, + ITenantManager tenantManager, ControllerBuilder controllerBuilder, IEnumerable shellContainerFactories) { _containerProvider = containerProvider; - _shellSettingsLoader = shellSettingsLoader; + _tenantManager = tenantManager; _controllerBuilder = controllerBuilder; _shellContainerFactories = shellContainerFactories; } @@ -95,7 +95,7 @@ namespace Orchard.Environment { } public virtual ILifetimeScope CreateShellContainer() { - var settings = _shellSettingsLoader.LoadSettings(); + var settings = _tenantManager.LoadSettings(); if (settings.Any()) { //TEMP: multi-tenancy not implemented yet var shellContainer = CreateShellContainer(settings.Single()); diff --git a/src/Orchard/Environment/OrchardStarter.cs b/src/Orchard/Environment/OrchardStarter.cs index d4633a565..67496ce84 100644 --- a/src/Orchard/Environment/OrchardStarter.cs +++ b/src/Orchard/Environment/OrchardStarter.cs @@ -1,14 +1,15 @@ using System; +using System.Configuration; +using System.IO; +using System.Web.Hosting; using Autofac; -using Autofac.Builder; -using Autofac.Core; +using Autofac.Configuration; using Autofac.Integration.Web; using Orchard.Environment.AutofacUtil; using Orchard.Environment.Configuration; using Orchard.Environment.ShellBuilders; using Orchard.Extensions; using Orchard.Extensions.Loaders; -using Orchard.Mvc; namespace Orchard.Environment { public static class OrchardStarter { @@ -20,7 +21,7 @@ namespace Orchard.Environment { builder.RegisterType().As().SingleInstance(); builder.RegisterType().As().SingleInstance(); builder.RegisterType().As().SingleInstance(); - builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); builder.RegisterType().As().SingleInstance(); // The container provider gives you access to the lowest container at the time, @@ -47,6 +48,15 @@ namespace Orchard.Environment { registrations(builder); + + var autofacSection = ConfigurationManager.GetSection(ConfigurationSettingsReader.DefaultSectionName); + if (autofacSection != null) + builder.RegisterModule(new ConfigurationSettingsReader()); + + var optionalHostConfig = HostingEnvironment.MapPath("~/Config/Host.config"); + if (File.Exists(optionalHostConfig)) + builder.RegisterModule(new ConfigurationSettingsReader(ConfigurationSettingsReader.DefaultSectionName, optionalHostConfig)); + return builder.Build(); } diff --git a/src/Orchard/Environment/ShellBuilders/DefaultShellContainerFactory.cs b/src/Orchard/Environment/ShellBuilders/DefaultShellContainerFactory.cs index 2af7bd087..88991f8ab 100644 --- a/src/Orchard/Environment/ShellBuilders/DefaultShellContainerFactory.cs +++ b/src/Orchard/Environment/ShellBuilders/DefaultShellContainerFactory.cs @@ -35,17 +35,18 @@ namespace Orchard.Environment.ShellBuilders { // add components by the IDependency interfaces they expose foreach (var serviceType in _compositionStrategy.GetDependencyTypes()) { + var registrar = addingModulesAndServices.RegisterType(serviceType) + .EnableDynamicProxy(dynamicProxyContext) + .InstancePerLifetimeScope(); + foreach (var interfaceType in serviceType.GetInterfaces()) { if (typeof(IDependency).IsAssignableFrom(interfaceType)) { - var registrar = addingModulesAndServices.RegisterType(serviceType).As(interfaceType).EnableDynamicProxy(dynamicProxyContext); + registrar = registrar.As(interfaceType); if (typeof(ISingletonDependency).IsAssignableFrom(interfaceType)) { - registrar.SingleInstance(); + registrar = registrar.SingleInstance(); } else if (typeof(ITransientDependency).IsAssignableFrom(interfaceType)) { - registrar.InstancePerDependency(); - } - else { - registrar.InstancePerLifetimeScope(); + registrar = registrar.InstancePerDependency(); } } } diff --git a/src/Orchard/Environment/ShellBuilders/SafeModeShellContainerFactory.cs b/src/Orchard/Environment/ShellBuilders/SafeModeShellContainerFactory.cs index 7eef7c180..cc79d536b 100644 --- a/src/Orchard/Environment/ShellBuilders/SafeModeShellContainerFactory.cs +++ b/src/Orchard/Environment/ShellBuilders/SafeModeShellContainerFactory.cs @@ -70,17 +70,15 @@ namespace Orchard.Environment.ShellBuilders { .GetExportedTypes() .Where(type => type.IsClass && !type.IsAbstract && typeof(IDependency).IsAssignableFrom(type)); foreach (var serviceType in dependencies) { + var registrar = builder.RegisterType(serviceType).EnableDynamicProxy(dynamicProxyContext).InstancePerLifetimeScope(); foreach (var interfaceType in serviceType.GetInterfaces()) { if (typeof(IDependency).IsAssignableFrom(interfaceType)) { - var registrar = builder.RegisterType(serviceType).As(interfaceType).EnableDynamicProxy(dynamicProxyContext); + registrar = registrar.As(interfaceType); if (typeof(ISingletonDependency).IsAssignableFrom(interfaceType)) { - registrar.SingleInstance(); + registrar = registrar.SingleInstance(); } else if (typeof(ITransientDependency).IsAssignableFrom(interfaceType)) { - registrar.InstancePerDependency(); - } - else { - registrar.InstancePerLifetimeScope(); + registrar = registrar.InstancePerDependency(); } } } diff --git a/src/Orchard/Extensions/ExtensionManager.cs b/src/Orchard/Extensions/ExtensionManager.cs index e6331cb54..f9a031ec3 100644 --- a/src/Orchard/Extensions/ExtensionManager.cs +++ b/src/Orchard/Extensions/ExtensionManager.cs @@ -16,15 +16,19 @@ namespace Orchard.Extensions { private readonly IEnumerable _folders; private readonly IEnumerable _loaders; private IEnumerable _activeExtensions; + //private readonly IRepository _extensionRepository; public Localizer T { get; set; } public ILogger Logger { get; set; } public ExtensionManager( IEnumerable folders, - IEnumerable loaders) { + IEnumerable loaders + //IRepository extensionRepository + ) { _folders = folders; _loaders = loaders.OrderBy(x => x.Order); + //_extensionRepository = extensionRepository; T = NullLocalizer.Instance; Logger = NullLogger.Instance; } @@ -97,10 +101,10 @@ namespace Orchard.Extensions { return _activeExtensions; } - public IEnumerable GetExtensionsTopology() { + public ShellTopology GetExtensionsTopology() { var types = ActiveExtensions().SelectMany(x => x.ExportedTypes); types = types.Concat(typeof(IOrchardHost).Assembly.GetExportedTypes()); - return types.Where(t => t.IsClass && !t.IsAbstract); + return new ShellTopology { Types = types.Where(t => t.IsClass && !t.IsAbstract) }; } public void InstallExtension(string extensionType, HttpPostedFileBase extensionBundle) { @@ -163,8 +167,8 @@ namespace Orchard.Extensions { } private IEnumerable BuildActiveExtensions() { - //TODO: this component needs access to some "current settings" to know which are active foreach (var descriptor in AvailableExtensions()) { + //_extensionRepository.Create(new ExtensionRecord { Name = descriptor.Name }); // Extensions that are Themes don't have buildable components. if (String.Equals(descriptor.ExtensionType, "Module", StringComparison.OrdinalIgnoreCase)) { yield return BuildEntry(descriptor); @@ -172,7 +176,15 @@ namespace Orchard.Extensions { } } + private bool IsExtensionEnabled(string name) { + //ExtensionRecord extensionRecord = _extensionRepository.Get(x => x.Name == name); + //if (extensionRecord.Enabled) return true; + //return false; + return true; + } + private ExtensionEntry BuildEntry(ExtensionDescriptor descriptor) { + if (!IsExtensionEnabled(descriptor.Name)) return null; foreach (var loader in _loaders) { var entry = loader.Load(descriptor); if (entry != null) diff --git a/src/Orchard/Extensions/IExtensionManager.cs b/src/Orchard/Extensions/IExtensionManager.cs index 6cf496c1b..2d6c5a3ca 100644 --- a/src/Orchard/Extensions/IExtensionManager.cs +++ b/src/Orchard/Extensions/IExtensionManager.cs @@ -1,12 +1,11 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Web; namespace Orchard.Extensions { public interface IExtensionManager { IEnumerable AvailableExtensions(); IEnumerable ActiveExtensions(); - IEnumerable GetExtensionsTopology(); + ShellTopology GetExtensionsTopology(); void InstallExtension(string extensionType, HttpPostedFileBase extensionBundle); void UninstallExtension(string extensionType, string extensionName); } diff --git a/src/Orchard/Extensions/Records/ExtensionRecord.cs b/src/Orchard/Extensions/Records/ExtensionRecord.cs new file mode 100644 index 000000000..5057562b1 --- /dev/null +++ b/src/Orchard/Extensions/Records/ExtensionRecord.cs @@ -0,0 +1,13 @@ +namespace Orchard.Extensions.Records { + public class ExtensionRecord { + public ExtensionRecord() { +// ReSharper disable DoNotCallOverridableMethodsInConstructor + Enabled = true; +// ReSharper restore DoNotCallOverridableMethodsInConstructor + } + + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual bool Enabled { get; set; } + } +} \ No newline at end of file diff --git a/src/Orchard/Extensions/ShellTopology.cs b/src/Orchard/Extensions/ShellTopology.cs new file mode 100644 index 000000000..eba9328db --- /dev/null +++ b/src/Orchard/Extensions/ShellTopology.cs @@ -0,0 +1,8 @@ +using System; +using System.Collections.Generic; + +namespace Orchard.Extensions { + public class ShellTopology { + public IEnumerable Types { get; set; } + } +} diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj index 928c861cf..afb8848c4 100644 --- a/src/Orchard/Orchard.Framework.csproj +++ b/src/Orchard/Orchard.Framework.csproj @@ -35,6 +35,10 @@ False ..\..\lib\autofac\Autofac.dll + + False + ..\..\lib\autofac\Autofac.Configuration.dll + False ..\..\lib\autofac\Autofac.Integration.Web.dll @@ -101,6 +105,10 @@ False ..\..\lib\yaml\Yaml.dll + + False + ..\..\lib\yaml\YamlSerializer.dll + @@ -155,7 +163,9 @@ - + + + @@ -166,6 +176,8 @@ + +