Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 20 additions & 10 deletions src/dk/ative/docjure/spreadsheet.clj
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,34 @@
(defmethod read-cell-value Cell/CELL_TYPE_ERROR [^CellValue cv _]
(keyword (.name (FormulaError/forInt (.getErrorValue cv)))))

(defmulti read-cell #(when % (.getCellType ^Cell %)))
(defmethod read-cell Cell/CELL_TYPE_BLANK [_] nil)
(defmethod read-cell nil [_] nil)
(defmethod read-cell Cell/CELL_TYPE_STRING [^Cell cell] (.getStringCellValue cell))
(defmethod read-cell Cell/CELL_TYPE_FORMULA [^Cell cell]
(let [evaluator (.. cell getSheet getWorkbook
getCreationHelper createFormulaEvaluator)
(defmulti configure-evaluator (fn [_ k _] k))
(defmethod configure-evaluator :ignore-missing-workbooks? [evaluator _ value]
(.setIgnoreMissingWorkbooks evaluator value)
evaluator)
(defmethod configure-evaluator :default [evaluator _ _]
;; probably should log or error so people know they've got a typo or something
evaluator)

(defmulti read-cell (fn [cell _] (when cell (.getCellType ^Cell cell))))
(defmethod read-cell Cell/CELL_TYPE_BLANK [_ _] nil)
(defmethod read-cell nil [_ _] nil)
(defmethod read-cell Cell/CELL_TYPE_STRING [^Cell cell _] (.getStringCellValue cell))
(defmethod read-cell Cell/CELL_TYPE_FORMULA [^Cell cell options]
(let [evaluator (reduce (fn [evaluator [k v]] (configure-evaluator evaluator k v))
(.. cell getSheet getWorkbook
getCreationHelper createFormulaEvaluator)
(:evaluator options))
cv (.evaluate evaluator cell)]
(if (and (= Cell/CELL_TYPE_NUMERIC (.getCellType cv))
(DateUtil/isCellDateFormatted cell))
(.getDateCellValue cell)
(read-cell-value cv false))))
(defmethod read-cell Cell/CELL_TYPE_BOOLEAN [^Cell cell] (.getBooleanCellValue cell))
(defmethod read-cell Cell/CELL_TYPE_NUMERIC [^Cell cell]
(defmethod read-cell Cell/CELL_TYPE_BOOLEAN [^Cell cell _] (.getBooleanCellValue cell))
(defmethod read-cell Cell/CELL_TYPE_NUMERIC [^Cell cell _]
(if (DateUtil/isCellDateFormatted cell)
(.getDateCellValue cell)
(.getNumericCellValue cell)))
(defmethod read-cell Cell/CELL_TYPE_ERROR [^Cell cell]
(defmethod read-cell Cell/CELL_TYPE_ERROR [^Cell cell _]
(keyword (.name (FormulaError/forInt (.getErrorCellValue cell)))))


Expand Down
63 changes: 63 additions & 0 deletions src/dk/ative/docjure/spreadsheet/v2.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
(ns dk.ative.docjure.spreadsheet.v2
(:require [dk.ative.docjure.spreadsheet :as spreadsheet])
(:import (org.apache.poi.ss.usermodel Workbook Sheet Cell Row)))

(defprotocol Context
(select-sheet [context predicate])
(select-cell [context ref])
(read-cell [context])

(sheet-seq [context])
(row-seq [context])
(cell-seq [context])

(add-style! [context style])

(set-cell-style! [context])
(set-row-styles! [context]))

(defrecord POIContext [^Workbook workbook ^Sheet sheet ^Row row ^Cell cell styles options]
Context
(select-sheet [context predicate]
(assert (instance? Workbook workbook) "We need a workbook to be able to select a sheet")
(assoc context :sheet (spreadsheet/select-sheet predicate workbook)))
(select-cell [context ref]
(assert (instance? Sheet sheet) "We require a sheet to be able to select a cell, please use select-sheet")
(assoc context :cell (spreadsheet/select-cell ref sheet)))
(read-cell [_]
(assert (instance? Cell cell) "Please select a cell using select-cell")
(spreadsheet/read-cell cell options))

(sheet-seq [context]
(assert (instance? Workbook workbook) "We need a workbook to be able to select a sheet")
(map #(assoc context :sheet %) (spreadsheet/sheet-seq workbook)))
(row-seq [context]
(assert (instance? Sheet sheet) "")
(map #(assoc context :row %) (spreadsheet/row-seq sheet)))
(cell-seq [context]
(assert (or (instance? Sheet sheet)
(instance? Row row)) "")
(map #(assoc context :cell %) (spreadsheet/cell-seq (or row sheet))))

(add-style! [context style]
(assert (instance? Workbook workbook) "We need a workbook to be able to select a sheet")
(update context :styles #(conj (or % []) (spreadsheet/create-cell-style! workbook style))))

(set-cell-style! [context]
(assert (instance? Cell cell) "Please select a cell using select-cell")
(spreadsheet/set-cell-style! cell (first styles)))
(set-row-styles! [context]
(assert (instance? Row row) "")
(spreadsheet/set-row-styles! row styles)))

(defn load-workbook [input & [options]]
(map->POIContext {:workbook (spreadsheet/load-workbook input)
:options (or options {})}))

(defn create-workbook [sheet-name data & [options]]
(map->POIContext {:workbook (spreadsheet/create-workbook sheet-name data)
:options (or options {})}))

(defmacro with-styles [context styles & body]
`(let [~context (reduce add-style! ~context ~styles)]
~@body))
44 changes: 44 additions & 0 deletions test/dk/ative/docjure/spreadsheet/v2_test.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
(ns dk.ative.docjure.spreadsheet.v2-test
(:require [clojure.test :refer :all]
[dk.ative.docjure.spreadsheet.v2 :refer :all])
(:import (org.apache.poi.ss.usermodel IndexedColors)))

(def config {:simple "test/dk/ative/docjure/testdata/simple.xlsx"
:missing-workbook "test/dk/ative/docjure/testdata/missing-workbook.xlsx"})

(deftest load-and-read-simple
(let [workbook (load-workbook (:simple config))
sheet (first (sheet-seq workbook))]
(is (= 1.0 (read-cell (select-cell sheet "A2"))))))

(deftest missing-workbooks-causes-explosions
(let [workbook (load-workbook (:missing-workbook config))
sheet (first (sheet-seq workbook))]
(is (thrown? java.lang.RuntimeException
(read-cell (select-cell sheet "A1"))))))

(deftest ignore-missing-workbooks-uses-cached-value
(let [workbook (load-workbook (:missing-workbook config)
{:evaluator {:ignore-missing-workbooks? true}})
sheet (first (sheet-seq workbook))]
(is (= 6.0 (read-cell (select-cell sheet "A1"))))))

(deftest formatting-cells
(let [workbook (load-workbook (:simple config))
sheet (first (sheet-seq workbook))]
(with-styles sheet [{:background :yellow}]
(let [cell (select-cell sheet "A1")]
(set-cell-style! cell)
(is (= (.getIndex IndexedColors/YELLOW) (.. (:cell cell) getCellStyle getFillForegroundColor)))))))

(deftest formatting-rows
(let [workbook (create-workbook "Dummy" [["foo" "bar"] ["data b" "data b"]])
[header-row data-row] (row-seq (select-sheet workbook "Dummy"))
[a1 b1] (cell-seq header-row)
[a2 b2] (cell-seq data-row)]
(with-styles header-row [{:background :yellow} {:background :red}]
(set-row-styles! header-row))
(is (= (.getIndex IndexedColors/YELLOW) (.. (:cell a1) getCellStyle getFillForegroundColor)))
(is (= (.getIndex IndexedColors/RED) (.. (:cell b1) getCellStyle getFillForegroundColor)))
(is (not= (.getIndex IndexedColors/YELLOW) (.. (:cell a2) getCellStyle getFillForegroundColor)))
(is (not= (.getIndex IndexedColors/RED) (.. (:cell b2) getCellStyle getFillForegroundColor)))))
2 changes: 1 addition & 1 deletion test/dk/ative/docjure/spreadsheet_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@
(let [wb (create-xls-workbook "Dummy" [["foo"]])
cs (create-cell-style! wb {:border-left :thin
:border-right :medium
:border-top :thick
:border-top :thick
:border-bottom :thin
:left-border-color :red
:right-border-color :blue
Expand Down
Binary file not shown.