consumer_composition_usability.tri (3992B)
1 -- Two public-library programs: collect matching route suffixes, then choose 2 -- the first nonempty suffix with a caller-supplied fallback. No new SCP syntax. 3 !import "consumers.base-source" B 4 !import "consumers.structural" S 5 !import "consumers.lexical-worker" L 6 !import "prelude" !Local 7 !import "io" !Local 8 9 loadPath path = (onResult_ (readFile path) 10 (problem : pure (err problem t)) 11 (source : pure (matchResult 12 (_ _ : err "consumer source did not parse" t) 13 (named _ : ok (snd named) t) 14 (B.compileBaseSource source)))) 15 load name = loadPath (append "lib/consumer/" (append name ".scp")) 16 worker program initial = S.makeConsumer initial (snd program) 17 compare pureWorker lexicalWorker input = (equal? 18 (S.runConsumer pureWorker input) (L.lRunChecked lexicalWorker input)) 19 referencePipeline collector chooser paths fallback = 20 bindResult (S.runConsumer collector paths) (suffixes _ : 21 S.runConsumer chooser (pair suffixes fallback)) 22 lexicalPipeline collector chooser paths fallback = 23 bindResult (L.lRunChecked collector paths) (suffixes _ : 24 L.lRunChecked chooser (pair suffixes fallback)) 25 badMapper = snd (resultOr t (B.compileBaseSource 26 "consumer malformed\n x @ _ => (leaf, leaf)")) 27 checks prefix mapMaybe nonempty finder chooser = 28 let refPrefix = worker prefix "/api/" in 29 let lexPrefix = resultOr t (L.lCompile refPrefix) in 30 let refCollect = worker mapMaybe refPrefix in 31 let lexCollect = resultOr t (L.lCompile 32 (worker mapMaybe lexPrefix)) in 33 let refNonempty = worker nonempty t in 34 let lexNonempty = resultOr t (L.lCompile refNonempty) in 35 let refFind = worker finder refNonempty in 36 let lexFind = resultOr t (L.lCompile (worker finder lexNonempty)) in 37 let refChoose = worker chooser refFind in 38 let lexChoose = resultOr t (L.lCompile 39 (worker chooser lexFind)) in 40 let refBad = worker mapMaybe badMapper in 41 let lexBad = resultOr t (L.lCompile (worker mapMaybe 42 (resultOr t (L.lCompile badMapper)))) in 43 let routes = ["/api/" "/other" "/api/item" "/api/health"] in 44 let collected = ["" "item" "health"] in 45 let noRoutes = ["/other" "/else"] in 46 foldl and? true [ 47 (resultIsOk (L.lCompile refPrefix)) 48 (resultIsOk (L.lCompile (worker mapMaybe lexPrefix))) 49 (resultIsOk (L.lCompile (worker finder lexNonempty))) 50 (resultIsOk (L.lCompile (worker chooser lexFind))) 51 (compare refCollect lexCollect routes) 52 (equal? (S.runConsumer refCollect routes) (ok collected t)) 53 (compare refCollect lexCollect ["/api/"]) 54 (equal? (S.runConsumer refCollect ["/api/"]) (ok [""] t)) 55 (compare refCollect lexCollect noRoutes) 56 (equal? (S.runConsumer refCollect noRoutes) (ok [] t)) 57 (equal? (referencePipeline refCollect refChoose routes "none") 58 (ok "item" t)) 59 (equal? (referencePipeline refCollect refChoose ["/api/"] "none") 60 (ok "none" t)) 61 (equal? (referencePipeline refCollect refChoose noRoutes "none") 62 (ok "none" t)) 63 (equal? (referencePipeline refCollect refChoose noRoutes "alternate") 64 (ok "alternate" t)) 65 (equal? (referencePipeline refCollect refChoose routes "none") 66 (lexicalPipeline lexCollect lexChoose routes "none")) 67 (equal? (referencePipeline refCollect refChoose ["/api/"] "none") 68 (lexicalPipeline lexCollect lexChoose ["/api/"] "none")) 69 (equal? (referencePipeline refCollect refChoose noRoutes "alternate") 70 (lexicalPipeline lexCollect lexChoose noRoutes "alternate")) 71 (compare refBad lexBad routes) 72 (equal? (S.runConsumer refBad routes) (err "no matching output arm" t))] 73 stage = do onOk_ 74 prefix <- load "stripPrefix" 75 mapMaybe <- load "mapMaybe" 76 nonempty <- load "nonempty" 77 finder <- load "find" 78 chooser <- loadPath "demos/consumers/collect-prefixes/choose-found.scp" 79 pure (ok (checks prefix mapMaybe nonempty finder chooser) t) 80 main = io (onResult_ stage 81 (_ : putStrLn "consumer-composition-LOAD-FAIL") 82 (success : putStrLn (matchBool "consumer-composition-ok" 83 "consumer-composition-DIFFER" success))) 84 main