Class: FormatParser::JSONParser::Validator

Inherits:
Object
  • Object
show all
Defined in:
lib/parsers/json_parser/validator.rb

Overview

This class checks whether a given file is a valid JSON file. The validation process DOES NOT assemble an object with the contents of the JSON file in memory, Instead, it implements a simple state-machine-like that digests the contents of the file while traversing the hierarchy of nodes in the document.

Although this is based on the IETF standard (www.rfc-editor.org/rfc/rfc8259), it does cut a few corners for the sake of simplicity. For instance, instead of validating Numbers, “true”, “false” and “null” tokens, it supports a type called Literal to hold generic sequences of characters. This decision makes the implementation simpler while being a good-enough approach to identify JSON files.

There is also a cap. Large files are not read all the way through. Instead, if the beginning of file is JSON-compliant, it is assumed that the file is a JSON file.

Defined Under Namespace

Classes: JSONParserError

Constant Summary collapse

MAX_SAMPLE_SIZE =
1024
MAX_LITERAL_SIZE =

much larger then necessary.

30
ESCAPE_CHAR =
"\\"
WHITESPACE_CHARS =
[" ", "\t", "\n", "\r"]
ENDING_VALUE_CHARS =
[",", "]", "}"]
LITERALS_CHAR_TEMPLATE =

any alphanumeric, “+”, “-” and “.”

/\w|[+\-.]/

Instance Method Summary collapse

Constructor Details

#initialize(io) ⇒ Validator

Returns a new instance of Validator.



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/parsers/json_parser/validator.rb', line 26

def initialize(io)
  @io = io
  @current_node = nil # :object, :array, :string, :literal
  @parent_nodes = []
  @current_state = :awaiting_root_node
  @escape_next = false
  @current_literal_size = 0
  @pos = 0

  @all_parsers = {}

  @execution_stats = {
    array: 0,
    object: 0,
    literal: 0,
    string: 0
  }

  setup_transitions
end

Instance Method Details

#stats(node_type) ⇒ Object



68
69
70
# File 'lib/parsers/json_parser/validator.rb', line 68

def stats(node_type)
  @execution_stats[node_type]
end

#validateObject



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/parsers/json_parser/validator.rb', line 47

def validate
  char_reader = FormatParser::UTF8Reader.new(@io)

  while (c = char_reader.read_char)
    @pos += 1
    parse_char c

    # Halt validation if the sampling limit is reached.
    if @pos >= MAX_SAMPLE_SIZE
      raise JSONParserError, "Invalid JSON file" if @current_state == :awaiting_root_node
      return false
    end
  end

  # Raising error in case the EOF is reached earlier than expected
  raise JSONParserError, "Incomplete JSON file" if @current_state != :closed
  true
rescue  FormatParser::UTF8Reader::UTF8CharReaderError
  raise JSONParserError, "Invalid UTF-8 character"
end