class Hana::Patch

Public Class Methods

new(is) click to toggle source
# File lib/hana.rb, line 88
def initialize is
  @is = is
end

Public Instance Methods

apply(doc) click to toggle source
# File lib/hana.rb, line 94
def apply doc
  @is.inject(doc) { |d, ins|
    send VALID.fetch(ins['op'].strip) { |k|
      raise Exception, "bad method `#{k}`"
    }, ins, d
  }
end

Private Instance Methods

add(ins, doc) click to toggle source
# File lib/hana.rb, line 107
def add ins, doc
  path = get_path ins
  list = Pointer.parse path
  key  = list.pop
  dest = Pointer.eval list, doc
  obj  = ins.fetch VALUE

  raise(MissingTargetException, "target location '#{ins['path']}' does not exist") unless dest

  if key
    add_op dest, key, obj
  else
    if doc.equal? dest
      doc = obj
    else
      dest.replace obj
    end
  end
  doc
end
add_op(dest, key, obj) click to toggle source
# File lib/hana.rb, line 223
def add_op dest, key, obj
  if Array === dest
    dest.insert check_index(dest, key), obj
  else
    raise Patch::InvalidObjectOperationException, "cannot add key '#{key}' to non-object" unless Hash === dest
    dest[key] = obj
  end
end
check_index(obj, key) click to toggle source
# File lib/hana.rb, line 214
def check_index obj, key
  return -1 if key == '-'

  raise ObjectOperationOnArrayException, "cannot apply non-numeric key '#{key}' to array" unless key =~ /\A-?\d+\Z/
  idx = key.to_i
  raise OutOfBoundsException, "key '#{key}' is out of bounds for array" if idx > obj.length || idx < 0
  idx
end
copy(ins, doc) click to toggle source
# File lib/hana.rb, line 144
def copy ins, doc
  path = get_path ins
  from     = Pointer.parse ins.fetch FROM
  to       = Pointer.parse path
  from_key = from.pop
  key      = to.pop
  src      = Pointer.eval from, doc
  dest     = Pointer.eval to, doc

  if Array === src
    raise Patch::ObjectOperationOnArrayException, "cannot apply non-numeric key '#{key}' to array" unless from_key =~ /\A\d+\Z/
    obj = src.fetch from_key.to_i
  else
    begin
      obj = src.fetch from_key
    rescue KeyError, NoMethodError
      raise Hana::Patch::MissingTargetException, "'from' location '#{ins.fetch FROM}' does not exist"
    end
  end

  raise(MissingTargetException, "target location '#{ins['path']}' does not exist") unless dest

  add_op dest, key, obj
  doc
end
get_path(ins) click to toggle source
# File lib/hana.rb, line 202
def get_path ins
  unless ins.key?('path')
    raise Hana::Patch::InvalidPath, "missing 'path' parameter"
  end

  unless ins['path']
    raise Hana::Patch::InvalidPath, "null is not valid value for 'path'"
  end

  ins['path']
end
move(ins, doc) click to toggle source
# File lib/hana.rb, line 128
def move ins, doc
  path = get_path ins
  from     = Pointer.parse ins.fetch FROM
  to       = Pointer.parse path
  from_key = from.pop
  key      = to.pop
  src      = Pointer.eval from, doc
  dest     = Pointer.eval to, doc

  raise(MissingTargetException, "target location '#{ins['path']}' does not exist") unless dest

  obj = rm_op src, from_key
  add_op dest, key, obj
  doc
end
remove(ins, doc) click to toggle source
# File lib/hana.rb, line 193
def remove ins, doc
  path = get_path ins
  list = Pointer.parse path
  key  = list.pop
  obj  = Pointer.eval list, doc
  rm_op obj, key
  doc
end
replace(ins, doc) click to toggle source
# File lib/hana.rb, line 180
def replace ins, doc
  path = get_path ins
  list = Pointer.parse path
  key  = list.pop
  obj  = Pointer.eval list, doc

  return ins.fetch VALUE unless key

  rm_op obj, key
  add_op obj, key, ins.fetch(VALUE)
  doc
end
rm_op(obj, key) click to toggle source
# File lib/hana.rb, line 232
def rm_op obj, key
  if Array === obj
    raise Patch::ObjectOperationOnArrayException, "cannot apply non-numeric key '#{key}' to array" unless key =~ /\A\d+\Z/
    key = key.to_i
    raise Patch::OutOfBoundsException, "key '#{key}' is out of bounds for array" if key >= obj.length
    obj.delete_at key
  else
    begin
      raise Patch::MissingTargetException, "key '#{key}' not found" unless obj&.key? key
      obj.delete key
    rescue ::NoMethodError
      raise Patch::InvalidObjectOperationException, "cannot remove key '#{key}' from non-object"
    end
  end
end
test(ins, doc) click to toggle source
# File lib/hana.rb, line 170
def test ins, doc
  path = get_path ins
  expected = Pointer.new(path).eval doc

  unless expected == ins.fetch(VALUE)
    raise FailedTestException.new(ins['path'], ins[VALUE])
  end
  doc
end