Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V3 #82

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft

V3 #82

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ if ENV['FARADAY_VERSION']
gem 'faraday', ENV['FARADAY_VERSION']
end

gem 'debug'
gem 'debug'
102 changes: 61 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ From the source code do `rake install`, or get the latest release [from RubyGems

## Building New Objects

There is (or will be) a class for all types in [IIIF Presentation API Spec](http://iiif.io/api/presentation/2.0/).
There is (or will be) a class for all types in [IIIF Presentation API Spec v3.0](http://iiif.io/api/presentation/3.0/).



Expand All @@ -19,7 +19,7 @@ There is (or will be) a class for all types in [IIIF Presentation API Spec](http
require 'iiif/presentation'

seed = {
'@id' => 'http://example.com/manifest',
'id' => 'http://example.com/manifest',
'label' => 'My Manifest'
}
# Any options you add are added to the object
Expand All @@ -33,32 +33,34 @@ manifest.sequences << sequence
canvas = IIIF::Presentation::Canvas.new()
# All classes act like `ActiveSupport::OrderedHash`es, for the most part.
# Use `[]=` to set JSON-LD properties...
canvas['@id'] = 'http://example.com/canvas'
canvas.id = 'http://example.com/canvas'
# ...but there are also accessors and mutators for the properties mentioned in
# the spec
canvas.width = 10
canvas.height = 20
canvas.label = 'My Canvas'

# Add images
service = IIIF::Presentation::Resource.new('@context' => 'http://iiif.io/api/image/2/context.json', 'profile' => 'http://iiif.io/api/image/2/level2.json', '@id' => "http://images.exampl.com/loris2/my-image")
service = IIIF::Presentation::Resource.new('@context' => 'http://iiif.io/api/image/3/context.json', 'profile' => 'http://iiif.io/api/image/2/level2.json', 'id' => "http://images.exampl.com/loris2/my-image")

image = IIIF::Presentation::ImageResource.new()
i['@id'] = "http://images.exampl.com/loris2/my-image/full/#{canvas.width},#{canvas.height}/0/default.jpg"
image = IIIF::Presentation::ImageResource.new
i.id = "http://images.exampl.com/loris2/my-image/full/#{canvas.width},#{canvas.height}/0/default.jpg"
i.format = "image/jpeg"
i.width = canvas.width
i.height = canvas.height
i.service = service

images = IIIF::Presentation::Resource.new('@type' => 'oa:Annotation', 'motivation' => 'sc:painting', '@id' => "#{canvas['@id']}/images", 'resource' => i)
annotation = IIIF::Presentation::Annotation.new('type' => 'Annotation', 'motivation' => 'painting', 'id' => "#{canvas.id}/images", 'resource' => i)

canvas.images << images
annotation_page = IIIF::Presentation::AnnotationPage.new()
annotation_page.items << annotation
canvas.items << annoation_page

# Add other content resources
oc = IIIF::Presentation::Resource.new('@id' => 'http://example.com/content')
canvas.other_content << oc

manifest.sequences.first.canvases << canvas
manifest.canvases << canvas

puts manifest.to_json(pretty: true)
```
Expand Down Expand Up @@ -92,8 +94,8 @@ manifest.viewing_hint = 'paged'
puts manifest.to_json(pretty: true, force: true) # force: true skips validations

> {
> "@context": "http://iiif.io/api/presentation/2/context.json",
> "@type": "sc:Manifest",
> "@context": "http://iiif.io/api/presentation/3/context.json",
> "type": "Manifest",
> "viewingHint": "paged"
> }

Expand All @@ -102,44 +104,61 @@ puts manifest.to_json(pretty: true, force: true) # force: true skips validations
## Parsing Existing Objects

Use `IIIF::Service#parse`. It will figure out what the object
should be, based on `@type`, and fall back to `Hash` when
should be, based on `type`, and fall back to `Hash` when
it can't e.g.:

```ruby
seed = '{
"@context": "http://iiif.io/api/presentation/2/context.json",
"@id": "http://example.com/manifest",
"@type": "sc:Manifest",
"@context": "http://iiif.io/api/presentation/3/context.json",
"id": "http://example.com/manifest",
"type": "Manifest",
"label": "My Manifest",
"service": {
"@context": "http://iiif.io/api/image/2/context.json",
"@id":"http://www.example.org/images/book1-page1",
"id":"http://www.example.org/images/book1-page1",
"profile":"http://iiif.io/api/image/2/profiles/level2.json"
},
"seeAlso": {
"@id": "http://www.example.org/library/catalog/book1.marc",
"id": "http://www.example.org/library/catalog/book1.marc",
"format": "application/marc"
},
"sequences": [
"items": [
{
"@id":"http://www.example.org/iiif/book1/sequence/normal",
"@type":"sc:Sequence",
"label":"Current Page Order",
"viewingDirection":"left-to-right",
"viewingHint":"paged",
"startCanvas": "http://www.example.org/iiif/book1/canvas/p2",
"canvases": [
"id": "http://example.com/canvas",
"type": "Canvas",
"width": 10,
"height": 20,
"label": "My Canvas",
"items": [
{
"@id": "http://example.com/canvas",
"@type": "sc:Canvas",
"width": 10,
"height": 20,
"label": "My Canvas",
"otherContent": [
"id": "https://example.org/iiif/book1/page/p1/1",
"type": "AnnotationPage",
"items": [
{
"@id": "http://example.com/content",
"@type":"sc:AnnotationList",
"motivation": "sc:painting"
"id": "https://example.org/iiif/book1/annotation/p0001-image",
"type": "Annotation",
"motivation": "painting",
"body": {
"id": "https://example.org/iiif/book1/page1/full/max/0/default.jpg",
"type": "Image",
"format": "image/jpeg",
"service": [
{
"id": "https://example.org/iiif/book1/page1",
"type": "ImageService3",
"profile": "level2",
"service": [
{
"@id": "https://example.org/iiif/auth/login",
"@type": "AuthCookieService1"
}
]
}
],
"height": 2000,
"width": 1500
},
"target": "https://example.org/iiif/book1/canvas/p1"
}
]
}
Expand All @@ -148,6 +167,7 @@ seed = '{
]
}'


obj = IIIF::Service.parse(seed) # can also be a file path or a Hash
puts obj.class
puts obj.see_also.class
Expand All @@ -163,15 +183,15 @@ try to set something to a type it should never be:

```ruby
manifest = IIIF::Presentation::Manifest.new
manifest.sequences = 'quux'
manifest.items = 'quux'

> [...] sequences must be an Array. (IIIF::Presentation::IllegalValueError)
> [...] items must be an Array. (IIIF::Presentation::IllegalValueError)
```

and also if any required properties are missing when calling `to_json`

```ruby
canvas = IIIF::Presentation::Canvas.new('@id' => 'http://example.com/canvas')
canvas = IIIF::Presentation::Canvas.new('id' => 'http://example.com/canvas')
puts canvas.to_json(pretty: true)

> A(n) width is required for each IIIF::Presentation::Canvas (IIIF::Presentation::MissingRequiredKeyError)
Expand All @@ -180,13 +200,13 @@ puts canvas.to_json(pretty: true)
but you can skip this validation by adding `force: true`:

```ruby
canvas = IIIF::Presentation::Canvas.new('@id' => 'http://example.com/canvas')
canvas = IIIF::Presentation::Canvas.new('id' => 'http://example.com/canvas')
puts canvas.to_json(pretty: true, force: true)

> {
> "@context": "http://iiif.io/api/presentation/2/context.json",
> "@id": "http://example.com/canvas",
> "@type": "sc:Canvas"
> "@context": "http://iiif.io/api/presentation/3/context.json",
> "id": "http://example.com/canvas",
> "type": "Canvas"
> }
```
This all needs a bit of tidying up, finishing, and refactoring, so expect it to
Expand Down
4 changes: 2 additions & 2 deletions lib/iiif/presentation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
manifest
resource
image_resource
sequence
service
range
start
}.each do |f|
require File.join(File.dirname(__FILE__), 'presentation', f)
end
Expand All @@ -20,7 +20,7 @@

module IIIF
module Presentation
CONTEXT ||= 'http://iiif.io/api/presentation/2/context.json'
CONTEXT ||= 'http://iiif.io/api/presentation/3/context.json'

class MissingRequiredKeyError < StandardError; end
class IllegalValueError < StandardError; end
Expand Down
2 changes: 1 addition & 1 deletion lib/iiif/presentation/abstract_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class AbstractResource < Service
# Every subclass should override the following five methods where
# appropriate, see Subclasses for how.
def required_keys
%w{ @type }
%w{ type }
end

def any_type_keys # these are allowed on all classes
Expand Down
4 changes: 2 additions & 2 deletions lib/iiif/presentation/annotation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ def abstract_resource_only_keys
end

def initialize(hsh={})
hsh['@type'] = TYPE unless hsh.has_key? '@type'
hsh['motivation'] = 'sc:painting' unless hsh.has_key? 'motivation'
hsh['type'] = TYPE unless hsh.has_key? 'type'
hsh['motivation'] = 'painting' unless hsh.has_key? 'motivation'
super(hsh)
end

Expand Down
6 changes: 3 additions & 3 deletions lib/iiif/presentation/annotation_list.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@ module IIIF
module Presentation
class AnnotationList < AbstractResource

TYPE = 'sc:AnnotationList'
TYPE = 'AnnotationList'

def required_keys
super + %w{ @id }
super + %w{ id }
end

def array_only_keys;
super + %w{ resources };
end

def initialize(hsh={})
hsh['@type'] = TYPE unless hsh.has_key? '@type'
hsh['type'] = TYPE unless hsh.has_key? 'type'
super(hsh)
end

Expand Down
6 changes: 3 additions & 3 deletions lib/iiif/presentation/canvas.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ class Canvas < AbstractResource

# TODO (?) a simple 'Image Canvas' constructor.

TYPE = 'sc:Canvas'
TYPE = 'Canvas'

def required_keys
super + %w{ @id width height label }
super + %w{ id width height label }
end

def any_type_keys
Expand All @@ -30,7 +30,7 @@ def legal_viewing_hint_values
end

def initialize(hsh={})
hsh['@type'] = TYPE unless hsh.has_key? '@type'
hsh['type'] = TYPE unless hsh.has_key? 'type'
super(hsh)
end

Expand Down
8 changes: 4 additions & 4 deletions lib/iiif/presentation/collection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,24 @@ module IIIF
module Presentation
class Collection < AbstractResource

TYPE = 'sc:Collection'
TYPE = 'Collection'

def required_keys
super + %w{ @id label }
super + %w{ id label }
end

def array_only_keys
super + %w{ collections manifests }
end

def initialize(hsh={})
hsh['@type'] = TYPE unless hsh.has_key? '@type'
hsh['type'] = TYPE unless hsh.has_key? 'type'
super(hsh)
end

def validate
# each member of collections and manifests must be a Hash
# each member of collections and manifests MUST have @id, @type, and label
# each member of collections and manifests MUST have id, type, and label
end

end
Expand Down
14 changes: 7 additions & 7 deletions lib/iiif/presentation/image_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def int_only_keys
end

def initialize(hsh={})
hsh['@type'] = TYPE unless hsh.has_key? '@type'
hsh['type'] = TYPE unless hsh.has_key? 'type'
super(hsh)
end

Expand All @@ -22,7 +22,7 @@ class << self
IMAGE_API_CONTEXT = 'http://iiif.io/api/image/2/context.json'
DEFAULT_FORMAT = 'image/jpeg'
# Create a new ImageResource that includes a IIIF Image API Service
# See http://iiif.io/api/presentation/2.0/#image-resources
# See http://iiif.io/api/presentation/3.0/#image-resources
#
# Params
# * :service_id (required) - The base URI for the image on the image
Expand All @@ -48,12 +48,12 @@ class << self
# The result is something like this:
#
# {
# "@id":"http://www.example.org/iiif/book1/res/page1.jpg",
# "@type":"dctypes:Image",
# "id":"http://www.example.org/iiif/book1/res/page1.jpg",
# "type":"dctypes:Image",
# "format":"image/jpeg",
# "service": {
# "@context": "http://iiif.io/api/image/2/context.json",
# "@id":"http://www.example.org/images/book1-page1",
# "id":"http://www.example.org/images/book1-page1",
# "profile":"http://iiif.io/api/image/2/profiles/level2.json",
# },
# "height":2000,
Expand All @@ -76,7 +76,7 @@ def create_image_api_image_resource(params={})
remote_info = get_info(service_id) if !have_whp || copy_info

resource = self.new
resource['@id'] = resource_id
resource['id'] = resource_id
resource.format = format
resource.width = width.nil? ? remote_info['width'] : width
resource.height = height.nil? ? remote_info['height'] : height
Expand All @@ -85,7 +85,7 @@ def create_image_api_image_resource(params={})
resource.service.merge!(remote_info)
else
resource.service['@context'] = IMAGE_API_CONTEXT
resource.service['@id'] = service_id
resource.service['id'] = service_id
if profile.nil?
if remote_info['profile'].kind_of?(Array)
resource.service['profile'] = remote_info['profile'][0]
Expand Down
6 changes: 3 additions & 3 deletions lib/iiif/presentation/layer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ module IIIF
module Presentation
class Layer < AbstractResource

TYPE = 'sc:Layer'
TYPE = 'Layer'

def required_keys
super + %w{ @id label }
super + %w{ id label }
end

def array_only_keys
Expand All @@ -19,7 +19,7 @@ def string_only_keys
end

def initialize(hsh={})
hsh['@type'] = TYPE unless hsh.has_key? '@type'
hsh['type'] = TYPE unless hsh.has_key? 'type'
super(hsh)
end

Expand Down
Loading