pb-serializer 0.5.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|