diff --git a/lib/yaml/YamlSerializer.XML b/lib/yaml/YamlSerializer.XML index 5023c52ab..06d1a45d7 100644 --- a/lib/yaml/YamlSerializer.XML +++ b/lib/yaml/YamlSerializer.XML @@ -4,6 +4,2014 @@ YamlSerializer + + + 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. + + + + + object に代入されたクラスや構造体のメンバーに、リフレクションを + 解して簡単にアクセスできるようにしたクラス + + アクセス方法をキャッシュするので、繰り返し使用する場合に高速化が + 期待できる + + + + + Caches ObjectMemberAccessor instances for reuse. + + + + + + 指定した型へのアクセス方法を表すインスタンスを返す + キャッシュに存在すればそれを返す + キャッシュに存在しなければ新しく作って返す + 作った物はキャッシュされる + + クラスまたは構造体を表す型情報 + + + + + メンバ名と Accessor のペアを巡回する + + + + + + メンバへの読み書きを行うことができる + + オブジェクト + メンバの名前 + + + + + 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. + + + + + + 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. + + + + + 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); + + } + + +
+ + + 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. + + + + + 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 + + + + + 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] + + + + + Reset(); + SetupDefaultTagPrefixes(); + Add(tag_handle, tag_prefix); + verbatim_tag = Resolve(tag_handle, tag_name); + + Configuration to customize YAML serialization. @@ -1504,1674 +3512,6 @@ The number of child nodes of the sequence. - - - 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. - - - - - object に代入されたクラスや構造体のメンバーに、リフレクションを - 解して簡単にアクセスできるようにしたクラス - - アクセス方法をキャッシュするので、繰り返し使用する場合に高速化が - 期待できる - - - - - Caches ObjectMemberAccessor instances for reuse. - - - - - - 指定した型へのアクセス方法を表すインスタンスを返す - キャッシュに存在すればそれを返す - キャッシュに存在しなければ新しく作って返す - 作った物はキャッシュされる - - クラスまたは構造体を表す型情報 - - - - - メンバ名と Accessor のペアを巡回する - - - - - - メンバへの読み書きを行うことができる - - オブジェクト - メンバの名前 - - - - - Validates a text as a global tag in YAML. - - RFC4151 - The 'tag' URI Scheme> - - - - - 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. - - A candidate for a global tag in YAML. - True if is a valid global tag. - - - - Not used in this parser - - - - - Reset(); - SetupDefaultTagPrefixes(); - Add(tag_handle, tag_prefix); - verbatim_tag = Resolve(tag_handle, tag_name); - - - - - 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. - - - Represents the way to automatically resolve Tag from the Value of a YamlScalar. @@ -3248,6 +3588,22 @@ Decoded value. True if decoded successfully. + + + Converts YamlNode tree into yaml text. + + + + YamlNode node; + YamlPresenter.ToYaml(node); + + YamlNode node1; + YamlNode node2; + YamlNode node3; + YamlPresenter.ToYaml(node1, node2, node3); + + + Extend string object to have .DoubleQuoteEscape() / .DoubleQuoteUnescape(). @@ -3287,276 +3643,6 @@ Unescape control codes, double quotations, backslashes escape in the YAML double quoted string format - - - 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. - - - - 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] - - Add string class two methods: .UriEscape(), .UriUnescape() @@ -3596,30 +3682,6 @@ NonUriChar = new Regex(@"[^0-9A-Za-z\-_.!~*'()\\;/?:@&=$,\[\]]"); - - - 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. - - - - Converts C# object to YamlNode - - - - object obj; - YamlNode node = YamlRepresenter.ObjectToNode(obj); - - - Dictionary that automatically rehash when the content of a key is changed. @@ -3688,67 +3750,5 @@ added to or removed from the dictionary. - - - Converts YamlNode tree into yaml text. - - - - YamlNode node; - YamlPresenter.ToYaml(node); - - YamlNode node1; - YamlNode node2; - YamlNode node3; - YamlPresenter.ToYaml(node1, node2, node3); - - - - - - 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); - - } - - -
- - - 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. - - diff --git a/lib/yaml/YamlSerializer.dll b/lib/yaml/YamlSerializer.dll index 2cc7ec287..74fec4710 100644 Binary files a/lib/yaml/YamlSerializer.dll and b/lib/yaml/YamlSerializer.dll differ diff --git a/src/Orchard.Web/Core/Contents/Views/Items/Content.Edit.cshtml b/src/Orchard.Web/Core/Contents/Views/Items/Content.Edit.cshtml index af834ed7e..08a086a2a 100644 --- a/src/Orchard.Web/Core/Contents/Views/Items/Content.Edit.cshtml +++ b/src/Orchard.Web/Core/Contents/Views/Items/Content.Edit.cshtml @@ -1,8 +1,21 @@ -
-
- @Display(Model.Content) +
+
+ @if (Model.Content != null) { +
+ @Display(Model.Content) +
+ }
-
- @Display(Model.Sidebar) +
+ @if (Model.Actions != null) { +
+ @Display(Model.Actions) +
+ } + @if (Model.Sidebar != null) { +
+ @Display(Model.Sidebar) +
+ }
\ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/DataMigration.txt b/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/DataMigration.txt index a37519809..8ad2238b0 100644 --- a/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/DataMigration.txt +++ b/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/DataMigration.txt @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Data; using Orchard.ContentManagement.Drivers; using Orchard.ContentManagement.MetaData; using Orchard.ContentManagement.MetaData.Builders; @@ -7,7 +8,7 @@ using Orchard.Core.Contents.Extensions; using Orchard.Data.Migration; namespace $$FeatureName$$.DataMigrations { - public class Migration : DataMigrationImpl { + public class Migrations : DataMigrationImpl { public int Create() { $$Commands$$ diff --git a/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleCsProj.txt b/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleCsProj.txt index 1d37c35b7..d56b6ae8f 100644 --- a/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleCsProj.txt +++ b/src/Orchard.Web/Modules/Orchard.CodeGeneration/CodeGenerationTemplates/ModuleCsProj.txt @@ -6,7 +6,7 @@ 9.0.30729 2.0 {$$ModuleProjectGuid$$} - {F85E285D-A4E0-4152-9332-AB1D724D3325};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} Library Properties $$ModuleName$$ @@ -39,6 +39,7 @@ AllRules.ruleset + diff --git a/src/Orchard.Web/Modules/Orchard.CodeGeneration/Commands/CodeGenerationCommands.cs b/src/Orchard.Web/Modules/Orchard.CodeGeneration/Commands/CodeGenerationCommands.cs index 63f71accc..edd77bbef 100644 --- a/src/Orchard.Web/Modules/Orchard.CodeGeneration/Commands/CodeGenerationCommands.cs +++ b/src/Orchard.Web/Modules/Orchard.CodeGeneration/Commands/CodeGenerationCommands.cs @@ -61,7 +61,7 @@ namespace Orchard.CodeGeneration.Commands { } string dataMigrationFolderPath = HostingEnvironment.MapPath("~/Modules/" + extensionDescriptor.Name + "/"); - string dataMigrationFilePath = dataMigrationFolderPath + "Migration.cs"; + string dataMigrationFilePath = dataMigrationFolderPath + "Migrations.cs"; string templatesPath = HostingEnvironment.MapPath("~/Modules/Orchard." + ModuleName + "/CodeGenerationTemplates/"); string moduleCsProjPath = HostingEnvironment.MapPath(string.Format("~/Modules/{0}/{0}.csproj", extensionDescriptor.Name)); @@ -93,11 +93,11 @@ namespace Orchard.CodeGeneration.Commands { // The string searches in solution/project files can be made aware of comment lines. if ( projectFileText.Contains("\r\n ", "DataMigrations\\" + extensionDescriptor.DisplayName + "DataMigration.cs"); + string compileReference = string.Format("\r\n ", "Migrations.cs"); projectFileText = projectFileText.Insert(projectFileText.LastIndexOf("\r\n \r\n \r\n ", "DataMigrations\\" + extensionDescriptor.DisplayName + "DataMigration.cs"); + string itemGroupReference = string.Format("\r\n \r\n \r\n ", "Migrations.cs"); projectFileText = projectFileText.Insert(projectFileText.LastIndexOf(""), itemGroupReference); } @@ -302,6 +302,7 @@ namespace Orchard.CodeGeneration.Commands { // include in solution but dont create a project: just add the references to Orchard.Themes project var itemGroup = CreateProjectItemGroup(HostingEnvironment.MapPath("~/Themes/"), createdFiles, createdFolders); AddFilesToOrchardThemesProject(output, itemGroup); + TouchSolution(output); } else { // create a project (already done) and add it to the solution diff --git a/src/Orchard.Web/Modules/Orchard.Widgets/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.Widgets/Controllers/AdminController.cs index 83da257c0..835c371c5 100644 --- a/src/Orchard.Web/Modules/Orchard.Widgets/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Widgets/Controllers/AdminController.cs @@ -7,7 +7,6 @@ using Orchard.Core.Contents.Controllers; using Orchard.Localization; using Orchard.UI.Admin; using Orchard.UI.Notify; -using Orchard.UI.Widgets; using Orchard.Widgets.Models; using Orchard.Widgets.Services; using Orchard.Widgets.ViewModels; @@ -20,16 +19,13 @@ namespace Orchard.Widgets.Controllers { private const string NotAuthorizedManageWidgetsLabel = "Not authorized to manage widgets"; private readonly IWidgetsService _widgetsService; - private readonly IRuleManager _ruleManager; public AdminController( IOrchardServices services, - IWidgetsService widgetsService, - IRuleManager ruleManager) { + IWidgetsService widgetsService) { Services = services; _widgetsService = widgetsService; - _ruleManager = ruleManager; T = NullLocalizer.Instance; } @@ -179,8 +175,6 @@ namespace Orchard.Widgets.Controllers { var model = Services.ContentManager.UpdateEditor(layerPart, this); - ValidateLayer(layerPart); - if (!ModelState.IsValid) { Services.TransactionManager.Cancel(); return View(model); @@ -227,8 +221,6 @@ namespace Orchard.Widgets.Controllers { var model = Services.ContentManager.UpdateEditor(layerPart, this); - ValidateLayer(layerPart); - if (!ModelState.IsValid) { Services.TransactionManager.Cancel(); return View(model); @@ -339,27 +331,6 @@ namespace Orchard.Widgets.Controllers { RedirectToAction("Index"); } - public bool ValidateLayer(LayerPart layer) { - if ( String.IsNullOrWhiteSpace(layer.LayerRule) ) { - layer.LayerRule = "true"; - } - - if(_widgetsService.GetLayers().Count(l => String.Equals(l.Name, layer.Name, StringComparison.InvariantCultureIgnoreCase)) > 1) { // the current layer counts for 1 - ModelState.AddModelError("Name", T("A Layer with the same name already exists").Text); - return false; - } - - try { - _ruleManager.Matches(layer.LayerRule); - } - catch ( Exception e ) { - ModelState.AddModelError("Description", T("The rule is not valid: {0}", e.Message).Text); - return false; - } - - return true; - } - bool IUpdateModel.TryUpdateModel(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) { return base.TryUpdateModel(model, prefix, includeProperties, excludeProperties); } diff --git a/src/Orchard.Web/Modules/Orchard.Widgets/Drivers/LayerPartDriver.cs b/src/Orchard.Web/Modules/Orchard.Widgets/Drivers/LayerPartDriver.cs index a37cfd2f6..e4d3c7b5d 100644 --- a/src/Orchard.Web/Modules/Orchard.Widgets/Drivers/LayerPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Widgets/Drivers/LayerPartDriver.cs @@ -1,12 +1,31 @@ -using JetBrains.Annotations; +using System; +using System.Linq; +using JetBrains.Annotations; using Orchard.ContentManagement; using Orchard.ContentManagement.Drivers; +using Orchard.Localization; +using Orchard.UI.Widgets; using Orchard.Widgets.Models; +using Orchard.Widgets.Services; namespace Orchard.Widgets.Drivers { [UsedImplicitly] public class LayerPartDriver : ContentPartDriver { + private readonly IRuleManager _ruleManager; + private readonly IWidgetsService _widgetsService; + + public LayerPartDriver( + IRuleManager ruleManager, + IWidgetsService widgetsService) { + + _ruleManager = ruleManager; + _widgetsService = widgetsService; + + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } protected override DriverResult Editor(LayerPart layerPart, dynamic shapeHelper) { return ContentShape("Parts_Widgets_LayerPart", @@ -14,7 +33,23 @@ namespace Orchard.Widgets.Drivers { } protected override DriverResult Editor(LayerPart layerPart, IUpdateModel updater, dynamic shapeHelper) { - updater.TryUpdateModel(layerPart, Prefix, null, null); + if(updater.TryUpdateModel(layerPart, Prefix, null, null)) { + if ( String.IsNullOrWhiteSpace(layerPart.LayerRule) ) { + layerPart.LayerRule = "true"; + } + + if ( _widgetsService.GetLayers().Any(l => String.Equals(l.Name, layerPart.Name, StringComparison.InvariantCultureIgnoreCase))) { + updater.AddModelError("Name", T("A Layer with the same name already exists")); + } + + try { + _ruleManager.Matches(layerPart.LayerRule); + } + catch ( Exception e ) { + updater.AddModelError("Description", T("The rule is not valid: {0}", e.Message)); + } + } + return Editor(layerPart, shapeHelper); } } diff --git a/src/Orchard.Web/Modules/Orchard.Widgets/Filters/WidgetFilter.cs b/src/Orchard.Web/Modules/Orchard.Widgets/Filters/WidgetFilter.cs index bc0e46f69..b971b1659 100644 --- a/src/Orchard.Web/Modules/Orchard.Widgets/Filters/WidgetFilter.cs +++ b/src/Orchard.Web/Modules/Orchard.Widgets/Filters/WidgetFilter.cs @@ -47,9 +47,8 @@ namespace Orchard.Widgets.Filters { IEnumerable widgetParts = _contentManager.Query().List(); IEnumerable activeLayers = _contentManager.Query().List(); - List activeLayerIds = new List(); + var activeLayerIds = new List(); foreach (var activeLayer in activeLayers) { - var context = workContext.HttpContext; // ignore the rule if it fails to execute try { if (_ruleManager.Matches(activeLayer.Record.LayerRule)) { @@ -57,7 +56,7 @@ namespace Orchard.Widgets.Filters { } } catch(Exception e) { - Logger.Debug(e, T("An error occured during layer evaluation on: {0}", activeLayer.Name).Text); + Logger.Warning(e, T("An error occured during layer evaluation on: {0}", activeLayer.Name).Text); } } diff --git a/src/Orchard.Web/Themes/TheAdmin/Styles/site.css b/src/Orchard.Web/Themes/TheAdmin/Styles/site.css index 687ee884f..03b7e88dc 100644 --- a/src/Orchard.Web/Themes/TheAdmin/Styles/site.css +++ b/src/Orchard.Web/Themes/TheAdmin/Styles/site.css @@ -120,7 +120,7 @@ body { h1,h2,h3,h4,h5,h6 { font-weight: normal;} h1 { font-size: 1.692em } -h2, h2 span { font-size: 1.538em; } +h2 { font-size: 1.538em; } h3 { font-size: 1.231em; } h4 { font-size: 1.154em; } h5 { font-size: 1.077em; } @@ -482,7 +482,6 @@ label { } label.forcheckbox { display:inline; - line-height:1.8em; } .bulk-actions label, .bulk-items h3, label.sub { display:inline; @@ -618,7 +617,7 @@ input[type="submit"]:hover,input[type="reset"]:hover, input[type="button"]:hover background: -webkit-gradient(linear, 0 0, 0 100%, from(#ffac40), to(#f9760d)); background: -moz-linear-gradient(top, #ffac40, #f9760d); } -input[type="submit"]:active, input[type="reset"]:active, input[type="button"]:active, button:active { +input[type="submit"]:active, input[type="reset"]:active, input[type="button"]:active, button:active, .buton:active, .button.primaryAction:active { text-decoration:none; background: #62a9e2; color:#fff; @@ -872,7 +871,7 @@ table .button { padding:1em; } .orchard-media fieldset div, .settings fieldset div, .settings .button { - margin:1em 0 .5em; + margin:.5em 0; } .settings legend { margin:0 0 -.4em; @@ -890,7 +889,7 @@ fieldset.publish-later-datetime { min-width:13.6em; padding-left:6px; padding-right:0; - width:68%; + width:50%; } fieldset.publish-later-datetime legend { display:none; diff --git a/src/Orchard/Data/Migration/DataMigrationManager.cs b/src/Orchard/Data/Migration/DataMigrationManager.cs index 06a8bffeb..8d1adebac 100644 --- a/src/Orchard/Data/Migration/DataMigrationManager.cs +++ b/src/Orchard/Data/Migration/DataMigrationManager.cs @@ -188,7 +188,7 @@ namespace Orchard.Data.Migration { .ToList(); foreach (var migration in migrations.OfType()) { - migration.SchemaBuilder = new SchemaBuilder(_interpreter, migration.Feature.Descriptor.Name.Replace(".", "_") + "_"); + migration.SchemaBuilder = new SchemaBuilder(_interpreter, migration.Feature.Descriptor.Name, (s) => s.Replace(".", "_") + "_"); migration.ContentDefinitionManager = _contentDefinitionManager; } diff --git a/src/Orchard/Data/Migration/Schema/SchemaBuilder.cs b/src/Orchard/Data/Migration/Schema/SchemaBuilder.cs index cfe318267..af73145b8 100644 --- a/src/Orchard/Data/Migration/Schema/SchemaBuilder.cs +++ b/src/Orchard/Data/Migration/Schema/SchemaBuilder.cs @@ -5,28 +5,30 @@ namespace Orchard.Data.Migration.Schema { public class SchemaBuilder { private readonly IDataMigrationInterpreter _interpreter; private readonly string _featurePrefix; + private readonly Func _formatPrefix; - public SchemaBuilder(IDataMigrationInterpreter interpreter, string featurePrefix = null) { + public SchemaBuilder(IDataMigrationInterpreter interpreter, string featurePrefix = null, Func formatPrefix = null) { _interpreter = interpreter; - _featurePrefix = featurePrefix; + _featurePrefix = featurePrefix ?? String.Empty; + _formatPrefix = formatPrefix ?? (s => s ?? String.Empty); } public SchemaBuilder CreateTable(string name, Action table) { - var createTable = new CreateTableCommand(String.Concat(_featurePrefix, name)); + var createTable = new CreateTableCommand(String.Concat(_formatPrefix(_featurePrefix), name)); table(createTable); Run(createTable); return this; } public SchemaBuilder AlterTable(string name, Action table) { - var alterTable = new AlterTableCommand(String.Concat(_featurePrefix, name)); + var alterTable = new AlterTableCommand(String.Concat(_formatPrefix(_featurePrefix), name)); table(alterTable); Run(alterTable); return this; } public SchemaBuilder DropTable(string name) { - var deleteTable = new DropTableCommand(String.Concat(_featurePrefix, name)); + var deleteTable = new DropTableCommand(String.Concat(_formatPrefix(_featurePrefix), name)); Run(deleteTable); return this; } @@ -45,13 +47,37 @@ namespace Orchard.Data.Migration.Schema { } public SchemaBuilder CreateForeignKey(string name, string srcTable, string[] srcColumns, string destTable, string[] destColumns) { - var command = new CreateForeignKeyCommand(name, String.Concat(_featurePrefix, srcTable), srcColumns, String.Concat(_featurePrefix, destTable), destColumns); + var command = new CreateForeignKeyCommand(name, String.Concat(_formatPrefix(_featurePrefix), srcTable), srcColumns, String.Concat(_formatPrefix(_featurePrefix), destTable), destColumns); + Run(command); + return this; + } + + public SchemaBuilder CreateForeignKey(string name, string srcModule, string srcTable, string[] srcColumns, string destTable, string[] destColumns) { + var command = new CreateForeignKeyCommand(name, String.Concat(_formatPrefix(srcModule), srcTable), srcColumns, String.Concat(_formatPrefix(_featurePrefix), destTable), destColumns); + Run(command); + return this; + } + + public SchemaBuilder CreateForeignKey(string name, string srcTable, string[] srcColumns, string destModule, string destTable, string[] destColumns) { + var command = new CreateForeignKeyCommand(name, String.Concat(_formatPrefix(_featurePrefix), srcTable), srcColumns, String.Concat(_formatPrefix(destModule), destTable), destColumns); + Run(command); + return this; + } + + public SchemaBuilder CreateForeignKey(string name, string srcModule, string srcTable, string[] srcColumns, string destModule, string destTable, string[] destColumns) { + var command = new CreateForeignKeyCommand(name, String.Concat(_formatPrefix(srcModule), srcTable), srcColumns, String.Concat(_formatPrefix(destModule), destTable), destColumns); Run(command); return this; } public SchemaBuilder DropForeignKey(string srcTable, string name) { - var command = new DropForeignKeyCommand(String.Concat(_featurePrefix, srcTable), name); + var command = new DropForeignKeyCommand(String.Concat(_formatPrefix(_featurePrefix), srcTable), name); + Run(command); + return this; + } + + public SchemaBuilder DropForeignKey(string srcModule, string srcTable, string name) { + var command = new DropForeignKeyCommand(String.Concat(_formatPrefix(srcModule), srcTable), name); Run(command); return this; }