Skip to content

Instantly share code, notes, and snippets.

@anaisbetts
Created May 19, 2012 23:37
Show Gist options
  • Save anaisbetts/2732823 to your computer and use it in GitHub Desktop.
Save anaisbetts/2732823 to your computer and use it in GitHub Desktop.
///////////////
// Type in this
///////////////
interface IColorPicker : IRoutableViewModel {
int Red { get; set; }
int Green { get; set; }
int Blue { get; set; }
Color FinalColor { get; }
}
interface ILoginDialog : IRoutableViewModel {
[Once]
IAppState AppState { get; }
string User { get; set; }
string Password { get; set; }
string PasswordAgain { get; set; }
ReactiveCommand Ok { get; }
}
//////////////////
//
// And you get this as output:
// NB: Not *quite* this, but 99% of the way there!
//////////////////
using System;
using ReactiveUI;
using ReactiveUI.Xaml;
using ReactiveUI.Routing;
namespace TODOFillMeIn.ViewModels
{
interface IColorPicker : IRoutableViewModel
{
int Red { get; set; }
int Green { get; set; }
int Blue { get; set; }
Color FinalColor { get; }
}
interface ILoginDialog : IRoutableViewModel
{
IAppState AppState { get; }
string User { get; set; }
string Password { get; set; }
string PasswordAgain { get; set; }
ReactiveCommand Ok { get; }
}
public void ColorPicker : ReactiveObject, IColorPicker
{
int _Red;
public int Red {
get { return _Red; }
set { this.RaiseAndSetIfChanged(x => x.Red, value); }
}
int _Green;
public int Green {
get { return _Green; }
set { this.RaiseAndSetIfChanged(x => x.Green, value); }
}
int _Blue;
public int Blue {
get { return _Blue; }
set { this.RaiseAndSetIfChanged(x => x.Blue, value); }
}
ObservableAsPropertyHelper<Color> _FinalColor;
public Color FinalColor {
get { return _FinalColor; }
}
public IScreen HostScreen { get; protected set; }
public string UrlPathSegment {
get { return "TODO: Implement Me"; }
}
public ColorPicker(IScreen hostScreen)
{
HostScreen = hostScreen;
// TODO: Wire up your properties here!
}
}
public void LoginDialog : ReactiveObject, ILoginDialog
{
IAppState AppState { get; protected set; }
string _User;
public string User {
get { return _User; }
set { this.RaiseAndSetIfChanged(x => x.User, value); }
}
string _Password;
public string Password {
get { return _Password; }
set { this.RaiseAndSetIfChanged(x => x.Password, value); }
}
string _PasswordAgain;
public string PasswordAgain {
get { return _PasswordAgain; }
set { this.RaiseAndSetIfChanged(x => x.PasswordAgain, value); }
}
ReactiveCommand Ok { get; protected set; }
public IScreen HostScreen { get; protected set; }
public string UrlPathSegment {
get { return "TODO: Implement Me"; }
}
public LoginDialog(IScreen hostScreen)
{
HostScreen = hostScreen;
AppState = null; // TODO: Set me
Ok = null; // TODO: Set me
// TODO: Wire up your properties here!
}
}
}
using System;
using ReactiveUI;
using ReactiveUI.Xaml;
using ReactiveUI.Routing;
namespace TODOFillMeIn.ViewModels
{
{{#interfaces}}
{{definition}}
{{/interfaces}}
{{#interfaces}}
public void {{implClassName}} : ReactiveObject, {{interfaceName}}
{
{{#properties}}
{{#outputProp}}
ObservableAsPropertyHelper<{{type}}> _{{name}};
public {{type}} {{name}}
{
get { return _{{name}}; }
}
{{/outputProp}}
{{#readWriteProp}}
{{type}} _{{name}};
public {{type}} {{name}}
{
get { return _{{name}}; }
set { this.RaiseAndSetIfChanged(x => x.{{name}}, value); }
}
{{/readWriteProp}}
{{#onceProp}}
{{type}} {{name}} { get; protected set; }
{{/onceProp}}
{{#anythingElse}}
{{name}}
{{/anythingElse}}
{{/properties}}
{{#isRoutableViewModel}}
public IScreen HostScreen { get; protected set; }
public string UrlPathSegment {
get { return "TODO: Implement Me"; }
}
public {{implClassName}}(IScreen hostScreen)
{
HostScreen = hostScreen;
{{#onceProperties}}
{{name}} = null; // TODO: Set me
{{/onceProperties}}
// TODO: Wire up your properties here!
}
{{/isRoutableViewModel}}
{{^isRoutableViewModel}}
public {{implClassName}}()
{
{{#onceProperties}}
{{name}} = null; // TODO: Set me
{{/onceProperties}}
// TODO: Wire up your properties here!
}
{{/isRoutableViewModel}}
}
{{/interfaces}}
}
public class ViewModelRenderer : IEnableLogger
{
public string RenderViewModel(string interfaceCode)
{
var tree = SyntaxTree.ParseCompilationUnit(interfaceCode, "foo.cs");
var root = tree.GetRoot(new CancellationToken());
if (!root.ChildNodes().Any()) {
throw new ArgumentException("Compilation failed or code is badly formatted");
}
if (!root.ChildNodes().All(x => x is InterfaceDeclarationSyntax)) {
throw new ArgumentException("Code must be one ore more interfaces");
}
var renderInfo = root.ChildNodes()
.OfType<InterfaceDeclarationSyntax>()
.Select(renderInterface)
.ToArray();
var template = File.ReadAllText(@"C:\Users\Administrator\Documents\GitHub\RxUIInterfaceToVM\Template.mustache");
var ret = chompedString(Nustache.Core.Render.StringToString(template, new { interfaces = renderInfo }));
return ret;
}
InterfaceRenderInformation renderInterface(InterfaceDeclarationSyntax interfaceDecl)
{
var ret = new InterfaceRenderInformation();
ret.isRoutableViewModel = interfaceDecl.BaseListOpt.Types.Any(x => x.PlainName == "IRoutableViewModel") ? this : null;
ret.definition = chompedString(interfaceDecl.ToString().Replace("[Once]", ""));
ret.interfaceName = chompedString(interfaceDecl.Identifier.ValueText);
ret.implClassName = ret.interfaceName.Substring(1); // Skip the 'I'
var children = interfaceDecl.ChildNodes().Skip(1);
ret.properties = children.Select(renderPropertyDeclaration).ToArray();
ret.onceProperties = ret.properties.Where(x => x.onceProp != null).Select(x => x.onceProp).ToArray();
return ret;
}
PropertyRenderInformation renderPropertyDeclaration(SyntaxNode node)
{
var propDecl = node as PropertyDeclarationSyntax;
if (propDecl == null) {
return new PropertyRenderInformation() {
anythingElse = new NameAndTypeRenderInformation() { name = chompedString(node.ToString()) },
};
}
var nameAndType = new NameAndTypeRenderInformation() {
name = chompedString(propDecl.Identifier.ValueText),
type = chompedString(propDecl.Type.PlainName),
};
var commands = new[] {
"ReactiveCommand",
"ReactiveAsyncCommand",
};
if (propDecl.Attributes.SelectMany(x => x.Attributes).Any(x => x.Name.PlainName == "Once") ||
commands.Contains(propDecl.Type.PlainName)) {
return new PropertyRenderInformation() { onceProp = nameAndType, };
}
if (propDecl.AccessorList.Accessors.Any(x => x.Keyword.Kind == SyntaxKind.SetKeyword)) {
return new PropertyRenderInformation() { readWriteProp = nameAndType, };
} else {
return new PropertyRenderInformation() { outputProp = nameAndType, };
}
}
string chompedString(string code)
{
if (!code.Contains("\n")) {
return code.TrimEnd(' ', '\t');
}
var lines = code.Split('\n')
.Select(x => x.TrimEnd(' ', '\t'))
.Where(x => !(String.IsNullOrWhiteSpace(x) && x.Length > 2));
return String.Join("\n", lines);
}
}
public class InterfaceRenderInformation
{
public IEnumerable<PropertyRenderInformation> properties { get; set; }
public string definition { get; set; }
public string implClassName { get; set; }
public string interfaceName { get; set; }
public object isRoutableViewModel { get; set; } // 'this' if true, null if false, Mustacheism
public IEnumerable<NameAndTypeRenderInformation> onceProperties { get; set; }
}
public class PropertyRenderInformation
{
// NB: Only *one* of these should be non-null, Mustacheism
public NameAndTypeRenderInformation outputProp { get; set; }
public NameAndTypeRenderInformation onceProp { get; set; }
public NameAndTypeRenderInformation readWriteProp { get; set; }
public NameAndTypeRenderInformation anythingElse { get; set; }
}
public class NameAndTypeRenderInformation
{
public string name { get; set; }
public string type { get; set; }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment