When I’m writing about or in Ruby 📖 code, sometimes I want to grab the qualified method name. For example, let’s say I have the following Ruby code:
module Hello module World def foo :bar end def self.call :yup end end end
The qualified method name for the method
#foo would be
Hello::World#foo. The qualified method name for the singleton method
A Ruby documentation convention is that instance methods are prefix with a
# and singleton methods are prefixed with a
treesit-explore-mode, I was able to quickly refine my recursive queries. Below is treesit’s rendering of the Abstract Syntax Tree (AST 📖) of the above Ruby code:
(program (module module name: (constant) (body_statement (module module name: (constant) (body_statement (method def body: (identifier) (body_statement (simple_symbol)) end) (singleton_method def object: (self) . body: (identifier) (body_statement (simple_symbol)) end)) body: end)) body: end))
, in a moment of dreary skies and sleeping dogs, I hacked together the following functions:
- Copy the qualified method name to the paste buffer (e.g. the
- Recurse up from a node to create a list of the module/class ancestors.
(require 'treesit) (cl-defun jf/treesit/qualified_method_name (&key (type "method")) "Get the fully qualified name of method at point." (interactive) (if-let ((func (treesit-defun-at-point))) ;; Instance method or class method? (let* ((method_type (if (string= type (treesit-node-type func)) "#" ".")) (method_name (treesit-node-text (car (treesit-filter-child func (lambda (node) (string= "identifier" (treesit-node-type node))))))) (module_space (s-join "::" (-flatten (jf/treesit/module_space func)))) (qualified_name (concat module_space method_type method_name))) (message qualified_name) (kill-new (substring-no-properties qualified_name))) (user-error "No %s at point." type))) ;; An ugly bit of code to recurse upwards from the node to the "oldest" ;; parent. And collect all module/class nodes along the way. This will ;; return a series of nested lists. It's on the originating caller to ;; flatten that list. (defun jf/treesit/module_space (node) (when-let* ((parent (treesit-parent-until node (lambda (n) (member (treesit-node-type n) '("class" "module"))))) (parent_name (treesit-node-text (car (treesit-filter-child parent (lambda (n) (string= "constant" (treesit-node-type n)))))))) (list (jf/treesit/module_space parent) parent_name)))
This is most certainly a rainy day kind of project; one that helped me learn just a bit more about the
The list returned by
'(nil ("Hello" ("World"))); which is a ugly but workable. Perhaps someone will write to me with a refactor of this code.