From d8dc5195b6e79bda890e301ea8fc6561eff3ea72 Mon Sep 17 00:00:00 2001 From: Christian Resma Helle Date: Thu, 8 Nov 2012 22:30:53 +0100 Subject: [PATCH] implemented codedom basd code generation --- .../CodeDomCodeGenerator.cs | 101 ++++++++++++++++++ .../ReswCodeGen.CustomTool/CodeGenerator.cs | 16 +++ .../CodeGeneratorFactory.cs | 2 +- .../ReswCodeGen.CustomTool/IResourceParser.cs | 33 +++++- .../ReswCodeGen.CustomTool.csproj | 4 +- .../CodeGeneratorFactoryTests.cs | 26 +++++ .../ReswCodeGen.Tests/CodeGeneratorTests.cs | 50 +++++++++ .../ReswCodeGen.Tests/ResourceParserTests.cs | 45 ++++++++ .../ReswCodeGen.Tests.csproj | 2 + 9 files changed, 276 insertions(+), 3 deletions(-) create mode 100644 RESW File Code Generator/ReswCodeGen.CustomTool/CodeDomCodeGenerator.cs create mode 100644 RESW File Code Generator/ReswCodeGen.CustomTool/CodeGenerator.cs create mode 100644 RESW File Code Generator/ReswCodeGen.Tests/CodeGeneratorFactoryTests.cs create mode 100644 RESW File Code Generator/ReswCodeGen.Tests/CodeGeneratorTests.cs diff --git a/RESW File Code Generator/ReswCodeGen.CustomTool/CodeDomCodeGenerator.cs b/RESW File Code Generator/ReswCodeGen.CustomTool/CodeDomCodeGenerator.cs new file mode 100644 index 0000000..c345906 --- /dev/null +++ b/RESW File Code Generator/ReswCodeGen.CustomTool/CodeDomCodeGenerator.cs @@ -0,0 +1,101 @@ +using System; +using System.CodeDom; +using System.CodeDom.Compiler; +using System.Globalization; +using System.IO; +using System.Text; +using Microsoft.CSharp; + +namespace ChristianHelle.DeveloperTools.CodeGenerators.Resw.CustomTool +{ + public class CodeDomCodeGenerator : CodeGenerator + { + private readonly CodeNamespace codeNamespace; + private readonly CodeCompileUnit compileUnit; + private readonly CodeDomProvider provider; + + public CodeDomCodeGenerator(IResourceParser resourceParser, string defaultNamespace, CodeDomProvider codeDomProvider = null) + : base(resourceParser, defaultNamespace) + { + compileUnit = new CodeCompileUnit(); + provider = codeDomProvider ?? new CSharpCodeProvider(); + codeNamespace = new CodeNamespace(defaultNamespace); + } + + public override string GenerateCode() + { + codeNamespace.Comments.Add(new CodeCommentStatement("--------------------------------------------------------------------------------------------------")); + codeNamespace.Comments.Add(new CodeCommentStatement("")); + codeNamespace.Comments.Add(new CodeCommentStatement("\tThis code was generated by ResW File Code Generator (http://reswcodegen.codeplex.com)")); + codeNamespace.Comments.Add(new CodeCommentStatement("\tResW File Code Generator was written by Christian Resma Helle")); + codeNamespace.Comments.Add(new CodeCommentStatement("\tand is under GNU General Public License version 2 (GPLv2)")); + codeNamespace.Comments.Add(new CodeCommentStatement(string.Empty)); + codeNamespace.Comments.Add(new CodeCommentStatement("\tThis code contains a helper class exposing property representations")); + codeNamespace.Comments.Add(new CodeCommentStatement("\tof the string resources defined in the specified .ResW file")); + codeNamespace.Comments.Add(new CodeCommentStatement(string.Empty)); + codeNamespace.Comments.Add(new CodeCommentStatement("\tGenerated: " + DateTime.Now.ToString(CultureInfo.InvariantCulture))); + codeNamespace.Comments.Add(new CodeCommentStatement("")); + codeNamespace.Comments.Add(new CodeCommentStatement("--------------------------------------------------------------------------------------------------")); + + codeNamespace.Imports.Add(new CodeNamespaceImport("Windows.ApplicationModel.Resources")); + + var targetClass = new CodeTypeDeclaration("Resources") + { + IsClass = true, + IsPartial = true, + Attributes = MemberAttributes.Public | MemberAttributes.Static + }; + + const string resourceLoaderType = "ResourceLoader"; + var resourceLoaderField = new CodeMemberField(resourceLoaderType, "resourceLoader") + { + Attributes = MemberAttributes.Private | MemberAttributes.Static | MemberAttributes.Final, + InitExpression = new CodeObjectCreateExpression(resourceLoaderType) + }; + targetClass.Members.Add(resourceLoaderField); + + var resources = ResourceParser.Parse(); + foreach (var item in resources) + { + if (item.Name.Contains(".")) + continue; + + var property = new CodeMemberProperty + { + Name = item.Name.Trim(), + Attributes = MemberAttributes.Public | MemberAttributes.Static, + HasGet = true, + Type = new CodeTypeReference(typeof(string)) + }; + + property.Comments.Add(new CodeCommentStatement("", true)); + property.Comments.Add(new CodeCommentStatement("Localized resource similar to \"" + item.Value + "\"", true)); + property.Comments.Add(new CodeCommentStatement("", true)); + property.GetStatements.Add( + new CodeMethodReturnStatement( + new CodeMethodInvokeExpression( + new CodeFieldReferenceExpression(null, "resourceLoader"), "GetString", + new CodePrimitiveExpression(item.Name)))); + + targetClass.Members.Add(property); + } + + codeNamespace.Types.Add(targetClass); + compileUnit.Namespaces.Add(codeNamespace); + + return GenerateCodeFromCompileUnit(); + } + + private string GenerateCodeFromCompileUnit() + { + var options = new CodeGeneratorOptions { BracingStyle = "C" }; + + var code = new StringBuilder(); + + using (var writer = new StringWriter(code)) + provider.GenerateCodeFromCompileUnit(compileUnit, writer, options); + + return code.ToString(); + } + } +} \ No newline at end of file diff --git a/RESW File Code Generator/ReswCodeGen.CustomTool/CodeGenerator.cs b/RESW File Code Generator/ReswCodeGen.CustomTool/CodeGenerator.cs new file mode 100644 index 0000000..a3560bb --- /dev/null +++ b/RESW File Code Generator/ReswCodeGen.CustomTool/CodeGenerator.cs @@ -0,0 +1,16 @@ +namespace ChristianHelle.DeveloperTools.CodeGenerators.Resw.CustomTool +{ + public abstract class CodeGenerator : ICodeGenerator + { + protected CodeGenerator(IResourceParser resourceParser, string defaultNamespace) + { + ResourceParser = resourceParser; + Namespace = defaultNamespace; + } + + public IResourceParser ResourceParser { get; set; } + public string Namespace { get; set; } + + public abstract string GenerateCode(); + } +} \ No newline at end of file diff --git a/RESW File Code Generator/ReswCodeGen.CustomTool/CodeGeneratorFactory.cs b/RESW File Code Generator/ReswCodeGen.CustomTool/CodeGeneratorFactory.cs index 063e41a..f9fc183 100644 --- a/RESW File Code Generator/ReswCodeGen.CustomTool/CodeGeneratorFactory.cs +++ b/RESW File Code Generator/ReswCodeGen.CustomTool/CodeGeneratorFactory.cs @@ -4,7 +4,7 @@ { public ICodeGenerator Create(string defaultNamespace, string inputFileContents) { - return null; + return new CodeDomCodeGenerator(new ResourceParser(inputFileContents), defaultNamespace); } } } diff --git a/RESW File Code Generator/ReswCodeGen.CustomTool/IResourceParser.cs b/RESW File Code Generator/ReswCodeGen.CustomTool/IResourceParser.cs index 1b94e21..13d3523 100644 --- a/RESW File Code Generator/ReswCodeGen.CustomTool/IResourceParser.cs +++ b/RESW File Code Generator/ReswCodeGen.CustomTool/IResourceParser.cs @@ -1,10 +1,41 @@ using System.Collections.Generic; +using System.Linq; +using System.Xml.Linq; namespace ChristianHelle.DeveloperTools.CodeGenerators.Resw.CustomTool { public interface IResourceParser { - string ReswContent { get; set; } + string ReswFileContents { get; set; } List Parse(); } + + public class ResourceParser : IResourceParser + { + public ResourceParser(string reswFileContents) + { + ReswFileContents = reswFileContents; + } + + public string ReswFileContents { get; set; } + + public List Parse() + { + var doc = XDocument.Parse(ReswFileContents); + + var list = new List(); + + foreach (var element in doc.Descendants("data")) + { + list.Add(new ResourceItem + { + Name = element.Attribute("name").Value, + Value = element.Descendants("value").First().Value, + Comment = element.Descendants("comment").First().Value + }); + } + + return list; + } + } } \ No newline at end of file diff --git a/RESW File Code Generator/ReswCodeGen.CustomTool/ReswCodeGen.CustomTool.csproj b/RESW File Code Generator/ReswCodeGen.CustomTool/ReswCodeGen.CustomTool.csproj index a402f20..90428e7 100644 --- a/RESW File Code Generator/ReswCodeGen.CustomTool/ReswCodeGen.CustomTool.csproj +++ b/RESW File Code Generator/ReswCodeGen.CustomTool/ReswCodeGen.CustomTool.csproj @@ -31,7 +31,7 @@ 4 - false + true ReswCodeGen.snk @@ -50,6 +50,8 @@ + + diff --git a/RESW File Code Generator/ReswCodeGen.Tests/CodeGeneratorFactoryTests.cs b/RESW File Code Generator/ReswCodeGen.Tests/CodeGeneratorFactoryTests.cs new file mode 100644 index 0000000..bf7d5fd --- /dev/null +++ b/RESW File Code Generator/ReswCodeGen.Tests/CodeGeneratorFactoryTests.cs @@ -0,0 +1,26 @@ +using System.IO; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace ChristianHelle.DeveloperTools.CodeGenerators.Resw.CustomTool.Tests +{ + [TestClass] + [DeploymentItem("Resources/Resources.resw")] + public class CodeGeneratorFactoryTests + { + private string reswFileContents; + + [TestInitialize] + public void Initialize() + { + reswFileContents = File.ReadAllText("Resources.resw"); + } + + [TestMethod] + public void CodeGeneratorFactoryReturnsValidInstance() + { + var target = new CodeGeneratorFactory(); + var actual = target.Create("TestApp", reswFileContents); + Assert.IsNotNull(actual); + } + } +} \ No newline at end of file diff --git a/RESW File Code Generator/ReswCodeGen.Tests/CodeGeneratorTests.cs b/RESW File Code Generator/ReswCodeGen.Tests/CodeGeneratorTests.cs new file mode 100644 index 0000000..92ac57f --- /dev/null +++ b/RESW File Code Generator/ReswCodeGen.Tests/CodeGeneratorTests.cs @@ -0,0 +1,50 @@ +using System.Diagnostics; +using System.IO; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace ChristianHelle.DeveloperTools.CodeGenerators.Resw.CustomTool.Tests +{ + [TestClass] + [DeploymentItem("Resources/Resources.resw")] + public class CodeGeneratorTests + { + private string reswFileContents; + + [TestInitialize] + public void Initialize() + { + reswFileContents = File.ReadAllText("Resources.resw"); + } + + [TestMethod] + public void GenerateCodeDoesNotReturnNull() + { + var target = new CodeGeneratorFactory().Create("TestApp", reswFileContents); + var actual = target.GenerateCode(); + Assert.IsNotNull(actual); + } + + [TestMethod] + public void GeneratedCodeContainsPropertiesDefinedInResources() + { + var target = new CodeGeneratorFactory().Create("TestApp", reswFileContents); + var resourceItems = target.ResourceParser.Parse(); + var actual = target.GenerateCode(); + + foreach (var item in resourceItems.Where(item => !item.Name.Contains("."))) + Assert.IsTrue(actual.Contains("public static string " + item.Name)); + } + + [TestMethod] + public void GeneratedCodePropertiesContainsCommentsSimilarToValuesDefinedInResources() + { + var target = new CodeGeneratorFactory().Create("TestApp", reswFileContents); + var resourceItems = target.ResourceParser.Parse(); + var actual = target.GenerateCode(); + + foreach (var item in resourceItems.Where(item => !item.Name.Contains("."))) + Assert.IsTrue(actual.Contains("Localized resource similar to \"" + item.Value + "\"")); + } + } +} \ No newline at end of file diff --git a/RESW File Code Generator/ReswCodeGen.Tests/ResourceParserTests.cs b/RESW File Code Generator/ReswCodeGen.Tests/ResourceParserTests.cs index a48a5d1..06bb83a 100644 --- a/RESW File Code Generator/ReswCodeGen.Tests/ResourceParserTests.cs +++ b/RESW File Code Generator/ReswCodeGen.Tests/ResourceParserTests.cs @@ -61,5 +61,50 @@ namespace ChristianHelle.DeveloperTools.CodeGenerators.Resw.CustomTool.Tests CollectionAssert.AllItemsAreNotNull(list); } + + [TestMethod] + public void ConstructorSetsReswFileContents() + { + var target = new ResourceParser(reswFileContents); + Assert.IsNotNull(target.ReswFileContents); + } + + [TestMethod] + public void ParseReturnsResourceItems() + { + var target = new ResourceParser(reswFileContents); + var actual = target.Parse(); + Assert.IsNotNull(actual); + } + + [TestMethod] + public void ParseReturnedResourceItemsContainsName() + { + var target = new ResourceParser(reswFileContents); + var actual = target.Parse(); + + foreach (var item in actual) + Assert.IsNotNull(item.Name); + } + + [TestMethod] + public void ParseReturnedResourceItemsContainsValue() + { + var target = new ResourceParser(reswFileContents); + var actual = target.Parse(); + + foreach (var item in actual) + Assert.IsNotNull(item.Value); + } + + [TestMethod] + public void ParseReturnedResourceItemsContainsComment() + { + var target = new ResourceParser(reswFileContents); + var actual = target.Parse(); + + foreach (var item in actual) + Assert.IsNotNull(item.Comment); + } } } \ No newline at end of file diff --git a/RESW File Code Generator/ReswCodeGen.Tests/ReswCodeGen.Tests.csproj b/RESW File Code Generator/ReswCodeGen.Tests/ReswCodeGen.Tests.csproj index a15ca39..73b3457 100644 --- a/RESW File Code Generator/ReswCodeGen.Tests/ReswCodeGen.Tests.csproj +++ b/RESW File Code Generator/ReswCodeGen.Tests/ReswCodeGen.Tests.csproj @@ -55,6 +55,8 @@ + +