slack_blocks/
lib.rs

1//! This crate brings Slack's terrific [Block Kit 🔗] to
2//! the Rust ecosystem.
3//!
4//! Inside, you'll find models for all of Slack's Layout Blocks,
5//! Block Elements, and Composition Objects. Each structure has Slack's API
6//! documentation copied in-place so you don't have to leave your editor to
7//! remember the details of the block kit API.
8//!
9//! Every model has builders that leverage Rust's type system
10//! to help you provide every required field, so you can be confident in your app.
11//!
12//! ## Troubleshooting common compiler errors
13//! `Method build not found for ...Builder` - Dig into the error message,
14//! you'll find something like `RequiredMethodNotCalled<method::foo>`,
15//! meaning you need to call `.foo()` before you can call `.build()`!
16//!
17//! # Example
18//! Using an example from Slack's Documentation:
19//! ```json
20//! {
21//!   "type": "section",
22//!   "text": {
23//!     "text": "*Sally* has requested you set the deadline for the Nano launch project",
24//!     "type": "mrkdwn"
25//!   },
26//!   "accessory": {
27//!     "type": "datepicker",
28//!     "action_id": "datepicker123",
29//!     "initial_date": "1990-04-28",
30//!     "placeholder": {
31//!       "type": "plain_text",
32//!       "text": "Select a date"
33//!     }
34//!   }
35//! }
36//! ```
37//!
38//! You can use raw Builders like so:
39//! ```rust
40//! use slack_blocks::{text::ToSlackMarkdown, blocks::Section, elems::DatePicker};
41//!
42//! let section = Section::builder()
43//!                       .text("*Sally* has requested you set the deadline for the Nano launch project".markdown())
44//!                       .accessory(DatePicker::builder()
45//!                                             .action_id("datepicker123")
46//!                                             .initial_date((28, 4, 1990))
47//!                                             .placeholder("Select a date")
48//!                                             .build()
49//!                       )
50//!                       .build();
51//! ```
52//!
53//! Or enable the `unstable` feature and use xml macros:
54//! ```rust
55//! use slack_blocks::blox::*;
56//!
57//! let pick_date = blox! {
58//!   <date_picker action_id="datepicker123"
59//!                placeholder="Select a date"
60//!                initial_date=(28, 4, 1990) />
61//! };
62//!
63//! let section = blox! {
64//!   <section_block accessory=pick_date>
65//!     <text kind=plain>"*Sally* has requested you set the deadline for the Nano launch project"</text>
66//!   </section_block>
67//! };
68//! ```
69//!
70//! [Block Kit 🔗]: https://api.slack.com/block-kit
71//! [`cargo-make`]: https://github.com/sagiegurari/cargo-make/
72//! [issues]: https://github.com/cakekindel/slack-blocks-rs/issues/
73//! [Conventional Commits]: https://www.conventionalcommits.org/en/v1.0.0/
74
75#![doc(html_root_url = "https://docs.rs/slack-blocks/0.25.0")]
76#![cfg_attr(docsrs, feature(doc_cfg))]
77// #![feature(doc_cfg)] // for local docs
78#![deny(missing_docs)]
79#![cfg_attr(not(test),
80            forbid(missing_copy_implementations,
81                   missing_debug_implementations,
82                   unreachable_pub,
83                   unsafe_code,
84                   unused_crate_dependencies))]
85
86#[macro_use]
87#[cfg(feature = "validation")]
88extern crate validator_derive;
89
90#[cfg(feature = "blox")]
91#[cfg_attr(docsrs, doc(cfg(feature = "blox")))]
92pub mod blox;
93
94pub mod blocks;
95pub mod compose;
96pub mod elems;
97
98mod build;
99#[cfg(feature = "validation")]
100mod val_helpr;
101
102#[doc(inline)]
103pub use blocks::Block;
104#[doc(inline)]
105pub use compose::text;
106#[doc(inline)]
107pub use elems::BlockElement;
108
109mod macros {
110  #[macro_export]
111  #[doc(hidden)]
112  macro_rules! convert {
113    (impl From<$source:ty> for $dest:ty => $closure:expr) => {
114      impl From<$source> for $dest {
115        fn from(src: $source) -> Self {
116          $closure(src)
117        }
118      }
119    };
120    (impl<'_> From<$source:ident> for $dest:ident => $closure:expr) => {
121      impl<'a> From<$source<'a>> for $dest<'a> {
122        fn from(src: $source<'a>) -> $dest<'a> {
123          $closure(src)
124        }
125      }
126    };
127    (impl<$lifetime:lifetime> From<$source:ty> for $dest:ty => $closure:expr) => {
128      convert!(impl<$lifetime, > From<$source> for $dest => $closure);
129    };
130    (impl<$lifetime:lifetime, $($ty_var:ident),*> From<$source:ty> for $dest:ty => $closure:expr) => {
131      impl<$lifetime, $($ty_var),*> From<$source> for $dest {
132        fn from(src: $source) -> Self {
133          $closure(src)
134        }
135      }
136    };
137    (impl<$($ty_var:tt),+> From<$source:ty> for $dest:ty => $closure:expr) => {
138      impl<$($ty_var),+> From<$source> for $dest {
139        fn from(src: $source) -> Self {
140          $closure(src)
141        }
142      }
143    };
144    (impl From<impl $trait_:ident<$source:ty>> for $dest:ty => $closure:expr) => {
145      impl<T> From<T> for $dest where T: $trait_<$source>
146      {
147        fn from(src: T) -> Self {
148          $closure(src)
149        }
150      }
151    };
152    (impl<'_> From<impl $trait_:ident<$source:ident>> for $dest:ident => |$param:ident| $body:expr) => {
153      impl<'a, T> From<T> for $dest<'a> where T: $trait_<$source<'a>>
154      {
155        fn from($param: T) -> Self {
156          $body
157        }
158      }
159    };
160  }
161}