lib/google/ads/google_ads/autoboxing_fields.rb in google-ads-googleads-2.4.1 vs lib/google/ads/google_ads/autoboxing_fields.rb in google-ads-googleads-3.0.0

- old
+ new

@@ -1,90 +1,96 @@ -require 'google/protobuf/message_exts' -require 'google/protobuf/wrappers_pb' +require 'google/ads/google_ads/autoboxing_mappings' + module Google module Ads module GoogleAds module AutoboxingFields - MAPPINGS = { - Google::Protobuf::Int32Value => lambda { |x| Integer(x) }, - Google::Protobuf::Int64Value => lambda { |x| Integer(x) }, - Google::Protobuf::StringValue => lambda { |x| String(x) }, - Google::Protobuf::BoolValue => lambda { |x| - case x - when TrueClass, true, "true", "TRUE", "True", "1", 1 - true - when FalseClass, false, "false", "FALSE", "False", "0", 0 - false - else - raise ArgumentError.new("Value #{x} is not boolish") - end - }, - Google::Protobuf::DoubleValue => lambda { |x| Float(x) }, - Google::Protobuf::BytesValue => lambda { |x| x.force_encoding("ASCII-8BIT") }, - } - def self.patch_class(klass) return if klass.instance_variable_get(:@_patched_for_autoboxing_fields) klass.instance_variable_set(:@_patched_for_autoboxing_fields, true) klass.instance_eval do fields = [] + repeated_fields = [] + descriptor.each do |field| if field.type == :message && AutoboxingFields.is_value_field?(field.subtype.msgclass) - fields << field - AutoboxingFields.patch_field_for_autoboxing(field, self) + repeated = field.label == :repeated + if repeated + repeated_fields << field + else + fields << field + end + + AutoboxingFields.patch_field_for_autoboxing(field, repeated, self) end end - AutoboxingFields.patch_constructor_for_autoboxing(fields, self) + AutoboxingFields.patch_constructor_for_autoboxing(fields, repeated_fields, self) end end def self.is_value_field?(class_name) - MAPPINGS.keys.include?(class_name) + AutoboxingMappings.has_type?(class_name) end - def self.patch_constructor_for_autoboxing(fields, klass_to_patch) + def self.patch_constructor_for_autoboxing(fields, repeated_fields, klass_to_patch) orig_initialize = klass_to_patch.instance_method(:initialize) klass_to_patch.instance_eval do define_method(:initialize) do |**kwargs| - new_kwargs = Hash[kwargs.map { |name, value| - field = fields.select { |x| x.name == name.to_s }.first - actual_value = if field - if field.subtype.msgclass === value - value - else - field.subtype.msgclass.new(value: MAPPINGS.fetch(field.subtype.msgclass).call(value)) - end - else - value - end - [name, actual_value] - }] + new_kwargs = kwargs.dup + fields.select { |x| new_kwargs.include?(x.name.to_sym) }.each do |field| + value = new_kwargs.fetch(field.name.to_sym) + new_kwargs[field.name.to_sym] = AutoboxingMappings.wrapped_mapping(field.subtype.msgclass).call(value) + end + + repeated_fields.select { |x| new_kwargs.include?(x.name.to_sym) }.each do |field| + value = new_kwargs.fetch(field.name.to_sym) + mapping = AutoboxingMappings.wrapped_mapping(field.subtype.msgclass) + new_kwargs[field.name.to_sym] = value.map { |x| mapping.call(x) } + end + orig_initialize.bind(self).call(**new_kwargs) end end end - def self.patch_field_for_autoboxing(field, klass_to_patch) + def self.patch_field_for_autoboxing(field, repeated, klass_to_patch) name = field.name - field_klass = field.subtype.msgclass - mapping = MAPPINGS.fetch(field_klass) + mapping = AutoboxingMappings.wrapped_mapping(field.subtype.msgclass) - klass_to_patch.instance_eval do - define_method("#{name}=".to_sym) do |value| - if value.nil? - send(:method_missing, :"#{name}=", value) - elsif field_klass === value - send(:method_missing, :"#{name}=", value) - else - send(:method_missing, :"#{name}=", field_klass.new(value: mapping.call(value))) + if repeated + klass_to_patch.instance_eval do + define_method(name.to_sym) do + @patched_repeated_fields ||= {} + @patched_repeated_fields[name] ||= RepeatedFieldProxy.new( + send(:method_missing, name.to_sym), + mapping, + ) + @patched_repeated_fields[name] end end + else + klass_to_patch.instance_eval do + define_method("#{name}=".to_sym) do |value| + send(:method_missing, :"#{name}=", mapping.call(value)) + end + end end end end end + end +end + +class RepeatedFieldProxy < SimpleDelegator + def initialize(collection, mapping) + super(collection) + @mapping = mapping + end + + def <<(value) + super(@mapping.call(value)) end end module Google::Protobuf module MessageExts