Created
November 5, 2019 07:57
-
-
Save kawasima/19beeed35775cdf1728fdaf22e264d1d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns bakusatsu | |
(:refer-clojure :exclude [+ -]) | |
(:require [clojure.spec.alpha :as s] | |
[clojure.spec.test.alpha :as stest] | |
[clojure.core :as core])) | |
;; 金額に関する振る舞い(金額同士の加算と減算ができる) | |
(defprotocol IMoney | |
(+ [this money]) | |
(- [this money])) | |
;; 売上金の型定義 | |
(defrecord Proceeds [amount]) | |
;; 契約日時から税率の計算をする | |
(defn apply-rule [contract-date] | |
(cond (.isAfter contract-date (java.time.LocalDateTime/parse "2019-10-01T00:00:00")) (/ 10 100) | |
(.isAfter contract-date (java.time.LocalDateTime/parse "2014-04-01T00:00:00")) (/ 8 100) | |
(.isAfter contract-date (java.time.LocalDateTime/parse "1997-04-01T00:00:00")) (/ 5 100) | |
(.isAfter contract-date (java.time.LocalDateTime/parse "1989-04-01T00:00:00")) (/ 3 100) | |
:else 0)) | |
;; 売上金額に金額のプロトコルを実装する | |
(extend-protocol IMoney | |
Proceeds | |
(+ [this money] | |
(->Proceeds (core/+ (:amount this) (:amount money)))) | |
(- [this money] | |
(->Proceeds (core/- (:amount this) (:amount money))))) | |
;; 消費税込金額を計算する | |
(defn sales-tax [proceeds contract-date] | |
(let [rate (apply-rule contract-date)] | |
(->Proceeds (int (* (:amount proceeds) (core/+ 1 rate)))))) | |
;;; Specの定義 | |
(s/def ::amount pos-int?) | |
(s/def ::money #(satisfies? IMoney %)) | |
(s/def ::proceeds (s/keys :req-un [::amount])) | |
(s/def ::tax-rate ratio?) | |
(s/fdef ->Proceeds | |
:args (s/cat :amount ::amount) | |
:ret ::proceeds) | |
(s/def ::contract-date #(instance? java.time.LocalDateTime %)) | |
(s/fdef + | |
:args (s/cat :this ::money :money ::money) | |
:ret ::money) | |
(s/fdef - | |
:args (s/cat :this ::money :money ::money) | |
:ret ::money) | |
(s/fdef apply-rule | |
:args (s/cat :contract-date ::contract-date) | |
:ret ::tax-rate) | |
(s/fdef sales-tax | |
:args (s/cat :proceeds ::proceeds :contact-date ::contract-date) | |
:ret ::proceeds) | |
(stest/instrument [`->Proceeds `apply-rule `sales-tax `+ `-]) | |
;;; 動かしてみる | |
(+ (->Proceeds 10) (->Proceeds 20)) ;; #Proceeds{:amount 30} | |
(+ (->Proceeds 10) 20) ;; 2つめの引数がIMoneyじゃないのでSpecエラー | |
(- (->Proceeds 10) 20) ;; 2つめの引数がIMoneyじゃないのでSpecエラー | |
(sales-tax (->Proceeds 100) (java.time.LocalDateTime/parse "2018-01-02T00:00:00")) ;; #Proceeds{:amount 108} | |
(sales-tax 100 (java.time.LocalDateTime/parse "2018-01-02T00:00:00")) ;; 1つめの引数がProceedsじゃないのでSpecエラー |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment