Example #1
0
        public static void TestGlobalReturnConversion()
        {
            // Conversions can be 'global' so they can be applied to any function.
            // The conversion returns 'null' for cases (type + attribute combinations) where it should not be applied.

            // This test simulates the return type conversion we would do to change async #N/A to something else
            // (though using strings instead of the real ExcelError.ExcelErrorNA result).

            var testLambda   = (Expression <Func <string, object> >)(name => name);
            var registration = new ExcelFunctionRegistration(testLambda);

            var conversionConfig = new ParameterConversionConfiguration()
                                   .AddReturnConversion((type, customAttributes) => type != typeof(object) ? null : ((Expression <Func <object, object> >)
                                                                                                                         ((object returnValue) => returnValue.Equals("NA") ? (object)"### WAIT ###" : returnValue)), null);

            var convertedRegistrations = ParameterConversionRegistration.ProcessParameterConversions(new[] { registration }, conversionConfig);
            var converted = convertedRegistrations.First();
            var compiled  = (Func <string, object>)converted.FunctionLambda.Compile();

            var resultNormal = compiled("XYZ");

            Assert.AreEqual("XYZ", resultNormal);

            var resultNA = compiled("NA");

            Assert.AreEqual("### WAIT ###", resultNA);
        }
        public static void TestGlobalReturnConversion()
        {
            // Conversions can be 'global' so they can be applied to any function.
            // The conversion returns 'null' for cases (type + attribute combinations) where it should not be applied.

            // This test simulates the return type conversion we would do to change async #N/A to something else
            // (though using strings instead of the real ExcelError.ExcelErrorNA result).

            var testLambda = (Expression<Func<string, object>>)(name => name);
            var registration = new ExcelFunctionRegistration(testLambda);

            var conversionConfig = new ParameterConversionConfiguration()
                .AddReturnConversion((type, customAttributes) => type != typeof(object) ? null : ((Expression<Func<object, object>>)
                                                ((object returnValue) => returnValue.Equals("NA") ? (object)"### WAIT ###" : returnValue)), null);

            var convertedRegistrations = ParameterConversionRegistration.ProcessParameterConversions(new[] { registration }, conversionConfig);
            var converted = convertedRegistrations.First();
            var compiled = (Func<string, object>)converted.FunctionLambda.Compile();

            var resultNormal = compiled("XYZ");
            Assert.AreEqual("XYZ", resultNormal);

            var resultNA = compiled("NA");
            Assert.AreEqual("### WAIT ###", resultNA);
        }
Example #3
0
        public ExcelFunctionRegistration UpdateHelpTopic(ExcelFunctionRegistration funcReg)
        {
            funcReg.FunctionAttribute.Category  = Resources.ExcelHelpCategory;
            funcReg.FunctionAttribute.HelpTopic = new Uri(new Uri(Resources.DocumentationBaseAddress), funcReg.FunctionAttribute.HelpTopic).ToString();

            return(funcReg);
        }
 internal static FunctionExecutionHandler TimingHandlerSelector(ExcelFunctionRegistration functionRegistration)
 {
     // Eat the TimingAttributes, and return a timer handler if there were any
     if (functionRegistration.CustomAttributes.RemoveAll(att => att is TimingAttribute) == 0)
     {
         // No attributes
         return(null);
     }
     return(_handler.Value);
 }
        /////////////////////// Registration handler //////////////////////////////////
        // (This code can be anywhere... - need not be in this class)

        // In this case, we only ever make one 'handler' object
        public static FunctionExecutionHandler CacheHandlerSelector(ExcelFunctionRegistration functionRegistration)
        {
            // Eat the TimingAttributes, and return a timer handler if there were any
            if (functionRegistration.CustomAttributes.OfType <CacheAttribute>().Any())
            {
                // Get the first cache attribute, and remove all of them
                var cacheAtt = functionRegistration.CustomAttributes.OfType <CacheAttribute>().First();
                functionRegistration.CustomAttributes.RemoveAll(att => att is CacheAttribute);

                return(new CacheFunctionExecutionHandler(cacheAtt.CacheTimeout));
            }
            return(null);
        }
        /// <summary>
        /// Register method as excel function
        /// </summary>
        /// <param name="methodInfo"></param>
        public void AddMethod(MethodInfo methodInfo)
        {
            var attribute = (IExcelFunctionAttribute)methodInfo.GetCustomAttributes(typeof(IExcelFunctionAttribute))
                            .Single();
            var lambda     = WrapMethod(methodInfo, attribute.IsFactory);
            var parameters = methodInfo.GetParameters()
                             .Where(p => !p.ParameterType.GetInterfaces().Contains(typeof(IInjectable)))
                             .Select(p => new ExcelParameterRegistration(p))
                             .ToList();
            var name = methodInfo.Name;

            if (!methodInfo.IsStatic)
            {
                if (!attribute.IsFactory)
                {
                    // add handle as a string parameter to resolve the instance
                    parameters.Insert(0, new ExcelParameterRegistration(
                                          new ExcelArgumentAttribute()
                    {
                        AllowReference = true,
                        Description    = "Object handle",
                        Name           = "Handle"
                    }));
                }
                if (attribute.IsFactory)
                {
                    var type = methodInfo.DeclaringType.DeclaringType;
                    while (!type.GenericTypeArguments.Any())
                    {
                        type = type.BaseType;
                    }
                    name = type.GenericTypeArguments.First().Name + "." + name;
                }
                else if (!methodInfo.DeclaringType.IsGenericType)
                {
                    name = methodInfo.DeclaringType.BaseType.GenericTypeArguments.First().Name + "." + name;
                }
                else
                {
                    // Generic base functions use the underlying type
                    name = methodInfo.DeclaringType.GenericTypeArguments.First().Name + "." + name;
                }
            }

            var registration =
                new ExcelFunctionRegistration(lambda, attribute.ToExcelFunctionAttribute(name), parameters);

            _registrations.Add(registration);
        }
Example #7
0
        public static void TestInstanceRegistration()
        {
            var instanceMethod = typeof(TestClass).GetMethod("GetContent");
            var lambda         = WrapInstanceMethod(instanceMethod);

            // Create a new object every time the instance method is called... (typically we'd look up using a handle)
            var paramConversionConfig = new ParameterConversionConfiguration()
                                        .AddParameterConversion((string content) => new TestClass(content));

            // TODO: Clean up how we suggest this code gets called
            var reg       = new ExcelFunctionRegistration(lambda);
            var processed = ParameterConversionRegistration.ProcessParameterConversions(new[] { reg }, paramConversionConfig);

            processed.RegisterFunctions();
        }
Example #8
0
        /// <summary>
        /// Currently only applied to functions that return object or string.
        /// </summary>
        /// <param name="functionRegistration"></param>
        /// <returns></returns>
        public static IFunctionExecutionHandler SuppressInDialogSelector(ExcelFunctionRegistration functionRegistration)
        {
            // Eat the TimingAttributes, and return a timer handler if there were any
            if (functionRegistration.CustomAttributes.OfType <SuppressInDialogAttribute>().Any() &&
                (functionRegistration.FunctionLambda.ReturnType == typeof(object) ||
                 functionRegistration.FunctionLambda.ReturnType == typeof(string)))
            {
                // Get the first cache attribute, and remove all of them
                var suppressAtt = functionRegistration.CustomAttributes.OfType <SuppressInDialogAttribute>().First();
                functionRegistration.CustomAttributes.RemoveAll(att => att is SuppressInDialogAttribute);

                return(suppressAtt);
            }
            return(null);
        }
        public static void TestIgnoredGlobalReturnConversion()
        {
            var testLambda = (Expression<Func<string, object>>)(name => name);
            var registration = new ExcelFunctionRegistration(testLambda);

            var conversionConfig = new ParameterConversionConfiguration()
                // Add a return conversion that is never applied
                .AddReturnConversion((type, customAttributes) => null, null);

            var convertedRegistrations = ParameterConversionRegistration.ProcessParameterConversions(new[] { registration }, conversionConfig);
            var converted = convertedRegistrations.First();
            var compiled = (Func<string, object>)converted.FunctionLambda.Compile();

            var resultNormal = compiled("XYZ");
            Assert.AreEqual("XYZ", resultNormal);
        }
Example #10
0
        public static void TestReturnConversion()
        {
            //
            var testLambda   = (Expression <Func <string, int, string> >)((name, value) => name + value.ToString());
            var registration = new ExcelFunctionRegistration(testLambda);

            // This conversion takes the return string and duplicates it
            var conversionConfig = new ParameterConversionConfiguration()
                                   .AddReturnConversion((string value) => value + value);

            var convertedRegistrations = ParameterConversionRegistration.ProcessParameterConversions(new[] { registration }, conversionConfig);
            var converted = convertedRegistrations.First();
            var compiled  = (Func <string, int, string>)converted.FunctionLambda.Compile();
            var result    = compiled("asd", 42);

            Assert.AreEqual("asd42asd42", result);
        }
Example #11
0
        public static void TestIgnoredGlobalReturnConversion()
        {
            var testLambda   = (Expression <Func <string, object> >)(name => name);
            var registration = new ExcelFunctionRegistration(testLambda);

            var conversionConfig = new ParameterConversionConfiguration()
                                   // Add a return conversion that is never applied
                                   .AddReturnConversion((type, customAttributes) => null, null);

            var convertedRegistrations = ParameterConversionRegistration.ProcessParameterConversions(new[] { registration }, conversionConfig);
            var converted = convertedRegistrations.First();
            var compiled  = (Func <string, object>)converted.FunctionLambda.Compile();

            var resultNormal = compiled("XYZ");

            Assert.AreEqual("XYZ", resultNormal);
        }
        public static void TestNestedLambdaConversion()
        {
            // The function duplicates the input string (inside a lambda that captures that input parameter)
            var registration = new ExcelFunctionRegistration(typeof(ParameterConversionTests).GetMethod("TestMethodWithLambda", BindingFlags.NonPublic | BindingFlags.Static));

            var conversionConfig = new ParameterConversionConfiguration()
                .AddReturnConversion((type, customAttributes) => type != typeof(object) ? null : ((Expression<Func<object, object>>)
                                                ((object returnValue) => returnValue.Equals("NANA") ? (object)"### WAIT ###" : returnValue)), null);

            var convertedRegistrations = ParameterConversionRegistration.ProcessParameterConversions(new[] { registration }, conversionConfig);
            var converted = convertedRegistrations.First();
            var compiled = (Func<string, object>)converted.FunctionLambda.Compile();

            var resultNormal = compiled("XYZ");
            Assert.AreEqual("XYZXYZ", resultNormal);

            var resultNA = compiled("NA");
            Assert.AreEqual("### WAIT ###", resultNA);
        }
Example #13
0
        private static ExcelFunctionRegistration UpdateAttributesForRangeParameters(ExcelFunctionRegistration reg)
        {
            var rangeParams = reg.FunctionLambda.Parameters.Select((x, i) => new { _Parameter = x, _Index = i })
                              .Where(x => x._Parameter.Type == typeof(Excel.Range));

            bool hasRangeParam = false;

            foreach (var param in rangeParams)
            {
                reg.ParameterRegistrations[param._Index].ArgumentAttribute.AllowReference = true;
                hasRangeParam = true;
            }

            if (hasRangeParam)
            {
                reg.FunctionAttribute.IsMacroType = true;
            }

            return(reg);
        }
Example #14
0
        public static void TestParameterConversions()
        {
            //
            var testLambda   = (Expression <Func <string, int, string> >)((name, value) => name + value.ToString());
            var registration = new ExcelFunctionRegistration(testLambda);

            // This conversion applied a mix of parameter and string conversions
            var conversionConfig = new ParameterConversionConfiguration()
                                   .AddParameterConversion((double value) => (int)(value * 10))
                                   .AddParameterConversion((string value) => value.Substring(0, 2))
                                   .AddReturnConversion((string value) => value + value)
                                   .AddReturnConversion((string value) => value.Length);

            var convertedRegistrations = ParameterConversionRegistration.ProcessParameterConversions(new[] { registration }, conversionConfig);
            var converted = convertedRegistrations.First();
            var compiled  = (Func <string, double, int>)converted.FunctionLambda.Compile();
            var result    = compiled("qwXXX", 4.2);

            Assert.AreEqual("qw42qw42".Length, result);
        }
Example #15
0
        public static void TestNestedLambdaConversion()
        {
            // The function duplicates the input string (inside a lambda that captures that input parameter)
            var registration = new ExcelFunctionRegistration(typeof(ParameterConversionTests).GetMethod("TestMethodWithLambda", BindingFlags.NonPublic | BindingFlags.Static));

            var conversionConfig = new ParameterConversionConfiguration()
                                   .AddReturnConversion((type, customAttributes) => type != typeof(object) ? null : ((Expression <Func <object, object> >)
                                                                                                                         ((object returnValue) => returnValue.Equals("NANA") ? (object)"### WAIT ###" : returnValue)), null);

            var convertedRegistrations = ParameterConversionRegistration.ProcessParameterConversions(new[] { registration }, conversionConfig);
            var converted = convertedRegistrations.First();
            var compiled  = (Func <string, object>)converted.FunctionLambda.Compile();

            var resultNormal = compiled("XYZ");

            Assert.AreEqual("XYZXYZ", resultNormal);

            var resultNA = compiled("NA");

            Assert.AreEqual("### WAIT ###", resultNA);
        }
        /// <summary>
        /// Register property as excel function
        /// </summary>
        /// <param name="property"></param>
        public void AddProperty(PropertyInfo property)
        {
            var getLambda       = GetProperty(property);
            var attribute       = (IExcelFunctionAttribute)property.GetCustomAttributes(typeof(IExcelFunctionAttribute)).Single();
            var handleParameter = new ExcelParameterRegistration(new ExcelArgumentAttribute()
            {
                Name = "Handle"
            });

            // we do not register twice the base properties
            if (property.ReflectedType != property.DeclaringType)
            {
                return;
            }

            var className = property.ReflectedType.Name.Replace("Public", "");

            var getRegistration = new ExcelFunctionRegistration(getLambda,
                                                                //attribute.ToExcelFunctionAttribute(property.DeclaringType.BaseType.GenericTypeArguments.First().Name + "." + "Get" +property.Name),
                                                                attribute.ToExcelFunctionAttribute(className + "." + "Get" + property.Name),
                                                                new List <ExcelParameterRegistration>()
            {
                handleParameter
            });

            _registrations.Add(getRegistration);

            var bindLambda       = BindProperty(property);
            var bindRegistration = new ExcelFunctionRegistration(bindLambda,
                                                                 attribute.ToExcelFunctionAttribute(className + "." + "Bind" + property.Name),
                                                                 new List <ExcelParameterRegistration>()
            {
                handleParameter
            });

            _registrations.Add(bindRegistration);
        }
Example #17
0
 public ExcelFunctionRegistrationWrapper(ExcelFunctionRegistration excelFunctionRegistration)
 {
     _excelFunctionRegistration = excelFunctionRegistration ?? throw new ArgumentNullException(nameof(excelFunctionRegistration));
 }
Example #18
0
 public ExcelFunctionRegistration UpdateHelpTopic(ExcelFunctionRegistration funcReg)
 {
     funcReg.FunctionAttribute.HelpTopic = "http://WDataSci.com";
     return(funcReg);
 }
 private static ExcelFunctionRegistration ProcessFunction(ExcelFunctionRegistration Registration)
 {
     return(ProcessFunctions(new ExcelFunctionRegistration[] { Registration }).Single());
 }
 private static void ProcessAndRegisterFunction(ExcelFunctionRegistration Registration)
 {
     ProcessAndRegisterFunctions(new ExcelFunctionRegistration[] { Registration });
 }
Example #21
0
 public ExcelFunctionRegistration UpdateHelpTopic(ExcelFunctionRegistration funcReg)
 {
     funcReg.FunctionAttribute.HelpTopic = "http://www.duckduckgo.com";
     return(funcReg);
 }
Example #22
0
        public static void TestMapArrayRegistrations(TestCase testCase)
        {
            var methodInfo = testCase.MethodInfo;

            ////////////////////////////////////////////
            // arrange

            Assert.IsNotNull(methodInfo);

            // wrap the method in a registrationentry
            var registration = new ExcelFunctionRegistration(methodInfo);

            registration.FunctionAttribute = new ExcelMapArrayFunctionAttribute();

            //////////////////////////////////////////
            // act - process the registration object

            var processed = Enumerable.Repeat(registration, 1).ProcessMapArrayFunctions(testCase.Config).ToList();

            //////////////////////////////////////////
            // assert

            Assert.AreEqual(1, processed.Count());
            var processedRegistration = processed.First();

            var functionDescription = registration.FunctionAttribute.Description;

            Assert.IsTrue(functionDescription.StartsWith("Returns "));
            var expectedOutputArray = testCase.ExpectedOutputData as object[, ];

            if (expectedOutputArray != null && expectedOutputArray.GetLength(0) != 1 && expectedOutputArray.GetLength(1) != 1)
            {
                // confirm function description contains list of field names for array result
                for (int col = 0; col != expectedOutputArray.GetLength(1); ++col)
                {
                    var colHeader = expectedOutputArray[0, col] as string;
                    Assert.IsNotNull(colHeader);
                    var regex = new Regex(@"\b" + colHeader + @"\b", RegexOptions.IgnoreCase);
                    Assert.IsTrue(regex.Match(functionDescription).Success, functionDescription);
                }
            }

            Assert.AreEqual(testCase.InputData.GetLength(0), registration.ParameterRegistrations.Count);
            for (int param = 0; param != testCase.InputData.GetLength(0); ++param)
            {
                var inputArray = testCase.InputData[param] as object[, ];
                if (inputArray != null && inputArray.GetLength(0) != 1 && inputArray.GetLength(1) != 1)
                {
                    // confirm function description contains list of field names for this array param
                    for (int col = 0; col != inputArray.GetLength(1); ++col)
                    {
                        var colHeader = _recordsInputData[0, col] as string;
                        Assert.IsNotNull(colHeader);
                        var regex = new Regex(@"\b" + colHeader + @"\b", RegexOptions.IgnoreCase);
                        var parameterDescription = registration.ParameterRegistrations[param].ArgumentAttribute.Description;
                        Assert.IsTrue(regex.Match(parameterDescription).Success, parameterDescription);
                    }
                }
            }

            //////////////////////////////////////////
            // act - invoke the delegate

            var output = processedRegistration.FunctionLambda.Compile().DynamicInvoke(testCase.InputData);

            //////////////////////////////////////////
            // assert

            if (output == null)
            {
                Assert.IsNull(output);
            }
            else
            {
                Assert.AreEqual(testCase.ExpectedOutputData, output);
            }
        }
Example #23
0
 internal static FunctionExecutionHandler LoggingHandlerSelector(ExcelFunctionRegistration functionRegistration)
 {
     return(new FunctionLoggingHandler {
         Index = _index++
     });
 }
Example #24
0
        private static ExcelFunctionRegistration ToExcelFunctionRegistration(IScript script, string FunctionName)
        {
            var paramExprs = script
                             .Parameters
                             .Select(x => Expression.Parameter(GetExcelRegistrationTypeFor(x), x.Name))
                             .ToList();

            var methodInfo = typeof(ExcelScriptAddin).GetMethod(nameof(InternalRun), BindingFlags.Static | BindingFlags.NonPublic);

            var paramsToObj = paramExprs.Select(x => Expression.Convert(x, typeof(object))); // cast parameter to object, otherwise won't match function signature of ExcelScriptAddin.Run
            var paramsArray = Expression.NewArrayInit(typeof(object), paramsToObj.ToArray());
            var methodArgs  = new Expression[] { Expression.Constant(script, typeof(IScript)), paramsArray };

            LambdaExpression lambdaExpression = Expression.Lambda(Expression.Call(methodInfo, methodArgs), FunctionName, paramExprs);

            ExcelFunctionAttribute excelFunctionAttribute = new ExcelFunctionAttribute()
            {
                Name = FunctionName
            };

            if (!String.IsNullOrEmpty(script.Description))
            {
                excelFunctionAttribute.Description = script.Description;
            }

            IEnumerable <ExcelParameterRegistration> paramRegistrations = script
                                                                          .Parameters
                                                                          .Select((IParameter x) =>
            {
                var argumentAttribute = new ExcelArgumentAttribute()
                {
                    Name = x.Name
                };
                var parameterRegistration = new ExcelParameterRegistration(argumentAttribute);

                if (x.Type == typeof(Excel.Range) || x.Type == typeof(ExcelReference))
                {
                    argumentAttribute.AllowReference = true;
                }

                if (x.IsOptional)
                {
                    var optionalAttribute = new OptionalAttribute();
                    parameterRegistration.CustomAttributes.Add(optionalAttribute);

                    var defaultValueAttribute = new DefaultParameterValueAttribute(x.DefaultValue);
                    parameterRegistration.CustomAttributes.Add(defaultValueAttribute);
                }

                if (!String.IsNullOrEmpty(x.Description))
                {
                    argumentAttribute.Description = x.Description;
                }

                return(parameterRegistration);
            });

            var reg = new ExcelFunctionRegistration(lambdaExpression, excelFunctionAttribute, paramRegistrations);

            return(reg);
        }
        public static void TestParameterConversions()
        {
            //
            var testLambda = (Expression<Func<string, int, string>>)((name, value) => name + value.ToString());
            var registration = new ExcelFunctionRegistration(testLambda);

            // This conversion applied a mix of parameter and string conversions
            var conversionConfig = new ParameterConversionConfiguration()
                                    .AddParameterConversion((double value) => (int)(value * 10))
                                    .AddParameterConversion((string value) => value.Substring(0, 2))
                                    .AddReturnConversion((string value) => value + value)
                                    .AddReturnConversion((string value) => value.Length);

            var convertedRegistrations = ParameterConversionRegistration.ProcessParameterConversions(new[] { registration }, conversionConfig);
            var converted = convertedRegistrations.First();
            var compiled = (Func<string, double, int>)converted.FunctionLambda.Compile();
            var result = compiled("qwXXX", 4.2);
            Assert.AreEqual("qw42qw42".Length, result);
        }
Example #26
0
 private static ExcelFunctionRegistration UpdateFunctionAttributes(ExcelFunctionRegistration excelFunction)
 {
     excelFunction.FunctionAttribute.Name = excelFunction.FunctionAttribute.Name.ToUpperInvariant();
     return(excelFunction);
 }
        public static void TestReturnConversion()
        {
            //
            var testLambda = (Expression<Func<string, int, string>>)((name, value) => name + value.ToString());
            var registration = new ExcelFunctionRegistration(testLambda);

            // This conversion takes the return string and duplicates it
            var conversionConfig = new ParameterConversionConfiguration()
                                    .AddReturnConversion((string value) => value + value);

            var convertedRegistrations = ParameterConversionRegistration.ProcessParameterConversions(new[] { registration }, conversionConfig);
            var converted = convertedRegistrations.First();
            var compiled = (Func<string, int, string>)converted.FunctionLambda.Compile();
            var result = compiled("asd", 42);
            Assert.AreEqual("asd42asd42", result);
        }