module JSONModel
Public Class Methods
JSONModel(source)
click to toggle source
# File lib/aspace_client/jsonmodel.rb, line 57 def self.JSONModel(source) if !@@models.has_key?(source.to_s) load_schema(source.to_s) end @@models[source.to_s] or raise "JSONModel not found for #{source}" end
add_error_handler(&block)
click to toggle source
# File lib/aspace_client/jsonmodel_client.rb, line 52 def self.add_error_handler(&block) @@error_handlers << block end
all(uri, type_descriptor)
click to toggle source
Grab an array of JSON
objects from ‘uri’ and use the ‘type_descriptor’ property of each object to cast it into a JSONModel
.
# File lib/aspace_client/jsonmodel_client.rb, line 23 def self.all(uri, type_descriptor) JSONModel::HTTP.get_json(uri).map do |obj| JSONModel(obj[type_descriptor.to_s]).new(obj) end end
allow_unmapped_enum_value(val, magic_value = 'other_unmapped')
click to toggle source
# File lib/aspace_client/jsonmodel.rb, line 125 def self.allow_unmapped_enum_value(val, magic_value = 'other_unmapped') if val.is_a? Array val.each { |elt| allow_unmapped_enum_value(elt) } elsif val.is_a? Hash val.each do |k, v| if k == 'enum' v << magic_value else allow_unmapped_enum_value(v) end end end end
backend_url()
click to toggle source
# File lib/aspace_client/jsonmodel_client.rb, line 41 def self.backend_url if Module.const_defined?(:BACKEND_SERVICE_URL) BACKEND_SERVICE_URL else init_args[:url] end end
client_mode?()
click to toggle source
# File lib/aspace_client/jsonmodel.rb, line 298 def self.client_mode? @@init_args[:client_mode] end
custom_validations()
click to toggle source
# File lib/aspace_client/jsonmodel.rb, line 18 def self.custom_validations @@custom_validations end
destroy_model(type)
click to toggle source
# File lib/aspace_client/jsonmodel.rb, line 100 def self.destroy_model(type) @@models.delete(type.to_s) end
enum_default_value(name)
click to toggle source
# File lib/aspace_client/jsonmodel.rb, line 293 def self.enum_default_value(name) @@init_args[:enum_source].default_value_for(name) end
enum_values(name)
click to toggle source
# File lib/aspace_client/jsonmodel.rb, line 288 def self.enum_values(name) @@init_args[:enum_source].values_for(name) end
handle_error(err)
click to toggle source
# File lib/aspace_client/jsonmodel_client.rb, line 56 def self.handle_error(err) @@error_handlers.each do |handler| handler.call(err) end end
init(opts = {})
click to toggle source
# File lib/aspace_client/jsonmodel.rb, line 218 def self.init(opts = {}) @@init_args ||= nil # Skip initialisation if this model has already been loaded. if @@init_args[:initialized] return true else @@init_args[:initialized] = true end if opts.has_key?(:strict_mode) @@strict_mode = true end @@init_args = opts if !opts.has_key?(:enum_source) if opts[:client_mode] require_relative 'jsonmodel_client' opts[:enum_source] = JSONModel::Client::EnumSource.new else raise "Required JSONModel.init arg :enum_source was missing" end end # Load all JSON schemas from the schemas subdirectory # Create a model class for each one. Dir.glob(File.join(File.dirname(__FILE__), "schemas", "*.rb")).sort.each do |schema| schema_name = File.basename(schema, ".rb") load_schema(schema_name) end require_relative "validations" # For dynamic enums, automatically slot in the 'other_unmapped' string as an allowable value if @@init_args[:allow_other_unmapped] enum_wrapper = Struct.new(:enum_source).new(@@init_args[:enum_source]) def enum_wrapper.valid?(name, value) value == 'other_unmapped' || enum_source.valid?(name, value) end def enum_wrapper.editable?(name) enum_source.editable?(name) end def enum_wrapper.values_for(name) enum_source.values_for(name) + ['other_unmapped'] end def enum_wrapper.default_value_for(name) enum_source.default_value_for(name) end @@init_args[:enum_source] = enum_wrapper end true rescue # If anything went wrong we're not initialised. @@init_args = nil raise $! end
load_schema(schema_name)
click to toggle source
# File lib/aspace_client/jsonmodel.rb, line 140 def self.load_schema(schema_name) if not @@models[schema_name] old_verbose = $VERBOSE $VERBOSE = nil src = schema_src(schema_name) return if !src entry = eval(src) $VERBOSE = old_verbose parent = entry[:schema]["parent"] if parent load_schema(parent) base = @@models[parent].schema["properties"].clone properties = ASUtils.deep_merge(base, entry[:schema]["properties"]) # Maybe we'll eventually want the version of a schema to be # automatically set to max(my_version, parent_version), but for now... if entry[:schema]["version"] < @@models[parent].schema_version raise ("Can't inherit from a JSON schema whose version is newer than ours " + "(our (#{schema_name}) version: #{entry[:schema]['version']}; " + "parent (#{parent}) version: #{@@models[parent].schema_version})") end entry[:schema]["properties"] = properties end # All records have a lock_version property that we use for optimistic concurrency control. entry[:schema]["properties"]["lock_version"] = {"type" => ["integer", "string"], "required" => false} # All records must indicate their model type entry[:schema]["properties"]["jsonmodel_type"] = {"type" => "string", "ifmissing" => "error"} # All records have audit fields entry[:schema]["properties"]["created_by"] = {"type" => "string", "readonly" => true} entry[:schema]["properties"]["last_modified_by"] = {"type" => "string", "readonly" => true} entry[:schema]["properties"]["user_mtime"] = {"type" => "date-time", "readonly" => true} entry[:schema]["properties"]["system_mtime"] = {"type" => "date-time", "readonly" => true} entry[:schema]["properties"]["create_time"] = {"type" => "date-time", "readonly" => true} # Records may include a reference to the repository that contains them entry[:schema]["properties"]["repository"] ||= { "type" => "object", "subtype" => "ref", "readonly" => "true", "properties" => { "ref" => { "type" => "JSONModel(:repository) uri", "ifmissing" => "error", "readonly" => "true" }, "_resolved" => { "type" => "object", "readonly" => "true" } } } if @@init_args && @@init_args[:allow_other_unmapped] allow_unmapped_enum_value(entry[:schema]['properties']) end ASUtils.find_local_directories("schemas/#{schema_name}_ext.rb"). select {|path| File.exists?(path)}. each do |schema_extension| entry[:schema]['properties'] = ASUtils.deep_merge(entry[:schema]['properties'], eval(File.open(schema_extension).read)) end self.create_model_for(schema_name, entry[:schema]) end end
parse_jsonmodel_ref(ref)
click to toggle source
# File lib/aspace_client/jsonmodel.rb, line 303 def self.parse_jsonmodel_ref(ref) if ref.is_a? String and ref =~ /JSONModel\(:([a-zA-Z_\-]+)\) (.*)/ [$1.intern, $2] else nil end end
parse_reference(reference, opts = {})
click to toggle source
Parse a URI reference like /repositories/123/archival_objects/500 into {:id => 500, :type => :archival_object}
# File lib/aspace_client/jsonmodel.rb, line 88 def self.parse_reference(reference, opts = {}) @@models.each do |type, model| id = model.id_for(reference, opts, true) if id return {:id => id, :type => type, :repository => repository_for(reference)} end end nil end
repository()
click to toggle source
The currently selected repository (if any)
# File lib/aspace_client/jsonmodel_client.rb, line 16 def self.repository Thread.current[:selected_repo_id] end
repository_for(reference)
click to toggle source
# File lib/aspace_client/jsonmodel.rb, line 77 def self.repository_for(reference) if reference =~ /^(\/repositories\/[0-9]+)\// return $1 else return nil end end
schema_src(schema_name)
click to toggle source
# File lib/aspace_client/jsonmodel.rb, line 105 def self.schema_src(schema_name) if schema_name.to_s !~ /\A[0-9A-Za-z_-]+\z/ raise "Invalid schema name: #{schema_name}" end [*ASUtils.find_local_directories('schemas'), File.join(File.dirname(__FILE__), "schemas")].each do |dir| schema = File.join(dir, "#{schema_name}.rb") if File.exists?(schema) return File.open(schema).read end end nil end
set_repository(id)
click to toggle source
Set the repository that subsequent operations will apply to.
# File lib/aspace_client/jsonmodel_client.rb, line 10 def self.set_repository(id) Thread.current[:selected_repo_id] = id end
strict_mode?()
click to toggle source
# File lib/aspace_client/jsonmodel.rb, line 27 def self.strict_mode? @@strict_mode end
with_repository(id) { || ... }
click to toggle source
# File lib/aspace_client/jsonmodel_client.rb, line 30 def self.with_repository(id) old_repo = Thread.current[:selected_repo_id] begin self.set_repository(id) yield ensure self.set_repository(old_repo) end end
Protected Class Methods
clean_data(data)
click to toggle source
# File lib/aspace_client/jsonmodel.rb, line 315 def self.clean_data(data) data = ASUtils.keys_as_strings(data) if data.is_a?(Hash) data = ASUtils.jsonmodels_to_hashes(data) data end
create_model_for(type, schema)
click to toggle source
Create and return a new JSONModel
class called ‘type’, based on the JSONSchema ‘schema’
# File lib/aspace_client/jsonmodel.rb, line 325 def self.create_model_for(type, schema) cls = Class.new(JSONModelType) cls.init(type, schema, Array(@@init_args[:mixins])) @@models[type] = cls end
init_args()
click to toggle source
# File lib/aspace_client/jsonmodel.rb, line 334 def self.init_args @@init_args end
Public Instance Methods
JSONModel(source)
click to toggle source
# File lib/aspace_client/jsonmodel.rb, line 66 def JSONModel(source) JSONModel.JSONModel(source) end
models()
click to toggle source
Yield all known JSONModel
classes
# File lib/aspace_client/jsonmodel.rb, line 72 def models @@models end
strict_mode(val)
click to toggle source
# File lib/aspace_client/jsonmodel.rb, line 22 def strict_mode(val) @@strict_mode = val end