Module: Natsuzora::Validator
- Defined in:
- lib/natsuzora/validator.rb
Overview
Centralized validation functions for Natsuzora templates
Class Method Summary collapse
-
.validate_data!(data) ⇒ Object
Validate that runtime data conforms to Natsuzora’s value type system.
-
.validate_identifier!(name, line: nil, column: nil) ⇒ Object
Validate an identifier (variable name, each binding, include argument key).
-
.validate_include_name_runtime!(name) ⇒ Object
Validate an include name at load time.
-
.validate_include_name_syntax!(name, line: nil, column: nil) ⇒ Object
Validate an include name at parse time.
Class Method Details
.validate_data!(data) ⇒ Object
Validate that runtime data conforms to Natsuzora’s value type system.
Error message:
-
Float NaN / Infinity → “Invalid number: …”
-
Other (non-whole) Float → “Floating point numbers are not supported: …”
-
Integer out of safe range → “Integer out of range: …”
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/natsuzora/validator.rb', line 55 def validate_data!(data) case data when Hash data.each_value { |v| validate_data!(v) } when Array data.each { |v| validate_data!(v) } when Integer return if data.between?(Value::INTEGER_MIN, Value::INTEGER_MAX) raise Natsuzora::TypeError, "Integer out of range: #{data}" when Float raise Natsuzora::TypeError, "Invalid number: #{data}" unless data.finite? raise Natsuzora::TypeError, "Floating point numbers are not supported: #{data}" end end |
.validate_identifier!(name, line: nil, column: nil) ⇒ Object
Validate an identifier (variable name, each binding, include argument key)
Rules:
-
Cannot be a reserved word (if, unless, each, as, unsecure, true, false, null, include)
-
Cannot start with ‘_’ (reserved for internal use)
-
Cannot contain ‘@’ (reserved for future use)
13 14 15 16 17 18 19 20 21 |
# File 'lib/natsuzora/validator.rb', line 13 def validate_identifier!(name, line: nil, column: nil) raise ReservedWordError.new("'#{name}' is a reserved word", line: line, column: column) if Token::RESERVED_WORDS.include?(name) raise ParseError.new("Identifier cannot start with '_': #{name}", line: line, column: column) if name.start_with?('_') return unless name.include?('@') raise ParseError.new("Identifier cannot contain '@': #{name}", line: line, column: column) end |
.validate_include_name_runtime!(name) ⇒ Object
Validate an include name at load time
Defense in depth: re-check basic rules even though lexer enforces them
40 41 42 43 44 45 46 47 |
# File 'lib/natsuzora/validator.rb', line 40 def validate_include_name_runtime!(name) raise IncludeError, "Include name must start with '/': #{name}" unless name.start_with?('/') # These should be impossible with the new lexer, but check anyway return unless name.include?('..') || name.include?('//') || name.include?('\\') || name.include?(':') raise IncludeError, "Invalid include name: #{name}" end |
.validate_include_name_syntax!(name, line: nil, column: nil) ⇒ Object
Validate an include name at parse time
Lexer ensures each segment follows Identifier rules (starts with letter). This validates additional constraints:
-
Must start with ‘/’
-
Must have at least one segment after ‘/’
29 30 31 32 33 34 35 |
# File 'lib/natsuzora/validator.rb', line 29 def validate_include_name_syntax!(name, line: nil, column: nil) raise ParseError.new("Include name must start with '/'", line: line, column: column) unless name.start_with?('/') return unless name == '/' raise ParseError.new('Include name must have at least one segment', line: line, column: column) end |