json-ld 1.1.8 → 1.1.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,12 +6,6 @@ module JSON::LD
6
6
  # @author [Gregg Kellogg](http://greggkellogg.net/)
7
7
  class Reader < RDF::Reader
8
8
  format Format
9
-
10
- ##
11
- # Override normal symbol generation
12
- def self.to_sym
13
- :jsonld
14
- end
15
9
 
16
10
  ##
17
11
  # Initializes the RDF/JSON reader instance.
@@ -29,12 +23,14 @@ module JSON::LD
29
23
  @options[:base] ||= base_uri.to_s if base_uri
30
24
  begin
31
25
  # Trim non-JSON stuff in script.
32
- input = input.read if input.respond_to?(:read)
33
- input = input.to_s.sub(%r(\A[^{\[]*)m, '').sub(%r([^}\]]*\Z)m, '')
34
- @doc = JSON.load(input)
26
+ @doc = if input.respond_to?(:read)
27
+ input
28
+ else
29
+ StringIO.new(input.to_s.sub(%r(\A[^{\[]*)m, '').sub(%r([^}\]]*\Z)m, ''))
30
+ end
35
31
  rescue JSON::ParserError => e
36
32
  raise RDF::ReaderError, "Failed to parse input document: #{e.message}" if validate?
37
- @doc = JSON.parse("{}")
33
+ @doc = StringIO.new("{}")
38
34
  end
39
35
 
40
36
  if block_given?
@@ -51,6 +47,8 @@ module JSON::LD
51
47
  # @see RDF::Reader#each_statement
52
48
  def each_statement(&block)
53
49
  JSON::LD::API.toRdf(@doc, @options, &block)
50
+ rescue ::JSON::LD::JsonLdError => e
51
+ raise RDF::ReaderError, e.message
54
52
  end
55
53
 
56
54
  ##
@@ -10,7 +10,7 @@ module JSON::LD
10
10
  def node?(value)
11
11
  value.is_a?(Hash) &&
12
12
  (value.keys & %w(@value @list @set)).empty? &&
13
- !(value.keys - ['@id']).empty?
13
+ (value.length > 1 || !value.has_key?('@id'))
14
14
  end
15
15
 
16
16
  ##
@@ -78,6 +78,100 @@ module JSON::LD
78
78
  end
79
79
  end
80
80
 
81
+ ##
82
+ # Compares two JSON-LD values for equality. Two JSON-LD values will be
83
+ # considered equal if:
84
+ #
85
+ # 1. They are both primitives of the same type and value.
86
+ # 2. They are both @values with the same @value, @type, @language,
87
+ # and @index, OR
88
+ # 3. They both have @ids that are the same.
89
+ #
90
+ # @param [Object] v1 the first value.
91
+ # @param [Object] v2 the second value.
92
+ #
93
+ # @return [Boolean] v1 and v2 are considered equal
94
+ def compare_values(v1, v2)
95
+ case
96
+ when node?(v1) && node?(v2) then v1['@id'] && v1['@id'] == v2['@id']
97
+ when value?(v1) && value?(v2)
98
+ v1['@value'] == v2['@value'] &&
99
+ v1['@type'] == v2['@type'] &&
100
+ v1['@language'] == v2['@language'] &&
101
+ v1['@index'] == v2['@index']
102
+ else
103
+ v1 == v2
104
+ end
105
+ end
106
+
107
+ # Adds a value to a subject. If the value is an array, all values in the
108
+ # array will be added.
109
+ #
110
+ # @param [Hash] subject the hash to add the value to.
111
+ # @param [String] property the property that relates the value to the subject.
112
+ # @param [Object] value the value to add.
113
+ # @param [Hash{Symbol => Object}] options
114
+ # @option options [Boolean] :property_is_array
115
+ # true if the property is always (false)
116
+ # an array, false if not.
117
+ # @option options [Boolean] :allow_duplicate (true)
118
+ # true to allow duplicates, false not to (uses
119
+ # a simple shallow comparison of subject ID or value).
120
+ def add_value(subject, property, value, options = {})
121
+ options = {property_is_array: false, allow_duplicate: true}.merge(options)
122
+
123
+ if value.is_a?(Array)
124
+ subject[property] = [] if value.empty? && options[:property_is_array]
125
+ value.each {|v| add_value(subject, property, v, options)}
126
+ elsif subject[property]
127
+ # check if subject already has value if duplicates not allowed
128
+ _has_value = !options[:allow_duplicate] && has_value(subject, property, value)
129
+
130
+ # make property an array if value not present or always an array
131
+ if !subject[property].is_a?(Array) && (!_has_value || options[:property_is_array])
132
+ subject[property] = [subject[property]]
133
+ end
134
+ subject[property] << value unless _has_value
135
+ else
136
+ subject[property] = options[:property_is_array] ? [value] : value
137
+ end
138
+ end
139
+
140
+ # Returns True if the given subject has the given property.
141
+ #
142
+ # @param subject the subject to check.
143
+ # @param property the property to look for.
144
+ #
145
+ # @return [Boolean] true if the subject has the given property, false if not.
146
+ def has_property(subject, property)
147
+ return false unless value = subject[property]
148
+ !value.is_a?(Array) || !value.empty?
149
+ end
150
+
151
+ # Determines if the given value is a property of the given subject.
152
+ #
153
+ # @param [Hash] subject the subject to check.
154
+ # @param [String] property the property to check.
155
+ # @param [Object] value the value to check.
156
+ #
157
+ # @return [Boolean] true if the value exists, false if not.
158
+ def has_value(subject, property, value)
159
+ if has_property(subject, property)
160
+ val = subject[property]
161
+ is_list = list?(val)
162
+ if val.is_a?(Array) || is_list
163
+ val = val['@list'] if is_list
164
+ val.any? {|v| compare_values(value, v)}
165
+ elsif !val.is_a?(Array)
166
+ compare_values(value, val)
167
+ else
168
+ false
169
+ end
170
+ else
171
+ false
172
+ end
173
+ end
174
+
81
175
  private
82
176
 
83
177
  # Merge the last value into an array based for the specified key if hash is not null and value is not already in that array
@@ -125,8 +219,14 @@ module JSON::LD
125
219
  list = args
126
220
  list << yield if block_given?
127
221
  message = " " * depth * 2 + (list.empty? ? "" : list.join(": "))
128
- puts message if JSON::LD::debug?
129
- @options[:debug] << message if @options[:debug].is_a?(Array)
222
+ case @options[:debug]
223
+ when Array
224
+ @options[:debug] << message
225
+ when TrueClass
226
+ $stderr.puts message
227
+ else
228
+ $stderr.puts message if JSON::LD::debug?
229
+ end
130
230
  end
131
231
 
132
232
  # Increase depth around a method invocation
@@ -194,7 +294,7 @@ module JSON::LD
194
294
  # @return [String]
195
295
  def get_sym(old = "")
196
296
  old = old.to_s.sub(/_:/, '')
197
- if old && self.has_key?(old)
297
+ if !old.empty? && self.has_key?(old)
198
298
  self[old]
199
299
  elsif !old.empty?
200
300
  @num += 1
@@ -64,12 +64,6 @@ module JSON::LD
64
64
  # @return [Context] context used to load and administer contexts
65
65
  attr_reader :context
66
66
 
67
- ##
68
- # Override normal symbol generation
69
- def self.to_sym
70
- :jsonld
71
- end
72
-
73
67
  ##
74
68
  # Initializes the RDF-LD writer instance.
75
69
  #
@@ -114,16 +108,6 @@ module JSON::LD
114
108
  end
115
109
  end
116
110
 
117
- ##
118
- # Write whole graph
119
- #
120
- # @param [Graph] graph
121
- # @return [void]
122
- def write_graph(graph)
123
- debug {"Add graph #{graph.inspect}"}
124
- @repo = graph
125
- end
126
-
127
111
  ##
128
112
  # Adds a statement to be serialized
129
113
  # @param [RDF::Statement] statement
@@ -25,9 +25,9 @@ describe JSON::LD::API do
25
25
  end
26
26
 
27
27
  it "loads document with loader and loads context" do
28
- expect(JSON::LD::API).to receive(:documentLoader).with("http://example.com/foo", anything).and_return(remote_doc)
29
- expect(JSON::LD::API).to receive(:documentLoader).with("http://example.com/context", anything).and_yield(context)
30
- JSON::LD::API.new("http://example.com/foo", nil)
28
+ expect(described_class).to receive(:documentLoader).with("http://example.com/foo", anything).and_return(remote_doc)
29
+ expect(described_class).to receive(:documentLoader).with("http://example.com/context", anything).and_yield(context)
30
+ described_class.new("http://example.com/foo", nil)
31
31
  end
32
32
  end
33
33
 
@@ -52,12 +52,18 @@ describe JSON::LD::API do
52
52
  end
53
53
 
54
54
  it "processes document and retrieves linked context" do
55
- expect(JSON::LD::API).to receive(:documentLoader).with("http://example.com/context", anything).and_yield(context)
56
- JSON::LD::API.new(remote_doc, nil)
55
+ expect(described_class).to receive(:documentLoader).with("http://example.com/context", anything).and_yield(context)
56
+ described_class.new(remote_doc, nil)
57
57
  end
58
58
  end
59
59
  end
60
60
 
61
+ context "when validating", pending: ("JRuby support for jsonlint" if RUBY_ENGINE == "jruby") do
62
+ it "detects invalid JSON" do
63
+ expect {described_class.new(StringIO.new(%({"a": "b", "a": "c"})), nil, validate: true)}.to raise_error(JSON::LD::JsonLdError::LoadingDocumentFailed)
64
+ end
65
+ end
66
+
61
67
  context "Test Files" do
62
68
  Dir.glob(File.expand_path(File.join(File.dirname(__FILE__), 'test-files/*-input.*'))) do |filename|
63
69
  test = File.basename(filename).sub(/-input\..*$/, '')
@@ -66,24 +72,23 @@ describe JSON::LD::API do
66
72
  compacted = filename.sub(/-input\..*$/, '-compacted.json')
67
73
  context = filename.sub(/-input\..*$/, '-context.json')
68
74
  expanded = filename.sub(/-input\..*$/, '-expanded.json')
69
- automatic = filename.sub(/-input\..*$/, '-automatic.json')
70
75
  ttl = filename.sub(/-input\..*$/, '-rdf.ttl')
71
76
 
72
77
  context test do
73
78
  it "expands" do
74
79
  options = {debug: @debug}
75
80
  options[:expandContext] = File.open(context) if context
76
- jld = JSON::LD::API.expand(File.open(filename), options)
81
+ jld = described_class.expand(File.open(filename), options)
77
82
  expect(jld).to produce(JSON.load(File.open(expanded)), @debug)
78
83
  end if File.exist?(expanded)
79
84
 
80
85
  it "compacts" do
81
- jld = JSON::LD::API.compact(File.open(filename), File.open(context), debug: @debug)
86
+ jld = described_class.compact(File.open(filename), File.open(context), debug: @debug)
82
87
  expect(jld).to produce(JSON.load(File.open(compacted)), @debug)
83
88
  end if File.exist?(compacted) && File.exist?(context)
84
89
 
85
90
  it "frame" do
86
- jld = JSON::LD::API.frame(File.open(filename), File.open(frame), debug: @debug)
91
+ jld = described_class.frame(File.open(filename), File.open(frame), debug: @debug)
87
92
  expect(jld).to produce(JSON.load(File.open(framed)), @debug)
88
93
  end if File.exist?(framed) && File.exist?(frame)
89
94
 
@@ -4,12 +4,10 @@ require 'spec_helper'
4
4
  require 'rdf/spec/format'
5
5
 
6
6
  describe JSON::LD::Format do
7
- before :each do
8
- @format_class = JSON::LD::Format
7
+ it_behaves_like 'an RDF::Format' do
8
+ let(:format_class) {JSON::LD::Format}
9
9
  end
10
10
 
11
- include RDF_Format
12
-
13
11
  describe ".for" do
14
12
  formats = [
15
13
  :jsonld,
@@ -20,7 +18,7 @@ describe JSON::LD::Format do
20
18
  {content_type: 'application/x-ld+json'},
21
19
  ].each do |arg|
22
20
  it "discovers with #{arg.inspect}" do
23
- expect(RDF::Format.for(arg)).to eq @format_class
21
+ expect(RDF::Format.for(arg)).to eq described_class
24
22
  end
25
23
  end
26
24
 
@@ -31,7 +29,7 @@ describe JSON::LD::Format do
31
29
  type: %({\n"@type": {),
32
30
  }.each do |sym, str|
33
31
  it "detects #{sym}" do
34
- expect(@format_class.for {str}).to eq @format_class
32
+ expect(described_class.for {str}).to eq described_class
35
33
  end
36
34
  end
37
35
 
@@ -41,7 +39,7 @@ describe JSON::LD::Format do
41
39
  end
42
40
 
43
41
  describe "#to_sym" do
44
- specify {expect(@format_class.to_sym).to eq :jsonld}
42
+ specify {expect(described_class.to_sym).to eq :jsonld}
45
43
  end
46
44
 
47
45
  describe ".detect" do
@@ -49,7 +47,7 @@ describe JSON::LD::Format do
49
47
  jsonld: '{"@context" => "foo"}',
50
48
  }.each do |sym, str|
51
49
  it "detects #{sym}" do
52
- expect(@format_class.detect(str)).to be_truthy
50
+ expect(described_class.detect(str)).to be_truthy
53
51
  end
54
52
  end
55
53
 
@@ -64,7 +62,7 @@ describe JSON::LD::Format do
64
62
  turtle: "@prefix foo: <bar> .\n foo:a foo:b <c> .",
65
63
  }.each do |sym, str|
66
64
  it "does not detect #{sym}" do
67
- expect(@format_class.detect(str)).to be_falsey
65
+ expect(described_class.detect(str)).to be_falsey
68
66
  end
69
67
  end
70
68
  end
@@ -8,16 +8,11 @@ describe JSON::LD::Reader do
8
8
  let!(:doap_nt) {File.expand_path("../../etc/doap.nt", __FILE__)}
9
9
  let!(:doap_count) {File.open(doap_nt).each_line.to_a.length}
10
10
 
11
- before(:each) do
12
- @reader_input = File.read(doap)
13
- @reader = JSON::LD::Reader.new(@reader_input)
14
- @reader_count = doap_count
11
+ it_behaves_like 'an RDF::Reader' do
12
+ let(:reader_input) {File.read(doap)}
13
+ let(:reader) {JSON::LD::Reader.new(reader_input)}
14
+ let(:reader_count) {doap_count}
15
15
  end
16
- before :each do
17
- @reader = JSON::LD::Reader.new(StringIO.new(""))
18
- end
19
-
20
- include RDF_Reader
21
16
 
22
17
  describe ".for" do
23
18
  formats = [
@@ -34,6 +29,14 @@ describe JSON::LD::Reader do
34
29
  end
35
30
  end
36
31
 
32
+ context "when validating", pending: ("JRuby support for jsonlint" if RUBY_ENGINE == "jruby") do
33
+ it "detects invalid JSON" do
34
+ expect do |b|
35
+ described_class.new(StringIO.new(%({"a": "b", "a": "c"})), validate: true).each_statement(&b)
36
+ end.to raise_error(RDF::ReaderError)
37
+ end
38
+ end
39
+
37
40
  context :interface do
38
41
  {
39
42
  plain: %q({
@@ -5,7 +5,6 @@ require "bundler/setup"
5
5
  require 'rspec'
6
6
  require 'rdf'
7
7
  require 'rdf/isomorphic'
8
- require 'json/ld'
9
8
  require 'rdf/nquads'
10
9
  require 'rdf/turtle'
11
10
  require 'rdf/trig'
@@ -15,6 +14,17 @@ require 'yaml'
15
14
  require 'restclient/components'
16
15
  require 'rack/cache'
17
16
  require 'matchers'
17
+ require 'simplecov'
18
+ require 'coveralls'
19
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
20
+ SimpleCov::Formatter::HTMLFormatter,
21
+ Coveralls::SimpleCov::Formatter
22
+ ]
23
+ SimpleCov.start do
24
+ add_filter "/spec/"
25
+ end
26
+
27
+ require 'json/ld'
18
28
 
19
29
  JSON_STATE = JSON::State.new(
20
30
  indent: " ",
@@ -36,16 +46,13 @@ RestClient.enable Rack::Cache,
36
46
  ::RSpec.configure do |c|
37
47
  c.filter_run focus: true
38
48
  c.run_all_when_everything_filtered = true
39
- c.exclusion_filter = {
40
- ruby: lambda { |version| !(RUBY_VERSION.to_s =~ /^#{version.to_s}/) },
41
- }
42
49
  c.include(RDF::Spec::Matchers)
43
50
  end
44
51
 
45
52
  # Heuristically detect the input stream
46
53
  def detect_format(stream)
47
54
  # Got to look into the file to see
48
- if stream.is_a?(IO) || stream.is_a?(StringIO)
55
+ if stream.respond_to?(:rewind) && stream.respond_to?(:read)
49
56
  stream.rewind
50
57
  string = stream.read(1000)
51
58
  stream.rewind
@@ -5,12 +5,10 @@ require 'rdf/spec/writer'
5
5
  require 'json/ld/streaming_writer'
6
6
 
7
7
  describe JSON::LD::StreamingWriter do
8
- before :each do
9
- @writer = JSON::LD::Writer.new(StringIO.new(""), stream: true)
8
+ it_behaves_like 'an RDF::Writer' do
9
+ let(:writer) {JSON::LD::Writer.new(StringIO.new(""), stream: true)}
10
10
  end
11
11
 
12
- include RDF_Writer
13
-
14
12
  context "simple tests" do
15
13
  it "should use full URIs without base" do
16
14
  input = %(<http://a/b> <http://a/c> <http://a/d> .)
@@ -9,6 +9,7 @@ describe JSON::LD do
9
9
  describe m.name do
10
10
  m.entries.each do |t|
11
11
  specify "#{t.property('input')}: #{t.name}#{' (negative test)' unless t.positiveTest?}" do
12
+ pending "Shared list BNode in different graphs" if t.property('input').include?("fromRdf-0021")
12
13
  t.run self
13
14
  end
14
15
  end
@@ -85,7 +85,7 @@ module Fixtures
85
85
 
86
86
  # Execute the test
87
87
  def run(rspec_example = nil)
88
- @debug = ["test: #{inspect}", "source: #{input}"]
88
+ debug = @debug = ["test: #{inspect}", "source: #{input}"]
89
89
  @debug << "context: #{context}" if context_loc
90
90
  @debug << "options: #{options.inspect}" unless options.empty?
91
91
  @debug << "frame: #{frame}" if frame_loc
@@ -97,23 +97,23 @@ module Fixtures
97
97
  end
98
98
 
99
99
  if positiveTest?
100
- debug << "expected: #{expect rescue nil}" if expect_loc
100
+ @debug << "expected: #{expect rescue nil}" if expect_loc
101
101
  begin
102
102
  result = case testType
103
103
  when "jld:ExpandTest"
104
- JSON::LD::API.expand(input_loc, options.merge(debug: @debug))
104
+ JSON::LD::API.expand(input_loc, options.merge(debug: debug))
105
105
  when "jld:CompactTest"
106
- JSON::LD::API.compact(input_loc, context_json['@context'], options.merge(debug: @debug))
106
+ JSON::LD::API.compact(input_loc, context_json['@context'], options.merge(debug: debug))
107
107
  when "jld:FlattenTest"
108
- JSON::LD::API.flatten(input_loc, context_loc, options.merge(debug: @debug))
108
+ JSON::LD::API.flatten(input_loc, context_loc, options.merge(debug: debug))
109
109
  when "jld:FrameTest"
110
- JSON::LD::API.frame(input_loc, frame_loc, options.merge(debug: @debug))
110
+ JSON::LD::API.frame(input_loc, frame_loc, options.merge(debug: debug))
111
111
  when "jld:FromRDFTest"
112
112
  repo = RDF::Repository.load(input_loc, format: :nquads)
113
113
  @debug << "repo: #{repo.dump(id == '#t0012' ? :nquads : :trig)}"
114
- JSON::LD::API.fromRdf(repo, options.merge(debug: @debug))
114
+ JSON::LD::API.fromRdf(repo, options.merge(debug: debug))
115
115
  when "jld:ToRDFTest"
116
- JSON::LD::API.toRdf(input_loc, options.merge(debug: @debug)).map do |statement|
116
+ JSON::LD::API.toRdf(input_loc, options.merge(debug: debug)).map do |statement|
117
117
  to_quad(statement)
118
118
  end
119
119
  else
@@ -123,12 +123,12 @@ module Fixtures
123
123
  if testType == "jld:ToRDFTest"
124
124
  expected = expect
125
125
  rspec_example.instance_eval {
126
- expect(result.sort.join("")).to produce(expected, @debug)
126
+ expect(result.sort.join("")).to produce(expected, debug)
127
127
  }
128
128
  else
129
129
  expected = JSON.load(expect)
130
130
  rspec_example.instance_eval {
131
- expect(result).to produce(expected, @debug)
131
+ expect(result).to produce(expected, debug)
132
132
  }
133
133
  end
134
134
  else
@@ -142,26 +142,26 @@ module Fixtures
142
142
  fail("Invalid Frame: #{e.message}")
143
143
  end
144
144
  else
145
- @debug << "expected: #{property('expect')}" if property('expect')
145
+ debug << "expected: #{property('expect')}" if property('expect')
146
146
  t = self
147
147
  rspec_example.instance_eval do
148
148
  if t.evaluationTest?
149
149
  expect do
150
150
  case t.testType
151
151
  when "jld:ExpandTest"
152
- JSON::LD::API.expand(t.input_loc, options.merge(debug: @debug))
152
+ JSON::LD::API.expand(t.input_loc, options.merge(debug: debug))
153
153
  when "jld:CompactTest"
154
- JSON::LD::API.compact(t.input_loc, t.context_json['@context'], options.merge(debug: @debug))
154
+ JSON::LD::API.compact(t.input_loc, t.context_json['@context'], options.merge(debug: debug))
155
155
  when "jld:FlattenTest"
156
- JSON::LD::API.flatten(t.input_loc, t.context_loc, options.merge(debug: @debug))
156
+ JSON::LD::API.flatten(t.input_loc, t.context_loc, options.merge(debug: debug))
157
157
  when "jld:FrameTest"
158
- JSON::LD::API.frame(t.input_loc, t.frame_loc, options.merge(debug: @debug))
158
+ JSON::LD::API.frame(t.input_loc, t.frame_loc, options.merge(debug: debug))
159
159
  when "jld:FromRDFTest"
160
160
  repo = RDF::Repository.load(t.input_loc)
161
- @debug << "repo: #{repo.dump(id == '#t0012' ? :nquads : :trig)}"
162
- JSON::LD::API.fromRdf(repo, options.merge(debug: @debug))
161
+ debug << "repo: #{repo.dump(id == '#t0012' ? :nquads : :trig)}"
162
+ JSON::LD::API.fromRdf(repo, options.merge(debug: debug))
163
163
  when "jld:ToRDFTest"
164
- JSON::LD::API.toRdf(t.input_loc, options.merge(debug: @debug)).map do |statement|
164
+ JSON::LD::API.toRdf(t.input_loc, options.merge(debug: debug)).map do |statement|
165
165
  t.to_quad(statement)
166
166
  end
167
167
  else