public void TestScriptObjectImport() { { var obj = new ScriptObject(); obj.Import(typeof(MyStaticObject)); Assert.True(obj.ContainsKey("static_field_a")); Assert.Equal("ValueStaticFieldA", obj["static_field_a"]); Assert.True(obj.ContainsKey("static_field_b")); Assert.Equal("ValueStaticFieldB", obj["static_field_b"]); Assert.True(obj.ContainsKey("static_property_a")); Assert.Equal("ValueStaticPropertyA", obj["static_property_a"]); Assert.True(obj.ContainsKey("static_property_b")); Assert.Equal("ValueStaticPropertyB", obj["static_property_b"]); Assert.True(obj.ContainsKey("static_yoyo")); Assert.False(obj.ContainsKey("invalid")); } // Test MemberFilterDelegate { var obj = new ScriptObject(); obj.Import(typeof(MyStaticObject), filter: member => member.Name.Contains("Property")); Assert.False(obj.ContainsKey("static_field_a")); Assert.False(obj.ContainsKey("static_field_b")); Assert.True(obj.ContainsKey("static_property_a")); Assert.Equal("ValueStaticPropertyA", obj["static_property_a"]); Assert.True(obj.ContainsKey("static_property_b")); Assert.Equal("ValueStaticPropertyB", obj["static_property_b"]); Assert.False(obj.ContainsKey("static_yoyo")); Assert.False(obj.ContainsKey("invalid")); } // Test MemberRenamerDelegate { var obj = new ScriptObject(); obj.Import(typeof(MyStaticObject), renamer: member => member.Name); Assert.True(obj.ContainsKey(nameof(MyStaticObject.StaticFieldA))); Assert.True(obj.ContainsKey(nameof(MyStaticObject.StaticFieldB))); Assert.True(obj.ContainsKey(nameof(MyStaticObject.StaticPropertyA))); Assert.Equal("ValueStaticPropertyA", obj[nameof(MyStaticObject.StaticPropertyA)]); Assert.True(obj.ContainsKey(nameof(MyStaticObject.StaticPropertyB))); Assert.Equal("ValueStaticPropertyB", obj[nameof(MyStaticObject.StaticPropertyB)]); Assert.True(obj.ContainsKey(nameof(MyStaticObject.StaticYoyo))); Assert.False(obj.ContainsKey(nameof(MyStaticObject.Invalid))); } { var obj = new ScriptObject(); obj.Import(new MyObject2(), renamer: member => member.Name); Assert.Equal(9, obj.Count); Assert.True(obj.ContainsKey(nameof(MyStaticObject.StaticFieldA))); Assert.True(obj.ContainsKey(nameof(MyObject.PropertyA))); Assert.True(obj.ContainsKey(nameof(MyObject2.PropertyC))); } }
/// <summary> /// Adds or updates a value /// </summary> /// <param name="scriptObject">Script object that is being updated</param> /// <param name="key">Key</param> /// <param name="value">Value</param> public static void AddOrUpdate(this ScriptObject scriptObject, string key, object value) { if (scriptObject.ContainsKey(key)) { scriptObject[key] = value; } else { scriptObject.Add(key, value); } }
/// <summary> /// <b>布局递归渲染器.</b><br /> /// 例如, 给定一个 ScriptObject, 一个布局模板文件(解析过meta 的)<br /> /// 本函数将把 ScriptObject 渲染至其中, 然后读取该布局文件的上层布局文件,<br /> /// 在此把 ScriptObject 渲染至其中, 重复进行这一过程, 直到没有上层布局文件, 最后返回渲染结果 html<br /> /// </summary> /// <returns></returns> public static string Render(ScriptObject pageModel, ScriptObject layoutPageModel) { var store = Engine.App.Store; var layoutContext = new TemplateContext() { TemplateLoader = store.TemplateLoader }; var paginatorModel = Converter.ObjectToScriptObject( new { Page = 1, Previous_Page = 0, Next_Page = 2, Total_Pages = 10 } ); // 0. 导入 pipe 函数 layoutContext.BuiltinObject.Import(typeof(PipeFunctions)); // 1. 将全局数据推送给模板 layoutContext.PushGlobal(Converter.WrapScriptObject("site", store.SiteModel)); layoutContext.PushGlobal(Converter.WrapScriptObject("content", pageModel["_content"])); layoutContext.PushGlobal(Converter.WrapScriptObject("page", new[] { pageModel, // 2. 将内容的模板数据推送给模板 layoutPageModel // 3. 将布局自身的模板数据推送给模板 })); // 4. 对于分页的处理 layoutContext.PushGlobal(Converter.WrapScriptObject("paginator", paginatorModel)); var layoutTemplate = Template.Parse(layoutPageModel.GetSafeValue <string>("_rawText")); var layoutResultHtml = layoutTemplate.Render(layoutContext); Logger.Info("* 渲染结束"); // 判断是否需要递归渲染 if (!layoutPageModel.ContainsKey("layout") || layoutPageModel.GetSafeValue <string>("layout") == "null") { return(layoutResultHtml); } var outLayoutShortName = layoutPageModel.GetSafeValue <string>("layout"); Logger.Info("发现上级布局, 进行递归渲染. 布局文件为: " + layoutPageModel.GetSafeValue <string>("layout")); var outLayout = store.GetLayoutFromCache(outLayoutShortName); //Logger.Info(Logger.Indent(isRecRendering) + "递归渲染中, 当前层数: " + isRecRendering); isRecRendering++; pageModel["_content"] = layoutResultHtml; var html = Render(pageModel, outLayout); isRecRendering--; Logger.Info(Logger.Indent(isRecRendering) + "递归渲染结束, 层数: " + isRecRendering); return(html); }
/// <summary> /// Collects the values for an export /// </summary> /// <param name="templateType">Template type</param> /// <param name="parsedTemplate">Parsed scriban template</param> /// <param name="scriptObject">Scriban script object to fill</param> /// <param name="data">Export Data</param> /// <returns>Task</returns> public override Task CollectValues(TemplateType templateType, Template parsedTemplate, ScriptObject scriptObject, ExportObjectData data) { List <DailyRoutineFunction> inputFunction = data.ExportData[ExportConstants.ExportDataObject] as List <DailyRoutineFunction>; if (inputFunction == null) { return(Task.CompletedTask); } List <ScribanExportDailyRoutineFunction> scribanFunctions = inputFunction.Select(i => new ScribanExportDailyRoutineFunction(i)).ToList(); scriptObject.AddOrUpdate(ExportConstants.ScribanDailyRoutineFunctionListObjectKey, scribanFunctions); if (!scriptObject.ContainsKey(DailyRoutineEventFunctionRenderer.DailyRoutineEventFunctionName)) { scriptObject.AddOrUpdate(DailyRoutineEventFunctionRenderer.DailyRoutineEventFunctionName, new DailyRoutineEventFunctionRenderer(_templatePlaceholderResolver, _cachedDbAccess, _defaultTemplateProvider, _errorCollection)); } return(Task.CompletedTask); }
public void TestScriptObjectImport() { { var obj = new ScriptObject(); obj.Import(typeof(MyStaticObject)); Assert.That(obj, Does.ContainKey("static_field_a")); Assert.AreEqual("ValueStaticFieldA", obj["static_field_a"]); Assert.True(obj.ContainsKey("static_field_b")); Assert.AreEqual("ValueStaticFieldB", obj["static_field_b"]); Assert.True(obj.ContainsKey("static_property_a")); Assert.AreEqual("ValueStaticPropertyA", obj["static_property_a"]); Assert.True(obj.ContainsKey("static_property_b")); Assert.AreEqual("ValueStaticPropertyB", obj["static_property_b"]); Assert.True(obj.ContainsKey("static_yoyo")); Assert.False(obj.ContainsKey("invalid")); } // Check new overrides { var obj = new ScriptObject(); obj.Import(typeof(MyStaticObject2)); Assert.True(obj.ContainsKey("static_yoyo")); var function = (IScriptCustomFunction)obj["static_yoyo"]; var context = new TemplateContext(); var result = function.Invoke(context, new ScriptFunctionCall(), new ScriptArray() { "a" }, null); Assert.AreEqual("yoyo2 a", result); } // Test MemberFilterDelegate { var obj = new ScriptObject(); obj.Import(typeof(MyStaticObject), filter: member => member.Name.Contains("Property")); Assert.That(obj, Does.Not.ContainKey("static_field_a")); Assert.That(obj, Does.Not.ContainKey("static_field_b")); Assert.That(obj, Does.ContainKey("static_property_a")); Assert.AreEqual("ValueStaticPropertyA", obj["static_property_a"]); Assert.That(obj, Does.ContainKey("static_property_b")); Assert.AreEqual("ValueStaticPropertyB", obj["static_property_b"]); Assert.That(obj, Does.Not.ContainKey("static_yoyo")); Assert.That(obj, Does.Not.ContainKey("invalid")); } // Test MemberRenamerDelegate { var obj = new ScriptObject(); obj.Import(typeof(MyStaticObject), renamer: member => member.Name); Assert.That(obj, Does.ContainKey(nameof(MyStaticObject.StaticFieldA))); Assert.That(obj, Does.ContainKey(nameof(MyStaticObject.StaticFieldB))); Assert.That(obj, Does.ContainKey(nameof(MyStaticObject.StaticPropertyA))); Assert.AreEqual("ValueStaticPropertyA", obj[nameof(MyStaticObject.StaticPropertyA)]); Assert.That(obj, Does.ContainKey(nameof(MyStaticObject.StaticPropertyB))); Assert.AreEqual("ValueStaticPropertyB", obj[nameof(MyStaticObject.StaticPropertyB)]); Assert.That(obj, Does.ContainKey(nameof(MyStaticObject.StaticYoyo))); Assert.That(obj, Does.Not.ContainKey(nameof(MyStaticObject.Invalid))); } { var obj = new ScriptObject(); obj.Import(new MyObject2(), renamer: member => member.Name); Assert.AreEqual(9, obj.Count); Assert.That(obj, Does.ContainKey(nameof(MyStaticObject.StaticFieldA))); Assert.That(obj, Does.ContainKey(nameof(MyObject.PropertyA))); Assert.That(obj, Does.ContainKey(nameof(MyObject2.PropertyC))); } }
public bool HasGlobalValue(string name) { return(Globals.ContainsKey(name)); }
/// <summary> /// This is similar to the Powershell command `ConvertFrom-StringData`, but uses the character "`" instead /// of "\"" as the escape character. /// /// For a list of characters that must be escaped, refer to /// the [MSDN documentation](https://msdn.microsoft.com/library/system.text.regularexpressions.regex.unescape) /// </summary> /// <param name="context">The template context.</param> /// <param name="span">The source span.</param> /// <param name="text">Text in the string data syntax.</param> /// <returns> /// An object representing key-value pairs of strings. /// </returns> /// <remarks> /// ```template-text /// {{ localized = include 'localization.txt' | object.from_string /// localized.foo /// }} /// ``` /// ```html /// bar! /// ``` /// </remarks> public static ScriptObject FromString(TemplateContext context, SourceSpan span, string text) { if (string.IsNullOrEmpty(text)) { return(new ScriptObject()); } // char ` is our escape char // we need to escape `` so it turns out as ` const string escapeChar = "`"; const string reservedSequence = escapeChar + escapeChar; // encodeAs is just an arbitary string. you don't need to escape encodeAs but choosing // something unique helps with the speed const string encodeAs = "^~^"; string inputEscaped = text.Replace(encodeAs, encodeAs + "2").Replace(reservedSequence, encodeAs + "1"); string inputRegexEscaped = inputEscaped.Replace("\\", "\\\\").Replace(escapeChar, "\\"); ScriptObject dataObj = new ScriptObject(); string[] textLines = inputRegexEscaped.Split('\n'); foreach (string textLine in textLines) { if (string.IsNullOrEmpty(textLine)) { continue; } string line = textLine.Trim(); if (string.IsNullOrEmpty(line)) { continue; } else if (line[0] == '#') { continue; } const string kvpDelimiter = "="; int kvpDelimiterIndex = line.IndexOf(kvpDelimiter); if (kvpDelimiterIndex <= 0) { throw new ScriptRuntimeException(span, RS.InvalidStringDataLine); } string itemName = line.Substring(0, kvpDelimiterIndex).Trim(); // +1 is ok, b'cos we already know there is a = somewhere string itemRawValue = line.Substring(kvpDelimiterIndex + 1).TrimStart(); string itemValue = Regex.Unescape(itemRawValue).Replace( encodeAs + "1", reservedSequence).Replace( encodeAs + "2", encodeAs).Replace( reservedSequence, escapeChar); if (dataObj.ContainsKey(itemName)) { dataObj[itemName] = itemValue; } else { dataObj.Add(itemName, itemValue); } } return(dataObj); }