mquote 0.1.0

Quasi-quoting library aimed on better readability and usability
Documentation
extern crate proc_macro2;

use proc_macro2::{Ident, Span};
use mquote::mquote;

#[test]
fn if_branches() {
    let cond = true;
    let a = 6i32;
    let q = mquote!(1i32 + #{if cond} #{a} #{else} 2i32 #{endif} + 3i32);
    assert_eq!(q.to_string(), "1i32 + 6i32 + 3i32");

    let cond = false;
    let q = mquote!(1i32 + #{if cond} #{a} #{else} 2i32 #{endif} + 3i32);
    assert_eq!(q.to_string(), "1i32 + 2i32 + 3i32");

    let (a, b, c) = (1, 2, 3);
    let n = 5;
    let q = mquote!(
        #{if n > 6}
            #{a}
        #{elif n > 3}
            #{b}
        #{else}
            #{c}
        #{endif}
    );
    assert_eq!(q.to_string(), "2i32");
}

#[test]
fn for_expr() {
    let idents = vec![
        Ident::new("ident1", Span::call_site()),
        Ident::new("ident2", Span::call_site()),
        Ident::new("ident3", Span::call_site()),
        Ident::new("ident4", Span::call_site()),
    ];

    let q = mquote!(
        #{for ident in idents}
            #{ident}
        #{endfor}
    );
    assert_eq!(q.to_string(), "ident1 ident2 ident3 ident4");
}

#[test]
fn match_expr() {
    let a = Some("abc");
    let q = mquote!(
        #{match &a}
            #{of Some(s) if s.is_empty()}
                "empty case"
            #{of Some(s)}
                #{s}
            #{of None}
                "default value"
        #{endmatch}
    );
    assert_eq!(q.to_string(), "\"abc\"");
}

#[test]
fn escaping() {
    let q = mquote!(#{{123}});
    assert_eq!(q.to_string(), "# { 123 }");
}

#[test]
fn insertion_via_expression() {
    let pair = (1, "abc");
    let foo = |i: i64| i * 2;
    let q = mquote!(#{pair.0} #{pair.1} #{foo(12)});
    assert_eq!(q.to_string(), "1i32 \"abc\" 24i64");
}

#[test]
fn insertion_via_variable_with_corresponding_name_to_used_in_expanded_macro() {
    let test_str = "test_str";
    let (i, p, s, inner_stream, insertion, token_stream) = (test_str,test_str,test_str,test_str,test_str,test_str);
    let q = mquote!(
        #{i} #{p} #{s} #{inner_stream} #{insertion} #{token_stream}
    );
    assert_eq!(q.to_string(), "\"test_str\" \"test_str\" \"test_str\" \"test_str\" \"test_str\" \"test_str\"");
}

#[test]
fn using_same_variable_twice() {
    let str: String = "123".into();
    let q = mquote!(#{str} #{str});
    assert_eq!(q.to_string(), "\"123\" \"123\"");
}

#[test]
fn nesting_if() {
    let q = mquote!{{
        #{if 2 + 2 == 4}
            { 123 }
        #{endif}
    }};
    assert_eq!(q.to_string(), "{ { 123 } }");
}

#[test]
fn extending_insertion() {
    let insertion = mquote!(h e l l o);
    let q = mquote!(let _ = [ ^{insertion} ]);
    assert_eq!(q.to_string(), "let _ = [ h e l l o ]");
}

#[test]
fn complex_case() {
    let enum_name = Ident::new("MyEnum", Span::call_site());
    let variants_str = vec![
        "Insertion",
        "Extend",
        "If",
        "For",
        "Match",
        "Group",
        "Plain",
    ];
    let variants = variants_str.iter()
        .map(|v| Ident::new(v, Span::call_site()))
        .collect::<Vec<_>>();
    let impl_default = Some(2);
    let q = mquote!{
        pub enum #{enum_name} {
            #{for variant in &variants}
                #{variant},
            #{endfor}
        }

        impl #{enum_name} {
            fn as_str(&self) -> &'static str {
                match self {
                    #{for (variant, variant_str) in variants.iter().zip(variants_str.iter())}
                        #{enum_name}::#{variant} => #{variant_str},
                    #{endfor}
                }
            }
        }

        #{match impl_default}
        #{of None}
        #{of Some(n)}
            impl Default for #{enum_name} {
                fn default() -> Self {
                    #{enum_name}::#{variants[n]}
                }
            }
        #{endmatch}
    };
    let expected =
        "pub enum MyEnum { \
            Insertion , \
            Extend , \
            If , \
            For , \
            Match , \
            Group , \
            Plain , \
        } \
        \
        impl MyEnum { \
            fn as_str ( & self ) -> & 'static str { \
                match self { \
                    MyEnum ::Insertion => \"Insertion\" , \
                    MyEnum ::Extend => \"Extend\" , \
                    MyEnum ::If => \"If\" , \
                    MyEnum ::For => \"For\" , \
                    MyEnum ::Match => \"Match\" , \
                    MyEnum ::Group => \"Group\" , \
                    MyEnum ::Plain => \"Plain\" , \
                } \
            } \
        } \
        \
        impl Default for MyEnum { \
            fn default ( ) -> Self { \
                MyEnum ::If \
            } \
        }";
    assert_eq!(q.to_string(), expected);
}