pb-serializer 0.5.0 → 0.5.1
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/CHANGELOG.md +8 -0
- data/lib/pb/serializable.rb +6 -104
- data/lib/pb/serializer.rb +42 -1
- data/lib/pb/serializer/attribute.rb +1 -1
- data/lib/pb/serializer/computed_model_support.rb +51 -0
- data/lib/pb/serializer/dsl.rb +69 -0
- data/lib/pb/serializer/version.rb +1 -1
- metadata +4 -3
- data/lib/pb/serializer/normalized_mask.rb +0 -57
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: db5867da46505d0facc08d12c1d6a3c93a87d7ca617110e8a9f2265444df72db
|
4
|
+
data.tar.gz: 594549370135b3237cbdfc2e701554eafa89c87fababd5b64e33476ed2ce11b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d40d26a27feb02d827068be43c3c93f44146cc7a2314047684bd7290cab34beee1e5930fd9d000922ad768fc00fcd7f544e530a85cf5267f7913a8f7e7f3fe4c
|
7
|
+
data.tar.gz: 7f2e1f146b3f5f466b1d3886b60e70ccc6505a919c7b8ef8c2a8498b2182b441a5695318b27e028f5f4943cdf39ea7f650ddc53370d475ea1385e5e4363dd48b
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
## Unreleased
|
2
2
|
|
3
|
+
## 0.5.1
|
4
|
+
|
5
|
+
- Improving interoperability with `computed_model`
|
6
|
+
- Simplify field mask normalizer and add `Pb::Serializer.parse_field_mask` method https://github.com/wantedly/pb-serializer/pull/40
|
7
|
+
- Stop defining accessor methods in `attribute` DSL if the method of the same name already existss https://github.com/wantedly/pb-serializer/pull/42
|
8
|
+
- Refactoring
|
9
|
+
- Extract Dsl and Hook from Serializable module https://github.com/wantedly/pb-serializer/pull/41
|
10
|
+
|
3
11
|
## 0.5.0
|
4
12
|
|
5
13
|
- Bump `computed_model` from 0.2.2 to 0.3.0 https://github.com/wantedly/pb-serializer/pull/38
|
data/lib/pb/serializable.rb
CHANGED
@@ -2,20 +2,20 @@ module Pb
|
|
2
2
|
module Serializable
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
include ComputedModel::Model
|
5
|
+
|
5
6
|
def self.included(base)
|
6
|
-
base.
|
7
|
-
base.
|
7
|
+
base.include Pb::Serializer::ComputedModelSupport
|
8
|
+
base.extend Pb::Serializer::Dsl
|
8
9
|
end
|
9
10
|
|
10
11
|
# @param with [
|
11
12
|
# Google::Protobuf::FieldMask,
|
12
13
|
# Array<(Symbol, Hash)>,
|
13
14
|
# Hash{Symbol=>(Array,Symbol,Hash)},
|
14
|
-
# Pb::Serializer::NormalizedMask
|
15
15
|
# ]
|
16
16
|
def to_pb(with: nil)
|
17
17
|
with ||= ::Pb::Serializer.build_default_mask(self.class.message_class.descriptor)
|
18
|
-
with = ::Pb::Serializer
|
18
|
+
with = ::Pb::Serializer.normalize_mask(with)
|
19
19
|
|
20
20
|
oneof_set = []
|
21
21
|
|
@@ -71,79 +71,7 @@ module Pb
|
|
71
71
|
o
|
72
72
|
end
|
73
73
|
|
74
|
-
private def primary_object
|
75
|
-
primary_object_name = self.class.__pb_serializer_primary_model_name
|
76
|
-
if primary_object_name
|
77
|
-
send(primary_object_name)
|
78
|
-
elsif kind_of?(Serializer::Base)
|
79
|
-
send(:object)
|
80
|
-
else
|
81
|
-
self
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
module Hook
|
86
|
-
def define_primary_loader(name)
|
87
|
-
self.__pb_serializer_primary_model_name = name
|
88
|
-
|
89
|
-
super
|
90
|
-
end
|
91
|
-
|
92
|
-
def computed(name)
|
93
|
-
__pb_serializer_attrs << name
|
94
|
-
|
95
|
-
super
|
96
|
-
end
|
97
|
-
|
98
|
-
def define_loader(name, **)
|
99
|
-
__pb_serializer_attrs << name
|
100
|
-
|
101
|
-
super
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
74
|
module ClassMethods
|
106
|
-
attr_reader :message_class
|
107
|
-
attr_accessor :__pb_serializer_primary_model_name
|
108
|
-
|
109
|
-
def message(klass)
|
110
|
-
@message_class = klass
|
111
|
-
end
|
112
|
-
|
113
|
-
# @param name [Symbol] An attribute name
|
114
|
-
# @param [Hash] opts options
|
115
|
-
# @option opts [Boolean] :allow_nil Set true if this attribute allow to be nil
|
116
|
-
# @option opts [Class] :serializer A serializer class for this attribute
|
117
|
-
# @option opts [String, Symbol, Proc] :if A method, proc or string to call to determine to serialize this field
|
118
|
-
def attribute(name, opts = {})
|
119
|
-
raise ::Pb::Serializer::MissingMessageTypeError, "message specificaiton is missed" unless message_class
|
120
|
-
|
121
|
-
fd = message_class.descriptor.find { |fd| fd.name.to_sym == name }
|
122
|
-
|
123
|
-
raise ::Pb::Serializer::UnknownFieldError, "#{name} is not defined in #{message_class.name}" unless fd
|
124
|
-
|
125
|
-
attr = ::Pb::Serializer::Attribute.new(
|
126
|
-
name: name,
|
127
|
-
options: opts,
|
128
|
-
field_descriptor: fd,
|
129
|
-
oneof: @current_oneof&.name,
|
130
|
-
)
|
131
|
-
|
132
|
-
@attr_by_name ||= {}
|
133
|
-
@attr_by_name[name] = attr
|
134
|
-
|
135
|
-
define_method attr.name do
|
136
|
-
primary_object.public_send(attr.name)
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
# @param names [Array<Symbol>] Attribute names to be ignored
|
141
|
-
def ignore(*names)
|
142
|
-
names.each do |name|
|
143
|
-
attribute name, ignore: true
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
75
|
# @param with [Array, Hash, Google::Protobuf::FieldMask, nil]
|
148
76
|
# @return [Array]
|
149
77
|
def bulk_load_and_serialize(with: nil, **args)
|
@@ -152,8 +80,8 @@ module Pb
|
|
152
80
|
|
153
81
|
def bulk_load(with: nil, **args)
|
154
82
|
with ||= ::Pb::Serializer.build_default_mask(message_class.descriptor)
|
155
|
-
with = ::Pb::Serializer
|
156
|
-
with = with
|
83
|
+
with = ::Pb::Serializer.normalize_mask(with)
|
84
|
+
with = __pb_serializer_filter_only_computed_model_attrs(with)
|
157
85
|
|
158
86
|
primary_object_name = __pb_serializer_primary_model_name
|
159
87
|
if primary_object_name
|
@@ -164,32 +92,6 @@ module Pb
|
|
164
92
|
|
165
93
|
bulk_load_and_compute(with, **args)
|
166
94
|
end
|
167
|
-
|
168
|
-
def oneof(name, allow_nil: false)
|
169
|
-
@oneof_by_name ||= {}
|
170
|
-
@current_oneof = ::Pb::Serializer::Oneof.new(
|
171
|
-
name: name,
|
172
|
-
allow_nil: allow_nil,
|
173
|
-
attributes: [],
|
174
|
-
)
|
175
|
-
yield
|
176
|
-
@oneof_by_name[name] = @current_oneof
|
177
|
-
@current_oneof = nil
|
178
|
-
end
|
179
|
-
|
180
|
-
private def __pb_serializer_attrs
|
181
|
-
@__pb_serializer_attrs ||= Set.new
|
182
|
-
end
|
183
|
-
|
184
|
-
# @param fd [Google::Protobuf::FieldDescriptor] a field descriptor
|
185
|
-
# @return [Pb::Serializer::Attribute, nil]
|
186
|
-
def find_attribute_by_field_descriptor(fd)
|
187
|
-
(@attr_by_name || {})[fd.name.to_sym]
|
188
|
-
end
|
189
|
-
|
190
|
-
def oneofs
|
191
|
-
@oneof_by_name&.values || []
|
192
|
-
end
|
193
95
|
end
|
194
96
|
end
|
195
97
|
end
|
data/lib/pb/serializer.rb
CHANGED
@@ -3,8 +3,9 @@ require "the_pb"
|
|
3
3
|
require "computed_model"
|
4
4
|
require "google/protobuf/field_mask_pb"
|
5
5
|
|
6
|
+
require "pb/serializer/dsl"
|
7
|
+
require "pb/serializer/computed_model_support"
|
6
8
|
require "pb/serializable"
|
7
|
-
require "pb/serializer/normalized_mask"
|
8
9
|
require "pb/serializer/base"
|
9
10
|
require "pb/serializer/attribute"
|
10
11
|
require "pb/serializer/oneof"
|
@@ -90,6 +91,46 @@ module Pb
|
|
90
91
|
end
|
91
92
|
set.to_a
|
92
93
|
end
|
94
|
+
|
95
|
+
# @param [Google::Protobuf::FieldMask]
|
96
|
+
# @return [Array]
|
97
|
+
def parse_field_mask(field_mask)
|
98
|
+
unless field_mask.kind_of?(Google::Protobuf::FieldMask)
|
99
|
+
raise ArgumentError, "expected Google::Protobuf::FieldMask, but got #{field_mask.class}"
|
100
|
+
end
|
101
|
+
|
102
|
+
field_mask.paths.map do |path|
|
103
|
+
path.split(".").reverse.inject(nil) { |h, key| h.nil? ? key.to_sym : { key.to_sym => [h].compact } }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# @param [Google::Protobuf::FieldMask, Symbol, Array<(Symbol,Hash)>, Hash{Symbol=>(Array,Symbol,Hash)}]
|
108
|
+
# @return [Hash{Symbol=>(Array,Hash)}]
|
109
|
+
def normalize_mask(input)
|
110
|
+
if input.kind_of?(Google::Protobuf::FieldMask)
|
111
|
+
input = parse_field_mask(input)
|
112
|
+
end
|
113
|
+
|
114
|
+
normalized = {}
|
115
|
+
|
116
|
+
input = [input] if input.kind_of?(Hash)
|
117
|
+
Array(input).each do |el|
|
118
|
+
case el
|
119
|
+
when Symbol
|
120
|
+
normalized[el] ||= []
|
121
|
+
when Hash
|
122
|
+
el.each do |k, v|
|
123
|
+
v = [v] if v.kind_of?(Hash)
|
124
|
+
normalized[k] ||= []
|
125
|
+
normalized[k].push(*Array(v))
|
126
|
+
end
|
127
|
+
else
|
128
|
+
raise "not supported field mask type: #{input.class}"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
normalized
|
133
|
+
end
|
93
134
|
end
|
94
135
|
end
|
95
136
|
end
|
@@ -54,7 +54,7 @@ module Pb
|
|
54
54
|
end
|
55
55
|
|
56
56
|
# @param v [Object]
|
57
|
-
# @param with [
|
57
|
+
# @param with [Hash, Array]
|
58
58
|
def convert_to_pb(v, with: nil, should_repeat: repeated?)
|
59
59
|
return nil if v.nil?
|
60
60
|
return v.map { |i| convert_to_pb(i, should_repeat: false, with: with) } if should_repeat
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Pb
|
2
|
+
module Serializer
|
3
|
+
module ComputedModelSupport
|
4
|
+
def self.included(base)
|
5
|
+
base.singleton_class.prepend Hook
|
6
|
+
end
|
7
|
+
|
8
|
+
private def primary_object
|
9
|
+
primary_object_name = self.class.__pb_serializer_primary_model_name
|
10
|
+
if primary_object_name
|
11
|
+
send(primary_object_name)
|
12
|
+
elsif kind_of?(Serializer::Base)
|
13
|
+
send(:object)
|
14
|
+
else
|
15
|
+
self
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module Hook
|
20
|
+
attr_accessor :__pb_serializer_primary_model_name
|
21
|
+
|
22
|
+
def define_primary_loader(name)
|
23
|
+
self.__pb_serializer_primary_model_name = name
|
24
|
+
|
25
|
+
super
|
26
|
+
end
|
27
|
+
|
28
|
+
def computed(name)
|
29
|
+
__pb_serializer_attrs << name
|
30
|
+
|
31
|
+
super
|
32
|
+
end
|
33
|
+
|
34
|
+
def define_loader(name, **)
|
35
|
+
__pb_serializer_attrs << name
|
36
|
+
|
37
|
+
super
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param with [Array]
|
41
|
+
private def __pb_serializer_filter_only_computed_model_attrs(with)
|
42
|
+
with.reject { |c| (__pb_serializer_attrs & (c.kind_of?(Hash) ? c.keys : [c])).empty? }
|
43
|
+
end
|
44
|
+
|
45
|
+
private def __pb_serializer_attrs
|
46
|
+
@__pb_serializer_attrs ||= Set.new
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Pb
|
2
|
+
module Serializer
|
3
|
+
module Dsl
|
4
|
+
def message(klass)
|
5
|
+
@message_class = klass
|
6
|
+
end
|
7
|
+
|
8
|
+
# @param name [Symbol] An attribute name
|
9
|
+
# @param [Hash] opts options
|
10
|
+
# @option opts [Boolean] :allow_nil Set true if this attribute allow to be nil
|
11
|
+
# @option opts [Class] :serializer A serializer class for this attribute
|
12
|
+
# @option opts [String, Symbol, Proc] :if A method, proc or string to call to determine to serialize this field
|
13
|
+
def attribute(name, opts = {})
|
14
|
+
raise ::Pb::Serializer::MissingMessageTypeError, "message specificaiton is missed" unless message_class
|
15
|
+
|
16
|
+
fd = message_class.descriptor.find { |fd| fd.name.to_sym == name }
|
17
|
+
|
18
|
+
raise ::Pb::Serializer::UnknownFieldError, "#{name} is not defined in #{message_class.name}" unless fd
|
19
|
+
|
20
|
+
attr = ::Pb::Serializer::Attribute.new(
|
21
|
+
name: name,
|
22
|
+
options: opts,
|
23
|
+
field_descriptor: fd,
|
24
|
+
oneof: @current_oneof&.name,
|
25
|
+
)
|
26
|
+
|
27
|
+
@attr_by_name ||= {}
|
28
|
+
@attr_by_name[name] = attr
|
29
|
+
|
30
|
+
unless method_defined?(attr.name)
|
31
|
+
define_method attr.name do
|
32
|
+
primary_object.public_send(attr.name)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# @param names [Array<Symbol>] Attribute names to be ignored
|
38
|
+
def ignore(*names)
|
39
|
+
names.each do |name|
|
40
|
+
attribute name, ignore: true
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def oneof(name, allow_nil: false)
|
45
|
+
@oneof_by_name ||= {}
|
46
|
+
@current_oneof = ::Pb::Serializer::Oneof.new(
|
47
|
+
name: name,
|
48
|
+
allow_nil: allow_nil,
|
49
|
+
attributes: [],
|
50
|
+
)
|
51
|
+
yield
|
52
|
+
@oneof_by_name[name] = @current_oneof
|
53
|
+
@current_oneof = nil
|
54
|
+
end
|
55
|
+
|
56
|
+
attr_reader :message_class
|
57
|
+
|
58
|
+
# @param fd [Google::Protobuf::FieldDescriptor] a field descriptor
|
59
|
+
# @return [Pb::Serializer::Attribute, nil]
|
60
|
+
def find_attribute_by_field_descriptor(fd)
|
61
|
+
(@attr_by_name || {})[fd.name.to_sym]
|
62
|
+
end
|
63
|
+
|
64
|
+
def oneofs
|
65
|
+
@oneof_by_name&.values || []
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pb-serializer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- izumin5210
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-07-
|
11
|
+
date: 2021-07-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: google-protobuf
|
@@ -210,7 +210,8 @@ files:
|
|
210
210
|
- lib/pb/serializer.rb
|
211
211
|
- lib/pb/serializer/attribute.rb
|
212
212
|
- lib/pb/serializer/base.rb
|
213
|
-
- lib/pb/serializer/
|
213
|
+
- lib/pb/serializer/computed_model_support.rb
|
214
|
+
- lib/pb/serializer/dsl.rb
|
214
215
|
- lib/pb/serializer/oneof.rb
|
215
216
|
- lib/pb/serializer/version.rb
|
216
217
|
- pb-serializer.gemspec
|
@@ -1,57 +0,0 @@
|
|
1
|
-
module Pb::Serializer
|
2
|
-
class NormalizedMask < ::Hash
|
3
|
-
class << self
|
4
|
-
# @param [Google::Protobuf::FieldMask, Symbol, Array<(Symbol,Hash)>, Hash{Symbol=>(Array,Symbol,Hash)}]
|
5
|
-
# @return [Hash{Symbol=>Hash}]
|
6
|
-
def build(input)
|
7
|
-
return input if input.kind_of? self
|
8
|
-
|
9
|
-
normalized = new
|
10
|
-
|
11
|
-
case input
|
12
|
-
when Google::Protobuf::FieldMask
|
13
|
-
normalized = normalize_mask_paths(input.paths)
|
14
|
-
when Array
|
15
|
-
input.each do |v|
|
16
|
-
deep_merge!(normalized, build(v))
|
17
|
-
end
|
18
|
-
when Hash
|
19
|
-
input.each do |k, v|
|
20
|
-
normalized[k] ||= new
|
21
|
-
deep_merge!(normalized[k], build(v))
|
22
|
-
end
|
23
|
-
when Symbol
|
24
|
-
normalized[input] ||= new
|
25
|
-
else
|
26
|
-
raise "not supported field mask type: #{input.class}"
|
27
|
-
end
|
28
|
-
|
29
|
-
normalized
|
30
|
-
end
|
31
|
-
|
32
|
-
private
|
33
|
-
|
34
|
-
# @param [Array<String>]
|
35
|
-
# @return [Hash{Symbol=>Hash}]
|
36
|
-
def normalize_mask_paths(paths)
|
37
|
-
paths_by_key = {}
|
38
|
-
|
39
|
-
paths.each do |path|
|
40
|
-
key, rest = path.split('.', 2)
|
41
|
-
paths_by_key[key.to_sym] ||= []
|
42
|
-
paths_by_key[key.to_sym].push(rest) if rest && !rest.empty?
|
43
|
-
end
|
44
|
-
|
45
|
-
paths_by_key.keys.each_with_object(new) do |key, normalized|
|
46
|
-
normalized[key] = normalize_mask_paths(paths_by_key[key])
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def deep_merge!(h1, h2)
|
51
|
-
h1.merge!(h2) do |_k, v1, v2|
|
52
|
-
deep_merge!(v1, v2)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|