Skip to content

Commit 757068b

Browse files
committed
Merge pull request #302 from nerdrew/fix-setters-and-getters
Clean up dynamic code generation in prep for extension namespacing
2 parents dee8a9d + 154fbad commit 757068b

14 files changed

Lines changed: 279 additions & 187 deletions

.rubocop_todo.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Metrics/BlockNesting:
1616

1717
# Offense count: 6
1818
Metrics/CyclomaticComplexity:
19-
Max: 10
19+
Max: 12
2020

2121
# Offense count: 493
2222
# Configuration parameters: AllowURI, URISchemes.
@@ -31,11 +31,11 @@ Metrics/MethodLength:
3131
# Offense count: 2
3232
# Configuration parameters: CountKeywordArgs.
3333
Metrics/ParameterLists:
34-
Max: 6
34+
Max: 7
3535

3636
# Offense count: 6
3737
Metrics/PerceivedComplexity:
38-
Max: 11
38+
Max: 17
3939

4040
# Offense count: 1
4141
# Cop supports --auto-correct.

lib/protobuf/field.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ module Field
4141
:bool => ::Protobuf::Field::BoolField,
4242
}.freeze
4343

44-
def self.build(message_class, rule, type, name, tag, options = {})
45-
field_class(type).new(message_class, rule, field_type(type), name, tag, options)
44+
def self.build(message_class, rule, type, name, tag, simple_name, options = {})
45+
field_class(type).new(message_class, rule, field_type(type), name, tag, simple_name, options)
4646
end
4747

4848
# Returns the field class for primitives,

lib/protobuf/field/base_field.rb

Lines changed: 20 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def self.default
3535
# Constructor
3636
#
3737

38-
def initialize(message_class, rule, type_class, name, tag, options)
38+
def initialize(message_class, rule, type_class, name, tag, simple_name, options)
3939
@message_class = message_class
4040
@name = name
4141
@rule = rule
@@ -44,7 +44,7 @@ def initialize(message_class, rule, type_class, name, tag, options)
4444
@options = options
4545

4646
validate_packed_field if packed?
47-
define_accessor
47+
define_accessor(simple_name, name) if simple_name
4848
tag_encoded
4949
end
5050

@@ -69,10 +69,12 @@ def default
6969
end
7070

7171
def default_value
72-
@default_value ||= case
73-
when optional? then typed_default_value
74-
when repeated? then ::Protobuf::Field::FieldArray.new(self).freeze
75-
when required? then nil
72+
@default_value ||= if optional? || required?
73+
typed_default_value
74+
elsif repeated?
75+
::Protobuf::Field::FieldArray.new(self).freeze
76+
else
77+
fail "Unknown field label -- something went very wrong"
7678
end
7779
end
7880

@@ -122,10 +124,10 @@ def required?
122124

123125
# FIXME: need to cleanup (rename) this warthog of a method.
124126
def set(message_instance, bytes)
125-
return message_instance.__send__(setter, decode(bytes)) unless repeated?
126-
return message_instance.__send__(getter) << decode(bytes) unless packed?
127+
return message_instance[name] = decode(bytes) unless repeated?
128+
return message_instance[name] << decode(bytes) unless packed?
127129

128-
array = message_instance.__send__(getter)
130+
array = message_instance[name]
129131
stream = StringIO.new(bytes)
130132

131133
if wire_type == ::Protobuf::WireType::VARINT
@@ -169,87 +171,23 @@ def wire_type
169171
# Private Instance Methods
170172
#
171173

172-
def define_accessor
173-
if repeated?
174-
define_array_getter
175-
define_array_setter
176-
else
177-
define_getter
178-
define_setter
179-
end
180-
end
181-
182-
def define_array_getter
183-
field = self
184-
method_name = field.getter
185-
174+
def define_accessor(simple_field_name, fully_qualified_field_name)
186175
message_class.class_eval do
187-
define_method(method_name) do
188-
@values[field.name] ||= ::Protobuf::Field::FieldArray.new(field)
176+
define_method("#{simple_field_name}!") do
177+
@values[fully_qualified_field_name]
189178
end
190179
end
191180

192-
::Protobuf.field_deprecator.deprecate_method(message_class, method_name) if field.deprecated?
193-
end
194-
195-
def define_array_setter
196-
field = self
197-
method_name = field.setter
198-
199181
message_class.class_eval do
200-
define_method(method_name) do |val|
201-
if val.is_a?(Array)
202-
val = val.dup
203-
val.compact!
204-
else
205-
fail TypeError, <<-TYPE_ERROR
206-
Expected repeated value of type '#{field.type_class}'
207-
Got '#{val.class}' for repeated protobuf field #{field.name}
208-
TYPE_ERROR
209-
end
210-
211-
if val.nil? || (val.respond_to?(:empty?) && val.empty?)
212-
@values.delete(field.name)
213-
else
214-
@values[field.name] ||= ::Protobuf::Field::FieldArray.new(field)
215-
@values[field.name].replace(val)
216-
end
217-
end
182+
define_method(simple_field_name) { self[fully_qualified_field_name] }
183+
define_method("#{simple_field_name}=") { |v| self[fully_qualified_field_name] = v }
218184
end
219185

220-
::Protobuf.field_deprecator.deprecate_method(message_class, method_name) if field.deprecated?
221-
end
222-
223-
def define_getter
224-
field = self
225-
method_name = field.getter
226-
227-
message_class.class_eval do
228-
define_method(method_name) do
229-
@values[field.name] || field.default_value
230-
end
231-
end
232-
233-
::Protobuf.field_deprecator.deprecate_method(message_class, method_name) if field.deprecated?
234-
end
235-
236-
def define_setter
237-
field = self
238-
method_name = field.setter
239-
240-
message_class.class_eval do
241-
define_method(method_name) do |val|
242-
if val.nil? || (val.respond_to?(:empty?) && val.empty?)
243-
@values.delete(field.name)
244-
elsif field.acceptable?(val)
245-
@values[field.name] = field.coerce!(val)
246-
else
247-
fail TypeError, "Unacceptable value #{val} for field #{field.name} of type #{field.type_class}"
248-
end
249-
end
250-
end
186+
return unless deprecated?
251187

252-
::Protobuf.field_deprecator.deprecate_method(message_class, method_name) if field.deprecated?
188+
::Protobuf.field_deprecator.deprecate_method(message_class, simple_field_name)
189+
::Protobuf.field_deprecator.deprecate_method(message_class, "#{simple_field_name}!")
190+
::Protobuf.field_deprecator.deprecate_method(message_class, "#{simple_field_name}=")
253191
end
254192

255193
def typed_default_value

lib/protobuf/field/bool_field.rb

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,21 +45,11 @@ def encode(value)
4545
# Private Instance Methods
4646
#
4747

48-
def define_getter
49-
field = self
50-
method_name = field.getter
51-
48+
def define_accessor(simple_field_name, _fully_qualified_field_name)
49+
super
5250
message_class.class_eval do
53-
define_method(method_name) do
54-
@values.fetch(field.name, field.default_value)
55-
end
51+
alias_method "#{simple_field_name}?", simple_field_name
5652
end
57-
58-
message_class.class_eval do
59-
alias_method "#{method_name}?", method_name
60-
end
61-
62-
::Protobuf.field_deprecator.deprecate_method(message_class, method_name) if field.deprecated?
6353
end
6454

6555
end

lib/protobuf/field/bytes_field.rb

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ def decode(bytes)
3333
end
3434

3535
def encode(value)
36-
value_to_encode = ""
3736
if value.is_a?(::Protobuf::Message)
3837
value_to_encode = value.encode
3938
else
@@ -50,32 +49,17 @@ def wire_type
5049
::Protobuf::WireType::LENGTH_DELIMITED
5150
end
5251

53-
private
54-
55-
##
56-
# Private Instance Methods
57-
#
58-
59-
def define_setter
60-
field = self
61-
method_name = field.setter
62-
63-
message_class.class_eval do
64-
define_method(method_name) do |val|
65-
case val
66-
when String, Symbol
67-
@values[field.name] = "#{val}"
68-
when NilClass
69-
@values.delete(field.name)
70-
when ::Protobuf::Message
71-
@values[field.name] = val.dup
72-
else
73-
fail TypeError, "Unacceptable value #{val} for field #{field.name} of type #{field.type_class}"
74-
end
75-
end
52+
def coerce!(value)
53+
case value
54+
when String, Symbol
55+
"#{value}"
56+
when NilClass
57+
nil
58+
when ::Protobuf::Message
59+
value.dup
60+
else
61+
fail TypeError, "Unacceptable value #{value} for field #{name} of type #{type_class}"
7662
end
77-
78-
::Protobuf.field_deprecator.deprecate_method(message_class, method_name) if field.deprecated?
7963
end
8064
end
8165
end

lib/protobuf/field/enum_field.rb

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,29 +32,18 @@ def enum?
3232
true
3333
end
3434

35+
def coerce!(value)
36+
enum_value = type_class.fetch(value)
37+
fail TypeError, "Invalid Enum value: #{value.inspect} for #{name}" unless enum_value
38+
enum_value
39+
end
40+
3541
private
3642

3743
##
3844
# Private Instance Methods
3945
#
4046

41-
def define_setter
42-
field = self
43-
message_class.class_eval do
44-
define_method("#{field.name}=") do |value|
45-
orig_value = value
46-
if value.nil?
47-
@values.delete(field.name)
48-
else
49-
value = field.type_class.fetch(value)
50-
fail TypeError, "Invalid Enum value: #{orig_value.inspect} for #{field.name}" unless value
51-
52-
@values[field.name] = value
53-
end
54-
end
55-
end
56-
end
57-
5847
def typed_default_value
5948
if default.is_a?(Symbol)
6049
type_class.const_get(default)

lib/protobuf/field/message_field.rb

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,29 +30,17 @@ def wire_type
3030
::Protobuf::WireType::LENGTH_DELIMITED
3131
end
3232

33-
private
34-
35-
##
36-
# Private Instance Methods
37-
#
38-
39-
def define_setter
40-
field = self
41-
message_class.class_eval do
42-
define_method("#{field.name}=") do |val|
43-
case
44-
when val.nil?
45-
@values.delete(field.name)
46-
when val.is_a?(field.type_class)
47-
@values[field.name] = val
48-
when val.respond_to?(:to_proto)
49-
@values[field.name] = val.to_proto
50-
when val.respond_to?(:to_hash)
51-
@values[field.name] = field.type_class.new(val.to_hash)
52-
else
53-
fail TypeError, "Expected value of type '#{field.type_class}' for field #{field.name}, but got '#{val.class}'"
54-
end
55-
end
33+
def coerce!(value)
34+
if value.nil?
35+
nil
36+
elsif value.is_a?(type_class)
37+
value
38+
elsif value.respond_to?(:to_proto)
39+
value.to_proto
40+
elsif value.respond_to?(:to_hash)
41+
type_class.new(value.to_hash)
42+
else
43+
fail TypeError, "Expected value of type '#{type_class}' for field #{name}, but got '#{value.class}'"
5644
end
5745
end
5846

0 commit comments

Comments
 (0)