//! # iReal Parser //! //! `ireal_parser` is a library that provides functionality to parse iReal Pro //! URLs and chord progressions according to the [iReal Pro //! specification](https://www.irealpro.com/ireal-pro-file-format). //! //! ## Features //! //! - Parse iReal Pro URLs into a [`Song`] struct with fields like title, //! composer, style, and key signature. //! - Parse iReal Pro progressions into a [`Progression`] struct containing //! [`ProgressionElement`]s. //! - Convert [`Song`], [`Progression`], and [`ProgressionElement`] structs back //! to iReal Pro URL and progression string formats. //! //! ## Usage //! //! Add `ireal_parser` as a dependency in your `Cargo.toml`, then use the //! parsing functions provided by the crate: //! //! ```rust //! use ireal_parser::parse_irealbook_url; //! //! // Parse an iReal Pro URL into a `Song` struct //! let song = parse_irealbook_url("irealbook://Song Title=LastName FirstName=Style=Ab=n=T44*A{C^7 |A-7 |D-9 |G7#5 }").unwrap(); //! ``` //! //! For more information, refer to the [iReal Pro //! specification](https://www.irealpro.com/ireal-pro-file-format). mod error; pub use error::*; mod time_signature; pub use time_signature::*; mod chord; pub use chord::*; mod staff_text; pub use staff_text::*; mod progression; pub use progression::*; mod song; pub use song::*; #[cfg(test)] mod tests { use super::*; #[test] fn test_parse_irealbook_progression() { let input = "{C |A- |D- |G7 }[C |A- |D- |G7 Z"; let p = parse_irealbook_progression(input).unwrap(); assert_eq!(input, p.to_string()); let input = "T44[C |A- T98|D- |G7 Z"; let p = parse_irealbook_progression(input).unwrap(); assert_eq!(input, p.to_string()); let input = "[T44C | x | x | x |D-7 |G7 | r| Z"; let _p = parse_irealbook_progression(input).unwrap(); let input = "*A[C |A- |SD- |G7 QZ"; let p = parse_irealbook_progression(input).unwrap(); assert_eq!(input, p.to_string()); let input = "T44{C |A- |N1D- |G7 } |N2D- G7 |C6 Z"; let _p = parse_irealbook_progression(input).unwrap(); let input = "[T44<*74Solo Section:>C |A- |D- |G7 Z"; let p = parse_irealbook_progression(input).unwrap(); assert_eq!(input, p.to_string()); let input = "[*AT44C |A- |D- |G7 |E- |A- |D- |G7 ZY[*BC |A- |D- |G7 Z"; let p = parse_irealbook_progression(input).unwrap(); assert_eq!(input, p.to_string()); } #[test] fn test_parse_a_walking_thing() { let input = "irealbook://A Walkin Thing=Carter Benny=Medium Swing=D-=n=\ {*AT44D- D-/C |Bh7, Bb7(A7b9) |D-/A G-7 |D-/F sEh,A7,|Y\ |lD- D-/C |Bh7, Bb7(A7b9) |D-/A G-7 |N1D-/F sEh,A7} Y|N2sD-,G-,lD- ]\ [*BC-7 F7 |Bb^7 |C-7 F7 |Bb^7 n |\ |C-7 F7 |Bb^7 |B-7 E7 |A7,p,p,p,]\ [*AD- D-/C |Bh7, Bb7(A7b9) |D-/A G-7 |D-/F sEh,A7,|\ |lD- D-/C |Bh7, Bb7(A7b9) |D-/A G-7 |D-/F sEh,A7Z"; let _p = parse_irealbook_url(input).unwrap(); } #[test] fn test_parse_invalid_irealbook_url() { let input = "irealbook://Song Title=LastName FirstName=Ab=n=T44"; let parsed = parse_irealbook_url(input); assert!(matches!(parsed, Err(Error::InvalidUrl))); } #[test] fn test_parse_irealbook_url() { let input = "irealbook://Song Title=LastName FirstName=Style=Ab=n=T44"; let _parsed = parse_irealbook_url(input).unwrap(); } }