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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b46a686595d5e9e919c21ff7e6902cec71be97d716085dc38b8b2ef0192e7cf1
4
- data.tar.gz: c453986c407e5e567bce43f3f45429697c552dedc44356ffee2a8e0b4d5eaea7
3
+ metadata.gz: db5867da46505d0facc08d12c1d6a3c93a87d7ca617110e8a9f2265444df72db
4
+ data.tar.gz: 594549370135b3237cbdfc2e701554eafa89c87fababd5b64e33476ed2ce11b2
5
5
  SHA512:
6
- metadata.gz: c58c5ab0714bd7bee52f3f30ede95b676b849cdf0be482a9de0187287d3ecfd0e758b6cc7c17831965d7e8e54fc13763c6290607330077c3a2135c6fe9cfd439
7
- data.tar.gz: 7b3cc2224f7550c72714cc21c1e656182891788b1f0aa67b02dce177ea44cb6dfef5115073aeb08eb130fe40decc15551e73bbb2aa6ec77c0fc997e8fbf3477f
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
@@ -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.extend ClassMethods
7
- base.singleton_class.prepend Hook
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::NormalizedMask.build(with)
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::NormalizedMask.build(with)
156
- with = with.reject { |c| (__pb_serializer_attrs & (c.kind_of?(Hash) ? c.keys : [c])).empty? }
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 [Pb::Serializer::NormalizedMask]
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
@@ -1,5 +1,5 @@
1
1
  module Pb
2
2
  module Serializer
3
- VERSION = "0.5.0".freeze
3
+ VERSION = "0.5.1".freeze
4
4
  end
5
5
  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.0
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-07 00:00:00.000000000 Z
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/normalized_mask.rb
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