I am writing an object in C# to mimic jQuery's various functions. That is, calling the constructor is akin to calling the $()
function of jQuery. For example,
var a = new JQuery("div").eq(0);
Assert.AreEqual("$(\"div\").eq(0)", a.ToString());
I also have an Append function which concatenates two or more existing JQuery objects into one, changing the $ of all but the first into a find. For example,
var a = new JQuery("body").find("ul").eq(0);
var b = new JQuery("li").filter("div").eq(0);
var c = new JQuery("span").filter("a");
var d = JQuery.Append(a, b, c);
Assert.AreEqual("$(\"body\").find(\"ul\").eq(0).find(\"li\").filter(\"div\").eq(0).find(\"span\").filter(\"a\")", d.ToString());
The code is below. There is a bit of recursion in the ChangeLastPredecessor
and in the ToString
methods. How do you suggest I clean up those two methods?
internal struct Parameter
{
private readonly object @object;
internal Parameter(object parameter)
{
@object = parameter;
}
public override string ToString()
{
if (@object == null)
{
return string.Empty;
}
// convert string to quoted and escaped string
var objString = @object as string;
return objString == null
? Convert.ToString(@object, CultureInfo.InvariantCulture)
: string.Concat("\"", objString.Replace("\"", "\\\""), "\"");
}
}
public class JQuery
{
public JQuery(string selector)
{
Function = "$";
Parameters = new List<Parameter> { new Parameter(selector) };
Predecessor = null;
}
public JQuery(JQuery obj)
{
Function = "$";
Parameters = new List<Parameter> { new Parameter(obj) };
Predecessor = null;
}
private JQuery(JQuery predecessor, string function, params object[] parameters)
{
Function = function;
Parameters = parameters.Select(x => new Parameter(x));
Predecessor = predecessor;
}
// the current function in the chain
private string Function { get; set; }
// the parameters to the current function
private IEnumerable<Parameter> Parameters { get; set; }
// the previous function in the chain
private JQuery Predecessor { get; set; }
public static JQuery Append(JQuery appendee, params JQuery[] appendices)
{
if (appendices == null)
{
throw new ArgumentNullException("appendices");
}
if (appendices.Length == 0)
{
return appendee;
}
for (var i = 0; i < appendices.Length - 1; ++i)
{
ChangeLastPredecessor(appendices[i], appendices[i + 1]);
}
ChangeLastPredecessor(appendee, appendices[appendices.Length - 1]);
return appendices[appendices.Length - 1];
}
private static void ChangeLastPredecessor(JQuery appendee, JQuery changee)
{
if (changee.Predecessor == null)
{
changee.Function = "find";
changee.Predecessor = appendee;
return;
}
var predecessor = changee.Predecessor;
ChangeLastPredecessor(appendee, predecessor);
changee.Predecessor = predecessor;
}
public override string ToString()
{
return (Predecessor == null)
? string.Format(CultureInfo.InvariantCulture, "{0}({1})", Function, string.Join(",", Parameters.Select(x => x.ToString())))
: string.Format(CultureInfo.InvariantCulture, "{0}.{1}({2})", Predecessor, Function, string.Join(",", Parameters.Select(x => x.ToString())));
}
public JQuery eq(int index)
{
return new JQuery(this, "eq", index);
}
public JQuery find(string selector)
{
return new JQuery(this, "find", selector);
}
public JQuery find(JQuery obj)
{
return new JQuery(this, "find", obj);
}
public JQuery filter(string selector)
{
return new JQuery(this, "filter", selector);
}
public JQuery filter(JQuery obj)
{
return new JQuery(this, "filter", obj);
}
}