Implement variables in attributes
Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
This commit is contained in:
parent
1f0a7e4e18
commit
c847ceb3bf
4 changed files with 115 additions and 10 deletions
|
@ -38,10 +38,16 @@
|
||||||
//! <message scansion:strict="true"/>
|
//! <message scansion:strict="true"/>
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use crate::{Client, ClientName};
|
||||||
|
use crate::types::VariableAttr;
|
||||||
|
use crate::parsers::parse_variable;
|
||||||
|
|
||||||
|
use jid::BareJid;
|
||||||
use minidom::{Element, Node};
|
use minidom::{Element, Node};
|
||||||
|
|
||||||
/// Namespaces used for Client entities
|
/// Namespaces used for Client entities
|
||||||
|
@ -193,25 +199,32 @@ impl PartialEq<Vec<Node>> for ScanNodes<NonStrictComparison> {
|
||||||
/// changes the way the comparison is done.
|
/// changes the way the comparison is done.
|
||||||
/// Also uses the custom ScanNode implementation.
|
/// Also uses the custom ScanNode implementation.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ScanElement<'a> {
|
pub struct ScanElement<'a, 'b> {
|
||||||
elem: &'a Element,
|
elem: &'a Element,
|
||||||
|
context: Option<&'b HashMap<ClientName, Client>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Deref for ScanElement<'a> {
|
impl<'a, 'b> Deref for ScanElement<'a, 'b> {
|
||||||
type Target = Element;
|
type Target = Element;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.elem
|
&self.elem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ScanElement<'a> {
|
impl<'a> ScanElement<'a, 'static> {
|
||||||
pub fn new(elem: &'a Element) -> ScanElement {
|
pub fn new(elem: &'a Element) -> ScanElement {
|
||||||
Self { elem }
|
Self { elem, context: None }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PartialEq<&Element> for ScanElement<'a> {
|
impl <'a, 'b> ScanElement<'a, 'b> {
|
||||||
|
pub fn with_context(self, context: &'b HashMap<ClientName, Client>) -> ScanElement<'a, 'b> {
|
||||||
|
Self { elem: self.elem, context: Some(context) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> PartialEq<&Element> for ScanElement<'a, 'b> {
|
||||||
fn eq(&self, other: &&Element) -> bool {
|
fn eq(&self, other: &&Element) -> bool {
|
||||||
let self_ns = self.elem.ns();
|
let self_ns = self.elem.ns();
|
||||||
if self.elem.name() == other.name() &&
|
if self.elem.name() == other.name() &&
|
||||||
|
@ -231,6 +244,28 @@ impl<'a> PartialEq<&Element> for ScanElement<'a> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse variables. If parsing fails, continue attr comparison.
|
||||||
|
// If context isn't set, skip this and continue attr comparison.
|
||||||
|
if let Ok((_, var)) = parse_variable(val.into()) &&
|
||||||
|
let Some(context) = self.context {
|
||||||
|
let res = match var {
|
||||||
|
VariableAttr::FullJid(name) => match context.get(&name) {
|
||||||
|
Some(Client { jid, .. }) => String::from(jid.clone()),
|
||||||
|
_ => return false,
|
||||||
|
},
|
||||||
|
VariableAttr::BareJid(name) => match context.get(&name) {
|
||||||
|
Some(Client { jid, .. }) => String::from(BareJid::from(jid.clone())),
|
||||||
|
_ => return false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(oval) = other.attr(attr) && res == oval {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match (attr, other.attr(attr)) {
|
match (attr, other.attr(attr)) {
|
||||||
(attr, _) if attr == "scansion:strict" => continue,
|
(attr, _) if attr == "scansion:strict" => continue,
|
||||||
(_, None) => return false,
|
(_, None) => return false,
|
||||||
|
@ -493,4 +528,22 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(scan1, &elem2);
|
assert_eq!(scan1, &elem2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn variables_from_context() {
|
||||||
|
let louise = Client::new(Jid::from_str("louise@example.com").unwrap(), "passwd");
|
||||||
|
|
||||||
|
let clients = {
|
||||||
|
let mut tmp = HashMap::new();
|
||||||
|
tmp.insert(String::from("louise"), louise);
|
||||||
|
tmp
|
||||||
|
};
|
||||||
|
|
||||||
|
let elem1: Element = "<message xmlns='foo' to=\"${louise's full JID}\" />"
|
||||||
|
.parse().unwrap();
|
||||||
|
let elem2: Element = "<message xmlns='foo' to='louise@example.com' />".parse().unwrap();
|
||||||
|
let scan1 = ScanElement::new(&elem1).with_context(&clients);
|
||||||
|
|
||||||
|
assert_eq!(scan1, &elem2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,12 @@
|
||||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
#![feature(let_chains)]
|
||||||
|
|
||||||
pub mod element;
|
pub mod element;
|
||||||
pub mod parsers;
|
pub mod parsers;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
pub use element::ScanElement;
|
pub use element::ScanElement;
|
||||||
pub use parsers::parse_spec;
|
pub use parsers::parse_spec;
|
||||||
pub use types::{Action, Client, Metadata, Spec};
|
pub use types::{Action, Client, ClientName, Metadata, Spec};
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
use crate::types::{Action, Client, ClientName, Metadata, Spec};
|
use crate::types::{Action, Client, ClientName, Metadata, VariableAttr, Spec};
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
@ -279,6 +279,25 @@ pub fn parse_spec(i: &str) -> Result<Spec, Token> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_variable(s: Span) -> IResult<Span, VariableAttr> {
|
||||||
|
let (s, (_, name, attr, _)) = tuple((
|
||||||
|
tag("${"), take_until_tags(vec![
|
||||||
|
"'s full JID",
|
||||||
|
"'s JID",
|
||||||
|
].into_iter(),
|
||||||
|
"}",
|
||||||
|
),
|
||||||
|
alt((tag("'s full JID"), tag("'s JID"))),
|
||||||
|
tag("}"),
|
||||||
|
))(s)?;
|
||||||
|
|
||||||
|
Ok((s, match *attr.fragment() {
|
||||||
|
"'s full JID" => VariableAttr::FullJid(name.to_string()),
|
||||||
|
"'s JID" => VariableAttr::BareJid(name.to_string()),
|
||||||
|
_ => unreachable!(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -602,4 +621,29 @@ louise receives:
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_variable_attr() {
|
||||||
|
let buf1: Span = "${louise's full JID}".into();
|
||||||
|
let buf2: Span = "${louise's JID}".into();
|
||||||
|
let buf3: Span = "${louise's JID".into();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
parse_variable(buf1).unwrap().1,
|
||||||
|
VariableAttr::FullJid(String::from("louise")),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
parse_variable(buf2).unwrap().1,
|
||||||
|
VariableAttr::BareJid(String::from("louise")),
|
||||||
|
);
|
||||||
|
|
||||||
|
match parse_variable(buf3) {
|
||||||
|
Err(nom::Err::Error(nom::error::Error { input, .. })) => {
|
||||||
|
assert_eq!(input.location_offset(), 2);
|
||||||
|
assert_eq!(input.location_line(), 1);
|
||||||
|
}
|
||||||
|
err => panic!("Expected Err, found: {err:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,12 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
use jid::Jid;
|
use jid::Jid;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum VariableAttr {
|
||||||
|
FullJid(ClientName),
|
||||||
|
BareJid(ClientName),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Metadata {
|
pub struct Metadata {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
|
|
Loading…
Reference in a new issue