diff --git a/presentation/bdd/01_slide.md b/presentation/bdd/01_slide.md deleted file mode 100644 index 5549e3c..0000000 --- a/presentation/bdd/01_slide.md +++ /dev/null @@ -1,2 +0,0 @@ -!SLIDE -# BDD (or TDD, or software development, or whatever) diff --git a/presentation/bdd_with_ragel/01_slide.md b/presentation/bdd_with_ragel/01_slide.md index a92b2ab..4460b25 100644 --- a/presentation/bdd_with_ragel/01_slide.md +++ b/presentation/bdd_with_ragel/01_slide.md @@ -1,10 +1,10 @@ -!SLIDE -# BDD with Ragel +!SLIDE bullets incremental +# BDD (or TDD, or software development, or whatever) +* with Ragel !SLIDE bullets incremental -* Get Ragel parsing _something_ -* There are no rules (RSpec, then Cucumber) -* Prove it +# Externalize Evidence of Operation +* Make assertions on the collected evidence !SLIDE * 1st passing test example (spec side-by-side w/ ragel) @@ -22,17 +22,40 @@ * pretty_formatter.feature !SLIDE bullets incremental -# Testing -.notes SUT -.notes Driving out behavior +# What the Tests Told Us .notes Event based design of Gherkin came about out of need to easily test lexer .notes Remember regex == state machine, so inherently event driven .notes Acceptance: when Ragel finishes its work and the current state is not less than the final lexer state -* Externalize evidence of operation -* Test spy: SexpRecorder -* Parameterize the ctor with object that receives events +* Parameterize the Lexer's ctor with a listener * (Dependency Injection) +* Compose listeners for flexibility and additional layers of responsibility +* Test using a Test Spy listener: SexpRecorder + +!SLIDE small + + @@@ Ruby + class Lexer + %%{ + machine lexer; + action do_action { + # Send the appropriate messages to the listener + } + main := 'foo' $do_action; + }%% + + def initialize(listener) + @listener = listener + %% write data; + end + + def scan(text) + data = text.unpack("c*") + + %% write init; + %% write exec; + end + end !SLIDE .notes We know not really sexps but annoying pedants is more fun than being correct @@ -73,6 +96,60 @@ [:step, "Then", "a GUI must be the answer", 4] ] +!SLIDE smaller +# A Real Test + + @@@ Ruby + it "should parse steps with inline py_string" do + scan("Given I have a string\n\"\"\"\nhello\nworld\n\"\"\"") + @listener.to_sexp.should == [ + [:step, "Given ", "I have a string", 1], + [:py_string, "hello\nworld", 2], + [:eof] + ] + end + +!SLIDE smallest +# Cucumber + @@@ Cucumber + Given a Gherkin parser + When the following text is parsed: + """ + Feature: Advanced Lulzfinding Mechanism + Scenario: Monty Python + Given the following excerpt: + \"\"\" + WOMAN: Who are the Britons? + ARTHUR: Well, we all are. we're all Britons and I am your king. + WOMAN: I didn't know we had a king. I thought we were an autonomous + collective. + DENNIS: You're fooling yourself. We're living in a dictatorship. + A self-perpetuating autocracy in which the working classes-- + WOMAN: Oh there you go, bringing class into it again. + DENNIS: That's what it's all about if only people would-- + ARTHUR: Please, please good people. I am in haste. Who lives + in that castle? + \"\"\" + When I read it + Then I should be amused + """ + Then there should be no parse errors + +!SLIDE small + + @@@ Ruby + Given /^a Gherkin parser$/ do + @parser = Gherkin::Parser.new(@listener) + end + + Given "the following text is parsed:" do |text| + @parser.parse(text) + end + + Then "there should be no parse errors" do + @listener.errors.should == [] + end + !SLIDE * utf8_pack * 1.8/1.9 and UTF8 diff --git a/presentation/introduction/01_slide.md b/presentation/introduction/01_slide.md index 35bc324..d5283f8 100644 --- a/presentation/introduction/01_slide.md +++ b/presentation/introduction/01_slide.md @@ -14,11 +14,11 @@ # Ragel * A tool for building parsers... * ...by specifying state machines... -* ...with regular expressions. +* ...in a regular language. !SLIDE bullets incremental # Some people, when confronted with a problem, think "I know, I'll use regular expressions." !SLIDE center -# "Now they have two problems" +# "Now they have two problems." ![atreyu](atreyu.png) diff --git a/presentation/ragel_syntax/01_slide.md b/presentation/ragel_syntax/01_slide.md index 126da1a..b77e696 100644 --- a/presentation/ragel_syntax/01_slide.md +++ b/presentation/ragel_syntax/01_slide.md @@ -18,7 +18,7 @@ %%write exec; end end -* +* !SLIDE bullets @@@ Ruby diff --git a/presentation/introduction/02_slide.md b/presentation/regular_language/01_slide.md similarity index 50% rename from presentation/introduction/02_slide.md rename to presentation/regular_language/01_slide.md index 99d44a2..3ae71e1 100644 --- a/presentation/introduction/02_slide.md +++ b/presentation/regular_language/01_slide.md @@ -1,3 +1,6 @@ +!SLIDE +# The Problems With Regular Expressions + !SLIDE # Regular expressions are a syntax @@ -27,33 +30,50 @@ !SLIDE small bullets incremental # Semantic Failure, Syntactic Confusion * Failures with regular expressions are usually _semantic_ -* (This doesn't mean the syntax is good) -* Two causes of confusion +* (This doesn't mean the syntax is that great) -.notes The primary source is that, well, Regexen are confusing -.notes It's really easy to write some that are impossible to understand -.notes Ragel addresses some of the syntax difficulties (but not all) -.notes We'll get to that in a second, but the other cause is how we think about matching +!SLIDE bullets incremental +# Two causes of confusion: +* Syntax +* Metaphor !SLIDE bullets # Syntax -* Ragel makes it easier to visualize what is happening when things go wrong + +* Character for character, few things produce complexity like a regular expression +* If only there were a way to visualize what it is they create... !SLIDE # Thinking About Matching +## What does it mean "to match"? +## What is doing the matching? + +!SLIDE bullets incremental +# Statements You May Have Heard +* "I matched the string against the regex" +* "This regex is matching more than it should" +* "All I did was try to parse HTML with regexen, and now Cthulhu insists I bring him home to meet Mom." + +!SLIDE +# REGULAR EXPRESSIONS DO NOT DO THE MATCHING +## There is no "there" there + +!SLIDE +# "Oh my god you guys! My class definition retrieved a record from the database!" !SLIDE # Regular Expressions Are A Syntax For Specifying State Machines !SLIDE bullets # State Machines -* The regex characters are the _transitions_ +* Characters in the regex are the _transitions_ * The characters of input are the _events_ -* The _states_ are generated by the compiler +* The _states_ are determined by the compiler + +!SLIDE +# Ragel converts expressions into a state machine that reads characters one at a time until it reaches the end of input !SLIDE center bullets incremental # Example: /abc/ * "a", "b" and "c" are named transitions * ![abc](abc.png) - -.notes Ragel converts a series of machines into a table-driven* FSM that reads bytes one at a time until it reaches the end of input diff --git a/presentation/introduction/abc.png b/presentation/regular_language/abc.png similarity index 100% rename from presentation/introduction/abc.png rename to presentation/regular_language/abc.png diff --git a/presentation/showoff.json b/presentation/showoff.json index 7a4c2a7..9b49541 100644 --- a/presentation/showoff.json +++ b/presentation/showoff.json @@ -1,7 +1,7 @@ { "name": "Consuming Gherkin", "sections": [ {"section":"introduction"}, + {"section":"regular_language"}, {"section":"ragel_syntax"}, - {"section":"bdd"}, {"section":"bdd_with_ragel"}, {"section":"why_ragel"}, {"section":"when_ragel"},