jsonapionify 0.0.1.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +29 -0
  3. data/.csslintrc +2 -0
  4. data/.gitignore +11 -0
  5. data/.rspec +3 -0
  6. data/.rubocop.yml +1171 -0
  7. data/.ruby-version +1 -0
  8. data/.travis.yml +10 -0
  9. data/CODE_OF_CONDUCT.md +13 -0
  10. data/Gemfile +4 -0
  11. data/Guardfile +14 -0
  12. data/LICENSE.txt +21 -0
  13. data/README.md +43 -0
  14. data/Rakefile +34 -0
  15. data/TODO +13 -0
  16. data/bin/console +14 -0
  17. data/bin/setup +7 -0
  18. data/config.ru +15 -0
  19. data/fixtures/documentation.json +364 -0
  20. data/jsonapionify.gemspec +50 -0
  21. data/lib/core_ext/boolean.rb +3 -0
  22. data/lib/jsonapionify/api/action.rb +211 -0
  23. data/lib/jsonapionify/api/attribute.rb +67 -0
  24. data/lib/jsonapionify/api/base/app_builder.rb +33 -0
  25. data/lib/jsonapionify/api/base/class_methods.rb +73 -0
  26. data/lib/jsonapionify/api/base/delegation.rb +15 -0
  27. data/lib/jsonapionify/api/base/doc_helper.rb +47 -0
  28. data/lib/jsonapionify/api/base/reloader.rb +10 -0
  29. data/lib/jsonapionify/api/base/resource_definitions.rb +39 -0
  30. data/lib/jsonapionify/api/base.rb +25 -0
  31. data/lib/jsonapionify/api/context.rb +14 -0
  32. data/lib/jsonapionify/api/context_delegate.rb +42 -0
  33. data/lib/jsonapionify/api/errors.rb +6 -0
  34. data/lib/jsonapionify/api/errors_object.rb +66 -0
  35. data/lib/jsonapionify/api/header_options.rb +13 -0
  36. data/lib/jsonapionify/api/param_options.rb +46 -0
  37. data/lib/jsonapionify/api/relationship/blocks.rb +41 -0
  38. data/lib/jsonapionify/api/relationship/many.rb +61 -0
  39. data/lib/jsonapionify/api/relationship/one.rb +36 -0
  40. data/lib/jsonapionify/api/relationship.rb +89 -0
  41. data/lib/jsonapionify/api/resource/builders.rb +81 -0
  42. data/lib/jsonapionify/api/resource/class_methods.rb +82 -0
  43. data/lib/jsonapionify/api/resource/defaults/actions.rb +11 -0
  44. data/lib/jsonapionify/api/resource/defaults/errors.rb +99 -0
  45. data/lib/jsonapionify/api/resource/defaults/request_contexts.rb +96 -0
  46. data/lib/jsonapionify/api/resource/defaults/response_contexts.rb +31 -0
  47. data/lib/jsonapionify/api/resource/defaults.rb +10 -0
  48. data/lib/jsonapionify/api/resource/definitions/actions.rb +196 -0
  49. data/lib/jsonapionify/api/resource/definitions/attributes.rb +51 -0
  50. data/lib/jsonapionify/api/resource/definitions/contexts.rb +16 -0
  51. data/lib/jsonapionify/api/resource/definitions/helpers.rb +9 -0
  52. data/lib/jsonapionify/api/resource/definitions/pagination.rb +79 -0
  53. data/lib/jsonapionify/api/resource/definitions/params.rb +49 -0
  54. data/lib/jsonapionify/api/resource/definitions/relationships.rb +42 -0
  55. data/lib/jsonapionify/api/resource/definitions/request_headers.rb +103 -0
  56. data/lib/jsonapionify/api/resource/definitions/response_headers.rb +22 -0
  57. data/lib/jsonapionify/api/resource/definitions/scopes.rb +50 -0
  58. data/lib/jsonapionify/api/resource/definitions/sorting.rb +85 -0
  59. data/lib/jsonapionify/api/resource/definitions.rb +14 -0
  60. data/lib/jsonapionify/api/resource/error_handling.rb +108 -0
  61. data/lib/jsonapionify/api/resource/http.rb +11 -0
  62. data/lib/jsonapionify/api/resource/includer.rb +4 -0
  63. data/lib/jsonapionify/api/resource.rb +35 -0
  64. data/lib/jsonapionify/api/response.rb +47 -0
  65. data/lib/jsonapionify/api/server/mock_response.rb +37 -0
  66. data/lib/jsonapionify/api/server/request.rb +78 -0
  67. data/lib/jsonapionify/api/server.rb +50 -0
  68. data/lib/jsonapionify/api/test_helper.rb +52 -0
  69. data/lib/jsonapionify/api.rb +9 -0
  70. data/lib/jsonapionify/autoload.rb +52 -0
  71. data/lib/jsonapionify/callbacks.rb +49 -0
  72. data/lib/jsonapionify/character_range.rb +41 -0
  73. data/lib/jsonapionify/continuation.rb +26 -0
  74. data/lib/jsonapionify/documentation/template.erb +487 -0
  75. data/lib/jsonapionify/documentation.rb +40 -0
  76. data/lib/jsonapionify/enumerable_observer.rb +91 -0
  77. data/lib/jsonapionify/indented_string.rb +27 -0
  78. data/lib/jsonapionify/inherited_attributes.rb +125 -0
  79. data/lib/jsonapionify/structure/collections/base.rb +104 -0
  80. data/lib/jsonapionify/structure/collections/errors.rb +7 -0
  81. data/lib/jsonapionify/structure/collections/included_resources.rb +39 -0
  82. data/lib/jsonapionify/structure/collections/resource_identifiers.rb +7 -0
  83. data/lib/jsonapionify/structure/collections/resources.rb +7 -0
  84. data/lib/jsonapionify/structure/helpers/errors.rb +71 -0
  85. data/lib/jsonapionify/structure/helpers/inherits_origin.rb +17 -0
  86. data/lib/jsonapionify/structure/helpers/member_names.rb +37 -0
  87. data/lib/jsonapionify/structure/helpers/meta_delegate.rb +16 -0
  88. data/lib/jsonapionify/structure/helpers/object_defaults.rb +123 -0
  89. data/lib/jsonapionify/structure/helpers/object_setters.rb +21 -0
  90. data/lib/jsonapionify/structure/helpers/pagination_links.rb +10 -0
  91. data/lib/jsonapionify/structure/helpers/validations.rb +296 -0
  92. data/lib/jsonapionify/structure/maps/base.rb +25 -0
  93. data/lib/jsonapionify/structure/maps/error_links.rb +7 -0
  94. data/lib/jsonapionify/structure/maps/links.rb +21 -0
  95. data/lib/jsonapionify/structure/maps/relationship_links.rb +11 -0
  96. data/lib/jsonapionify/structure/maps/relationships.rb +23 -0
  97. data/lib/jsonapionify/structure/maps/resource_links.rb +7 -0
  98. data/lib/jsonapionify/structure/maps/top_level_links.rb +10 -0
  99. data/lib/jsonapionify/structure/objects/attributes.rb +29 -0
  100. data/lib/jsonapionify/structure/objects/base.rb +166 -0
  101. data/lib/jsonapionify/structure/objects/error.rb +16 -0
  102. data/lib/jsonapionify/structure/objects/included_resource.rb +14 -0
  103. data/lib/jsonapionify/structure/objects/jsonapi.rb +7 -0
  104. data/lib/jsonapionify/structure/objects/link.rb +18 -0
  105. data/lib/jsonapionify/structure/objects/meta.rb +7 -0
  106. data/lib/jsonapionify/structure/objects/relationship.rb +20 -0
  107. data/lib/jsonapionify/structure/objects/resource.rb +45 -0
  108. data/lib/jsonapionify/structure/objects/resource_identifier.rb +40 -0
  109. data/lib/jsonapionify/structure/objects/source.rb +10 -0
  110. data/lib/jsonapionify/structure/objects/top_level.rb +105 -0
  111. data/lib/jsonapionify/structure.rb +27 -0
  112. data/lib/jsonapionify/types/array_type.rb +32 -0
  113. data/lib/jsonapionify/types/boolean_type.rb +22 -0
  114. data/lib/jsonapionify/types/date_string_type.rb +28 -0
  115. data/lib/jsonapionify/types/float_type.rb +8 -0
  116. data/lib/jsonapionify/types/integer_type.rb +9 -0
  117. data/lib/jsonapionify/types/object_type.rb +22 -0
  118. data/lib/jsonapionify/types/string_type.rb +66 -0
  119. data/lib/jsonapionify/types/time_string_type.rb +28 -0
  120. data/lib/jsonapionify/types.rb +49 -0
  121. data/lib/jsonapionify/unstrict_proc.rb +28 -0
  122. data/lib/jsonapionify/version.rb +3 -0
  123. data/lib/jsonapionify.rb +37 -0
  124. metadata +530 -0
@@ -0,0 +1,125 @@
1
+ module JSONAPIonify
2
+ module InheritedAttributes
3
+
4
+ def inherited_hash_attribute(*attrs, instance_reader: true, instance_writer: true, instance_accessor: true)
5
+ instance_reader, instance_writer = false, false unless instance_accessor
6
+ attrs.each do |attr|
7
+ ivar = :"@#{attr}"
8
+ setter = :"#{attr}="
9
+ getter = :"#{attr}"
10
+
11
+ # Define First Variable
12
+ instance_variable_set(ivar, Hash.new)
13
+
14
+ # Define Setter
15
+ define_singleton_method setter do |value|
16
+ instance_variable_get(ivar).tap(&:clear).merge! value
17
+ end
18
+
19
+ # Define Getter
20
+ define_singleton_method getter do
21
+ instance_variable_get(ivar)
22
+ end
23
+
24
+ # Define Instance Getter
25
+ define_method getter do
26
+ if instance_variable_defined?(ivar)
27
+ instance_variable_get(ivar)
28
+ else
29
+ instance_variable_set(
30
+ ivar,
31
+ self.class.instance_variable_get(ivar).dup
32
+ )
33
+ end
34
+ end if instance_reader
35
+
36
+ # Define Instance Setter
37
+ define_method setter do |value|
38
+ instance_variable_get(ivar).tap(&:clear).merge! value
39
+ end if instance_writer
40
+
41
+ # Define Inheritor
42
+ mod = Module.new do
43
+ define_method :inherited do |subclass|
44
+ super(subclass)
45
+
46
+ # Set subclass variable
47
+ subclass.instance_variable_set(ivar, Hash.new)
48
+ parent_var = instance_variable_get(ivar)
49
+ subclass_var = subclass.instance_variable_get(ivar)
50
+
51
+ # Merge changes from parent
52
+ subclass_var.deep_merge!(parent_var)
53
+
54
+ # Observe
55
+ observer = EnumerableObserver.observe(parent_var)
56
+ observer.added { |items| subclass_var.deep_merge! items.to_h }
57
+ observer.removed { |items| subclass_var.delete_if { |k, v| items.to_h[k] == v } }
58
+ end
59
+ end
60
+ extend mod
61
+ end
62
+ end
63
+
64
+ def inherited_array_attribute(*attrs, instance_reader: true, instance_writer: true, instance_accessor: true)
65
+ instance_reader, instance_writer = false, false unless instance_accessor
66
+ attrs.each do |attr|
67
+ ivar = :"@#{attr}"
68
+ setter = :"#{attr}="
69
+ getter = :"#{attr}"
70
+
71
+ # Define First Variable
72
+ instance_variable_set(ivar, Array.new)
73
+
74
+ # Define Setter
75
+ define_singleton_method setter do |value|
76
+ instance_variable_get(ivar).tap(&:clear).concat(value)
77
+ end
78
+
79
+ # Define Getter
80
+ define_singleton_method getter do
81
+ instance_variable_get(ivar)
82
+ end
83
+
84
+ # Define Instance Getter
85
+ define_method getter do
86
+ if instance_variable_defined?(ivar)
87
+ instance_variable_get(ivar)
88
+ else
89
+ instance_variable_set(
90
+ ivar,
91
+ self.class.instance_variable_get(ivar).dup
92
+ )
93
+ end
94
+ end if instance_reader
95
+
96
+ # Define Instance Setter
97
+ define_method setter do |value|
98
+ instance_variable_get(ivar).tap(&:clear).concat(value)
99
+ end if instance_writer
100
+
101
+ # Define Inheritor
102
+ mod = Module.new do
103
+ define_method :inherited do |subclass|
104
+ super(subclass)
105
+
106
+ # Set subclass variable
107
+ subclass.instance_variable_set(ivar, Array.new)
108
+ parent_var = instance_variable_get(ivar)
109
+ subclass_var = subclass.instance_variable_get(ivar)
110
+
111
+ # Merge changes from parent
112
+ subclass_var.concat(parent_var)
113
+
114
+ # Observe
115
+ observer = EnumerableObserver.observe(parent_var)
116
+ observer.added { |items| subclass_var.concat items }
117
+ observer.removed { |items| items.each { |item| subclass_var.delete item } }
118
+ end
119
+ end
120
+ extend mod
121
+ end
122
+ end
123
+
124
+ end
125
+ end
@@ -0,0 +1,104 @@
1
+ require 'active_support/core_ext/module/delegation'
2
+
3
+ module JSONAPIonify::Structure
4
+ module Collections
5
+ class Base < Array
6
+ include JSONAPIonify::EnumerableObserver
7
+ include Helpers::InheritsOrigin
8
+ attr_reader :parent
9
+
10
+ delegate :cache_store, to: JSONAPIonify
11
+
12
+ def self.value_is(type_class)
13
+ define_method(:type_class) do
14
+ type_class
15
+ end
16
+ end
17
+
18
+ value_is Objects::Base
19
+
20
+ def initialize(array = [])
21
+ observe.added do |items|
22
+ items.each do |item|
23
+ item.instance_variable_set(:@parent, self) unless item.frozen?
24
+ end
25
+ end
26
+ array.each do |instance|
27
+ self << instance
28
+ end
29
+ end
30
+
31
+ def original_method(method)
32
+ Array.instance_method(method).bind(self)
33
+ end
34
+
35
+ def validate
36
+ each do |member|
37
+ member.validate if member.respond_to? :validate
38
+ end
39
+ end
40
+
41
+ def signature
42
+ "#{self.class.name}:#{Digest::SHA2.hexdigest map(&:signature).join}"
43
+ end
44
+
45
+ def collect_hashes
46
+ map do |member|
47
+ case member
48
+ when Objects::Base, Hash
49
+ member.to_hash
50
+ else
51
+ member
52
+ end
53
+ end
54
+ end
55
+
56
+ def compile
57
+ collect_hashes
58
+ end
59
+
60
+ def new(**attributes)
61
+ self << attributes
62
+ end
63
+
64
+ alias_method :append, :new
65
+
66
+ def <<(instance)
67
+ new_instance =
68
+ case instance
69
+ when Hash
70
+ type_class.new(**instance)
71
+ when type_class
72
+ instance
73
+ else
74
+ raise ValidationError,
75
+ " Can 't initialize collection `#{self.class.name}` with a type of `#{instance.class.name}`"
76
+ end
77
+ super new_instance
78
+ end
79
+
80
+ def errors
81
+ map.each_with_index.each_with_object({}) do |(value, key), errors|
82
+ next unless value.respond_to? :errors
83
+ value.errors.each do |error_key, message|
84
+ errors[[key, error_key].join('/')] = message
85
+ end
86
+ end
87
+ end
88
+
89
+ def warnings
90
+ map.each_with_index.each_with_object({}) do |(value, key), warnings|
91
+ next unless value.respond_to? :all_warnings
92
+ value.all_warnings.each do |warning_key, message|
93
+ warnings[[key, warning_key].join('. ')] = message
94
+ end
95
+ end
96
+ end
97
+
98
+ alias_method :all_warnings, :warnings
99
+
100
+ private
101
+
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,7 @@
1
+ module JSONAPIonify::Structure
2
+ module Collections
3
+ class Errors < Base
4
+ value_is Objects::Error
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,39 @@
1
+ module JSONAPIonify::Structure
2
+ module Collections
3
+ class IncludedResources < Resources
4
+ value_is Objects::IncludedResource
5
+
6
+ def self.referenceable?(referenced, not_referenced)
7
+ not_referenced.any? do |unreferenced_item|
8
+ referenced.any? do |referenced_item|
9
+ referenced_item.relates_to? unreferenced_item
10
+ end
11
+ end
12
+ end
13
+
14
+ def referenced
15
+ return [] unless parent
16
+ top_level_referenced.tap do |referenced|
17
+ not_referenced = reduce([]) { |a, i| a << i }
18
+
19
+ while self.class.referenceable?(referenced, not_referenced)
20
+ not_referenced.each do |resource|
21
+ if referenced.any? { |referenced_item| referenced_item.relates_to? resource }
22
+ referenced << not_referenced.delete(resource)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def top_level_referenced
32
+ return [] unless parent
33
+ reduce([]) { |a, i| a << i }.select do |resource|
34
+ Array.wrap(parent[:data]).any? { |tlr| tlr.relates_to? resource }
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,7 @@
1
+ module JSONAPIonify::Structure
2
+ module Collections
3
+ class ResourceIdentifiers < Base
4
+ value_is Objects::ResourceIdentifier
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module JSONAPIonify::Structure
2
+ module Collections
3
+ class Resources < Base
4
+ value_is Objects::Resource
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,71 @@
1
+ require 'active_support/core_ext/module/delegation'
2
+
3
+ module JSONAPIonify::Structure
4
+ module Helpers
5
+ class Errors
6
+ include Enumerable
7
+
8
+ delegate :clear, :present?, :blank?, :each, to: :@hash
9
+
10
+ def initialize
11
+ @hash = {}
12
+ end
13
+
14
+ def initialize_copy(new_copy)
15
+ super
16
+ instance_variables.each do |ivar|
17
+ new_copy.instance_variable_set(
18
+ ivar, instance_variable_get(ivar).dup
19
+ ) rescue nil
20
+ end
21
+ end
22
+
23
+ def add(key, value)
24
+ (@hash[key] ||= []) << value
25
+ end
26
+
27
+ alias_method :[]=, :add
28
+
29
+ def [](key)
30
+ @hash[key]
31
+ end
32
+
33
+ def replace(key, messages)
34
+ @hash[key] = Array.wrap(messages)
35
+ end
36
+
37
+ def all_messages
38
+ @hash.each_with_object([]) do |(key, errors), messages|
39
+ errors.each do |error|
40
+ messages << [backtick_key(key), error].join(' ')
41
+ end
42
+ end
43
+ end
44
+
45
+ def as_collection
46
+ each_with_object(Collections::Errors.new) do |(pointer, messages), collection|
47
+ *, key = pointer.to_s.split('/')
48
+ entity = key.present? ? key : 'object'
49
+ messages.each do |message|
50
+ message = "#{entity} #{message}".chomp('.') << '.'
51
+ object = {
52
+ source: {
53
+ pointer: pointer
54
+ },
55
+ detail: message,
56
+ status: "422"
57
+ }
58
+ collection << object
59
+ end
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def backtick_key(key)
66
+ "`#{key}`"
67
+ end
68
+
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,17 @@
1
+ module JSONAPIonify::Structure
2
+ module Helpers
3
+ module InheritsOrigin
4
+ def client?
5
+ origin == :client
6
+ end
7
+
8
+ def server?
9
+ origin == :server
10
+ end
11
+
12
+ def origin
13
+ self.parent.try(:origin)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,37 @@
1
+ module JSONAPIonify::Structure
2
+ module Helpers
3
+ module MemberNames
4
+ extend self
5
+
6
+ def valid?(value)
7
+ return false if value.nil?
8
+ value = value.to_s if value.is_a? Symbol
9
+ [
10
+ value.present?,
11
+ valid_ends?(value),
12
+ contains_valid_characters?(value),
13
+ !contains_invalid_characters?(value)
14
+ ].reduce(:&)
15
+ end
16
+
17
+ private
18
+
19
+ def contains_valid_characters?(value)
20
+ value =~ /\A[a-zA-Z0-9\u0080-\uFFFF_\s-]+\Z/
21
+ end
22
+
23
+ def valid_ends?(value)
24
+ ['-', '_', ' '].map do |char|
25
+ !value.start_with?(char) & !value.end_with?(char)
26
+ end.reduce(:&)
27
+ end
28
+
29
+ def contains_invalid_characters?(value)
30
+ %w{+ , . [ ] ! " # $ % & ' ( ) * / : ; < = > ? @ \\ ^ ` { } | ~}.map do |char|
31
+ value.include? char
32
+ end.reduce(:|)
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,16 @@
1
+ class JSONAPIonify::Structure::Helpers::MetaDelegate
2
+ attr_reader :object
3
+
4
+ def initialize(object)
5
+ @object = object
6
+ end
7
+
8
+ def []=(k, v)
9
+ object[:meta] ||= {}
10
+ object[:meta][k] = v
11
+ end
12
+
13
+ def [](k)
14
+ object[:meta] && object[:meta][k]
15
+ end
16
+ end
@@ -0,0 +1,123 @@
1
+ require 'active_support/concern'
2
+
3
+ module JSONAPIonify::Structure
4
+ module Helpers
5
+ module ObjectDefaults
6
+ extend ActiveSupport::Concern
7
+ include JSONAPIonify::EnumerableObserver
8
+
9
+ module ClassMethods
10
+ # Forces the setter to a type
11
+ def implements(key, as:, **opts)
12
+ type_of! key, must_be: as, allow_nil: true
13
+ track_implementation key, as, **opts
14
+ end
15
+
16
+ # Forces the setter to the collection type
17
+ # Allows unset types to expose collection and type_map methods
18
+ def collects(key, as:, **opts)
19
+ type_of! key, must_be: as
20
+ track_collection key, as, **opts
21
+ end
22
+
23
+ # implements_or_collects(:data, implements: A, collects: B, if: ->(obj){ obj.has_key? :attributes })
24
+ # implements_or_collects(:data, implements: C, collects: D, unless: ->(obj){ obj.has_key? :attributes })
25
+ def collects_or_implements(key, implements:, collects:, allow_nil: false, **opts)
26
+ allowed = [implements, collects]
27
+ allowed << NilClass if allow_nil
28
+ type_of! key, must_be: allowed
29
+ track_collection key, collects, **opts
30
+ track_implementation key, implements, **opts
31
+ end
32
+
33
+ alias_method :implements_or_collects, :collects_or_implements
34
+
35
+ # Defaults
36
+ def default(key, &block)
37
+ after_initialize do
38
+ self[key] ||= instance_eval(&block)
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def track_implementation(key, klass, **opts)
45
+ (implementations[key] ||= {})[klass] = opts
46
+ end
47
+
48
+ def track_collection(key, klass, **opts)
49
+ (collections[key] ||= {})[klass] = opts
50
+ end
51
+ end
52
+
53
+ included do
54
+ include JSONAPIonify::InheritedAttributes
55
+ # Class Attributes
56
+ attr_reader :unset
57
+
58
+ inherited_hash_attribute :implementations, :collections
59
+
60
+ before_initialize do
61
+ @unset = {}
62
+ end
63
+ end
64
+
65
+ def [](k)
66
+ if has_key? k
67
+ super
68
+ elsif collections[k]
69
+ @unset[k] ||= [].tap do |ary|
70
+ observe(ary).added { self[k] = ary }
71
+ end
72
+ else
73
+ nil
74
+ end
75
+ end
76
+
77
+ def []=(k, v)
78
+ unset.delete_if { |unset_key, _| unset_key == k }
79
+ super k, coerce_value(k, v)
80
+ end
81
+
82
+ def object
83
+ super.tap do
84
+ newly_set = unset.select { |_, v| v.present? }
85
+ newly_set.each do |k, v|
86
+ self[k] = v
87
+ end
88
+ end
89
+ end
90
+
91
+ private
92
+
93
+ def coerce_value(k, v)
94
+ if implementations[k] && v.is_a?(Hash)
95
+ coerce_implementation(k, v)
96
+ elsif collections[k] && v.is_a?(Array)
97
+ coerce_collection(k, v)
98
+ else
99
+ v
100
+ end
101
+ end
102
+
103
+ def coerce_implementation(k, v)
104
+ klass, * = (implementations[k] || {}).find do |_, options|
105
+ JSONAPIonify::Continuation.new(**options).check(v) { true }
106
+ end
107
+ return v unless klass && !v.is_a?(klass)
108
+ klass.new(v)
109
+ end
110
+
111
+ def coerce_collection(k, v)
112
+ klass, * = (collections[k] || {}).find do |_, options|
113
+ v.all? do |obj|
114
+ JSONAPIonify::Continuation.new(**options).check(obj) { true }
115
+ end
116
+ end
117
+ return v unless klass && !v.is_a?(klass)
118
+ klass.new(v)
119
+ end
120
+
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,21 @@
1
+ require 'active_support/concern'
2
+
3
+ module JSONAPIonify::Structure
4
+ module Helpers
5
+ module ObjectSetters
6
+ extend ActiveSupport::Concern
7
+
8
+ # Setter
9
+ def []=(k, v)
10
+ raise TypeError, 'key must be a Symbol.' unless k.is_a? Symbol
11
+ object[k] = v
12
+ end
13
+
14
+ # Getter
15
+ def [](k)
16
+ raise TypeError, 'key must be a Symbol.' unless k.is_a? Symbol
17
+ object[k]
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ module JSONAPIonify::Structure
2
+ module Helpers
3
+ PaginationLinks = [
4
+ :first, # the first page of data
5
+ :last, # the last page of data
6
+ :prev, # the previous page of data
7
+ :next # the next page of data
8
+ ]
9
+ end
10
+ end