rdf-n3 3.1.2 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c53b64b52fa5a16fdfe462a270e5eb861c8cbd432aadc0df0aedaf057accb3f3
4
- data.tar.gz: 2e7537cc0ab6084f7a321ffe4347a5071e6d9204025a746b21856c786fd491d4
3
+ metadata.gz: c5082274015223c285074d961b1de134d76a9e4b4174ec70cabb326161609ec8
4
+ data.tar.gz: a8df856b348d43664a99d1ce183da15082cb803b271eafd6f98abf3b8ac2f0eb
5
5
  SHA512:
6
- metadata.gz: b8fd2b701f9eb17083ca81884f98de32435068e494445d14ffdbb7fff7f323a0c32a507e6490466b56f77abb3b7d3cd523861f50e82cb494236537871be8f840
7
- data.tar.gz: f68c2f4a5f91ecb35d95ad9e58f58adb9ade18b66fd24ad04bfb34482f49cb245e98f27660e46b5bfc4adf72da1c6e534ae903deec35d07fe1419949cefc5312
6
+ metadata.gz: 561febe8dde9ad892eab9eda2cdf957c1d79c350be900a35c487ee6d3362c780aa5eee9868ba07c2c66d201f4f2a16a5bb0bb7853c366d2ab9b1593e50b25b0b
7
+ data.tar.gz: c15291bf10df5b98eb5f02f859b2c5d00d25b145f9effcf7c256b6a0d2edce32b1a66e9254308d6674131a84322fa33068bb9c661236b8c1ee26468ca26ee8fc
data/README.md CHANGED
@@ -3,7 +3,7 @@ Notation-3 reader/writer for [RDF.rb][RDF.rb] .
3
3
 
4
4
  [![Gem Version](https://badge.fury.io/rb/rdf-n3.png)](https://badge.fury.io/rb/rdf-n3)
5
5
  [![Build Status](https://github.com/ruby-rdf/rdf-n3/workflows/CI/badge.svg?branch=develop)](https://github.com/ruby-rdf/rdf-n3/actions?query=workflow%3ACI)
6
- [![Coverage Status](https://coveralls.io/repos/ruby-rdf/rdf-n3/badge.svg)](https://coveralls.io/github/ruby-rdf/rdf-n3)
6
+ [![Coverage Status](https://coveralls.io/repos/github/ruby-rdf/rdf-n3/badge.svg?branch=develop)](https://coveralls.io/github/ruby-rdf/rdf-n3?branch=develop)
7
7
  [![Gitter chat](https://badges.gitter.im/ruby-rdf/rdf.png)](https://gitter.im/ruby-rdf/rdf)
8
8
 
9
9
  ## Description
@@ -19,6 +19,7 @@ This version tracks the [W3C N3 Community Group][] [Specification][N3] which has
19
19
  * The modifier `<-` is introduced as a synonym for `is ... of`.
20
20
  * The SPARQL `BASE` and `PREFIX` declarations are supported.
21
21
  * Implicit universal variables are defined at the top-level, rather than in the parent formula of the one in which they are defined.
22
+ * Support for explicit existential and universal variables (`@forAll` and `@forSome`) has been removed. Quick variables are the standard for universal quantification and blank nodes for existential, but scoping rules are different: Quickvars have top-level scope, and blank nodes formula scope.
22
23
 
23
24
  This brings N3 closer to compatibility with Turtle.
24
25
 
@@ -27,6 +28,8 @@ RDF::N3 parses [Notation-3][N3], [Turtle][] and [N-Triples][] into statements or
27
28
 
28
29
  Install with `gem install rdf-n3`
29
30
 
31
+ [Implementation Report](https://ruby-rdf.github.io/rdf-n3/etc/earl.html)
32
+
30
33
  ## Limitations
31
34
  * Support for Variables in Formulae. Existential variables are quantified to RDF::Node instances, Universals to RDF::Query::Variable, with the URI of the variable target used as the variable name.
32
35
 
@@ -69,6 +72,7 @@ Reasoning is discussed in the [Design Issues][] document.
69
72
  * `list:append` (See {RDF::N3::Algebra::List::Append})
70
73
  * `list:first` (See {RDF::N3::Algebra::List::First})
71
74
  * `list:in` (See {RDF::N3::Algebra::List::In})
75
+ * `list:iterate` (See {RDF::N3::Algebra::List::Iterate})
72
76
  * `list:last` (See {RDF::N3::Algebra::List::Last})
73
77
  * `list:length` (See {RDF::N3::Algebra::List::Length})
74
78
  * `list:member` (See {RDF::N3::Algebra::List::Member})
@@ -78,9 +82,11 @@ Reasoning is discussed in the [Design Issues][] document.
78
82
  * `log:conclusion` (See {RDF::N3::Algebra::Log::Conclusion})
79
83
  * `log:conjunction` (See {RDF::N3::Algebra::Log::Conjunction})
80
84
  * `log:content` (See {RDF::N3::Algebra::Log::Content})
85
+ * `log:dtlit` (See {RDF::N3::Algebra::Log::DtLit})
81
86
  * `log:equalTo` (See {RDF::N3::Algebra::Log::EqualTo})
82
87
  * `log:implies` (See {RDF::N3::Algebra::Log::Implies})
83
88
  * `log:includes` (See {RDF::N3::Algebra::Log::Includes})
89
+ * `log:langlit` (See {RDF::N3::Algebra::Log::LangLit})
84
90
  * `log:n3String` (See {RDF::N3::Algebra::Log::N3String})
85
91
  * `log:notEqualTo` (See {RDF::N3::Algebra::Log::NotEqualTo})
86
92
  * `log:notIncludes` (See {RDF::N3::Algebra::Log::NotIncludes})
@@ -139,7 +145,7 @@ Reasoning is discussed in the [Design Issues][] document.
139
145
  * `string:scrape` (See {RDF::N3::Algebra::Str::Scrape})
140
146
  * `string:startsWith` (See {RDF::N3::Algebra::Str::StartsWith})
141
147
 
142
- #### RDF Time vocabulary <>
148
+ #### RDF Time vocabulary <http://www.w3.org/2000/10/swap/time#>
143
149
 
144
150
  * `time:dayOfWeek` (See {RDF::N3::Algebra::Time::DayOfWeek})
145
151
  * `time:day` (See {RDF::N3::Algebra::Time::Day})
@@ -173,15 +179,8 @@ when turned into an RDF Repository results in the following quads
173
179
  Reasoning uses a Notation3 Algebra, similar to [SPARQL S-Expressions][]. This implementation considers formulae to be patterns, which may be asserted on statements made in the default graph, possibly loaded from a separate file. The logical relationships are reduced to algebraic operators.
174
180
 
175
181
  ### Variables
176
- N3 Variables are introduced with `@forAll`, `@forSome`, or `?x`. Variables reference URIs described in formulae, typically defined in the default vocabulary (e.g., `":x"`). Existential variables are replaced with an allocated `RDF::Node` instance. Universal variables are replaced with a `RDF::Query::Variable` instance. For example, the following N3 generates the associated statements:
177
-
178
- @forAll <#h>. @forSome <#g>. <#g> <#loves> <#h> .
179
-
180
- results in:
181
-
182
- h = RDF::Query::Variable.new(<#h>)
183
- g = RDF::Node.new()
184
- RDF::Statement(f, <#loves>, h)
182
+ The latest version of N3 supports only quickVars (e.g., `?x`). THe former explicit `@forAll` and `@forSome` of been removed.
183
+ Existential variables are replaced with an allocated `RDF::Node` instance.
185
184
 
186
185
  Note that the behavior of both existential and universal variables is not entirely in keeping with the [Team Submission][], and neither work quite like SPARQL variables. When used in the antecedent part of an implication, universal variables should behave much like SPARQL variables. This area is subject to a fair amount of change.
187
186
 
@@ -194,11 +193,11 @@ Formulae are typically used to query the knowledge-base, which is set from the b
194
193
  Blank nodes associated with rdf:List statements used as part of a built-in are made _non-distinguished_ existential variables, and patters containing these variables become optional. If they are not bound as part of the query, the implicitly are bound as the original blank nodes defined within the formula, which allows for both constant list arguments, list arguments that contain variables, or arguments which are variables expanding to lists.
195
194
 
196
195
  ## Dependencies
197
- * [Ruby](https://ruby-lang.org/) (>= 2.4)
198
- * [RDF.rb](https://rubygems.org/gems/rdf) (~> 3.1, >= 3.1.4)
199
- * [EBNF][EBNF gem] (~> 2.1)
196
+ * [Ruby](https://ruby-lang.org/) (>= 2.6)
197
+ * [RDF.rb](https://rubygems.org/gems/rdf) (~> 3.2)
198
+ * [EBNF][EBNF gem] (~> 2.2)
200
199
  * [SPARQL][SPARQL gem] (~> 3.1)
201
- * [SXP][SXP gem] (~> 1.1)
200
+ * [SXP][SXP gem] (~> 1.2)
202
201
 
203
202
  ## Documentation
204
203
  Full documentation available on [RubyDoc.info](https://rubydoc.info/github/ruby-rdf/rdf-n3)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.1.2
1
+ 3.2.0
@@ -0,0 +1,96 @@
1
+ module RDF::N3::Algebra::List
2
+ ##
3
+ # Generates a list of lists when each constituent list is composed of the index and value of each element in the subject.
4
+ #
5
+ # Binds variables in the object list.
6
+ #
7
+ # @example
8
+ # { (1 2 3) list:iterate ((0 1) (1 2) (2 3)) } => { :test4a a :SUCCESS }.
9
+ class Iterate < RDF::N3::Algebra::ListOperator
10
+ NAME = :listIterate
11
+ URI = RDF::N3::List.iterate
12
+
13
+ ##
14
+ # Evaluates this operator using the given variable `bindings`.
15
+ # The subject MUST evaluate to a list and the object to a list composed of two components: index and value.
16
+ #
17
+ # @example
18
+ # {(1 2 3) list:iterate (?x ?y)} => {:solution :is (?x ?y)} .
19
+ #
20
+ # @example
21
+ # {(1 2 3) list:iterate ?L} => {:solution :is ?L} .
22
+ #
23
+ # @example
24
+ # {(1 2 3) list:iterate (1 ?y)} => {:value :is ?y} .
25
+ #
26
+ # @example
27
+ # {(1 2 3) list:iterate (?x 2)} => {:index :is ?x} .
28
+ #
29
+ # @param [RDF::Queryable] queryable
30
+ # the graph or repository to query
31
+ # @param [RDF::Query::Solutions] solutions
32
+ # solutions for chained queries
33
+ # @return [RDF::Query::Solutions]
34
+ def execute(queryable, solutions:, **options)
35
+ RDF::Query::Solutions(solutions.map do |solution|
36
+ subject = operand(0).evaluate(solution.bindings, formulae: formulae) || operand(0)
37
+ # Might be a variable or node evaluating to a list in queryable, or might be a list with variables
38
+ # If subject evaluated to a BNode, re-expand as a list
39
+ subject = RDF::N3::List.try_list(subject, queryable).evaluate(solution.bindings, formulae: formulae)
40
+ next unless validate(subject)
41
+
42
+ object = operand(1).evaluate(solution.bindings, formulae: formulae) || operand(1)
43
+ next unless object
44
+ # If object evaluated to a BNode, re-expand as a list
45
+ object = RDF::N3::List.try_list(object, queryable).evaluate(solution.bindings, formulae: formulae) || object
46
+
47
+ if object.list? && object.variable?
48
+ # Create a solution for those entries in subject that match object
49
+ if object.length != 2
50
+ log_error(NAME) {"object is not a list with two entries: #{object.to_sxp}"}
51
+ next
52
+ end
53
+ if object.first.variable? && object.last.variable?
54
+ solutions = RDF::Query::Solutions.new
55
+ subject.each_with_index do |r, i|
56
+ s = solution.merge(object.first.to_sym => RDF::Literal(i), object.last.to_sym => r)
57
+ log_debug(self.class.const_get(:NAME), "result: #{s.to_sxp}")
58
+ solutions << s
59
+ end
60
+ solutions
61
+ elsif object.first.variable?
62
+ # Solution binds indexes to all matching values
63
+ solutions = RDF::Query::Solutions.new
64
+ subject.each_with_index do |r, i|
65
+ next unless r == object.last
66
+ s = solution.merge(object.first.to_sym => RDF::Literal(i))
67
+ log_debug(self.class.const_get(:NAME), "result: #{s.to_sxp}")
68
+ solutions << s
69
+ end
70
+ solutions
71
+ elsif object.last.variable?
72
+ # Solution binds value at specified index
73
+ next unless v = subject.at(object.first)
74
+ s = solution.merge(object.last.to_sym => v)
75
+ log_debug(self.class.const_get(:NAME), "result: #{s.to_sxp}")
76
+ s
77
+ end
78
+ elsif object.variable?
79
+ # Create a solution for each index/value pair in subject
80
+ solutions = RDF::Query::Solutions.new
81
+ subject.each_with_index do |r, i|
82
+ s = solution.merge(object.to_sym => RDF::N3::List[RDF::Literal(i), r])
83
+ log_debug(self.class.const_get(:NAME), "result: #{s.to_sxp}")
84
+ solutions << s
85
+ end
86
+ solutions
87
+ else
88
+ # Evaluates to true if the subject has a matching entry
89
+ same = subject.at(object.first) == object.last
90
+ log_debug(self.class.const_get(:NAME), "result: #{same.inspect}")
91
+ solution if same
92
+ end
93
+ end.flatten.compact.uniq)
94
+ end
95
+ end
96
+ end
@@ -79,5 +79,18 @@ module RDF::N3::Algebra
79
79
  false
80
80
  end
81
81
  end
82
+
83
+ ##
84
+ # Returns a literal for the numeric argument.
85
+ def as_literal(object)
86
+ case object
87
+ when Float
88
+ literal = RDF::Literal(object, canonicalize: true)
89
+ literal.instance_variable_set(:@string, literal.to_s.downcase)
90
+ literal
91
+ else
92
+ RDF::Literal(object, canonicalize: true)
93
+ end
94
+ end
82
95
  end
83
96
  end
@@ -0,0 +1,41 @@
1
+ module RDF::N3::Algebra::Log
2
+ ##
3
+ # Takes a list of a string and an IRI and creates a datatyped literal.
4
+ class DtLit < RDF::N3::Algebra::ListOperator
5
+ NAME = :dtlit
6
+ URI = RDF::N3::Log.dtlit
7
+
8
+ ##
9
+ # Reads the subject into the object.
10
+ #
11
+ # Returns nil if resource does not validate, given its position
12
+ #
13
+ # @param [RDF::N3::List] resource
14
+ # @return [RDF::Term]
15
+ def resolve(resource, position: :subject)
16
+ case position
17
+ when :subject
18
+ RDF::Literal(as_literal(resource.first).to_s, datatype: resource.last)
19
+ when :object
20
+ return nil unless resource.literal? || resource.variable?
21
+ resource
22
+ end
23
+ end
24
+
25
+ def validate(list)
26
+ if super(list)
27
+ if list.length != 2
28
+ log_error(NAME) {"operand is not a list with two elements: #{list.to_sxp}"}
29
+ false
30
+ elsif !list.last.uri?
31
+ log_error(NAME) {"second component of subject must be an IRI: #{list.last.to_sxp}"}
32
+ false
33
+ else
34
+ true
35
+ end
36
+ else
37
+ false
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,41 @@
1
+ module RDF::N3::Algebra::Log
2
+ ##
3
+ # Takes a list of two strings creates a language-tagged literal.
4
+ class LangLit < RDF::N3::Algebra::ListOperator
5
+ NAME = :langlit
6
+ URI = RDF::N3::Log.langlit
7
+
8
+ ##
9
+ # Reads the subject into the object.
10
+ #
11
+ # Returns nil if resource does not validate, given its position
12
+ #
13
+ # @param [RDF::N3::List] resource
14
+ # @return [RDF::Term]
15
+ def resolve(resource, position: :subject)
16
+ case position
17
+ when :subject
18
+ RDF::Literal(as_literal(resource.first).to_s, language: resource.last.to_s.to_sym)
19
+ when :object
20
+ return nil unless resource.literal? || resource.variable?
21
+ resource
22
+ end
23
+ end
24
+
25
+ def validate(list)
26
+ if super(list)
27
+ if list.length != 2
28
+ log_error(NAME) {"operand is not a list with two elements: #{list.to_sxp}"}
29
+ false
30
+ elsif !list.last.to_s.match?(/^[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*$/)
31
+ log_warn(NAME) {"second component of subject should be BCP47 language tag: #{list.last.to_sxp}"}
32
+ false
33
+ else
34
+ true
35
+ end
36
+ else
37
+ false
38
+ end
39
+ end
40
+ end
41
+ end
@@ -49,7 +49,6 @@ module RDF::N3::Algebra
49
49
  res = apply(lhs, rhs)
50
50
  log_debug(self.class.const_get(:NAME), "result") {SXP::Generator.string(res.to_sxp_bin).strip}
51
51
  # Return the result applying subject and object
52
- #require 'byebug'; byebug
53
52
  case res
54
53
  when RDF::Literal::TRUE
55
54
  solution
@@ -19,6 +19,7 @@ module RDF::N3
19
19
  autoload :Append, 'rdf/n3/algebra/list/append'
20
20
  autoload :First, 'rdf/n3/algebra/list/first'
21
21
  autoload :In, 'rdf/n3/algebra/list/in'
22
+ autoload :Iterate, 'rdf/n3/algebra/list/iterate'
22
23
  autoload :Last, 'rdf/n3/algebra/list/last'
23
24
  autoload :Length, 'rdf/n3/algebra/list/length'
24
25
  autoload :Member, 'rdf/n3/algebra/list/member'
@@ -30,9 +31,11 @@ module RDF::N3
30
31
  autoload :Conclusion, 'rdf/n3/algebra/log/conclusion'
31
32
  autoload :Conjunction, 'rdf/n3/algebra/log/conjunction'
32
33
  autoload :Content, 'rdf/n3/algebra/log/content'
34
+ autoload :DtLit, 'rdf/n3/algebra/log/dtlit'
33
35
  autoload :EqualTo, 'rdf/n3/algebra/log/equal_to'
34
36
  autoload :Implies, 'rdf/n3/algebra/log/implies'
35
37
  autoload :Includes, 'rdf/n3/algebra/log/includes'
38
+ autoload :LangLit, 'rdf/n3/algebra/log/langlit'
36
39
  autoload :N3String, 'rdf/n3/algebra/log/n3_string'
37
40
  autoload :NotEqualTo, 'rdf/n3/algebra/log/not_equal_to'
38
41
  autoload :NotIncludes, 'rdf/n3/algebra/log/not_includes'
@@ -117,6 +120,7 @@ module RDF::N3
117
120
  RDF::N3::List.append => List.const_get(:Append),
118
121
  RDF::N3::List.first => List.const_get(:First),
119
122
  RDF::N3::List.in => List.const_get(:In),
123
+ RDF::N3::List.iterate => List.const_get(:Iterate),
120
124
  RDF::N3::List.last => List.const_get(:Last),
121
125
  RDF::N3::List.length => List.const_get(:Length),
122
126
  RDF::N3::List.member => List.const_get(:Member),
@@ -124,9 +128,11 @@ module RDF::N3
124
128
  RDF::N3::Log.conclusion => Log.const_get(:Conclusion),
125
129
  RDF::N3::Log.conjunction => Log.const_get(:Conjunction),
126
130
  RDF::N3::Log.content => Log.const_get(:Content),
131
+ RDF::N3::Log.dtlit => Log.const_get(:DtLit),
127
132
  RDF::N3::Log.equalTo => Log.const_get(:EqualTo),
128
133
  RDF::N3::Log.implies => Log.const_get(:Implies),
129
134
  RDF::N3::Log.includes => Log.const_get(:Includes),
135
+ RDF::N3::Log.langlit => Log.const_get(:LangLit),
130
136
  RDF::N3::Log.n3String => Log.const_get(:N3String),
131
137
  RDF::N3::Log.notEqualTo => Log.const_get(:NotEqualTo),
132
138
  RDF::N3::Log.notIncludes => Log.const_get(:NotIncludes),
@@ -33,8 +33,8 @@ module RDF
33
33
  # Returns an S-Expression (SXP) representation
34
34
  #
35
35
  # @return [String]
36
- def to_sxp
37
- to_a.to_sxp_bin.to_sxp
36
+ def to_sxp(**options)
37
+ to_a.to_sxp_bin.to_sxp(**options)
38
38
  end
39
39
  end
40
40
 
data/lib/rdf/n3/reader.rb CHANGED
@@ -12,7 +12,7 @@ module RDF::N3
12
12
  #
13
13
  # Separate pass to create branch_table from n3-selectors.n3
14
14
  #
15
- # This implementation uses distinguished variables for both universal and explicit existential variables (defined with `@forSome`). Variables created from blank nodes are non-distinguished. Distinguished existential variables are named using an `_ext` suffix, internally, as the RDF `query_pattern` logic looses details of the variable definition in solutions, where the variable is represented using a symbol.
15
+ # This implementation only supports quickVars at the document scope.
16
16
  #
17
17
  # Non-distinguished blank node variables are created as part of reasoning.
18
18
  #
@@ -200,7 +200,6 @@ module RDF::N3
200
200
  |<-|<=|=>|=
201
201
  | true|false
202
202
  | has|is|of
203
- |@forAll|@forSome
204
203
  )x)
205
204
 
206
205
  terminal(:PREFIX, PREFIX)
@@ -244,7 +243,6 @@ module RDF::N3
244
243
  def read_n3Statement
245
244
  prod(:n3Statement, %w{.}) do
246
245
  error("read_n3Doc", "Unexpected end of file") unless token = @lexer.first
247
- read_uniext ||
248
246
  read_triples ||
249
247
  error("Expected token", production: :statement, token: token)
250
248
  end
@@ -573,12 +571,6 @@ module RDF::N3
573
571
  formula_nodes[node] = true
574
572
  debug(:formula, depth: @options[:depth]) {"id: #{node}, depth: #{formulae.length}"}
575
573
 
576
- # Promote variables defined on the earlier formula to this formula
577
- variables[node] = {}
578
- variables.fetch(formulae[-2], {}).each do |name, var|
579
- variables[node][name] = var
580
- end
581
-
582
574
  read_formulaContent
583
575
 
584
576
  # Pop off the formula
@@ -664,54 +656,7 @@ module RDF::N3
664
656
  prod(:quickVar) do
665
657
  token = @lexer.shift
666
658
  value = token.value.sub('?', '')
667
- iri = ns(nil, "#{value}_quick")
668
- variables[nil][iri] ||= univar(iri, scope: nil)
669
- end
670
- end
671
- end
672
-
673
- ##
674
- # Read a list of IRIs
675
- #
676
- # [27] iriList ::= iri ( ',' iri )*
677
- #
678
- # @return [Array<RDF::URI>] the list of IRIs
679
- def read_irilist
680
- iris = []
681
- prod(:iriList, %{,}) do
682
- while iri = read_iri
683
- iris << iri
684
- break unless @lexer.first === ','
685
- @lexer.shift while @lexer.first === ','
686
- end
687
- end
688
- iris
689
- end
690
-
691
- ##
692
- # Read a univeral or existential
693
- #
694
- # Apart from the set of statements, a formula also has a set of URIs of symbols which are universally quantified,
695
- # and a set of URIs of symbols which are existentially quantified.
696
- # Variables are then in general symbols which have been quantified.
697
- #
698
- # Here we allocate a variable (making up a name) and record with the defining formula. Quantification is done
699
- # when the formula is completed against all in-scope variables
700
- #
701
- # [31] existential ::= '@forSome' iriList
702
- # [32] universal ::= '@forAll' iriList
703
- #
704
- # @return [void]
705
- def read_uniext
706
- if %w(@forSome @forAll).include?(@lexer.first.value)
707
- token = @lexer.shift
708
- prod(token === '@forAll' ? :universal : :existential) do
709
- iri_list = read_irilist
710
- iri_list.each do |iri|
711
- # Note, this might re-create an equivalent variable already defined in this formula, and replaces an equivalent variable that may have been defined in the parent formula.
712
- var = univar(iri, scope: formulae.last, existential: token === '@forSome')
713
- add_var_to_formula(formulae.last, iri, var)
714
- end
659
+ variables[value] ||= RDF::Query::Variable.new(value)
715
660
  end
716
661
  end
717
662
  end
@@ -786,10 +731,9 @@ module RDF::N3
786
731
  end
787
732
 
788
733
  # If not in ground formula, note scope, and if existential
789
- def univar(label, scope:, existential: false)
790
- value = existential ? "#{label}_ext" : label
791
- value = "#{value}#{scope.id}" if scope
792
- RDF::Query::Variable.new(value, existential: existential)
734
+ def univar(label, scope:)
735
+ value = label
736
+ RDF::Query::Variable.new(value)
793
737
  end
794
738
 
795
739
  # add a pattern or statement
@@ -865,20 +809,11 @@ module RDF::N3
865
809
  label
866
810
  end
867
811
 
868
- # Find any variable that may be defined in the formula identified by `bn`
812
+ # Find any variable that may be defined identified by `name`
869
813
  # @param [RDF::Node] name of formula
870
814
  # @return [RDF::Query::Variable]
871
815
  def find_var(name)
872
- (variables[@formulae.last] ||= {})[name.to_s]
873
- end
874
-
875
- # Add a variable to the formula identified by `bn`, returning the variable. Useful as an LRU for variable name lookups
876
- # @param [RDF::Node] bn name of formula
877
- # @param [#to_s] name of variable for lookup
878
- # @param [RDF::Query::Variable] var
879
- # @return [RDF::Query::Variable]
880
- def add_var_to_formula(bn, name, var)
881
- (variables[bn] ||= {})[name.to_s] = var
816
+ variables[name.to_s]
882
817
  end
883
818
 
884
819
  def prod(production, recover_to = [])
@@ -74,7 +74,5 @@ module RDF::N3
74
74
  WS = /(?:\s|(?:#[^\n\r]*))+/um.freeze
75
75
  # 162s
76
76
  ANON = /\[\s*\]/u.freeze
77
-
78
- FORALL = /@forAll/u.freeze
79
77
  end
80
78
  end
data/lib/rdf/n3/writer.rb CHANGED
@@ -273,13 +273,26 @@ module RDF::N3
273
273
  case literal
274
274
  when RDF::Literal
275
275
  case literal.valid? ? literal.datatype : false
276
- when RDF::XSD.boolean, RDF::XSD.integer, RDF::XSD.decimal
277
- literal.canonicalize.to_s
276
+ when RDF::XSD.boolean
277
+ %w(true false).include?(literal.value) ? literal.value : literal.canonicalize.to_s
278
+ when RDF::XSD.integer
279
+ literal.value.match?(/^[\+\-]?\d+$/) && !canonicalize? ? literal.value : literal.canonicalize.to_s
280
+ when RDF::XSD.decimal
281
+ literal.value.match?(/^[\+\-]?\d+\.\d+?$/) && !canonicalize? ?
282
+ literal.value :
283
+ literal.canonicalize.to_s
278
284
  when RDF::XSD.double
279
285
  if literal.nan? || literal.infinite?
280
286
  quoted(literal.value) + "^^#{format_uri(literal.datatype)}"
281
287
  else
282
- literal.canonicalize.to_s
288
+ in_form = case literal.value
289
+ when /[\+\-]?\d+\.\d*E[\+\-]?\d+$/i then true
290
+ when /[\+\-]?\.\d+E[\+\-]?\d+$/i then true
291
+ when /[\+\-]?\d+E[\+\-]?\d+$/i then true
292
+ else false
293
+ end && !canonicalize?
294
+
295
+ in_form ? literal.value : literal.canonicalize.to_s.sub('E', 'e')
283
296
  end
284
297
  else
285
298
  text = quoted(literal.value)
@@ -331,19 +344,6 @@ module RDF::N3
331
344
  prefixes.keys.sort_by(&:to_s).each do |prefix|
332
345
  @output.write("@prefix #{prefix}: <#{prefixes[prefix]}> .\n")
333
346
  end
334
-
335
- # Universals and extentials at top-level
336
- unless @universals.empty?
337
- log_debug("start_document: universals") { @universals.inspect}
338
- terms = @universals.map {|v| format_uri(RDF::URI(v.name.to_s))}
339
- @output.write("@forAll #{terms.join(', ')} .\n")
340
- end
341
-
342
- unless @existentials.empty?
343
- log_debug("start_document: existentials") { @existentials.inspect}
344
- terms = @existentials.map {|v| format_uri(RDF::URI(v.name.to_s.sub(/_ext$/, '')))}
345
- @output.write("@forSome #{terms.join(', ')} .\n")
346
- end
347
347
  end
348
348
 
349
349
  # Defines rdf:type of subjects to be emitted at the beginning of the graph. Defaults to rdfs:Class
@@ -424,10 +424,6 @@ module RDF::N3
424
424
 
425
425
  @options[:prefixes] = {} # Will define actual used when matched
426
426
  repo.each {|statement| preprocess_statement(statement)}
427
-
428
- vars = repo.enum_term.to_a.uniq.select {|r| r.is_a?(RDF::Query::Variable) && !r.to_s.end_with?('_quick')}
429
- @universals = vars.reject(&:existential?)
430
- @existentials = vars - @universals
431
427
  end
432
428
 
433
429
  # Perform any statement preprocessing required. This is used to perform reference counts and determine required
@@ -462,7 +458,6 @@ module RDF::N3
462
458
 
463
459
  # Reset internal helper instance variables
464
460
  def reset
465
- @universals, @existentials = [], []
466
461
  @lists = {}
467
462
  @references = {}
468
463
  @serialized = {}
@@ -521,11 +516,7 @@ module RDF::N3
521
516
  def p_term(resource, position)
522
517
  #log_debug("p_term") {"#{resource.to_sxp}, #{position}"}
523
518
  l = if resource.is_a?(RDF::Query::Variable)
524
- if resource.to_s.end_with?('_quick')
525
- '?' + RDF::URI(resource.name).fragment.sub(/_quick$/, '')
526
- else
527
- format_term(RDF::URI(resource.name.to_s.sub(/_ext$/, '')))
528
- end
519
+ "?#{resource.name}"
529
520
  elsif resource == RDF.nil
530
521
  "()"
531
522
  else
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rdf-n3
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.2
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gregg
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-12-25 00:00:00.000000000 Z
12
+ date: 2021-12-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ebnf
@@ -17,138 +17,126 @@ dependencies:
17
17
  requirements:
18
18
  - - "~>"
19
19
  - !ruby/object:Gem::Version
20
- version: '2.1'
20
+ version: '2.2'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - "~>"
26
26
  - !ruby/object:Gem::Version
27
- version: '2.1'
27
+ version: '2.2'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: rdf
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
32
  - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: '3.1'
35
- - - ">="
36
- - !ruby/object:Gem::Version
37
- version: 3.1.8
34
+ version: '3.2'
38
35
  type: :runtime
39
36
  prerelease: false
40
37
  version_requirements: !ruby/object:Gem::Requirement
41
38
  requirements:
42
39
  - - "~>"
43
40
  - !ruby/object:Gem::Version
44
- version: '3.1'
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: 3.1.8
41
+ version: '3.2'
48
42
  - !ruby/object:Gem::Dependency
49
43
  name: sparql
50
44
  requirement: !ruby/object:Gem::Requirement
51
45
  requirements:
52
46
  - - "~>"
53
47
  - !ruby/object:Gem::Version
54
- version: '3.1'
55
- - - ">="
56
- - !ruby/object:Gem::Version
57
- version: 3.1.4
48
+ version: '3.2'
58
49
  type: :runtime
59
50
  prerelease: false
60
51
  version_requirements: !ruby/object:Gem::Requirement
61
52
  requirements:
62
53
  - - "~>"
63
54
  - !ruby/object:Gem::Version
64
- version: '3.1'
65
- - - ">="
66
- - !ruby/object:Gem::Version
67
- version: 3.1.4
55
+ version: '3.2'
68
56
  - !ruby/object:Gem::Dependency
69
57
  name: sxp
70
58
  requirement: !ruby/object:Gem::Requirement
71
59
  requirements:
72
60
  - - "~>"
73
61
  - !ruby/object:Gem::Version
74
- version: '1.1'
62
+ version: '1.2'
75
63
  type: :runtime
76
64
  prerelease: false
77
65
  version_requirements: !ruby/object:Gem::Requirement
78
66
  requirements:
79
67
  - - "~>"
80
68
  - !ruby/object:Gem::Version
81
- version: '1.1'
69
+ version: '1.2'
82
70
  - !ruby/object:Gem::Dependency
83
71
  name: json-ld
84
72
  requirement: !ruby/object:Gem::Requirement
85
73
  requirements:
86
74
  - - "~>"
87
75
  - !ruby/object:Gem::Version
88
- version: '3.1'
76
+ version: '3.2'
89
77
  type: :development
90
78
  prerelease: false
91
79
  version_requirements: !ruby/object:Gem::Requirement
92
80
  requirements:
93
81
  - - "~>"
94
82
  - !ruby/object:Gem::Version
95
- version: '3.1'
83
+ version: '3.2'
96
84
  - !ruby/object:Gem::Dependency
97
85
  name: rdf-spec
98
86
  requirement: !ruby/object:Gem::Requirement
99
87
  requirements:
100
88
  - - "~>"
101
89
  - !ruby/object:Gem::Version
102
- version: '3.1'
90
+ version: '3.2'
103
91
  type: :development
104
92
  prerelease: false
105
93
  version_requirements: !ruby/object:Gem::Requirement
106
94
  requirements:
107
95
  - - "~>"
108
96
  - !ruby/object:Gem::Version
109
- version: '3.1'
97
+ version: '3.2'
110
98
  - !ruby/object:Gem::Dependency
111
99
  name: rdf-isomorphic
112
100
  requirement: !ruby/object:Gem::Requirement
113
101
  requirements:
114
102
  - - "~>"
115
103
  - !ruby/object:Gem::Version
116
- version: '3.1'
104
+ version: '3.2'
117
105
  type: :development
118
106
  prerelease: false
119
107
  version_requirements: !ruby/object:Gem::Requirement
120
108
  requirements:
121
109
  - - "~>"
122
110
  - !ruby/object:Gem::Version
123
- version: '3.1'
111
+ version: '3.2'
124
112
  - !ruby/object:Gem::Dependency
125
113
  name: rdf-trig
126
114
  requirement: !ruby/object:Gem::Requirement
127
115
  requirements:
128
116
  - - "~>"
129
117
  - !ruby/object:Gem::Version
130
- version: '3.1'
118
+ version: '3.2'
131
119
  type: :development
132
120
  prerelease: false
133
121
  version_requirements: !ruby/object:Gem::Requirement
134
122
  requirements:
135
123
  - - "~>"
136
124
  - !ruby/object:Gem::Version
137
- version: '3.1'
125
+ version: '3.2'
138
126
  - !ruby/object:Gem::Dependency
139
127
  name: rdf-vocab
140
128
  requirement: !ruby/object:Gem::Requirement
141
129
  requirements:
142
130
  - - "~>"
143
131
  - !ruby/object:Gem::Version
144
- version: '3.1'
132
+ version: '3.2'
145
133
  type: :development
146
134
  prerelease: false
147
135
  version_requirements: !ruby/object:Gem::Requirement
148
136
  requirements:
149
137
  - - "~>"
150
138
  - !ruby/object:Gem::Version
151
- version: '3.1'
139
+ version: '3.2'
152
140
  - !ruby/object:Gem::Dependency
153
141
  name: rspec
154
142
  requirement: !ruby/object:Gem::Requirement
@@ -208,6 +196,7 @@ files:
208
196
  - lib/rdf/n3/algebra/list/append.rb
209
197
  - lib/rdf/n3/algebra/list/first.rb
210
198
  - lib/rdf/n3/algebra/list/in.rb
199
+ - lib/rdf/n3/algebra/list/iterate.rb
211
200
  - lib/rdf/n3/algebra/list/last.rb
212
201
  - lib/rdf/n3/algebra/list/length.rb
213
202
  - lib/rdf/n3/algebra/list/member.rb
@@ -215,9 +204,11 @@ files:
215
204
  - lib/rdf/n3/algebra/log/conclusion.rb
216
205
  - lib/rdf/n3/algebra/log/conjunction.rb
217
206
  - lib/rdf/n3/algebra/log/content.rb
207
+ - lib/rdf/n3/algebra/log/dtlit.rb
218
208
  - lib/rdf/n3/algebra/log/equal_to.rb
219
209
  - lib/rdf/n3/algebra/log/implies.rb
220
210
  - lib/rdf/n3/algebra/log/includes.rb
211
+ - lib/rdf/n3/algebra/log/langlit.rb
221
212
  - lib/rdf/n3/algebra/log/n3_string.rb
222
213
  - lib/rdf/n3/algebra/log/not_equal_to.rb
223
214
  - lib/rdf/n3/algebra/log/not_includes.rb
@@ -305,14 +296,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
305
296
  requirements:
306
297
  - - ">="
307
298
  - !ruby/object:Gem::Version
308
- version: '2.4'
299
+ version: '2.6'
309
300
  required_rubygems_version: !ruby/object:Gem::Requirement
310
301
  requirements:
311
302
  - - ">="
312
303
  - !ruby/object:Gem::Version
313
304
  version: '0'
314
305
  requirements: []
315
- rubygems_version: 3.1.4
306
+ rubygems_version: 3.3.3
316
307
  signing_key:
317
308
  specification_version: 4
318
309
  summary: Notation3 reader/writer and reasoner for RDF.rb.