jsonapionify 0.0.1.pre

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 (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