json-ld 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/History.markdown +3 -0
  2. data/VERSION +1 -1
  3. data/bin/jsonld +134 -0
  4. data/lib/json/ld/api.rb +4 -4
  5. data/lib/json/ld/frame.rb +2 -1
  6. data/lib/json/ld/from_rdf.rb +1 -1
  7. data/spec/api_spec.rb +66 -0
  8. data/spec/compact_spec.rb +420 -0
  9. data/spec/evaluation_context_spec.rb +1039 -0
  10. data/spec/expand_spec.rb +625 -0
  11. data/spec/format_spec.rb +71 -0
  12. data/spec/frame_spec.rb +542 -0
  13. data/spec/from_rdf_spec.rb +316 -0
  14. data/spec/matchers.rb +67 -0
  15. data/spec/reader_spec.rb +79 -0
  16. data/spec/spec_helper.rb +56 -0
  17. data/spec/suite_helper.rb +184 -0
  18. data/spec/suite_spec.rb +104 -0
  19. data/spec/support/extensions.rb +10 -0
  20. data/spec/test-files/test-1-automatic.json +10 -0
  21. data/spec/test-files/test-1-compacted.json +10 -0
  22. data/spec/test-files/test-1-context.json +7 -0
  23. data/spec/test-files/test-1-expanded.json +5 -0
  24. data/spec/test-files/test-1-input.json +10 -0
  25. data/spec/test-files/test-1-normalized.json +8 -0
  26. data/spec/test-files/test-1-rdf.ttl +7 -0
  27. data/spec/test-files/test-2-automatic.json +27 -0
  28. data/spec/test-files/test-2-compacted.json +20 -0
  29. data/spec/test-files/test-2-context.json +7 -0
  30. data/spec/test-files/test-2-expanded.json +16 -0
  31. data/spec/test-files/test-2-input.json +20 -0
  32. data/spec/test-files/test-2-normalized.json +32 -0
  33. data/spec/test-files/test-2-rdf.ttl +14 -0
  34. data/spec/test-files/test-3-compacted.json +11 -0
  35. data/spec/test-files/test-3-context.json +8 -0
  36. data/spec/test-files/test-3-expanded.json +10 -0
  37. data/spec/test-files/test-3-input.json +11 -0
  38. data/spec/test-files/test-3-normalized.json +13 -0
  39. data/spec/test-files/test-3-rdf.ttl +7 -0
  40. data/spec/test-files/test-4-automatic.json +10 -0
  41. data/spec/test-files/test-4-compacted.json +10 -0
  42. data/spec/test-files/test-4-context.json +7 -0
  43. data/spec/test-files/test-4-expanded.json +6 -0
  44. data/spec/test-files/test-4-input.json +10 -0
  45. data/spec/test-files/test-4-rdf.ttl +5 -0
  46. data/spec/test-files/test-5-automatic.json +13 -0
  47. data/spec/test-files/test-5-compacted.json +13 -0
  48. data/spec/test-files/test-5-context.json +7 -0
  49. data/spec/test-files/test-5-expanded.json +9 -0
  50. data/spec/test-files/test-5-input.json +13 -0
  51. data/spec/test-files/test-5-rdf.ttl +6 -0
  52. data/spec/test-files/test-6-automatic.json +10 -0
  53. data/spec/test-files/test-6-compacted.json +10 -0
  54. data/spec/test-files/test-6-context.json +7 -0
  55. data/spec/test-files/test-6-expanded.json +10 -0
  56. data/spec/test-files/test-6-input.json +10 -0
  57. data/spec/test-files/test-6-rdf.ttl +5 -0
  58. data/spec/test-files/test-7-automatic.json +20 -0
  59. data/spec/test-files/test-7-compacted.json +23 -0
  60. data/spec/test-files/test-7-context.json +4 -0
  61. data/spec/test-files/test-7-expanded.json +20 -0
  62. data/spec/test-files/test-7-input.json +23 -0
  63. data/spec/test-files/test-7-rdf.ttl +13 -0
  64. data/spec/test-files/test-8-automatic.json +1 -0
  65. data/spec/test-files/test-8-compacted.json +34 -0
  66. data/spec/test-files/test-8-context.json +11 -0
  67. data/spec/test-files/test-8-expanded.json +24 -0
  68. data/spec/test-files/test-8-frame.json +18 -0
  69. data/spec/test-files/test-8-framed.json +29 -0
  70. data/spec/test-files/test-8-input.json +30 -0
  71. data/spec/test-files/test-8-rdf.ttl +15 -0
  72. data/spec/test-files/test-9-compacted.json +20 -0
  73. data/spec/test-files/test-9-context.json +13 -0
  74. data/spec/test-files/test-9-expanded.json +14 -0
  75. data/spec/test-files/test-9-input.json +12 -0
  76. data/spec/to_rdf_spec.rb +640 -0
  77. data/spec/writer_spec.rb +161 -0
  78. metadata +150 -22
@@ -0,0 +1,56 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $:.unshift File.dirname(__FILE__)
3
+
4
+ require "bundler/setup"
5
+ require 'rspec'
6
+ require 'rdf'
7
+ require 'rdf/isomorphic'
8
+ require 'json/ld'
9
+ require 'rdf/nquads'
10
+ require 'rdf/turtle'
11
+ require 'rdf/trig'
12
+ require 'rdf/spec'
13
+ require 'rdf/spec/matchers'
14
+ require 'yaml'
15
+ require 'open-uri/cached'
16
+ require 'matchers'
17
+
18
+ JSON_STATE = JSON::State.new(
19
+ :indent => " ",
20
+ :space => " ",
21
+ :space_before => "",
22
+ :object_nl => "\n",
23
+ :array_nl => "\n"
24
+ )
25
+
26
+ # Create and maintain a cache of downloaded URIs
27
+ URI_CACHE = File.expand_path(File.join(File.dirname(__FILE__), "uri-cache"))
28
+ Dir.mkdir(URI_CACHE) unless File.directory?(URI_CACHE)
29
+ OpenURI::Cache.class_eval { @cache_path = URI_CACHE }
30
+
31
+ ::RSpec.configure do |c|
32
+ c.filter_run :focus => true
33
+ c.run_all_when_everything_filtered = true
34
+ c.exclusion_filter = {
35
+ :ruby => lambda { |version| !(RUBY_VERSION.to_s =~ /^#{version.to_s}/) },
36
+ }
37
+ c.include(RDF::Spec::Matchers)
38
+ end
39
+
40
+ # Heuristically detect the input stream
41
+ def detect_format(stream)
42
+ # Got to look into the file to see
43
+ if stream.is_a?(IO) || stream.is_a?(StringIO)
44
+ stream.rewind
45
+ string = stream.read(1000)
46
+ stream.rewind
47
+ else
48
+ string = stream.to_s
49
+ end
50
+ case string
51
+ when /<html/i then RDF::RDFa::Reader
52
+ when /\{\s*\"@\"/i then JSON::LD::Reader
53
+ else RDF::Turtle::Reader
54
+ end
55
+ end
56
+
@@ -0,0 +1,184 @@
1
+ # Spira class for manipulating test-manifest style test suites.
2
+ # Used for SWAP tests
3
+ require 'spira'
4
+ require 'json/ld'
5
+ require 'open-uri'
6
+ require 'support/extensions'
7
+
8
+ # For now, override RDF::Utils::File.open_file to look for the file locally before attempting to retrieve it
9
+ module RDF::Util
10
+ module File
11
+ REMOTE_PATH = "http://json-ld.org/test-suite/"
12
+ LOCAL_PATH = ::File.expand_path("../json-ld.org/test-suite", __FILE__) + '/'
13
+
14
+ ##
15
+ # Override to use Patron for http and https, Kernel.open otherwise.
16
+ #
17
+ # @param [String] filename_or_url to open
18
+ # @param [Hash{Symbol => Object}] options
19
+ # @option options [Array, String] :headers
20
+ # HTTP Request headers.
21
+ # @return [IO] File stream
22
+ # @yield [IO] File stream
23
+ def self.open_file(filename_or_url, options = {}, &block)
24
+ case filename_or_url.to_s
25
+ when /^file:/
26
+ path = filename_or_url[5..-1]
27
+ Kernel.open(path.to_s, &block)
28
+ when /^#{REMOTE_PATH}/
29
+ #puts "attempt to open #{filename_or_url} locally"
30
+ if response = ::File.open(filename_or_url.to_s.sub(REMOTE_PATH, LOCAL_PATH))
31
+ #puts "use #{filename_or_url} locally"
32
+ case filename_or_url.to_s
33
+ when /\.jsonld$/
34
+ def response.content_type; 'application/ld+json'; end
35
+ when /\.sparql$/
36
+ def response.content_type; 'application/sparql-query'; end
37
+ end
38
+
39
+ if block_given?
40
+ begin
41
+ yield response
42
+ ensure
43
+ response.close
44
+ end
45
+ else
46
+ response
47
+ end
48
+ else
49
+ Kernel.open(filename_or_url.to_s, &block)
50
+ end
51
+ else
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ module Fixtures
58
+ module JSONLDTest
59
+ SUITE = RDF::URI("http://json-ld.org/test-suite/")
60
+ class Test < RDF::Vocabulary("http://www.w3.org/2006/03/test-description#"); end
61
+ class Jld < RDF::Vocabulary("http://json-ld.org/test-suite/vocab#"); end
62
+
63
+ class Manifest < Spira::Base
64
+ type Jld.Manifest
65
+ property :name, :predicate => RDF::DC.title, :type => XSD.string
66
+ property :comment, :predicate => RDF::RDFS.comment, :type => XSD.string
67
+ property :sequence, :predicate => Jld.sequence
68
+
69
+ def entries
70
+ @entries ||= begin
71
+ repo = self.class.repository
72
+ RDF::List.new(sequence, repo).map do |entry|
73
+ results = repo.query(:subject => entry, :predicate => RDF.type)
74
+ entry_types = results.map(&:object)
75
+
76
+ # Load entry if it is not in repo
77
+ if entry_types.empty?
78
+ repo.load(entry, :format => :jsonld)
79
+ entry_types = repo.query(:subject => entry, :predicate => RDF.type).map(&:object)
80
+ end
81
+
82
+ case
83
+ when entry_types.include?(Jld.Manifest) then entry.as(Manifest)
84
+ when entry_types.include?(Jld.CompactTest) then entry.as(CompactTest)
85
+ when entry_types.include?(Jld.ExpandTest) then entry.as(ExpandTest)
86
+ when entry_types.include?(Jld.FrameTest) then entry.as(FrameTest)
87
+ when entry_types.include?(Jld.NormalizeTest) then entry.as(NormalizeTest)
88
+ when entry_types.include?(Jld.ToRDFTest) then entry.as(ToRDFTest)
89
+ when entry_types.include?(Jld.FromRDFTest) then entry.as(FromRDFTest)
90
+ when entry_types.include?(Test.TestCase) then entry.as(Entry)
91
+ else raise "Unexpected entry type: #{entry_types.inspect}"
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ def inspect
98
+ "[#{self.class.to_s} " + %w(
99
+ subject
100
+ name
101
+ ).map {|a| v = self.send(a); "#{a}='#{v}'" if v}.compact.join(", ") +
102
+ ", entries=#{entries.length}" +
103
+ "]"
104
+ end
105
+ end
106
+
107
+ class Entry
108
+ attr_accessor :debug
109
+ include Spira::Resource
110
+ type Test.TestCase
111
+
112
+ property :name, :predicate => RDF::DC.title, :type => XSD.string
113
+ property :purpose, :predicate => Test.purpose, :type => XSD.string
114
+ property :expected, :predicate => Test.expectedResults
115
+ property :inputDocument, :predicate => Test.informationResourceInput
116
+ property :resultDocument, :predicate => Test.informationResourceResults
117
+ property :extraDocument, :predicate => Test.input
118
+
119
+ def information; name; end
120
+
121
+ def input
122
+ RDF::Util::File.open_file(self.inputDocument)
123
+ end
124
+
125
+ def extra
126
+ RDF::Util::File.open_file(self.extraDocument)
127
+ end
128
+
129
+ def expect
130
+ RDF::Util::File.open_file(self.resultDocument)
131
+ end
132
+
133
+ def base_uri
134
+ inputDocument.to_s
135
+ end
136
+
137
+ def trace
138
+ @debug.to_a.join("\n")
139
+ end
140
+
141
+ def inspect
142
+ "[#{self.class.to_s} " + %w(
143
+ subject
144
+ name
145
+ inputDocument
146
+ resultDocument
147
+ extraDocument
148
+ ).map {|a| v = self.send(a); "#{a}='#{v}'" if v}.compact.join(", ") +
149
+ "]"
150
+ end
151
+ end
152
+
153
+ class CompactTest < Entry
154
+ type Jld.CompactTest
155
+ end
156
+
157
+ class ExpandTest < Entry
158
+ type Jld.ExpandTest
159
+ end
160
+
161
+ class FrameTest < Entry
162
+ type Jld.FameTest
163
+ end
164
+
165
+ class NormalizeTest < Entry
166
+ type Jld.NormalizeTest
167
+ end
168
+
169
+ class FromRDFTest < Entry
170
+ type Jld.FromRDFTest
171
+ end
172
+
173
+ class ToRDFTest < Entry
174
+ type Jld.ToRDFTest
175
+
176
+ def quads
177
+ RDF::Util::File.open_file(self.expected)
178
+ end
179
+ end
180
+
181
+ repo = RDF::Repository.load(SUITE.join("manifest.jsonld"), :format => :jsonld)
182
+ Spira.add_repository! :default, repo
183
+ end
184
+ end
@@ -0,0 +1,104 @@
1
+ # coding: utf-8
2
+ $:.unshift "."
3
+ require 'spec_helper'
4
+
5
+ describe JSON::LD do
6
+ describe "test suite" do
7
+ require 'suite_helper'
8
+
9
+ m = Fixtures::JSONLDTest::Manifest.each.to_a.first
10
+ describe m.name do
11
+ m.entries.each do |m2|
12
+ describe m2.name do
13
+ m2.entries.each do |t|
14
+ next if t.is_a?(Fixtures::JSONLDTest::NormalizeTest)
15
+ specify "#{File.basename(t.inputDocument.to_s)}: #{t.name}" do
16
+ begin
17
+ t.debug = ["test: #{t.inspect}", "source: #{t.input.read}"]
18
+ case t
19
+ when Fixtures::JSONLDTest::CompactTest
20
+ t.debug << "context: #{t.extra.read}" if t.extraDocument
21
+ result = JSON::LD::API.compact(t.input, t.extra, nil,
22
+ :base => t.base_uri,
23
+ :debug => t.debug)
24
+ expected = JSON.load(t.expect)
25
+ result.should produce(expected, t.debug)
26
+ when Fixtures::JSONLDTest::ExpandTest
27
+ t.debug << "context: #{t.extra.read}" if t.extraDocument
28
+ result = JSON::LD::API.expand(t.input, nil, nil,
29
+ :base => t.base_uri,
30
+ :debug => t.debug)
31
+ expected = JSON.load(t.expect)
32
+ result.should produce(expected, t.debug)
33
+ when Fixtures::JSONLDTest::FrameTest
34
+ t.debug << "frame: #{t.extra.read}" if t.extraDocument
35
+ result = JSON::LD::API.frame(t.input, t.extra, nil,
36
+ :base => t.inputDocument,
37
+ :debug => t.debug)
38
+ expected = JSON.load(t.expect)
39
+ result.should produce(expected, t.debug)
40
+ when Fixtures::JSONLDTest::FromRDFTest
41
+ repo = RDF::Repository.load(t.inputDocument)
42
+ result = JSON::LD::API.fromRDF(repo.each_statement.to_a, nil,
43
+ :debug => t.debug)
44
+ expected = JSON.load(t.expect)
45
+ result.should produce(expected, t.debug)
46
+ when Fixtures::JSONLDTest::ToRDFTest
47
+ quads = []
48
+ JSON::LD::API.toRDF(t.input, nil, nil,
49
+ :base => t.inputDocument,
50
+ :debug => t.debug) do |statement|
51
+ quads << to_quad(statement)
52
+ end
53
+
54
+ quads.sort.join("").should produce(t.expect.read, t.debug)
55
+ else
56
+ pending("unkown test type #{t.inspect}")
57
+ end
58
+ rescue JSON::LD::ProcessingError => e
59
+ fail("Processing error: #{e.message}")
60
+ rescue JSON::LD::InvalidContext => e
61
+ fail("Invalid Context: #{e.message}")
62
+ rescue JSON::LD::InvalidFrame => e
63
+ fail("Invalid Frame: #{e.message}")
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ # Don't use NQuads writer so that we don't escape Unicode
73
+ def to_quad(thing)
74
+ case thing
75
+ when RDF::URI
76
+ "<#{escaped(thing.to_s)}>"
77
+ when RDF::Node
78
+ escaped(thing.to_s)
79
+ when RDF::Literal::Double
80
+ quoted("%1.15e" % thing.value) + "^^<#{RDF::XSD.double}>"
81
+ when RDF::Literal
82
+ quoted(escaped(thing.value)) +
83
+ (thing.datatype? ? "^^<#{thing.datatype}>" : "") +
84
+ (thing.language? ? "@#{thing.language}" : "")
85
+ when RDF::Statement
86
+ thing.to_quad.map {|r| to_quad(r)}.compact.join(" ") + " .\n"
87
+ end
88
+ end
89
+
90
+ ##
91
+ # @param [String] string
92
+ # @return [String]
93
+ def quoted(string)
94
+ "\"#{string}\""
95
+ end
96
+
97
+ ##
98
+ # @param [String] string
99
+ # @return [String]
100
+ def escaped(string)
101
+ string.gsub('\\', '\\\\').gsub("\t", '\\t').
102
+ gsub("\n", '\\n').gsub("\r", '\\r').gsub('"', '\\"')
103
+ end
104
+ end
@@ -0,0 +1,10 @@
1
+ class Hash
2
+ def diff(other)
3
+ self.keys.inject({}) do |memo, key|
4
+ unless self[key] == other[key]
5
+ memo[key] = [self[key], other[key]]
6
+ end
7
+ memo
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ {
2
+ "@context": {
3
+ "avatar": "http://xmlns.com/foaf/0.1/avatar",
4
+ "homepage": "http://xmlns.com/foaf/0.1/homepage",
5
+ "name": "http://xmlns.com/foaf/0.1/name"
6
+ },
7
+ "avatar": "http://twitter.com/account/profile_image/manusporny",
8
+ "homepage": "http://manu.sporny.org/",
9
+ "name": "Manu Sporny"
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "@context": {
3
+ "avatar": "http://xmlns.com/foaf/0.1/avatar",
4
+ "homepage": "http://xmlns.com/foaf/0.1/homepage",
5
+ "name": "http://xmlns.com/foaf/0.1/name"
6
+ },
7
+ "avatar": "http://twitter.com/account/profile_image/manusporny",
8
+ "homepage": "http://manu.sporny.org/",
9
+ "name": "Manu Sporny"
10
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "@context": {
3
+ "name": "http://xmlns.com/foaf/0.1/name",
4
+ "homepage": "http://xmlns.com/foaf/0.1/homepage",
5
+ "avatar": "http://xmlns.com/foaf/0.1/avatar"
6
+ }
7
+ }
@@ -0,0 +1,5 @@
1
+ [{
2
+ "http://xmlns.com/foaf/0.1/name": [{"@value": "Manu Sporny"}],
3
+ "http://xmlns.com/foaf/0.1/homepage": [{"@value": "http://manu.sporny.org/"}],
4
+ "http://xmlns.com/foaf/0.1/avatar": [{"@value": "http://twitter.com/account/profile_image/manusporny"}]
5
+ }]
@@ -0,0 +1,10 @@
1
+ {
2
+ "@context": {
3
+ "name": "http://xmlns.com/foaf/0.1/name",
4
+ "homepage": "http://xmlns.com/foaf/0.1/homepage",
5
+ "avatar": "http://xmlns.com/foaf/0.1/avatar"
6
+ },
7
+ "name": "Manu Sporny",
8
+ "homepage": "http://manu.sporny.org/",
9
+ "avatar": "http://twitter.com/account/profile_image/manusporny"
10
+ }
@@ -0,0 +1,8 @@
1
+ [{
2
+ "@id": {
3
+ "@id": "_:c14n0"
4
+ },
5
+ "http://xmlns.com/foaf/0.1/avatar": "http://twitter.com/account/profile_image/manusporny",
6
+ "http://xmlns.com/foaf/0.1/homepage": "http://manu.sporny.org/",
7
+ "http://xmlns.com/foaf/0.1/name": "Manu Sporny"
8
+ }]
@@ -0,0 +1,7 @@
1
+ @prefix avatar: <http://xmlns.com/foaf/0.1/avatar> .
2
+ @prefix homepage: <http://xmlns.com/foaf/0.1/homepage> .
3
+ @prefix name: <http://xmlns.com/foaf/0.1/name> .
4
+
5
+ [ avatar: "http://twitter.com/account/profile_image/manusporny";
6
+ homepage: "http://manu.sporny.org/";
7
+ name: "Manu Sporny"] .
@@ -0,0 +1,27 @@
1
+ {
2
+ "@context": [
3
+ {
4
+ "dc": "http://purl.org/dc/elements/1.1/",
5
+ "ex": "http://example.org/vocab#"
6
+ },
7
+ {
8
+ "ex:contains": {
9
+ "@coerce": "@id"
10
+ }
11
+ }
12
+ ],
13
+ "@id": "http://example.org/library",
14
+ "@type": "ex:Library",
15
+ "ex:contains": {
16
+ "@id": "http://example.org/library/the-republic",
17
+ "@type": "ex:Book",
18
+ "dc:creator": "Plato",
19
+ "dc:title": "The Republic",
20
+ "ex:contains": {
21
+ "@id": "http://example.org/library/the-republic#introduction",
22
+ "@type": "ex:Chapter",
23
+ "dc:description": "An introductory chapter on The Republic.",
24
+ "dc:title": "The Introduction"
25
+ }
26
+ }
27
+ }