barley 0.3.0 → 0.4.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.
- checksums.yaml +4 -4
- data/README.md +28 -3
- data/lib/barley/serializable.rb +16 -0
- data/lib/barley/serializer.rb +161 -6
- data/lib/barley/version.rb +1 -1
- data/lib/barley.rb +1 -0
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: faa7d627d11906ae112f0a8fd640f0a2d90acacc114c63297a26e227d5120c3d
|
4
|
+
data.tar.gz: c36d22bee59469e7e98f481086a5a32a75ac96d9bab984330a4d945c97efa5f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3adb8da65be384daf38feaf056541f6b3e2c2f7f400917ed2da43a9f382e3bbc28afdad2437fe7489bdcd1ccd3980a587697525f0b493e1ec7b5374acfb61bb8
|
7
|
+
data.tar.gz: a359ed1a3c15f8efdd62ec86112163edc8d423f9d0d8c8790e781c651ac208dfa722a42bb4c93f822b5bbfc2a072626bbf1c9ad088c24354828745476247fc58
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-

|
2
2
|
|
3
3
|
Barley is a dead simple, fast, and efficient ActiveModel JSON serializer.
|
4
4
|
|
@@ -6,6 +6,9 @@ Cerealize your ActiveModel objects into flat hashes with a dead simple, yet vers
|
|
6
6
|
|
7
7
|
You don't believe us? Check out the [benchmarks](#benchmarks). 😎
|
8
8
|
|
9
|
+
## API documentation
|
10
|
+
[Check out the API documentation here](https://rubydoc.info/github/MoskitoHero/barley/main).
|
11
|
+
|
9
12
|
## Usage
|
10
13
|
Add the `Barley::Serializable` module to your ActiveModel object.
|
11
14
|
|
@@ -21,8 +24,9 @@ Then define your attributes and associations in a serializer class.
|
|
21
24
|
```ruby
|
22
25
|
# /app/serializers/user_serializer.rb
|
23
26
|
class UserSerializer < Barley::Serializer
|
24
|
-
attributes :
|
27
|
+
attributes id: Types::Strict::Integer, :name # multiple attributes, optional type checking with dry-types
|
25
28
|
attribute :email # single attribute
|
29
|
+
attribute :value, type: Types::Coercible::Integer # optional type checking with dry-types
|
26
30
|
|
27
31
|
many :posts # relations
|
28
32
|
one :group, serializer: CustomGroupSerializer # custom serializer
|
@@ -243,6 +247,27 @@ Barley.configure do |config|
|
|
243
247
|
end
|
244
248
|
```
|
245
249
|
|
250
|
+
## Type checking
|
251
|
+
Barley can check the type of the object you are serializing with the [dry-types](https://dry-rb.org/gems/dry-types/main/) gem.
|
252
|
+
|
253
|
+
It will raise an error if the object is not of the expected type, or coerce it to the correct type and perform constraints checks.
|
254
|
+
|
255
|
+
```ruby
|
256
|
+
module Types
|
257
|
+
include Dry.Types()
|
258
|
+
end
|
259
|
+
|
260
|
+
class UserSerializer < Barley::Serializer
|
261
|
+
attributes id: Types::Strict::Integer, name: Types::Strict::String, email: Types::Strict::String.constrained(format: URI::MailTo::EMAIL_REGEXP)
|
262
|
+
|
263
|
+
attribute :role, type: Types::Coercible::String do
|
264
|
+
object.role.integer_or_string_coercible_value
|
265
|
+
end
|
266
|
+
end
|
267
|
+
```
|
268
|
+
|
269
|
+
Check out [dry-types](https://dry-rb.org/gems/dry-types/main/) for all options and available types.
|
270
|
+
|
246
271
|
## Breakfast mode 🤡 (coming soon)
|
247
272
|
You will soon be able to replace all occurrences of `Serializer` with `Cerealizer` in your codebase. Just for fun. And for free.
|
248
273
|
|
@@ -364,4 +389,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
364
389
|
## Credits
|
365
390
|
Barley is brought to you by the developer team from [StockPro](https://www.stock-pro.fr/).
|
366
391
|
|
367
|
-
[](https://www.stock-pro.fr/)
|
data/lib/barley/serializable.rb
CHANGED
@@ -4,6 +4,7 @@ module Barley
|
|
4
4
|
# Makes a Model serializable
|
5
5
|
#
|
6
6
|
# * Allows setting a default model Serializer
|
7
|
+
#
|
7
8
|
# @example
|
8
9
|
# class Item < ApplicationRecord
|
9
10
|
# include Barley::Serializable
|
@@ -19,10 +20,15 @@ module Barley
|
|
19
20
|
class_methods do
|
20
21
|
# @example without cache
|
21
22
|
# serializer ItemSerializer
|
23
|
+
#
|
22
24
|
# @example with cache
|
23
25
|
# serializer ItemSerializer, cache: true
|
26
|
+
#
|
24
27
|
# @example with cache and expires_in
|
25
28
|
# serializer ItemSerializer, cache: {expires_in: 1.hour}
|
29
|
+
#
|
30
|
+
# @param klass [Class] the serializer class
|
31
|
+
# @param cache [Boolean, Hash<Symbol, ActiveSupport::Duration>] whether to cache the result, or a hash with options for the cache
|
26
32
|
def serializer(klass, cache: false)
|
27
33
|
define_method(:serializer) do
|
28
34
|
klass.new(self, cache: cache)
|
@@ -33,6 +39,16 @@ module Barley
|
|
33
39
|
included do
|
34
40
|
serializer "#{self}Serializer".constantize
|
35
41
|
|
42
|
+
# Serializes the model
|
43
|
+
#
|
44
|
+
# @note this method does not provide default rails options like `only` or `except`.
|
45
|
+
# This is because the Barley serializer should be the only place where the attributes are defined.
|
46
|
+
#
|
47
|
+
# @param serializer [Class] the serializer to use
|
48
|
+
# @param cache [Boolean, Hash<Symbol, ActiveSupport::Duration>] whether to cache the result, or a hash with options for the cache
|
49
|
+
# @param root [Boolean] whether to include the root key in the hash
|
50
|
+
#
|
51
|
+
# @return [Hash] the serialized attributes
|
36
52
|
def as_json(serializer: nil, cache: false, root: false)
|
37
53
|
serializer ||= self.serializer.class
|
38
54
|
serializer.new(self, cache: cache, root: root).serializable_hash
|
data/lib/barley/serializer.rb
CHANGED
@@ -5,29 +5,118 @@ module Barley
|
|
5
5
|
attr_accessor :object
|
6
6
|
|
7
7
|
class << self
|
8
|
+
# Defines attributes for the serializer
|
9
|
+
#
|
10
|
+
# Accepts either a list of symbols or a hash of symbols and Dry::Types, or a mix of both
|
11
|
+
#
|
12
|
+
# @example only symbols
|
13
|
+
# attributes :id, :name, :email
|
14
|
+
# # => {id: 1234, name: "John Doe", email: "john.doe@example"}
|
15
|
+
#
|
16
|
+
# @example with types
|
17
|
+
# attributes id: Types::Strict::Integer, name: Types::Strict::String, email: Types::Strict::String
|
18
|
+
# # => {id: 1234, name: "John Doe", email: "john.doe@example"}
|
19
|
+
#
|
20
|
+
# @example with types and symbols
|
21
|
+
# attributes :id, name: Types::Strict::String, email: Types::Strict::String
|
22
|
+
# # => {id: 1234, name: "John Doe", email: "john.doe@example"}
|
23
|
+
#
|
24
|
+
# @see Serializer#attribute
|
25
|
+
#
|
26
|
+
# @param keys [Hash<Symbol, Dry::Types>, Array<Symbol>] mix of symbols and hashes of symbols and Dry::Types
|
8
27
|
def attributes(*keys)
|
28
|
+
if keys.last.is_a?(Hash)
|
29
|
+
keys.pop.each do |key, type|
|
30
|
+
attribute(key, type: type)
|
31
|
+
end
|
32
|
+
end
|
9
33
|
keys.each do |key|
|
10
|
-
|
11
|
-
|
34
|
+
if key.is_a?(Hash)
|
35
|
+
attribute(key.keys.first, type: key.values.first)
|
36
|
+
else
|
37
|
+
attribute(key)
|
12
38
|
end
|
13
|
-
set_class_iv(:@defined_attributes, key)
|
14
39
|
end
|
15
40
|
end
|
16
41
|
|
17
|
-
|
42
|
+
# Defines a single attribute for the serializer
|
43
|
+
#
|
44
|
+
# Type checking is done with Dry::Types. If a type is not provided, the value is returned as is.
|
45
|
+
# Dry::Types can be used to coerce the value to the desired type and to check constraints.
|
46
|
+
#
|
47
|
+
# @see https://dry-rb.org/gems/dry-types/main/
|
48
|
+
#
|
49
|
+
# @raise [Dry::Types::ConstraintError] if the type does not match
|
50
|
+
#
|
51
|
+
# @example simple attribute
|
52
|
+
# attribute :id
|
53
|
+
# # => {id: 1234}
|
54
|
+
#
|
55
|
+
# @example attribute with a different key name
|
56
|
+
# attribute :name, key_name: :full_name
|
57
|
+
# # => {full_name: "John Doe"}
|
58
|
+
#
|
59
|
+
# @example attribute with a type
|
60
|
+
# attribute :email, type: Types::Strict::String
|
61
|
+
# # => {email: "john.doe@example"}
|
62
|
+
#
|
63
|
+
# @example attribute with a type and a block
|
64
|
+
# attribute :email, type: Types::Strict::String do
|
65
|
+
# object.email.upcase
|
66
|
+
# end
|
67
|
+
# # => {email: "JOHN.DOE@EXAMPLE"}
|
68
|
+
#
|
69
|
+
# @param key [Symbol] the attribute name
|
70
|
+
# @param key_name [Symbol] the key name in the hash
|
71
|
+
# @param type [Dry::Types] the type to use, or coerce the value to
|
72
|
+
# @param block [Proc] a block to use to compute the value
|
73
|
+
def attribute(key, key_name: nil, type: nil, &block)
|
18
74
|
key_name ||= key
|
19
75
|
if block
|
20
76
|
define_method(key_name) do
|
21
|
-
instance_eval(&block)
|
77
|
+
type.nil? ? instance_eval(&block) : type[instance_eval(&block)]
|
22
78
|
end
|
23
79
|
else
|
24
80
|
define_method(key_name) do
|
25
|
-
object.send(key)
|
81
|
+
type.nil? ? object.send(key) : type[object.send(key)]
|
26
82
|
end
|
27
83
|
end
|
28
84
|
set_class_iv(:@defined_attributes, key_name)
|
29
85
|
end
|
30
86
|
|
87
|
+
# Defines a single association for the serializer
|
88
|
+
#
|
89
|
+
# @example using the default serializer of the associated model
|
90
|
+
# one :group
|
91
|
+
# # => {group: {id: 1234, name: "Group 1"}}
|
92
|
+
#
|
93
|
+
# @example using a custom serializer
|
94
|
+
# one :group, serializer: MyCustomGroupSerializer
|
95
|
+
# # => {group: {id: 1234, name: "Group 1"}}
|
96
|
+
#
|
97
|
+
# @example using a block with an inline serializer definition
|
98
|
+
# one :group do
|
99
|
+
# attributes :id, :name
|
100
|
+
# end
|
101
|
+
# # => {group: {id: 1234, name: "Group 1"}}
|
102
|
+
#
|
103
|
+
# @example using a different key name
|
104
|
+
# one :group, key_name: :my_group
|
105
|
+
# # => {my_group: {id: 1234, name: "Group 1"}}
|
106
|
+
#
|
107
|
+
# @example using cache
|
108
|
+
# one :group, cache: true
|
109
|
+
# # => {group: {id: 1234, name: "Group 1"}}
|
110
|
+
#
|
111
|
+
# @example using cache and expires_in
|
112
|
+
# one :group, cache: {expires_in: 1.hour}
|
113
|
+
# # => {group: {id: 1234, name: "Group 1"}}
|
114
|
+
#
|
115
|
+
# @param key [Symbol] the association name
|
116
|
+
# @param key_name [Symbol] the key name in the hash
|
117
|
+
# @param serializer [Class] the serializer to use
|
118
|
+
# @param cache [Boolean, Hash<Symbol, ActiveSupport::Duration>] whether to cache the result, or a hash with options for the cache
|
119
|
+
# @param block [Proc] a block to use to define the serializer inline
|
31
120
|
def one(key, key_name: nil, serializer: nil, cache: false, &block)
|
32
121
|
key_name ||= key
|
33
122
|
if block
|
@@ -45,6 +134,39 @@ module Barley
|
|
45
134
|
set_class_iv(:@defined_attributes, key_name)
|
46
135
|
end
|
47
136
|
|
137
|
+
# Defines a collection association for the serializer
|
138
|
+
#
|
139
|
+
# @example using the default serializer of the associated model
|
140
|
+
# many :groups
|
141
|
+
# # => {groups: [{id: 1234, name: "Group 1"}, {id: 5678, name: "Group 2"}]}
|
142
|
+
#
|
143
|
+
# @example using a custom serializer
|
144
|
+
# many :groups, serializer: MyCustomGroupSerializer
|
145
|
+
# # => {groups: [{id: 1234, name: "Group 1"}, {id: 5678, name: "Group 2"}]}
|
146
|
+
#
|
147
|
+
# @example using a block with an inline serializer definition
|
148
|
+
# many :groups do
|
149
|
+
# attributes :id, :name
|
150
|
+
# end
|
151
|
+
# # => {groups: [{id: 1234, name: "Group 1"}, {id: 5678, name: "Group 2"}]}
|
152
|
+
#
|
153
|
+
# @example using a different key name
|
154
|
+
# many :groups, key_name: :my_groups
|
155
|
+
# # => {my_groups: [{id: 1234, name: "Group 1"}, {id: 5678, name: "Group 2"}]}
|
156
|
+
#
|
157
|
+
# @example using cache
|
158
|
+
# many :groups, cache: true
|
159
|
+
# # => {groups: [{id: 1234, name: "Group 1"}, {id: 5678, name: "Group 2"}]}
|
160
|
+
#
|
161
|
+
# @example using cache and expires_in
|
162
|
+
# many :groups, cache: {expires_in: 1.hour}
|
163
|
+
# # => {groups: [{id: 1234, name: "Group 1"}, {id: 5678, name: "Group 2"}]}
|
164
|
+
#
|
165
|
+
# @param key [Symbol] the association name
|
166
|
+
# @param key_name [Symbol] the key name in the hash
|
167
|
+
# @param serializer [Class] the serializer to use
|
168
|
+
# @param cache [Boolean, Hash<Symbol, ActiveSupport::Duration>] whether to cache the result, or a hash with options for the cache
|
169
|
+
# @param block [Proc] a block to use to define the serializer inline
|
48
170
|
def many(key, key_name: nil, serializer: nil, cache: false, &block)
|
49
171
|
key_name ||= key
|
50
172
|
if block
|
@@ -62,6 +184,12 @@ module Barley
|
|
62
184
|
set_class_iv(:@defined_attributes, key_name)
|
63
185
|
end
|
64
186
|
|
187
|
+
# Either sets or appends a key to an instance variable
|
188
|
+
#
|
189
|
+
# @api private
|
190
|
+
#
|
191
|
+
# @param iv [Symbol] the instance variable to set
|
192
|
+
# @param key [Symbol] the key to add to the instance variable
|
65
193
|
def set_class_iv(iv, key)
|
66
194
|
instance_variable_defined?(iv) ? instance_variable_get(iv) << key : instance_variable_set(iv, [key])
|
67
195
|
end
|
@@ -69,8 +197,13 @@ module Barley
|
|
69
197
|
|
70
198
|
# @example with cache
|
71
199
|
# Barley::Serializer.new(object, cache: true)
|
200
|
+
#
|
72
201
|
# @example with cache and expires_in
|
73
202
|
# Barley::Serializer.new(object, cache: {expires_in: 1.hour})
|
203
|
+
#
|
204
|
+
# @param object [Object] the object to serialize
|
205
|
+
# @param cache [Boolean, Hash<Symbol, ActiveSupport::Duration>] a boolean to cache the result, or a hash with options for the cache
|
206
|
+
# @param root [Boolean] whether to include the root key in the hash
|
74
207
|
def initialize(object, cache: false, root: false)
|
75
208
|
@object = object
|
76
209
|
@root = root
|
@@ -81,6 +214,9 @@ module Barley
|
|
81
214
|
end
|
82
215
|
end
|
83
216
|
|
217
|
+
# Serializes the object
|
218
|
+
#
|
219
|
+
# @return [Hash] the serializable hash
|
84
220
|
def serializable_hash
|
85
221
|
if @cache
|
86
222
|
Barley::Cache.fetch(cache_base_key, expires_in: @expires_in) do
|
@@ -91,12 +227,20 @@ module Barley
|
|
91
227
|
end
|
92
228
|
end
|
93
229
|
|
230
|
+
# Clears the cache for the object
|
231
|
+
#
|
232
|
+
# @param key [String] the cache key
|
233
|
+
#
|
234
|
+
# @return [Boolean] whether the cache was cleared
|
94
235
|
def clear_cache(key: cache_base_key)
|
95
236
|
Barley::Cache.delete(key)
|
96
237
|
end
|
97
238
|
|
98
239
|
private
|
99
240
|
|
241
|
+
# @api private
|
242
|
+
#
|
243
|
+
# @return [String] the cache key
|
100
244
|
def cache_base_key
|
101
245
|
if object.updated_at.present?
|
102
246
|
"#{object.class.name&.underscore}/#{object.id}/#{object.updated_at&.to_i}/barley_cache/"
|
@@ -105,10 +249,18 @@ module Barley
|
|
105
249
|
end
|
106
250
|
end
|
107
251
|
|
252
|
+
# @api private
|
253
|
+
#
|
254
|
+
# @return [Array<Symbol>] the defined attributes
|
108
255
|
def defined_attributes
|
109
256
|
self.class.instance_variable_get(:@defined_attributes)
|
110
257
|
end
|
111
258
|
|
259
|
+
# Serializes the object
|
260
|
+
#
|
261
|
+
# @api private
|
262
|
+
#
|
263
|
+
# @return [Hash] the serializable hash
|
112
264
|
def _serializable_hash
|
113
265
|
hash = {}
|
114
266
|
|
@@ -119,6 +271,9 @@ module Barley
|
|
119
271
|
@root ? {root_key => hash} : hash
|
120
272
|
end
|
121
273
|
|
274
|
+
# @api private
|
275
|
+
#
|
276
|
+
# @return [Symbol] the root key, based on the class name
|
122
277
|
def root_key
|
123
278
|
object.class.name.underscore.to_sym
|
124
279
|
end
|
data/lib/barley/version.rb
CHANGED
data/lib/barley.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: barley
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cedric Delalande
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-10-
|
11
|
+
date: 2023-10-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 6.1.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: dry-types
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.7.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.7.1
|
27
41
|
description: Cerealize your ActiveModel objects into flat JSON objects with a dead
|
28
42
|
simple DSL. Our daily bread is to make your API faster.
|
29
43
|
email:
|