Skip to content

Commit

Permalink
Finish 3.0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
gkellogg committed Sep 12, 2018
2 parents 5c83570 + 8cba4a4 commit 07e5c73
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 85 deletions.
2 changes: 1 addition & 1 deletion VERSION
@@ -1 +1 @@
3.0.0
3.0.1
41 changes: 29 additions & 12 deletions lib/rdf/n3/writer.rb
Expand Up @@ -273,8 +273,6 @@ def format_node(node, options = {})
protected
# Output @base and @prefix definitions
def start_document
@started = true

@output.write("#{indent}@base <#{base_uri}> .\n") unless base_uri.to_s.empty?

log_debug {"start_document: #{prefixes.inspect}"}
Expand Down Expand Up @@ -317,14 +315,24 @@ def order_subjects

# Add distinguished classes
top_classes.each do |class_uri|
graph.query(predicate: RDF.type, object: class_uri).map {|st| st.subject}.sort.uniq.each do |subject|
log_debug {"order_subjects: #{subject.inspect}"}
graph.query(predicate: RDF.type, object: class_uri).
map {|st| st.subject}.
sort.
uniq.
each do |subject|
log_debug("order_subjects") {subject.to_ntriples}
subjects << subject
seen[subject] = true
end
end
log_debug {"subjects2: #{subjects.inspect}"}


# Mark as seen lists that are part of another list
@lists.values.map(&:statements).
flatten.each do |st|
seen[st.object] if @lists.has_key?(st.object)
end

# Sort subjects by resources over bnodes, ref_counts and the subject URI itself
recursable = @subjects.keys.
select {|s| !seen.include?(s)}.
Expand Down Expand Up @@ -358,7 +366,17 @@ def preprocess_statement(statement)
references = ref_count(statement.object) + 1
@references[statement.object] = references
@subjects[statement.subject] = true


# Collect lists
if statement.predicate == RDF.first
@lists[statement.subject] = RDF::List.new(subject: statement.subject, graph: graph)
end

if statement.object == RDF.nil || statement.subject == RDF.nil
# Add an entry for the list tail
@lists[RDF.nil] ||= RDF::List[]
end

# Pre-fetch qnames, to fill prefixes
get_qname(statement.subject)
get_qname(statement.predicate)
Expand All @@ -385,12 +403,10 @@ def indent(modifier = 0)
def reset
@depth = 0
@lists = {}
@namespaces = {}

@references = {}
@serialized = {}
@subjects = {}
@shortNames = {}
@started = false
end

##
Expand All @@ -412,11 +428,11 @@ def quoted(string)
# Checks if l is a valid RDF list, i.e. no nodes have other properties.
def is_valid_list(l)
#log_debug {"is_valid_list: #{l.inspect}"}
return (l.node? && RDF::List.new(subject: l, graph: @graph).valid?) || l == RDF.nil
return @lists[l] && @lists[l].valid?
end

def do_list(l)
list = RDF::List.new(subject: l, graph: @graph)
list = @lists[l]
log_debug {"do_list: #{list.inspect}"}
position = :subject
list.each_statement do |st|
Expand Down Expand Up @@ -502,7 +518,8 @@ def predicate_list(subject)
properties[st.predicate.to_s] << st.object
end

prop_list = sort_properties(properties) - [RDF.first.to_s, RDF.rest.to_s]
prop_list = sort_properties(properties)
prop_list -= [RDF.first.to_s, RDF.rest.to_s] if subject.node?
log_debug {"predicate_list: #{prop_list.inspect}"}
return if prop_list.empty?

Expand Down
1 change: 0 additions & 1 deletion rdf-n3.gemspec
Expand Up @@ -17,7 +17,6 @@ Gem::Specification.new do |gem|
gem.platform = Gem::Platform::RUBY
gem.files = %w(README.md History.markdown AUTHORS VERSION UNLICENSE) + Dir.glob('lib/**/*.rb')
gem.require_paths = %w(lib)
gem.has_rdoc = false

gem.required_ruby_version = '>= 2.2.2'
gem.requirements = []
Expand Down
60 changes: 9 additions & 51 deletions spec/matchers.rb
@@ -1,57 +1,15 @@
require 'rdf/isomorphic'

# Don't use be_equivalent_graph from rdf/spec because of odd N3 semantics
Info = Struct.new(:about, :logger, :inputDocument, :outputDocument, :format)

RSpec::Matchers.define :be_equivalent_graph do |expected, info|
# coding: utf-8
RSpec::Matchers.define :match_re do |expected, info|
match do |actual|
def normalize(graph)
case graph
when RDF::Enumerable then graph
when IO, StringIO
RDF::Repository.new.load(graph, base_uri: @info.about)
else
# Figure out which parser to use
g = RDF::Repository.new
reader_class = RDF::Reader.for(detect_format(graph))
reader_class.new(graph, base_uri: @info.about).each {|s| g << s}
g
end
end

@info = if info.respond_to?(:about)
info
elsif info.is_a?(Logger)
Info.new("", info)
elsif info.is_a?(Hash)
Info.new(info[:about], info[:logger])
else
Info.new(expected.is_a?(RDF::Graph) ? expected.graph_name : info, info.to_s)
end
@info.format ||= :n3
@expected = normalize(expected)
@actual = normalize(actual)
@actual.isomorphic_with?(@expected) rescue false
actual.to_s.match(expected)
end

failure_message do |actual|
trace = case @info.logger
when Logger then @info.logger.to_s
when Array then @info.logger.join("\n")
end
info = @info.respond_to?(:about) ? @info.about : @info.inspect
if @expected.is_a?(RDF::Enumerable) && @actual.size != @expected.size
"Graph entry count differs:\nexpected: #{@expected.size}\nactual: #{@actual.size}"
elsif @expected.is_a?(Array) && @actual.size != @expected.length
"Graph entry count differs:\nexpected: #{@expected.length}\nactual: #{@actual.size}"
else
"Graph differs"
end +
"\n#{info + "\n" unless info.to_s.empty?}" +
(@info.inputDocument ? "Input file: #{@info.inputDocument}\n" : "") +
(@info.outputDocument ? "Output file: #{@info.outputDocument}\n" : "") +
"Expected:\n#{@expected.dump(@info.format, standard_prefixes: true)}" +
"Results:\n#{@actual.dump(@info.format, standard_prefixes: true)}" +
(trace ? "\nDebug:\n#{trace}" : "")
"Match failed\n" +
"#{info[:about]}\n" +
"Input file:\n#{info[:input]}\n" +
"Result:\n#{actual}\n" +
"Expression: #{expected}\n" +
"Debug:\n#{info[:trace]}"
end
end
45 changes: 29 additions & 16 deletions spec/reader_spec.rb
Expand Up @@ -263,7 +263,8 @@
}.each_pair do |name, statement|
specify "test #{name}" do
graph = parse([statement].flatten.first)
expect(graph).to be_equivalent_graph([statement].flatten.last, about: "http://a/b", logger: logger)
g2 = RDF::NTriples::Reader.new([statement].flatten.last)
expect(graph).to be_equivalent_graph(g2, about: "http://a/b", logger: logger)
end
end

Expand Down Expand Up @@ -438,7 +439,8 @@
%(:a :b 1.0E1) => %(<http://a/b#a> <http://a/b#b> "1.0E1"^^<http://www.w3.org/2001/XMLSchema#double> .),
}.each_pair do |n3, nt|
it "should create typed literal for '#{n3}'" do
expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(nt, about: "http://a/b", logger: logger)
expected = RDF::NTriples::Reader.new(nt)
expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(expected, about: "http://a/b", logger: logger)
end
end

Expand Down Expand Up @@ -635,7 +637,8 @@
%(@keywords has. :a has :b :c.) => %(<http://a/b#a> <http://a/b#b> <http://a/b#c> .),
} .each_pair do |n3, nt|
it "should use keyword for '#{n3}'" do
expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(nt, about: "http://a/b", logger: logger)
expected = RDF::NTriples::Reader.new(nt)
expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(expected, about: "http://a/b", logger: logger)
end
end

Expand Down Expand Up @@ -708,9 +711,9 @@

it "should create BNode for [] as predicate" do
n3 = %(@prefix a: <http://foo/a#> . a:s [] a:o .)
nt = %(<http://foo/a#s> _:bnode0 <http://foo/a#o> .)
g = parse(n3, base_uri: "http://a/b")
expect(g).to be_equivalent_graph(nt, about: "http://a/b", logger: logger)
st = g.statements.first
expect(st.predicate).to be_a_node
end

it "should create BNode for [] as object" do
Expand Down Expand Up @@ -757,7 +760,8 @@
_:bnode0 <http://foo/a#qq> "2" .
_:a :pred _:bnode0 .
)
expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(nt, about: "http://a/b", logger: logger)
expected = RDF::Graph.new {|g| g << RDF::N3::Reader.new(nt, base_uri: "http://a/b")}
expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(expected, about: "http://a/b", logger: logger)
end

it "should create nested BNodes" do
Expand All @@ -780,14 +784,16 @@
describe "from paths" do
it "should create bnode for path x!p" do
n3 = %(:x2!:y2 :p2 "3" .)
nt = %(:x2 :y2 _:bnode0 . _:bnode0 :p2 "3" .)
expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(nt, about: "http://a/b", logger: logger)
nt = %(:x2 :y2 _:bnode0 ._:bnode0 :p2 "3" .)
expected = RDF::Graph.new {|g| g << RDF::N3::Reader.new(nt, base_uri: "http://a/b")}
expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(expected, about: "http://a/b", logger: logger)
end

it "should create bnode for path x^p" do
n3 = %(:x2^:y2 :p2 "3" .)
nt = %(_:bnode0 :y2 :x2 . _:bnode0 :p2 "3" .)
expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(nt, about: "http://a/b", logger: logger)
expected = RDF::Graph.new {|g| g << RDF::N3::Reader.new(nt, base_uri: "http://a/b")}
expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(expected, about: "http://a/b", logger: logger)
end

it "should decode :joe!fam:mother!loc:office!loc:zip as Joe's mother's office's zipcode" do
Expand All @@ -802,7 +808,8 @@
_:bnode0 <http://foo/loc#office> _:bnode1 .
_:bnode1 <http://foo/loc#zip> _:bnode2 .
)
expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(nt, about: "http://a/b", logger: logger)
expected = RDF::Graph.new {|g| g << RDF::N3::Reader.new(nt, base_uri: "http://a/b")}
expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(expected, about: "http://a/b", logger: logger)
end

it "should decode :joe!fam:mother^fam:mother Anyone whose mother is Joe's mother." do
Expand All @@ -816,7 +823,8 @@
:joe <http://foo/fam#mother> _:bnode0 .
_:bnode1 <http://foo/fam#mother> _:bnode0 .
)
expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(nt, about: "http://a/b", logger: logger)
expected = RDF::Graph.new {|g| g << RDF::N3::Reader.new(nt, base_uri: "http://a/b")}
expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(expected, about: "http://a/b", logger: logger)
end

it "should decode path with property list." do
Expand All @@ -831,7 +839,8 @@
_:bnode1 :q2 "4" .
_:bnode1 :q2 "5" .
)
expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(nt, about: "http://a/b", logger: logger)
expected = RDF::Graph.new {|g| g << RDF::N3::Reader.new(nt, base_uri: "http://a/b")}
expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(expected, about: "http://a/b", logger: logger)
end

it "should decode path as object(1)" do
Expand All @@ -840,7 +849,8 @@
:a :b _:bnode .
_:bnode :c "lit" .
)
expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(nt, about: "http://a/b", logger: logger)
expected = RDF::Graph.new {|g| g << RDF::N3::Reader.new(nt, base_uri: "http://a/b")}
expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(expected, about: "http://a/b", logger: logger)
end

it "should decode path as object(2)" do
Expand All @@ -850,7 +860,8 @@
_:bnode0 <http://a/ns#p2> _:bnode1 .
:r :p _:bnode1 .
)
expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(nt, about: "http://a/b", logger: logger)
expected = RDF::Graph.new {|g| g << RDF::N3::Reader.new(nt, base_uri: "http://a/b")}
expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(expected, about: "http://a/b", logger: logger)
end
end
end
Expand Down Expand Up @@ -920,7 +931,8 @@
it "should create 2 statements for simple list" do
n3 = %(:a :b :c, :d)
nt = %(<http://a/b#a> <http://a/b#b> <http://a/b#c> . <http://a/b#a> <http://a/b#b> <http://a/b#d> .)
expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(nt, about: "http://a/b", logger: logger)
expected = RDF::Graph.new {|g| g << RDF::N3::Reader.new(nt, base_uri: "http://a/b")}
expect(parse(n3, base_uri: "http://a/b")).to be_equivalent_graph(expected, about: "http://a/b", logger: logger)
end
end

Expand Down Expand Up @@ -1167,7 +1179,8 @@
it "returns object #{result} given #{input}" do
n3 = %(@prefix xsd: <http://www.w3.org/2001/XMLSchema#> . :a :b #{input} .)
nt = %(<http://a/b#a> <http://a/b#b> #{result} .)
expect(parse(n3, base_uri: "http://a/b", canonicalize: true)).to be_equivalent_graph(nt, about: "http://a/b", logger: logger)
expected = RDF::Graph.new {|g| g << RDF::N3::Reader.new(nt, base_uri: "http://a/b")}
expect(parse(n3, base_uri: "http://a/b", canonicalize: true)).to be_equivalent_graph(expected, about: "http://a/b", logger: logger)
end
end
end
Expand Down
29 changes: 25 additions & 4 deletions spec/writer_spec.rb
Expand Up @@ -6,8 +6,6 @@
describe RDF::N3::Writer do
let(:logger) {RDF::Spec.logger}

after(:each) {|example| puts logger.to_s if example.exception}

it_behaves_like 'an RDF::Writer' do
let(:writer) {RDF::N3::Writer.new(StringIO.new)}
end
Expand Down Expand Up @@ -265,6 +263,27 @@
)
#$verbose = false
end

it "should generate list with first subject a URI" do
input = %(
<http://example.com> <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1"^^<http://www.w3.org/2001/XMLSchema#integer> .
<http://example.com> <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:g47006741228480 .
_:g47006741228480 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2"^^<http://www.w3.org/2001/XMLSchema#integer> .
_:g47006741228480 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:g47006737917560 .
_:g47006737917560 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "3"^^<http://www.w3.org/2001/XMLSchema#integer> .
_:g47006737917560 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
)
#$verbose = true
serialize(input, nil,
[
%r(@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> \.),
%r(<http://example.com> rdf:first 1;),
%r(rdf:rest \(2 3\) \.),
],
standard_prefixes: true
)
#$verbose = false
end
end

describe "literals" do
Expand Down Expand Up @@ -415,7 +434,7 @@ def parse(input, options = {})
# Serialize ntstr to a string and compare against regexps
def serialize(ntstr, base = nil, regexps = [], options = {})
prefixes = options[:prefixes] || {}
g = parse(ntstr, base_uri: base, prefixes: prefixes)
g = ntstr.is_a?(RDF::Enumerable) ? ntstr : parse(ntstr, base_uri: base, prefixes: prefixes, validate: false, logger: [])
result = RDF::N3::Writer.buffer(options.merge(logger: logger, base_uri: base, prefixes: prefixes)) do |writer|
writer << g
end
Expand All @@ -424,8 +443,10 @@ def serialize(ntstr, base = nil, regexps = [], options = {})
#puts CGI.escapeHTML(result)
end

logger.info "result: #{result}"
regexps.each do |re|
expect(result).to match re
logger.info "match: #{re.inspect}"
expect(result).to match_re(re, about: base, logger: logger, input: ntstr), logger.to_s
end

result
Expand Down

0 comments on commit 07e5c73

Please sign in to comment.