Garajeando takes on the Gilded Rose Kata in Clojure

(written by lawrence krubner, however indented passages are often quotes). You can contact lawrence at: lawrence@krubner.com

I dislike this line:

not-conjured-item-name (clojure.string/replace name #”Conjured ” “”)

Seems like calling “update” twice could be done with the opposite of this test:

(if (.contains name “Conjured”)

How to find the name of the unconjured item? I agree that is a tough issue.

For something this short, perhaps it doesn’t matter, but if this was non-trivial software, I would store a “:conjured” key in “items” and match against that. Seems less fragile than matching against a string.

(defn- type-of-item [{name :name}]
  (let [item-types-by-name
        {"Aged Brie" :aged-brie
         "Backstage passes to a TAFKAL80ETC concert" :backstage-pass
         "+5 Dexterity Vest" :regular-item
         "Elixir of the Mongoose" :regular-item}]
    (if (.contains name "Conjured")
      :conjured
      (item-types-by-name name))))

(defmulti update type-of-item)

(defmethod update :conjured [{name :name :as item}]
  (let
    [not-conjured-item-name (clojure.string/replace name #"Conjured " "")
     not-conjured-item      (assoc item :name not-conjured-item-name)]
    (assoc (update (update not-conjured-item))
      :name name)))

(defmethod update :default [item]
  item)

(defmethod update :aged-brie [item]
  (increase-quality item 1))

(defmethod update :backstage-pass [item]
  (cond
    (ten-or-more-days-to-selling-date? item) (increase-quality item 1)

    (between-days-to-selling-date? 5 10 item) (increase-quality item 2)

    (between-days-to-selling-date? 0 5 item) (increase-quality item 3)

    (after-selling-date? item) (set-quality-to-zero item)

    :else item))

(defmethod update :regular-item [item]
  (if (after-selling-date? item)
    (decrease-quality item 2)
    (decrease-quality item 1)))

Notice the change in the update multimethod dispatch function. Now instead of being :name as before, it’s the function type-of-item that returns the dispatch value :conjured if the item is a conjured one (i. e., if its name contains “Conjured”), or the type of item corresponding to each item name otherwise (which it looks up in the item-types-by-name map).

I also added a defmethod for the :conjured dispatch values which decorates update by calling it twice passing the not conjured version of the item and modified the other defmethod functions to use the type of item instead of its name. This made possible a better way of removing the duplication for regular items than the previous update-regular-item-quality private function.

Source