aspace_client 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/lib/aspace_client.rb +15 -0
  3. data/lib/aspace_client/archivesspace_json_schema.rb +210 -0
  4. data/lib/aspace_client/asutils.rb +142 -0
  5. data/lib/aspace_client/client_enum_source.rb +30 -0
  6. data/lib/aspace_client/exceptions.rb +15 -0
  7. data/lib/aspace_client/helpers.rb +0 -0
  8. data/lib/aspace_client/json_schema_concurrency_fix.rb +52 -0
  9. data/lib/aspace_client/json_schema_utils.rb +414 -0
  10. data/lib/aspace_client/jsonmodel.rb +342 -0
  11. data/lib/aspace_client/jsonmodel_client.rb +528 -0
  12. data/lib/aspace_client/jsonmodel_i18n_mixin.rb +77 -0
  13. data/lib/aspace_client/jsonmodel_type.rb +478 -0
  14. data/lib/aspace_client/memoryleak.rb +59 -0
  15. data/lib/aspace_client/schemas/abstract_agent.rb +51 -0
  16. data/lib/aspace_client/schemas/abstract_agent_relationship.rb +12 -0
  17. data/lib/aspace_client/schemas/abstract_archival_object.rb +96 -0
  18. data/lib/aspace_client/schemas/abstract_classification.rb +44 -0
  19. data/lib/aspace_client/schemas/abstract_name.rb +23 -0
  20. data/lib/aspace_client/schemas/abstract_note.rb +13 -0
  21. data/lib/aspace_client/schemas/accession.rb +174 -0
  22. data/lib/aspace_client/schemas/accession_parts_relationship.rb +31 -0
  23. data/lib/aspace_client/schemas/accession_sibling_relationship.rb +31 -0
  24. data/lib/aspace_client/schemas/active_edits.rb +23 -0
  25. data/lib/aspace_client/schemas/advanced_query.rb +12 -0
  26. data/lib/aspace_client/schemas/agent_contact.rb +25 -0
  27. data/lib/aspace_client/schemas/agent_corporate_entity.rb +32 -0
  28. data/lib/aspace_client/schemas/agent_family.rb +29 -0
  29. data/lib/aspace_client/schemas/agent_person.rb +31 -0
  30. data/lib/aspace_client/schemas/agent_relationship_associative.rb +28 -0
  31. data/lib/aspace_client/schemas/agent_relationship_earlierlater.rb +28 -0
  32. data/lib/aspace_client/schemas/agent_relationship_parentchild.rb +26 -0
  33. data/lib/aspace_client/schemas/agent_relationship_subordinatesuperior.rb +26 -0
  34. data/lib/aspace_client/schemas/agent_software.rb +22 -0
  35. data/lib/aspace_client/schemas/archival_object.rb +60 -0
  36. data/lib/aspace_client/schemas/archival_record_children.rb +15 -0
  37. data/lib/aspace_client/schemas/boolean_field_query.rb +13 -0
  38. data/lib/aspace_client/schemas/boolean_query.rb +13 -0
  39. data/lib/aspace_client/schemas/classification.rb +10 -0
  40. data/lib/aspace_client/schemas/classification_term.rb +38 -0
  41. data/lib/aspace_client/schemas/classification_tree.rb +17 -0
  42. data/lib/aspace_client/schemas/collection_management.rb +27 -0
  43. data/lib/aspace_client/schemas/container.rb +29 -0
  44. data/lib/aspace_client/schemas/container_location.rb +19 -0
  45. data/lib/aspace_client/schemas/date.rb +19 -0
  46. data/lib/aspace_client/schemas/date_field_query.rb +14 -0
  47. data/lib/aspace_client/schemas/deaccession.rb +20 -0
  48. data/lib/aspace_client/schemas/defaults.rb +104 -0
  49. data/lib/aspace_client/schemas/digital_object.rb +64 -0
  50. data/lib/aspace_client/schemas/digital_object_component.rb +53 -0
  51. data/lib/aspace_client/schemas/digital_object_tree.rb +19 -0
  52. data/lib/aspace_client/schemas/digital_record_children.rb +15 -0
  53. data/lib/aspace_client/schemas/enumeration.rb +29 -0
  54. data/lib/aspace_client/schemas/enumeration_migration.rb +14 -0
  55. data/lib/aspace_client/schemas/event.rb +88 -0
  56. data/lib/aspace_client/schemas/extent.rb +17 -0
  57. data/lib/aspace_client/schemas/external_document.rb +12 -0
  58. data/lib/aspace_client/schemas/external_id.rb +11 -0
  59. data/lib/aspace_client/schemas/field_query.rb +15 -0
  60. data/lib/aspace_client/schemas/file_version.rb +26 -0
  61. data/lib/aspace_client/schemas/group.rb +17 -0
  62. data/lib/aspace_client/schemas/instance.rb +27 -0
  63. data/lib/aspace_client/schemas/job.rb +57 -0
  64. data/lib/aspace_client/schemas/location.rb +36 -0
  65. data/lib/aspace_client/schemas/location_batch.rb +45 -0
  66. data/lib/aspace_client/schemas/merge_request.rb +48 -0
  67. data/lib/aspace_client/schemas/name_corporate_entity.rb +15 -0
  68. data/lib/aspace_client/schemas/name_family.rb +13 -0
  69. data/lib/aspace_client/schemas/name_form.rb +15 -0
  70. data/lib/aspace_client/schemas/name_person.rb +19 -0
  71. data/lib/aspace_client/schemas/name_software.rb +14 -0
  72. data/lib/aspace_client/schemas/note_abstract.rb +17 -0
  73. data/lib/aspace_client/schemas/note_bibliography.rb +29 -0
  74. data/lib/aspace_client/schemas/note_bioghist.rb +22 -0
  75. data/lib/aspace_client/schemas/note_chronology.rb +28 -0
  76. data/lib/aspace_client/schemas/note_citation.rb +32 -0
  77. data/lib/aspace_client/schemas/note_definedlist.rb +25 -0
  78. data/lib/aspace_client/schemas/note_digital_object.rb +23 -0
  79. data/lib/aspace_client/schemas/note_index.rb +29 -0
  80. data/lib/aspace_client/schemas/note_index_item.rb +25 -0
  81. data/lib/aspace_client/schemas/note_multipart.rb +25 -0
  82. data/lib/aspace_client/schemas/note_orderedlist.rb +27 -0
  83. data/lib/aspace_client/schemas/note_outline.rb +20 -0
  84. data/lib/aspace_client/schemas/note_outline_level.rb +21 -0
  85. data/lib/aspace_client/schemas/note_singlepart.rb +24 -0
  86. data/lib/aspace_client/schemas/note_text.rb +17 -0
  87. data/lib/aspace_client/schemas/permission.rb +15 -0
  88. data/lib/aspace_client/schemas/preference.rb +16 -0
  89. data/lib/aspace_client/schemas/record_tree.rb +17 -0
  90. data/lib/aspace_client/schemas/repository.rb +32 -0
  91. data/lib/aspace_client/schemas/repository_with_agent.rb +14 -0
  92. data/lib/aspace_client/schemas/resource.rb +112 -0
  93. data/lib/aspace_client/schemas/resource_tree.rb +20 -0
  94. data/lib/aspace_client/schemas/rights_statement.rb +35 -0
  95. data/lib/aspace_client/schemas/subject.rb +30 -0
  96. data/lib/aspace_client/schemas/term.rb +16 -0
  97. data/lib/aspace_client/schemas/user.rb +56 -0
  98. data/lib/aspace_client/schemas/user_defined.rb +42 -0
  99. data/lib/aspace_client/schemas/vocabulary.rb +15 -0
  100. data/lib/aspace_client/validations.rb +434 -0
  101. data/lib/aspace_client/validator_cache.rb +47 -0
  102. data/lib/aspace_client/version.rb +3 -0
  103. metadata +244 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ac953db47d3758e451a44a90dbdf570bad1c6d48
4
+ data.tar.gz: ee196ef429407e4f59cea5190865fd08a70b9c44
5
+ SHA512:
6
+ metadata.gz: 191e45a120e291974d55e0000073acfd460e6162847d3c891c7b9422e98532b5ad8f8f7861410d4906191bb4d37fbbfe4833c05c5c45328f957152e8880cc1ec
7
+ data.tar.gz: 34076a7f7f5fb3d8c8d64ac578c66bde17f1c5887da65462af9b76855c94c5ed70bafcf145c4c7b58db9bd121d9fa6ed0015039cf8000705e00b7c5343a8426c
@@ -0,0 +1,15 @@
1
+ $: << "#{File.dirname(__FILE__)}" unless $:.include? File.dirname(__FILE__)
2
+
3
+ require "aspace_client/jsonmodel"
4
+ require "aspace_client/asutils"
5
+ require "aspace_client/memoryleak"
6
+ require "aspace_client/client_enum_source"
7
+ require "aspace_client/jsonmodel_i18n_mixin"
8
+ require 'aspace_client/jsonmodel_client'
9
+ require 'aspace_client/archivesspace_json_schema.rb'
10
+
11
+ include JSONModel
12
+
13
+ module AspaceClient
14
+
15
+ end
@@ -0,0 +1,210 @@
1
+ require 'date'
2
+
3
+ # Add a new 'ifmissing' attribute which emits either an error or warning
4
+ # depending on its value.
5
+ class IfMissingAttribute < JSON::Schema::PropertiesAttribute
6
+
7
+ def self.validate(current_schema, data, fragments, validator, options = {})
8
+ super
9
+
10
+ if data.is_a?(Hash)
11
+ current_schema.schema['properties'].each do |property, property_schema|
12
+ if (property_schema['ifmissing'] && !data.has_key?(property))
13
+ message = nil
14
+
15
+ if property_schema['ifmissing'] == 'error'
16
+ message = "ERROR: The property '#{build_fragment(fragments)}' did not contain a required property of '#{property}'"
17
+ elsif property_schema['ifmissing'] == 'warn'
18
+ message = "WARNING: The property '#{build_fragment(fragments)}' did not contain a required property of '#{property}'"
19
+ end
20
+
21
+ if message
22
+ validation_error(message, fragments, current_schema, self, options[:record_errors])
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+
32
+ class ArchivesSpaceTypeAttribute < JSON::Schema::TypeAttribute
33
+ extend JSONModel
34
+
35
+
36
+ # This reuse business is a bit of a pain. The story here: JRuby backtraces
37
+ # are relatively expensive to create (relative to MRI Ruby), and JSON Schema
38
+ # validation is using exceptions as control flow here (sigh). During imports,
39
+ # these validation error are hit a *lot*, and calculating a backtrace every
40
+ # time is expensive.
41
+ #
42
+ # So, we recycle.
43
+ def self.validation_error_for(expected_type, fragments, current_schema)
44
+ Thread.current[:json_validation_cached_errors] ||= {}
45
+ if !Thread.current[:json_validation_cached_errors][expected_type]
46
+ msg = "ERROR: Schema type mismatch. Expected type: #{expected_type}"
47
+ Thread.current[:json_validation_cached_errors][expected_type] = JSON::Schema::ValidationError.new(msg, fragments, self, current_schema)
48
+ end
49
+
50
+ Thread.current[:json_validation_cached_errors][expected_type].fragments = fragments
51
+ Thread.current[:json_validation_cached_errors][expected_type]
52
+ end
53
+
54
+
55
+ def self.validate(current_schema, data, fragments, validator, options = {})
56
+ types = current_schema.schema['type']
57
+
58
+ if types == 'date'
59
+ begin
60
+ Date.parse(data)
61
+ return
62
+ rescue
63
+ validation_error("The property '#{build_fragment(fragments)}' was not " +
64
+ "a well-formed date (value: #{data})",
65
+ fragments, current_schema, self, options[:record_errors])
66
+ end
67
+ end
68
+
69
+
70
+ if types == 'object' && data.is_a?(Hash) && data.has_key?('ref') && current_schema.schema['subtype'] != 'ref'
71
+ # Provide a helpful warning about potentially missing subtype definitions
72
+ $stderr.puts("WARNING: Schema #{current_schema.inspect} appears to be missing a subtype definition of 'ref'")
73
+ end
74
+
75
+ # A bit crazy, sorry. If we're being asked to validate a hash whose
76
+ # jsonmodel_type is marked against a different JSONModel schema, we're
77
+ # wasting our time. Just stop straight away.
78
+ if (data.is_a?(Hash) && data["jsonmodel_type"]) &&
79
+ (current_schema.schema.is_a?(Hash) &&
80
+ "#{current_schema.schema["type"]}".include?("JSONModel") &&
81
+ !"#{current_schema.schema["type"]}".include?("JSONModel(:#{data['jsonmodel_type']})"))
82
+
83
+ raise validation_error_for(data['jsonmodel_type'], fragments, current_schema)
84
+ end
85
+
86
+ if JSONModel.parse_jsonmodel_ref(types)
87
+ (model, qualifier) = JSONModel.parse_jsonmodel_ref(types)
88
+
89
+ if qualifier == 'uri' || (qualifier == 'uri_or_object' && data.is_a?(String))
90
+ if JSONModel(model).id_for(data, {}, true).nil?
91
+ validation_error("The property '#{build_fragment(fragments)}' of type " +
92
+ "#{data.class} did not match the following type: #{types} in schema",
93
+ fragments, current_schema, self, options[:record_errors])
94
+ end
95
+
96
+ elsif qualifier == 'uri_or_object' || qualifier == 'object'
97
+ if data.is_a?(Hash)
98
+ data["jsonmodel_type"] ||= model.to_s
99
+
100
+ ValidatorCache.with_validator_for(JSONModel(model), data) do |subvalidator|
101
+ # Urk. Validate the subrecord but pass in the fragments of the point
102
+ # we're at in the parent record.
103
+ subvalidator.instance_eval do
104
+ @base_schema.validate(@data, fragments, @validation_options)
105
+ end
106
+ end
107
+
108
+ else
109
+ validation_error("The property '#{build_fragment(fragments)}' of type " +
110
+ "#{data.class} did not match the following type: #{types} in schema",
111
+ fragments, current_schema, self, options[:record_errors])
112
+ end
113
+ end
114
+ else
115
+ super
116
+ end
117
+ end
118
+ end
119
+
120
+
121
+ class ArchivesSpaceSubTypeAttribute < JSON::Schema::TypeAttribute
122
+
123
+ def self.validate(current_schema, data, fragments, validator, options = {})
124
+ if data.is_a?(Hash) && !data.has_key?('ref')
125
+ message = "ERROR: The property '#{build_fragment(fragments)}' did not contain a required property of 'ref'"
126
+ validation_error(message, fragments, current_schema, self, options[:record_errors])
127
+ end
128
+ end
129
+
130
+ end
131
+
132
+ class ArchivesSpaceReadOnlyDynamicEnumAttribute < JSON::Schema::TypeAttribute; end
133
+
134
+ class ArchivesSpaceDynamicEnumAttribute < JSON::Schema::TypeAttribute
135
+
136
+ def self.validate(current_schema, data, fragments, validator, options = {})
137
+ enum_name = current_schema.schema['dynamic_enum']
138
+
139
+ if !JSONModel.init_args[:enum_source].valid?(enum_name, data)
140
+ possible_values = JSONModel.init_args[:enum_source].values_for(enum_name)
141
+ message = ("The property '#{build_fragment(fragments)}' value #{data.inspect} " +
142
+ "did not match one of the following configurable values: #{possible_values.join(', ')}")
143
+
144
+ if JSONModel.init_args[:enum_source].editable?(enum_name)
145
+ klass = self
146
+ else
147
+ klass = ArchivesSpaceReadOnlyDynamicEnumAttribute
148
+ end
149
+
150
+ validation_error(message, fragments, current_schema, klass, options[:record_errors])
151
+ end
152
+ end
153
+
154
+ end
155
+
156
+
157
+ class ArchivesSpaceSchema < JSON::Schema::Validator
158
+ def initialize
159
+ super
160
+ extend_schema_definition("http://json-schema.org/draft-03/schema#")
161
+ @attributes["type"] = ArchivesSpaceTypeAttribute
162
+ @attributes["subtype"] = ArchivesSpaceSubTypeAttribute
163
+ @attributes["dynamic_enum"] = ArchivesSpaceDynamicEnumAttribute
164
+ @attributes["properties"] = IfMissingAttribute
165
+ @uri = URI.parse("http://www.archivesspace.org/archivesspace.json")
166
+ end
167
+
168
+
169
+ def already_failed?(fragments)
170
+ JSON::Validator.validation_errors.any? {|error|
171
+ error.fragments == fragments
172
+ }
173
+ end
174
+
175
+
176
+ def validate(current_schema, data, fragments, options = {})
177
+ super
178
+
179
+ # Run any custom validations if we've made it this far with no errors
180
+ if !already_failed?(fragments) && current_schema.schema.has_key?("validations")
181
+ current_schema.schema["validations"].each do |level_and_name|
182
+ level, name = level_and_name
183
+
184
+ errors = JSONModel::custom_validations[name].call(data)
185
+
186
+ errors.each do |error|
187
+ error_string = nil
188
+
189
+ if error.is_a? Symbol
190
+ error_string = "Validation error code: #{error}"
191
+ else
192
+ field, msg = error
193
+ prefix = level == :warning ? "Warning generated for" : "Validation failed for"
194
+ error_string = "#{prefix} '#{field}': #{msg}"
195
+
196
+ end
197
+
198
+ err = JSON::Schema::ValidationError.new(error_string,
199
+ fragments,
200
+ "custom_validation",
201
+ current_schema)
202
+
203
+ JSON::Validator.validation_error(err)
204
+ end
205
+ end
206
+ end
207
+ end
208
+
209
+ JSON::Validator.register_validator(self.new)
210
+ end
@@ -0,0 +1,142 @@
1
+ require 'json'
2
+ require 'tmpdir'
3
+ require 'tempfile'
4
+
5
+ module ASUtils
6
+
7
+ def self.keys_as_strings(hash)
8
+ result = {}
9
+
10
+ hash.each do |key, value|
11
+ result[key.to_s] = value.is_a?(Date) ? value.to_s : value
12
+ end
13
+
14
+ result
15
+ end
16
+
17
+
18
+ def self.as_array(thing)
19
+ return [] if thing.nil?
20
+ thing.kind_of?(Array) ? thing : [thing]
21
+ end
22
+
23
+
24
+ def self.jsonmodels_to_hashes(elt)
25
+
26
+ if elt.is_a?(JSONModelType)
27
+ elt = elt.to_hash(:raw)
28
+ end
29
+
30
+ if elt.is_a?(Hash)
31
+ Hash[elt.map {|k, v| [k, self.jsonmodels_to_hashes(v)]}]
32
+ elsif elt.is_a?(Array)
33
+ elt.map {|v| self.jsonmodels_to_hashes(v)}
34
+ else
35
+ elt
36
+ end
37
+ end
38
+
39
+
40
+ def self.json_parse(s)
41
+ JSON.parse(s, :max_nesting => false, :create_additions => false)
42
+ end
43
+
44
+
45
+
46
+ def self.to_json(obj, opts = {})
47
+ if obj.respond_to?(:jsonize)
48
+ obj.jsonize(opts.merge(:max_nesting => false))
49
+ else
50
+ obj.to_json(opts.merge(:max_nesting => false))
51
+ end
52
+ end
53
+
54
+
55
+ def self.find_base_directory(root = nil)
56
+ [ File.join(*[File.dirname(__FILE__), "..", root].compact)].find {|dir|
57
+ Dir.exists?(dir)
58
+ }
59
+ end
60
+
61
+
62
+ def self.find_local_directories(base = nil, *plugins)
63
+ base_directory = self.find_base_directory
64
+ Array(plugins).map { |plugin| File.join(*[base_directory, "plugins", plugin, base].compact) }
65
+ end
66
+
67
+
68
+ def self.find_locales_directories(base = nil)
69
+ [File.join(*[self.find_base_directory("common"), "locales", base].compact)]
70
+ end
71
+
72
+
73
+ def self.extract_nested_strings(coll)
74
+ if coll.is_a?(Hash)
75
+ coll.values.map {|v| self.extract_nested_strings(v)}.flatten.compact
76
+ elsif coll.is_a?(Array)
77
+ coll.map {|v| self.extract_nested_strings(v)}.flatten.compact
78
+ else
79
+ coll
80
+ end
81
+ end
82
+
83
+ def self.dump_diagnostics(exception = nil)
84
+ diagnostics = self.get_diagnostics( exception )
85
+ tmp = File.join(Dir.tmpdir, "aspaue_diagnostic_#{Time.now.to_i}.txt")
86
+ File.open(tmp, "w") do |fh|
87
+ fh.write(JSON.pretty_generate(diagnostics))
88
+ end
89
+
90
+ msg = <<EOF
91
+ A trace file has been written to the following location: #{tmp}
92
+
93
+ This file contains information that will assist developers in diagnosing
94
+ problems with your ArchivesSpace installation. Please review the file's
95
+ contents for sensitive information (such as passwords) that you might not
96
+ want to share.
97
+ EOF
98
+
99
+ $stderr.puts("=" * 72)
100
+ $stderr.puts(msg)
101
+ $stderr.puts("=" * 72)
102
+
103
+ raise exception if exception
104
+ end
105
+
106
+
107
+ # Recursively overlays hash2 onto hash 1
108
+ def self.deep_merge(hash1, hash2)
109
+ target = hash1.dup
110
+ hash2.keys.each do |key|
111
+ if hash2[key].is_a? Hash and hash1[key].is_a? Hash
112
+ target[key] = self.deep_merge(target[key], hash2[key])
113
+ next
114
+ end
115
+ target[key] = hash2[key]
116
+ end
117
+ target
118
+ end
119
+
120
+
121
+ def self.load_plugin_gems(context)
122
+ ASUtils.find_local_directories.each do |plugin|
123
+ gemfile = File.join(plugin, 'Gemfile')
124
+ if File.exists?(gemfile)
125
+ context.instance_eval(File.read(gemfile))
126
+ end
127
+ end
128
+ end
129
+
130
+
131
+ # Borrowed from: file activesupport/lib/active_support/core_ext/array/wrap.rb, line 36
132
+ def self.wrap(object)
133
+ if object.nil?
134
+ []
135
+ elsif object.respond_to?(:to_ary)
136
+ object.to_ary || [object]
137
+ else
138
+ [object]
139
+ end
140
+ end
141
+
142
+ end
@@ -0,0 +1,30 @@
1
+ require "aspace_client/jsonmodel"
2
+ require "aspace_client/memoryleak"
3
+
4
+ class ClientEnumSource
5
+
6
+ def initialize
7
+ MemoryLeak::Resources.define(:enumerations, proc {
8
+ JSONModel::Client::EnumSource.fetch_enumerations
9
+ }, 300)
10
+ end
11
+
12
+
13
+ def valid?(name, value)
14
+ values_for(name).include?(value)
15
+ end
16
+
17
+ def editable?(name)
18
+ MemoryLeak::Resources.get(:enumerations).fetch(name).editable?
19
+ end
20
+
21
+
22
+ def values_for(name)
23
+ MemoryLeak::Resources.get(:enumerations).fetch(name)
24
+ end
25
+
26
+ def default_value_for(name)
27
+ MemoryLeak::Resources.get(:enumerations)[:defaults].fetch(name)
28
+ end
29
+
30
+ end
@@ -0,0 +1,15 @@
1
+ class AccessDeniedException < StandardError
2
+ end
3
+
4
+
5
+ class ConflictException < StandardError
6
+ attr_reader :conflicts
7
+
8
+ def initialize(conflicts)
9
+ @conflicts = conflicts
10
+ super
11
+ end
12
+ end
13
+
14
+ class RecordNotFound < StandardError
15
+ end
File without changes
@@ -0,0 +1,52 @@
1
+ # Monkey patch against json-schema 1.0.12 to work around
2
+ # https://github.com/hoxworth/json-schema/issues/24
3
+
4
+
5
+ module JSON
6
+ class Validator
7
+
8
+ # Run a simple true/false validation of data against a schema
9
+ def validate()
10
+ begin
11
+ Validator.clear_errors
12
+ @base_schema.validate(@data,[],@validation_options)
13
+ Validator.clear_cache
14
+ if @options[:errors_as_objects]
15
+ self.class.validation_errors.map{|e| e.to_hash}
16
+ else
17
+ self.class.validation_errors.map{|e| e.to_string}
18
+ end
19
+ rescue JSON::Schema::ValidationError
20
+ Validator.clear_cache
21
+ raise $!
22
+ end
23
+ end
24
+
25
+ class << self
26
+ def clear_errors
27
+ Thread.current[:jsonschema_errors] = []
28
+ end
29
+
30
+ def validation_error(error)
31
+ Thread.current[:jsonschema_errors] << error
32
+ end
33
+
34
+ def validation_errors
35
+ Thread.current[:jsonschema_errors] or []
36
+ end
37
+ end
38
+
39
+
40
+ # Plus one bonus: don't use MultiJson here.
41
+ def serialize schema
42
+ # if defined?(MultiJson)
43
+ # MultiJson.respond_to?(:dump) ? MultiJson.dump(schema) : MultiJson.encode(schema)
44
+ # else
45
+ # @@serializer.call(schema)
46
+ # end
47
+
48
+ ASUtils.to_json(schema)
49
+ end
50
+
51
+ end
52
+ end