Reviewing Where We Are


The XML Notepad is now much improved. Starting from where we were initially, we now have all the insert menus being created by looping over a data structure that TextModel provides. Essentially, TextModel is publishing what it knows how to do, and the Notepad just creates menus for each action. This should mean that we can add a new tag simply by adding one new InsertAction instance to the insertActions variable. We ll try that in a moment. If it works ” and I m sure it will ”it will reduce that seven-step process of adding a new item to just one step! Not bad at all!

At this point, counting writing the chapter, I ve been working for an hour and twenty minutes, a very good return on my investment. Now let s work on deleting some variables in TextModel, commenting them out as before. I m sure we ll get some compiler messages or some tests failing.

 class TextModel { 
private ArrayList lines;
private int selectionStart;
private static string[] newParagraph = { "<P></P>" };
private static string[] paragraphSkip = { "<P>" };
private static string[] newListItem = { "<LI></LI>" };
private static string[] listItemSkip = { "<LI>" };
private static string[] emptyLine = { "" };
private static string[] emptyLineSkip = { "" };
// private static string[] newSection = {" < sect1 >< title >< /title > ",
// " < /sect1 > " };
// private static string[] sectionSkip = { " < sect1 >< title > " };
// private static string[] newUnorderedList = {" < UL > "," < LI >< /LI > "," < /UL > "}; // private static string[] unorderedListSkip = { " < UL > ", " < LI > " };
// private static string[] newOrderedList = {" < OL > "," < LI >< /LI > "," < /OL > "};
// private static string[] orderedListSkip = { " < OL > ", " < LI > " };
// private static string[] newPre = { " < pre >< /pre > " };
// private static string[] preSkip = { " < pre > " };
private static string[] InsertStrings(Tags tag) {
// if (tag == Tags.Pre) return newPre;
// else if (tag == Tags.Section) return newSection;
// else if (tag == Tags.UnorderedList) return newUnorderedList;
// else if (tag == Tags.OrderedList) return newOrderedList;
if (tag == Tags.ListItem) return newListItem;
else return newParagraph;
}
private static string[] SkipStrings(Tags tag) {
// if (tag == Tags.Pre) return preSkip;
// else if (tag == Tags.Section) return sectionSkip;
// else if (tag == Tags.UnorderedList) return unorderedListSkip;
// else if (tag == Tags.OrderedList) return orderedListSkip;
if (tag == Tags.ListItem) return listItemSkip;
else return paragraphSkip;
}

Well! That s what we wanted to delete, but we cannot. The reason is that some of the tests are now failing. For example, with those deletions as shown, this test fails:

 [Test] public void AltS() { 
model.Lines = new ArrayList(new String[0]);
model.InsertTags(TextModel.Tags.Section);
AssertEquals("<sect1><title></title>", model.Lines[0]);
AssertEquals("</sect1>", model.Lines[1]);
AssertEquals(14, model.SelectionStart);
}

Several tests are relying on the old logic in the Tags enum and the InsertString() and SkipStrings() methods. It s not quite as simple as I thought to remove those methods and the static lists. What can we do? Let s look again at the overloaded method InsertTags():

 public void InsertTags(Tags command) { 
int cursorLine = LineContainingCursor();
lines.InsertRange(cursorLine+1, InsertStrings(command));
selectionStart = NewSelectionStart(cursorLine + 1, SkipStrings(command));
}
public void InsertTags(InsertAction action) {
int cursorLine = LineContainingCursor();
lines.InsertRange(cursorLine+1, action.TagsToInsert);
selectionStart = NewSelectionStart(cursorLine + 1, action.TagsToSkip);
}

Looking at both of those gave me an idea. How about changing the first one to use the second, something like this:

 public void InsertTags(Tags command) { 
InsertTags(ActionForCommand(command));
}

The idea is that we will look up the action we need with the ActionForCommand() method. I ll make the change, and then we ll see about making it work. We know that ActionForCommand() has to look something like this:

 private InsertAction ActionForCommand(Tags command) { 
// look up and return an InsertAction
}

The first thing this tells us is that our InsertAction items need to be accessible, somehow, by Tags. One way would be to build an auxiliary structure such as a hashtable. It would be easier just to put the Tags in the InsertAction object and fill in the table. Here s the updated class:

 class InsertAction { 
private TextModel.Tags command;
private string menuString;
private string[] tagsToInsert;
private string[] tagsToSkip; public InsertAction(TextModel.Tags tag, string menu, string[] inserts,
string[] skips) {
command = tag;
menuString = menu;
tagsToInsert = inserts;
tagsToSkip = skips;
}
public TextModel.Tags Command {
get { return command; }
}
public string MenuString {
get { return menuString; }
}
public string[] TagsToInsert {
get { return tagsToInsert; }
}
public string[] TagsToSkip {
get { return tagsToSkip; }
}
}

Now we need to add the tags to the InsertActions array, and we need to add all the tags that are in the scalars but not in the menu. This means that I ll be faced with that horrible formatting bug in Visual Studio. I wonder if there is a way to turn off auto-formatting for a while. Ah, yes: Tools/Options/Text Editor/C#/Formatting has an option. I ll turn it off and then edit that array to look like this:

 private static InsertAction[] insertActions = new InsertAction[] { 
new InsertAction(
Tags.Pre,
"Insert &Pre",
new string[] { "<pre></pre>" },
new string[] { "<pre>" }),
new InsertAction(
Tags.Section,
"Insert &Section",
new string[] {"<sect1><title></title>","</sect1>" },
new string[] {"<sect1><title>" }),
new InsertAction(
Tags.UnorderedList,
"Insert &UL",
new string[] {"<UL>","<LI></LI>","</UL>"},
new string[] {"<UL>", "<LI>" }),
new InsertAction(
Tags.OrderedList,
"Insert &OL",
new string[] {"<OL>","<LI></LI>","</OL>"},
new string[] {"<OL>", "<LI>" })
};

This should be enough to make all the tests work again. Let s find out...grrr, not quite. The lookup with the comment in it doesn t compile ”probably you remembered that, but I needed the compiler to remind me. Let s code that up now:

 private InsertAction ActionForCommand(Tags command) { 
foreach ( InsertAction action in InsertActions) {
if (action.Command == command)
return action;
}
return null;
}

This won t work for all cases ”some tests should break. But it should compile, and making the rest of the tests run should be accomplished by adding new entries to InsertActions. I ll try it. Sure enough, all but four tests pass. I think they re the four that failed before. I ll add the additional tags to the array:

 private static InsertAction[] insertActions = new InsertAction[] { 
new InsertAction(
Tags.Pre,
"Insert &Pre",
new string[] { "<pre></pre>" },
new string[] { "<pre>" }),
new InsertAction(
Tags.Section,
"Insert &Section",
new string[] {"<sect1><title></title>","</sect1>" },
new string[] {"<sect1><title>" }),
new InsertAction(
Tags.UnorderedList,
"Insert &UL",
new string[] {"<UL>","<LI></LI>","</UL>"},
new string[] {"<UL>", "<LI>" }),
new InsertAction(
Tags.OrderedList,
"Insert &OL",
new string[] {"<OL>","<LI></LI>","</OL>"},
new string[] {"<OL>", "<LI>" }),
new InsertAction(
Tags.Paragraph,
null,
new string[] { " < P >< /P > " },
new string[] { "<P>" }),
new InsertAction(
Tags.ListItem,
null,
new string[] { "<LI></LI>" },
new string[] { "<LI>" })
};

You ll notice the nulls I put in there for those last two items. I don t want them to have menus. So we ll enhance the menu-building code just a bit also:

 foreach (InsertAction action in model.InsertActions) { 
if (action.MenuString != null ) {
insertMenus.Add(new NotepadMenuItem (
action.MenuString,
new EventHandler(MenuInsertTags),
action));
}
}

Everything compiles, and the tests all run. I should be able to remove all the commented code here:

 class TextModel { 
private ArrayList lines;
private int selectionStart;
// private static string[] newParagraph = { " < P >< /P > " };
// private static string[] paragraphSkip = { " < P > " };
// private static string[] newListItem = { " < LI >< /LI > " };
// private static string[] listItemSkip = { " < LI > " };
// private static string[] emptyLine = { "" };
// private static string[] emptyLineSkip = { "" };
// private static string[] newSection = {" < sect1 >< title >< /title > ",
// " < /sect1 > " };
// private static string[] sectionSkip = { " < sect1 >< title > " };
// private static string[] newUnorderedList = {" < UL > "," < LI >< /LI > "," < /UL > "}; // private static string[] unorderedListSkip = { " < UL > ", " < LI > " };
// private static string[] newOrderedList = {" < OL > "," < LI >< /LI > "," < /OL > "};
// private static string[] orderedListSkip = { " < OL > ", " < LI > " };
// private static string[] newPre = { " < pre >< /pre > " };
// private static string[] preSkip = { " < pre > " };
...
// private static string[] InsertStrings(Tags tag) {
// if (tag == Tags.Pre) return newPre;
// else if (tag == Tags.Section) return newSection;
// else if (tag == Tags.UnorderedList) return newUnorderedList;
// else if (tag == Tags.OrderedList) return newOrderedList;
// if (tag == Tags.ListItem) return newListItem;
// else return newParagraph;
// }
// private static string[] SkipStrings(Tags tag) {
// if (tag == Tags.Pre) return preSkip;
// else if (tag == Tags.Section) return sectionSkip;
// else if (tag == Tags.UnorderedList) return unorderedListSkip;
// else if (tag == Tags.OrderedList) return orderedListSkip;
// if (tag == Tags.ListItem) return listItemSkip;
// else return paragraphSkip;
// }

This compiles, and the tests run. I ll delete all that code now. And it still compiles and still runs.

start sidebar
Lesson: Where Are We Now?

The code is much improved. The lookups have been converted to loops , instead of those ugly if/else structures, and all the information about the TextModel s capabilities is encapsulated in one array. We have deleted a lot of code, one of the best signs of progress.

Notice that we have spent only short amounts of time with tests not running. There was one stretch there, filling in the array, that was a few steps long, but it was straightforward and not really difficult. There may have been a way to get the tests running sooner, but I didn t see it; this way was quite simple, and no problems arose.

We created a lot of dead code and removed it. Now I m wondering if other methods in these classes are not used and therefore are subject to being deleted. I ve looked for any indication that the compiler can tell me about things that are unused, but I ve found nothing. I guess I ll have to inspect the code manually. That s no fun at all, but I ll take a few minutes and see if I find anything. A quick inspection doesn t turn anything up. I think I ll post a question on some of the lists, however. I ll let you know if I find out anything. [Added in editing: I found no tools for finding dead code. Someone should write one.]

end sidebar
 



Extreme Programming Adventures in C#
Javaв„ў EE 5 Tutorial, The (3rd Edition)
ISBN: 735619492
EAN: 2147483647
Year: 2006
Pages: 291

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net