class CF::UAA::ScimFilter

Public Class Methods

new(filter_string) click to toggle source
# File lib/uaa/stub/scim.rb, line 474
def initialize(filter_string)
  if filter_string.nil?
    @filter = true
  else
    @input = StringScanner.new(filter_string)
    @filter = eat_phrase
    raise BadFilter unless @input.eos?
  end
  self
rescue BadFilter => b
  raise BadFilter, "invalid filter expression at offset #{@input.pos}: #{@input.string}"
end

Public Instance Methods

match?(entry) click to toggle source
# File lib/uaa/stub/scim.rb, line 487
def match?(entry)
  @filter == true || eval(entry, @filter)
end

Private Instance Methods

eat_expr() click to toggle source
# File lib/uaa/stub/scim.rb, line 400
def eat_expr
  if @input.skip(/\s*\(\s*/)
    phrase = eat_phrase
    raise BadFilter unless @input.skip(/\s*\)\s*/)
    return phrase
  end
  raise BadFilter unless (attr = eat_word) &&
      (op = eat_word("eq", "co", "sw", "pr", "gt", "ge", "lt", "le")) &&
      (op == "pr" || value = eat_json_string)
  (attr_sym = StubScim.searchable_attribute(attr)) ?
      [:item, attr_sym, op, value] : [:undefined, attr, op, value]
end
eat_json_string() click to toggle source
# File lib/uaa/stub/scim.rb, line 375
def eat_json_string
  raise BadFilter unless @input.skip(/\s*"/)
  str = ""
  while true
    case
    when @input.scan(/[^\\"]+/); str << @input.matched
    when @input.scan(%r{\\["\\/]}); str << @input.matched[-1]
    when @input.scan(/\\[bfnrt]/); str << eval(%Q{"#{@input.matched}"})
    when @input.scan(/\\u[0-9a-fA-F]{4}/); str << [Integer("0x#{@input.matched[2..-1]}")].pack("U")
    else break
    end
  end
  raise BadFilter unless @input.skip(/"\s*/)
  str
end
eat_phrase() click to toggle source

OR level

# File lib/uaa/stub/scim.rb, line 421
def eat_phrase
  phrase = [:or, eat_subphrase]
  while eat_word("or"); phrase << eat_subphrase end
  phrase.length == 2 ? phrase[1] : phrase
end
eat_subphrase() click to toggle source

AND level

# File lib/uaa/stub/scim.rb, line 414
def eat_subphrase
  phrase = [:and, eat_expr]
  while eat_word("and"); phrase << eat_expr end
  phrase.length == 2 ? phrase[1] : phrase
end
eat_word(*words) click to toggle source
# File lib/uaa/stub/scim.rb, line 391
def eat_word(*words)
  @input.skip(/\s*/)
  return unless s = @input.scan(/(\S+)\s*/)
  w = @input[1].downcase
  return w if words.empty? || words.include?(w)
  @input.unscan
  false
end
eval(entry, filtr) click to toggle source
# File lib/uaa/stub/scim.rb, line 452
def eval(entry, filtr)
  undefd = 0
  case filtr[0]
  when :undefined ; nil
  when :item ; eval_expr(entry, filtr[1], filtr[2], filtr[3])
  when :or
    filtr[1..-1].each { |f|
      return true if (res = eval(entry, f)) == true
      undefd += 1 if res.nil?
    }
    filtr.length == undefd + 1 ? nil: false
  when :and
    filtr[1..-1].each { |f|
      return false if (res = eval(entry, f)) == false
      undefd += 1 if res.nil?
    }
    filtr.length == undefd + 1 ? nil: true
  end
end
eval_expr(entry, attr, op, value) click to toggle source
# File lib/uaa/stub/scim.rb, line 427
def eval_expr(entry, attr, op, value)
  return false unless val = entry[attr]
  return true if op == "pr"
  case attr
  when *StubScim::REFERENCES
    return nil unless op == "eq"
    val.each {|v| return true if v.casecmp(value) == 0 }
    false
  when *StubScim::GENERAL_MULTI
    return nil unless op == "eq"
    val.each {|k, v| return true if v.casecmp(value) == 0 }
    false
  else
    case op
    when "eq"; val.casecmp(value) == 0
    when "sw"; val =~ /^#{Regexp.escape(value)}/i
    when "co"; val =~ /#{Regexp.escape(value)}/i
    when "gt"; val.casecmp(value) > 0
    when "ge"; val.casecmp(value) >= 0
    when "lt"; val.casecmp(value) < 0
    when "le"; val.casecmp(value) <= 0
    end
  end
end