Commit 310c6d4

mokha <mokha@cisco.com>
2019-05-21 23:48:27
try an alternative approach to the recursion
1 parent 95ec4f6
Changed files (2)
lib
scim
spec
scim
lib/scim/kit/v2/filter.rb
@@ -11,27 +11,31 @@ module Scim
 
         # FILTER = attrExp / logExp / valuePath / assignVariable / *1"not" "(" FILTER ")"
         rule(:filter) do
-          attribute_expression | logical_expression | value_path | assign_variable | not_op >> lparen >> filter >> rparen
+          logical_expression | filter_atom
+        end
+
+        rule(:filter_atom) do
+          (not_op? >> lparen >> filter >> rparen) | attribute_expression | value_path
         end
 
         # valuePath = attrPath "[" valFilter "]" ; FILTER uses sub-attributes of a parent attrPath
         rule(:value_path) do
-          attribute_path.as(:attribute) >> lbracket >> value_filter >> rbracket
+          attribute_path >> lbracket >> value_filter >> rbracket
         end
 
         # valFilter = attrExp / logExp / *1"not" "(" valFilter ")"
         rule(:value_filter) do
-          attribute_expression | logical_expression | not_op >> lparen >> value_filter >> rparen
+          attribute_expression | logical_expression | not_op? >> lparen >> value_filter >> rparen
         end
 
         # attrExp = (attrPath SP "pr") / (attrPath SP compareOp SP compValue)
         rule(:attribute_expression) do
-          (attribute_path.as(:attribute) >> space >> presence) | attribute_path.as(:attribute) >> space >> comparison_operator.as(:comparison_operator) >> space >> comparison_value.as(:comparison_value)
+          (attribute_path >> space >> presence) | (attribute_path >> space >> comparison_operator.as(:comparison_operator) >> space >> comparison_value.as(:comparison_value))
         end
 
         # logExp = FILTER SP ("and" / "or") SP FILTER
         rule(:logical_expression) do
-          lparen >> filter >> rparen >> space >> (and_op | or_op) >> space >> lparen >> filter >> rparen
+          filter_atom >> space >> (and_op | or_op).as(:logical_operator) >> space >> filter
         end
 
         # compValue = false / null / true / number / string ; rules from JSON (RFC 7159)
@@ -47,7 +51,7 @@ module Scim
 
         # attrPath = [URI ":"] ATTRNAME *1subAttr ; SCIM attribute name ; URI is SCIM "schema" URI
         rule(:attribute_path) do
-          (uri >> colon).repeat(0, 1) >> attribute_name >> sub_attribute.repeat(0, 1)
+          ((uri >> colon).repeat(0, 1) >> attribute_name >> sub_attribute.repeat(0, 1)).as(:attribute)
         end
 
         # ATTRNAME  = ALPHA *(nameChar)
@@ -78,18 +82,13 @@ module Scim
           )
         end
 
-        # assignVariable = ATTRNAME '=' *(NAMECHAR) | STRING
-        rule(:assign_variable) do
-          attribute_name >> space >> assign >> space >> (name_character.repeat(1, nil) | string)
-        end
-
         rule(:presence) { str('pr').as(:presence) }
-        rule(:and_op) { str('and').as(:and) }
-        rule(:or_op) { str('or').as(:or) }
-        rule(:not_op) { str('not').repeat(0, 1).as(:not) }
-        rule(:falsey) { str('false').as(:falsey) }
-        rule(:truthy) { str('true').as(:truthy) }
-        rule(:null) { str('null').as(:null) }
+        rule(:and_op) { str('and') }
+        rule(:or_op) { str('or') }
+        rule(:not_op?) { str('not').repeat(0, 1).as(:not) }
+        rule(:falsey) { str('false') }
+        rule(:truthy) { str('true') }
+        rule(:null) { str('null') }
         rule(:number) do
           str('-').maybe >> (
             str('0') | (match('[1-9]') >> digit.repeat)
spec/scim/kit/v2/filter_spec.rb
@@ -107,9 +107,9 @@ RSpec.describe Scim::Kit::V2::Filter do
   specify { expect(subject.presence).to parse('pr') }
   specify { expect(subject.and_op).to parse('and') }
   specify { expect(subject.or_op).to parse('or') }
-  specify { expect(subject.not_op).to parse('not') }
-  specify { expect(subject.not_op).to parse('') }
-  specify { expect(subject.not_op).not_to parse('not not') }
+  specify { expect(subject.not_op?).to parse('not') }
+  specify { expect(subject.not_op?).to parse('') }
+  specify { expect(subject.not_op?).not_to parse('not not') }
   specify { expect(subject.falsey).to parse('false') }
   specify { expect(subject.truthy).to parse('true') }
   specify { expect(subject.null).to parse('null') }
@@ -125,15 +125,30 @@ RSpec.describe Scim::Kit::V2::Filter do
 
   [
     # '',
-    '(userType eq "Employee") and ((emails co "example.com") or (emails.value co "example.org"))',
+    # %Q(userType ne "Employee" and not (emails co "example.com" or emails.value co "example.org")),
+    # %Q(userType eq "Employee" and emails[type eq "work" and value co "@example.com"]),
+    # %Q(emails[type eq "work" and value co "@example.com"] or ims[type eq "xmpp" and value co "@foo.com"]),
     '(userType ne "Employee") and (not((emails co "example.com") or (emails.value co "example.org")))',
     '(userType eq "Employee") and (emails.type eq "work")',
     '(userType eq "Employee") and (emails[(type eq "work") and (value co "@example.com")])',
     '(emails[(type eq "work") and (value co "@example.com")]) or (ims[(type eq "xmpp") and (value co "@foo.com")])',
     '(title pr) and (userType eq "Employee")',
     '(title pr) or (userType eq "Intern")',
-    '((email eq "hello@example.org") or (name.givenName eq "Tsuyoshi")) or (id = "4CE7E760-F222-4096-90B1-4AC491D12F2E")',
-    'title pr'
+    'title pr',
+    %(userName eq "bjensen"),
+    %(name.familyName co "O'Malley"),
+    %(userName sw "J"),
+    %(urn:ietf:params:scim:schemas:core:2.0:User:userName sw "J"),
+    %(title pr),
+    %(meta.lastModified gt "2011-05-13T04:42:34Z"),
+    %(meta.lastModified ge "2011-05-13T04:42:34Z"),
+    %(meta.lastModified lt "2011-05-13T04:42:34Z"),
+    %(meta.lastModified le "2011-05-13T04:42:34Z"),
+    %(title pr and userType eq "Employee"),
+    %(title pr or userType eq "Intern"),
+    %(schemas eq "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"),
+    %(userType eq "Employee" and (emails co "example.com" or emails.value co "example.org")),
+    %(userType eq "Employee" and (emails.type eq "work"))
   ].each do |x|
     specify { expect(subject).to parse(x) }
   end