= Advice Advice are event-based procedures that augment demonstrations. They are used to keep demonstrations clean of extraneous, repetitive and merely adminstrative code that the reader does not need to see over and over. Typically you will want to put advice definitions in applique files, rather then place them directly in the demonstration document, but you can do so, as you will see in this document. == Before and After QED supports *before* and *after* clauses in a specification through the use of Before and After code blocks. These blocks are executed at the beginning and at the end of each indicated step. We use a *before* clause if we want to setup some code at the start of each code step. a, z = nil, nil Before do a = "BEFORE" end And an *after* clause to teardown objects after a code step. After do z = "AFTER" end Notice we assigned +a+ and +z+ before the block. This was to ensure their visibility in the scope later. Now, lets verify that the *before* and *after* clauses work. a.assert == "BEFORE" a = "A" z = "Z" And now. z.assert == "AFTER" There can be more than one before and after clause at a time. If we define a new *before* or *after* clause later in the document, it will be appended to the current list of clauses in use. As a demonstration of this, b = nil Before do b = "BEFORE AGAIN" end We will see it is the case. b.assert == "BEFORE AGAIN" Only use *before* and *after* clauses when necessary --specifications are generally more readable without them. Indeed, some developers make a policy of avoiding them altogether. YMMV. == Caveats of Before and After Instead of using Before and After clauses, it is wiser to define a reusable setup method. For example, in the helper if we define a method such as #prepare_example. def prepare_example "Hello, World!" end Then we can reuse it in later code blocks. example = prepare_example example.assert == "Hello, World!" The advantage to this is that it gives the reader an indication of what is going on behind the scenes, rather the having an object just magically appear. == Event Targets There is a small set of advice targets that do not come before or after, rather they occur *upon* a particular event. These include +:load+ and +:unload+ for when a new helper is loaded; +:pass+, +:fail+ and +:error+ for when a code block passes, fails or raises an error; and +:head+, +:desc:+, +:code+ and +:data:+ which targets the immediate processing of a text block and code excecution. These event targets can be advised by calling the +When+ method with the target type as an argument along with the code block to be run when the event is triggered. x = [] When(:step) do |section| section.text.scan(/^\*(.*?)$/) do |m| x << $1.strip end end Now let's see if it worked. * SampleA * SampleB * SampleC So +x+ should now contain these three list samples. x.assert == [ 'SampleA', 'SampleB', 'SampleC' ] == Pattern Matchers QED also supports comment match triggers. With the +When+ method one can define procedures to run when a given pattern matches comment text. When 'given the facts' do @facts = "this is truth" end Then whenever the words, 'given the facts' appear in step description the `@facts` varaible will be set. @facts.assert == "this is truth" Pattern matchers reall shine when we also add captures to the mix. When 'given a setting @a equal to (((\d+)))' do |n| @a = n.to_i end Now, @a will be set to 1 whenever a comment like this one contains, "given a setting @a equal to 1". @a.assert == 1 A string pattern is translated into a regular expression. In fact, you can use a regular expression if you need more control over the match. When using a string all spaces are converted to \s+ and anything within double-parenthesis is treated as raw regular expression. Since the above example has (((\d+))), the actual regular expression contains (\d+), so any number can be used. For example, "given a setting @a equal to 2". @a.assert == 2 When clauses can also use consecutive pattern matching. For instance we could write, When 'first match #(((\d+)))', 'then match #(((\d+)))' do |i1, i2| @a = [i1.to_i, i2.to_i] end So that 'first match #1' will be looked for first, and only after that if 'then match #2' is found, will it be considered a complete match. All regular expression slots are collected from all matches and passed to the block. We can see that the rule matched this very paragraph. @a.assert == [1,2] This concludes the basic overview of QED's specification system, which is itself a QED document. Yes, we eat our own dog food.