Class: IIIF::Service

Inherits:
Object
  • Object
show all
Includes:
HashBehaviours
Defined in:
lib/iiif/service.rb

Direct Known Subclasses

Presentation::AbstractResource

Constant Summary

Constants included from HashBehaviours

HashBehaviours::SIMPLE_SELF_RETURNERS

Class Method Summary collapse

Instance Method Summary collapse

Methods included from HashBehaviours

#clear, #merge, #merge!, #reject!, #select, #select!

Constructor Details

#initialize(hsh = {}) ⇒ Service

Returns a new instance of Service.



21
22
23
24
25
26
27
28
29
# File 'lib/iiif/service.rb', line 21

def initialize(hsh={})
  @data = IIIF::OrderedHash[hsh]
  self.define_methods_for_any_type_keys
  self.define_methods_for_array_only_keys
  self.define_methods_for_string_only_keys
  self.define_methods_for_int_only_keys
  self.define_methods_for_abstract_resource_only_keys
  self.snakeize_keys
end

Class Method Details

.from_ordered_hash(hsh, default_klass = IIIF::OrderedHash) ⇒ Object



199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/iiif/service.rb', line 199

def self.from_ordered_hash(hsh, default_klass=IIIF::OrderedHash)
  # Create a new object (new_object)
  type = nil
  if hsh.has_key?('@type')
    type = IIIF::Service.get_descendant_class_by_jld_type(hsh['@type'])
  end
  new_object = type.nil? ? default_klass.new : type.new

  hsh.keys.each do |key|
    new_key = key.underscore == key ? key : key.underscore
    if hsh[key].kind_of?(Array)
      new_object[new_key] = []
      hsh[key].each do |member|
        if new_key == 'service'
          new_object[new_key] << IIIF::Service.from_ordered_hash(member, IIIF::Service)
        elsif new_key == 'resource'
          new_object[new_key] << IIIF::Service.from_ordered_hash(hsh[key], IIIF::Presentation::Resource)
        elsif member.kind_of?(Hash)
          new_object[new_key] << IIIF::Service.from_ordered_hash(member)
        else
          new_object[new_key] << member
          # Again, no nested arrays, right?
        end
      end
    elsif new_key == 'service'
      new_object[new_key] = IIIF::Service.from_ordered_hash(hsh[key], IIIF::Service)
    elsif new_key == 'resource'
      new_object[new_key] = IIIF::Service.from_ordered_hash(hsh[key], IIIF::Presentation::Resource)
    elsif hsh[key].kind_of?(Hash)
      new_object[new_key] = IIIF::Service.from_ordered_hash(hsh[key])
    else
      new_object[new_key] = hsh[key]
    end
  end
  new_object
end

.parse(s) ⇒ Object

Parse from a file path, string, or existing hash



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/iiif/service.rb', line 34

def parse(s)
  ordered_hash = nil
  if s.kind_of?(String) && File.exist?(s)
    ordered_hash = IIIF::OrderedHash[JSON.parse(IO.read(s))]
  elsif s.kind_of?(String) && !File.exist?(s)
    ordered_hash = IIIF::OrderedHash[JSON.parse(s)]
  elsif s.kind_of?(Hash)
    ordered_hash = IIIF::OrderedHash[s]
  else
    m = '#parse takes a path to a file, a JSON String, or a Hash, '
    m += "argument was a #{s.class}."
    if s.kind_of?(String)
      m+= "If you were trying to point to a file, does it exist?"
    end
    raise ArgumentError, m
  end
  return IIIF::Service.from_ordered_hash(ordered_hash)
end

Instance Method Details

#abstract_resource_only_keysObject



17
# File 'lib/iiif/service.rb', line 17

def abstract_resource_only_keys; %w{ }; end

#any_type_keysObject



14
# File 'lib/iiif/service.rb', line 14

def any_type_keys; %w{ }; end

#array_only_keysObject



16
# File 'lib/iiif/service.rb', line 16

def array_only_keys; %w{ }; end

#hash_only_keysObject



18
# File 'lib/iiif/service.rb', line 18

def hash_only_keys; %w{ }; end

#int_only_keysObject



19
# File 'lib/iiif/service.rb', line 19

def int_only_keys; %w{ }; end

#required_keysObject

Anything goes! SHOULD have @id and profile, MAY have label Consider subclassing this for typical services…



13
# File 'lib/iiif/service.rb', line 13

def required_keys; %w{ }; end

#string_only_keysObject



15
# File 'lib/iiif/service.rb', line 15

def string_only_keys; %w{ }; end

#to_json(opts = {}) ⇒ Object

Options

* pretty: (true|false). Should the JSON be pretty-printed? (default: false)
* All options available in #to_ordered_hash


93
94
95
96
97
98
99
100
# File 'lib/iiif/service.rb', line 93

def to_json(opts={})
  hsh = self.to_ordered_hash(opts)
  if opts.fetch(:pretty, false)
    JSON.pretty_generate(hsh)
  else
    hsh.to_json
  end
end

#to_ordered_hash(opts = {}) ⇒ Object

Options:

* force: (true|false). Skips validations.
* sort_json_ld_keys: (true|false). Brings all properties starting with
    '@'. Default: true. to the top of the document and sorts them.


106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/iiif/service.rb', line 106

def to_ordered_hash(opts={})
  force = opts.fetch(:force, false)
  sort_json_ld_keys = opts.fetch(:sort_json_ld_keys, true)

  unless force
    self.validate
  end

  export_hash = IIIF::OrderedHash.new

  if sort_json_ld_keys
    self.keys.select { |k| k.start_with?('@') }.sort!.each do |k|
      export_hash[k] = self.data[k]
    end
  end

  sub_opts = {
    include_context: false,
    sort_json_ld_keys: sort_json_ld_keys,
    force: force
  }
  self.keys.each do |k|
    unless sort_json_ld_keys && k.start_with?('@')
      if self.data[k].respond_to?(:to_ordered_hash) #.respond_to?(:to_ordered_hash)
        export_hash[k] = self.data[k].to_ordered_hash(sub_opts)

      elsif self.data[k].kind_of?(Hash)
        export_hash[k] = IIIF::OrderedHash.new
        self.data[k].each do |sub_k, v|

          if v.respond_to?(:to_ordered_hash)
            export_hash[k][sub_k] = v.to_ordered_hash(sub_opts)

          elsif v.kind_of?(Array)
            export_hash[k][sub_k] = []
            v.each do |member|
              if member.respond_to?(:to_ordered_hash)
                export_hash[k][sub_k] << member.to_ordered_hash(sub_opts)
              else
                export_hash[k][sub_k] << member
              end
            end
          else
            export_hash[k][sub_k] = v
          end
        end

      elsif self.data[k].kind_of?(Array)
        export_hash[k] = []

        self.data[k].each do |member|
          if member.respond_to?(:to_ordered_hash)
            export_hash[k] << member.to_ordered_hash(sub_opts)

          elsif member.kind_of?(Hash)
            hsh = IIIF::OrderedHash.new
            export_hash[k] << hsh
            member.each do |sub_k,v|

              if v.respond_to?(:to_ordered_hash)
                hsh[sub_k] = v.to_ordered_hash(sub_opts)

              elsif v.kind_of?(Array)
                hsh[sub_k] = []

                v.each do |sub_member|
                  if sub_member.respond_to?(:to_ordered_hash)
                    hsh[sub_k] << sub_member.to_ordered_hash(sub_opts)
                  else
                    hsh[sub_k] << sub_member
                  end
                end
              else
                hsh[sub_k] = v
              end
            end

          else
            export_hash[k] << member
            # there are no nested arrays, right?
          end
        end
      else
        export_hash[k] = self.data[k]
      end

    end
  end
  export_hash.remove_empties
  export_hash.camelize_keys
  export_hash
end

#validateObject



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/iiif/service.rb', line 54

def validate
  # TODO:
  # * check for required keys
  # * type check Array-only values
  # * type check String-only values
  # * type check Integer-only values
  # * type check AbstractResource-only values
  self.required_keys.each do |k|
    unless self.has_key?(k)
      m = "A(n) #{k} is required for each #{self.class}"
      raise IIIF::Presentation::MissingRequiredKeyError, m
    end
  end
  # Viewing Direction values
  if self.has_key?('viewing_direction')
    unless self.legal_viewing_direction_values.include?(self['viewing_direction'])
      m = "viewingDirection must be one of #{legal_viewing_direction_values}"
      raise IIIF::Presentation::IllegalValueError, m
    end
  end
  # Viewing Hint values
  if self.has_key?('viewing_hint')
    unless self.legal_viewing_hint_values.include?(self['viewing_hint'])
      m = "viewingHint for #{self.class} must be one of #{self.legal_viewing_hint_values}."
      raise IIIF::Presentation::IllegalValueError, m
    end
  end
  # Metadata is all hashes
  if self.has_key?('metadata')
    unless self['metadata'].all? { |entry| entry.kind_of?(Hash) }
      m = 'All entries in the metadata list must be a type of Hash'
      raise IIIF::Presentation::IllegalValueError, m
    end
  end
end