* guile: some more improvements

This commit is contained in:
djcb 2012-07-15 12:44:52 +03:00
parent 18ce677299
commit 543f4a1926
5 changed files with 50 additions and 77 deletions

View File

@ -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

View File

@ -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

View File

@ -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))

View File

@ -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)))

View File

@ -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))