从Ruby中编译的protobuf消息中获取枚举值
Posted
技术标签:
【中文标题】从Ruby中编译的protobuf消息中获取枚举值【英文标题】:Getting enum values from compiled protobuffer message in Ruby 【发布时间】: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
但是没有任何效果。我怎样才能得到这些值?
【问题讨论】:
【参考方案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
【讨论】:
以上是关于从Ruby中编译的protobuf消息中获取枚举值的主要内容,如果未能解决你的问题,请参考以下文章