diff --git a/src/Roux/Parser.hs b/src/Roux/Parser.hs index e7e2a93..120caa8 100644 --- a/src/Roux/Parser.hs +++ b/src/Roux/Parser.hs @@ -131,11 +131,12 @@ pLineBreak = do pRecipeRef :: Parser StepItem pRecipeRef = do _ <- P.char '@' + -- Consume @ and store ./ as part of the path _ <- P.char '.' _ <- P.char '/' path <- P.many (P.noneOf "{(\n\\") mqty <- P.optionMaybe (P.between (P.char '{') (P.char '}') pQuantityBody) - return (StepRecipeRef (RecipeRef path (join mqty))) + return (StepRecipeRef (RecipeRef ("./" <> path) (join mqty))) -- | Ingredient: @name{quantity%unit}(preparation) pIngredient :: Parser StepItem diff --git a/test/Roux/ParserSpec.hs b/test/Roux/ParserSpec.hs index 71105f7..13169ac 100644 --- a/test/Roux/ParserSpec.hs +++ b/test/Roux/ParserSpec.hs @@ -2,6 +2,7 @@ module Roux.ParserSpec (spec) where import Data.List.NonEmpty (NonEmpty ((:|))) import qualified Data.List.NonEmpty as NE +import qualified Data.Text.IO as TIO import Test.Hspec (Spec, describe, expectationFailure, it, shouldBe) import Roux.Parser (parseCookFile) @@ -369,3 +370,44 @@ spec = do _ -> expectationFailure ("expected SecStep as third body item, got body=" <> show body) + + describe "Recipe references" $ do + it "parses a recipe reference" $ do + let input = "Pour over with @./sauces/Hollandaise{150%g}." + case parseCookFile input of + Left err -> expectationFailure ("parse failed: " <> err) + Right recipe -> do + let items = stepItems recipe + let expected = + [ StepText "Pour over with " + , StepRecipeRef (RecipeRef "./sauces/Hollandaise" (Just (Quantity 150 (Just "g") False))) + , StepText "." + ] + items `shouldBe` expected + + describe "Full recipe files" $ do + let readExample name = do + content <- TIO.readFile ("cooklang-examples/" <> name <> ".cook") + case parseCookFile content of + Left err -> expectationFailure (name <> ": " <> err) + Right _ -> pure () + + it "EasyPancakes parses without error" $ do + readExample "EasyPancakes" + + it "FriedRice parses without error" $ do + readExample "FriedRice" + + it "CoffeeSouffle parses without error" $ do + readExample "CoffeeSouffle" + + it "OlivierSalad parses without error" $ do + readExample "OlivierSalad" + +-- | Extract step items from the first step of an unnamed section. +stepItems :: Recipe -> [StepItem] +stepItems r = + let s = NE.head (recipeSections r) + in case NE.head (sectionBody s) of + SecStep step -> unStep step + _ -> []