media_types-serialization 0.8.1 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +10 -1
- data/.gitignore +12 -12
- data/.idea/.rakeTasks +5 -5
- data/.idea/inspectionProfiles/Project_Default.xml +5 -5
- data/.idea/runConfigurations/test.xml +19 -19
- data/CHANGELOG.md +18 -0
- data/CODE_OF_CONDUCT.md +74 -74
- data/Gemfile +4 -4
- data/Gemfile.lock +58 -61
- data/LICENSE.txt +21 -21
- data/README.md +640 -173
- data/Rakefile +10 -10
- data/bin/console +14 -14
- data/bin/setup +8 -8
- data/lib/media_types/problem.rb +64 -0
- data/lib/media_types/serialization.rb +431 -172
- data/lib/media_types/serialization/base.rb +111 -91
- data/lib/media_types/serialization/error.rb +178 -0
- data/lib/media_types/serialization/fake_validator.rb +52 -0
- data/lib/media_types/serialization/serialization_dsl.rb +117 -0
- data/lib/media_types/serialization/serialization_registration.rb +235 -0
- data/lib/media_types/serialization/serializers/api_viewer.rb +133 -0
- data/lib/media_types/serialization/serializers/common_css.rb +168 -0
- data/lib/media_types/serialization/serializers/endpoint_description_serializer.rb +80 -0
- data/lib/media_types/serialization/serializers/fallback_not_acceptable_serializer.rb +85 -0
- data/lib/media_types/serialization/serializers/fallback_unsupported_media_type_serializer.rb +58 -0
- data/lib/media_types/serialization/serializers/input_validation_error_serializer.rb +89 -0
- data/lib/media_types/serialization/serializers/problem_serializer.rb +87 -0
- data/lib/media_types/serialization/version.rb +1 -1
- data/media_types-serialization.gemspec +50 -50
- metadata +40 -43
- data/.travis.yml +0 -17
- data/lib/generators/media_types/serialization/api_viewer/api_viewer_generator.rb +0 -25
- data/lib/generators/media_types/serialization/api_viewer/templates/api_viewer.html.erb +0 -98
- data/lib/generators/media_types/serialization/api_viewer/templates/initializer.rb +0 -33
- data/lib/generators/media_types/serialization/api_viewer/templates/template_controller.rb +0 -23
- data/lib/media_types/serialization/media_type/register.rb +0 -4
- data/lib/media_types/serialization/migrations_command.rb +0 -38
- data/lib/media_types/serialization/migrations_support.rb +0 -50
- data/lib/media_types/serialization/mime_type_support.rb +0 -64
- data/lib/media_types/serialization/no_content_type_given.rb +0 -11
- data/lib/media_types/serialization/no_media_type_serializers.rb +0 -11
- data/lib/media_types/serialization/no_serializer_for_content_type.rb +0 -15
- data/lib/media_types/serialization/renderer.rb +0 -41
- data/lib/media_types/serialization/renderer/register.rb +0 -4
- data/lib/media_types/serialization/wrapper.rb +0 -13
- data/lib/media_types/serialization/wrapper/html_wrapper.rb +0 -45
- data/lib/media_types/serialization/wrapper/media_collection_wrapper.rb +0 -61
- data/lib/media_types/serialization/wrapper/media_index_wrapper.rb +0 -61
- data/lib/media_types/serialization/wrapper/media_object_wrapper.rb +0 -55
- data/lib/media_types/serialization/wrapper_support.rb +0 -38
@@ -1,33 +0,0 @@
|
|
1
|
-
require 'media_types/serialization'
|
2
|
-
|
3
|
-
# This registers the renderer as side-effect
|
4
|
-
require 'media_types/serialization/renderer/register'
|
5
|
-
|
6
|
-
# This registers the media type as side-effect
|
7
|
-
require 'media_types/serialization/media_type/register'
|
8
|
-
|
9
|
-
##
|
10
|
-
# The following options are breaking and therefore disabled by default.
|
11
|
-
#
|
12
|
-
# When these are true, the +header_links+ and +extract_links+ methods is called
|
13
|
-
# when dealing with a .collection or .index view, respectively. It allows you
|
14
|
-
# to define +_links+ for the root level from your serializer.
|
15
|
-
#
|
16
|
-
#
|
17
|
-
MediaTypes::Serialization.collect_links_for_collection = true
|
18
|
-
MediaTypes::Serialization.collect_links_for_index = true
|
19
|
-
|
20
|
-
##
|
21
|
-
# The API Viewer template is provided if you used the generator. You can change
|
22
|
-
# the view it renders by changing the path below.
|
23
|
-
#
|
24
|
-
#
|
25
|
-
# ::MediaTypes::Serialization.api_viewer_layout = '/path/to/wrapper/layout'
|
26
|
-
|
27
|
-
##
|
28
|
-
# When .to_html is not provided by a serializer, it will fall back to render
|
29
|
-
# the API Viewer, but this template can be changed by changing the path
|
30
|
-
# below.
|
31
|
-
#
|
32
|
-
#
|
33
|
-
# ::MediaTypes::Serialization.html_wrapper_layout = '/path/to/wrapper/layout'
|
@@ -1,23 +0,0 @@
|
|
1
|
-
module Api
|
2
|
-
class TemplateController < ApiController
|
3
|
-
def create
|
4
|
-
href = params[:template].delete(:href)
|
5
|
-
templated_values = params[:template].permit!.to_h
|
6
|
-
|
7
|
-
response["Location"] = templated_values.reduce(href) do |result, (key, value)|
|
8
|
-
result.sub!(%r{:#{key}|{#{key}}|%7B#{key}%7D}, value) || invalid_parameter(key, href)
|
9
|
-
end
|
10
|
-
head :temporary_redirect
|
11
|
-
end
|
12
|
-
|
13
|
-
private
|
14
|
-
|
15
|
-
def invalid_parameter(key, href)
|
16
|
-
raise ActionController::BadRequest, format(
|
17
|
-
'Received templated value for "%<key>s" which does not exist in templated link "%<href>s"',
|
18
|
-
key: key,
|
19
|
-
href: href.gsub('%7B', '{').gsub('%7D', '}')
|
20
|
-
)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
#
|
3
|
-
module MediaTypes
|
4
|
-
module Serialization
|
5
|
-
class MigrationsCommand
|
6
|
-
def initialize(serializer)
|
7
|
-
self.serializer = serializer
|
8
|
-
self.migrations = {}
|
9
|
-
end
|
10
|
-
|
11
|
-
def call(result, mime_type, view)
|
12
|
-
return result if mime_type.is_a?(String) || matches_current_mime_type?(view: view, mime_type: mime_type)
|
13
|
-
|
14
|
-
migrations.reduce(result) do |migrated, (version, migration)|
|
15
|
-
migrated = migration.call(migrated)
|
16
|
-
next migrated unless matches_mime_type?(mime_type.version(version), mime_type)
|
17
|
-
break migrated
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
attr_accessor :serializer, :migrations
|
24
|
-
|
25
|
-
def version(version, &block)
|
26
|
-
migrations[version] = ->(result) { serializer.instance_exec(result, &block) }
|
27
|
-
end
|
28
|
-
|
29
|
-
def matches_current_mime_type?(view:, mime_type:)
|
30
|
-
serializer.class.current_mime_type(view: view) == mime_type.to_s
|
31
|
-
end
|
32
|
-
|
33
|
-
def matches_mime_type?(left, right)
|
34
|
-
left.to_s == right.to_s
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'active_support/concern'
|
4
|
-
require 'media_types/serialization/migrations_command'
|
5
|
-
|
6
|
-
module MediaTypes
|
7
|
-
module Serialization
|
8
|
-
module MigrationsSupport
|
9
|
-
extend ActiveSupport::Concern
|
10
|
-
|
11
|
-
included do
|
12
|
-
# This is the same as doing matrr_accessor but have it isolated to the class. Subclass changes to change these
|
13
|
-
# values, but this allows for definition as a concern.
|
14
|
-
|
15
|
-
class << self
|
16
|
-
attr_accessor :migrations
|
17
|
-
end
|
18
|
-
|
19
|
-
delegate :migrations,
|
20
|
-
:migrations=,
|
21
|
-
to: :class
|
22
|
-
end
|
23
|
-
|
24
|
-
class_methods do
|
25
|
-
def migrator(serializer)
|
26
|
-
return nil unless migrations
|
27
|
-
migrations.call(serializer)
|
28
|
-
end
|
29
|
-
|
30
|
-
protected
|
31
|
-
|
32
|
-
def backward_migrations(&block)
|
33
|
-
self.migrations = lambda do |serializer|
|
34
|
-
MigrationsCommand.new(serializer).tap do |callable|
|
35
|
-
callable.instance_exec(&block)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def migrate(result = nil, media_type = current_media_type, view = current_view)
|
42
|
-
result ||= yield
|
43
|
-
|
44
|
-
migrator = self.class.migrator(self)
|
45
|
-
return result unless migrator
|
46
|
-
migrator.call(result, media_type, view)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
@@ -1,64 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'active_support/concern'
|
4
|
-
|
5
|
-
module MediaTypes
|
6
|
-
module Serialization
|
7
|
-
module MimeTypeSupport
|
8
|
-
extend ActiveSupport::Concern
|
9
|
-
|
10
|
-
included do
|
11
|
-
# This is the same as doing matrr_accessor but have it isolated to the class. Subclass changes to change these
|
12
|
-
# values, but this allows for definition as a concern.
|
13
|
-
|
14
|
-
class << self
|
15
|
-
attr_accessor :media_type_constructable, :serializes_html_flag, :media_type_versions
|
16
|
-
end
|
17
|
-
|
18
|
-
delegate :media_type_constructable, :serializes_html_flag, :media_type_versions,
|
19
|
-
:media_type_constructable=, :serializes_html_flag=, :media_type_versions=,
|
20
|
-
to: :class
|
21
|
-
end
|
22
|
-
|
23
|
-
class_methods do
|
24
|
-
def current_mime_type(view: nil)
|
25
|
-
media_type_constructable&.view(view)
|
26
|
-
end
|
27
|
-
|
28
|
-
def media_types(view: nil)
|
29
|
-
media_type_view = current_mime_type(view: view)
|
30
|
-
|
31
|
-
suffixes = [].tap do |result|
|
32
|
-
result << :json if instance_methods.include?(:to_json)
|
33
|
-
result << :xml if instance_methods.include?(:to_xml)
|
34
|
-
end
|
35
|
-
|
36
|
-
additionals = [].tap do |result|
|
37
|
-
result << 'text/html' if serializes_html_flag || instance_methods.include?(:to_html)
|
38
|
-
end
|
39
|
-
|
40
|
-
[media_type_view].concat(
|
41
|
-
media_type_versions.map { |version| media_type_view&.version(version) },
|
42
|
-
media_type_versions.flat_map do |version|
|
43
|
-
(suffixes).map { |suffix| media_type_view&.suffix(suffix)&.version(version) }
|
44
|
-
end,
|
45
|
-
additionals
|
46
|
-
).compact.uniq
|
47
|
-
end
|
48
|
-
|
49
|
-
alias_method :media_type, :media_types
|
50
|
-
|
51
|
-
protected
|
52
|
-
|
53
|
-
def serializes_media_type(media_type, additional_versions: [])
|
54
|
-
self.media_type_constructable = media_type&.to_constructable
|
55
|
-
self.media_type_versions = additional_versions
|
56
|
-
end
|
57
|
-
|
58
|
-
def serializes_html
|
59
|
-
self.serializes_html_flag = true
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
@@ -1,11 +0,0 @@
|
|
1
|
-
require 'media_types/serialization/error'
|
2
|
-
|
3
|
-
module MediaTypes
|
4
|
-
module Serialization
|
5
|
-
class NoContentTypeGiven < Error
|
6
|
-
def initialize
|
7
|
-
super 'Unable to render data because :content_type was not passed in to "render media: data, content_type: ..."'
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
@@ -1,11 +0,0 @@
|
|
1
|
-
require 'media_types/serialization/error'
|
2
|
-
|
3
|
-
module MediaTypes
|
4
|
-
module Serialization
|
5
|
-
class NoMediaTypeSerializers < Error
|
6
|
-
def initialize
|
7
|
-
super 'No serializer has been set up for this request. You can not fix this by changing the request headers.'
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
require 'media_types/serialization/error'
|
2
|
-
|
3
|
-
module MediaTypes
|
4
|
-
module Serialization
|
5
|
-
class NoSerializerForContentType < Error
|
6
|
-
def initialize(given, supported)
|
7
|
-
super format(
|
8
|
-
'Unable to serialize to requested Content-Type: %<given>s. I can give you: %<supported>s',
|
9
|
-
given: Array(given).map(&:to_s).inspect,
|
10
|
-
supported: supported.map(&:to_s)
|
11
|
-
)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
require 'media_types/serialization/no_content_type_given'
|
2
|
-
require 'active_support/core_ext/object/blank'
|
3
|
-
require 'active_support/core_ext/hash/conversions'
|
4
|
-
|
5
|
-
require 'media_types/serialization'
|
6
|
-
|
7
|
-
module MediaTypes
|
8
|
-
module Serialization
|
9
|
-
# noinspection RubyConstantNamingConvention
|
10
|
-
Renderer = lambda do |obj, options|
|
11
|
-
content_type = options[:content_type] ||
|
12
|
-
options[:mime_type]&.to_s ||
|
13
|
-
self.content_type&.to_s ||
|
14
|
-
obj.current_media_type.to_s
|
15
|
-
|
16
|
-
raise NoContentTypeGiven if content_type.blank?
|
17
|
-
|
18
|
-
self.content_type ||= content_type
|
19
|
-
|
20
|
-
if content_type.ends_with?('+json') || Mime::Type.lookup(content_type) == Mime[:json]
|
21
|
-
obj.respond_to?(:to_json) ? obj.to_json(options) : obj.to_hash.to_json(options)
|
22
|
-
elsif content_type.ends_with?('+xml') || Mime::Type.lookup(content_type) == Mime[:xml]
|
23
|
-
obj.respond_to?(:to_xml) ? obj.to_xml(options) : obj.to_hash.to_xml(options)
|
24
|
-
elsif Mime::Type.lookup(content_type) == Mime[:html] && obj.respond_to?(:to_html)
|
25
|
-
obj.to_html
|
26
|
-
elsif content_type === MEDIA_TYPE_API_VIEWER && obj.respond_to?(:to_api_viewer)
|
27
|
-
obj.to_api_viewer(content_type: options[:api_viewer_content_type]).tap do
|
28
|
-
self.content_type = 'text/html' # because the api viewer will not be seen as
|
29
|
-
end
|
30
|
-
else
|
31
|
-
obj.to_body(content_type: options.delete(:content_type) || content_type, **options)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
module_function
|
36
|
-
|
37
|
-
def register_renderer
|
38
|
-
::ActionController::Renderers.add :media, &Renderer
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,13 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'media_types/serialization/wrapper/html_wrapper'
|
4
|
-
require 'media_types/serialization/wrapper/media_object_wrapper'
|
5
|
-
require 'media_types/serialization/wrapper/media_index_wrapper'
|
6
|
-
require 'media_types/serialization/wrapper/media_collection_wrapper'
|
7
|
-
|
8
|
-
module MediaTypes
|
9
|
-
module Serialization
|
10
|
-
module Wrapper
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'delegate'
|
4
|
-
|
5
|
-
require 'action_controller'
|
6
|
-
|
7
|
-
module MediaTypes
|
8
|
-
module Serialization
|
9
|
-
module Wrapper
|
10
|
-
class HtmlWrapper < SimpleDelegator
|
11
|
-
|
12
|
-
delegate :to_s, to: :to_html
|
13
|
-
delegate :class, to: :__getobj__
|
14
|
-
|
15
|
-
def initialize(serializer, view: nil, **render_options)
|
16
|
-
__setobj__ serializer
|
17
|
-
|
18
|
-
self.view = view
|
19
|
-
self.render_options = render_options
|
20
|
-
end
|
21
|
-
|
22
|
-
def to_html
|
23
|
-
return super if __getobj__.respond_to?(:to_html)
|
24
|
-
to_api_viewer(layout: ::MediaTypes::Serialization.html_wrapper_layout)
|
25
|
-
end
|
26
|
-
|
27
|
-
def to_api_viewer(content_type: nil, layout: ::MediaTypes::Serialization.api_viewer_layout)
|
28
|
-
ActionController::Base.render(
|
29
|
-
layout || 'serializers/wrapper/html_wrapper',
|
30
|
-
assigns: {
|
31
|
-
serializer: self,
|
32
|
-
view: view,
|
33
|
-
content_type: content_type,
|
34
|
-
**render_options
|
35
|
-
}
|
36
|
-
)
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
attr_accessor :view, :render_options
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
@@ -1,61 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'delegate'
|
4
|
-
|
5
|
-
require 'active_support/core_ext/string/inflections'
|
6
|
-
|
7
|
-
module MediaTypes
|
8
|
-
module Serialization
|
9
|
-
module Wrapper
|
10
|
-
class MediaCollectionWrapper < SimpleDelegator
|
11
|
-
|
12
|
-
delegate :to_json, to: :to_hash
|
13
|
-
delegate :class, :set, :current_view, :current_media_type, to: :__getobj__
|
14
|
-
attr_accessor :inner_serializer
|
15
|
-
|
16
|
-
def initialize(serializer)
|
17
|
-
self.inner_serializer = serializer.dup
|
18
|
-
__setobj__ serializer
|
19
|
-
end
|
20
|
-
|
21
|
-
def to_hash
|
22
|
-
{
|
23
|
-
root_key => {
|
24
|
-
'_embedded': wrapped_serializable.map(&method(:item_hash)),
|
25
|
-
'_links': extract_links
|
26
|
-
}
|
27
|
-
}
|
28
|
-
end
|
29
|
-
alias to_h to_hash
|
30
|
-
|
31
|
-
def header_links(view: current_view)
|
32
|
-
return __getobj__.send(:header_links, view: view) if ::MediaTypes::Serialization.collect_links_for_collection
|
33
|
-
{}
|
34
|
-
end
|
35
|
-
|
36
|
-
protected
|
37
|
-
|
38
|
-
def extract_links(view: current_view)
|
39
|
-
return __getobj__.send(:extract_set_links, view: view) if ::MediaTypes::Serialization.collect_links_for_collection
|
40
|
-
{}
|
41
|
-
end
|
42
|
-
|
43
|
-
def wrapped_serializable
|
44
|
-
return __getobj__.wrapped_serializable if __getobj__.respond_to?(:wrapped_serializable)
|
45
|
-
return [serializable] if serializable.is_a?(::Hash)
|
46
|
-
Array(serializable)
|
47
|
-
end
|
48
|
-
|
49
|
-
def item_hash(item)
|
50
|
-
inner_serializer.instance_exec do
|
51
|
-
set(item).to_hash
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def root_key(view: current_view)
|
56
|
-
__getobj__.class.root_key(view: view)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
@@ -1,61 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'delegate'
|
4
|
-
|
5
|
-
require 'active_support/core_ext/string/inflections'
|
6
|
-
|
7
|
-
module MediaTypes
|
8
|
-
module Serialization
|
9
|
-
module Wrapper
|
10
|
-
class MediaIndexWrapper < SimpleDelegator
|
11
|
-
|
12
|
-
delegate :to_json, to: :to_hash
|
13
|
-
delegate :class, :set, :current_view, :current_media_type, to: :__getobj__
|
14
|
-
attr_accessor :inner_serializer
|
15
|
-
|
16
|
-
def initialize(serializer)
|
17
|
-
self.inner_serializer = serializer.dup
|
18
|
-
__setobj__ serializer
|
19
|
-
end
|
20
|
-
|
21
|
-
def to_hash
|
22
|
-
{
|
23
|
-
root_key => {
|
24
|
-
'_index': wrapped_serializable.map(&method(:item_hash)),
|
25
|
-
'_links': extract_links
|
26
|
-
}
|
27
|
-
}
|
28
|
-
end
|
29
|
-
alias to_h to_hash
|
30
|
-
|
31
|
-
def header_links(view: current_view)
|
32
|
-
return __getobj__.send(:header_links, view: view) if ::MediaTypes::Serialization.collect_links_for_index
|
33
|
-
{}
|
34
|
-
end
|
35
|
-
|
36
|
-
protected
|
37
|
-
|
38
|
-
def wrapped_serializable
|
39
|
-
return __getobj__.wrapped_serializable if __getobj__.respond_to?(:wrapped_serializable)
|
40
|
-
return [serializable] if serializable.is_a?(::Hash)
|
41
|
-
Array(serializable)
|
42
|
-
end
|
43
|
-
|
44
|
-
def item_hash(item)
|
45
|
-
inner_serializer.instance_exec do
|
46
|
-
set(item).send(:extract_self)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def extract_links(view: current_view)
|
51
|
-
return __getobj__.send(:extract_set_links, view: view) if ::MediaTypes::Serialization.collect_links_for_index
|
52
|
-
{}
|
53
|
-
end
|
54
|
-
|
55
|
-
def root_key(view: current_view)
|
56
|
-
__getobj__.class.root_key(view: view)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|