# Cases Message Valid Notebook Structure

Note: Spelunking will likely be needed.

Execute the following. You should get back and error along the lines of First::first:... This error is unimportant except it helps illustrate a potential issue with Cases internal code.

Print[Button["Print Cell",
Cell[BoxData[
ToBoxes@
First@Cases[NotebookGet[EvaluationNotebook[]][[1]],
Cell[___, CellTags -> "MyCode", ___]]
], "Input", CellTags -> "MyGraphic"]
]
];
CellPrint@
Cell[BoxData[
ToBoxes[Cases[NotebookGet[EvaluationNotebook[]],
Cell[___, CellTags -> "MyGraphic", ___], Infinity], StandardForm]
], "Output", CellTags -> "MyCode"];


Now ultimately although the notebook is outputting an error the Notebook itself should have a valid structure, considering the notebook can be saved and duplicated like so NotebookPut@NotebookGet[EvaluationNotebook[]].

Interestingly if execute the following code in the same Notebook.

Cases[NotebookGet[EvaluationNotebook[]]
, Cell[__, CellTags -> "MyGraphic"], Infinity]


Cases return the appropriate values and you get back a First::first error.

My question: Why does Cases return a message from a perfectly valid Notebook structure. Other then using Quiet to suppress an error, how might I solve such a problem?

-
You're not calling Cases at the proper level. See the third argument of Cases... use level Infinity –  rm -rf Aug 8 '13 at 18:33
@rm-rf I'm sorry not sure what you mean Infinity means at calling at every level, yes? –  Liam William Aug 8 '13 at 18:35
See the difference between Cases[{{Cell["foo", CellTags -> "bar"]}}, Cell[__, CellTags -> "bar", ___]] and Cases[{Cell["foo", CellTags -> "bar"]}, Cell[__, CellTags -> "bar", ___]]... by default Cases operates at level spec {1}, which is why the first returns {} whereas the second returns a cell. In a generic notebook expression, the cell tag rule is at an arbitrary depth, which you may or may not know in advance. It certainly isn't at level {1}. So you use Infinity to tell Cases to look for the pattern at all levels. –  rm -rf Aug 8 '13 at 18:40
@rm-rf but the 2nd Cases is set to Infinity. Read the question again. My question isn't why the 1st error is outputted, but why a perfectly valid Notebook structure causes the 2nd Cases to return a message in addition to returning the output. Something internally on how Cases is structure is causing the issue. –  Liam William Aug 8 '13 at 18:43
@rm-rf In the following example the Notebook structure is somehow causing Cases to fail pastebin.com/uP7CNrUS –  Liam William Aug 8 '13 at 18:47

This "answer", if it can be considered an answer, consists of a mixture of comments and suggestions.

Aside from dealing with levels as rm-rf has shown in another answer, one probably ought to deal with the possibility of Cases returning {}, even if it should not happen. How to deal with it is something you should decide. Here's a way to return Null, if it's of any help:

First[Cases[..] /. {} -> {Null}]


You can avoid the Cell pattern matching itself if, as I surmise, the "MyCode" and "MyGraphics" tags indicate the type of cells. Code and graphics cells start Cell[BoxData[..],..]. So the patterns could be these:

Cell[_BoxData, ___, CellTags -> "MyCode", ___]
Cell[_BoxData, ___, CellTags -> "MyGraphic", ___]


You can get the cells in a notebook, except inline cells, at level 1 in a List, with the following (not extensively tested, however):

Clear[cells];
cells[nb_NotebookObject] := cells[nb, _];
cells[nb_NotebookObject, pat_] := Flatten @ cells[First @ NotebookGet[nb], pat];
cells[cellList_List, pat_] := cells[#, pat] & /@ cellList;
cells[Cell[CellGroupData[group_List, ___]], pat_] := cells[#, pat] & /@ group;
cells[c_Cell, pat_] := If[MatchQ[c, pat], c, {}];
cells[__] := {};


All cells:

cells[EvaluationNotebook[]]


You can even get only the cells matching a pattern:

cells[EvaluationNotebook[],
_?(MemberQ[Flatten[{CellTags} /. Options[#]], "MyCode"] &)]

-
This question was a follow up from here mathematica.stackexchange.com/questions/30069/… If you would like you are welcome to post an answer and receive more points (like you really need them) –  Liam William Aug 10 '13 at 1:59
Genious technique, you are welcome to the following function as an answer at the above question. pastebin.com/mvFPqvVY –  Liam William Aug 10 '13 at 2:37
@Liam Thanks for pointing it out. I've been busy and haven't kept up with all the questions. –  Michael E2 Aug 10 '13 at 14:10

The following expression should result in an error:

First@Cases[NotebookGet[EvaluationNotebook[]][[1]], Cell[___, CellTags -> "MyCode", ___]]]


because Cases, by default, operates at level {1} and in a notebook's expression, CellTags will never be at level {1}. Thus, Cases returns {} and First throws an error. The solution here, is to use level Infinity.

Now coming to the second Cases — you've now evaluated the first code block and you have a button in your notebook. This button's expression is:

ButtonBox["\"Print Cell\"", Appearance -> Automatic,
ButtonFunction :> Cell[
BoxData[
ToBoxes[First[Cases[NotebookGet[EvaluationNotebook[]][[1]],
Cell[___, CellTags -> "MyCode", ___]]]
]
],
"Input", CellTags -> "MyGraphic"
], Evaluator -> Automatic, Method -> "Preemptive"
]


Note that this expression is stored as an input expression instead of parsed boxform expression. As Cases walks through the tree, it evaluates the leaves and the RHS of ButtonFunction gets evaluated, which is what results in the error (for reasons explained above).

-
@Liam The "fix" is to use the correct levelspec in the 1st Cases... As I said, in general you'll not find a cell tag at that level, so this button is designed to generate an error. So as long as that incorrect button is present, the 2nd Cases will throw an error. You should also read this answer by Leonid. You might be able to use it to "shield" certain expressions (like ButtonFunction's RHS, for example). –  rm -rf Aug 8 '13 at 19:10