require 'json' require 'protocol_buffers' require 'protocol_buffers/compiler' class ProtocolBuffers::Message def to_json(*args) json = to_json_ready_object() json.to_json(*args) end def to_json_ready_object() hash = {} # simpler version, includes all fields in the output, using the default # values if unset. also includes empty repeated fields as empty arrays. # fields.each do |tag, field| # hash[field.name] = value_for_tag(field.tag) # end # prettier output, only includes non-empty repeated fields and set fields fields.each do |tag, field| if field.repeated? value = value_for_tag(field.tag) hash[field.name] = value unless value.empty? else if value_for_tag?(field.tag) value = value_for_tag(field.tag) if field.instance_of? ProtocolBuffers::Field::EnumField # if value is enum, resolve string value as ruby const hash[field.name] = field.value_to_name[value] else proxy_class = field.instance_variable_get(:@proxy_class) if proxy_class.nil? hash[field.name] = value else hash[field.name] = value.to_json_ready_object end end end end end return hash end def self.json_create(hash) # initialize takes a hash of { attribute_name => value } so you can just # pass the hash into the constructor. but we're supposed to be showing off # reflection, here. plus, that raises an exception if there is an unknown # key in the hash. # new(hash) message = new fields.each do |tag, field| if value = hash[field.name.to_s] if value.instance_of? Hash # if the value is a Hash, descend down into PB hierachy inner_class = field.instance_variable_get(:@proxy_class) value = inner_class.json_create(value) message.set_value_for_tag(field.tag, value) elsif field.instance_of? ProtocolBuffers::Field::EnumField # if value is enum, resolve string value as ruby const message.set_value_for_tag(field.tag, field.instance_variable_get(:@proxy_enum).const_get(value)) else message.set_value_for_tag(field.tag, value) end end end message end end