genderphasing

troeseddau yn erbyn duw a satan yn macros datgannol

clasur rhwddog

hwyl: balchrhaglennurhwd

so, before realizing that glob can do it, i wrote a tiny thing to do glob-matching. (tl;dr: it's how you specify which stylesheets to apply to which posts/pages in blog/reblog.)

naturally, i wrote unit tests for it. at first, they were pretty bulky – 6 lines for every glob and expression to test it against. before long i realized i could slim it a bit, but then it occurred to me i could write a macro to remove all the boilerplate.

so i did, and this is that macro:

macro_rules! tests {
  ( $(
    $name:ident: $glob:literal
    $( ! $(|$ne:literal|)?)? ~
    $text:literal
  );* $(;)? ) => {$(
    #[test]
    fn $name() {
      assert!($(!$($ne)?)? Glob::new($glob).matches($text));
    }
  )*}
}

obviously (/s) this is crystal clear to any rust dev, but in case you want to see how it's used:

tests! {
  match_exact: "foobar" ~ "foobar";
  unmatch_suffix_exact: "foobar" !~ "asdf.foobar";
  unmatch_prefix_exact: "foobar" !~ "foobar.asdf";
  match_star_text: "*" ~ "asdf.fdsa";
  match_star_empty: "*" ~ "";
  match_suffix: "*foobar" ~ "asdf.foobar";
  unmatch_suffix: "*foobar" !~ "asdf.foobar.fdsa";
  match_prefix: "foobar*" ~ "foobar.fdsa";
  unmatch_prefix: "foobar*" !~ "asdf.foobar.fdsa";
  match_middle: "foo*bar" ~ "foo.meow.bar";
  unmatch_middle_prefix: "foo*bar" !~ "asdf.foo.meow.bar";
  unmatch_middle_suffix: "foo*bar" !~ "foo.meow.bar.fdsa";
  match_multi: "foo*meow*bar" ~ "foo____meow____bar";
  unmatch_multi_prefix: "foo*meow*bar" !~ "asdf.foo____meow____bar";
  unmatch_multi_suffix: "foo*meow*bar" !~ "foo____meow____bar.fdsa";
  match_leading_multi: "*meow*bar" ~ "foo____meow____bar";
  unmatch_leading_multi_prefix: "*meow*bar" ~ "asdf.foo____meow____bar";
  unmatch_leading_multi_suffix: "*meow*bar" !~ "foo____meow____bar.fdsa";
  match_trailing_multi: "foo*meow*" ~ "foo____meow____bar";
  unmatch_trailing_multi_prefix: "foo*meow*" !~ "asdf.foo____meow____bar";
  unmatch_trailing_multi_suffix: "foo*meow*" ~ "foo____meow____bar.fdsa";
}

and then, after writing all this and using it, i realized that glob can do everything i need and more. so that code's gone now! but it's still an archetypical example of the kind of thing decl macros are perfect for: tiny, quick dsls to automate the boilerplate away.

someday i'll write up an explainer with all my random tips and tricks about writing these. they're extremely expressive and powerful, and for a lot of things, way easier than proc macros, even with syn and co. for now, though, i just thought y'all would enjoy this minor crime.


with luck, i'll have more to write about b/rb proper soon. for now i have other obligations to tend to. in the mean time, expect more rechosts, or maybe a roundup – i'm due for one.