emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/taxy e09dc38 32/39: Add: (taxy-mapc*) And musicy.el exa


From: ELPA Syncer
Subject: [elpa] externals/taxy e09dc38 32/39: Add: (taxy-mapc*) And musicy.el example
Date: Fri, 27 Aug 2021 10:57:35 -0400 (EDT)

branch: externals/taxy
commit e09dc38a5786b3de2a70437f232968b644f32e13
Author: Adam Porter <adam@alphapapa.net>
Commit: Adam Porter <adam@alphapapa.net>

    Add: (taxy-mapc*) And musicy.el example
---
 README.org          |  49 +++++++++++---------
 examples/README.org |  26 +++++++++++
 examples/musicy.el  | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 images/musicy.png   | Bin 0 -> 28010 bytes
 taxy.el             |  11 +++++
 taxy.info           |  77 +++++++++++++++++++++++++-------
 6 files changed, 252 insertions(+), 37 deletions(-)

diff --git a/README.org b/README.org
index 4624c6f..168a687 100644
--- a/README.org
+++ b/README.org
@@ -23,37 +23,17 @@ Helpful features include:
 :END:
 :CONTENTS:
 - [[#examples][Examples]]
+  - [[#example-applications][Example applications]]
 - [[#usage][Usage]]
   - [[#dynamic-taxys][Dynamic taxys]]
   - [[#reusable-taxys][Reusable taxys]]
   - [[#threading-macros][Threading macros]]
+  - [[#modifying-filled-taxys][Modifying filled taxys]]
   - [[#magit-section][Magit section]]
 - [[#changelog][Changelog]]
 - [[#development][Development]]
 :END:
 
-# * Installation
-# :PROPERTIES:
-# :TOC:      :depth 0
-# :END:
-#
-# ** MELPA
-#
-# If you installed from MELPA, you're done.  Just run one of the commands 
below.
-#
-# ** Manual
-#
-#   Install these required packages:
-#
-#   + =foo=
-#   + =bar=
-#
-#   Then put this file in your load-path, and put this in your init file:
-#
-#   #+BEGIN_SRC elisp
-# (require 'taxy)
-#   #+END_SRC
-
 * Examples
 
 Let's imagine a silly taxonomy of numbers below 100:
@@ -220,6 +200,10 @@ That's better:
      ("B" "C" "D" "F" "G" "H" "J" "K" "L" "M" "N" "N" "P" "Q" "R" "S" "T" "V" 
"W" "X" "Y" "Z"))))
 #+END_SRC
 
+** Example applications
+
+Some example applications may be found in the 
[[file:examples/README.org][examples directory]].
+
 * Usage
 :PROPERTIES:
 :TOC:      :include descendants :depth 1
@@ -228,6 +212,7 @@ That's better:
 - [[#dynamic-taxys][Dynamic taxys]]
 - [[#reusable-taxys][Reusable taxys]]
 - [[#threading-macros][Threading macros]]
+- [[#modifying-filled-taxys][Modifying filled taxys]]
 - [[#magit-section][Magit section]]
 :END:
 
@@ -458,6 +443,26 @@ If you happen to like macros, ~taxy~ works well with 
threading (i.e. ~thread-las
     taxy-plain)
 #+END_SRC
 
+** Modifying filled taxys
+
+Sometimes it's necessary to modify a taxy after filling it with objects, e.g. 
to sort the objects and/or the sub-taxys.  For this, use the function 
~taxy-mapc-taxys~ (a.k.a. ~taxy-mapc*~).  For example, in the sample 
application [[file:examples/musicy.el][musicy.el]], the taxys and their objects 
are sorted after filling, like so:
+
+#+BEGIN_SRC elisp
+  (defun musicy-files (files)
+    (thread-last musicy-taxy
+      taxy-emptied
+      (taxy-fill files)
+      (taxy-mapc* (lambda (taxy)
+                    ;; Sort sub-taxys by their name.
+                    (setf (taxy-taxys taxy)
+                          (cl-sort (taxy-taxys taxy) #'string<
+                                   :key #'taxy-name))
+                    ;; Sort sub-taxys' objects by name.
+                    (setf (taxy-objects taxy)
+                          (cl-sort (taxy-objects taxy) #'string<))))
+      taxy-magit-section-pp))
+#+END_SRC
+
 ** Magit section
 
 Showing a =taxy= with =magit-section= is very easy:
diff --git a/examples/README.org b/examples/README.org
new file mode 100644
index 0000000..06d7325
--- /dev/null
+++ b/examples/README.org
@@ -0,0 +1,26 @@
+#+TITLE: Taxy Examples
+
+Some example applcations using ~taxy~.
+
+* Musicy
+
+[[file:musicy.el][Musicy]] displays a music library in a ~magit-section~ 
buffer.  Use it like:
+
+#+BEGIN_SRC elisp
+  (require 'musicy)
+
+  (musicy "~/Music")
+#+END_SRC
+
+Since it calls the =mediainfo= program on every file, it can be slow on large 
music libraries, so you might want to test it on only a subset of them, like:
+
+#+BEGIN_SRC elisp
+  (musicy-files
+   (seq-take (directory-files-recursively
+              "~/Music" (rx "." (or "mp3" "ogg") eos))
+             100))
+#+END_SRC
+
+The resulting buffer shows tracks organized by genre, then artist, then year, 
then album, then track name:
+
+[[../images/musicy.png]]
diff --git a/examples/musicy.el b/examples/musicy.el
new file mode 100644
index 0000000..be74fcd
--- /dev/null
+++ b/examples/musicy.el
@@ -0,0 +1,126 @@
+;;; musicy.el --- View a music library in a useful taxonomy  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2021  Adam Porter
+
+;; Author: Adam Porter <adam@alphapapa.net>
+;; Keywords: convenience
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This is a sample application using `taxi'.  It uses the "mediainfo"
+;; program to get info about audio files, but any function could be
+;; swapped into its place (e.g. one that retrieved data from MPD).
+
+;;; Code:
+
+;;;; Requirements
+
+(require 'cl-lib)
+
+(require 'taxy)
+(require 'taxy-magit-section)
+
+;; Used to avoid repeated calls to "mediainfo" for the same file.
+(require 'memoize)
+
+;;;; Variables
+
+(defvar musicy-taxy
+  (cl-labels ((call-proc (process &rest args)
+                         "Return results of running PROCESS with ARGS."
+                         (declare (indent defun))
+                         (with-temp-buffer
+                           (if (zerop (apply #'call-process process nil t nil
+                                             args))
+                               (buffer-substring-no-properties (point-min) 
(point-max))
+                             (warn "mediainfo failed for: %S" args))))
+              (mediainfo (file)
+                         (call-proc "mediainfo" file))
+              (mediainfo-attr (attr file)
+                              (if-let ((info (musicy-mediainfo file)))
+                                  (when (string-match
+                                         (rx-to-string `(seq (eval ,attr) (1+ 
blank) ":" (1+ blank) (group (1+ nonl))))
+                                         info)
+                                    (match-string 1 info))
+                                (format "No info for file: %S" file)))
+              (genre (file)
+                     (or (mediainfo-attr "Genre" file)
+                         "[unknown genre]"))
+              (year (file)
+                    (or (when-let (date (or (mediainfo-attr "Recorded date" 
file)
+                                            (mediainfo-attr "Original/Released 
date" file)
+                                            (mediainfo-attr "Year" file)))
+                          (when (string-match (rx (group (1+ digit))) date)
+                            (match-string 1 date)))
+                        "[unknown year]"))
+              (artist (file)
+                      (mediainfo-attr "Performer" file))
+              (album (file)
+                     (mediainfo-attr "Album" file))
+              (track-name (file)
+                          (mediainfo-attr "Track name" file))
+              (track-number (file)
+                            (mediainfo-attr "Track name/Position" file))
+              (track-string (file)
+                            (concat
+                             (pcase (track-number file)
+                               ((or "-1" 'nil) nil)
+                               (number (format "%s: " number)))
+                             (track-name file))))
+    (make-taxy
+     :name "Musicy"
+     :taxys (list (make-taxy
+                   :name "Genres"
+                   :take (apply-partially #'taxy-take-keyed*
+                                          (list #'genre #'artist #'year 
#'album #'track-string)))))))
+
+;;;; Customization
+
+
+;;;; Commands
+
+(defun musicy (directory)
+  (interactive (list (read-directory-name "Directory of music files: ")))
+  (let ((files (directory-files-recursively
+                directory (rx "." (or "mp3" "ogg") eos))))
+    (musicy-files files)))
+
+(defun musicy-files (files)
+  (thread-last musicy-taxy
+    taxy-emptied
+    (taxy-fill files)
+    (taxy-mapc* (lambda (taxy)
+                  (setf (taxy-taxys taxy)
+                        (cl-sort (taxy-taxys taxy) #'string<
+                                 :key #'taxy-name))
+                  (setf (taxy-objects taxy)
+                        (cl-sort (taxy-objects taxy) #'string<))))
+    ;;  taxy-plain
+    taxy-magit-section-pp))
+
+;;;; Functions
+
+(defmemoize musicy-mediainfo (file)
+  (with-temp-buffer
+    (if (zerop (call-process "mediainfo" nil t nil file))
+        (buffer-substring-no-properties (point-min) (point-max))
+      (warn "mediainfo failed for: %S" file))))
+
+;;;; Footer
+
+(provide 'musicy)
+
+;;; musicy.el ends here
diff --git a/images/musicy.png b/images/musicy.png
new file mode 100644
index 0000000..8b2af29
Binary files /dev/null and b/images/musicy.png differ
diff --git a/taxy.el b/taxy.el
index 335f7dd..6ba04a5 100644
--- a/taxy.el
+++ b/taxy.el
@@ -116,6 +116,17 @@ replace objects with a more useful form after 
classification."
 
 (defalias 'taxy-mapcar #'taxy-mapcar-objects)
 
+(defun taxy-mapc-taxys (fn taxy)
+  "Return TAXY having applied FN to it and its descendants.
+Does not copy TAXY.  Destructively modifies TAXY, if FN does."
+  (declare (indent defun))
+  (funcall fn taxy)
+  (cl-loop for sub-taxy in-ref (taxy-taxys taxy)
+           do (setf sub-taxy (taxy-mapc-taxys fn sub-taxy)))
+  taxy)
+
+(defalias 'taxy-mapc* #'taxy-mapc-taxys)
+
 (cl-defun taxy-take-keyed (key-fn object taxy &key (key-name-fn #'identity))
   "Take OBJECT into TAXY, adding new taxys dynamically.
 Places OBJECT into a taxy in TAXY for the value returned by
diff --git a/taxy.info b/taxy.info
index 43ef1bc..ccb6d37 100644
--- a/taxy.info
+++ b/taxy.info
@@ -21,12 +21,17 @@ taxy.el
 
 — The Detailed Node Listing —
 
+Examples
+
+* Example applications::
+
 
 Usage
 
 * Dynamic taxys::
 * Reusable taxys::
 * Threading macros::
+* Modifying filled taxys::
 * Magit section::
 
 Dynamic taxys
@@ -210,13 +215,26 @@ subset of the taxys’ slots, suitable for display.
        ("Consonants" "Well, if they aren't a vowel..."
         ("B" "C" "D" "F" "G" "H" "J" "K" "L" "M" "N" "N" "P" "Q" "R" "S" "T" 
"V" "W" "X" "Y" "Z"))))
 
+* Menu:
+
+* Example applications::
+
+
+File: README.info,  Node: Example applications,  Up: Examples
+
+1.1 Example applications
+========================
+
+Some example applications may be found in the examples directory
+(examples/README.org).
+
 
 File: README.info,  Node: Usage,  Next: Changelog,  Prev: Examples,  Up: Top
 
 2 Usage
 *******
 
-   • • • • 
+   • • • • • 
    A taxy is defined with the ‘make-taxy’ constructor, like:
 
      (make-taxy :name "Numbery"
@@ -257,6 +275,7 @@ replace objects in a taxy with, e.g.  a more useful 
representation.
 * Dynamic taxys::
 * Reusable taxys::
 * Threading macros::
+* Modifying filled taxys::
 * Magit section::
 
 
@@ -477,7 +496,7 @@ replace the room structs with useful representations for 
display:
            ("#matrix-dev:matrix.org" "!jxlRxnrZCsjpjDubDX:matrix.org")))))))
 
 
-File: README.info,  Node: Threading macros,  Next: Magit section,  Prev: 
Reusable taxys,  Up: Usage
+File: README.info,  Node: Threading macros,  Next: Modifying filled taxys,  
Prev: Reusable taxys,  Up: Usage
 
 2.3 Threading macros
 ====================
@@ -494,9 +513,35 @@ If you happen to like macros, ‘taxy’ works well with 
threading (i.e.
        taxy-plain)
 
 
-File: README.info,  Node: Magit section,  Prev: Threading macros,  Up: Usage
+File: README.info,  Node: Modifying filled taxys,  Next: Magit section,  Prev: 
Threading macros,  Up: Usage
+
+2.4 Modifying filled taxys
+==========================
+
+Sometimes it’s necessary to modify a taxy after filling it with objects,
+e.g.  to sort the objects and/or the sub-taxys.  For this, use the
+function ‘taxy-mapc-taxys’ (a.k.a.  ‘taxy-mapc*’).  For example, in the
+sample application musicy.el (examples/musicy.el), the taxys and their
+objects are sorted after filling, like so:
+
+     (defun musicy-files (files)
+       (thread-last musicy-taxy
+         taxy-emptied
+         (taxy-fill files)
+         (taxy-mapc* (lambda (taxy)
+                       ;; Sort sub-taxys by their name.
+                       (setf (taxy-taxys taxy)
+                             (cl-sort (taxy-taxys taxy) #'string<
+                                      :key #'taxy-name))
+                       ;; Sort sub-taxys' objects by name.
+                       (setf (taxy-objects taxy)
+                             (cl-sort (taxy-objects taxy) #'string<))))
+         taxy-magit-section-pp))
+
+
+File: README.info,  Node: Magit section,  Prev: Modifying filled taxys,  Up: 
Usage
 
-2.4 Magit section
+2.5 Magit section
 =================
 
 Showing a taxy with magit-section is very easy:
@@ -552,17 +597,19 @@ GPLv3
 
 Tag Table:
 Node: Top218
-Node: Examples1101
-Node: Usage9001
-Node: Dynamic taxys11087
-Node: Multi-level dynamic taxys13505
-Node: Reusable taxys15668
-Node: Threading macros19837
-Node: Magit section20367
-Node: Changelog20962
-Node: 01-pre21100
-Node: Development21194
-Node: License21365
+Node: Examples1164
+Node: Example applications9099
+Node: Usage9304
+Node: Dynamic taxys11421
+Node: Multi-level dynamic taxys13839
+Node: Reusable taxys16002
+Node: Threading macros20171
+Node: Modifying filled taxys20710
+Node: Magit section21803
+Node: Changelog22404
+Node: 01-pre22542
+Node: Development22636
+Node: License22807
 
 End Tag Table
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]