scim-query-filter-parser 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gemspec +1 -1
- data/lib/scim/query/filter/parser.rb +16 -8
- data/test/case.rb +32 -0
- data/test/spec.rb +76 -0
- metadata +4 -3
- data/test/parse.rb +0 -82
data/.gemspec
CHANGED
@@ -42,11 +42,19 @@ class SCIM::Query::Filter::Parser
|
|
42
42
|
|
43
43
|
def parse_expr
|
44
44
|
ast = []
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
45
|
+
until eos or peek == ')'
|
46
|
+
assert_not_op
|
47
|
+
ast.push(start_group ? parse_group : pop.downcase)
|
48
|
+
break if (eos or peek == ')')
|
49
|
+
assert_op
|
50
|
+
ast.push pop.downcase
|
51
|
+
if !Unary[ast.last]
|
52
|
+
assert_not_op
|
53
|
+
ast.push(start_group ? parse_group : pop)
|
54
|
+
end
|
55
|
+
break if eos or peek == ')'
|
56
|
+
assert_op
|
57
|
+
ast.push pop.downcase
|
50
58
|
end
|
51
59
|
to_rpn ast
|
52
60
|
end
|
@@ -77,10 +85,10 @@ class SCIM::Query::Filter::Parser
|
|
77
85
|
out.push ast.shift if not ast.empty?
|
78
86
|
while not ast.empty? do
|
79
87
|
op = ast.shift
|
80
|
-
|
88
|
+
precedence = Ops[op] \
|
81
89
|
or fail "Unknown operator '#{op}'"
|
82
90
|
while not ops.empty? do
|
83
|
-
break if
|
91
|
+
break if precedence > Ops[ops.first]
|
84
92
|
out.push ops.shift
|
85
93
|
end
|
86
94
|
ops.unshift op
|
@@ -114,7 +122,7 @@ class SCIM::Query::Filter::Parser
|
|
114
122
|
def eos; @tokens.empty? end
|
115
123
|
def start_group; peek == '(' end
|
116
124
|
def peek_operator
|
117
|
-
not(eos) and peek.match IsOperator
|
125
|
+
not(eos) and peek.downcase.match IsOperator
|
118
126
|
end
|
119
127
|
|
120
128
|
|
data/test/case.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'scim/query/filter/parser'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'yaml'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
class TestCase < Test::Unit::TestCase
|
7
|
+
def test_case
|
8
|
+
data = YAML.load $test_case_data
|
9
|
+
parser = SCIM::Query::Filter::Parser.new
|
10
|
+
data.each do |test_case|
|
11
|
+
query = test_case['query']
|
12
|
+
parser.parse query
|
13
|
+
|
14
|
+
got_rpn_json = parser.rpn.to_json
|
15
|
+
want_rpn_json = test_case['rpn'].to_json
|
16
|
+
assert_equal want_rpn_json, got_rpn_json,
|
17
|
+
"Test parse to RPN: '#{query}'"
|
18
|
+
|
19
|
+
got_tree_json = parser.tree.to_json
|
20
|
+
want_tree_json = test_case['tree'].to_json
|
21
|
+
assert_equal want_tree_json, got_tree_json,
|
22
|
+
"Test parse to tree: '#{query}'"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# See http://www.simplecloud.info/specs/draft-scim-api-01.html#query-resources
|
28
|
+
$test_case_data = <<'...'
|
29
|
+
- query: USERName eQ "Ingy döt Net"
|
30
|
+
rpn: [username,'"Ingy döt Net"',eq]
|
31
|
+
tree: [eq, username,'"Ingy döt Net"']
|
32
|
+
...
|
data/test/spec.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'scim/query/filter/parser'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'yaml'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
class TestSpec < Test::Unit::TestCase
|
7
|
+
def test_spec
|
8
|
+
data = YAML.load $test_spec_data
|
9
|
+
parser = SCIM::Query::Filter::Parser.new
|
10
|
+
data.each do |test_case|
|
11
|
+
query = test_case['query']
|
12
|
+
parser.parse query
|
13
|
+
|
14
|
+
got_rpn_json = parser.rpn.to_json
|
15
|
+
want_rpn_json = test_case['rpn'].to_json
|
16
|
+
assert_equal want_rpn_json, got_rpn_json,
|
17
|
+
"Test parse to RPN: '#{query}'"
|
18
|
+
|
19
|
+
got_tree_json = parser.tree.to_json
|
20
|
+
want_tree_json = test_case['tree'].to_json
|
21
|
+
assert_equal want_tree_json, got_tree_json,
|
22
|
+
"Test parse to tree: '#{query}'"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# See http://www.simplecloud.info/specs/draft-scim-api-01.html#query-resources
|
28
|
+
$test_spec_data = <<'...'
|
29
|
+
- query: ''
|
30
|
+
rpn: []
|
31
|
+
tree: []
|
32
|
+
|
33
|
+
- query: userName eq "bjensen"
|
34
|
+
rpn: [username,'"bjensen"',eq]
|
35
|
+
tree: [eq, username,'"bjensen"']
|
36
|
+
|
37
|
+
- query: name.familyName co "O'Malley"
|
38
|
+
rpn: [name.familyname, '"O''Malley"', co]
|
39
|
+
tree: [co, name.familyname, '"O''Malley"']
|
40
|
+
|
41
|
+
- query: userName sw "J"
|
42
|
+
rpn: [username, '"J"', sw]
|
43
|
+
tree: [sw, username, '"J"']
|
44
|
+
|
45
|
+
- query: title pr
|
46
|
+
rpn: [title, pr]
|
47
|
+
tree: [pr, title]
|
48
|
+
|
49
|
+
- query: meta.lastModified gt "2011-05-13T04:42:34Z"
|
50
|
+
rpn: [meta.lastmodified, '"2011-05-13T04:42:34Z"', gt]
|
51
|
+
tree: [gt, meta.lastmodified, '"2011-05-13T04:42:34Z"']
|
52
|
+
|
53
|
+
- query: meta.lastModified ge "2011-05-13T04:42:34Z"
|
54
|
+
rpn: [meta.lastmodified, '"2011-05-13T04:42:34Z"', ge]
|
55
|
+
tree: [ge, meta.lastmodified, '"2011-05-13T04:42:34Z"']
|
56
|
+
|
57
|
+
- query: meta.lastModified lt "2011-05-13T04:42:34Z"
|
58
|
+
rpn: [meta.lastmodified, '"2011-05-13T04:42:34Z"', lt]
|
59
|
+
tree: [lt, meta.lastmodified, '"2011-05-13T04:42:34Z"']
|
60
|
+
|
61
|
+
- query: meta.lastModified le "2011-05-13T04:42:34Z"
|
62
|
+
rpn: [meta.lastmodified, '"2011-05-13T04:42:34Z"', le]
|
63
|
+
tree: [le, meta.lastmodified, '"2011-05-13T04:42:34Z"']
|
64
|
+
|
65
|
+
- query: title pr and userType eq "Employee"
|
66
|
+
rpn: [title, pr, usertype, '"Employee"', eq, and]
|
67
|
+
tree: [and, [pr, title], [eq, usertype, '"Employee"']]
|
68
|
+
|
69
|
+
- query: title pr or userType eq "Intern"
|
70
|
+
rpn: [title, pr, usertype, '"Intern"', eq, or]
|
71
|
+
tree: [or, [pr, title], [eq, usertype, '"Intern"']]
|
72
|
+
|
73
|
+
- query: userType eq "Employee" and (emails co "example.com" or emails co "example.org")
|
74
|
+
rpn: [usertype, '"Employee"', eq, emails, '"example.com"', co, emails, '"example.org"', co, or ,and]
|
75
|
+
tree: [and, [eq, usertype, '"Employee"'], [or, [co, emails, '"example.com"'], [co, emails, '"example.org"']]]
|
76
|
+
...
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scim-query-filter-parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-09-
|
12
|
+
date: 2013-09-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -45,7 +45,8 @@ files:
|
|
45
45
|
- README.rdoc
|
46
46
|
- Rakefile
|
47
47
|
- lib/scim/query/filter/parser.rb
|
48
|
-
- test/
|
48
|
+
- test/case.rb
|
49
|
+
- test/spec.rb
|
49
50
|
homepage: https://github.com/ingydotnet/scim-query-filter-parser-rb
|
50
51
|
licenses:
|
51
52
|
- MIT
|
data/test/parse.rb
DELETED
@@ -1,82 +0,0 @@
|
|
1
|
-
require 'scim/query/filter/parser'
|
2
|
-
require 'test/unit'
|
3
|
-
require 'yaml'
|
4
|
-
require 'json'
|
5
|
-
|
6
|
-
class TestParser < Test::Unit::TestCase
|
7
|
-
def test_spec
|
8
|
-
data = $test_parse_data.lines.to_a
|
9
|
-
parser = SCIM::Query::Filter::Parser.new
|
10
|
-
while true do
|
11
|
-
input = data.shift or break
|
12
|
-
input.chomp!
|
13
|
-
rpn_yaml = data.shift or break
|
14
|
-
next if rpn_yaml == "\n"
|
15
|
-
parser.parse(input)
|
16
|
-
got_rpn_json = parser.rpn.to_json
|
17
|
-
want_rpn_json = YAML.load(rpn_yaml).to_json
|
18
|
-
assert_equal want_rpn_json, got_rpn_json,
|
19
|
-
"Test parse to RPN: '#{input.chomp}'"
|
20
|
-
tree_yaml = data.shift or break
|
21
|
-
next if tree_yaml == "\n"
|
22
|
-
got_tree_json = parser.tree.to_json
|
23
|
-
want_tree_json = YAML.load(tree_yaml).to_json
|
24
|
-
assert_equal want_tree_json, got_tree_json,
|
25
|
-
"Test parse to tree: '#{input.chomp}'"
|
26
|
-
blank_line = data.shift or break
|
27
|
-
fail "Got '#{blank_line.chomp}', expected blank line" \
|
28
|
-
unless blank_line == "\n"
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
# See http://www.simplecloud.info/specs/draft-scim-api-01.html#query-resources
|
34
|
-
$test_parse_data = <<'...'
|
35
|
-
|
36
|
-
[]
|
37
|
-
[]
|
38
|
-
|
39
|
-
userName eq "bjensen"
|
40
|
-
[userName,'"bjensen"',eq]
|
41
|
-
[eq, userName,'"bjensen"']
|
42
|
-
|
43
|
-
name.familyName co "O'Malley"
|
44
|
-
[name.familyName, '"O''Malley"', co]
|
45
|
-
[co, name.familyName, '"O''Malley"']
|
46
|
-
|
47
|
-
userName sw "J"
|
48
|
-
[userName, '"J"', sw]
|
49
|
-
[sw, userName, '"J"']
|
50
|
-
|
51
|
-
title pr
|
52
|
-
[title, pr]
|
53
|
-
[pr, title]
|
54
|
-
|
55
|
-
meta.lastModified gt "2011-05-13T04:42:34Z"
|
56
|
-
[meta.lastModified, '"2011-05-13T04:42:34Z"', gt]
|
57
|
-
[gt, meta.lastModified, '"2011-05-13T04:42:34Z"']
|
58
|
-
|
59
|
-
meta.lastModified ge "2011-05-13T04:42:34Z"
|
60
|
-
[meta.lastModified, '"2011-05-13T04:42:34Z"', ge]
|
61
|
-
[ge, meta.lastModified, '"2011-05-13T04:42:34Z"']
|
62
|
-
|
63
|
-
meta.lastModified lt "2011-05-13T04:42:34Z"
|
64
|
-
[meta.lastModified, '"2011-05-13T04:42:34Z"', lt]
|
65
|
-
[lt, meta.lastModified, '"2011-05-13T04:42:34Z"']
|
66
|
-
|
67
|
-
meta.lastModified le "2011-05-13T04:42:34Z"
|
68
|
-
[meta.lastModified, '"2011-05-13T04:42:34Z"', le]
|
69
|
-
[le, meta.lastModified, '"2011-05-13T04:42:34Z"']
|
70
|
-
|
71
|
-
title pr and userType eq "Employee"
|
72
|
-
[title, pr, userType, '"Employee"', eq, and]
|
73
|
-
[and, [pr, title], [eq, userType, '"Employee"']]
|
74
|
-
|
75
|
-
title pr or userType eq "Intern"
|
76
|
-
[title, pr, userType, '"Intern"', eq, or]
|
77
|
-
[or, [pr, title], [eq, userType, '"Intern"']]
|
78
|
-
|
79
|
-
userType eq "Employee" and (emails co "example.com" or emails co "example.org")
|
80
|
-
[userType, '"Employee"', eq, emails, '"example.com"', co, emails, '"example.org"', co, or ,and]
|
81
|
-
[and, [eq, userType, '"Employee"'], [or, [co, emails, '"example.com"'], [co, emails, '"example.org"']]]
|
82
|
-
...
|