Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
clojure.specの話(仮)
Search
OHTA Shogo
July 21, 2016
2
350
clojure.specの話(仮)
OHTA Shogo
July 21, 2016
Tweet
Share
More Decks by OHTA Shogo
See All by OHTA Shogo
テンクーでのClojure活用事例
athos
0
320
軽量デバッグツールPostmortemの紹介.pdf
athos
1
200
Clojure 1.10 概要紹介
athos
3
630
やってみる!clojure.spec
athos
4
1k
kitchen-async: a promising (?) Promise library, or a poor man's core.async
athos
3
460
Clojure 1.9 概要紹介
athos
4
1.4k
ここ最近のClojureScript
athos
5
1.7k
(= ? (+ nREPL Docker))
athos
0
520
clojure.specの話
athos
3
2.3k
Featured
See All Featured
Reflections from 52 weeks, 52 projects
jeffersonlam
349
20k
Docker and Python
trallard
44
3.3k
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3.1k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
104
19k
Embracing the Ebb and Flow
colly
85
4.6k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
356
30k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
53k
The Power of CSS Pseudo Elements
geoffreycrofte
75
5.7k
Rails Girls Zürich Keynote
gr2m
94
13k
jQuery: Nuts, Bolts and Bling
dougneiner
63
7.7k
Typedesign – Prime Four
hannesfritz
41
2.6k
A Modern Web Designer's Workflow
chriscoyier
693
190k
Transcript
DMPKVSFTQFDͷ Ծ OJTIJTIJOKVDMPKVSF !BUIPT
ࣗݾհ ‣ 5XJUUFS!BUIPT ‣ χϟϯύεגࣜձࣾॴଐ ‣ $MPKVSFίϯτϦϏϡʔλ
ૣͰ͕͢
$MPKVSFͷҰ൪ ϜΧͭ͘ͱ͜Ζͬͯʁ
Τϥʔϝοηʔδ ࠾༻ εΫϦϓτΛ࡞Δ͠͞ υΩϡϝϯτɾνϡʔτϦΞϧ ੩తܕ͕ͳ͍ $MPKVSFTVSWFZʮ$MPKVSFͷҰ൪ϜΧͭ͘ͱ͜Ζʁʯ
Τϥʔϝοηʔδ
‣ $MPKVSFͷΤϥʔͷ͔Γʹ͘͞Α͘ࢦఠ͞ΕΔ ‣ $MPKVSFͷࠐΈؔͷଟ͘ΨʔϕδΠϯΨʔϕδ Ξτ ‣ ҾνΣοΫΛೖΕΔͱɺ+*5ίϯύΠϥͷ࠷దԽΛ ્͠ɺύϑΥʔϚϯεʹӨڹ͢ΔͨΊ
Կ͕ωοΫ͔ʁ ‣ ύϑΥʔϚϯε໘͔Βߟ͑Δͱ࣮ߦ࣌ͷνΣοΫ ۃྗආ͚͍ͨ ‣ ͔͠͠ɺ੩తܕ͕ͳ͍Ҏ্ίϯύΠϧ͚࣌ͩͰνΣο Ϋ͖͠Δͷ͍͠ ‣ ։ൃ͚࣌ͩΦϯʹͰ͖ΔҾνΣοΫͷΈ͕͋ Ε͍͍
DMPKVSFTQFD
DMPKVSFTQFD ‣ ࣍ظϦϦʔε$MPKVSFͰͷಋೖ͕ਐΊΒΕ͍ͯΔ৽ػೳ ‣ ੩తܕͰͳ͘ɺड़ޠͷΈ߹ΘͤʹΑͬͯσʔλܕͷ༷ Λهड़͢Δ ‣ Ұ༷ εϖοΫ Λॻ͚ҰཻͰԿ͓͍͍͠
υΩϡϝϯςʔγϣϯ ܖϓϩάϥϛϯά ϓϩύςΟϕʔεςετ ϚΫϩͷߏจνΣοΫ
DMPKVSFTQFDͷ͍ํ ‣ [org.clojure/clojure “1.9.0-alphaXX”] Λ:dependenciesʹՃ ‣ ࠷৽൛BMQIB ݱࡏ ‣
(require ‘[clojure.spec :as s])
DMPKVSFTQFDೖ
ड़ޠ ‣ ड़ޠ CPPMΛฦؔ͢ ͦͷ··ͰεϖοΫͱͯ͠ ͑Δ user=> (s/valid? integer? 42)
true user=> (s/valid? integer? “foo”) false
WBMJE FYQMBJO ‣ WBMJE εϖοΫΛຬ͔ͨ͢Ͳ͏͔Λฦ͢ ‣ FYQMBJOεϖοΫΛຬͨ͞ͳ͍ՕॴΛࢦఠ͢Δ user=> (s/valid? integer?
“foo”) false user=> (s/explain integer? “foo”) val: "foo" fails predicate: :clojure.spec/unknown nil user=> (s/explain integer? 42) Success! nil
εϖοΫͷ߹ ‣ BOEPSΛͬͯෳͷεϖοΫΛΈ߹ΘͤՄೳ user=> (s/valid? (s/and integer? even?) 0) true
user=> (s/valid? (s/and integer? even?) 1) false user=> (s/valid? (s/or :int integer? :str string?) “foo”) true
εϖοΫʹ໊લΛ͚ͭΔ ‣ EFGͰεϖοΫʹ໊લΛ͚ͭΔ͜ͱ͕Ͱ͖Δ ‣ εϖοΫࣗମΛ࠶ར༻Ͱ͖Δ user=> (s/def ::answer-to-everything (fn [x]
(= x 42)) :user/answer-to-everything user=> (s/valid? ::answer-to-everything 43) false user=> (s/valid? ::answer-to-everything 42) true
ίϨΫγϣϯͷεϖοΫ ‣ coll-ofmap-ofͰίϨΫγϣϯͷཁૉ͕εϖοΫ Λຬ͍ͨͯ͠Δ͔νΣοΫͰ͖Δ user=> (s/valid? (s/coll-of integer?) [1 2
3]) true user=> (s/valid? (s/coll-of integer?) [1 :a]) false user=> (s/valid? (s/map-of keyword? integer?) {:a 0, :b 1}) true user=> (s/valid? (s/map-of keyword? integer?) {:a 0, :b “foo”}) false
ίϨΫγϣϯͷεϖοΫ ‣ ΩʔʹΑͬͯͷܕ͕ҧ͏ϚοϓͷεϖοΫఆٛՄೳ user=> (s/def ::x integer?) :user/x user=> (s/def
::y string?) :user/y user=> (s/explain (s/keys :req-un [::x ::y]) {:x 1, :y 2}) In: [:y] val: 2 fails spec: :user/y at: [:y] predicate: string? nil user=> (s/valid? (s/keys :req-un [::x ::y]) {:x 1, :y “foo”}) true
DMPKVSFTQFDʹΑΔ ܖϓϩάϥϛϯά
ܖϓϩάϥϛϯάͱ ‣ ؔͷݺͼग़͠ʹؔͯ͠ɺࣄલ݅ɾࣄޙ݅ɾෆ ม݅ΛܾΊɺݺͼग़͢ଆͱݺͼग़͞ΕΔଆͷٛ Λ໌֬ʹ͢Δख๏ ݺͼग़͢ଆɿ ؔΛݺͼग़͢લʹࣄલ݅ͱෆม݅Λຬͨٛ͢Λෛ͏ ݺͼग़͞Εͨଆɿ
͔ؔΒͬͨޙʹࣄޙ݅ͱෆม݅Λຬͨٛ͢Λෛ͏
ؔʹର͢ΔεϖοΫ ‣ fizzbuzzؔͷεϖοΫ্ͷΑ͏ʹఆٛͰ͖Δ ‣ :args :ret͕ͦΕͧΕࣄલ݅ɾࣄޙ݅ʹରԠ (s/fdef fizzbuzz :args (s/cat
:n (s/and integer? #(> % 0))) :ret (s/or :int integer? :key keyword?)) (defn fizzbuzz [n] (cond (= (mod n 15) 0) :fizzbuzz (= (mod n 5) 0) :buzz (= (mod n 3) 0) “fizz” ;;←όά :else n))
JOTUSVNFOU ‣ ؔʹҾ͕εϖοΫΛຬ͍ͨͯ͠Δ͔ͷνΣοΫ ΛΦϯɾΦϑͰ͖Δ user=> (require ‘[clojure.spec.test :as t]) nil
user=> (t/instrument) [user/fizzbuzz] user=> (fizzbuzz 15) “fizzbuzz” user=> (fizzbuzz “foo”) ExceptionInfo Call to #'user/fizzbuzz did not conform to spec: In: [0] val: "foo" fails at: [:args :n] predicate: integer? :clojure.spec/args ("foo") … user=>
DIFDL ‣ ҾͷεϖοΫΛຬͨ͢Λࣗಈੜͯ͠ɺͦͷΛؔʹ ͨ݁͠Ռ͕ΓͷεϖοΫΛຬ͔ͨ͢νΣοΫ͢Δ user=> (t/check) ({:spec … :clojure.spec.test.check/ret {:result
#error {:cause "Specification-based check failed” :data {:clojure.spec/problems (… {:path [:ret :key], :pred keyword?, :val “fizz", :via [], :in [], :clojure.spec.test/args (3), :clojure.spec/failure :check-failed}…)} user=>
DIFDL ‣ ҾͷεϖοΫΛຬͨ͢Λࣗಈੜͯ͠ɺͦͷΛؔʹ ͨ݁͠Ռ͕ΓͷεϖοΫΛຬ͔ͨ͢νΣοΫ͢Δ user=> (t/check) ({:spec … :clojure.spec.test.check/ret {:result
#error {:cause "Specification-based check failed” :data {:clojure.spec/problems (… {:path [:ret :key], :pred keyword?, :val “fizz", :via [], :in [], :clojure.spec.test/args (3), :clojure.spec/failure :check-failed}…)} user=> Ͱݺͼग़ͨ͠ͱ͖ʹ ࣦഊ͢Δ͜ͱΛݕग़
DMPKVSFTQFDʹΑΔ ϓϩύςΟϕʔεςετ
ϓϩύςΟϕʔεςετͱ ‣ ී௨ͷςετ FYBNQMFCBTFEUFTUJOH ͷΑ͏ʹɺ ۩ମతͳςετέʔεʹର͢ΔςετͰͳ͘ɺ ҙͷೖྗʹରͯ͠Γཱͭੑ࣭Λهड़ͨ͠ςετ ‣ ೖྗͷϥϯμϜʹͨ͘͞Μੜ͠ɺͦͷʹର͠ ͯςετΛ࣮ߦ͢Δ
‣ )BTLFMMͷ2VJDL$IFDL͕༗໊ ‣ $MPKVSFͰUFTUDIFDLΛ͏ͷ͕ελϯμʔυ
p[[CV[[ؔͷςετ ‣ εϖοΫΛຬͨ͢Λࣗಈੜ͠ɺͯ͢ͷʹର ͯ͠ੑ࣭͕Γཱ͔ͭͲ͏͔νΣοΫ͢Δ (ns fizzbuzz-test (:require [clojure.test.check.clojure-test :refer [defspec]]
[clojure.test.check.properties :as prop] [clojure.spec :as s] [fizzbuzz :as fb])) (defspec fizzbuzz-prop (prop/for-all [n (s/gen (s/and integer? #(> % 0)))] (let [v (fb/fizzbuzz n)] (cond (= (mod n 3) 0) (contains? #{:fizz :fizzbuzz} v) (= (mod n 5) 0) (contains? #{:buzz :fizzbuzz} v) :else (= n v)))))
·ͱΊ ‣ DMPKVSFTQFDσʔλܕؔͷ༷Λड़ޠͷΈ ߹ΘͤͰهड़͢Δํ๏Λఏڙ͢Δ ‣ ҰεϖοΫΛॻ͘ͱɺίʔσΟϯάத͚ͩͰͳ͘ɺ υΩϡϝϯςʔγϣϯςετʹཱͯΒΕΔ ‣ $MPKVSFͷࠐΈؔʹର͢ΔεϖοΫ͕༻ҙ͞Ε ΕΤϥʔϝοηʔδվળ͞ΕΔ͔ʁ
ࠓ͞ͳ͔ͬͨ͜ͱ ‣ TDPOGPSN ‣ γʔέϯεʹର͢ΔεϖοΫ ‣ εϖοΫʹΑΔϚΫϩͷߏจղੳ ଓ͖ͷ-JTQNFFUVQͰʂʂ