Class: JSON::Schema::Pointer

Inherits:
Object
  • Object
show all
Defined in:
lib/jsi/json-schema-fragments.rb

Overview

a JSON Pointer, as described by RFC 6901 https://tools.ietf.org/html/rfc6901

Defined Under Namespace

Classes: Error, PointerSyntaxError, ReferenceError

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(type, representation) ⇒ Pointer

initializes a JSON::Schema::Pointer from the given representation.

type may be one of:

  • :fragment - the representation is a fragment containing a pointer (starting with #)
  • :pointer - the representation is a pointer (starting with /)
  • :reference_tokens - the representation is an array of tokens referencing a path in a document


67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/jsi/json-schema-fragments.rb', line 67

def initialize(type, representation)
  @type = type
  if type == :reference_tokens
    reference_tokens = representation
  elsif type == :fragment
    reference_tokens = self.class.parse_fragment(representation)
  elsif type == :pointer
    reference_tokens = self.class.parse_pointer(representation)
  else
    raise ArgumentError, "invalid initialization type: #{type.inspect} with representation #{representation.inspect}"
  end
  @reference_tokens = reference_tokens.map(&:freeze).freeze
end

Instance Attribute Details

#reference_tokensObject (readonly)

Returns the value of attribute reference_tokens.



81
82
83
# File 'lib/jsi/json-schema-fragments.rb', line 81

def reference_tokens
  @reference_tokens
end

Class Method Details

.parse_fragment(fragment) ⇒ Object

parse a fragment to an array of reference tokens

/foo/bar

=> ['foo', 'bar']

/foo%20bar

=> ['foo bar']



28
29
30
31
32
33
34
35
36
# File 'lib/jsi/json-schema-fragments.rb', line 28

def self.parse_fragment(fragment)
  fragment = Addressable::URI.unescape(fragment)
  match = fragment.match(/\A#/)
  if match
    parse_pointer(match.post_match)
  else
    raise(PointerSyntaxError, "Invalid fragment syntax in #{fragment.inspect}: fragment must begin with #")
  end
end

.parse_pointer(pointer_string) ⇒ Object

parse a pointer to an array of reference tokens

/foo

=> ['foo']

/foo~0bar/baz~1qux

=> ['foo~bar', 'baz/qux']



47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/jsi/json-schema-fragments.rb', line 47

def self.parse_pointer(pointer_string)
  tokens = pointer_string.split('/', -1).map! do |piece|
    piece.gsub('~1', '/').gsub('~0', '~')
  end
  if tokens[0] == ''
    tokens[1..-1]
  elsif tokens.empty?
    tokens
  else
    raise(PointerSyntaxError, "Invalid pointer syntax in #{pointer_string.inspect}: pointer must begin with /")
  end
end

Instance Method Details

#evaluate(document) ⇒ Object

takes a root json document and evaluates this pointer through the document, returning the value pointed to by this pointer.



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/jsi/json-schema-fragments.rb', line 85

def evaluate(document)
  reference_tokens.inject(document) do |value, token|
    if value.respond_to?(:to_ary)
      if token.is_a?(String) && token =~ /\A\d|[1-9]\d+\z/
        token = token.to_i
      end
      unless token.is_a?(Integer)
        raise(ReferenceError, "Invalid resolution for #{to_s}: #{token.inspect} is not an integer and cannot be resolved in array #{value.inspect}")
      end
      unless (0...(value.respond_to?(:size) ? value : value.to_ary).size).include?(token)
        raise(ReferenceError, "Invalid resolution for #{to_s}: #{token.inspect} is not a valid index of #{value.inspect}")
      end
      (value.respond_to?(:[]) ? value : value.to_ary)[token]
    elsif value.respond_to?(:to_hash)
      unless (value.respond_to?(:key?) ? value : value.to_hash).key?(token)
        raise(ReferenceError, "Invalid resolution for #{to_s}: #{token.inspect} is not a valid key of #{value.inspect}")
      end
      (value.respond_to?(:[]) ? value : value.to_hash)[token]
    else
      raise(ReferenceError, "Invalid resolution for #{to_s}: #{token.inspect} cannot be resolved in #{value.inspect}")
    end
  end
end

#fragmentObject

the fragment string representation of this Pointer



115
116
117
# File 'lib/jsi/json-schema-fragments.rb', line 115

def fragment
  '#' + Addressable::URI.escape(pointer)
end

#pointerObject

the pointer string representation of this Pointer



110
111
112
# File 'lib/jsi/json-schema-fragments.rb', line 110

def pointer
  reference_tokens.map { |t| '/' + t.to_s.gsub('~', '~0').gsub('/', '~1') }.join('')
end

#to_sObject



119
120
121
# File 'lib/jsi/json-schema-fragments.rb', line 119

def to_s
  "#<#{self.class.inspect} #{@type} = #{representation_s}>"
end