【问题标题】:Getting enum values from compiled protobuffer message in Ruby从Ruby中编译的protobuf消息中获取枚举值
【发布时间】:2018-10-14 09:30:46
【问题描述】:

我有一个像这样编译的 Ruby protobuf 消息:

  require 'google/protobuf'

  Google::Protobuf::DescriptorPool.generated_pool.build do
    add_message "PingPacket" do
      optional :message_counter, :int32, 1
      optional :message_type, :enum, 2, "PingPacket.MessageType"
    end
    add_enum "PingPacket.MessageType" do
      value :REPORT, 0
      value :LOW_BATTERY, 1
      value :LOCATE_REQUEST, 2
      value :CHECK_IN, 3
      value :SOS, 4
      value :RESTING, 5
      value :MOVING, 6
      value :EVENT, 7
      value :SYSTEM_TEST, 8
    end
  end

  PingPacket = Google::Protobuf::DescriptorPool.generated_pool.lookup("PingPacket").msgclass
  PingPacket::MessageType = Google::Protobuf::DescriptorPool.generated_pool.lookup("PingPacket.MessageType").enummodule

我试图获取一个包含所有 MessageType 值的数组。我已经尝试了明显的:

PingPacket::MessageType.enums
PingPacket::MessageType.values
PingPacket::MessageType.to_s

但是没有任何效果。我怎样才能得到这些值?

【问题讨论】:

    标签: ruby protocol-buffers


    【解决方案1】:

    我喜欢用 Pry 检查东西,如果我在 pry 控制台中加载代码,我会得到:

    1) 你的类是一个模块

    [2] pry(main)> PingPacket::MessageType.class
    => Module
    

    如果我进入课堂,我会得到:

    [4] pry(main)> cd PingPacket::MessageType
    [5] pry(PingPacket::MessageType):1> ls
    constants: 
      CHECK_IN  LOCATE_REQUEST  MOVING  RESTING  SYSTEM_TEST
      EVENT     LOW_BATTERY     REPORT  SOS    
    PingPacket::MessageType.methods: descriptor  lookup  resolve
    locals: _  __  _dir_  _ex_  _file_  _in_  _out_  _pry_
    

    然后我可以检查所有常量:

    [6] pry(PingPacket::MessageType):1> constants
    => [:CHECK_IN,
     :SOS,
     :RESTING,
     :MOVING,
     :EVENT,
     :SYSTEM_TEST,
     :REPORT,
     :LOW_BATTERY,
     :LOCATE_REQUEST]
    

    我终于可以通过这个技巧将常量值组成一个模块:

    [9] pry(PingPacket::MessageType):1> constants(false).map &method(:const_get)
    => [3, 4, 5, 6, 7, 8, 0, 1, 2]
    

    这样就可以了

    [12] pry(main)> PingPacket::MessageType.constants(false).map &PingPacket::MessageType.method(:const_get)
    => [3, 4, 5, 6, 7, 8, 0, 1, 2]
    

    你也可以看到它有三种方法,工作如下:

    [31] pry(PingPacket::MessageType):1> resolve :CHECK_IN
    => 3
    [33] pry(PingPacket::MessageType):1> lookup 3
    => :CHECK_IN
    [37] pry(PingPacket::MessageType):1> descriptor.each do |i|
    [37] pry(PingPacket::MessageType):1* puts i
    [37] pry(PingPacket::MessageType):1* end
    LOCATE_REQUEST
    SOS
    SYSTEM_TEST
    LOW_BATTERY
    EVENT
    CHECK_IN
    RESTING
    MOVING
    REPORT
    => nil
    

    例如检查这个:

    [42] pry(PingPacket::MessageType):1> descriptor.each do |i|
    [42] pry(PingPacket::MessageType):1* puts resolve i
    [42] pry(PingPacket::MessageType):1* end
    2
    4
    8
    1
    7
    3
    5
    6
    0
    => nil
    

    最后结合在一起,让我们把所有的键和值放在一个哈希中

    [54] pry(main)> Hash[PingPacket::MessageType.descriptor.collect do |i| [i, PingPacket::MessageType.resolve(i)] end]
    => {:LOCATE_REQUEST=>2,
     :SOS=>4,
     :SYSTEM_TEST=>8,
     :LOW_BATTERY=>1,
     :EVENT=>7,
     :CHECK_IN=>3,
     :RESTING=>5,
     :MOVING=>6,
     :REPORT=>0}
    

    【讨论】:

      【解决方案2】:

      对于那些对按枚举值排序的枚举感兴趣的人:

      PingPacket::MessageType.constants.map(&PingPacket::MessageType.method(:const_get)).collect do |i| [PingPacket::MessageType.lookup(i),i]; end.to_h
      

      我知道它有点冗长,如果有人能想出一些更简洁的东西,我肯定会喜欢它。

      为了完整起见 - 对于那些有兴趣按枚举名称按字母顺序排序的人:

      Hash[PingPacket::MessageType.descriptor.collect do |i| [i, PingPacket::MessageType.resolve(i)] end].sort
      

      【讨论】:

        猜你喜欢
        • 2021-04-29
        • 2013-04-07
        • 1970-01-01
        • 2016-07-27
        • 2010-11-01
        • 2016-12-22
        • 2012-12-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多