/// <summary> /// Adds the given object to the object store, and returns its handle name (name:version). /// Throws exceptions if anything goes wrong. /// </summary> /// <typeparam name="T">Type of the object to add</typeparam> /// <param name="HandleName">Name under which the object shall be stored</param> /// <param name="obj">The object which shall be stored</param> /// <param name="storedObject">[out] the stored object</param> /// <returns>The Handle (name:version) under which the object was stored</returns> private static string AddOrUpdateInStoreOrThrow <T>(string HandleName, T obj, out IStoredObject <T> storedObject, Action OnUnregister = null) where T : class { // Remove any invalid parts from the input HandleName = HandleNames.GetNameFrom(HandleName); if (String.IsNullOrWhiteSpace(HandleName)) { throw new ArgumentException($"Invalid Handle name {HandleName}", nameof(HandleName)); } if (!m_ObjectStore.AddOrUpdate <T>(HandleName, obj, out storedObject, OnUnregister)) { throw new Exception("Could not add script to the object store"); } return(HandleNames.ToHandle(storedObject)); }
public static object Create( [ExcelArgument("Name for a handle under which the script object will be stored in memory")] string HandleName, [ExcelArgument("The code for this script. Multiple lines are allowed.")] string[] code, [ExcelArgument("A handle to script option definitions as created by ExcelScript.Options.Create. Can be left blank to use defaults.")] string OptionsHandle = "", [ExcelArgument("An arbitrary number of handles to parameter definitions (as created by ExcelScript.Parameters.Create), which define input parameters for the script")] params string[] ParameterHandles) { if (code == null) { throw new ArgumentNullException(nameof(code)); } string _code = String.Join(Environment.NewLine, code); // Get Options XlScriptOptions xlScriptOptions = (String.IsNullOrEmpty(OptionsHandle)) ? XlScriptOptions.Default : GetFromStoreOrThrow <XlScriptOptions>(OptionsHandle); // Create Script object var script = CreateScript(xlScriptOptions); script.Code = _code; script.ReturnType = xlScriptOptions.ReturnType; foreach (var parameterHandle in ParameterHandles) { var parameterHandleName = HandleNames.GetNameFrom(parameterHandle); IParameter storedParameter = GetFromStoreOrThrow <IParameter>(parameterHandleName); script.Parameters.Add(storedParameter); } IStoredObject <IScript> storedScript; if (m_ObjectStore.GetByName <IScript>(HandleName, out storedScript) && storedScript.Object.GetHashCode() == script.GetHashCode()) { return(HandleNames.ToHandle(storedScript)); } else { return(AddOrUpdateInStoreOrThrow <IScript>(HandleName, script, () => TryDispose(script))); } }
public static object Deserialize( [ExcelArgument("Data input. Can either be the raw data as it was generated by ExcelScript.Serialize(), or can be a filepath from which to load the data")] string input) { var obj = InternalDeserialize(input); IStoredObject storedObj = (IStoredObject)obj; // Re-inject dependencies into the object var underlyingObj = storedObj.Object; InjectDependencies(underlyingObj); Type objType = storedObj.GetType().GetGenericArguments().Single(); IStoredObject reStoredObj; // todo: maybe reflect & call correct generic method? if (!m_ObjectStore.AddOrUpdate(storedObj.Name, underlyingObj, objType, out reStoredObj, () => TryDispose(underlyingObj))) { throw new InvalidOperationException("Object could not be re-added to the data store"); } return(HandleNames.ToHandle(reStoredObj)); }
public static object Parse( [ExcelArgument("The code for this script. Multiple lines are allowed.")] string[] code, [ExcelArgument("A handle to script option definitions as created by ExcelScript.Options.Create. Can be left blank to use defaults.")] string OptionsHandle = "", [ExcelArgument("Name for a handle under which the script object will be stored in memory, Can be ommitted, in which case the function name will be used.")] string HandleName = "") { if (code == null) { throw new ArgumentNullException(nameof(code)); } string _code = String.Join(Environment.NewLine, code); // CAREFUL: This method may be run in a different AppDomain! Don't reference anything from outside of the delegate Func <MethodInfo[], MethodInfo> EntryMethodSelector = (methods) => { var _DEBUG_APPD = AppDomain.CurrentDomain.Id; MethodInfo result = null; // When only one method is available, we'll just return that one... if (methods.Count() == 1) { result = methods.Single(); } else { // Otherwise, we'll try to find a (one) function marked with an [ExcelFunction] attribute var markedMethods = methods .Where(x => x.GetCustomAttribute <ExcelFunctionAttribute>() != null); if (markedMethods.Count() == 0) { throw new ArgumentException($"Your script defines {methods.Count()} methods; please mark one of them with the [ExcelFunction] attribute, to mark which function shall be used as an entry point to your script."); } if (markedMethods.Count() > 1) { throw new ArgumentException($"Please only mark one function with an [ExcelFunction] attribute; you have currently marked {markedMethods.Count()} functions: " + String.Join(", ", markedMethods.Select(x => x.Name))); } result = markedMethods.Single(); } return(result); }; // CAREFUL: This method may be run in a different AppDomain! Don't reference anything from outside of the delegate Func <MethodInfo, IParameter[]> EntryMethodParameterFactory = (method => { return(method .GetParameters() .Select(x => { var excelArgumentAttribute = x.GetCustomAttribute <ExcelArgumentAttribute>(); return new Parameter { Name = (excelArgumentAttribute == null || String.IsNullOrWhiteSpace(excelArgumentAttribute.Name)) ? x.Name : excelArgumentAttribute.Name, Type = x.ParameterType, IsOptional = x.IsOptional, DefaultValue = x.DefaultValue, Description = (excelArgumentAttribute == null || String.IsNullOrWhiteSpace(excelArgumentAttribute.Description)) ? String.Empty : excelArgumentAttribute.Description }; }) .ToArray()); }); // Create Script object XlScriptOptions xlScriptOptions = (String.IsNullOrEmpty(OptionsHandle)) ? XlScriptOptions.Default : GetFromStoreOrThrow <XlScriptOptions>(OptionsHandle); var options = CreateScriptingOptionsFrom(xlScriptOptions); options.References.Add(typeof(ExcelFunctionAttribute).Assembly); options.Imports.Add(typeof(ExcelFunctionAttribute).Namespace); var parseResult = m_ScriptFactory.ParseFromAsync <Globals>(m_GlobalsFactory, options, _code, EntryMethodSelector, EntryMethodParameterFactory).Result; var script = parseResult.Script; script.ReturnType = xlScriptOptions.ReturnType; if (String.IsNullOrWhiteSpace(HandleName)) { HandleName = parseResult.EntryMethodName; } IStoredObject <IScript> storedScript; if (m_ObjectStore.GetByName <IScript>(HandleName, out storedScript) && storedScript.Object.GetHashCode() == script.GetHashCode()) { return(HandleNames.ToHandle(storedScript)); } else { return(AddOrUpdateInStoreOrThrow <IScript>(HandleName, script, () => TryDispose(script))); } }