diff --git a/module/core/format_tools/src/format/md_math.rs b/module/core/format_tools/src/format/md_math.rs index a53625fc21..d4de6ae6af 100644 --- a/module/core/format_tools/src/format/md_math.rs +++ b/module/core/format_tools/src/format/md_math.rs @@ -29,7 +29,20 @@ mod private /// # Returns /// /// A value of type `T` representing the flat offset. - fn md_offset( & self, md_index : [ T ; 3 ] ) -> T; + fn md_offset( & self, md_index : Self ) -> T; + } + + impl< T > MdOffset< T > for [ T ; 2 ] + where + T : Mul< T, Output = T > + Add< T, Output = T > + PartialOrd + Copy + fmt::Debug, + { + fn md_offset( & self, md_index : [ T ; 2 ] ) -> T + { + debug_assert!( md_index[ 0 ] < self[ 0 ], "md_index : {md_index:?} | md_size : {self:?}" ); + debug_assert!( md_index[ 1 ] < self[ 1 ], "md_index : {md_index:?} | md_size : {self:?}" ); + let m1 = self[ 0 ]; + md_index[ 0 ] + m1 * md_index[ 1 ] + } } impl< T > MdOffset< T > for [ T ; 3 ] diff --git a/module/core/format_tools/src/format/output_format/records.rs b/module/core/format_tools/src/format/output_format/records.rs index 263177edb8..45a1206e41 100644 --- a/module/core/format_tools/src/format/output_format/records.rs +++ b/module/core/format_tools/src/format/output_format/records.rs @@ -39,7 +39,49 @@ use std::sync::OnceLock; /// `Records` provides an implementation for table formatting that outputs /// each row as a separate table with 2 columns, first is name of column in the original data and second is cell value itself. #[derive( Debug )] -pub struct Records; +pub struct Records +{ + /// Prefix added to each row. + pub table_prefix : String, + /// Postfix added to each row. + pub table_postfix : String, + /// Separator used between rows. + pub table_separator : String, + /// Prefix added to each row. + pub row_prefix : String, + /// Postfix added to each row. + pub row_postfix : String, + /// Separator used between rows. + pub row_separator : String, + /// Prefix added to each cell. + pub cell_prefix : String, + /// Postfix added to each cell. + pub cell_postfix : String, + /// Separator used between table columns. + pub cell_separator : String, + // /// Horizontal line character. + // pub h : char, + // /// Vertical line character. + // pub v : char, + // /// Left T-junction character. + // pub t_l : char, + // /// Right T-junction character. + // pub t_r : char, + // /// Top T-junction character. + // pub t_t : char, + // /// Bottom T-junction character. + // pub t_b : char, + // /// Cross junction character. + // pub cross : char, + // /// Top-left corner character. + // pub corner_lt : char, + // /// Top-right corner character. + // pub corner_rt : char, + // /// Bottom-left corner character. + // pub corner_lb : char, + // /// Bottom-right corner character. + // pub corner_rb : char, +} impl Records { @@ -47,7 +89,7 @@ impl Records pub fn instance() -> & 'static dyn TableOutputFormat { static INSTANCE : OnceLock< Records > = OnceLock::new(); - INSTANCE.get_or_init( || Records ) + INSTANCE.get_or_init( || Records::default() ) } } @@ -55,36 +97,128 @@ impl Default for Records { fn default() -> Self { + + let cell_prefix = "".to_string(); + let cell_postfix = "".to_string(); + let cell_separator = " │ ".to_string(); + let row_prefix = "│ ".to_string(); + let row_postfix = " │".to_string(); + let row_separator = "\n".to_string(); + let table_prefix = "".to_string(); + let table_postfix = "".to_string(); + let table_separator = "\n".to_string(); + + // let h = '─'; + // let v = '|'; + // let t_l = '├'; + // let t_r = '┤'; + // let t_t = '┬'; + // let t_b = '┴'; + // let cross = '┼'; + // let corner_lt = '┌'; + // let corner_rt = '┐'; + // let corner_lb = '└'; + // let corner_rb = '┘'; + Self { + table_prefix, + table_postfix, + table_separator, + row_prefix, + row_postfix, + row_separator, + cell_prefix, + cell_postfix, + cell_separator, + // h, + // v, + // t_l, + // t_r, + // t_t, + // t_b, + // cross, + // corner_lt, + // corner_rt, + // corner_lb, + // corner_rb, } } } impl TableOutputFormat for Records { - fn extract_write< 'buf, 'data > - ( + + fn extract_write< 'buf, 'data >( & self, x : & InputExtract< 'data >, c : & mut Context< 'buf >, ) -> fmt::Result { - for ( i, row ) in x.row_descriptors.iter().enumerate() + + let label_width = x.header().fold( 0, | acc, cell | acc.max( cell.1[ 0 ] ) ); + + write!( c.buf, "{}", self.table_prefix )?; + + let mut first = true; + // Write each record + for ( irow, row ) in x.rows() { + if !row.vis { continue; } - writeln!( c.buf, "-[ RECORD {} ]", i + 1 )?; - for ( icol, col ) in x.col_descriptors.iter().enumerate() + + if first + { + first = false; + } + else + { + write!( c.buf, "{}", self.table_separator )?; + } + + let slice_width = x.data[ irow ].iter().fold( 0, | acc, cell | acc.max( cell.1[ 0 ] ) ); + + writeln!( c.buf, " = {}", irow )?; + + for ( icol, _col ) in x.col_descriptors.iter().enumerate() { - // let cell_width = x.data[ i ][ icol ].1[ 0 ]; - let md_index = [ 0, icol, i ]; - let slice = x.slices[ x.slices_dim.md_offset( md_index ) ]; - writeln!( c.buf, "{} | {}", col.width, slice )?; + let cell = &x.data[ irow ][ icol ]; + let height = cell.1[ 1 ]; + + for islice in 0..height + { + let label = x.header_slice( islice, icol ); + let md_index = [ islice, icol, irow ]; + let slice = x.slices[ x.slices_dim.md_offset( md_index ) ]; + + if icol > 0 || islice > 0 + { + write!( c.buf, "{}", self.row_separator )?; + } + + write!( c.buf, "{}", self.row_prefix )?; + + write!( c.buf, "{}", self.cell_prefix )?; + write!( c.buf, "{: { pub icol : usize, pub width : usize, + pub label : &'label str, } /// A struct for extracting and organizing table data for formatting. @@ -270,21 +273,17 @@ mod private /// Descriptors for each column, including optional title, width, and index. // width, index - // pub col_descriptors : Vec< ( usize, usize ) >, - pub col_descriptors : Vec< ColDescriptor >, + pub col_descriptors : Vec< ColDescriptor< 'data > >, /// Descriptors for each row, including height. - // height - // pub row_descriptors : Vec< ( usize, ) >, pub row_descriptors : Vec< RowDescriptor >, /// Extracted data for each cell, including string content and size. // string, size, - pub data : Vec< Vec< ( Cow< 'data, str >, [ usize ; 2 ] ) > >, + pub data : Vec< Vec< ( Cow< 'data, str >, [ usize ; 2 ] ) > >, // xxx : use maybe flat vector /// Dimensions of slices for retrieving data from multi-matrix. pub slices_dim : [ usize ; 3 ], - /// Extracted slices or strings for further processing. pub slices : Vec< &'data str >, @@ -295,6 +294,76 @@ mod private impl< 'data > InputExtract< 'data > { + /// Returns an iterator over the row descriptors, skipping the header if present. + /// + /// This function provides an iterator that yields each row descriptor along with its index. + /// If the table has a header, the first row is skipped, ensuring that iteration starts from + /// the first data row. + /// + /// # Returns + /// + /// An iterator over tuples containing: + /// - `usize`: The index of the row. + /// - `&RowDescriptor`: A reference to the row descriptor. + /// + pub fn rows( & self ) -> impl _IteratorTrait< Item = ( usize, &RowDescriptor ) > + { + self.row_descriptors + .iter() + .enumerate() + .skip( if self.has_header { 1 } else { 0 } ) + } + + /// Returns an iterator over the header cells, or a default value if no header is present. + /// + /// This function provides an iterator that yields each cell in the header row. If the table + /// does not have a header, it returns an iterator over default values, which are empty strings + /// with a size of `[0, 1]`. + /// + /// # Returns + /// + /// A boxed iterator yielding tuples containing: + /// - `Cow<'data, str>`: A clone-on-write string representing the cell content. + /// - `[usize; 2]`: An array representing the size of the cell. + /// + pub fn header( & self ) -> Box< dyn Iterator< Item = ( Cow< 'data, str >, [ usize ; 2 ] ) > + '_ > + { + if self.has_header + { + Box::new( self.data[ 0 ].iter().cloned() ) + } + else + { + Box::new( std::iter::repeat( ( Cow::Borrowed( "" ), [ 0, 1 ] ) ).take( self.mcells[ 0 ] ) ) + } + } + + /// Returns a slice from the header, or an empty string if no header is present. + /// + /// This function retrieves a specific slice from the header row based on the provided indices. + /// If the table does not have a header, it returns an empty string. + /// + /// # Arguments + /// + /// - `islice`: The slice index within the header cell. + /// - `icol`: The column index within the header row. + /// + /// # Returns + /// + /// A string slice representing the header content at the specified indices. + /// + pub fn header_slice( & self, islice : usize, icol : usize ) -> & str + { + if self.has_header + { + let md_index = [ islice, icol, 0 ]; + self.slices[ self.slices_dim.md_offset( md_index ) ] + } + else + { + "" + } + } /// Extract input data from and collect it in a format consumable by output formatter. pub fn extract< 't, 'context, Table, RowKey, Row, CellKey, CellRepr > ( @@ -306,6 +375,7 @@ mod private -> fmt::Result where 'data : 't, + // 't : 'data, Table : TableRows< RowKey = RowKey, Row = Row, CellKey = CellKey, CellRepr = CellRepr >, Table : TableHeader< CellKey = CellKey >, RowKey : table::RowKey, @@ -323,7 +393,7 @@ mod private // key width, index let mut key_to_ikey : HashMap< &'t CellKey, usize > = HashMap::new(); - let mut col_descriptors : Vec< ColDescriptor > = Vec::with_capacity( mcells[ 0 ] ); + let mut col_descriptors : Vec< ColDescriptor< '_ > > = Vec::with_capacity( mcells[ 0 ] ); let mut row_descriptors : Vec< RowDescriptor > = Vec::with_capacity( mcells[ 1 ] ); let mut has_header = false; @@ -377,12 +447,13 @@ mod private { let col = &mut col_descriptors[ *icol ]; col.width = col.width.max( sz[ 0 ] ); + col.label = ""; }) .or_insert_with( || { let icol = l; let width = sz[ 0 ]; - let col = ColDescriptor { width, icol }; + let col = ColDescriptor { width, icol, label : "" }; col_descriptors.push( col ); icol }); @@ -496,7 +567,6 @@ mod private std::mem::swap( &mut x.slices, &mut slices ); let mut irow : isize = -1; - for row_data in x.data.iter() { @@ -513,6 +583,7 @@ mod private slices[ x.slices_dim.md_offset( md_index ) ] = s; }) ; + x.col_descriptors[ icol ].label = cell.0.as_ref(); } } diff --git a/module/core/format_tools/tests/inc/collection_test.rs b/module/core/format_tools/tests/inc/collection_test.rs index 3c973c94e2..7e1607820e 100644 --- a/module/core/format_tools/tests/inc/collection_test.rs +++ b/module/core/format_tools/tests/inc/collection_test.rs @@ -12,7 +12,6 @@ use the_module:: use std:: { collections::HashMap, - // borrow::Cow, }; use test_object::TestObject; diff --git a/module/core/format_tools/tests/inc/format_ordinary_test.rs b/module/core/format_tools/tests/inc/format_ordinary_test.rs index f0854cd6c0..5dbe2a95d2 100644 --- a/module/core/format_tools/tests/inc/format_ordinary_test.rs +++ b/module/core/format_tools/tests/inc/format_ordinary_test.rs @@ -324,3 +324,5 @@ fn filter_row_callback() } // + +// xxx : implement test for vector of vectors diff --git a/module/core/format_tools/tests/inc/format_records_test.rs b/module/core/format_tools/tests/inc/format_records_test.rs index c1e2cf2b26..8325dea020 100644 --- a/module/core/format_tools/tests/inc/format_records_test.rs +++ b/module/core/format_tools/tests/inc/format_records_test.rs @@ -5,16 +5,16 @@ use the_module:: { AsTable, WithRef, - // filter, + filter, print, output_format, }; -// use std:: -// { -// // collections::HashMap, -// // borrow::Cow, -// }; +use std:: +{ + // collections::HashMap, + borrow::Cow, +}; // @@ -34,287 +34,286 @@ fn basic() assert!( got.is_ok() ); println!( "{}", &output ); - // -[ RECORD 1 ] - // sid | 3 - // sname | Alice - // gap | 5 - // -[ RECORD 2 ] - // sid | 6 - // sname | Joe - // gap | 1 - // -[ RECORD 3 ] - // sid | 10 - // sname | Boris - // gap | 5 - - let exp = r#"xxx"#; - // a_id!( output.as_str(), exp ); + let exp = r#" = 1 +│ id │ 1 │ +│ created_at │ 1627845583 │ +│ file_ids │ [ │ +│ │ "file1", │ +│ │ "file2", │ +│ │ ] │ +│ tools │ │ + = 2 +│ id │ 2 │ +│ created_at │ 13 │ +│ file_ids │ [ │ +│ │ "file3", │ +│ │ "file4\nmore details", │ +│ │ ] │ +│ tools │ [ │ +│ │ { │ +│ │ "tool1": "value1", │ +│ │ }, │ +│ │ { │ +│ │ "tool2": "value2", │ +│ │ }, │ +│ │ ] │"#; + a_id!( output.as_str(), exp ); } // -// #[ test ] -// fn table_to_string() -// { -// use the_module::TableFormatter; -// let test_objects = test_object::test_objects_gen(); -// -// // with explicit arguments -// -// let as_table : AsTable< '_, Vec< test_object::TestObject >, usize, test_object::TestObject, str, WithRef > = AsTable::new( &test_objects ); -// let table_string = as_table.table_to_string(); -// println!( "\ntable_string\n{table_string}" ); -// assert!( table_string.contains( "id" ) ); -// assert!( table_string.contains( "created_at" ) ); -// assert!( table_string.contains( "file_ids" ) ); -// assert!( table_string.contains( "tools" ) ); -// -// // without explicit arguments -// -// println!( "" ); -// let as_table = AsTable::new( &test_objects ); -// let table_string = as_table.table_to_string(); -// assert!( table_string.contains( "id" ) ); -// assert!( table_string.contains( "created_at" ) ); -// assert!( table_string.contains( "file_ids" ) ); -// assert!( table_string.contains( "tools" ) ); -// println!( "\ntable_string\n{table_string}" ); -// -// } -// -// // -// -// #[ test ] -// fn custom_format() -// { -// // use the_module::TableFormatter; -// let test_objects = test_object::test_objects_gen(); -// -// let mut format = output_format::Ordinary::default(); -// format.cell_prefix = "( ".into(); -// format.cell_postfix = " )".into(); -// format.cell_separator = "|".into(); -// format.row_prefix = ">".into(); -// format.row_postfix = "<".into(); -// format.row_separator = "\n".into(); -// -// let printer = print::Printer::with_format( &format ); -// let as_table = AsTable::new( &test_objects ); -// let mut output = String::new(); -// let mut context = print::Context::new( &mut output, printer ); -// let result = the_module::TableFormatter::fmt( &as_table, &mut context ); -// assert!( result.is_ok() ); -// -// println!( "\noutput\n{output}" ); -// assert!( output.contains( "id" ) ); -// assert!( output.contains( "created_at" ) ); -// assert!( output.contains( "file_ids" ) ); -// assert!( output.contains( "tools" ) ); -// -// let exp = r#">( id )|( created_at )|( file_ids )|( tools )< -// ───────────────────────────────────────────────────────────────────────────────────── -// >( 1 )|( 1627845583 )|( [ )|( )< -// >( )|( )|( "file1", )|( )< -// >( )|( )|( "file2", )|( )< -// >( )|( )|( ] )|( )< -// >( 2 )|( 13 )|( [ )|( [ )< -// >( )|( )|( "file3", )|( { )< -// >( )|( )|( "file4\nmore details", )|( "tool1": "value1", )< -// >( )|( )|( ] )|( }, )< -// >( )|( )|( )|( { )< -// >( )|( )|( )|( "tool2": "value2", )< -// >( )|( )|( )|( }, )< -// >( )|( )|( )|( ] )<"#; -// a_id!( output.as_str(), exp ); -// -// // using table_to_string_with_format -// -// use the_module::TableFormatter; -// -// let mut format = output_format::Ordinary::default(); -// format.cell_prefix = "( ".into(); -// format.cell_postfix = " )".into(); -// format.cell_separator = "|".into(); -// format.row_prefix = ">".into(); -// format.row_postfix = "<".into(); -// format.row_separator = "\n".into(); -// -// // let as_table = AsTable::new( &test_objects ); -// let got = AsTable::new( &test_objects ).table_to_string_with_format( &format ); -// let exp = r#">( id )|( created_at )|( file_ids )|( tools )< -// ───────────────────────────────────────────────────────────────────────────────────── -// >( 1 )|( 1627845583 )|( [ )|( )< -// >( )|( )|( "file1", )|( )< -// >( )|( )|( "file2", )|( )< -// >( )|( )|( ] )|( )< -// >( 2 )|( 13 )|( [ )|( [ )< -// >( )|( )|( "file3", )|( { )< -// >( )|( )|( "file4\nmore details", )|( "tool1": "value1", )< -// >( )|( )|( ] )|( }, )< -// >( )|( )|( )|( { )< -// >( )|( )|( )|( "tool2": "value2", )< -// >( )|( )|( )|( }, )< -// >( )|( )|( )|( ] )<"#; -// a_id!( got, exp ); -// -// } -// -// -// -// #[ test ] -// fn filter_col_none() -// { -// let test_objects = test_object::test_objects_gen(); -// -// let mut format = output_format::Ordinary::default(); -// format.cell_prefix = "( ".into(); -// format.cell_postfix = " )".into(); -// format.cell_separator = "|".into(); -// format.row_prefix = ">".into(); -// format.row_postfix = "<".into(); -// format.row_separator = "\n".into(); -// -// let mut printer = print::Printer::with_format( &format ); -// printer.filter_col = &filter::None; -// -// let as_table = AsTable::new( &test_objects ); -// let mut output = String::new(); -// let mut context = print::Context::new( &mut output, printer ); -// let result = the_module::TableFormatter::fmt( &as_table, &mut context ); -// assert!( result.is_ok() ); -// -// println!( "\noutput\n{output}" ); -// -// let exp = r#">< -// ── -// >< -// ><"#; -// -// a_id!( output.as_str(), exp ); -// -// } -// -// // -// -// #[ test ] -// fn filter_col_callback() -// { -// let test_objects = test_object::test_objects_gen(); -// -// let mut format = output_format::Ordinary::default(); -// format.cell_prefix = "( ".into(); -// format.cell_postfix = " )".into(); -// format.cell_separator = "|".into(); -// format.row_prefix = ">".into(); -// format.row_postfix = "<".into(); -// format.row_separator = "\n".into(); -// -// let mut printer = print::Printer::with_format( &format ); -// printer.filter_col = &| title : &str | -// { -// title != "tools" -// }; -// -// let as_table = AsTable::new( &test_objects ); -// let mut output = String::new(); -// let mut context = print::Context::new( &mut output, printer ); -// let result = the_module::TableFormatter::fmt( &as_table, &mut context ); -// assert!( result.is_ok() ); -// -// println!( "\noutput\n{output}" ); -// -// let exp = r#">( id )|( created_at )|( file_ids )< -// ────────────────────────────────────────────────────── -// >( 1 )|( 1627845583 )|( [ )< -// >( )|( )|( "file1", )< -// >( )|( )|( "file2", )< -// >( )|( )|( ] )< -// >( 2 )|( 13 )|( [ )< -// >( )|( )|( "file3", )< -// >( )|( )|( "file4\nmore details", )< -// >( )|( )|( ] )<"#; -// -// a_id!( output.as_str(), exp ); -// -// } -// -// // -// -// #[ test ] -// fn filter_row_none() -// { -// let test_objects = test_object::test_objects_gen(); -// -// let mut format = output_format::Ordinary::default(); -// format.cell_prefix = "( ".into(); -// format.cell_postfix = " )".into(); -// format.cell_separator = "|".into(); -// format.row_prefix = ">".into(); -// format.row_postfix = "<".into(); -// format.row_separator = "\n".into(); -// -// let mut printer = print::Printer::with_format( &format ); -// printer.filter_row = &filter::None; -// -// let as_table = AsTable::new( &test_objects ); -// let mut output = String::new(); -// let mut context = print::Context::new( &mut output, printer ); -// let result = the_module::TableFormatter::fmt( &as_table, &mut context ); -// assert!( result.is_ok() ); -// -// println!( "\noutput\n{output}" ); -// -// let exp = r#""#; -// -// a_id!( output.as_str(), exp ); -// -// } -// -// // -// -// #[ test ] -// fn filter_row_callback() -// { -// let test_objects = test_object::test_objects_gen(); -// -// let mut format = output_format::Ordinary::default(); -// format.cell_prefix = "( ".into(); -// format.cell_postfix = " )".into(); -// format.cell_separator = "|".into(); -// format.row_prefix = ">".into(); -// format.row_postfix = "<".into(); -// format.row_separator = "\n".into(); -// -// let mut printer = print::Printer::with_format( &format ); -// printer.filter_row = &| _typ, irow, _row : &[ ( Cow< '_, str >, [ usize ; 2 ] ) ] | -// { -// irow != 1 -// }; -// -// let as_table = AsTable::new( &test_objects ); -// let mut output = String::new(); -// let mut context = print::Context::new( &mut output, printer ); -// let result = the_module::TableFormatter::fmt( &as_table, &mut context ); -// assert!( result.is_ok() ); +#[ test ] +fn custom_format() +{ + // use the_module::TableFormatter; + let test_objects = test_object::test_objects_gen(); + + let mut format = output_format::Records::default(); + format.cell_prefix = "( ".into(); + format.cell_postfix = " )".into(); + format.cell_separator = "|".into(); + format.row_prefix = ">".into(); + format.row_postfix = "<".into(); + format.row_separator = "\n".into(); + + let printer = print::Printer::with_format( &format ); + let as_table = AsTable::new( &test_objects ); + let mut output = String::new(); + let mut context = print::Context::new( &mut output, printer ); + let result = the_module::TableFormatter::fmt( &as_table, &mut context ); + assert!( result.is_ok() ); + + println!( "\noutput\n{output}" ); + + let exp = r#" = 1 +>( id )|( 1 )< +>( created_at )|( 1627845583 )< +>( file_ids )|( [ )< +>( )|( "file1", )< +>( )|( "file2", )< +>( )|( ] )< +>( tools )|( )< + = 2 +>( id )|( 2 )< +>( created_at )|( 13 )< +>( file_ids )|( [ )< +>( )|( "file3", )< +>( )|( "file4\nmore details", )< +>( )|( ] )< +>( tools )|( [ )< +>( )|( { )< +>( )|( "tool1": "value1", )< +>( )|( }, )< +>( )|( { )< +>( )|( "tool2": "value2", )< +>( )|( }, )< +>( )|( ] )<"#; + a_id!( output.as_str(), exp ); + + // using table_to_string_with_format + + use the_module::TableFormatter; + + let mut format = output_format::Records::default(); + format.cell_prefix = "( ".into(); + format.cell_postfix = " )".into(); + format.cell_separator = "|".into(); + format.row_prefix = ">".into(); + format.row_postfix = "<".into(); + format.row_separator = "\n".into(); + + // let as_table = AsTable::new( &test_objects ); + let got = AsTable::new( &test_objects ).table_to_string_with_format( &format ); + let exp = r#" = 1 +>( id )|( 1 )< +>( created_at )|( 1627845583 )< +>( file_ids )|( [ )< +>( )|( "file1", )< +>( )|( "file2", )< +>( )|( ] )< +>( tools )|( )< + = 2 +>( id )|( 2 )< +>( created_at )|( 13 )< +>( file_ids )|( [ )< +>( )|( "file3", )< +>( )|( "file4\nmore details", )< +>( )|( ] )< +>( tools )|( [ )< +>( )|( { )< +>( )|( "tool1": "value1", )< +>( )|( }, )< +>( )|( { )< +>( )|( "tool2": "value2", )< +>( )|( }, )< +>( )|( ] )<"#; + a_id!( got, exp ); + +} + // -// println!( "\noutput\n{output}" ); + +#[ test ] +fn filter_col_none() +{ + let test_objects = test_object::test_objects_gen(); + + let mut format = output_format::Records::default(); + format.cell_prefix = "( ".into(); + format.cell_postfix = " )".into(); + format.cell_separator = "|".into(); + format.row_prefix = ">".into(); + format.row_postfix = "<".into(); + format.row_separator = "\n".into(); + + let mut printer = print::Printer::with_format( &format ); + printer.filter_col = &filter::None; + + let as_table = AsTable::new( &test_objects ); + let mut output = String::new(); + let mut context = print::Context::new( &mut output, printer ); + let result = the_module::TableFormatter::fmt( &as_table, &mut context ); + assert!( result.is_ok() ); + println!( "\noutput\n{output}" ); + + let exp = r#" = 1 + + = 2 +"#; + + a_id!( output.as_str(), exp ); + +} + // -// let exp = r#">( id )|( created_at )|( file_ids )|( tools )< -// ───────────────────────────────────────────────────────────────────────────────────── -// >( 2 )|( 13 )|( [ )|( [ )< -// >( )|( )|( "file3", )|( { )< -// >( )|( )|( "file4\nmore details", )|( "tool1": "value1", )< -// >( )|( )|( ] )|( }, )< -// >( )|( )|( )|( { )< -// >( )|( )|( )|( "tool2": "value2", )< -// >( )|( )|( )|( }, )< -// >( )|( )|( )|( ] )<"#; + +#[ test ] +fn filter_col_callback() +{ + let test_objects = test_object::test_objects_gen(); + + let mut format = output_format::Records::default(); + format.cell_prefix = "( ".into(); + format.cell_postfix = " )".into(); + format.cell_separator = "|".into(); + format.row_prefix = ">".into(); + format.row_postfix = "<".into(); + format.row_separator = "\n".into(); + + let mut printer = print::Printer::with_format( &format ); + printer.filter_col = &| title : &str | + { + title != "tools" + }; + + let as_table = AsTable::new( &test_objects ); + let mut output = String::new(); + let mut context = print::Context::new( &mut output, printer ); + let result = the_module::TableFormatter::fmt( &as_table, &mut context ); + assert!( result.is_ok() ); + println!( "\noutput\n{output}" ); + + let exp = r#" = 1 +>( id )|( 1 )< +>( created_at )|( 1627845583 )< +>( file_ids )|( [ )< +>( )|( "file1", )< +>( )|( "file2", )< +>( )|( ] )< + = 2 +>( id )|( 2 )< +>( created_at )|( 13 )< +>( file_ids )|( [ )< +>( )|( "file3", )< +>( )|( "file4\nmore details", )< +>( )|( ] )<"#; + + a_id!( output.as_str(), exp ); + +} + // -// a_id!( output.as_str(), exp ); + +#[ test ] +fn filter_row_none() +{ + let test_objects = test_object::test_objects_gen(); + + let mut format = output_format::Records::default(); + format.cell_prefix = "( ".into(); + format.cell_postfix = " )".into(); + format.cell_separator = "|".into(); + format.row_prefix = ">".into(); + format.row_postfix = "<".into(); + format.row_separator = "\n".into(); + + let mut printer = print::Printer::with_format( &format ); + printer.filter_row = &filter::None; + + let as_table = AsTable::new( &test_objects ); + let mut output = String::new(); + let mut context = print::Context::new( &mut output, printer ); + let result = the_module::TableFormatter::fmt( &as_table, &mut context ); + assert!( result.is_ok() ); + + println!( "\noutput\n{output}" ); + + let exp = r#""#; + + a_id!( output.as_str(), exp ); + +} + // -// } + +#[ test ] +fn filter_row_callback() +{ + let test_objects = test_object::test_objects_gen(); + + let mut format = output_format::Records::default(); + format.cell_prefix = "( ".into(); + format.cell_postfix = " )".into(); + format.cell_separator = "|".into(); + format.row_prefix = ">".into(); + format.row_postfix = "<".into(); + format.row_separator = "\n".into(); + + let mut printer = print::Printer::with_format( &format ); + printer.filter_row = &| _typ, irow, _row : &[ ( Cow< '_, str >, [ usize ; 2 ] ) ] | + { + irow != 1 + }; + + let as_table = AsTable::new( &test_objects ); + let mut output = String::new(); + let mut context = print::Context::new( &mut output, printer ); + let result = the_module::TableFormatter::fmt( &as_table, &mut context ); + assert!( result.is_ok() ); + + println!( "\noutput\n{output}" ); + + let exp = r#" = 2 +>( id )|( 2 )< +>( created_at )|( 13 )< +>( file_ids )|( [ )< +>( )|( "file3", )< +>( )|( "file4\nmore details", )< +>( )|( ] )< +>( tools )|( [ )< +>( )|( { )< +>( )|( "tool1": "value1", )< +>( )|( }, )< +>( )|( { )< +>( )|( "tool2": "value2", )< +>( )|( }, )< +>( )|( ] )<"#; + + a_id!( output.as_str(), exp ); + +} + // -// // // xxx : enable \ No newline at end of file