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 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