media_types-serialization 0.8.0 → 1.1.0

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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +16 -3
  3. data/.prettierrc +1 -0
  4. data/CHANGELOG.md +42 -0
  5. data/CODE_OF_CONDUCT.md +74 -74
  6. data/Gemfile.lock +74 -83
  7. data/README.md +691 -179
  8. data/lib/media_types/problem.rb +64 -0
  9. data/lib/media_types/serialization.rb +497 -173
  10. data/lib/media_types/serialization/base.rb +115 -91
  11. data/lib/media_types/serialization/error.rb +186 -0
  12. data/lib/media_types/serialization/fake_validator.rb +52 -0
  13. data/lib/media_types/serialization/serialization_dsl.rb +117 -0
  14. data/lib/media_types/serialization/serialization_registration.rb +245 -0
  15. data/lib/media_types/serialization/serializers/api_viewer.rb +133 -0
  16. data/lib/media_types/serialization/serializers/common_css.rb +168 -0
  17. data/lib/media_types/serialization/serializers/endpoint_description_serializer.rb +80 -0
  18. data/lib/media_types/serialization/serializers/fallback_not_acceptable_serializer.rb +85 -0
  19. data/lib/media_types/serialization/serializers/fallback_unsupported_media_type_serializer.rb +58 -0
  20. data/lib/media_types/serialization/serializers/input_validation_error_serializer.rb +89 -0
  21. data/lib/media_types/serialization/serializers/problem_serializer.rb +100 -0
  22. data/lib/media_types/serialization/utils/accept_header.rb +77 -0
  23. data/lib/media_types/serialization/utils/accept_language_header.rb +82 -0
  24. data/lib/media_types/serialization/utils/header_list.rb +89 -0
  25. data/lib/media_types/serialization/version.rb +1 -1
  26. data/media_types-serialization.gemspec +48 -50
  27. metadata +48 -79
  28. data/.travis.yml +0 -17
  29. data/lib/generators/media_types/serialization/api_viewer/api_viewer_generator.rb +0 -25
  30. data/lib/generators/media_types/serialization/api_viewer/templates/api_viewer.html.erb +0 -98
  31. data/lib/generators/media_types/serialization/api_viewer/templates/initializer.rb +0 -33
  32. data/lib/generators/media_types/serialization/api_viewer/templates/template_controller.rb +0 -23
  33. data/lib/media_types/serialization/media_type/register.rb +0 -4
  34. data/lib/media_types/serialization/migrations_command.rb +0 -38
  35. data/lib/media_types/serialization/migrations_support.rb +0 -50
  36. data/lib/media_types/serialization/mime_type_support.rb +0 -64
  37. data/lib/media_types/serialization/no_content_type_given.rb +0 -11
  38. data/lib/media_types/serialization/no_media_type_serializers.rb +0 -11
  39. data/lib/media_types/serialization/no_serializer_for_content_type.rb +0 -15
  40. data/lib/media_types/serialization/renderer.rb +0 -41
  41. data/lib/media_types/serialization/renderer/register.rb +0 -4
  42. data/lib/media_types/serialization/wrapper.rb +0 -13
  43. data/lib/media_types/serialization/wrapper/html_wrapper.rb +0 -45
  44. data/lib/media_types/serialization/wrapper/media_collection_wrapper.rb +0 -59
  45. data/lib/media_types/serialization/wrapper/media_index_wrapper.rb +0 -59
  46. data/lib/media_types/serialization/wrapper/media_object_wrapper.rb +0 -55
  47. data/lib/media_types/serialization/wrapper_support.rb +0 -38
@@ -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,4 +0,0 @@
1
- require 'action_controller/metal/renderers'
2
- require 'media_types/serialization/renderer'
3
-
4
- ::MediaTypes::Serialization.register_renderer
@@ -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,59 +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
-
15
- def initialize(serializer)
16
- __setobj__ serializer
17
- end
18
-
19
- def to_hash
20
- {
21
- root_key => {
22
- '_embedded': wrapped_serializable.map(&method(:item_hash)),
23
- '_links': extract_links
24
- }
25
- }
26
- end
27
- alias to_h to_hash
28
-
29
- def header_links(view: current_view)
30
- return __getobj__.send(:header_links, view: view) if ::MediaTypes::Serialization.collect_links_for_collection
31
- {}
32
- end
33
-
34
- protected
35
-
36
- def extract_links(view: current_view)
37
- return __getobj__.send(:extract_set_links, view: view) if ::MediaTypes::Serialization.collect_links_for_collection
38
- {}
39
- end
40
-
41
- def wrapped_serializable
42
- return __getobj__.wrapped_serializable if __getobj__.respond_to?(:wrapped_serializable)
43
- return [serializable] if serializable.is_a?(::Hash)
44
- Array(serializable)
45
- end
46
-
47
- def item_hash(item)
48
- __getobj__.instance_exec do
49
- set(item).to_hash
50
- end
51
- end
52
-
53
- def root_key(view: current_view)
54
- __getobj__.class.root_key(view: view)
55
- end
56
- end
57
- end
58
- end
59
- end
@@ -1,59 +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
-
15
- def initialize(serializer)
16
- __setobj__ serializer
17
- end
18
-
19
- def to_hash
20
- {
21
- root_key => {
22
- '_index': wrapped_serializable.map(&method(:item_hash)),
23
- '_links': extract_links
24
- }
25
- }
26
- end
27
- alias to_h to_hash
28
-
29
- def header_links(view: current_view)
30
- return __getobj__.send(:header_links, view: view) if ::MediaTypes::Serialization.collect_links_for_index
31
- {}
32
- end
33
-
34
- protected
35
-
36
- def wrapped_serializable
37
- return __getobj__.wrapped_serializable if __getobj__.respond_to?(:wrapped_serializable)
38
- return [serializable] if serializable.is_a?(::Hash)
39
- Array(serializable)
40
- end
41
-
42
- def item_hash(item)
43
- __getobj__.instance_exec do
44
- set(item).send(:extract_self)
45
- end
46
- end
47
-
48
- def extract_links(view: current_view)
49
- return __getobj__.send(:extract_set_links, view: view) if ::MediaTypes::Serialization.collect_links_for_index
50
- {}
51
- end
52
-
53
- def root_key(view: current_view)
54
- __getobj__.class.root_key(view: view)
55
- end
56
- end
57
- end
58
- end
59
- end
@@ -1,55 +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 MediaObjectWrapper < SimpleDelegator
11
-
12
- delegate :to_json, to: :to_hash
13
- delegate :class, :set, :current_view, :current_media_type, to: :__getobj__
14
-
15
- mattr_accessor :auto_unwrap_klazzes
16
-
17
- self.auto_unwrap_klazzes = [Array, defined?(ActiveRecord) ? ActiveRecord::Relation : nil].compact
18
-
19
- def initialize(serializer)
20
- __setobj__ serializer
21
- end
22
-
23
- def to_hash
24
- set unwrapped_serializable
25
- { root_key => serializable && super || nil }
26
- end
27
-
28
- alias to_h to_hash
29
-
30
- def header_links(view: current_view)
31
- __getobj__.send(:header_links, view: view)
32
- end
33
-
34
- def inspect
35
- "#{__getobj__.inspect} (wrapped by MediaObjectWrapper #{self.object_id})"
36
- end
37
-
38
- protected
39
-
40
- def unwrapped_serializable
41
- return __getobj__.unwrapped_serializable if __getobj__.respond_to?(:unwrapped_serializable)
42
- auto_unwrap_klazzes.any? { |klazz| serializable.is_a?(klazz) } ? serializable.first : serializable
43
- end
44
-
45
- def extract_links(view: current_view)
46
- __getobj__.send(:extract_set_links, view: view)
47
- end
48
-
49
- def root_key(view: current_view)
50
- __getobj__.class.root_key(view: view)
51
- end
52
- end
53
- end
54
- end
55
- end