ldpath 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,36 @@
1
+ # This configuration was generated by `rubocop --auto-gen-config`
2
+ # on 2015-05-03 18:22:33 -0700 using RuboCop version 0.30.0.
3
+ # The point is for the user to remove these configuration records
4
+ # one by one as the offenses are removed from the code base.
5
+ # Note that changes in the inspected code, or installation of new
6
+ # versions of RuboCop, may require this file to be generated again.
7
+
8
+ # Offense count: 1
9
+ # Cop supports --auto-correct.
10
+ Lint/UnusedBlockArgument:
11
+ Enabled: false
12
+
13
+ # Offense count: 68
14
+ # Cop supports --auto-correct.
15
+ Lint/UnusedMethodArgument:
16
+ Enabled: false
17
+
18
+ # Offense count: 4
19
+ Metrics/AbcSize:
20
+ Max: 28
21
+
22
+ # Offense count: 47
23
+ # Configuration parameters: AllowURI, URISchemes.
24
+ Metrics/LineLength:
25
+ Max: 171
26
+
27
+ # Offense count: 7
28
+ # Cop supports --auto-correct.
29
+ Style/ExtraSpacing:
30
+ Enabled: false
31
+
32
+ # Offense count: 42
33
+ # Cop supports --auto-correct.
34
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
35
+ Style/StringLiterals:
36
+ Enabled: false
data/Gemfile CHANGED
@@ -2,4 +2,3 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in ldpath.gemspec
4
4
  gemspec
5
-
data/Rakefile CHANGED
@@ -3,4 +3,4 @@ require "rspec/core/rake_task"
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- task :default => :spec
6
+ task default: :spec
data/bin/ldpath CHANGED
@@ -6,8 +6,8 @@ require 'ldpath'
6
6
  require 'byebug'
7
7
 
8
8
  begin
9
- require 'rest-client'
10
- rescue LoadError
9
+ require 'rest-client'
10
+ rescue LoadError
11
11
  end
12
12
 
13
13
  options = {}
@@ -15,7 +15,7 @@ OptionParser.new do |opts|
15
15
  opts.banner = "Usage: ldpath [options] URI"
16
16
 
17
17
  opts.on("--program=STRING_URI_OR_FILE", "LDPath program to run (- for STDIN)") do |program|
18
- if File.exists? program or program =~ /^http/
18
+ if File.exists?(program) || program =~ /^http/
19
19
  options[:program] = open(program).read
20
20
  elsif program.strip == "-"
21
21
  options[:program] = $stdin.read
data/lib/ldpath.rb CHANGED
@@ -10,9 +10,9 @@ module Ldpath
10
10
  require 'ldpath/transform'
11
11
  require 'ldpath/functions'
12
12
  require 'ldpath/program'
13
-
13
+
14
14
  class << self
15
- def evaluate program, uri, context
15
+ def evaluate(program, uri, context)
16
16
  Ldpath::Program.parse(program).evaluate(uri, context)
17
17
  end
18
18
 
@@ -26,7 +26,7 @@ module Ldpath
26
26
  end
27
27
  end
28
28
 
29
- def logger= logger
29
+ def logger=(logger)
30
30
  @logger = logger
31
31
  end
32
32
  end
@@ -1,2 +1 @@
1
- class Ldpath::FieldMapping < Struct.new(:name, :selector, :field_type)
2
- end
1
+ Ldpath::FieldMapping = Struct.new(:name, :selector, :field_type)
@@ -1,180 +1,187 @@
1
+ # rubocop:disable Style/MethodName
1
2
  module Ldpath
2
3
  module Functions
3
- def concat uri, context, *args
4
+ def concat(uri, context, *args)
4
5
  args.flatten.compact.join
5
6
  end
6
-
7
- def first uri, context, *args
7
+
8
+ def first(uri, context, *args)
8
9
  args.flatten.compact.first
9
10
  end
10
-
11
- def last uri, context, *args
11
+
12
+ def last(uri, context, *args)
12
13
  args.flatten.compact.last
13
14
  end
14
15
 
15
- def count uri, context, *args
16
+ def count(uri, context, *args)
16
17
  args.flatten.compact.length
17
18
  end
18
-
19
- def eq uri, context, *args
19
+
20
+ def eq(uri, context, *args)
20
21
  a, b, *rem = args.flatten
21
22
  unless rem.empty?
22
23
  raise "Too many arguments to fn:eq"
23
24
  end
24
25
  a == b
25
26
  end
26
-
27
- def ne uri, context, *args
27
+
28
+ def ne(uri, context, *args)
28
29
  a, b, *rem = args.flatten
29
30
  unless rem.empty?
30
31
  raise "Too many arguments to fn:ne"
31
32
  end
32
33
  a != b
33
34
  end
34
-
35
- def lt uri, context, *args
35
+
36
+ def lt(uri, context, *args)
36
37
  a, b, *rem = args.flatten
37
38
  unless rem.empty?
38
39
  raise "Too many arguments to fn:lt"
39
40
  end
40
41
  a < b
41
42
  end
42
-
43
- def le uri, context, *args
43
+
44
+ def le(uri, context, *args)
44
45
  a, b, *rem = args.flatten
45
46
  unless rem.empty?
46
47
  raise "Too many arguments to fn:le"
47
48
  end
48
49
  a <= b
49
50
  end
50
-
51
- def gt uri, context, *args
51
+
52
+ def gt(uri, context, *args)
52
53
  a, b, *rem = args.flatten
53
54
  unless rem.empty?
54
55
  raise "Too many arguments to fn:gt"
55
56
  end
56
57
  a > b
57
58
  end
58
-
59
- def ge uri, context, *args
59
+
60
+ def ge(uri, context, *args)
60
61
  a, b, *rem = args.flatten
61
62
  unless rem.empty?
62
63
  raise "Too many arguments to fn:ge"
63
64
  end
64
65
  a >= b
65
66
  end
66
-
67
+
67
68
  # collections
68
- def flatten uri, context, *args
69
-
69
+ def flatten(uri, context, lists)
70
+ Array(lists).flatten.map { |x| RDF::List.new(x, context).to_a }.flatten
70
71
  end
71
-
72
- def get uri, context, *args
72
+
73
+ def get(uri, context, list, idx)
74
+ flatten(uri, context, list)[idx.to_i]
73
75
  end
74
-
75
- def subList uri, context, *args
76
-
76
+
77
+ def subList(uri, context, list, idx_start, idx_end = nil)
78
+ arr = flatten(uri, context, list)
79
+
80
+ if idx_end
81
+ arr[(idx_start.to_i..(idx_end.to_i - idx_start.to_i))]
82
+ else
83
+ arr.drop(idx_start.to_i)
84
+ end
77
85
  end
78
-
86
+
79
87
  # dates
80
-
81
- def earliest uri, context, *args
88
+
89
+ def earliest(uri, context, *args)
82
90
  args.flatten.min
83
91
  end
84
-
85
- def latest uri, context, *args
92
+
93
+ def latest(uri, context, *args)
86
94
  args.flatten.max
87
95
  end
88
-
96
+
89
97
  # math
90
-
91
- def min uri, context, *args
98
+
99
+ def min(uri, context, *args)
92
100
  args.flatten.min
93
101
  end
94
-
95
- def max uri, context, *args
102
+
103
+ def max(uri, context, *args)
96
104
  args.flatten.max
97
105
  end
98
-
99
- def round uri, context, *args
100
- args.map do |n|
106
+
107
+ def round(uri, context, *args)
108
+ args.map do |n|
101
109
  Array(n).map do |i|
102
110
  i.respond_to? :round ? i.round : i
103
111
  end
104
112
  end
105
113
  end
106
-
107
- def sum uri, context, *args
114
+
115
+ def sum(uri, context, *args)
108
116
  args.inject(0) { |sum, n| sum + n }
109
117
  end
110
-
118
+
111
119
  # text
112
-
113
- def replace uri, context, str, pattern, replacement
120
+
121
+ def replace(uri, context, str, pattern, replacement)
114
122
  regex = Regexp.parse(pattern)
115
123
  Array(str).map do |x|
116
124
  x.gsub(regex, replacement)
117
125
  end
118
126
  end
119
-
120
- def strlen uri, context, str
121
- Array(str).map { |x| x.length }
127
+
128
+ def strlen(uri, context, str)
129
+ Array(str).map(&:length)
122
130
  end
123
-
124
- def wc uri, context, str
131
+
132
+ def wc(uri, context, str)
125
133
  Array(str).map { |x| x.split.length }
126
134
  end
127
-
128
- def strLeft uri, context, str, left
135
+
136
+ def strLeft(uri, context, str, left)
129
137
  Array(str).map { |x| x[0..left.to_i] }
130
138
  end
131
-
132
- def strRight uri, context, str, right
139
+
140
+ def strRight(uri, context, str, right)
133
141
  Array(str).map { |x| x[right.to_i..x.length] }
134
142
  end
135
-
136
- def substr uri, context, str, left, right
143
+
144
+ def substr(uri, context, str, left, right)
137
145
  Array(str).map { |x| x[left.to_i..right.to_i] }
138
146
  end
139
-
140
- def strJoin uri, context, str, sep = "", prefix = "", suffix = ""
147
+
148
+ def strJoin(uri, context, str, sep = "", prefix = "", suffix = "")
141
149
  prefix + Array(str).join(sep) + suffix
142
150
  end
143
-
144
- def equals uri, context, str, other
151
+
152
+ def equals(uri, context, str, other)
145
153
  Array(str).map { |x| x == other }
146
154
  end
147
-
148
- def equalsIgnoreCase uri, context, str, other
155
+
156
+ def equalsIgnoreCase(uri, context, str, other)
149
157
  Array(str).map { |x| x.downcase == other.downcase }
150
158
  end
151
-
152
- def contains uri, context, str, substr
159
+
160
+ def contains(uri, context, str, substr)
153
161
  Array(str).map { |x| x.include? substr }
154
162
  end
155
-
156
- def startsWith uri, context, str, suffix
163
+
164
+ def startsWith(uri, context, str, suffix)
157
165
  Array(str).map { |x| x.start_with? suffix }
158
166
  end
159
-
160
- def endsWith uri, context, str, suffix
167
+
168
+ def endsWith(uri, context, str, suffix)
161
169
  Array(str).map { |x| x.end_with? suffix }
162
170
  end
163
-
164
- def isEmpty uri, context, str
171
+
172
+ def isEmpty(uri, context, str)
165
173
  Array(str).map(&:empty?)
166
174
  end
167
175
 
168
- def predicates uri, context, *args
176
+ def predicates(uri, context, *args)
169
177
  context.query([uri, nil, nil]).map(&:predicate).uniq
170
178
  end
171
179
 
172
- def xpath uri, context, xpath, node
180
+ def xpath(uri, context, xpath, node)
173
181
  x = Array(xpath).flatten.first
174
182
  Array(node).flatten.compact.map do |n|
175
- Nokogiri::XML(n).xpath(x, prefixes.map { |k,v| [k, v.to_s] }).map(&:text)
183
+ Nokogiri::XML(n).xpath(x, prefixes.map { |k, v| [k, v.to_s] }).map(&:text)
176
184
  end
177
185
  end
178
-
179
186
  end
180
187
  end
data/lib/ldpath/parser.rb CHANGED
@@ -2,36 +2,64 @@ require 'parslet'
2
2
 
3
3
  module Ldpath
4
4
  class Parser < Parslet::Parser
5
- root :lines
6
- rule(:lines) { line.repeat }
7
- rule(:line) { ((wsp >> expression) | expression) >> space_not_newline? >> (newline | eof) }
5
+ root :doc
6
+ rule(:doc) { prologue? >> statements? >> eof }
8
7
 
9
- rule(:newline) { (str("\n") >> str("\r").maybe).repeat(1) }
10
- rule(:eof) { any.absent? }
8
+ rule(:prologue) { wsp? >> directive?.repeat(1, 1) >> (eol >> wsp? >> directive >> wsp?).repeat >> wsp? >> eol? }
9
+ rule(:prologue?) { prologue.maybe }
10
+ rule(:directive) { prefixID | graph | filter | boost }
11
+ rule(:directive?) { directive.maybe }
11
12
 
12
- rule(:space) { match('\s').repeat(1) }
13
- rule(:spaces?) { space.maybe }
14
- rule(:space_not_newline) { str("\n").absent? >> space }
15
- rule(:space_not_newline?) { space_not_newline.maybe }
13
+ rule(:statements) { wsp? >> statement?.repeat(1, 1) >> (eol >> wsp? >> statement >> wsp?).repeat >> wsp? >> eol? }
14
+ rule(:statements?) { statements.maybe }
15
+ rule(:statement) { mapping }
16
+ rule(:statement?) { mapping.maybe }
16
17
 
17
- rule(:wsp) { (space | multiline_comment).repeat(1) }
18
+ # whitespace rules
19
+ rule(:eol) { (str("\n") >> str("\r").maybe).repeat(1) }
20
+ rule(:eol?) { eol.maybe }
21
+ rule(:eof) { any.absent? }
22
+ rule(:space) { str("\n").absent? >> match('\s').repeat(1) }
23
+ rule(:space?) { space.maybe }
24
+ rule(:wsp) { (space | multiline_comment | single_line_comment).repeat(1) }
18
25
  rule(:wsp?) { wsp.maybe }
19
- rule(:multiline_comment) { (str('/*') >> (str('*/').absent? >> any).repeat >> str('*/') ) }
26
+ rule(:multiline_comment) { (str("/*") >> (str("*/").absent? >> any).repeat >> str("*/")) }
27
+ rule(:single_line_comment) { str("#") >> (eol.absent? >> any).repeat }
20
28
 
21
- rule(:expression) { wsp | namespace | mapping | graph | filter | boost }
22
-
23
- rule(:int) { match("\\d+") }
24
-
25
- rule(:comma) { str(",") }
26
- rule(:scolon) { str(";") }
27
- rule(:colon) { str(":") }
28
- rule(:dcolon) { str("::") }
29
- rule(:assign) { str("=") }
30
- rule(:k_prefix) { str("@prefix")}
31
- rule(:k_graph) { str("@graph")}
32
- rule(:k_filter) { str("@filter")}
33
- rule(:k_boost) { str("@boost")}
34
-
29
+ # simple types
30
+ rule(:integer) { match("[+-]").maybe >> match("\\d+") }
31
+ rule(:decimal) { match("[+-]").maybe >> match("\\d*") >> str(".") >> match("\\d+") }
32
+ rule(:double) do
33
+ match("[+-]").maybe >> (
34
+ (match("\\d+") >> str('.') >> match("\\d*") >> exponent) |
35
+ (str('.') >> match("\\d+") >> exponent) |
36
+ (match("\\d+") >> exponent)
37
+ )
38
+ end
39
+
40
+ rule(:exponent) { match('[Ee]') >> match("[+-]").maybe >> match("\\d+") }
41
+ rule(:numeric_literal) { integer | decimal | double }
42
+ rule(:boolean_literal) { str('true') | str('false') }
43
+
44
+ rule(:string) { string_literal_quote | string_literal_single_quote | string_literal_long_single_quote | string_literal_long_quote }
45
+
46
+ rule(:string_literal_quote) do
47
+ str('"') >> (match("[^\\\"\\\\\\r\\n]") | echar | uchar).repeat.as(:literal) >> str('"')
48
+ end
49
+
50
+ rule(:string_literal_single_quote) do
51
+ str("'") >> (match("[^'\\\\\\r\\n]") | echar | uchar).repeat.as(:literal) >> str("'")
52
+ end
53
+
54
+ rule(:string_literal_long_quote) do
55
+ str('"""') >> (str('"""').absent? >> match("[^\\\\]") | echar | uchar).repeat.as(:literal) >> str('"""')
56
+ end
57
+
58
+ rule(:string_literal_long_single_quote) do
59
+ str("'''") >> (str("'''").absent? >> match("[^\\\\]") | echar | uchar).repeat.as(:literal) >> str("'''")
60
+ end
61
+
62
+ # operators
35
63
  rule(:self_op) { str(".") }
36
64
  rule(:and_op) { str("&") }
37
65
  rule(:or_op) { str("|") }
@@ -40,337 +68,374 @@ module Ldpath
40
68
  rule(:star) { str("*") }
41
69
  rule(:not_op) { str("!") }
42
70
  rule(:inverse) { str("^") }
43
- rule(:tap) { str("?") }
71
+ rule(:question) { str("?") }
44
72
  rule(:is) { str "is" }
45
73
  rule(:is_a) { str "is-a" }
46
- rule(:func) { str "fn:"}
74
+ rule(:func) { str "fn:" }
47
75
  rule(:type) { str "^^" }
48
76
  rule(:lang) { str "@" }
49
77
  rule(:loose) { str("~") }
50
-
51
- # todo: fixme
52
- rule(:uri) do
53
- uri_in_brackets |
54
- prefix_and_localname
78
+
79
+ # strings
80
+ rule(:comma) { str(",") }
81
+ rule(:scolon) { str(";") }
82
+ rule(:colon) { str(":") }
83
+ rule(:dcolon) { str("::") }
84
+ rule(:assign) { str("=") }
85
+ rule(:k_prefix) { str("@prefix") }
86
+ rule(:k_graph) { str("@graph") }
87
+ rule(:k_filter) { str("@filter") }
88
+ rule(:k_boost) { str("@boost") }
89
+
90
+ # iris
91
+ rule(:iri) do
92
+ iriref |
93
+ prefixed_name
94
+ end
95
+
96
+ rule(:iriref) do
97
+ str("<") >> (match("[^[[:cntrl:]]<>\"{}|^`\\\\]") | uchar).repeat.as(:iri) >> str('>')
98
+ end
99
+
100
+ rule(:uchar) do
101
+ str('\u') >> hex.repeat(4, 4) | hex.repeat(6, 6)
102
+ end
103
+
104
+ rule(:echar) do
105
+ str('\\') >> match("[tbnrf\"'\\\\]")
106
+ end
107
+
108
+ rule(:hex) do
109
+ match("[[:xdigit:]]")
110
+ end
111
+
112
+ rule(:prefixed_name) do
113
+ (identifier.as(:prefix) >> str(":") >> identifier.as(:localName)).as(:iri)
55
114
  end
56
-
57
- rule(:uri_in_brackets) do
58
- str("<") >> (str(">").absent? >> any).repeat.as(:uri) >> str(">")
115
+
116
+ rule(:identifier) { pn_chars_base >> (str(".").maybe >> pn_chars).repeat }
117
+
118
+ rule(:pn_chars_base) do
119
+ # also \u10000-\uEFFFF
120
+ match("[A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]")
59
121
  end
60
-
61
- rule(:prefix_and_localname) do
62
- (identifier.as(:prefix) >> str(":") >> identifier.as(:localName)).as(:uri)
122
+
123
+ rule(:pn_chars) do
124
+ pn_chars_base | match("[0-9\u00B7\u0300-\u036F\u203F-\u2040_-]")
63
125
  end
64
-
65
- rule(:identifier) { match["a-zA-Z0-9_"] >> (match["a-zA-Z0-9_'\\.-"]).repeat }
66
126
 
67
- rule(:strlit) {
68
- str('"') >> (str("\\") >> str("\"") | (str('"').absent? >> any)).repeat.as(:literal) >> str('"')
69
- }
127
+ # "xyz"; 0.123e52; true
128
+ rule(:literal) do
129
+ rdf_literal | numeric_literal | boolean_literal
130
+ end
70
131
 
71
- rule(:node) {
72
- uri.as(:uri) | strlit.as(:literal)
73
- }
132
+ # "xyz"; "xyz"^^a; "xyz"@en
133
+ rule(:rdf_literal) do
134
+ string >> (literal_language_test | literal_type_test).maybe
135
+ end
136
+
137
+ rule(:node) do
138
+ iri.as(:iri) | literal.as(:literal)
139
+ end
74
140
 
75
- # @prefix id = uri ;
76
- rule(:namespace) {
141
+ # @prefix id = iri ;
142
+ rule(:prefixID) do
77
143
  (
78
144
  k_prefix >> wsp? >>
79
- identifier.as(:id) >> wsp? >>
145
+ (identifier | str("")).as(:id) >> wsp? >>
80
146
  colon >> wsp? >>
81
- uri.as(:uri) >> space_not_newline? >> scolon.maybe
82
- ).as(:namespace)
83
- }
84
-
85
- # @graph uri, uri, uri ;
86
- rule(:graph) {
87
- k_graph >> wsp? >>
88
- uri_list.as(:graphs) >> wsp? >> scolon
89
- }
90
-
91
- rule(:uri_list) {
92
- uri.as(:uri) >>
93
- (
94
- wsp? >>
95
- comma >> wsp? >>
96
- uri_list.as(:rest)
97
- ).repeat
98
- }
147
+ iriref >> space? >> scolon.maybe
148
+ ).as(:prefixID)
149
+ end
150
+
151
+ # @graph iri, iri, iri ;
152
+ rule(:graph) do
153
+ k_graph >> wsp? >>
154
+ iri_list.as(:graphs) >> wsp? >> scolon
155
+ end
156
+
157
+ # <info:a>, <info:b>
158
+ rule(:iri_list) do
159
+ iri.as(:iri) >>
160
+ (
161
+ wsp? >>
162
+ comma >> wsp? >>
163
+ iri_list.as(:rest)
164
+ ).repeat
165
+ end
99
166
 
100
167
  # @filter test ;
101
- rule(:filter) {
168
+ rule(:filter) do
102
169
  (k_filter >> wsp? >> node_test.as(:test) >> wsp? >> scolon).as(:filter)
103
- }
170
+ end
104
171
 
105
172
  # @boost selector ;
106
- rule(:boost) {
173
+ rule(:boost) do
107
174
  (k_boost >> wsp? >> selector.as(:selector) >> wsp? >> scolon).as(:boost)
108
- }
109
-
175
+ end
176
+
110
177
  # id = . ;
111
- rule(:mapping) {
178
+ rule(:mapping) do
112
179
  (
113
- (uri_in_brackets | prefix_and_localname | identifier).as(:name) >> wsp? >>
180
+ label.as(:name) >> wsp? >>
114
181
  assign >> wsp? >>
115
182
  selector.as(:selector) >>
116
- ( wsp? >>
183
+ (wsp? >>
117
184
  dcolon >> wsp? >> field_type
118
185
  ).maybe >> wsp? >> scolon
119
186
  ).as(:mapping)
120
- }
187
+ end
121
188
 
122
- rule(:field_type) {
123
- uri.as(:field_type) >> field_type_options.maybe
124
- }
189
+ rule(:label) do
190
+ iri | identifier
191
+ end
125
192
 
126
- rule(:field_type_options) {
193
+ # xsd:string
194
+ rule(:field_type) do
195
+ iri.as(:field_type) >> field_type_options.maybe
196
+ end
197
+
198
+ # ( x = "xyz", y = "abc" )
199
+ rule(:field_type_options) do
127
200
  str("(") >> wsp? >> (field_type_option >> (wsp? >> comma >> wsp? >> field_type_option).repeat).as(:options) >> wsp? >> str(")")
128
- }
201
+ end
202
+
203
+ # x = "xyz"
204
+ rule(:field_type_option) do
205
+ identifier.as(:key) >> wsp? >> assign >> wsp? >> literal.as(:value)
206
+ end
129
207
 
130
- rule(:field_type_option) {
131
- identifier.as(:key) >> wsp? >> assign >> wsp? >> strlit.as(:value)
132
- }
133
-
134
208
  # selector groups
135
- rule(:selector) {
209
+ rule(:selector) do
136
210
  (
137
- compound_selector |
211
+ compound_or_path_selector |
138
212
  testing_selector |
139
213
  atomic_selector
140
214
  )
141
- }
215
+ end
142
216
 
143
- rule(:compound_selector) {
144
- (
145
- union_selector |
146
- intersection_selector |
147
- path_selector
148
- )
149
- }
150
-
151
- rule(:testing_selector) {
217
+ # &; |
218
+ rule(:compound_operator) { and_op | or_op }
219
+
220
+ # a & b; a | b; a / b
221
+ rule(:compound_or_path_selector) do
222
+ path_selector | compound_selector
223
+ end
224
+
225
+ # a & b; a | b
226
+ rule(:compound_selector) do
227
+ atomic_or_testing_or_path_selector.as(:left) >> wsp? >>
228
+ compound_operator.as(:op) >> wsp? >>
229
+ selector.as(:right)
230
+ end
231
+
232
+ # a / b
233
+ rule(:path_selector) do
234
+ atomic_or_testing_selector.as(:left) >> wsp? >>
235
+ p_sep.as(:op) >> wsp? >>
236
+ atomic_or_testing_or_path_selector.as(:right)
237
+ end
238
+
239
+ # info:a[is-a z]
240
+ rule(:testing_selector) do
152
241
  atomic_selector.as(:delegate) >>
153
- str("[") >> wsp? >>
154
- node_test.as(:test) >> wsp? >>
155
- str("]")
156
- }
242
+ str("[") >> wsp? >>
243
+ node_test.as(:test) >> wsp? >>
244
+ str("]")
245
+ end
157
246
 
158
- rule(:atomic_selector) {
247
+ rule(:atomic_selector) do
159
248
  (
160
249
  self_selector |
161
250
  function_selector |
162
251
  property_selector |
163
252
  loose_property_selector |
164
- wildcard_selector |
253
+ wildcard_selector |
165
254
  reverse_property_selector |
166
255
  string_constant_selector |
167
256
  recursive_path_selector |
168
257
  grouped_selector |
169
258
  tap_selector
170
259
  )
171
- }
172
-
260
+ end
173
261
 
174
- rule(:atomic_or_testing_selector) {
262
+ rule(:atomic_or_testing_selector) do
175
263
  (testing_selector | atomic_selector)
176
- }
264
+ end
177
265
 
178
- rule(:atomic_or_testing_or_path_selector) {
266
+ rule(:atomic_or_testing_or_path_selector) do
179
267
  (path_selector | atomic_or_testing_selector)
180
- }
181
-
182
- # Compound selectors
183
- ## x / y
184
- rule(:path_selector) {
185
- (
186
- atomic_or_testing_selector.as(:left) >> wsp? >>
187
- p_sep >> wsp? >>
188
- atomic_or_testing_or_path_selector.as(:right)
189
- ).as(:path)
190
- }
191
-
192
- ## x & y
193
- rule(:intersection_selector) {
194
- (
195
- atomic_or_testing_or_path_selector.as(:left) >> wsp? >>
196
- and_op >> wsp? >>
197
- selector.as(:right)
198
- ).as(:intersection)
199
- }
200
-
201
- ## x | y
202
- rule(:union_selector) {
203
- (
204
- atomic_or_testing_or_path_selector.as(:left) >> wsp? >>
205
- or_op >> wsp? >>
206
- selector.as(:right)
207
- ).as(:union)
208
- }
268
+ end
209
269
 
210
270
  # Atomic Selectors
211
- rule(:self_selector) {
271
+ rule(:self_selector) do
212
272
  self_op.as(:self)
213
- }
214
-
273
+ end
274
+
215
275
  # fn:x() or fn:x(1,2,3)
216
- rule(:function_selector) {
217
- func >> identifier.as(:fname) >> str("()") |
276
+ rule(:function_selector) do
277
+ function_without_args | function_with_arglist
278
+ end
279
+
280
+ rule(:function_without_args) do
281
+ func >> identifier.as(:fname) >> str("()")
282
+ end
283
+
284
+ rule(:function_with_arglist) do
218
285
  func >> identifier.as(:fname) >> str("(") >> wsp? >> arglist.as(:arglist) >> wsp? >> str(")")
219
- }
220
-
221
- rule(:arglist) {
222
- selector >>
223
- (
224
- wsp? >>
225
- comma >> wsp? >>
226
- selector
227
- ).repeat
228
- }
229
-
286
+ end
287
+
288
+ rule(:arglist) do
289
+ selector >>
290
+ (
291
+ wsp? >>
292
+ comma >> wsp? >>
293
+ selector
294
+ ).repeat
295
+ end
296
+
230
297
  # xyz
231
- rule(:loose_property_selector) {
232
- loose >>
233
- wsp? >>
234
- uri.as(:loose_property)
235
- }
298
+ rule(:loose_property_selector) do
299
+ loose.as(:loose) >>
300
+ wsp? >>
301
+ iri.as(:property)
302
+ end
236
303
 
237
304
  # xyz
238
- rule(:property_selector) {
239
- uri.as(:property)
240
- }
305
+ rule(:property_selector) do
306
+ iri.as(:property)
307
+ end
241
308
 
242
309
  # *
243
- rule(:wildcard_selector) {
310
+ rule(:wildcard_selector) do
244
311
  star.as(:wildcard)
245
- }
312
+ end
246
313
 
247
314
  # ^xyz
248
- rule(:reverse_property_selector) {
249
- inverse >> uri.as(:reverse_property)
250
- }
251
-
252
- rule(:string_constant_selector) {
253
- strlit
254
- }
255
-
256
- # (x)*
257
- rule(:recursive_path_selector) {
258
- (
259
- str("(") >> wsp? >>
260
- selector.as(:delegate) >> wsp? >>
315
+ rule(:reverse_property_selector) do
316
+ inverse.as(:reverse) >> iri.as(:property)
317
+ end
318
+
319
+ rule(:string_constant_selector) do
320
+ string
321
+ end
322
+
323
+ # (x)?; (x)*; (x)+; (x){3,5}
324
+ rule(:recursive_path_selector) do
325
+ str("(") >> wsp? >>
326
+ selector.as(:delegate) >> wsp? >>
261
327
  str(")") >>
262
- (
263
- star |
264
- plus |
265
- (str("{") >> wsp? >> int.as(:min).maybe >> wsp? >>str(",") >> wsp? >> int.as(:max).maybe >> wsp? >>str("}") ).as(:range)
266
- ).as(:repeat)
267
- ).as(:recursive)
268
- }
269
-
270
- rule(:grouped_selector) {
271
- str("(") >> wsp? >>
272
- selector >> wsp? >>
273
- str(")")
274
- }
275
-
276
- rule(:tap_selector) {
277
- tap >>
278
- str("<") >> wsp? >>
279
- identifier.as(:identifier) >> wsp? >>
280
- str(">") >> wsp? >>
281
- (atomic_selector).as(:tap)
282
- }
283
-
328
+ range.as(:repeat)
329
+ end
330
+
331
+ # ?; *; +; {3,5}; {,5}; {3,}
332
+ rule(:range) do
333
+ (
334
+ star |
335
+ plus |
336
+ question |
337
+ str("{") >> wsp? >> integer.as(:min).maybe >> wsp? >> str(",") >> wsp? >> integer.as(:max).maybe >> wsp? >> str("}")
338
+ ).as(:range)
339
+ end
340
+
341
+ # (<info:a>)
342
+ rule(:grouped_selector) do
343
+ str("(") >> wsp? >>
344
+ selector >> wsp? >>
345
+ str(")")
346
+ end
347
+
348
+ # ?<a>(<info:a>)
349
+ rule(:tap_selector) do
350
+ question >>
351
+ str("<") >> wsp? >>
352
+ identifier.as(:identifier) >> wsp? >>
353
+ str(">") >> wsp? >>
354
+ (atomic_selector).as(:tap)
355
+ end
356
+
284
357
  # Testing Selectors
285
-
286
- rule(:node_test) {
358
+
359
+ rule(:node_test) do
287
360
  grouped_test |
288
- not_test |
289
- and_test |
290
- or_test |
291
- atomic_node_test
292
- }
361
+ not_test |
362
+ and_test |
363
+ or_test |
364
+ atomic_node_test
365
+ end
293
366
 
294
- rule(:atomic_node_test) {
367
+ rule(:atomic_node_test) do
295
368
  literal_language_test |
296
- literal_type_test |
297
- is_a_test |
298
- path_equality_test |
299
- function_test |
300
- path_test
301
- }
302
-
303
- rule(:grouped_test) {
304
- str("(") >> wsp? >>
305
- node_test >> wsp? >>
306
- str(")")
307
- }
308
-
309
- rule(:not_test) {
369
+ literal_type_test |
370
+ is_a_test |
371
+ path_equality_test |
372
+ function_test |
373
+ path_test
374
+ end
375
+
376
+ rule(:grouped_test) do
377
+ str("(") >> wsp? >>
378
+ node_test >> wsp? >>
379
+ str(")")
380
+ end
381
+
382
+ rule(:not_test) do
310
383
  (
311
384
  not_op >> node_test.as(:delegate)
312
385
  ).as(:not)
313
- }
314
-
315
- rule(:and_test) {
386
+ end
387
+
388
+ rule(:and_test) do
316
389
  (
317
- atomic_node_test.as(:left) >> wsp? >>
318
- and_op >> wsp? >>
390
+ atomic_node_test.as(:left) >> wsp? >>
391
+ and_op >> wsp? >>
319
392
  node_test.as(:right)
320
393
  ).as(:and)
321
- }
322
-
323
- rule(:or_test) {
394
+ end
395
+
396
+ rule(:or_test) do
324
397
  (
325
- atomic_node_test.as(:left) >> wsp? >>
326
- or_op >> wsp? >>
398
+ atomic_node_test.as(:left) >> wsp? >>
399
+ or_op >> wsp? >>
327
400
  node_test.as(:right)
328
401
  ).as(:or)
329
- }
402
+ end
330
403
 
331
404
  # @en
332
- rule(:literal_language_test) {
405
+ rule(:literal_language_test) do
333
406
  lang >> identifier.as(:lang)
334
- }
335
-
407
+ end
408
+
336
409
  # ^^xyz
337
- rule(:literal_type_test) {
338
- type >> uri.as(:type)
339
- }
340
-
341
- rule(:is_a_test) {
410
+ rule(:literal_type_test) do
411
+ type >> iri.as(:type)
412
+ end
413
+
414
+ rule(:is_a_test) do
342
415
  (
343
- is_a >> wsp? >>
416
+ is_a >> wsp? >>
344
417
  node.as(:right)
345
418
  ).as(:is_a)
346
- }
347
-
348
- rule(:path_equality_test) {
419
+ end
420
+
421
+ rule(:path_equality_test) do
349
422
  (
350
423
  selector >> wsp? >>
351
424
  is >> wsp? >>
352
425
  node.as(:right)
353
426
  ).as(:is)
354
- }
355
-
356
- rule(:function_test) {
357
- (
358
- func >> identifier.as(:fname) >> str("()") |
359
- func >> identifier.as(:fname) >> str("(") >>
360
- wsp? >>
361
- arglist.as(:arglist) >>
362
- wsp? >>
363
- str(")")
364
- )
365
- }
427
+ end
366
428
 
367
- rule(:path_test) {
429
+ rule(:function_test) do
430
+ function_without_args | function_with_arglist
431
+ end
432
+
433
+ rule(:path_test) do
368
434
  (
369
435
  path_selector |
370
436
  testing_selector |
371
437
  atomic_selector
372
438
  )
373
- }
374
-
439
+ end
375
440
  end
376
441
  end