chiark / gitweb /
Changed my mind again about constructor API
authorSimon Tatham <anakin@pobox.com>
Tue, 26 Dec 2023 10:18:08 +0000 (10:18 +0000)
committerSimon Tatham <anakin@pobox.com>
Tue, 26 Dec 2023 10:18:08 +0000 (10:18 +0000)
src/text.rs

index 4b87b63c739bfe60d85e7e1b137a8d1fdef262bc..49fa81946db551f8c970dca4c47bd9b15b79e45c 100644 (file)
@@ -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<ColouredString>;
 
     fn as_extendable_indicator(&self) -> Option<&ExtendableIndicator> { None }
 }
 
-struct BlankLine {}
+pub struct BlankLine {}
 
-pub fn blank() -> Box<dyn TextFragment> {
-    Box::new(BlankLine{})
+impl BlankLine {
+    pub fn new() -> Box<dyn TextFragment> {
+        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<DateTime<Utc>>,
     favourited: bool,
     boosted: bool,
 }
 
-pub fn separator(
-    timestamp: Option<DateTime<Utc>>,
-    favourited: bool,
-    boosted: bool,
-    ) -> Box<dyn TextFragment> {
-    Box::new(SeparatorLine {
-            timestamp,
-            favourited,
-            boosted,
-        })
+impl SeparatorLine {
+    pub fn new(
+        timestamp: Option<DateTime<Utc>>,
+        favourited: bool,
+        boosted: bool,
+        ) -> Box<dyn TextFragment> {
+        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<dyn TextFragment> {
-    Box::new(EditorHeaderSeparator{})
+impl EditorHeaderSeparator {
+    pub fn new() -> Box<dyn TextFragment> {
+        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<dyn TextFragment> {
+impl UsernameHeader {
+    pub fn from(account: &str, nameline: &str) -> Box<dyn TextFragment> {
     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<dyn TextFragment> {
-    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<dyn TextFragment> {
+        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<dyn TextFragment> {
-    Box::new(FileHeader{
-            text: text,
-        })
+impl FileHeader {
+    pub fn new(text: ColouredString) -> Box<dyn TextFragment> {
+        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<dyn TextFragment> {
-    Box::new(ExtendableIndicator{})
+impl ExtendableIndicator {
+    pub fn new() -> Box<dyn TextFragment> {
+        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<Paragraph>) -> Box<dyn TextFragment> {
-    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<Paragraph>) -> Box<dyn TextFragment> {
+        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<Utc>, account: &str, nameline: &str,
-    ntype: NotificationLogType, post: Option<&Vec<Paragraph>>)
-    -> Box<dyn TextFragment> {
+impl NotificationLog {
+    pub fn new(
+        timestamp: DateTime<Utc>, account: &str, nameline: &str,
+        ntype: NotificationLogType, post: Option<&Vec<Paragraph>>)
+        -> Box<dyn TextFragment> {
 
-    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<dyn TextFragment> {
-    Box::new(UserListEntry {
-            account_desc: format!("{} ({})", nameline, account),
-        })
+impl UserListEntry {
+    pub fn new(account: &str, nameline: &str)
+               -> Box<dyn TextFragment> {
+        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<Paragraph>,
 }
 
-pub fn media(url: &str, description: &str)
-    -> Box<dyn TextFragment> {
-    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<dyn TextFragment> {
+        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"),