Lock in $30 Savings on PRO—Offer Ends Soon! ⏳
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
clojure.specの話(仮)
Search
OHTA Shogo
July 21, 2016
2
330
clojure.specの話(仮)
OHTA Shogo
July 21, 2016
Tweet
Share
More Decks by OHTA Shogo
See All by OHTA Shogo
テンクーでのClojure活用事例
athos
0
280
軽量デバッグツールPostmortemの紹介.pdf
athos
1
190
Clojure 1.10 概要紹介
athos
3
610
やってみる!clojure.spec
athos
4
960
kitchen-async: a promising (?) Promise library, or a poor man's core.async
athos
3
410
Clojure 1.9 概要紹介
athos
4
1.4k
ここ最近のClojureScript
athos
5
1.7k
(= ? (+ nREPL Docker))
athos
0
490
clojure.specの話
athos
3
2.2k
Featured
See All Featured
The Straight Up "How To Draw Better" Workshop
denniskardys
232
140k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
280
13k
Fontdeck: Realign not Redesign
paulrobertlloyd
82
5.3k
StorybookのUI Testing Handbookを読んだ
zakiyama
27
5.3k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
126
18k
What's in a price? How to price your products and services
michaelherold
243
12k
Become a Pro
speakerdeck
PRO
25
5k
Code Reviewing Like a Champion
maltzj
520
39k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
251
21k
Statistics for Hackers
jakevdp
796
220k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
27
4.3k
Designing for humans not robots
tammielis
250
25k
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Ͱʂʂ