serega 0.14.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f11821b5953500ef9f895ad8c96e97951734615363f3147c623b70519b6199a5
4
- data.tar.gz: 8b03241a9def2e5a8777a75e61062f8b81544e497a1a1e490e085d52f14a326c
3
+ metadata.gz: d780c3d344370b36d9e6db64dfdfa08878bfe32885469610ac2314638c878d87
4
+ data.tar.gz: d282c6466f7b7205a7b524999b85a3e928d79c00ee11445abd26582e0146842c
5
5
  SHA512:
6
- metadata.gz: eb5cb48e74c0e9c8307c6ceb6c47b918eb46ef3c160de90d0eb976239bbc036f1d3fb78219abd5567977f348e3e03d7e492e29140e6d85223fcf14289d794d89
7
- data.tar.gz: acb7623ea317aab640aae70d0a5dfa0c436b706529741b36b15d938ab6af7523576f72ab4633b591b61dcdc38df768818eab3811005c248c3a00d2872cdccc46
6
+ metadata.gz: e2a161487df001b0074d1864770a7dfecd77ef788e187de6e460cd3d2856162cba8777eb807a65a8d4d49471bb50380fc49ffd17f36c16eb52a2ab8b84ed7991
7
+ data.tar.gz: 4a672090d0893ef8d3945b2528fc9861d245833ec4b21074b73481ab7acbf8fa5207c786cad8496bf022070f3341339522bbf4970c7a554cfa543f002f51f504
data/README.md CHANGED
@@ -888,91 +888,14 @@ Look at [select serialized fields](#selecting-fields) for `:hide` usage examples
888
888
  end
889
889
  ```
890
890
 
891
- ### Plugin :openapi
892
-
893
- Helps to build OpenAPI schemas
894
-
895
- This schemas can be easily used with [rswag](https://github.com/rswag/rswag#referenced-parameters-and-schema-definitions)"
896
- gem by adding them to "config.swagger_docs"
897
-
898
- Schemas properties will have no any "type" or other limits specified by default,
899
- you should provide them as new attribute `:openapi` option.
900
-
901
- This plugin adds type "object" or "array" only for relationships and marks
902
- attributes as **required** if they have no `:hide` option set
903
- (manually or automatically).
904
-
905
- After enabling this plugin attributes with :serializer option will have
906
- to have `:many` option set to construct "object" or "array" openapi
907
- property type.
908
-
909
- - constructing all serializers schemas:
910
- `Serega::OpenAPI.schemas`
911
- - constructing specific serializers schemas:
912
- `Serega::OpenAPI.schemas(Serega::OpenAPI.serializers - [MyBaseSerializer])`
913
- - constructing one serializer schema:
914
- `SomeSerializer.openapi_schema`
915
-
916
- ```ruby
917
- class BaseSerializer < Serega
918
- plugin :openapi
919
- end
920
-
921
- class UserSerializer < BaseSerializer
922
- attribute :name, openapi: { type: "string" }
923
-
924
- openapi_properties(
925
- name: { type: :string }
926
- )
927
- end
928
-
929
- class PostSerializer < BaseSerializer
930
- attribute :text, openapi: { type: "string" }
931
- attribute :user, serializer: UserSerializer, many: false
932
- attribute :comments, serializer: PostSerializer, many: true, hide: true
933
-
934
- openapi_properties(
935
- text: { type: :string },
936
- user: { type: 'object' }, # `$ref` added automatically
937
- comments: { type: 'array' } # `items` option with `$ref` added automatically
938
- )
939
- end
940
-
941
- puts Serega::OpenAPI.schemas
942
- # =>
943
- # {
944
- # "PostSerializer" => {
945
- # type: "object",
946
- # properties: {
947
- # text: {type: "string"},
948
- # user: {:$ref => "#/components/schemas/UserSerializer"},
949
- # comments: {type: "array", items: {:$ref => "#/components/schemas/PostSerializer"}}
950
- # },
951
- # required: [:text, :comments],
952
- # additionalProperties: false
953
- # },
954
- # "UserSerializer" => {
955
- # type: "object",
956
- # properties: {
957
- # name: {type: "string"}
958
- # },
959
- # required: [:name],
960
- # additionalProperties: false
961
- # }
962
- # }
963
- ```
964
-
965
891
  ### Plugin :explicit_many_option
966
892
 
967
893
  Plugin requires to add :many option when adding relationships
968
894
  (relationships are attributes with :serializer option specified)
969
895
 
970
- Adding this plugin makes clearer to find if relationship returns array or single
896
+ Adding this plugin makes it clearer to find if relationship returns array or single
971
897
  object
972
898
 
973
- Also plugin `:openapi` load this plugin automatically as it need to know if
974
- relationship is array
975
-
976
899
  ```ruby
977
900
  class BaseSerializer < Serega
978
901
  plugin :explicit_many_option
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.14.0
1
+ 0.15.0
@@ -8,10 +8,7 @@ class Serega
8
8
  # Plugin requires to add :many option when adding relationships
9
9
  # (relationships are attributes with :serializer option specified)
10
10
  #
11
- # Adding this plugin makes clearer to find if relationship returns array or single object
12
- #
13
- # Also some plugins like :openapi load this plugin automatically as they need to know if
14
- # relationship is array
11
+ # Adding this plugin makes it clearer to find if relationship returns array or single object
15
12
  #
16
13
  # @example
17
14
  # class BaseSerializer < Serega
@@ -7,17 +7,34 @@ class Serega
7
7
  # Attribute `:many` option validator
8
8
  #
9
9
  class CheckOptMany
10
- #
11
- # Checks attribute :many option
12
- #
13
- # @param opts [Hash] Attribute options
14
- #
15
- # @raise [SeregaError] SeregaError that option has invalid value
16
- #
17
- # @return [void]
18
- #
19
- def self.call(opts)
20
- Utils::CheckOptIsBool.call(opts, :many)
10
+ class << self
11
+ #
12
+ # Checks attribute :many option
13
+ #
14
+ # @param opts [Hash] Attribute options
15
+ #
16
+ # @raise [SeregaError] SeregaError that option has invalid value
17
+ #
18
+ # @return [void]
19
+ #
20
+ def call(opts)
21
+ return unless opts.key?(:many)
22
+
23
+ check_many_option_makes_sence(opts)
24
+ Utils::CheckOptIsBool.call(opts, :many)
25
+ end
26
+
27
+ private
28
+
29
+ def check_many_option_makes_sence(opts)
30
+ return if many_option_makes_sence?(opts)
31
+
32
+ raise SeregaError, "Option :many can be provided only together with :serializer or :batch option"
33
+ end
34
+
35
+ def many_option_makes_sence?(opts)
36
+ opts[:serializer] || opts[:batch]
37
+ end
21
38
  end
22
39
  end
23
40
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: serega
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.0
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrey Glushkov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-24 00:00:00.000000000 Z
11
+ date: 2023-08-13 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
14
  JSON Serializer
@@ -74,9 +74,6 @@ files:
74
74
  - lib/serega/plugins/metadata/validations/check_opt_hide_nil.rb
75
75
  - lib/serega/plugins/metadata/validations/check_opts.rb
76
76
  - lib/serega/plugins/metadata/validations/check_path.rb
77
- - lib/serega/plugins/openapi/lib/modules/config.rb
78
- - lib/serega/plugins/openapi/lib/openapi_config.rb
79
- - lib/serega/plugins/openapi/openapi.rb
80
77
  - lib/serega/plugins/preloads/lib/format_user_preloads.rb
81
78
  - lib/serega/plugins/preloads/lib/modules/attribute.rb
82
79
  - lib/serega/plugins/preloads/lib/modules/attribute_normalizer.rb
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Serega
4
- module SeregaPlugins
5
- module OpenAPI
6
- #
7
- # Config class additional/patched instance methods
8
- #
9
- # @see Serega::SeregaConfig
10
- #
11
- module ConfigInstanceMethods
12
- #
13
- # Returns openapi plugin config
14
- #
15
- # @return [Serega::SeregaPlugins::OpenAPI::OpenAPIConfig] configuration for openapi plugin
16
- #
17
- def openapi
18
- @openapi ||= OpenAPIConfig.new(self.class.serializer_class, opts.fetch(:openapi))
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,101 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Serega
4
- module SeregaPlugins
5
- module OpenAPI
6
- #
7
- # OpenAPI plugin config
8
- #
9
- class OpenAPIConfig
10
- attr_reader :serializer_class, :opts
11
-
12
- def initialize(serializer_class, opts)
13
- @serializer_class = serializer_class
14
- @opts = opts
15
- end
16
-
17
- #
18
- # Saves new properties
19
- #
20
- # @param new_properties [Hash] new properties
21
- #
22
- # @return [Hash] OpenAPI properties
23
- #
24
- def properties(new_properties = FROZEN_EMPTY_HASH)
25
- properties = opts[:properties]
26
- return properties if new_properties.empty?
27
-
28
- new_properties = SeregaUtils::EnumDeepDup.call(new_properties)
29
- symbolize_keys!(new_properties)
30
-
31
- new_properties.each do |attribute_name, new_attribute_properties|
32
- check_attribute_exists(attribute_name)
33
- check_properties_is_a_hash(attribute_name, new_attribute_properties)
34
-
35
- properties[attribute_name] = symbolize_keys!(new_attribute_properties)
36
- end
37
- end
38
-
39
- #
40
- # @return [#call] builder of `$ref` attribute
41
- #
42
- def ref_builder
43
- opts[:ref_builder]
44
- end
45
-
46
- #
47
- # Sets new $ref option builder
48
- #
49
- # @param builder [#call] Callable object that accepts serializer_class and constructs $ref option string
50
- #
51
- # @return Specified new builder
52
- #
53
- def ref_builder=(builder)
54
- raise SeregaError, "ref_builder must respond to #call" unless builder.respond_to?(:call)
55
- opts[:ref_builder] = builder
56
- end
57
-
58
- #
59
- # @return [#call] builder of schema name
60
- #
61
- def schema_name_builder
62
- opts[:schema_name_builder]
63
- end
64
-
65
- #
66
- # Sets new schema_name_builder
67
- #
68
- # @param builder [#call] Callable object that accepts serializer_class and
69
- # constructs schema name to use in schemas list and in $ref option
70
- #
71
- # @return Specified new builder
72
- #
73
- def schema_name_builder=(builder)
74
- raise SeregaError, "schema_name_builder must respond to #call" unless builder.respond_to?(:call)
75
- opts[:schema_name_builder] = builder
76
- end
77
-
78
- private
79
-
80
- def check_attribute_exists(attribute_name)
81
- return if serializer_class.attributes.key?(attribute_name)
82
-
83
- raise SeregaError, "No attribute with name :#{attribute_name}"
84
- end
85
-
86
- def check_properties_is_a_hash(attribute_name, new_attribute_properties)
87
- return if new_attribute_properties.is_a?(Hash)
88
-
89
- raise SeregaError, "Property #{attribute_name} value must be a Hash," \
90
- " but #{new_attribute_properties.inspect} was provided"
91
- end
92
-
93
- def symbolize_keys!(opts)
94
- opts.transform_keys! do |key|
95
- key.to_sym
96
- end
97
- end
98
- end
99
- end
100
- end
101
- end
@@ -1,245 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Serega
4
- #
5
- # Utility class to build OpenAPI schemas
6
- #
7
- class OpenAPI
8
- #
9
- # Constructs OpenAPI schemas for multiple serializers
10
- #
11
- # @params serializers [Class<Serega>] Serializers tobuild schemas,
12
- # by default it is all serializers with :openapi plugin enabled
13
- #
14
- # @return [Hash] Schemas hash
15
- #
16
- def self.schemas(serializers = self.serializers)
17
- serializers.each_with_object({}) do |serializer_class, schemas|
18
- schema = serializer_class.openapi_schema
19
- schema_name = serializer_class.openapi_schema_name
20
- schemas[schema_name] = schema
21
- end
22
- end
23
-
24
- #
25
- # Returns list of serializers with :openapi plugin
26
- #
27
- def self.serializers
28
- @serializers ||= []
29
- end
30
- end
31
-
32
- module SeregaPlugins
33
- #
34
- # Plugin :openapi
35
- #
36
- # Helps to build OpenAPI schemas
37
- #
38
- # This schemas can be easielty used with "rswag" gem by adding them to "config.swagger_docs"
39
- # https://github.com/rswag/rswag#referenced-parameters-and-schema-definitions
40
- #
41
- # This plugin only adds type "object" or "array" for relationships and marks
42
- # attributes as **required** if they have no :hide option set.
43
- #
44
- # OpenAPI properties will have no any "type" or other options specified by default,
45
- # you should provide them in 'YourSerializer.openapi_properties' method.
46
- # `openapi_properties` can be specified multiple time, in this case they wil be merged.
47
- #
48
- # After enabling this plugin attributes with :serializer option will have
49
- # to have :many option set to construct "object" or "array" openapi type for relationships.
50
- #
51
- # OpenAPI `$ref` property will be added automatically for all relationships.
52
- #
53
- # Example constructing all serializers schemas:
54
- # `Serega::OpenAPI.schemas`
55
- #
56
- # Example constructing specific serializers schemas:
57
- # `Serega::OpenAPI.schemas(Serega::OpenAPI.serializers - [MyBaseSerializer])`
58
- #
59
- # Example constructing one serializer schema:
60
- # `SomeSerializer.openapi_schema`
61
- #
62
- # @example
63
- # class BaseSerializer < Serega
64
- # plugin :openapi
65
- # end
66
- #
67
- # class UserSerializer < BaseSerializer
68
- # attribute :name
69
- #
70
- # openapi_properties(
71
- # name: { type: :string }
72
- # )
73
- # end
74
- #
75
- # class PostSerializer < BaseSerializer
76
- # attribute :text
77
- # attribute :user, serializer: UserSerializer, many: false
78
- # attribute :comments, serializer: PostSerializer, many: true, hide: true
79
- #
80
- # openapi_properties(
81
- # text: { type: :string },
82
- # user: { type: 'object' }, # `$ref` option will be added automatically when constructing schema
83
- # comments: { type: 'array' } # `items` option with `$ref` will be added automatically when constructing schema
84
- # )
85
- # end
86
- #
87
- # puts Serega::OpenAPI.schemas
88
- # =>
89
- # {
90
- # "PostSerializer" => {
91
- # type: "object",
92
- # properties: {
93
- # text: {type: "string"},
94
- # user: {:$ref => "#/components/schemas/UserSerializer"},
95
- # comments: {type: "array", items: {:$ref => "#/components/schemas/PostSerializer"}}
96
- # },
97
- # required: [:text, :comments],
98
- # additionalProperties: false
99
- # },
100
- # "UserSerializer" => {
101
- # type: "object",
102
- # properties: {
103
- # name: {type: "string"}
104
- # },
105
- # required: [:name],
106
- # additionalProperties: false
107
- # }
108
- # }
109
- #
110
- module OpenAPI
111
- # Builder for schema name (used is schemas list). Returns serializer class name
112
- DEFAULT_SCHEMA_NAME_BUILDER = ->(serializer_class) { serializer_class.name }
113
-
114
- # Builder for $ref openapi property
115
- DEFAULT_REF_BUILDER = ->(serializer_class) { "#/components/schemas/#{serializer_class.openapi_schema_name}" }
116
-
117
- # @return [Symbol] Plugin name
118
- def self.plugin_name
119
- :openapi
120
- end
121
-
122
- # Checks requirements and loads additional plugins
123
- #
124
- # @param serializer_class [Class<Serega>] Current serializer class
125
- # @param opts [Hash] loaded plugins opts
126
- #
127
- # @return [void]
128
- #
129
- def self.before_load_plugin(serializer_class, **opts)
130
- unless serializer_class.plugin_used?(:explicit_many_option)
131
- serializer_class.plugin :explicit_many_option
132
- end
133
- end
134
-
135
- #
136
- # Applies plugin code to specific serializer
137
- #
138
- # @param serializer_class [Class<Serega>] Current serializer class
139
- # @param _opts [Hash] Loaded plugins options
140
- #
141
- # @return [void]
142
- #
143
- def self.load_plugin(serializer_class, **opts)
144
- require_relative "./lib/modules/config"
145
- require_relative "./lib/openapi_config"
146
-
147
- serializer_class.extend(ClassMethods)
148
- serializer_class::SeregaConfig.include(ConfigInstanceMethods)
149
-
150
- config = serializer_class.config
151
- config.opts[:openapi] = {properties: {}}
152
- openapi_config = serializer_class.config.openapi
153
- openapi_config.schema_name_builder = opts[:schema_name_builder] || DEFAULT_SCHEMA_NAME_BUILDER
154
- openapi_config.ref_builder = opts[:ref_builder] || DEFAULT_REF_BUILDER
155
- end
156
-
157
- #
158
- # Adds config options and runs other callbacks after plugin was loaded
159
- #
160
- # @param serializer_class [Class<Serega>] Current serializer class
161
- # @param opts [Hash] loaded plugins opts
162
- #
163
- # @return [void]
164
- #
165
- def self.after_load_plugin(serializer_class, **opts)
166
- Serega::OpenAPI.serializers << serializer_class unless serializer_class.equal?(Serega)
167
- end
168
-
169
- #
170
- # Serega additional/patched class methods
171
- #
172
- # @see Serega
173
- #
174
- module ClassMethods
175
- #
176
- # OpenAPI schema for current serializer
177
- #
178
- def openapi_schema
179
- properties = SeregaUtils::EnumDeepDup.call(openapi_properties)
180
- required_properties = []
181
-
182
- attributes.each do |attribute_name, attribute|
183
- add_openapi_property(properties, attribute_name, attribute)
184
- add_openapi_required_property(required_properties, attribute_name, attribute)
185
- end
186
-
187
- {
188
- type: "object",
189
- properties: properties,
190
- required: required_properties,
191
- additionalProperties: false
192
- }
193
- end
194
-
195
- #
196
- # Adds new OpenAPI properties and returns all properties
197
- #
198
- # @param props [Hash] Specifies new properties
199
- #
200
- # @return [Hash] Specified OpenAPI properties
201
- #
202
- def openapi_properties(props = FROZEN_EMPTY_HASH)
203
- config.openapi.properties(props)
204
- end
205
-
206
- #
207
- # Builds OpenAPI schema name using configured builder
208
- #
209
- # @return [String] OpenAPI schema name
210
- #
211
- def openapi_schema_name
212
- config.openapi.schema_name_builder.call(self)
213
- end
214
-
215
- private
216
-
217
- def inherited(subclass)
218
- super
219
- Serega::OpenAPI.serializers << subclass
220
- end
221
-
222
- def add_openapi_property(properties, attribute_name, attribute)
223
- property = properties[attribute_name] ||= {}
224
- return unless attribute.relation?
225
-
226
- ref = attribute.serializer.config.openapi.ref_builder.call(attribute.serializer)
227
-
228
- if attribute.many
229
- property[:type] = "array"
230
- property[:items] ||= {}
231
- property[:items][:$ref] ||= ref
232
- else
233
- property[:$ref] ||= ref
234
- end
235
- end
236
-
237
- def add_openapi_required_property(required_properties, attribute_name, attribute)
238
- required_properties << attribute_name unless attribute.hide
239
- end
240
- end
241
- end
242
-
243
- register_plugin(OpenAPI.plugin_name, OpenAPI)
244
- end
245
- end