从已编译的Ruby Protobuffer消息中获取枚举值

5

我有一个已编译的 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

但是什么都没用。我该如何获取这些值?
3个回答

5
我喜欢用Pry来检查代码,在Pry控制台中加载代码后,我会得到以下信息:

1) 您的类是一个模块(Module)

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

1

对于那些希望按枚举值顺序排列的人:

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

0
PingPacket::MessageType.descriptor.to_h { |const, value| [const, value] }

应该输出
{:LOCATE_REQUEST=>2,
 :SOS=>4,
 :SYSTEM_TEST=>8,
 :LOW_BATTERY=>1,
 :EVENT=>7,
 :CHECK_IN=>3,
 :RESTING=>5,
 :MOVING=>6,
 :REPORT=>0}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接