json-ld 1.1.8 → 1.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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