Skip to content

Commit 4a7a92d

Browse files
committed
Finish 3.0.4
2 parents a35d255 + 3b5bddc commit 4a7a92d

18 files changed

Lines changed: 147 additions & 29 deletions

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.0.3
1+
3.0.4

lib/rdf.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
require 'time'
55

66
require 'rdf/version'
7+
require 'rdf/extensions'
78

89
module RDF
910
# RDF mixins
@@ -197,7 +198,7 @@ def self.StrictVocabulary(prefix)
197198
# @return [#to_s] property
198199
# @return [URI]
199200
def self.[](property)
200-
property.to_s =~ %r{_\d+} ? RDF::URI("#{to_uri}#{property}") : RDF::RDFV[property]
201+
property.to_s.match?(%r{_\d+}) ? RDF::URI("#{to_uri}#{property}") : RDF::RDFV[property]
201202
end
202203

203204
##
@@ -227,7 +228,7 @@ def self.respond_to?(method, include_all = false)
227228
def self.method_missing(property, *args, &block)
228229
if args.empty?
229230
# Special-case rdf:_n for all integers
230-
RDF_N_REGEXP.match(property) ? RDF::URI("#{to_uri}#{property}") : RDF::RDFV.send(property)
231+
RDF_N_REGEXP.match?(property) ? RDF::URI("#{to_uri}#{property}") : RDF::RDFV.send(property)
231232
else
232233
super
233234
end

lib/rdf/extensions.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
##
2+
# This file provides compatibility monkeypatches to standard library classes
3+
# Implementation taken from MIT-licensed https://github.com/marcandre/backports
4+
#
5+
6+
# https://github.com/marcandre/backports/blob/master/lib/backports/2.4.0/regexp/match.rb
7+
unless Regexp.method_defined? :match?
8+
class Regexp
9+
def match?(*args)
10+
!match(*args).nil?
11+
end
12+
end
13+
end
14+
15+
# https://github.com/marcandre/backports/blob/master/lib/backports/2.4.0/string/match.rb
16+
unless String.method_defined? :match?
17+
class String
18+
def match?(*args)
19+
!match(*args).nil?
20+
end
21+
end
22+
end

lib/rdf/model/list.rb

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,12 @@ def list?
100100

101101
##
102102
# Validate the list ensuring that
103+
# * each node is referenced exactly once (except for the head, which may have no reference)
103104
# * rdf:rest values are all BNodes are nil
104105
# * each subject has exactly one value for `rdf:first` and
105106
# `rdf:rest`.
106107
# * The value of `rdf:rest` must be either a BNode or `rdf:nil`.
107-
# * All other properties are ignored.
108+
# * only the list head may have any other properties
108109
# @return [Boolean]
109110
def valid?
110111
li = subject
@@ -123,12 +124,25 @@ def valid?
123124
rest = st.object
124125
return false unless rest.node? || rest == RDF.nil
125126
rests += 1
127+
when RDF.type
128+
else
129+
# It may have no other properties
130+
return false unless li == subject
126131
end
127132
end
128133
return false unless firsts == 1 && rests == 1
129134
li = rest
130135
end
131-
true
136+
137+
# All elements other than the head must be referenced exactly once
138+
return list_nodes.all? do |li|
139+
refs = @graph.query(object: li).count
140+
case refs
141+
when 0 then li == subject
142+
when 1 then true
143+
else false
144+
end
145+
end
132146
end
133147

134148
# @!attribute [r] subject

lib/rdf/model/literal.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ def valid?
363363
return false if language? && language.to_s !~ /^[a-zA-Z]+(-[a-zA-Z0-9]+)*$/
364364
return false if datatype? && datatype.invalid?
365365
grammar = self.class.const_get(:GRAMMAR) rescue nil
366-
grammar.nil? || !!(value =~ grammar)
366+
grammar.nil? || value.match?(grammar)
367367
end
368368

369369
##

lib/rdf/model/uri.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1006,7 +1006,7 @@ def path
10061006
def path=(value)
10071007
if value
10081008
# Always lead with a slash
1009-
value = "/#{value}" if host && value.to_s =~ /^[^\/]/
1009+
value = "/#{value}" if host && value.to_s.match?(/^[^\/]/)
10101010
object[:path] = value.to_s.force_encoding(Encoding::UTF_8)
10111011
else
10121012
object[:path] = nil

lib/rdf/nquads.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class Format < RDF::Format
3636
# @param [String] sample Beginning several bytes (about 1K) of input.
3737
# @return [Boolean]
3838
def self.detect(sample)
39-
!!sample.match(%r(
39+
sample.match?(%r(
4040
(?:\s*(?:<[^>]*>) | (?:_:\w+)) # Subject
4141
\s*
4242
(?:\s*<[^>]*>) # Predicate
@@ -46,8 +46,8 @@ def self.detect(sample)
4646
(?:\s*(?:<[^>]*>) | (?:_:\w+)) # Graph Name
4747
\s*\.
4848
)x) && !(
49-
sample.match(%r(@(base|prefix|keywords)|\{)) || # Not Turtle/N3/TriG
50-
sample.match(%r(<(html|rdf))i) # Not HTML or XML
49+
sample.match?(%r(@(base|prefix|keywords)|\{)) || # Not Turtle/N3/TriG
50+
sample.match?(%r(<(html|rdf))i) # Not HTML or XML
5151
)
5252
end
5353

lib/rdf/ntriples/format.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,16 @@ class Format < RDF::Format
3232
# @param [String] sample Beginning several bytes (about 1K) of input.
3333
# @return [Boolean]
3434
def self.detect(sample)
35-
!!sample.match(%r(
35+
sample.match?(%r(
3636
(?:(?:<[^>]*>) | (?:_:\w+)) # Subject
3737
\s*
3838
(?:<[^>]*>) # Predicate
3939
\s*
4040
(?:(?:<[^>]*>) | (?:_:\w+) | (?:"[^"\n]*"(?:^^|@\S+)?)) # Object
4141
\s*\.
4242
)x) && !(
43-
sample.match(%r(@(base|prefix|keywords)|\{)) || # Not Turtle/N3/TriG
44-
sample.match(%r(<(html|rdf))i) # Not HTML or XML
43+
sample.match?(%r(@(base|prefix|keywords)|\{)) || # Not Turtle/N3/TriG
44+
sample.match?(%r(<(html|rdf))i) # Not HTML or XML
4545
) && !RDF::NQuads::Format.detect(sample)
4646
end
4747

lib/rdf/ntriples/reader.rb

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,22 +154,41 @@ def self.parse_literal(input, **options)
154154
end
155155
end
156156

157+
# cache constants to optimize escaping the escape chars in self.unescape
158+
ESCAPE_CHARS_ESCAPED = ESCAPE_CHARS.each_with_object({}) do |escape, memo|
159+
memo[escape.inspect[1...-1]] = escape
160+
end.freeze
161+
ESCAPE_CHARS_ESCAPED_REGEXP = Regexp.union(
162+
ESCAPE_CHARS_ESCAPED.keys
163+
).freeze
164+
157165
##
158166
# @param [String] string
159167
# @return [String]
160168
# @see http://www.w3.org/TR/rdf-testcases/#ntrip_strings
161169
# @see http://blog.grayproductions.net/articles/understanding_m17n
162170
# @see http://yehudakatz.com/2010/05/17/encodings-unabridged/
163171
def self.unescape(string)
164-
string = string.dup.force_encoding(Encoding::UTF_8)
172+
# Note: avoiding copying the input string when no escaping is needed
173+
# greatly reduces the number of allocations and the processing time.
174+
unless string.encoding == Encoding::UTF_8
175+
string = string.dup.force_encoding(Encoding::UTF_8)
176+
end
177+
178+
has_escape_chars = ESCAPE_CHARS_ESCAPED_REGEXP.match?(string)
179+
has_uchar = UCHAR.match?(string)
165180

166-
# Decode \t|\n|\r|\"|\\ character escapes:
167-
ESCAPE_CHARS.each { |escape| string.gsub!(escape.inspect[1...-1], escape) }
181+
string = string.dup if has_escape_chars || has_uchar
182+
183+
# Decode \t|\n|\r|\"|\\ character escapes using Regexp:
184+
string.gsub!(ESCAPE_CHARS_ESCAPED_REGEXP) do
185+
ESCAPE_CHARS_ESCAPED.fetch($~[0])
186+
end if has_escape_chars
168187

169188
# Decode \uXXXX and \UXXXXXXXX code points:
170189
string.gsub!(UCHAR) do
171190
[($1 || $2).hex].pack('U*')
172-
end
191+
end if has_uchar
173192

174193
string
175194
end

lib/rdf/ntriples/writer.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class Writer < RDF::Writer
5656
# @see http://www.w3.org/TR/rdf-testcases/#ntrip_strings
5757
def self.escape(string, encoding = nil)
5858
ret = case
59-
when string =~ ESCAPE_PLAIN # a shortcut for the simple case
59+
when string.match?(ESCAPE_PLAIN) # a shortcut for the simple case
6060
string
6161
when string.ascii_only?
6262
StringIO.open do |buffer|
@@ -164,7 +164,7 @@ def self.escape_utf32(u)
164164
# @return [String]
165165
# @raise [ArgumentError] if `value` is not an `RDF::Statement` or `RDF::Term`
166166
def self.serialize(value)
167-
writer = self.new
167+
writer = (@serialize_writer_memo ||= self.new)
168168
case value
169169
when nil then nil
170170
when FalseClass then value.to_s
@@ -256,7 +256,7 @@ def format_node(node, unique_bnodes: false, **options)
256256
def format_uri(uri, **options)
257257
string = uri.to_s
258258
iriref = case
259-
when string =~ ESCAPE_PLAIN_U # a shortcut for the simple case
259+
when string.match?(ESCAPE_PLAIN_U) # a shortcut for the simple case
260260
string
261261
when string.ascii_only? || (encoding && encoding != Encoding::ASCII)
262262
StringIO.open do |buffer|

0 commit comments

Comments
 (0)