diff -Nru ht-el-2.1/CHANGELOG.md ht-el-2.2/CHANGELOG.md --- ht-el-2.1/CHANGELOG.md 2016-08-07 00:52:15.000000000 +0000 +++ ht-el-2.2/CHANGELOG.md 2017-11-12 22:05:35.000000000 +0000 @@ -1,3 +1,11 @@ +## v2.2 + +* Added `ht-select-keys` +* Added `ht-get*` + +ht.el now uses `defsubst` for many of its functions, which may improve +performance in byte-compiled code. + ## v2.1 * `ht<-alist` and `ht<-plist` gained an optional argument `test` to diff -Nru ht-el-2.1/debian/changelog ht-el-2.2/debian/changelog --- ht-el-2.1/debian/changelog 2017-02-10 18:58:25.000000000 +0000 +++ ht-el-2.2/debian/changelog 2017-11-15 08:23:18.000000000 +0000 @@ -1,3 +1,14 @@ +ht-el (2.2-1) unstable; urgency=medium + + * New upstream version 2.2 + * d/control: Declare Standards-Version 4.1.1 (no changes needed) + * d/control: Clean dependencies (remove dash-el and emacsen-common) + * d/control: Remove emacs24 from Enchances field + * d/control: Remove Built-Using field + * d/control: Capitalize Emacs Lisp properly in description + + -- Lev Lamberov Wed, 15 Nov 2017 13:23:18 +0500 + ht-el (2.1-1) unstable; urgency=medium * Initial release (Closes: #854824) diff -Nru ht-el-2.1/debian/control ht-el-2.2/debian/control --- ht-el-2.1/debian/control 2017-02-10 18:58:25.000000000 +0000 +++ ht-el-2.2/debian/control 2017-11-15 08:23:18.000000000 +0000 @@ -6,7 +6,7 @@ Build-Depends: debhelper (>= 10), dh-elpa, dash-el -Standards-Version: 3.9.8 +Standards-Version: 4.1.1 Testsuite: autopkgtest-pkg-elpa Homepage: https://github.com/Wilfred/ht.el Vcs-Browser: https://anonscm.debian.org/cgit/pkg-emacsen/pkg/ht-el.git/ @@ -15,14 +15,10 @@ Package: elpa-ht Architecture: all Depends: ${elpa:Depends}, - ${misc:Depends}, - dash-el, - emacsen-common (>= 2.0.8) + ${misc:Depends} Recommends: emacs (>= 46.0) Enhances: emacs, - emacs24, emacs25 -Built-Using: ${misc:Built-Using} Description: hash table library for Emacs The missing hash table library for Emacs. Libraries like `s.el' (strings) and `dash.el' (lists) have shown how much nicer Emacs Lisp @@ -30,7 +26,7 @@ simplify working with hash tables. . Common operations with hash tables (e.g. enumerate the keys) are too - difficult in Emacs lisp. + difficult in Emacs Lisp. . `ht.el' offers: . diff -Nru ht-el-2.1/.gitignore ht-el-2.2/.gitignore --- ht-el-2.1/.gitignore 2016-08-07 00:52:15.000000000 +0000 +++ ht-el-2.2/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -*.elc -/.cask diff -Nru ht-el-2.1/ht.el ht-el-2.2/ht.el --- ht-el-2.1/ht.el 2016-08-07 00:52:15.000000000 +0000 +++ ht-el-2.2/ht.el 2017-11-12 22:05:35.000000000 +0000 @@ -3,7 +3,7 @@ ;; Copyright (C) 2013 Wilfred Hughes ;; Author: Wilfred Hughes -;; Version: 2.1 +;; Version: 2.2 ;; Keywords: hash table, hash map, hash ;; Package-Requires: ((dash "2.12.0")) @@ -22,9 +22,9 @@ ;;; Commentary: -;; The missing hash table utility library for Emacs. +;; The missing hash table library for Emacs. ;; -;; See documentation on https://github.com/Wilfred/ht.el +;; See documentation at https://github.com/Wilfred/ht.el ;;; Code: @@ -44,7 +44,7 @@ ,@assignments ,table-symbol))) -(defun ht-create (&optional test) +(defsubst ht-create (&optional test) "Create an empty hash table. TEST indicates the function used to compare the hash @@ -68,30 +68,6 @@ (defalias 'ht-from-alist 'ht<-alist) -;; based on the excellent -partition from dash.el, but we aim to be self-contained -(defun ht/group-pairs (list) - "Return a new list with the items in LIST grouped into pairs. -Errors if LIST doesn't contain an even number of elements." - (let ((result) - (sublist) - (len 0)) - - (while list - ;; take the head of LIST and push onto SUBLIST - (setq sublist (cons (car list) sublist)) - (setq list (cdr list)) - - (setq len (1+ len)) - - (when (= len 2) - ;; push this two-item list onto RESULT - (setq result (cons (nreverse sublist) result)) - (setq sublist nil) - (setq len 0))) - - (when sublist (error "Expected an even number of elements")) - (nreverse result))) - (defun ht<-plist (plist &optional test) "Create a hash table with initial values according to PLIST. @@ -99,19 +75,27 @@ keys. Default is `equal'. It can be `eq', `eql', `equal' or a user-supplied test created via `define-hash-table-test'." (let ((h (ht-create test))) - (dolist (pair (ht/group-pairs plist) h) + (dolist (pair (-partition 2 plist) h) (let ((key (car pair)) (value (cadr pair))) (ht-set! h key value))))) (defalias 'ht-from-plist 'ht<-plist) -(defun ht-get (table key &optional default) +(defsubst ht-get (table key &optional default) "Look up KEY in TABLE, and return the matching value. If KEY isn't present, return DEFAULT (nil if not specified)." (gethash key table default)) -(defun ht-set! (table key value) +(defun ht-get* (table &rest keys) + "Look up KEYS in nested hash tables, starting with TABLE. +The lookup for each key should return another hash table, except +for the final key, which may return any value." + (if (cdr keys) + (apply #'ht-get* (ht-get table (car keys)) (cdr keys)) + (ht-get table (car keys)))) + +(defsubst ht-set! (table key value) "Associate KEY in TABLE with VALUE." (puthash key value table) nil) @@ -135,13 +119,13 @@ (mapc (lambda (table) (ht-update! merged table)) tables) merged)) -(defun ht-remove! (table key) +(defsubst ht-remove! (table key) "Remove KEY from TABLE." (remhash key table)) (defalias 'ht-remove 'ht-remove!) -(defun ht-clear! (table) +(defsubst ht-clear! (table) "Remove all keys from TABLE." (clrhash table) nil) @@ -186,6 +170,14 @@ variables key and value bound." `(ht-each (lambda (key value) ,form) ,table)) +(defun ht-select-keys (table keys) + "Return a copy of TABLE with only the specified KEYS." + (let (result) + (setq result (make-hash-table :test (hash-table-test table))) + (dolist (key keys result) + (if (not (equal (gethash key table 'key-not-found) 'key-not-found)) + (puthash key (gethash key table) result))))) + (defun ht->plist (table) "Return a flat list '(key1 value1 key2 value2...) from TABLE. @@ -199,7 +191,7 @@ (defalias 'ht-to-plist 'ht->plist) -(defun ht-copy (table) +(defsubst ht-copy (table) "Return a shallow copy of TABLE (keys and values are shared)." (copy-hash-table table)) @@ -226,11 +218,11 @@ (defalias 'ht-contains-p 'ht-contains?) -(defun ht-size (table) +(defsubst ht-size (table) "Return the actual number of entries in TABLE." (hash-table-count table)) -(defun ht-empty? (table) +(defsubst ht-empty? (table) "Return true if the actual number of entries in TABLE is zero." (zerop (ht-size table))) diff -Nru ht-el-2.1/README.md ht-el-2.2/README.md --- ht-el-2.1/README.md 2016-08-07 00:52:15.000000000 +0000 +++ ht-el-2.2/README.md 2017-11-12 22:05:35.000000000 +0000 @@ -40,10 +40,12 @@ * `ht-copy` `(table)` * `ht-select` `(function table)` * `ht-reject` `(function table)` +* `ht-select-keys` `(table keys)` ### Accessing the hash table * `ht-get` `(table key default?)` +* `ht-get*` `(table &rest keys)` * `ht-keys` `(table)` * `ht-values` `(table)` * `ht-items` `(table)` @@ -95,22 +97,40 @@ Creating a hash table and accessing it: - (require 'ht) +``` emacs-lisp +(require 'ht) - (defun say-hello (name) - (let ((greetings (ht ("Bob" "Hey bob!") - ("Chris" "Hi Chris!")))) - (ht-get greetings name "Hello stranger!"))) +(defun say-hello (name) + (let ((greetings (ht ("Bob" "Hey bob!") + ("Chris" "Hi Chris!")))) + (ht-get greetings name "Hello stranger!"))) +``` This could be alternatively written as: - (require 'ht) +``` emacs-lisp +(require 'ht) - (defun say-hello (name) - (let ((greetings (ht-create))) - (ht-set! greetings "Bob" "Hey Bob!") - (ht-set! greetings "Chris" "Hi Chris!") - (ht-get greetings name "Hello stranger!"))) +(defun say-hello (name) + (let ((greetings (ht-create))) + (ht-set! greetings "Bob" "Hey Bob!") + (ht-set! greetings "Chris" "Hi Chris!") + (ht-get greetings name "Hello stranger!"))) +``` + +Accessing nested hash tables: + +``` emacs-lisp +(let ((alphabets (ht ("Greek" (ht (1 (ht ('letter "α") + ('name "alpha"))) + (2 (ht ('letter "β") + ('name "beta"))))) + ("English" (ht (1 (ht ('letter "a") + ('name "A"))) + (2 (ht ('letter "b") + ('name "B")))))))) + (ht-get* alphabets "Greek" 1 'letter)) ; => "α" +``` ## Why? @@ -139,15 +159,17 @@ ## Installation -ht.el is available on [MELPA](https://melpa.org/) and +ht.el is available on [MELPA](https://melpa.org/) (recommended) and [Marmalade](http://marmalade-repo.org/). -Add a package archive to your .emacs.d/init.el: +Add MELPA to your .emacs.d/init.el: - (require 'package) - (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) - -then run `M-x package-install ht ` +``` emacs-lisp +(require 'package) +(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) +``` + +then run `M-x package-install ht `. ## Changelog diff -Nru ht-el-2.1/test/ht-test.el ht-el-2.2/test/ht-test.el --- ht-el-2.1/test/ht-test.el 2016-08-07 00:52:15.000000000 +0000 +++ ht-el-2.2/test/ht-test.el 2017-11-12 22:05:35.000000000 +0000 @@ -19,6 +19,22 @@ (let ((test-table (ht-create))) (should (equal (ht-get test-table "foo" "default") "default")))) +(ert-deftest ht-test-get* () + (let ((alphabets (ht ("Greek" (ht (1 (ht ('letter "α") + ('name "alpha"))) + (2 (ht ('letter "β") + ('name "beta"))))) + ("English" (ht (1 (ht ('letter "a") + ('name "A"))) + (2 (ht ('letter "b") + ('name "B")))))))) + ;; Nested + (should (equal (ht-get* alphabets "English" 1 'letter) + "a")) + ;; Non-nested + (should (equal (ht-get* (ht (1 "one")) 1) + "one")))) + (ert-deftest ht-test-update () (let ((test-table (ht ("foo" 1)))) (ht-update test-table (ht ("bar" 2))) @@ -119,6 +135,21 @@ (ht ("foo" 1) ("bar" 2))) nil)))) +(ert-deftest ht-test-select-keys-empty () + "ht-select-keys should return an empty table if the keys list is empty" + (let ((table (ht (:foo 1) (:bar 3)))) + (should (ht-empty? (ht-select-keys table '()))))) + +(ert-deftest ht-test-select-keys () + "size of returned table should be the same as the keys list" + (let ((table (ht (:foo 1) (:bar 3)))) + (should (equal (ht-size (ht-select-keys table '(:foo :bar))) 2)))) + +(ert-deftest ht-test-select-keys-not-found () + "if the key is not found, it doesn't occur in the returned table" + (let ((table (ht (:foo 1) (:bar 3)))) + (should (equal (ht-size (ht-select-keys table '(:foo :baz))) 1)))) + (ert-deftest ht-test-from-alist () (let* ((alist '(("key1" . "value1"))) (test-table (ht-from-alist alist)))