<commit_before>// Copyright <NAME> 2014

// Package export provides tools to dump tabulated data.
//
// Export allows to dump tabular data in different output formats.
// The main type is Exporter which determines which data is output
// and in which order. An Exporter is constructed from (almost)
// any slice type.  Take a struct S with two fields A and B and two
// methods C and D and.
//
//     type S struct {
//         A float64
//         B string
//     }
//
//     func (s S) C() int {
//         return int(s.A+0.5)
//     }
//
//     func (s S) D() (bool, error) {
//         if s.B == "" {
//             return false, errors.New("empty")
//         }
//         return len(s.B) > 5, nil
//     }
//
//     var data = []S{S{3.14, "Hello"}, S{55.5, ""}}
//     exp, err := NewExtractor("C", "D", "A", B")
//     dumper := TabDumper{Writer: os.Stdout}
//     dumper.dump(exp)
//
// Would produce a text table and output the collumns C, D, A and B.
// Note that column D may contain NA for "not avialable".
//
package export

import (
	"encoding/csv"
	"fmt"
	"io"
	"reflect"
	"text/tabwriter"
	"time"
)

func isTime(x reflect.Type) bool {
	return x.PkgPath() == "time" && x.Kind() == reflect.Struct && x.Name() == "Time"
}

// -------------------------------------------------------------------------
// Type

// Type represents the basisc type of a columne.
type Type uint

const (
	NA Type = iota
	Bool<commit_msg>Document the idea of a gob-like generic type traversal.<commit_after>// Copyright <NAME> 2014

// Package export provides tools to dump tabulated data.
//
// Export allows to dump tabular data in different output formats.
// The main type is Exporter which determines which data is output
// and in which order. An Exporter is constructed from (almost)
// any slice type.  Take a struct S with two fields A and B and two
// methods C and D and.
//
//     type S struct {
//         A float64
//         B string
//     }
//
//     func (s S) C() int {
//         return int(s.A+0.5)
//     }
//
//     func (s S) D() (bool, error) {
//         if s.B == "" {
//             return false, errors.New("empty")
//         }
//         return len(s.B) > 5, nil
//     }
//
//     var data = []S{S{3.14, "Hello"}, S{55.5, ""}}
//     exp, err := NewExtractor("C", "D", "A", B")
//     dumper := TabDumper{Writer: os.Stdout}
//     dumper.dump(exp)
//
// Would produce a text table and output the collumns C, D, A and B.
// Note that column D may contain NA for "not avialable".
//
package export


// Stuff is getting complicated once there are pointers involved.
//     data := []*S{...}
//     type S struct {
//         A *int
//         B struct { C bool; D string}
           E *T
//     }
//     type T struct {
//             F string
//         }
//     }
//     func (t T) M() float64 { return 3.14 }
//     type U struct { G int64 }
//     func (t T) N() (*U, error) { return &U{123}, nil }
// Might be interesting to extract from nested structs like
//     NewExtractor{"A", "B.C", "E.F", "E.M", "E.N.G"}
// So we would have:
//   - plain field: a leaf
//   - ptr to plain field: may fail, one to go for a leaf
//   - nested struct
//   - ptr to nested struct
//   - ptr to ptr to ... ? (realy needed)
//   - method call
// That means a columns spec like "E.N.G" above translates to
// an access rule for row n like:
//   - take element n
//   - deref ptr (to get a S) if non nil, else --> nil
//   - deref E (to get a T) if non nil, else --> nil
//   - call N (to get a *U) if err --> nil
//   - deref ret (to get a U) if non nil, else --> nil
//   - return N
// Each step can be summarized as working on cur
//   If cur is Method:
//       cur = call method
//       if mayFail && hasErr  -->  nil
//       restart
//   If a ptr:
//       If nil  -->  nil
//       Else cur = deref cur
//       restart
//   If struct:
//       cur = field from next part in colspec
//       restart
//   If field:
//       If known type --> return
//       If assignable to known type --> return
//       If encodingTextMarshal-able --> do it an return
//       Printf %v --> return.
// NewExtractor would build such a list of access rules and Column.Value
// would execute this rule list. Pre-Built closures are of limits.
// It would be basically what encoding/gob does, just without cycle
// detection and other fancyness.
//

import (
	"encoding/csv"
	"fmt"
	"io"
	"reflect"
	"text/tabwriter"
	"time"
)

func isTime(x reflect.Type) bool {
	return x.PkgPath() == "time" && x.Kind() == reflect.Struct && x.Name() == "Time"
}

// -------------------------------------------------------------------------
// Type

// Type represents the basisc type of a columne.
type Type uint

const (
	NA Type = iota
	Bool
{'fraction_non_alphanumeric': 0.17872250423011846, 'fraction_numerical': 0.008460236886632826, 'mean_word_length': 1.7115825688073394, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1106709', 'n_tokens_mistral': 1540, 'n_tokens_neox': 1506, 'n_words': 603}