User Tools

Site Tools


study:clojure-spec:guides

가이드

spec 라이브러리는 데이타의 구조를 정한다. 그리고 데이타를 검증하고 구조분해하며, 또한 spec에 맞추어서 데이타를 발생한다. clojure.spec 이름공간은 Clojure core 배포판에 포함되어서 추가적인 라이브러리가 필요없다. clojure.spec을 사요하기 위해서는 아래와 같이 최신 버전의 Clojure 의존성을 선언해 주어야 한다.

[org.clojure/clojure "1.9.0-alpha7"]

진위 함수(Predicates)

spec을 사용하기 위해서는 사용자의 이름공간에서 clojure.spec을 요청해 주어야 한다.

(require '[clojure.spec :as s])

각 스펙(spec)은 일단의 허용된 값을 설명한다. 여러가지 방식으로 스펙을 만들 수 있는데, 이들을 조립해서 보다 더 정교하고 복잡한 스펙을 만들 수 있다.

하나의 인수를 받고 진리값을 리턴하는 어떤 기존 클로저 함수도 정당한 진위 스펙 (predicate spec)이다. 어떤 특정 데이타 값이 어떤 스펙을 확언하는지를 conform을 통해 알 수 있다.

(s/conform even? 1000)
;;=> 1000

conform 함수는 스펙이 될 수 있는 무언가와 데이타 값을 인수로 받는다. 여기서 우리는 암묵적으로 스펙으로 바뀌는 진위(predicate)을 전달했다. 반환값은 “conformed”된 것이다. conformed된 값은 원래 값과 같은 값이다 - 나중에는 조금 달라진다. 만약 값이 스펙에 맞지 않으면, :clojure.spec/invalid 라는 특별값이 반환된다.

만약 conformed 값을 사요하지 않고 단지 :clojure.spec/invalid 인지만 검사하고 싶다면, boolean 값을 반환하는 valid? 라는 도우미 함수를 사용할 수 있다.

(s/valid? even? 10)
;;=> true

valid? 또한 내부적으로 진위 함수를 스펙으로 바꾼다. 스펙 라이브러리에서는 기존의 함수들을 모두 사용할 수 있다. 다른 예들을 보자:

(s/valid? nil? nil)  ;; true
(s/valid? string? "abc")  ;; true
(s/valid? #(> % 5) 10) ;; true
(s/valid? #(> % 5) 0) ;; false
(import java.util.Date)
(s/valid? inst? (Date.))  ;; true

특정 리터럴 값이 있는지 확인하기 위해 집합을 사용하는 것도 가능하다.

(s/valid? #{:club :diamond :heart :spade} :club) ;; true
(s/valid? #{:club :diamond :heart :spade} 42) ;; false
(s/valid? #{42} 42) ;; true

등록(Registry)

지금까지, 스펙을 있는 그대로 사용했다. 하지만 스펙을 전역적으로 선언하고 재사용할 수 있도록 중앙 등록소에 등록할 수 있다. 등록소는 이름공간이 붙은 키워드와 스펙을 관련짓는다. 이름 공간을 통해 충돌없이 각종 라이브러리에서 재사용할 수 있다.

스펙 등록은 def를 사용한다. 이름 공간과 의미있는 스펙을 등록해야 한다.

(s/def ::date inst?)
(s/def ::suit #{:club :diamond :heart :spade}) 

등록된 스펙 식별자는 우리가 위에서 보았던 conform과 valid? 함수를 사용한 코드의 스펙 자리에 사용될 수 있다.

(s/valid? ::date (Date.))
;;=> true
(s/conform ::suit :club)
;;=> :club

등록된 스펙들을 조합해서 다른 스펙을 만들 수 있다.

진위 함수 조립하기

스펙을 조립하는 가장 간단한 방식은 and와 or이다. s/and로 진위 함수들을 조립해서 합성 스펙을 만들어 보자.

(s/def ::big-even (s/and int? even? #(> % 1000)))
(s/valid? ::big-even :foo) ;; false
(s/valid? ::big-even 10) ;; false
(s/valid? ::big-even 100000) ;; true

s/or를 사용해서 2개의 진위 함수를 조립할 수 있다.

(s/def ::name-or-id (s/or :name string?
                          :id   int?))
(s/valid? ::name-or-id "abc") ;; true
(s/valid? ::name-or-id 100) ;; true
(s/valid? ::name-or-id :foo) ;; false
study/clojure-spec/guides.txt · Last modified: 2019/02/04 14:26 (external edit)