Fork me on GitHub
#rewrite-clj
<
2022-11-23
>
Noah Bogart01:11:06

I want to get a seq of every top-level form that starts with a specific token/symbol in a file. Which is to say, I want a seq (lazy or realized) that is every (defcard ...) in my file, and I want to spit it out into a new file with a prepended (in-ns 'game.cards.agendas) form. Is that something rewrite-clj can give me? How is the best way to do it? If I was writing a macro, I'd probably do something like (->> forms (filter #(= 'defcard (first %))) (run! save-to-new-file))

Noah Bogart03:11:33

i figured out a solution, but it's late, so i'll post it in the morning

lread05:11:07

Yeah, I think rewrite-clj is a good choice for this. Looking forward to seeing what you came up with!

jpmonettas13:11:56

not sure if this works 100% of the times but it feels simple, just working at strings level with no parsing :

(->> "(ns ...) (defn ...) (defcard 1) (defn ...) (defcard 2)" ;; replace by (slurp "file.clj")
     (re-seq #"(\(defcard.+?\))")
     (map (fn [[dc-form-str]]
            (str "(in-ns 'game.cards.agendas)\n" dc-form-str "\n")))
     (apply str)
     (println)) ;; replace by (spit "output.clj")

(in-ns 'game.cards.agendas)
(defcard 1)
(in-ns 'game.cards.agendas)
(defcard 2)

Noah Bogart14:11:27

Yeah, I tried doing string parsing, but I ran into issues with incorrect whitespace or similar issues, so seemed better to reach for the correct tool

Noah Bogart14:11:21

This has been edited for clarity:

(loop [zloc (z/of-file (format "src/clj/game/cards/%s.clj" card-type))]
  (when-not (z/end? zloc)
    (let [form (z/next zloc)]
      (when (= 'defcard (z/sexpr form))
        (let [card-name (-> form z/next z/sexpr)
              filename (str (slugify card-name "_") ".clj")]
          (spit (format "src/clj/game/cards/%s/%s" card-type filename)
                (n/string (n/forms-node
                            [(p/parse-string-all (format "(in-ns 'game.cards.%s)"
                                                         card-type))
                             (n/newlines 2)
                             (z/node (z/up form))
                             (n/newlines 1)])))))
      (recur (z/right zloc)))))
Loop over the top-level forms with z/right, get the z/next token and see if it matches 'defcard, then "slugify" the card name (defcard "Day Job" -> "day_job", then create a new "forms" node containing the node (in-ns 'game.cards.X) and the whole defcard node (`(z/node (z/up form))`), plus some newlines and stuff, and spit out out to a file named for the slug

🎉 1
jpmonettas15:11:09

yeah, the regex solution will not work at all now I think a little bit more about it