Share
Embed
Transcript
11 slides
-
"DUJWF3FDPSE 3VCZPO3BJMT ͷόϦσʔγϣϯ class Article < ApplicationRecord validates :title, :body,
presence: true validates :status, inclusion: { in: %w[draft published] } validates :title, length: { maximum: 100 } validates :email, format: { with: URI::MailTo::EMAIL_REGEXP } end > article.valid? #=> true or false -
4XJGU.BDSPTͰ࠶ݱ @Validatable struct Article { var title: String var body:
String var status: Status var email: String? #Validation(\Self.title, \.body, presence: .required) #Validation(\Self.status, inclusion: [.draft, .published]) #Validation(\Self.title, countWithin: ...100) #Validation(\Self.email, format: /^[a-zA-Z0-9._%+-]+@.+\..{2,}$/) } > article.isValid > try article.validate() IUUQTHJUIVCDPNIPLVSPOTXJGUWBMJEBUJPOT IPLVSPOTXJGUWBMJEBUJPOT -
"DUJWF3FDPSE 4XJGU7BMJEBUJPOT validates :title, :body, presence: true #Validation(\Self.title, \.body, presence:
.required) validates :status, inclusion: { in: %w[…] } #Validation(\Self.status, inclusion: […]) validates :title, length: { maximum: 100 } #Validation(\Self.title, countWithin: ...100) validates :email, format: { with: /…/} #Validation(\Self.email, format: /…/) ΠϯλϑΣʔε֓Ͷಉ͡ʹͭͭ͠ɺࡉ͔͍෦4XJGU"QQMFϑϨʔϜϫʔΫͷޠኮΛ༻ɻ -
ܕ҆શੑ "DUJWF3FDPSE validates :age, length: { minimum: 16 } //
⚠ ܻνΣοΫͱͳΓҙਤ͠ͳ͍ݕূ݁ՌʹͳΔɻ͜ͷ߹numericalityݕূΛ͢Δͷ ͕ਖ਼͍͠ɻ 4XJGU7BMJEBUJPOT #Validation(\Self.age, countWithin: 16…) // ❌ Macro 'Validation(_:countWithin:where:)' requires that 'Int' conform to 'Collection' -
4XJGUͳΒͰͷ੍ w ݕূରΛ,FZ1BUIͰࢦఆ͢Δඞཁ͕͋Δ w 'SFFTUBOEJOHNBDSPͳͷͰɺपลͷίϯςΩετΛ֬ೝͰ͖ͳ͍ w Φʔόʔϩʔυ͕૿͕͑ͪ w ੩తܕ͚ͳͷͰɺݕূରͱݕূͷܕͷؔੑ͝ͱʹఆ͕ٛඞཁ w
ઌͷ੍ʢ,FZ1BUIࢦఆʣͷͨΊɺ0QUJPOBM൛ͱඇ0QUJPOBM൛ͷ྆ํͷఆ͕ٛඞཁ w ͜ͷ੍ʹΑΓɺఆ͕ٛ୯७ʹഒʹͳΔ w IUUQTHJUIVCDPNIPLVSPOTXJGUWBMJEBUJPOT4PVSDFT7BMJEBUJPOT.BDSPTTXJGU ޙऀ࣮ଆͷ߹ͳͷͰɺར༻ऀʹӨڹ͕͋ΔͷલऀͱͳΔɻ -
.BDSPͷ࣮ w #ValidationࣗମԿੜ͠ͳ͍ struct ValidationMacro: DeclarationMacro { public static func
expansion(...) throws -> [DeclSyntax] { return [] // ۭྻΛฦ͠ίʔυੜͳ͍ } } w @ValidatableϚΫϩଆϝϯόʔͷ#ValidationͷଘࡏΛ֬ೝ͠ίʔυੜ Λߦ͏ w IUUQTHJUIVCDPNIPLVSPOTXJGUWBMJEBUJPOT4PVSDFT7BMJEBUJPOT.BDSPT7BMJEBUBCMF.BDSPTXJGU -
@Validatable struct User { var name: String var age: UInt
var email: String? var bio: String? var password: String #Validation(\Self.name, presence: .required) #Validation(\Self.age, comparison: .greaterThan(16)) #Validation(\Self.email, format: /…/, presence: .required(allowsNil: true)) #Validation(\Self.bio, presence: .none) #Validation(\Self.password, presence: .required(allowsEmpty: true)) } -
@Validatable struct User { var name: String var age: UInt
var email: String? var bio: String? var password: String #Validation(\Self.name, presence: .required) #Validation(\Self.age, comparison: .greaterThan(16)) #Validation(\Self.email, format: /…/, presence: .required(allowsNil: true)) #Validation(\Self.bio, presence: .none) #Validation(\Self.password, presence: .required(allowsEmpty: true)) } ˣੜίʔυ SFTVMUCVJMEFS extension User: Validations.Validatable { var validation: some Validator { Presence(of: self[keyPath: \Self.name]).presence(.required) .errorKey(Self.self, \Self.name) Comparison(of: self[keyPath: \Self.age], .greaterThan(16)) .errorKey(Self.self, \Self.age) Format(of: self[keyPath: \Self.email], with: /…/).presence(.required(allowsNil: true)) .errorKey(Self.self, \Self.email) Presence(of: self[keyPath: \Self.bio]).presence(.none) .errorKey(Self.self, \Self.bio) Presence(of: self[keyPath: \Self.password]).presence(.required(allowsEmpty: true)) .errorKey(Self.self, \Self.password) } }