From: Simon Tatham Date: Tue, 26 Dec 2023 10:18:08 +0000 (+0000) Subject: Changed my mind again about constructor API X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ian/git?a=commitdiff_plain;h=54dac41922e255db32ff4855147b36fa592ee9e4;p=mastodonochrome.git Changed my mind again about constructor API --- diff --git a/src/text.rs b/src/text.rs index 4b87b63..49fa819 100644 --- a/src/text.rs +++ b/src/text.rs @@ -12,15 +12,18 @@ pub trait TextFragment { // Some indication of how many usernames are in here and how many statuses // Some means of passing a flag to render() that says which username or // status is to be highlighted + // Some means of having ExtendableIndicator flag itself as active fn render(&self, width: usize) -> Vec; fn as_extendable_indicator(&self) -> Option<&ExtendableIndicator> { None } } -struct BlankLine {} +pub struct BlankLine {} -pub fn blank() -> Box { - Box::new(BlankLine{}) +impl BlankLine { + pub fn new() -> Box { + Box::new(BlankLine{}) + } } impl TextFragment for BlankLine { @@ -33,27 +36,29 @@ impl TextFragment for BlankLine { #[test] fn test_blank() { - assert_eq!(blank().render(40), vec! { + assert_eq!(BlankLine::new().render(40), vec! { ColouredString::plain("") }); } -struct SeparatorLine { +pub struct SeparatorLine { timestamp: Option>, favourited: bool, boosted: bool, } -pub fn separator( - timestamp: Option>, - favourited: bool, - boosted: bool, - ) -> Box { - Box::new(SeparatorLine { - timestamp, - favourited, - boosted, - }) +impl SeparatorLine { + pub fn new( + timestamp: Option>, + favourited: bool, + boosted: bool, + ) -> Box { + Box::new(SeparatorLine { + timestamp, + favourited, + boosted, + }) + } } impl TextFragment for SeparatorLine { @@ -95,7 +100,7 @@ fn test_separator() { let t = NaiveDateTime::parse_from_str("2001-08-03 04:05:06", "%Y-%m-%d %H:%M:%S") .unwrap().and_local_timezone(Local).unwrap().with_timezone(&Utc); - assert_eq!(separator(Some(t), true, false) + assert_eq!(SeparatorLine::new(Some(t), true, false) .render(60), vec! { ColouredString::general( "--------------------------[F]--[Fri Aug 3 04:05:06 2001]--", @@ -104,10 +109,12 @@ fn test_separator() { }); } -struct EditorHeaderSeparator {} +pub struct EditorHeaderSeparator {} -pub fn editorsep() -> Box { - Box::new(EditorHeaderSeparator{}) +impl EditorHeaderSeparator { + pub fn new() -> Box { + Box::new(EditorHeaderSeparator{}) + } } impl TextFragment for EditorHeaderSeparator { @@ -123,7 +130,7 @@ impl TextFragment for EditorHeaderSeparator { #[test] fn test_editorsep() { - assert_eq!(editorsep().render(5), vec! { + assert_eq!(EditorHeaderSeparator::new().render(5), vec! { ColouredString::general( "---|", "----", @@ -131,29 +138,31 @@ fn test_editorsep() { }); } -struct UsernameHeader { +pub struct UsernameHeader { header: String, colour: char, account: String, nameline: String, } -pub fn fromline(account: &str, nameline: &str) -> Box { +impl UsernameHeader { + pub fn from(account: &str, nameline: &str) -> Box { Box::new(UsernameHeader{ header: "From".to_string(), colour: 'F', account: account.to_string(), nameline: nameline.to_string(), }) -} + } -pub fn boosterline(account: &str, nameline: &str) -> Box { - Box::new(UsernameHeader{ - header: "Via".to_string(), - colour: 'f', - account: account.to_string(), - nameline: nameline.to_string(), - }) + pub fn via(account: &str, nameline: &str) -> Box { + Box::new(UsernameHeader{ + header: "Via".to_string(), + colour: 'f', + account: account.to_string(), + nameline: nameline.to_string(), + }) + } } impl TextFragment for UsernameHeader { @@ -169,13 +178,14 @@ impl TextFragment for UsernameHeader { #[test] fn test_userheader() { - assert_eq!(fromline("stoat@example.com", "Some Person").render(80), vec! { + assert_eq!(UsernameHeader::from("stoat@example.com", "Some Person") + .render(80), vec! { ColouredString::general( "From: Some Person (stoat@example.com)", " FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", ) }); - assert_eq!(boosterline("stoat@example.com", "Some Person") + assert_eq!(UsernameHeader::via("stoat@example.com", "Some Person") .render(80), vec! { ColouredString::general( "Via: Some Person (stoat@example.com)", @@ -442,14 +452,16 @@ fn test_para_wrap() { }); } -struct FileHeader { +pub struct FileHeader { text: ColouredString, } -pub fn fileheader(text: ColouredString) -> Box { - Box::new(FileHeader{ - text: text, - }) +impl FileHeader { + pub fn new(text: ColouredString) -> Box { + Box::new(FileHeader{ + text: text, + }) + } } impl TextFragment for FileHeader { @@ -478,8 +490,8 @@ impl TextFragment for FileHeader { #[test] fn test_fileheader() { - assert_eq!(fileheader(ColouredString::uniform("hello, world", 'H')) - .render(40), + let fh = FileHeader::new(ColouredString::uniform("hello, world", 'H')); + assert_eq!(fh.render(40), vec! { ColouredString::general("(o) hello, world (o)", "JJJ HHHHHHHHHHHH JJJ"), @@ -487,8 +499,7 @@ fn test_fileheader() { "JJJ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JJJ"), }); - assert_eq!(fileheader(ColouredString::uniform("hello, world", 'H')) - .render(21), + assert_eq!(fh.render(21), vec! { ColouredString::general("(o) hello, world (o)", "JJJ HHHHHHHHHHHH JJJ"), @@ -496,8 +507,7 @@ fn test_fileheader() { "JJJ ~~~~~~~~~~~~ JJJ"), }); - assert_eq!(fileheader(ColouredString::uniform("hello, world", 'H')) - .render(20), + assert_eq!(fh.render(20), vec! { ColouredString::general("(o) hello, worl (o)", "JJJ HHHHHHHHHHH JJJ"), @@ -505,8 +515,7 @@ fn test_fileheader() { "JJJ ~~~~~~~~~~~ JJJ"), }); - assert_eq!(fileheader(ColouredString::uniform("hello, world", 'H')) - .render(10), + assert_eq!(fh.render(10), vec! { ColouredString::general("hello, wo", "HHHHHHHHH"), @@ -750,8 +759,10 @@ fn test_html() { pub struct ExtendableIndicator {} -pub fn extendable_indicator() -> Box { - Box::new(ExtendableIndicator{}) +impl ExtendableIndicator { + pub fn new() -> Box { + Box::new(ExtendableIndicator{}) + } } impl TextFragment for ExtendableIndicator { @@ -779,7 +790,7 @@ impl TextFragment for ExtendableIndicator { #[test] fn test_extendable() { - assert_eq!(extendable_indicator().render(40), vec! { + assert_eq!(ExtendableIndicator::new().render(40), vec! { ColouredString::plain(""), ColouredString::general( " Press [0] at top of file to extend", @@ -792,16 +803,18 @@ pub struct InReplyToLine { para: Paragraph, } -pub fn in_reply_to_line(post: &Vec) -> Box { - let mut para = Paragraph::new().add(&ColouredString::plain("Re: ")); - let currlen = para.words.len(); - for cpara in post { - para.push_para(cpara); +impl InReplyToLine { + pub fn new(post: &Vec) -> Box { + let mut para = Paragraph::new().add(&ColouredString::plain("Re: ")); + let currlen = para.words.len(); + for cpara in post { + para.push_para(cpara); + } + para.delete_mention_words_from(currlen); + Box::new(InReplyToLine { + para: para + }) } - para.delete_mention_words_from(currlen); - Box::new(InReplyToLine { - para: para - }) } impl TextFragment for InReplyToLine { @@ -830,7 +843,7 @@ fn test_in_reply_to() { "@@@@@@@ ")), }; - let irt = in_reply_to_line(&post); + let irt = InReplyToLine::new(&post); assert_eq!(irt.render(48), vec!{ ColouredString::general( "Re: take a look at this otter! @badger might...", @@ -860,33 +873,35 @@ pub struct NotificationLog { para: Paragraph, } -pub fn notification_log( - timestamp: DateTime, account: &str, nameline: &str, - ntype: NotificationLogType, post: Option<&Vec>) - -> Box { +impl NotificationLog { + pub fn new( + timestamp: DateTime, account: &str, nameline: &str, + ntype: NotificationLogType, post: Option<&Vec>) + -> Box { - let mut para = Paragraph::new(); + let mut para = Paragraph::new(); - let verb = match ntype { - NotificationLogType::Favourited => "favourited: ", - NotificationLogType::Boosted => "boosted: ", - NotificationLogType::Followed => "followed you", - }; - para.push_text(&ColouredString::plain(verb), false); + let verb = match ntype { + NotificationLogType::Favourited => "favourited: ", + NotificationLogType::Boosted => "boosted: ", + NotificationLogType::Followed => "followed you", + }; + para.push_text(&ColouredString::plain(verb), false); - if let Some(paras) = post { - let currlen = para.words.len(); - for cpara in paras { - para.push_para(cpara); + if let Some(paras) = post { + let currlen = para.words.len(); + for cpara in paras { + para.push_para(cpara); + } + para.delete_mention_words_from(currlen); } - para.delete_mention_words_from(currlen); - } - Box::new(NotificationLog { - timestamp: timestamp, - account_desc: format!("{} ({})", nameline, account), - para: para, - }) + Box::new(NotificationLog { + timestamp: timestamp, + account_desc: format!("{} ({})", nameline, account), + para: para, + }) + } } impl TextFragment for NotificationLog { @@ -927,7 +942,7 @@ fn test_notification_log() { "@@@@@@@ ")), }; - assert_eq!(notification_log( + assert_eq!(NotificationLog::new( t, "foo@example.com", "Foo Bar", NotificationLogType::Boosted, Some(&post)).render(80), vec! { ColouredString::general("Fri Aug 3 04:05:06 2001 Foo Bar (foo@example.com) boosted: take a look at this", @@ -936,7 +951,7 @@ fn test_notification_log() { " @@@@@@@ "), }); - assert_eq!(notification_log( + assert_eq!(NotificationLog::new( t, "foo@example.com", "Foo Bar", NotificationLogType::Favourited, Some(&post)).render(51), vec! { ColouredString::general("Fri Aug 3 04:05:06 2001 Foo Bar (foo@example.com)", @@ -945,7 +960,7 @@ fn test_notification_log() { " @@@@@@@ "), }); - assert_eq!(notification_log( + assert_eq!(NotificationLog::new( t, "foo@example.com", "Foo Bar", NotificationLogType::Followed, None).render(80), vec! { ColouredString::general("Fri Aug 3 04:05:06 2001 Foo Bar (foo@example.com) followed you", @@ -957,11 +972,13 @@ pub struct UserListEntry { account_desc: String, } -pub fn user_list_entry(account: &str, nameline: &str) - -> Box { - Box::new(UserListEntry { - account_desc: format!("{} ({})", nameline, account), - }) +impl UserListEntry { + pub fn new(account: &str, nameline: &str) + -> Box { + Box::new(UserListEntry { + account_desc: format!("{} ({})", nameline, account), + }) + } } impl TextFragment for UserListEntry { @@ -976,7 +993,8 @@ impl TextFragment for UserListEntry { #[test] fn test_user_list_entry() { - assert_eq!(user_list_entry("foo@example.com", "Foo Bar").render(80), vec! { + assert_eq!(UserListEntry::new("foo@example.com", "Foo Bar") + .render(80), vec! { ColouredString::general("Foo Bar (foo@example.com)", " "), }); @@ -987,19 +1005,21 @@ pub struct Media { description: Vec, } -pub fn media(url: &str, description: &str) - -> Box { - let mut paras = description - .split('\n') - .map(|x| Paragraph::new() - .set_indent(2, 2) - .add(&ColouredString::uniform(x, 'm'))) - .collect(); - trim_para_list(&mut paras); - Box::new(Media { - url: url.to_string(), - description: paras, - }) +impl Media { + pub fn new(url: &str, description: &str) + -> Box { + let mut paras = description + .split('\n') + .map(|x| Paragraph::new() + .set_indent(2, 2) + .add(&ColouredString::uniform(x, 'm'))) + .collect(); + trim_para_list(&mut paras); + Box::new(Media { + url: url.to_string(), + description: paras, + }) + } } impl TextFragment for Media { @@ -1014,8 +1034,8 @@ impl TextFragment for Media { #[test] fn test_media() { - assert_eq!(media("https://example.com/example.png", - "A picture of an example, sitting on an example, with examples dotted around the example landscape.\n\nThis doesn't really make sense, but whatever.").render(50), vec! { + assert_eq!(Media::new("https://example.com/example.png", + "A picture of an example, sitting on an example, with examples dotted around the example landscape.\n\nThis doesn't really make sense, but whatever.").render(50), vec! { ColouredString::uniform("https://example.com/example.png", 'M'), ColouredString::general(" A picture of an example, sitting on an example,", " mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm"),