json-ld 3.1.4 → 3.1.9

Sign up to get free protection for your applications and to get access to all the features.
data/spec/api_spec.rb CHANGED
@@ -44,7 +44,7 @@ describe JSON::LD::API do
44
44
  end
45
45
 
46
46
  context "Test Files" do
47
- %w(oj json_gem ok_json yajl).map(&:to_sym).each do |adapter|
47
+ %i(oj json_gem ok_json yajl).each do |adapter|
48
48
  context "with MultiJson adapter #{adapter.inspect}" do
49
49
  Dir.glob(File.expand_path(File.join(File.dirname(__FILE__), 'test-files/*-input.*'))) do |filename|
50
50
  test = File.basename(filename).sub(/-input\..*$/, '')
data/spec/compact_spec.rb CHANGED
@@ -3113,6 +3113,210 @@ describe JSON::LD::API do
3113
3113
  end
3114
3114
  end
3115
3115
 
3116
+ context "JSON-LD-star" do
3117
+ {
3118
+ "subject-iii": {
3119
+ input: %([{
3120
+ "@id": {
3121
+ "@id": "http://example/s1",
3122
+ "http://example/p1": [{"@id": "http://example/o1"}]
3123
+ },
3124
+ "http://example/p": [{"@id": "http://example/o"}]
3125
+ }]),
3126
+ context: %({"ex": "http://example/"}),
3127
+ output: %({
3128
+ "@context": {"ex": "http://example/"},
3129
+ "@id": {
3130
+ "@id": "ex:s1",
3131
+ "ex:p1": {"@id": "ex:o1"}
3132
+ },
3133
+ "ex:p": {"@id": "ex:o"}
3134
+ })
3135
+ },
3136
+ "subject-iib": {
3137
+ input: %([{
3138
+ "@id": {
3139
+ "@id": "http://example/s1",
3140
+ "http://example/p1": [{"@id": "_:o1"}]
3141
+ },
3142
+ "http://example/p": [{"@id": "http://example/o"}]
3143
+ }]),
3144
+ context: %({"ex": "http://example/"}),
3145
+ output: %({
3146
+ "@context": {"ex": "http://example/"},
3147
+ "@id": {
3148
+ "@id": "ex:s1",
3149
+ "ex:p1": {"@id": "_:o1"}
3150
+ },
3151
+ "ex:p": {"@id": "ex:o"}
3152
+ })
3153
+ },
3154
+ "subject-iil": {
3155
+ input: %([{
3156
+ "@id": {
3157
+ "@id": "http://example/s1",
3158
+ "http://example/p1": [{"@value": "o1"}]
3159
+ },
3160
+ "http://example/p": [{"@id": "http://example/o"}]
3161
+ }]),
3162
+ context: %({"ex": "http://example/"}),
3163
+ output: %({
3164
+ "@context": {"ex": "http://example/"},
3165
+ "@id": {
3166
+ "@id": "ex:s1",
3167
+ "ex:p1": "o1"
3168
+ },
3169
+ "ex:p": {"@id": "ex:o"}
3170
+ })
3171
+ },
3172
+ "subject-bii": {
3173
+ input: %([{
3174
+ "@id": {
3175
+ "@id": "_:s1",
3176
+ "http://example/p1": [{"@id": "http://example/o1"}]
3177
+ },
3178
+ "http://example/p": [{"@id": "http://example/o"}]
3179
+ }]),
3180
+ context: %({"ex": "http://example/"}),
3181
+ output: %({
3182
+ "@context": {"ex": "http://example/"},
3183
+ "@id": {
3184
+ "@id": "_:s1",
3185
+ "ex:p1": {"@id": "ex:o1"}
3186
+ },
3187
+ "ex:p": {"@id": "ex:o"}
3188
+ })
3189
+ },
3190
+ "subject-bib": {
3191
+ input: %([{
3192
+ "@id": {
3193
+ "@id": "_:s1",
3194
+ "http://example/p1": [{"@id": "_:o1"}]
3195
+ },
3196
+ "http://example/p": [{"@id": "http://example/o"}]
3197
+ }]),
3198
+ context: %({"ex": "http://example/"}),
3199
+ output: %({
3200
+ "@context": {"ex": "http://example/"},
3201
+ "@id": {
3202
+ "@id": "_:s1",
3203
+ "ex:p1": {"@id": "_:o1"}
3204
+ },
3205
+ "ex:p": {"@id": "ex:o"}
3206
+ })
3207
+ },
3208
+ "subject-bil": {
3209
+ input: %([{
3210
+ "@id": {
3211
+ "@id": "_:s1",
3212
+ "http://example/p1": [{"@value": "o1"}]
3213
+ },
3214
+ "http://example/p": [{"@id": "http://example/o"}]
3215
+ }]),
3216
+ context: %({"ex": "http://example/"}),
3217
+ output: %({
3218
+ "@context": {"ex": "http://example/"},
3219
+ "@id": {
3220
+ "@id": "_:s1",
3221
+ "ex:p1": "o1"
3222
+ },
3223
+ "ex:p": {"@id": "ex:o"}
3224
+ })
3225
+ },
3226
+ "object-iii": {
3227
+ input: %([{
3228
+ "@id": "http://example/s",
3229
+ "http://example/p": [{
3230
+ "@id": {
3231
+ "@id": "http://example/s1",
3232
+ "http://example/p1": [{"@id": "http://example/o1"}]
3233
+ }
3234
+ }]
3235
+ }]),
3236
+ context: %({"ex": "http://example/"}),
3237
+ output: %({
3238
+ "@context": {"ex": "http://example/"},
3239
+ "@id": "ex:s",
3240
+ "ex:p": {
3241
+ "@id": {
3242
+ "@id": "ex:s1",
3243
+ "ex:p1": {"@id": "ex:o1"}
3244
+ }
3245
+ }
3246
+ })
3247
+ },
3248
+ "object-iib": {
3249
+ input: %([{
3250
+ "@id": "http://example/s",
3251
+ "http://example/p": [{
3252
+ "@id": {
3253
+ "@id": "http://example/s1",
3254
+ "http://example/p1": [{"@id": "_:o1"}]
3255
+ }
3256
+ }]
3257
+ }]),
3258
+ context: %({"ex": "http://example/"}),
3259
+ output: %({
3260
+ "@context": {"ex": "http://example/"},
3261
+ "@id": "ex:s",
3262
+ "ex:p": {
3263
+ "@id": {
3264
+ "@id": "ex:s1",
3265
+ "ex:p1": {"@id": "_:o1"}
3266
+ }
3267
+ }
3268
+ })
3269
+ },
3270
+ "object-iil": {
3271
+ input: %([{
3272
+ "@id": "http://example/s",
3273
+ "http://example/p": [{
3274
+ "@id": {
3275
+ "@id": "http://example/s1",
3276
+ "http://example/p1": [{"@value": "o1"}]
3277
+ }
3278
+ }]
3279
+ }]),
3280
+ context: %({"ex": "http://example/"}),
3281
+ output: %({
3282
+ "@context": {"ex": "http://example/"},
3283
+ "@id": "ex:s",
3284
+ "ex:p": {
3285
+ "@id": {
3286
+ "@id": "ex:s1",
3287
+ "ex:p1": "o1"
3288
+ }
3289
+ }
3290
+ })
3291
+ },
3292
+ "recursive-subject": {
3293
+ input: %([{
3294
+ "@id": {
3295
+ "@id": {
3296
+ "@id": "http://example/s2",
3297
+ "http://example/p2": [{"@id": "http://example/o2"}]
3298
+ },
3299
+ "http://example/p1": [{"@id": "http://example/o1"}]
3300
+ },
3301
+ "http://example/p": [{"@id": "http://example/o"}]
3302
+ }]),
3303
+ context: %({"ex": "http://example/"}),
3304
+ output: %({
3305
+ "@context": {"ex": "http://example/"},
3306
+ "@id": {
3307
+ "@id": {
3308
+ "@id": "ex:s2",
3309
+ "ex:p2": {"@id": "ex:o2"}
3310
+ },
3311
+ "ex:p1": {"@id": "ex:o1"}
3312
+ },
3313
+ "ex:p": {"@id": "ex:o"}
3314
+ })
3315
+ },
3316
+ }.each do |name, params|
3317
+ it(name) {run_compact(params.merge(rdfstar: true))}
3318
+ end
3319
+ end
3116
3320
 
3117
3321
  context "problem cases" do
3118
3322
  {
@@ -3185,7 +3389,7 @@ describe JSON::LD::API do
3185
3389
  input = ::JSON.parse(input) if input.is_a?(String)
3186
3390
  output = ::JSON.parse(output) if output.is_a?(String)
3187
3391
  context = ::JSON.parse(context) if context.is_a?(String)
3188
- context = context['@context'] if context.has_key?('@context')
3392
+ context = context['@context'] if context.key?('@context')
3189
3393
  pending params.fetch(:pending, "test implementation") unless input
3190
3394
  if params[:exception]
3191
3395
  expect {JSON::LD::API.compact(input, context, logger: logger, **params)}.to raise_error(params[:exception])
@@ -3200,8 +3404,8 @@ describe JSON::LD::API do
3200
3404
  expect(jld).to produce_jsonld(output, logger)
3201
3405
 
3202
3406
  # Compare expanded jld/output too to make sure list values remain ordered
3203
- exp_jld = JSON::LD::API.expand(jld, processingMode: 'json-ld-1.1')
3204
- exp_output = JSON::LD::API.expand(output, processingMode: 'json-ld-1.1')
3407
+ exp_jld = JSON::LD::API.expand(jld, processingMode: 'json-ld-1.1', rdfstar: params[:rdfstar])
3408
+ exp_output = JSON::LD::API.expand(output, processingMode: 'json-ld-1.1', rdfstar: params[:rdfstar])
3205
3409
  expect(exp_jld).to produce_jsonld(exp_output, logger)
3206
3410
  end
3207
3411
  end
data/spec/context_spec.rb CHANGED
@@ -1148,7 +1148,6 @@ describe JSON::LD::Context do
1148
1148
  "nil" => [nil, nil],
1149
1149
  "absolute IRI" => ["http://example.com/", "http://example.com/"],
1150
1150
  "prefix:suffix" => ["ex:suffix", "http://example.org/suffix"],
1151
- "keyword" => ["@type", "@type"],
1152
1151
  "unmapped" => ["foo", "foo"],
1153
1152
  "bnode" => [JSON::LD::JsonLdError:: IRIConfusedWithPrefix, RDF::Node("a")],
1154
1153
  "relative" => ["foo/bar", "http://base/foo/bar"],
@@ -1338,7 +1337,6 @@ describe JSON::LD::Context do
1338
1337
  "nil" => [nil, nil],
1339
1338
  "absolute IRI" => ["http://example.com/", "http://example.com/"],
1340
1339
  "prefix:suffix" => ["ex:suffix", "http://example.org/suffix"],
1341
- "keyword" => ["@type", "@type"],
1342
1340
  "unmapped" => ["foo", "foo"],
1343
1341
  "bnode" => [JSON::LD::JsonLdError:: IRIConfusedWithPrefix, RDF::Node("a")],
1344
1342
  "relative" => ["foo/bar", "http://base/foo/bar"],
data/spec/expand_spec.rb CHANGED
@@ -3371,9 +3371,640 @@ describe JSON::LD::API do
3371
3371
  }),
3372
3372
  exception: JSON::LD::JsonLdError::InvalidReversePropertyMap,
3373
3373
  },
3374
+ "Explicit and implicit @reverse in same object": {
3375
+ input: %({
3376
+ "@context": {
3377
+ "fooOf": {"@reverse": "ex:foo", "@type": "@id"}
3378
+ },
3379
+ "@id": "ex:s",
3380
+ "fooOf": "ex:o1",
3381
+ "@reverse": {
3382
+ "ex:bar": {"@id": "ex:o2"}
3383
+ }
3384
+ }),
3385
+ output: %([{
3386
+ "@id": "ex:s",
3387
+ "@reverse": {
3388
+ "ex:bar": [{"@id": "ex:o2"}],
3389
+ "ex:foo": [{"@id": "ex:o1"}]
3390
+ }
3391
+ }])
3392
+ },
3393
+ "Two properties both with @reverse": {
3394
+ input: %({
3395
+ "@context": {
3396
+ "fooOf": {"@reverse": "ex:foo", "@type": "@id"},
3397
+ "barOf": {"@reverse": "ex:bar", "@type": "@id"}
3398
+ },
3399
+ "@id": "ex:s",
3400
+ "fooOf": "ex:o1",
3401
+ "barOf": "ex:o2"
3402
+ }),
3403
+ output: %([{
3404
+ "@id": "ex:s",
3405
+ "@reverse": {
3406
+ "ex:bar": [{"@id": "ex:o2"}],
3407
+ "ex:foo": [{"@id": "ex:o1"}]
3408
+ }
3409
+ }])
3410
+ },
3411
+ }.each do |title, params|
3412
+ it(title) {run_expand params}
3413
+ end
3414
+ end
3415
+
3416
+ context "JSON-LD-star" do
3417
+ {
3418
+ "node with embedded subject without rdfstar option": {
3419
+ input: %({
3420
+ "@id": {
3421
+ "@id": "ex:rei",
3422
+ "ex:prop": "value"
3423
+ },
3424
+ "ex:prop": "value2"
3425
+ }),
3426
+ exception: JSON::LD::JsonLdError::InvalidIdValue
3427
+ },
3428
+ "node object with @annotation property is ignored without rdfstar option": {
3429
+ input: %({
3430
+ "@id": "ex:bob",
3431
+ "ex:knows": {
3432
+ "@id": "ex:fred",
3433
+ "@annotation": {
3434
+ "ex:certainty": 0.8
3435
+ }
3436
+ }
3437
+ }),
3438
+ output: %([{
3439
+ "@id": "ex:bob",
3440
+ "ex:knows": [{"@id": "ex:fred"}]
3441
+ }])
3442
+ },
3443
+ "value object with @annotation property is ignored without rdfstar option": {
3444
+ input: %({
3445
+ "@id": "ex:bob",
3446
+ "ex:age": {
3447
+ "@value": 23,
3448
+ "@annotation": {
3449
+ "ex:certainty": 0.8
3450
+ }
3451
+ }
3452
+ }),
3453
+ output: %([{
3454
+ "@id": "ex:bob",
3455
+ "ex:age": [{"@value": 23}]
3456
+ }])
3457
+ },
3374
3458
  }.each do |title, params|
3375
3459
  it(title) {run_expand params}
3376
3460
  end
3461
+
3462
+ {
3463
+ "node with embedded subject having no @id": {
3464
+ input: %({
3465
+ "@id": {
3466
+ "ex:prop": "value"
3467
+ },
3468
+ "ex:prop": "value2"
3469
+ }),
3470
+ output: %([{
3471
+ "@id": {
3472
+ "ex:prop": [{"@value": "value"}]
3473
+ },
3474
+ "ex:prop": [{"@value": "value2"}]
3475
+ }])
3476
+ },
3477
+ "node with embedded subject having IRI @id": {
3478
+ input: %({
3479
+ "@id": {
3480
+ "@id": "ex:rei",
3481
+ "ex:prop": "value"
3482
+ },
3483
+ "ex:prop": "value2"
3484
+ }),
3485
+ output: %([{
3486
+ "@id": {
3487
+ "@id": "ex:rei",
3488
+ "ex:prop": [{"@value": "value"}]
3489
+ },
3490
+ "ex:prop": [{"@value": "value2"}]
3491
+ }])
3492
+ },
3493
+ "node with embedded subject having BNode @id": {
3494
+ input: %({
3495
+ "@id": {
3496
+ "@id": "_:rei",
3497
+ "ex:prop": "value"
3498
+ },
3499
+ "ex:prop": "value2"
3500
+ }),
3501
+ output: %([{
3502
+ "@id": {
3503
+ "@id": "_:rei",
3504
+ "ex:prop": [{"@value": "value"}]
3505
+ },
3506
+ "ex:prop": [{"@value": "value2"}]
3507
+ }])
3508
+ },
3509
+ "node with embedded subject having a type": {
3510
+ input: %({
3511
+ "@id": {
3512
+ "@id": "ex:rei",
3513
+ "@type": "ex:Type"
3514
+ },
3515
+ "ex:prop": "value2"
3516
+ }),
3517
+ output: %([{
3518
+ "@id": {
3519
+ "@id": "ex:rei",
3520
+ "@type": ["ex:Type"]
3521
+ },
3522
+ "ex:prop": [{"@value": "value2"}]
3523
+ }])
3524
+ },
3525
+ "node with embedded subject having an IRI value": {
3526
+ input: %({
3527
+ "@id": {
3528
+ "@id": "ex:rei",
3529
+ "ex:prop": {"@id": "ex:value"}
3530
+ },
3531
+ "ex:prop": "value2"
3532
+ }),
3533
+ output: %([{
3534
+ "@id": {
3535
+ "@id": "ex:rei",
3536
+ "ex:prop": [{"@id": "ex:value"}]
3537
+ },
3538
+ "ex:prop": [{"@value": "value2"}]
3539
+ }])
3540
+ },
3541
+ "node with embedded subject having an BNode value": {
3542
+ input: %({
3543
+ "@id": {
3544
+ "@id": "ex:rei",
3545
+ "ex:prop": {"@id": "_:value"}
3546
+ },
3547
+ "ex:prop": "value2"
3548
+ }),
3549
+ output: %([{
3550
+ "@id": {
3551
+ "@id": "ex:rei",
3552
+ "ex:prop": [{"@id": "_:value"}]
3553
+ },
3554
+ "ex:prop": [{"@value": "value2"}]
3555
+ }])
3556
+ },
3557
+ "node with recursive embedded subject": {
3558
+ input: %({
3559
+ "@id": {
3560
+ "@id": {
3561
+ "@id": "ex:rei",
3562
+ "ex:prop": "value3"
3563
+ },
3564
+ "ex:prop": "value"
3565
+ },
3566
+ "ex:prop": "value2"
3567
+ }),
3568
+ output: %([{
3569
+ "@id": {
3570
+ "@id": {
3571
+ "@id": "ex:rei",
3572
+ "ex:prop": [{"@value": "value3"}]
3573
+ },
3574
+ "ex:prop": [{"@value": "value"}]
3575
+ },
3576
+ "ex:prop": [{"@value": "value2"}]
3577
+ }])
3578
+ },
3579
+ "illegal node with subject having no property": {
3580
+ input: %({
3581
+ "@id": {
3582
+ "@id": "ex:rei"
3583
+ },
3584
+ "ex:prop": "value3"
3585
+ }),
3586
+ exception: JSON::LD::JsonLdError::InvalidEmbeddedNode
3587
+ },
3588
+ "illegal node with subject having multiple properties": {
3589
+ input: %({
3590
+ "@id": {
3591
+ "@id": "ex:rei",
3592
+ "ex:prop": ["value1", "value2"]
3593
+ },
3594
+ "ex:prop": "value3"
3595
+ }),
3596
+ exception: JSON::LD::JsonLdError::InvalidEmbeddedNode
3597
+ },
3598
+ "illegal node with subject having multiple types": {
3599
+ input: %({
3600
+ "@id": {
3601
+ "@id": "ex:rei",
3602
+ "@type": ["ex:Type1", "ex:Type2"]
3603
+ },
3604
+ "ex:prop": "value3"
3605
+ }),
3606
+ exception: JSON::LD::JsonLdError::InvalidEmbeddedNode
3607
+ },
3608
+ "illegal node with subject having type and property": {
3609
+ input: %({
3610
+ "@id": {
3611
+ "@id": "ex:rei",
3612
+ "@type": "ex:Type",
3613
+ "ex:prop": "value"
3614
+ },
3615
+ "ex:prop": "value2"
3616
+ }),
3617
+ exception: JSON::LD::JsonLdError::InvalidEmbeddedNode
3618
+ },
3619
+ "node with embedded object": {
3620
+ input: %({
3621
+ "@id": "ex:subj",
3622
+ "ex:value": {
3623
+ "@id": {
3624
+ "@id": "ex:rei",
3625
+ "ex:prop": "value"
3626
+ }
3627
+ }
3628
+ }),
3629
+ output: %([{
3630
+ "@id": "ex:subj",
3631
+ "ex:value": [{
3632
+ "@id": {
3633
+ "@id": "ex:rei",
3634
+ "ex:prop": [{"@value": "value"}]
3635
+ }
3636
+ }]
3637
+ }])
3638
+ },
3639
+ "node with embedded object having properties": {
3640
+ input: %({
3641
+ "@id": "ex:subj",
3642
+ "ex:value": {
3643
+ "@id": {
3644
+ "@id": "ex:rei",
3645
+ "ex:prop": "value"
3646
+ },
3647
+ "ex:prop": "value2"
3648
+ }
3649
+ }),
3650
+ output: %([{
3651
+ "@id": "ex:subj",
3652
+ "ex:value": [{
3653
+ "@id": {
3654
+ "@id": "ex:rei",
3655
+ "ex:prop": [{"@value": "value"}]
3656
+ },
3657
+ "ex:prop": [{"@value": "value2"}]
3658
+ }]
3659
+ }])
3660
+ },
3661
+ "node with recursive embedded object": {
3662
+ input: %({
3663
+ "@id": "ex:subj",
3664
+ "ex:value": {
3665
+ "@id": {
3666
+ "@id": {
3667
+ "@id": "ex:rei",
3668
+ "ex:prop": "value3"
3669
+ },
3670
+ "ex:prop": "value"
3671
+ },
3672
+ "ex:prop": "value2"
3673
+ }
3674
+ }),
3675
+ output: %([{
3676
+ "@id": "ex:subj",
3677
+ "ex:value": [{
3678
+ "@id": {
3679
+ "@id": {
3680
+ "@id": "ex:rei",
3681
+ "ex:prop": [{"@value": "value3"}]
3682
+ },
3683
+ "ex:prop":[{"@value": "value"}]
3684
+ },
3685
+ "ex:prop": [{"@value": "value2"}]
3686
+ }]
3687
+ }])
3688
+ },
3689
+ "node with @annotation property on value object": {
3690
+ input: %({
3691
+ "@id": "ex:bob",
3692
+ "ex:age": {
3693
+ "@value": 23,
3694
+ "@annotation": {"ex:certainty": 0.8}
3695
+ }
3696
+ }),
3697
+ output: %([{
3698
+ "@id": "ex:bob",
3699
+ "ex:age": [{
3700
+ "@value": 23,
3701
+ "@annotation": [{"ex:certainty": [{"@value": 0.8}]}]
3702
+ }]
3703
+ }])
3704
+ },
3705
+ "node with @annotation property on node object": {
3706
+ input: %({
3707
+ "@id": "ex:bob",
3708
+ "ex:name": "Bob",
3709
+ "ex:knows": {
3710
+ "@id": "ex:fred",
3711
+ "ex:name": "Fred",
3712
+ "@annotation": {"ex:certainty": 0.8}
3713
+ }
3714
+ }),
3715
+ output: %([{
3716
+ "@id": "ex:bob",
3717
+ "ex:name": [{"@value": "Bob"}],
3718
+ "ex:knows": [{
3719
+ "@id": "ex:fred",
3720
+ "ex:name": [{"@value": "Fred"}],
3721
+ "@annotation": [{"ex:certainty": [{"@value": 0.8}]}]
3722
+ }]
3723
+ }])
3724
+ },
3725
+ "node with @annotation property multiple values": {
3726
+ input: %({
3727
+ "@id": "ex:bob",
3728
+ "ex:name": "Bob",
3729
+ "ex:knows": {
3730
+ "@id": "ex:fred",
3731
+ "ex:name": "Fred",
3732
+ "@annotation": [{
3733
+ "ex:certainty": 0.8
3734
+ }, {
3735
+ "ex:source": {"@id": "http://example.org/"}
3736
+ }]
3737
+ }
3738
+ }),
3739
+ output: %([{
3740
+ "@id": "ex:bob",
3741
+ "ex:name": [{"@value": "Bob"}],
3742
+ "ex:knows": [{
3743
+ "@id": "ex:fred",
3744
+ "ex:name": [{"@value": "Fred"}],
3745
+ "@annotation": [{
3746
+ "ex:certainty": [{"@value": 0.8}]
3747
+ }, {
3748
+ "ex:source": [{"@id": "http://example.org/"}]
3749
+ }]
3750
+ }]
3751
+ }])
3752
+ },
3753
+ "node with @annotation property that is on the top-level is invalid": {
3754
+ input: %({
3755
+ "@id": "ex:bob",
3756
+ "ex:name": "Bob",
3757
+ "@annotation": {"ex:prop": "value2"}
3758
+ }),
3759
+ exception: JSON::LD::JsonLdError::InvalidAnnotation
3760
+ },
3761
+ "node with @annotation property on a top-level graph node is invalid": {
3762
+ input: %({
3763
+ "@id": "ex:bob",
3764
+ "ex:name": "Bob",
3765
+ "@graph": {
3766
+ "@id": "ex:fred",
3767
+ "ex:name": "Fred",
3768
+ "@annotation": {"ex:prop": "value2"}
3769
+ }
3770
+ }),
3771
+ exception: JSON::LD::JsonLdError::InvalidAnnotation
3772
+ },
3773
+ "node with @annotation property having @id is invalid": {
3774
+ input: %({
3775
+ "@id": "ex:bob",
3776
+ "ex:knows": {
3777
+ "@id": "ex:fred",
3778
+ "@annotation": {
3779
+ "@id": "ex:invalid-ann-id",
3780
+ "ex:prop": "value2"
3781
+ }
3782
+ }
3783
+ }),
3784
+ exception: JSON::LD::JsonLdError::InvalidAnnotation
3785
+ },
3786
+ "node with @annotation property with value object value is invalid": {
3787
+ input: %({
3788
+ "@id": "ex:bob",
3789
+ "ex:knows": {
3790
+ "@id": "fred",
3791
+ "@annotation": "value2"
3792
+ }
3793
+ }),
3794
+ exception: JSON::LD::JsonLdError::InvalidAnnotation
3795
+ },
3796
+ "node with @annotation on a list": {
3797
+ input: %({
3798
+ "@id": "ex:bob",
3799
+ "ex:knows": {
3800
+ "@list": [{"@id": "ex:fred"}],
3801
+ "@annotation": {"ex:prop": "value2"}
3802
+ }
3803
+ }),
3804
+ exception: JSON::LD::JsonLdError::InvalidSetOrListObject
3805
+ },
3806
+ "node with @annotation on a list value": {
3807
+ input: %({
3808
+ "@id": "ex:bob",
3809
+ "ex:knows": {
3810
+ "@list": [
3811
+ {
3812
+ "@id": "ex:fred",
3813
+ "@annotation": {"ex:prop": "value2"}
3814
+ }
3815
+ ]
3816
+ }
3817
+ }),
3818
+ exception: JSON::LD::JsonLdError::InvalidAnnotation
3819
+ },
3820
+ "node with @annotation property on a top-level @included node is invalid": {
3821
+ input: %({
3822
+ "@id": "ex:bob",
3823
+ "ex:name": "Bob",
3824
+ "@included": [{
3825
+ "@id": "ex:fred",
3826
+ "ex:name": "Fred",
3827
+ "@annotation": {"ex:prop": "value2"}
3828
+ }]
3829
+ }),
3830
+ exception: JSON::LD::JsonLdError::InvalidAnnotation
3831
+ },
3832
+ "node with @annotation property on embedded subject": {
3833
+ input: %({
3834
+ "@id": {
3835
+ "@id": "ex:rei",
3836
+ "ex:prop": {"@id": "_:value"}
3837
+ },
3838
+ "ex:prop": {
3839
+ "@value": "value2",
3840
+ "@annotation": {"ex:certainty": 0.8}
3841
+ }
3842
+ }),
3843
+ output: %([{
3844
+ "@id": {
3845
+ "@id": "ex:rei",
3846
+ "ex:prop": [{"@id": "_:value"}]
3847
+ },
3848
+ "ex:prop": [{
3849
+ "@value": "value2",
3850
+ "@annotation": [{
3851
+ "ex:certainty": [{"@value": 0.8}]
3852
+ }]
3853
+ }]
3854
+ }])
3855
+ },
3856
+ "node with @annotation property on embedded object": {
3857
+ input: %({
3858
+ "@id": "ex:subj",
3859
+ "ex:value": {
3860
+ "@id": {
3861
+ "@id": "ex:rei",
3862
+ "ex:prop": "value"
3863
+ },
3864
+ "@annotation": {"ex:certainty": 0.8}
3865
+ }
3866
+ }),
3867
+ output: %([{
3868
+ "@id": "ex:subj",
3869
+ "ex:value": [{
3870
+ "@id": {
3871
+ "@id": "ex:rei",
3872
+ "ex:prop": [{"@value": "value"}]
3873
+ },
3874
+ "@annotation": [{
3875
+ "ex:certainty": [{"@value": 0.8}]
3876
+ }]
3877
+ }]
3878
+ }])
3879
+ },
3880
+ "embedded node with reverse relationship": {
3881
+ input: %({
3882
+ "@context": {
3883
+ "rel": {"@reverse": "ex:rel"}
3884
+ },
3885
+ "@id": {
3886
+ "@id": "ex:rei",
3887
+ "rel": {"@id": "ex:value"}
3888
+ },
3889
+ "ex:prop": "value2"
3890
+ }),
3891
+ exception: JSON::LD::JsonLdError::InvalidEmbeddedNode
3892
+ },
3893
+ "embedded node with expanded reverse relationship": {
3894
+ input: %({
3895
+ "@id": {
3896
+ "@id": "ex:rei",
3897
+ "@reverse": {
3898
+ "ex:rel": {"@id": "ex:value"}
3899
+ }
3900
+ },
3901
+ "ex:prop": "value2"
3902
+ }),
3903
+ exception: JSON::LD::JsonLdError::InvalidEmbeddedNode
3904
+ },
3905
+ "embedded node used as subject in reverse relationship": {
3906
+ input: %({
3907
+ "@context": {
3908
+ "rel": {"@reverse": "ex:rel"}
3909
+ },
3910
+ "@id": {
3911
+ "@id": "ex:rei",
3912
+ "ex:prop": {"@id": "ex:value"}
3913
+ },
3914
+ "rel": {"@id": "ex:value2"}
3915
+ }),
3916
+ output: %([{
3917
+ "@id": {
3918
+ "@id": "ex:rei",
3919
+ "ex:prop": [{"@id": "ex:value"}]
3920
+ },
3921
+ "@reverse": {
3922
+ "ex:rel": [{"@id": "ex:value2"}]
3923
+ }
3924
+ }])
3925
+ },
3926
+ "embedded node used as object in reverse relationship": {
3927
+ input: %({
3928
+ "@context": {
3929
+ "rel": {"@reverse": "ex:rel"}
3930
+ },
3931
+ "@id": "ex:subj",
3932
+ "rel": {
3933
+ "@id": {
3934
+ "@id": "ex:rei",
3935
+ "ex:prop": {"@id": "ex:value"}
3936
+ },
3937
+ "ex:prop": {"@id": "ex:value2"}
3938
+ }
3939
+ }),
3940
+ output: %([{
3941
+ "@id": "ex:subj",
3942
+ "@reverse": {
3943
+ "ex:rel": [{
3944
+ "@id": {
3945
+ "@id": "ex:rei",
3946
+ "ex:prop": [{"@id": "ex:value"}]
3947
+ },
3948
+ "ex:prop": [{"@id": "ex:value2"}]
3949
+ }]
3950
+ }
3951
+ }])
3952
+ },
3953
+ "node with @annotation property on node object with reverse relationship": {
3954
+ input: %({
3955
+ "@context": {
3956
+ "knownBy": {"@reverse": "ex:knows"}
3957
+ },
3958
+ "@id": "ex:bob",
3959
+ "ex:name": "Bob",
3960
+ "knownBy": {
3961
+ "@id": "ex:fred",
3962
+ "ex:name": "Fred",
3963
+ "@annotation": {"ex:certainty": 0.8}
3964
+ }
3965
+ }),
3966
+ output: %([{
3967
+ "@id": "ex:bob",
3968
+ "ex:name": [{"@value": "Bob"}],
3969
+ "@reverse": {
3970
+ "ex:knows": [{
3971
+ "@id": "ex:fred",
3972
+ "ex:name": [{"@value": "Fred"}],
3973
+ "@annotation": [{"ex:certainty": [{"@value": 0.8}]}]
3974
+ }]
3975
+ }
3976
+ }])
3977
+ },
3978
+ "reverse relationship inside annotation": {
3979
+ input: %({
3980
+ "@context": {
3981
+ "claims": {"@reverse": "ex:claims", "@type": "@id"}
3982
+ },
3983
+ "@id": "ex:bob",
3984
+ "ex:knows": {
3985
+ "@id": "ex:jane",
3986
+ "@annotation": {
3987
+ "ex:certainty": 0.8,
3988
+ "claims": "ex:sue"
3989
+ }
3990
+ }
3991
+ }),
3992
+ output: %([{
3993
+ "@id": "ex:bob",
3994
+ "ex:knows": [{
3995
+ "@id": "ex:jane",
3996
+ "@annotation": [{
3997
+ "ex:certainty": [{"@value": 0.8}],
3998
+ "@reverse": {
3999
+ "ex:claims": [{"@id": "ex:sue"}]
4000
+ }
4001
+ }]
4002
+ }]
4003
+ }])
4004
+ },
4005
+ }.each do |title, params|
4006
+ it(title) {run_expand params.merge(rdfstar: true)}
4007
+ end
3377
4008
  end
3378
4009
 
3379
4010
  begin