implemented codedom basd code generation

This commit is contained in:
Christian Resma Helle
2012-11-08 22:30:53 +01:00
parent 1559769152
commit d8dc5195b6
9 changed files with 276 additions and 3 deletions
@@ -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("<auto-generatedInfo>"));
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("</auto-generatedInfo>"));
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("<summary>", true));
property.Comments.Add(new CodeCommentStatement("Localized resource similar to \"" + item.Value + "\"", true));
property.Comments.Add(new CodeCommentStatement("</summary>", 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();
}
}
}
@@ -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();
}
}
@@ -4,7 +4,7 @@
{
public ICodeGenerator Create(string defaultNamespace, string inputFileContents)
{
return null;
return new CodeDomCodeGenerator(new ResourceParser(inputFileContents), defaultNamespace);
}
}
}
@@ -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<ResourceItem> Parse();
}
public class ResourceParser : IResourceParser
{
public ResourceParser(string reswFileContents)
{
ReswFileContents = reswFileContents;
}
public string ReswFileContents { get; set; }
public List<ResourceItem> Parse()
{
var doc = XDocument.Parse(ReswFileContents);
var list = new List<ResourceItem>();
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;
}
}
}
@@ -31,7 +31,7 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>false</SignAssembly>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>ReswCodeGen.snk</AssemblyOriginatorKeyFile>
@@ -50,6 +50,8 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="CodeDomCodeGenerator.cs" />
<Compile Include="CodeGenerator.cs" />
<Compile Include="CodeGeneratorFactory.cs" />
<Compile Include="ICodeGenerator.cs" />
<Compile Include="IResourceParser.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);
}
}
}
@@ -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 + "\""));
}
}
}
@@ -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);
}
}
}
@@ -55,6 +55,8 @@
</Otherwise>
</Choose>
<ItemGroup>
<Compile Include="CodeGeneratorFactoryTests.cs" />
<Compile Include="CodeGeneratorTests.cs" />
<Compile Include="ResourceParserTests.cs" />
<Compile Include="Spikes.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />