mirror of https://github.com/djcb/mu.git
* guile: some more improvements
This commit is contained in:
parent
18ce677299
commit
543f4a1926
|
@ -374,7 +374,7 @@ SCM_DEFINE (get_header, "mu:c:get-header", 2, 0, 0,
|
|||
{
|
||||
MuMsgWrapper *msgwrap;
|
||||
char *header;
|
||||
const char *val;
|
||||
SCM val;
|
||||
|
||||
MU_GUILE_INITIALIZED_OR_ERROR;
|
||||
|
||||
|
@ -384,13 +384,14 @@ SCM_DEFINE (get_header, "mu:c:get-header", 2, 0, 0,
|
|||
|
||||
msgwrap = (MuMsgWrapper*) SCM_CDR(MSG);
|
||||
header = scm_to_utf8_string (HEADER);
|
||||
val = mu_msg_get_header (msgwrap->_msg, header);
|
||||
val = mu_guile_scm_from_str
|
||||
(mu_msg_get_header(msgwrap->_msg, header));
|
||||
free (header);
|
||||
|
||||
/* explicitly close the file backend, so we won't run of fds */
|
||||
mu_msg_close_file_backend (msgwrap->_msg);
|
||||
|
||||
return mu_guile_scm_from_str(val);
|
||||
return val;
|
||||
}
|
||||
#undef FUNC_NAME
|
||||
|
||||
|
|
|
@ -204,23 +204,14 @@ Enter `,help' for help.
|
|||
scheme@(guile-user)>
|
||||
@end verbatim
|
||||
|
||||
Now, the first thing we need to do is load the @t{mu-guile} modules;
|
||||
currently, there are six available:
|
||||
|
||||
@itemize
|
||||
@item @code{mu} - initialization, functions to get messages, contacts
|
||||
@item @code{mu message} - functions to deal with messages
|
||||
@item @code{mu contact} - functions to deal with contacts
|
||||
@item @code{mu part} - functions to deal with message-parts / attachments
|
||||
@item @code{mu stats} - some functions for doing statistics on your messages
|
||||
@item @code{mu plot} - functions to draw graphs from the statistics (requires @t{gnuplot}
|
||||
@end itemize
|
||||
The first thing we need to do is loading the modules. All the basics are in
|
||||
the @t{(mu)} module, with some statistical extras in @t{(mu stats)}, and some
|
||||
graph plotting functionality in @t{(mu plot)}.
|
||||
|
||||
Let's simply load all of them:
|
||||
|
||||
@verbatim
|
||||
scheme@(guile-user)> (use-modules (mu) (mu message) (mu contact) (mu part)
|
||||
(mu stats) (mu plot))
|
||||
scheme@(guile-user)> (use-modules (mu) (mu stats) (mu plot))
|
||||
@end verbatim
|
||||
|
||||
Assuming you have installed everything correctly, the first time you do this,
|
||||
|
@ -383,12 +374,12 @@ subject} of any e-mail messages we received in the year 2011. You can try
|
|||
this if you put the following in a separate file, make it executable, and run
|
||||
it like any program.
|
||||
|
||||
@verbatim
|
||||
@lisp
|
||||
#!/bin/sh
|
||||
exec guile -s $0 $@
|
||||
!#
|
||||
|
||||
(use-modules (mu) (mu message))
|
||||
(use-modules (mu))
|
||||
(use-modules (srfi srfi-1))
|
||||
|
||||
(mu:initialize)
|
||||
|
@ -405,14 +396,13 @@ exec guile -s $0 $@
|
|||
subj1 subj2))
|
||||
"" list-of-subjects))
|
||||
|
||||
(format #t "Longest subject: ~s" longest-subject)
|
||||
(newline)
|
||||
@end verbatim
|
||||
(format #t "Longest subject: ~s\n" longest-subject)
|
||||
@end lisp
|
||||
|
||||
There are many other ways to solve the same problem, for example by using an
|
||||
iterative approach with @code{mu:for-each-message}, but it should show how one
|
||||
can easily write little programs to answer specific questions about an e-mail
|
||||
corpus.
|
||||
can easily write little programs to answer specific questions about your
|
||||
e-mail corpus.
|
||||
|
||||
@node Contacts
|
||||
@chapter Contacts
|
||||
|
@ -422,10 +412,6 @@ like @code{mu:from}, @code{mu:to} etc.; @xref{Message methods}. These
|
|||
functions return the list of recipients as a single string; however, often it
|
||||
is more useful to deal with recipients as separate objects.
|
||||
|
||||
@t{mu-guile} offers some functionality for this in the @code{(mu contact)}
|
||||
module. Also, it adds some contact-related methods for @code{<mu:message>}
|
||||
objects.
|
||||
|
||||
@menu
|
||||
* Contact functions and objects::
|
||||
* All contacts::
|
||||
|
@ -437,17 +423,12 @@ objects.
|
|||
@node Contact functions and objects
|
||||
@section Contact functions and objects
|
||||
|
||||
@verbatim
|
||||
(use-modules (mu contact))
|
||||
@end verbatim
|
||||
|
||||
After loading the @code{(mu contact)}, message objects (@pxref{Messages}) gain
|
||||
the the @t{contacts}-methods:
|
||||
Message objects (@pxref{Messages}) have a method @t{mu:contacts}:
|
||||
|
||||
@code{(mu:contacts <message-object> [<contact-type>])}
|
||||
|
||||
The @t{<contact-type>} is a symbol, one of @code{mu:to}, @code{mu:from},
|
||||
@code{mu:cc} or @code{mu:bcc}; this will then get the contact objects for the
|
||||
@code{mu:cc} or @code{mu:bcc}. This will then get the contact objects for the
|
||||
contacts of the corresponding type. If you leave out the contact-type (or
|
||||
specify @t{#t} for it, you will get a list of @emph{all} contact objects for
|
||||
the message.
|
||||
|
@ -462,7 +443,7 @@ Let's get a list of all names and e-mail addresses in the 'To:' field, of
|
|||
messages matching 'book':
|
||||
|
||||
@lisp
|
||||
(use-modules (mu) (mu message) (mu contact))
|
||||
(use-modules (mu))
|
||||
(mu:initialize)
|
||||
(mu:for-each-message
|
||||
(lambda (msg)
|
||||
|
@ -481,10 +462,9 @@ have each of the contacts only show up @emph{once} - for that, please refer to
|
|||
@node All contacts
|
||||
@section All contacts
|
||||
|
||||
Sometimes it may also be useful to look at @emph{all} the different contacts
|
||||
in the @t{mu} database -- that is, all the different contacts. This is useful,
|
||||
for example, when exporting contacts to some external format that can then be
|
||||
important in an e-mail program.
|
||||
Sometimes you may want to inspect @emph{all} the different contacts in the
|
||||
@t{mu} database. This is useful, for instance, when exporting contacts to some
|
||||
external format that can then be important in an e-mail program.
|
||||
|
||||
To enable this, there is the function @code{mu:for-each-contact}, defined as
|
||||
|
||||
|
@ -492,7 +472,7 @@ To enable this, there is the function @code{mu:for-each-contact}, defined as
|
|||
|
||||
This will aggregate the unique contacts from @emph{all} messages matching
|
||||
@t{<search-expression>} (when it is left empty, it will match all messages in
|
||||
the database), and execute @t{function} for each of these contacts.
|
||||
the database), and execute @t{function} for each of them.
|
||||
|
||||
The @t{function} receives an object of the type @t{<mu:contact-with-stats>},
|
||||
which is a @emph{subclass} of the @t{<mu:contact>} class discussed in
|
||||
|
@ -551,7 +531,7 @@ adjust them later by hand, obviously.
|
|||
exec guile -s $0 $@
|
||||
!#
|
||||
|
||||
(use-modules (mu) (mu message) (mu contact))
|
||||
(use-modules (mu))
|
||||
(mu:initialize)
|
||||
|
||||
;; Get a list of contacts that were seen at least 20 times since 2010
|
||||
|
@ -627,7 +607,7 @@ in messages about Luxemburg:
|
|||
exec guile -s $0 $@
|
||||
!#
|
||||
|
||||
(use-modules (mu) (mu message) (mu part))
|
||||
(use-modules (mu))
|
||||
(mu:initialize)
|
||||
|
||||
(define (all-attachments expr)
|
||||
|
@ -676,7 +656,7 @@ how many messages we receive per weekday:
|
|||
exec guile -s $0 $@
|
||||
!#
|
||||
|
||||
(use-modules (mu) (mu message) (mu stats) (mu plot))
|
||||
(use-modules (mu) (mu stats) (mu plot))
|
||||
(mu:initialize)
|
||||
|
||||
;; create a list like (("Sun" . 13) ("Mon" . 23) ...)
|
||||
|
@ -746,7 +726,7 @@ message per hour:
|
|||
exec guile -s $0 $@
|
||||
!#
|
||||
|
||||
(use-modules (mu) (mu message) (mu contact) (mu stats) (mu plot))
|
||||
(use-modules (mu) (mu stats) (mu plot))
|
||||
(mu:initialize)
|
||||
|
||||
(define (mail-per-hour-table)
|
||||
|
@ -784,8 +764,6 @@ exec guile -s $0 $@
|
|||
Hour
|
||||
@end verbatim
|
||||
|
||||
|
||||
|
||||
@node GNU Free Documentation License
|
||||
@appendix GNU Free Documentation License
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
mu:for-each-msg
|
||||
mu:message-list
|
||||
;; message funcs
|
||||
header
|
||||
mu:header
|
||||
;; message accessors
|
||||
mu:field:bcc
|
||||
mu:field:body-html
|
||||
|
@ -143,7 +143,7 @@
|
|||
(define-getter mu:timestamp mu:field:timestamp)
|
||||
(define-getter mu:to mu:field:to)
|
||||
|
||||
(define-method (header (msg <mu:message>) (hdr <string>))
|
||||
(define-method (mu:header (msg <mu:message>) (hdr <string>))
|
||||
"Get an arbitrary header HDR from message MSG; return #f if it does
|
||||
not exist."
|
||||
(mu:c:get-header (slot-ref msg 'msg) hdr))
|
||||
|
|
|
@ -24,8 +24,9 @@
|
|||
:use-module (ice-9 r5rs)
|
||||
:export ( mu:tabulate
|
||||
mu:average
|
||||
mu:standard-deviation
|
||||
mu:pearsons-r
|
||||
mu:stddev
|
||||
mu:max
|
||||
mu:min
|
||||
mu:weekday-numbers->names
|
||||
mu:month-numbers->names))
|
||||
|
||||
|
@ -68,11 +69,11 @@ undefined."
|
|||
EXPR (or #t for all). Returns #f if undefined."
|
||||
(average (map func (mu:message-list expr))))
|
||||
|
||||
(define* (mu:standard-deviation func #:optional (expr #t))
|
||||
"Get the standard deviation for the the values of FUNC applied to
|
||||
all messages matching EXPR (or #t for all). Returns #f if undefined."
|
||||
(define* (mu:stddev func #:optional (expr #t))
|
||||
"Get the standard deviation the the values of FUNC applied to all
|
||||
messages matching EXPR (or #t for all). This is the 'population' stddev, not the 'sample' stddev. Returns #f if undefined."
|
||||
(stddev (map func (mu:message-list expr))))
|
||||
|
||||
|
||||
(define* (mu:max func #:optional (expr #t))
|
||||
"Get the maximum value of FUNC applied to all messages matching
|
||||
EXPR (or #t for all). Returns #f if undefined."
|
||||
|
@ -82,25 +83,7 @@ EXPR (or #t for all). Returns #f if undefined."
|
|||
"Get the minimum value of FUNC applied to all messages matching
|
||||
EXPR (or #t for all). Returns #f if undefined."
|
||||
(apply min (map func (mu:message-list expr))))
|
||||
|
||||
(define* (mu:pearsons-r func1 func2 #:optional (expr #t))
|
||||
"Calculate Pearson's product-moment correlation coefficient between
|
||||
func1 and func2. Inefficient implementation."
|
||||
(let* ((msglist (mu:message-list expr))
|
||||
(lst-x (map func1 msglist))
|
||||
(lst-y (map func2 msglist))
|
||||
(avg-x (average lst-x))
|
||||
(avg-y (average lst-y))
|
||||
(denominator (sqrt (* (stddev lst-x) (stddev lst-y))))
|
||||
(n (length lst-x))
|
||||
(cov-xy 0))
|
||||
(while (not (null? lst-x))
|
||||
(set! cov-xy (+ (* (- (car lst-x) avg-x) (- (car lst-y) avg-y))))
|
||||
(set! lst-x (cdr lst-x))
|
||||
(set! lst-y (cdr lst-y)))
|
||||
(/ (/ cov-xy n) denominator)))
|
||||
|
||||
|
||||
|
||||
;; a list of abbreviated, localized day names
|
||||
(define day-names
|
||||
(map locale-day-short (iota 7 1)))
|
||||
|
|
|
@ -20,8 +20,9 @@ exec guile -e main -s $0 $@
|
|||
;; Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
(setlocale LC_ALL "")
|
||||
|
||||
(use-modules (srfi srfi-1))
|
||||
(use-modules (ice-9 getopt-long) (ice-9 optargs) (ice-9 popen) (ice-9 format))
|
||||
(use-modules (mu))
|
||||
(use-modules (mu) (mu stats))
|
||||
|
||||
(define (n-results-or-exit query n)
|
||||
"Run QUERY, and exit 1 if the number of results != N."
|
||||
|
@ -73,6 +74,7 @@ exec guile -e main -s $0 $@
|
|||
(str-equal-or-exit (mu:subject msg) "Fwd: rfc822")
|
||||
(str-equal-or-exit (mu:to msg) "martin")
|
||||
(str-equal-or-exit (mu:from msg) "foobar <foo@example.com>")
|
||||
(str-equal-or-exit (mu:header msg "X-Mailer") "Ximian Evolution 1.4.5")
|
||||
|
||||
(if (not (equal? (mu:priority msg) mu:prio:normal))
|
||||
(error-exit "Expected ~A, got ~A" (mu:priority msg) mu:prio:normal)))
|
||||
|
@ -81,18 +83,27 @@ exec guile -e main -s $0 $@
|
|||
(str-equal-or-exit (mu:subject msg) "atoms")
|
||||
(str-equal-or-exit (mu:to msg) "Democritus <demo@example.com>")
|
||||
(str-equal-or-exit (mu:from msg) "\"Richard P. Feynman\" <rpf@example.com>")
|
||||
(str-equal-or-exit (mu:header msg "Content-transfer-encoding") "7BIT")
|
||||
|
||||
(if (not (equal? (mu:priority msg) mu:prio:high))
|
||||
(error-exit "Expected ~a, got ~a" (mu:priority msg) mu:prio:high))))
|
||||
|
||||
(define (num-equal-or-exit got exp)
|
||||
"S1 == S2 or exit 1."
|
||||
;; (format #t "'~A' <=> '~A'\n" s1 s2)
|
||||
(if (not (= exp got))
|
||||
(error-exit "Expected \"~S\", got \"~S\"\n" exp got)))
|
||||
|
||||
(define (test-stats)
|
||||
"Test statistical functions."
|
||||
)
|
||||
|
||||
;; average
|
||||
(num-equal-or-exit (mu:average mu:size) 20422/3)
|
||||
(num-equal-or-exit (floor (mu:stddev mu:size))
|
||||
(floor 13414.7101616927))
|
||||
(num-equal-or-exit (mu:max mu:size) 46230)
|
||||
(num-equal-or-exit (mu:min mu:size) 111))
|
||||
|
||||
(define (main args)
|
||||
|
||||
(let* ((optionspec '((muhome (value #t))
|
||||
(test (value #t))))
|
||||
(options (getopt-long args optionspec))
|
||||
|
|
Loading…
Reference in New Issue