1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/*!
This crate provides a set of modules that contain the IRIs and QName strings for commonly used
vocabularies. It also provides [macro](macro.namespace.html) support for defining new namespaces
in the same style as this library.

The vocabularies supported can be found [below](#modules).

# Macro Example

The following example replicates the `geo` module using the `namespace!` macro. Note that as this
macro uses `paste::item` the client will need to have a dependency on the
[paste crate](https://crates.io/crates/paste), and a macro use statement in their code.


```rust,ignore
#[macro_use]
extern crate paste;

#[macro_use]
extern crate rdftk_names;

namespace! {
    "geo",
    "http://www.w3.org/2003/01/geo/wgs84_pos#",
    {
        spatial_thing, "SpatialThing",
        temporal_thing, "TemporalThing",
        event, "Event",
        point, "Point",
        lat, "lat",
        location, "location",
        long, "long",
        alt, "alt",
        lat_long, "lat_long"
    }
}
```

*/

#[allow(unused_imports)]
#[macro_use]
extern crate paste;

// ------------------------------------------------------------------------------------------------
// Macros
// ------------------------------------------------------------------------------------------------

///
/// This macro produces the constants and functions to describe a vocabulary. It creates the
/// following items.
///
/// 1. A constant, `PREFIX` that contains the string passed in the `$prefix` parameter.
/// 1. A constant, `NAMESPACE` that contains the string passed in the `namespace` parameter.
/// 1. For each pair of `$fn_name`, `$name` (assuming `foo` and `"Foo"`):
///    1. create a function `fn foo() -> IRI` that returns the name as a full IRI. This concatenates
///       `NAMESPACE` and `$name`.
///    1. create a function `fn foo_qname() -> String` that returns a qualified name String. This
///       concatenates the `PREFIX`, `":"`, and `$name`.
///
/// # Example
///
/// Given the following namespace invocation,
///
/// ```rust,ignore
/// #[macro_use]
/// extern crate rdftk_names;
///
/// namespace!("fb", "http://example.com/schema/FooBar#", { foo, "Foo" } );
/// ```
///
/// The folowing would be generated.
///
/// ```rust
/// use rdftk_iri::IRI;
/// use std::str::FromStr;
///
/// #[doc = "The default prefix for this namespace"]
/// pub const PREFIX: &str = "fb";
///
/// #[doc = "The IRI for this namespace"]
/// pub const NAMESPACE: &str = "http://example.com/schema/FooBar#";
///
/// #[doc = "Construct an IRI for this name"]
/// #[inline]
/// pub fn foo() -> IRI {
///     IRI::from_str(&format!("{}{}", NAMESPACE, "Foo")).unwrap()
/// }
///
/// #[doc = "Construct a prefixed qualified name String for this name"]
/// #[inline]
/// pub fn foo_qname() -> String {
///     format!("{}:{}", PREFIX, "Foo")
/// }
/// ```
///
#[macro_export]
macro_rules! namespace {
    ($prefix:expr, $namespace:expr, { $($fn_name:ident, $name:expr),* }) => {

    use rdftk_iri::IRI;
    use std::str::FromStr;

    #[doc = "The default prefix for this namespace"]
    pub const PREFIX: &str = $prefix;

    #[doc = "The IRI (as string) for this namespace"]
    pub const NAMESPACE: &str = $namespace;

    $(
        nsname!($fn_name, $name);
    )*
    };
}

///
/// Typically this macro is only called by the `namespace!` macro. It takes an identifier and a
/// string and produces:
///
/// 1. a function with the same identifier which returns a complete IRI using the
///    value of `NAMESPACE` in the current scope, and
/// 1. a function with the same identifier, but the suffix `_qname` which returns a qualified name
///    using the value of `PREFIX` in the current scope.
///
#[macro_export]
macro_rules! nsname {
    ($fn_name:ident, $name:expr) => {
        #[doc = "Construct an IRI for this name"]
        #[inline]
        pub fn $fn_name() -> IRI {
            IRI::from_str(&format!("{}{}", NAMESPACE, $name)).unwrap()
        }

        paste::item! {
        #[doc = "Construct a prefixed qualified name String for this name"]
        #[inline]
        pub fn [<$fn_name _qname>]() -> String {
            format!("{}:{}", PREFIX, $name)
        }
        }
    };
}

// ------------------------------------------------------------------------------------------------
// Modules
// ------------------------------------------------------------------------------------------------

pub mod dc;

pub mod foaf;

pub mod geo;

pub mod owl;

pub mod rdf;

pub mod rdfs;

pub mod xsd;

// ------------------------------------------------------------------------------------------------
// Unit Tests
// ------------------------------------------------------------------------------------------------

#[cfg(test)]
mod tests {
    use super::*;

    namespace!("p", "heep://schema/com/p#", { foo, "Foo", bar, "Bar" } );

    #[test]
    fn test_expansion() {
        assert_eq!(foo().to_string(), "heep://schema/com/p#Foo");
        assert_eq!(foo_qname(), "p:Foo");
        assert_eq!(bar().to_string(), "heep://schema/com/p#Bar");
        assert_eq!(bar_qname(), "p:Bar");
    }
}