ldpath 0.1.0 → 0.2.0

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/.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