lluminary 0.1.4 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/lluminary/models/base.rb +177 -66
- data/lib/lluminary/schema.rb +37 -7
- data/lib/lluminary/schema_model.rb +149 -65
- data/lib/lluminary/task.rb +37 -0
- data/lib/lluminary/tasks/describe_openai_model.rb +61 -0
- data/lib/lluminary/tasks/identify_and_describe_open_ai_models.rb +51 -0
- data/spec/examples/character_profiler_spec.rb +85 -0
- data/spec/lluminary/models/base_spec.rb +933 -100
- data/spec/lluminary/schema_model_spec.rb +259 -0
- data/spec/lluminary/schema_spec.rb +228 -134
- data/spec/lluminary/task_custom_validation_spec.rb +262 -0
- data/spec/spec_helper.rb +3 -0
- metadata +20 -2
@@ -169,4 +169,263 @@ RSpec.describe Lluminary::SchemaModel do
|
|
169
169
|
)
|
170
170
|
end
|
171
171
|
end
|
172
|
+
|
173
|
+
describe "boolean field validation" do
|
174
|
+
let(:fields) do
|
175
|
+
{ active: { type: :boolean, description: "Whether the item is active" } }
|
176
|
+
end
|
177
|
+
let(:model_class) { described_class.build(fields: fields, validations: []) }
|
178
|
+
|
179
|
+
it "accepts true values" do
|
180
|
+
instance = model_class.new(active: true)
|
181
|
+
expect(instance.valid?).to be true
|
182
|
+
expect(instance.errors.full_messages).to be_empty
|
183
|
+
end
|
184
|
+
|
185
|
+
it "accepts false values" do
|
186
|
+
instance = model_class.new(active: false)
|
187
|
+
expect(instance.valid?).to be true
|
188
|
+
expect(instance.errors.full_messages).to be_empty
|
189
|
+
end
|
190
|
+
|
191
|
+
it "accepts nil values" do
|
192
|
+
instance = model_class.new(active: nil)
|
193
|
+
expect(instance.valid?).to be true
|
194
|
+
expect(instance.errors.full_messages).to be_empty
|
195
|
+
end
|
196
|
+
|
197
|
+
it "returns errors for non-boolean values" do
|
198
|
+
instance = model_class.new(active: "true")
|
199
|
+
expect(instance.valid?).to be false
|
200
|
+
expect(instance.errors.full_messages).to contain_exactly(
|
201
|
+
"Active must be true or false"
|
202
|
+
)
|
203
|
+
|
204
|
+
instance = model_class.new(active: 1)
|
205
|
+
expect(instance.valid?).to be false
|
206
|
+
expect(instance.errors.full_messages).to contain_exactly(
|
207
|
+
"Active must be true or false"
|
208
|
+
)
|
209
|
+
end
|
210
|
+
|
211
|
+
it "can be required using presence validation" do
|
212
|
+
validations = [[[:active], { presence: true }]]
|
213
|
+
model_class_with_presence =
|
214
|
+
described_class.build(fields: fields, validations: validations)
|
215
|
+
instance = model_class_with_presence.new(active: nil)
|
216
|
+
expect(instance.valid?).to be false
|
217
|
+
expect(instance.errors.full_messages).to contain_exactly(
|
218
|
+
"Active can't be blank"
|
219
|
+
)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
describe "hash field with array validation" do
|
224
|
+
let(:fields) do
|
225
|
+
{
|
226
|
+
config: {
|
227
|
+
type: :hash,
|
228
|
+
description: "Configuration",
|
229
|
+
fields: {
|
230
|
+
name: {
|
231
|
+
type: :string,
|
232
|
+
description: nil
|
233
|
+
},
|
234
|
+
tags: {
|
235
|
+
type: :array,
|
236
|
+
description: nil,
|
237
|
+
element_type: {
|
238
|
+
type: :string,
|
239
|
+
description: nil
|
240
|
+
}
|
241
|
+
}
|
242
|
+
}
|
243
|
+
}
|
244
|
+
}
|
245
|
+
end
|
246
|
+
let(:model_class) { described_class.build(fields: fields, validations: []) }
|
247
|
+
|
248
|
+
it "validates arrays inside hashes" do
|
249
|
+
instance =
|
250
|
+
model_class.new(
|
251
|
+
config: {
|
252
|
+
name: "test",
|
253
|
+
tags: ["valid", 123, "also valid"]
|
254
|
+
}
|
255
|
+
)
|
256
|
+
expect(instance.valid?).to be false
|
257
|
+
expect(instance.errors.full_messages).to contain_exactly(
|
258
|
+
"Config[tags][1] must be a String"
|
259
|
+
)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
describe "nested hash validation" do
|
264
|
+
let(:fields) do
|
265
|
+
{
|
266
|
+
config: {
|
267
|
+
type: :hash,
|
268
|
+
description: nil,
|
269
|
+
fields: {
|
270
|
+
name: {
|
271
|
+
type: :string,
|
272
|
+
description: nil
|
273
|
+
},
|
274
|
+
database: {
|
275
|
+
type: :hash,
|
276
|
+
description: nil,
|
277
|
+
fields: {
|
278
|
+
host: {
|
279
|
+
type: :string,
|
280
|
+
description: nil
|
281
|
+
},
|
282
|
+
port: {
|
283
|
+
type: :integer,
|
284
|
+
description: nil
|
285
|
+
},
|
286
|
+
credentials: {
|
287
|
+
type: :hash,
|
288
|
+
description: nil,
|
289
|
+
fields: {
|
290
|
+
username: {
|
291
|
+
type: :string,
|
292
|
+
description: nil
|
293
|
+
},
|
294
|
+
password: {
|
295
|
+
type: :string,
|
296
|
+
description: nil
|
297
|
+
}
|
298
|
+
}
|
299
|
+
}
|
300
|
+
}
|
301
|
+
}
|
302
|
+
}
|
303
|
+
}
|
304
|
+
}
|
305
|
+
end
|
306
|
+
let(:model_class) { described_class.build(fields: fields, validations: []) }
|
307
|
+
|
308
|
+
it "validates nested hashes" do
|
309
|
+
instance =
|
310
|
+
model_class.new(
|
311
|
+
config: {
|
312
|
+
name: "test",
|
313
|
+
database: {
|
314
|
+
host: 123, # should be string
|
315
|
+
port: "80", # should be integer
|
316
|
+
credentials: {
|
317
|
+
username: 456, # should be string
|
318
|
+
password: 789 # should be string
|
319
|
+
}
|
320
|
+
}
|
321
|
+
}
|
322
|
+
)
|
323
|
+
expect(instance.valid?).to be false
|
324
|
+
expect(instance.errors.full_messages).to contain_exactly(
|
325
|
+
"Config[database][host] must be a String",
|
326
|
+
"Config[database][port] must be an Integer",
|
327
|
+
"Config[database][credentials][username] must be a String",
|
328
|
+
"Config[database][credentials][password] must be a String"
|
329
|
+
)
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
describe "hash type enforcement" do
|
334
|
+
let(:fields) do
|
335
|
+
{
|
336
|
+
config: {
|
337
|
+
type: :hash,
|
338
|
+
description: nil,
|
339
|
+
fields: {
|
340
|
+
host: {
|
341
|
+
type: :string,
|
342
|
+
description: nil
|
343
|
+
}
|
344
|
+
}
|
345
|
+
}
|
346
|
+
}
|
347
|
+
end
|
348
|
+
let(:model_class) { described_class.build(fields: fields, validations: []) }
|
349
|
+
|
350
|
+
it "validates that value is a hash" do
|
351
|
+
instance = model_class.new(config: "not a hash")
|
352
|
+
expect(instance.valid?).to be false
|
353
|
+
expect(instance.errors.full_messages).to contain_exactly(
|
354
|
+
"Config must be a Hash"
|
355
|
+
)
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
describe "array of hashes validation" do
|
360
|
+
let(:fields) do
|
361
|
+
{
|
362
|
+
users: {
|
363
|
+
type: :array,
|
364
|
+
description: nil,
|
365
|
+
element_type: {
|
366
|
+
type: :hash,
|
367
|
+
description: nil,
|
368
|
+
fields: {
|
369
|
+
name: {
|
370
|
+
type: :string,
|
371
|
+
description: nil
|
372
|
+
},
|
373
|
+
age: {
|
374
|
+
type: :integer,
|
375
|
+
description: nil
|
376
|
+
}
|
377
|
+
}
|
378
|
+
}
|
379
|
+
}
|
380
|
+
}
|
381
|
+
end
|
382
|
+
let(:model_class) { described_class.build(fields: fields, validations: []) }
|
383
|
+
|
384
|
+
it "validates hashes inside arrays" do
|
385
|
+
instance =
|
386
|
+
model_class.new(
|
387
|
+
users: [
|
388
|
+
{ name: "Alice", age: 30 },
|
389
|
+
{ name: 123, age: "invalid" }, # name should be string, age should be integer
|
390
|
+
{ name: "Bob", age: 25 }
|
391
|
+
]
|
392
|
+
)
|
393
|
+
expect(instance.valid?).to be false
|
394
|
+
expect(instance.errors.full_messages).to contain_exactly(
|
395
|
+
"Users[1][name] must be a String",
|
396
|
+
"Users[1][age] must be an Integer"
|
397
|
+
)
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
describe "float field validation" do
|
402
|
+
let(:fields) { { score: { type: :float, description: "The score" } } }
|
403
|
+
let(:model_class) { described_class.build(fields: fields, validations: []) }
|
404
|
+
|
405
|
+
it "accepts float values" do
|
406
|
+
instance = model_class.new(score: 3.14)
|
407
|
+
expect(instance.valid?).to be true
|
408
|
+
expect(instance.errors.full_messages).to be_empty
|
409
|
+
end
|
410
|
+
|
411
|
+
it "accepts nil values" do
|
412
|
+
instance = model_class.new(score: nil)
|
413
|
+
expect(instance.valid?).to be true
|
414
|
+
expect(instance.errors.full_messages).to be_empty
|
415
|
+
end
|
416
|
+
|
417
|
+
it "returns errors for non-float values" do
|
418
|
+
instance = model_class.new(score: "not a float")
|
419
|
+
expect(instance.valid?).to be false
|
420
|
+
expect(instance.errors.full_messages).to contain_exactly(
|
421
|
+
"Score must be a float"
|
422
|
+
)
|
423
|
+
|
424
|
+
instance = model_class.new(score: 42)
|
425
|
+
expect(instance.valid?).to be false
|
426
|
+
expect(instance.errors.full_messages).to contain_exactly(
|
427
|
+
"Score must be a float"
|
428
|
+
)
|
429
|
+
end
|
430
|
+
end
|
172
431
|
end
|
@@ -10,6 +10,58 @@ RSpec.describe Lluminary::Schema do
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
+
describe "#validate" do
|
14
|
+
it "registers a custom validation method" do
|
15
|
+
schema.validate(:validate_something)
|
16
|
+
expect(schema.custom_validations).to eq(
|
17
|
+
[{ method: :validate_something, description: nil }]
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "can register multiple validation methods" do
|
22
|
+
schema.validate(:validate_something)
|
23
|
+
schema.validate(:validate_something_else)
|
24
|
+
expect(schema.custom_validations).to eq(
|
25
|
+
[
|
26
|
+
{ method: :validate_something, description: nil },
|
27
|
+
{ method: :validate_something_else, description: nil }
|
28
|
+
]
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "registers a custom validation method with a description" do
|
33
|
+
schema.validate(
|
34
|
+
:validate_score_range,
|
35
|
+
description: "Score must be between 0 and 100"
|
36
|
+
)
|
37
|
+
expect(schema.custom_validations).to eq(
|
38
|
+
[
|
39
|
+
{
|
40
|
+
method: :validate_score_range,
|
41
|
+
description: "Score must be between 0 and 100"
|
42
|
+
}
|
43
|
+
]
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "registers multiple custom validations with and without descriptions" do
|
48
|
+
schema.validate(
|
49
|
+
:validate_score_range,
|
50
|
+
description: "Score must be between 0 and 100"
|
51
|
+
)
|
52
|
+
schema.validate(:validate_score_parity)
|
53
|
+
expect(schema.custom_validations).to eq(
|
54
|
+
[
|
55
|
+
{
|
56
|
+
method: :validate_score_range,
|
57
|
+
description: "Score must be between 0 and 100"
|
58
|
+
},
|
59
|
+
{ method: :validate_score_parity, description: nil }
|
60
|
+
]
|
61
|
+
)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
13
65
|
describe "#string" do
|
14
66
|
it "adds a string field to the schema" do
|
15
67
|
schema.string(:name)
|
@@ -213,10 +265,154 @@ RSpec.describe Lluminary::Schema do
|
|
213
265
|
)
|
214
266
|
end
|
215
267
|
|
216
|
-
it "
|
217
|
-
schema.array(:
|
218
|
-
|
219
|
-
|
268
|
+
it "supports hashes inside arrays" do
|
269
|
+
schema.array(:users) do
|
270
|
+
hash do
|
271
|
+
string :name
|
272
|
+
integer :age
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
expect(schema.fields[:users]).to eq(
|
277
|
+
{
|
278
|
+
type: :array,
|
279
|
+
description: nil,
|
280
|
+
element_type: {
|
281
|
+
type: :hash,
|
282
|
+
description: nil,
|
283
|
+
fields: {
|
284
|
+
name: {
|
285
|
+
type: :string,
|
286
|
+
description: nil
|
287
|
+
},
|
288
|
+
age: {
|
289
|
+
type: :integer,
|
290
|
+
description: nil
|
291
|
+
}
|
292
|
+
}
|
293
|
+
}
|
294
|
+
}
|
295
|
+
)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
describe "#hash" do
|
300
|
+
it "requires a block for hash fields" do
|
301
|
+
expect { schema.hash(:config) }.to raise_error(
|
302
|
+
ArgumentError,
|
303
|
+
"Hash fields must be defined with a block"
|
304
|
+
)
|
305
|
+
end
|
306
|
+
|
307
|
+
it "adds a hash field with nested fields to the schema" do
|
308
|
+
schema.hash(:config, description: "Configuration") do
|
309
|
+
string :host, description: "The server hostname"
|
310
|
+
integer :port
|
311
|
+
end
|
312
|
+
|
313
|
+
expect(schema.fields).to eq(
|
314
|
+
{
|
315
|
+
config: {
|
316
|
+
type: :hash,
|
317
|
+
description: "Configuration",
|
318
|
+
fields: {
|
319
|
+
host: {
|
320
|
+
type: :string,
|
321
|
+
description: "The server hostname"
|
322
|
+
},
|
323
|
+
port: {
|
324
|
+
type: :integer,
|
325
|
+
description: nil
|
326
|
+
}
|
327
|
+
}
|
328
|
+
}
|
329
|
+
}
|
330
|
+
)
|
331
|
+
end
|
332
|
+
|
333
|
+
it "supports nested hashes" do
|
334
|
+
schema.hash(:config) do
|
335
|
+
string :name
|
336
|
+
hash :database do
|
337
|
+
string :host
|
338
|
+
integer :port
|
339
|
+
hash :credentials do
|
340
|
+
string :username
|
341
|
+
string :password
|
342
|
+
end
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
expect(schema.fields[:config]).to eq(
|
347
|
+
{
|
348
|
+
type: :hash,
|
349
|
+
description: nil,
|
350
|
+
fields: {
|
351
|
+
name: {
|
352
|
+
type: :string,
|
353
|
+
description: nil
|
354
|
+
},
|
355
|
+
database: {
|
356
|
+
type: :hash,
|
357
|
+
description: nil,
|
358
|
+
fields: {
|
359
|
+
host: {
|
360
|
+
type: :string,
|
361
|
+
description: nil
|
362
|
+
},
|
363
|
+
port: {
|
364
|
+
type: :integer,
|
365
|
+
description: nil
|
366
|
+
},
|
367
|
+
credentials: {
|
368
|
+
type: :hash,
|
369
|
+
description: nil,
|
370
|
+
fields: {
|
371
|
+
username: {
|
372
|
+
type: :string,
|
373
|
+
description: nil
|
374
|
+
},
|
375
|
+
password: {
|
376
|
+
type: :string,
|
377
|
+
description: nil
|
378
|
+
}
|
379
|
+
}
|
380
|
+
}
|
381
|
+
}
|
382
|
+
}
|
383
|
+
}
|
384
|
+
}
|
385
|
+
)
|
386
|
+
end
|
387
|
+
|
388
|
+
it "supports arrays inside hashes" do
|
389
|
+
schema.hash(:config) do
|
390
|
+
string :name
|
391
|
+
array :tags do
|
392
|
+
string
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
expect(schema.fields[:config]).to eq(
|
397
|
+
{
|
398
|
+
type: :hash,
|
399
|
+
description: nil,
|
400
|
+
fields: {
|
401
|
+
name: {
|
402
|
+
type: :string,
|
403
|
+
description: nil
|
404
|
+
},
|
405
|
+
tags: {
|
406
|
+
type: :array,
|
407
|
+
description: nil,
|
408
|
+
element_type: {
|
409
|
+
type: :string,
|
410
|
+
description: nil
|
411
|
+
}
|
412
|
+
}
|
413
|
+
}
|
414
|
+
}
|
415
|
+
)
|
220
416
|
end
|
221
417
|
end
|
222
418
|
|
@@ -254,136 +450,6 @@ RSpec.describe Lluminary::Schema do
|
|
254
450
|
second_call = schema.fields
|
255
451
|
expect(first_call).to be(second_call)
|
256
452
|
end
|
257
|
-
|
258
|
-
context "with datetime fields" do
|
259
|
-
let(:schema) { described_class.new.tap { |s| s.datetime(:start_time) } }
|
260
|
-
|
261
|
-
it "accepts DateTime values" do
|
262
|
-
errors = schema.validate(start_time: DateTime.now)
|
263
|
-
expect(errors).to be_empty
|
264
|
-
end
|
265
|
-
|
266
|
-
it "accepts nil values" do
|
267
|
-
errors = schema.validate(start_time: nil)
|
268
|
-
expect(errors).to be_empty
|
269
|
-
end
|
270
|
-
|
271
|
-
it "returns errors for non-DateTime values" do
|
272
|
-
errors = schema.validate(start_time: "2024-01-01")
|
273
|
-
expect(errors).to contain_exactly("Start time must be a DateTime")
|
274
|
-
end
|
275
|
-
|
276
|
-
it "can be required using presence validation" do
|
277
|
-
schema.validates :start_time, presence: true
|
278
|
-
errors = schema.validate(start_time: nil)
|
279
|
-
expect(errors).to contain_exactly("Start time can't be blank")
|
280
|
-
end
|
281
|
-
end
|
282
|
-
end
|
283
|
-
|
284
|
-
describe "#validate" do
|
285
|
-
let(:schema) do
|
286
|
-
described_class.new.tap do |s|
|
287
|
-
s.string(:name)
|
288
|
-
s.integer(:age)
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
it "returns no errors when all values match their field types" do
|
293
|
-
errors = schema.validate(name: "John", age: 30)
|
294
|
-
expect(errors).to be_empty
|
295
|
-
end
|
296
|
-
|
297
|
-
it "returns errors for type mismatches" do
|
298
|
-
errors = schema.validate(name: 123, age: "30")
|
299
|
-
expect(errors).to contain_exactly(
|
300
|
-
"Name must be a String",
|
301
|
-
"Age must be an Integer"
|
302
|
-
)
|
303
|
-
end
|
304
|
-
|
305
|
-
context "with boolean fields" do
|
306
|
-
let(:schema) { described_class.new.tap { |s| s.boolean(:active) } }
|
307
|
-
|
308
|
-
it "accepts true values" do
|
309
|
-
errors = schema.validate(active: true)
|
310
|
-
expect(errors).to be_empty
|
311
|
-
end
|
312
|
-
|
313
|
-
it "accepts false values" do
|
314
|
-
errors = schema.validate(active: false)
|
315
|
-
expect(errors).to be_empty
|
316
|
-
end
|
317
|
-
|
318
|
-
it "accepts nil values" do
|
319
|
-
errors = schema.validate(active: nil)
|
320
|
-
expect(errors).to be_empty
|
321
|
-
end
|
322
|
-
|
323
|
-
it "returns errors for non-boolean values" do
|
324
|
-
errors = schema.validate(active: "true")
|
325
|
-
expect(errors).to contain_exactly("Active must be true or false")
|
326
|
-
|
327
|
-
errors = schema.validate(active: 1)
|
328
|
-
expect(errors).to contain_exactly("Active must be true or false")
|
329
|
-
end
|
330
|
-
|
331
|
-
it "can be required using presence validation" do
|
332
|
-
schema.validates :active, presence: true
|
333
|
-
errors = schema.validate(active: nil)
|
334
|
-
expect(errors).to contain_exactly("Active can't be blank")
|
335
|
-
end
|
336
|
-
end
|
337
|
-
|
338
|
-
context "with string fields" do
|
339
|
-
let(:schema) { described_class.new.tap { |s| s.string(:name) } }
|
340
|
-
|
341
|
-
it "accepts string values" do
|
342
|
-
errors = schema.validate(name: "John")
|
343
|
-
expect(errors).to be_empty
|
344
|
-
end
|
345
|
-
|
346
|
-
it "accepts nil values" do
|
347
|
-
errors = schema.validate(name: nil)
|
348
|
-
expect(errors).to be_empty
|
349
|
-
end
|
350
|
-
|
351
|
-
it "returns errors for non-string values" do
|
352
|
-
errors = schema.validate(name: 123)
|
353
|
-
expect(errors).to contain_exactly("Name must be a String")
|
354
|
-
end
|
355
|
-
|
356
|
-
it "can be required using presence validation" do
|
357
|
-
schema.validates :name, presence: true
|
358
|
-
errors = schema.validate(name: nil)
|
359
|
-
expect(errors).to contain_exactly("Name can't be blank")
|
360
|
-
end
|
361
|
-
end
|
362
|
-
|
363
|
-
context "with integer fields" do
|
364
|
-
let(:schema) { described_class.new.tap { |s| s.integer(:age) } }
|
365
|
-
|
366
|
-
it "accepts integer values" do
|
367
|
-
errors = schema.validate(age: 30)
|
368
|
-
expect(errors).to be_empty
|
369
|
-
end
|
370
|
-
|
371
|
-
it "accepts nil values" do
|
372
|
-
errors = schema.validate(age: nil)
|
373
|
-
expect(errors).to be_empty
|
374
|
-
end
|
375
|
-
|
376
|
-
it "returns errors for non-integer values" do
|
377
|
-
errors = schema.validate(age: "30")
|
378
|
-
expect(errors).to contain_exactly("Age must be an Integer")
|
379
|
-
end
|
380
|
-
|
381
|
-
it "can be required using presence validation" do
|
382
|
-
schema.validates :age, presence: true
|
383
|
-
errors = schema.validate(age: nil)
|
384
|
-
expect(errors).to contain_exactly("Age can't be blank")
|
385
|
-
end
|
386
|
-
end
|
387
453
|
end
|
388
454
|
|
389
455
|
describe "ActiveModel validations" do
|
@@ -433,4 +499,32 @@ RSpec.describe Lluminary::Schema do
|
|
433
499
|
expect(instance.valid?).to be true
|
434
500
|
end
|
435
501
|
end
|
502
|
+
|
503
|
+
describe "custom method validations" do
|
504
|
+
it "passes custom validations to schema model" do
|
505
|
+
schema = described_class.new
|
506
|
+
schema.integer(:score)
|
507
|
+
schema.validate(:validate_score_range)
|
508
|
+
|
509
|
+
model_class = schema.schema_model
|
510
|
+
method_names =
|
511
|
+
model_class.custom_validation_methods.map { |v| v[:method] }
|
512
|
+
expect(method_names).to contain_exactly(:validate_score_range)
|
513
|
+
end
|
514
|
+
|
515
|
+
it "accepts multiple custom validations" do
|
516
|
+
schema = described_class.new
|
517
|
+
schema.integer(:score)
|
518
|
+
schema.validate(:validate_score_range)
|
519
|
+
schema.validate(:validate_score_parity)
|
520
|
+
|
521
|
+
model_class = schema.schema_model
|
522
|
+
method_names =
|
523
|
+
model_class.custom_validation_methods.map { |v| v[:method] }
|
524
|
+
expect(method_names).to contain_exactly(
|
525
|
+
:validate_score_range,
|
526
|
+
:validate_score_parity
|
527
|
+
)
|
528
|
+
end
|
529
|
+
end
|
436
530
|
end
|