Skip to content

Commit

Permalink
Add validate_as: switch to validation methods.
Browse files Browse the repository at this point in the history
This allows for validating against a particular schema version.

Fixes: #127
  • Loading branch information
hainesr committed Feb 22, 2024
1 parent 0ab5f8b commit e929176
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 22 deletions.
48 changes: 37 additions & 11 deletions lib/cff/file.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

# Copyright (c) 2018-2022 The Ruby Citation File Format Developers.
# Copyright (c) 2018-2024 The Ruby Citation File Format Developers.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -108,31 +108,41 @@ def self.open(file)
end

# :call-seq:
# validate(filename, fail_on_filename: true) -> Array
# validate(filename, validate_as: nil, fail_on_filename: true) -> Array
#
# Read a file and return an array with the result. The result array is a
# three-element array, with `true`/`false` at index 0 to indicate
# pass/fail, an array of schema validation errors at index 1 (if any), and
# `true`/`false` at index 2 to indicate whether the filename passed/failed
# validation.
#
# Setting `validate_as` to a specific version will validate against that
# version of the schema, rather than the version specified in the CFF file.
# If the version specified is not a valid schema version, the version in
# the CFF file, or the default schema version will be used.
#
# You can choose whether filename validation failure should cause overall
# validation failure with the `fail_on_filename` parameter (default: true).
def self.validate(file, fail_on_filename: true)
File.read(file).validate(fail_on_filename: fail_on_filename)
def self.validate(file, validate_as: nil, fail_on_filename: true)
File.read(file).validate(validate_as: validate_as, fail_on_filename: fail_on_filename)
end

# :call-seq:
# validate!(filename, fail_on_filename: true)
# validate!(filename, validate_as: nil, fail_on_filename: true)
#
# Read a file and raise a ValidationError upon failure. If an error is
# raised it will contain the detected validation failures for further
# inspection.
#
# Setting `validate_as` to a specific version will validate against that
# version of the schema, rather than the version specified in the CFF file.
# If the version specified is not a valid schema version, the version in
# the CFF file, or the default schema version will be used.
#
# You can choose whether filename validation failure should cause overall
# validation failure with the `fail_on_filename` parameter (default: true).
def self.validate!(file, fail_on_filename: true)
File.read(file).validate!(fail_on_filename: fail_on_filename)
def self.validate!(file, validate_as: nil, fail_on_filename: true)
File.read(file).validate!(validate_as: validate_as, fail_on_filename: fail_on_filename)
end

# :call-seq:
Expand All @@ -158,11 +168,19 @@ def self.write(file, cff, comment = '')
# `true`/`false` at index 2 to indicate whether the filename passed/failed
# validation.
#
# Setting `fail_fast` to true will fail validation at the first detected
# failure, rather than gathering and returning all failures.
#
# Setting `validate_as` to a specific version will validate against that
# version of the schema, rather than the version specified in the CFF file.
# If the version specified is not a valid schema version, the version in
# the CFF file, or the default schema version will be used.
#
# You can choose whether filename validation failure should cause overall
# validation failure with the `fail_on_filename` parameter (default: true).
def validate(fail_fast: false, fail_on_filename: true)
def validate(fail_fast: false, validate_as: nil, fail_on_filename: true)
valid_filename = (::File.basename(@filename) == CFF_VALID_FILENAME)
result = (@index.validate(fail_fast: fail_fast) << valid_filename)
result = (@index.validate(fail_fast: fail_fast, validate_as: validate_as) << valid_filename)
result[0] &&= valid_filename if fail_on_filename

result
Expand All @@ -175,11 +193,19 @@ def validate(fail_fast: false, fail_on_filename: true)
# is raised it will contain the detected validation failures for further
# inspection.
#
# Setting `fail_fast` to true will fail validation at the first detected
# failure, rather than gathering and returning all failures.
#
# Setting `validate_as` to a specific version will validate against that
# version of the schema, rather than the version specified in the CFF file.
# If the version specified is not a valid schema version, the version in
# the CFF file, or the default schema version will be used.
#
# You can choose whether filename validation failure should cause overall
# validation failure with the `fail_on_filename` parameter (default: true).
def validate!(fail_fast: false, fail_on_filename: true)
def validate!(fail_fast: false, validate_as: nil, fail_on_filename: true)
result = validate(
fail_fast: fail_fast, fail_on_filename: fail_on_filename
fail_fast: fail_fast, validate_as: validate_as, fail_on_filename: fail_on_filename
)
return if result[0]

Expand Down
35 changes: 25 additions & 10 deletions lib/cff/validatable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,33 +31,48 @@ module Validatable
end.freeze # :nodoc:

# :call-seq:
# validate!(fail_fast: false)
# validate!(fail_fast: false, validate_as: nil)
#
# Validate a CFF file or model (Index) and raise a ValidationError upon
# failure. If an error is raised it will contain the detected validation
# failures for further inspection. Setting `fail_fast` to true will fail
# validation at the first detected failure, rather than gathering and
# returning all failures.
def validate!(fail_fast: false)
result = validate(fail_fast: fail_fast)
# failures for further inspection.
#
# Setting `fail_fast` to true will fail validation at the first detected
# failure, rather than gathering and returning all failures.
#
# Setting `validate_as` to a specific version will validate against that
# version of the schema, rather than the version specified in the CFF file.
# If the version specified is not a valid schema version, the version in
# the CFF file, or the default schema version will be used.
def validate!(fail_fast: false, validate_as: nil)
result = validate(fail_fast: fail_fast, validate_as: validate_as)
return if result[0]

raise ValidationError.new(result[1])
end

# :call-seq:
# validate(fail_fast: false) -> Array
# validate(fail_fast: false, validate_as: nil) -> Array
#
# Validate a CFF file or model (Index) and return an array with the result.
# The result array is a two-element array, with `true`/`false` at index 0
# to indicate pass/fail, and an array of errors at index 1 (if any).
#
# Setting `fail_fast` to true will fail validation at the first detected
# failure, rather than gathering and returning all failures.
def validate(fail_fast: false)
schema = @fields['cff-version']
#
# Setting `validate_as` to a specific version will validate against that
# version of the schema, rather than the version specified in the CFF file.
# If the version specified is not a valid schema version, the version in
# the CFF file, or the default schema version will be used.
def validate(fail_fast: false, validate_as: nil)
schema = Schemas::VERSIONS.include?(validate_as) ? validate_as : @fields['cff-version']
schema = Schemas::DEFAULT_VERSION if schema.nil? || schema.empty?

SCHEMAS[schema].validate(fields(validate: true), fail_fast: fail_fast)
model = fields(validate: true)
model['cff-version'] = schema unless validate_as.nil?

SCHEMAS[schema].validate(model, fail_fast: fail_fast)
end
end
end
28 changes: 27 additions & 1 deletion test/validatable_test.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

# Copyright (c) 2018-2022 The Ruby Citation File Format Developers.
# Copyright (c) 2018-2024 The Ruby Citation File Format Developers.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -180,4 +180,30 @@ def test_valid_filename_validates
assert_empty(result[1])
assert(result[2])
end

def test_validate_model_against_specific_schema_version
cff = ::CFF::Index.read(File.read(SHORT_CFF))

# Validate a 1.2.0 CFF against schema version 1.3.0.
result = cff.validate(validate_as: '1.3.0')
assert(result[0])
assert_empty(result[1])
assert_equal('1.2.0', cff.cff_version) # No change to the model.

cff.validate!(validate_as: '1.3.0')
assert_equal('1.2.0', cff.cff_version) # No change to the model.
end

def test_validate_file_against_specific_schema_version
cff = ::CFF::File.read(SHORT_CFF)

# Validate a 1.2.0 CFF against schema version 1.3.0.
result = cff.validate(validate_as: '1.3.0', fail_on_filename: false)
assert(result[0])
assert_empty(result[1])
assert_equal('1.2.0', cff.cff_version) # No change to the model.

cff.validate!(validate_as: '1.3.0', fail_on_filename: false)
assert_equal('1.2.0', cff.cff_version) # No change to the model.
end
end

0 comments on commit e929176

Please sign in to comment.