protobuf 2.0.0.rc2 → 2.0.0.rc3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. data/.gitignore +1 -0
  2. data/ext/ruby_generator/Makefile +10 -0
  3. data/ext/ruby_generator/RubyGenerator.cpp +85 -70
  4. data/ext/ruby_generator/RubyGenerator.h +23 -4
  5. data/lib/protobuf.rb +33 -26
  6. data/lib/protobuf/cli.rb +18 -13
  7. data/lib/protobuf/enum.rb +39 -34
  8. data/lib/protobuf/enum_value.rb +29 -0
  9. data/lib/protobuf/field/base_field.rb +34 -5
  10. data/lib/protobuf/field/enum_field.rb +6 -14
  11. data/lib/protobuf/field/extension_fields.rb +13 -5
  12. data/lib/protobuf/field/field_array.rb +17 -7
  13. data/lib/protobuf/field/varint_field.rb +4 -6
  14. data/lib/protobuf/message.rb +44 -148
  15. data/lib/protobuf/rpc/server.rb +2 -2
  16. data/lib/protobuf/version.rb +1 -1
  17. data/spec/benchmark/tasks.rb +7 -8
  18. data/spec/functional/evented_server_spec.rb +9 -9
  19. data/spec/functional/socket_server_spec.rb +8 -8
  20. data/spec/functional/zmq_server_spec.rb +8 -8
  21. data/spec/lib/protobuf/cli_spec.rb +30 -11
  22. data/spec/lib/protobuf/enum_spec.rb +90 -0
  23. data/spec/lib/protobuf/enum_value_spec.rb +13 -0
  24. data/spec/lib/protobuf/message/encoder_spec.rb +1 -1
  25. data/spec/lib/protobuf/message_spec.rb +50 -0
  26. data/spec/lib/protobuf/rpc/client_spec.rb +23 -23
  27. data/spec/lib/protobuf/rpc/servers/evented_server_spec.rb +1 -1
  28. data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +1 -1
  29. data/spec/lib/protobuf/rpc/service_spec.rb +18 -18
  30. data/spec/lib/protobuf_spec.rb +62 -0
  31. data/spec/spec_helper.rb +12 -1
  32. data/spec/support/all.rb +0 -1
  33. data/spec/support/server.rb +1 -1
  34. data/spec/support/test/enum.pb.rb +32 -0
  35. data/spec/support/test/enum.proto +12 -0
  36. data/spec/support/test/resource.pb.rb +52 -0
  37. data/spec/{proto/test.proto → support/test/resource.proto} +2 -2
  38. data/spec/support/test/resource_service.rb +14 -0
  39. metadata +51 -48
  40. data/ext/Makefile +0 -11
  41. data/spec/lib/protobuf/message/enum_spec.rb +0 -13
  42. data/spec/lib/protobuf/message/message_spec.rb +0 -67
  43. data/spec/proto/test.pb.rb +0 -54
  44. data/spec/proto/test_service.rb +0 -30
  45. data/spec/proto/test_service_impl.rb +0 -18
  46. data/spec/support/silent_constants.rb +0 -44
data/lib/protobuf/enum.rb CHANGED
@@ -1,52 +1,57 @@
1
- require 'delegate'
1
+ require 'protobuf/enum_value'
2
2
 
3
3
  module Protobuf
4
4
  class Enum
5
- class << self
6
- attr_reader :values
7
-
8
- def name_by_value(value)
9
- if not defined?(@values)
10
- constants.find {|c| const_get(c) == value} # for compatibility
11
- else
12
- @values_index ||= @values.inject({}) {|hash, (n, v)| hash[v.value] = n; hash }
13
- @values_index[value]
14
- end
15
- end
16
5
 
17
- alias get_name_by_tag name_by_value
6
+ def self.define(name, value)
7
+ enum_value = ::Protobuf::EnumValue.new(self, name, value)
8
+ const_set(name, enum_value)
9
+ @values ||= {}
10
+ @names ||= []
11
+ @values[name] = enum_value
12
+ @names[value] = name
13
+ end
18
14
 
19
- def valid_tag?(tag)
20
- !! name_by_value(tag)
15
+ # Fetch the given enum by a variety of type-checking
16
+ # mechanisms. This is useful for the enum field setters
17
+ # as well as repeated enum field construction.
18
+ def self.fetch(value)
19
+ if value.is_a?(::Protobuf::EnumValue)
20
+ value
21
+ elsif value.respond_to?(:to_sym)
22
+ value_by_name(value.to_sym) rescue nil
23
+ elsif value.respond_to?(:to_i)
24
+ enum_by_value(value.to_i) rescue nil
25
+ else
26
+ nil
21
27
  end
28
+ end
22
29
 
23
- def define(name, value)
24
- enum_value = EnumValue.new(self, name, value)
25
- const_set(name, enum_value)
26
- @values ||= {}
27
- @values[name] = enum_value
28
- end
30
+ def self.enum_by_value(value)
31
+ value_by_name(name_by_value(value))
29
32
  end
30
- end
31
33
 
32
- class EnumValue < SimpleDelegator
34
+ def self.name_by_value(value)
35
+ @names[value]
36
+ end
33
37
 
34
- attr_reader :parent_class, :name, :value
38
+ def self.valid_tag?(tag)
39
+ !! name_by_value(tag)
40
+ end
35
41
 
36
- def initialize(parent_class, name, value)
37
- @parent_class = parent_class
38
- @name = name
39
- @value = value
40
- super(@value)
42
+ def self.value_by_name(name)
43
+ @values[name]
41
44
  end
42
45
 
43
- def to_s
44
- @name.to_s
46
+ def self.values
47
+ @values
45
48
  end
46
49
 
47
- def inspect
48
- "\#<#{self.class} #{@parent_class}::#{@name}=#{@value}>"
50
+ ##
51
+ # Class Aliases
52
+ #
53
+ class << self
54
+ alias_method :get_name_by_tag, :name_by_value
49
55
  end
50
56
  end
51
-
52
57
  end
@@ -0,0 +1,29 @@
1
+ require 'delegate'
2
+ require 'protobuf/enum'
3
+
4
+ module Protobuf
5
+ class EnumValue < SimpleDelegator
6
+
7
+ attr_reader :parent_class, :name, :value
8
+
9
+ def initialize(parent_class, name, value)
10
+ @parent_class = parent_class
11
+ @name = name
12
+ @value = value
13
+ super(@value)
14
+ end
15
+
16
+ def inspect
17
+ "\#<#{self.class} #{@parent_class}::#{@name}=#{@value}>"
18
+ end
19
+
20
+ def to_hash_value
21
+ self.to_i
22
+ end
23
+
24
+ def to_s
25
+ @name.to_s
26
+ end
27
+ end
28
+ end
29
+
@@ -8,7 +8,7 @@ module Protobuf
8
8
  # Attributes
9
9
  #
10
10
  attr_reader :message_class, :rule, :type, :name, :tag, :default, :default_value, :setter_method_name, :getter_method_name
11
-
11
+
12
12
  ##
13
13
  # Class Methods
14
14
  #
@@ -28,6 +28,7 @@ module Protobuf
28
28
  @default = options.delete(:default)
29
29
  @extension = options.delete(:extension)
30
30
  @packed = repeated? && options.delete(:packed)
31
+ @deprecated = options.delete(:deprecated)
31
32
  unless options.empty?
32
33
  warn "WARNING: Invalid options: #{options.inspect} (in #{@message_class.name.split('::').last}.#{@name})"
33
34
  end
@@ -134,9 +135,14 @@ module Protobuf
134
135
  @_optional = (@rule == :optional)
135
136
  end
136
137
 
138
+ # Is this a deprecated field?
139
+ def deprecated?
140
+ !! @deprecated
141
+ end
142
+
137
143
  # Is this a packed repeated field?
138
144
  def packed?
139
- !!@packed
145
+ !! @packed
140
146
  end
141
147
 
142
148
  # Upper limit for this field.
@@ -153,24 +159,42 @@ module Protobuf
153
159
  "#{@rule} #{@type} #{@name} = #{@tag} #{@default ? "[default=#{@default.inspect}]" : ''}"
154
160
  end
155
161
 
162
+ def warn_if_deprecated
163
+ if ::Protobuf.print_deprecation_warnings? && deprecated?
164
+ $stderr.puts("[WARNING] #{@message_class.name}##{@name} field usage is deprecated.")
165
+ end
166
+ end
167
+
156
168
  private
157
169
 
158
- ##
170
+ ##
159
171
  # Private Instance Methods
160
172
  #
161
173
  def define_accessor
162
- define_getter
163
174
  if repeated?
175
+ define_array_getter
164
176
  define_array_setter
165
177
  else
178
+ define_getter
166
179
  define_setter
167
180
  end
168
181
  end
169
182
 
183
+ def define_array_getter
184
+ field = self
185
+ @message_class.class_eval do
186
+ define_method(field.getter_method_name) do
187
+ @values[field.name] ||= ::Protobuf::Field::FieldArray.new(field)
188
+ end
189
+ end
190
+ end
191
+
170
192
  def define_array_setter
171
193
  field = self
172
194
  @message_class.class_eval do
173
195
  define_method(field.setter_method_name) do |val|
196
+ field.warn_if_deprecated
197
+ @values[field.name] ||= ::Protobuf::Field::FieldArray.new(field)
174
198
  @values[field.name].replace(val)
175
199
  end
176
200
  end
@@ -180,6 +204,7 @@ module Protobuf
180
204
  field = self
181
205
  @message_class.class_eval do
182
206
  define_method(field.getter_method_name) do
207
+ field.warn_if_deprecated
183
208
  @values.fetch(field.name, field.default_value)
184
209
  end
185
210
  end
@@ -189,10 +214,13 @@ module Protobuf
189
214
  field = self
190
215
  @message_class.class_eval do
191
216
  define_method(field.setter_method_name) do |val|
217
+ field.warn_if_deprecated
192
218
  if val.nil?
193
219
  @values.delete(field.name)
194
220
  elsif field.acceptable?(val)
195
221
  @values[field.name] = val
222
+ else
223
+ raise TypeError, "unacceptable value #{val} for type #{field.type}"
196
224
  end
197
225
  end
198
226
  end
@@ -205,6 +233,7 @@ module Protobuf
205
233
  @default
206
234
  end
207
235
  end
208
- end
236
+
237
+ end
209
238
  end
210
239
  end
@@ -32,23 +32,15 @@ module Protobuf
32
32
  def define_setter
33
33
  field = self
34
34
  @message_class.class_eval do
35
- define_method("#{field.name}=") do |val|
36
- if val.nil?
35
+ define_method("#{field.name}=") do |value|
36
+ orig_value = value
37
+ if value.nil?
37
38
  @values.delete(field.name)
38
39
  else
39
- val = \
40
- case val
41
- when Symbol then
42
- field.type.const_get(val) rescue nil
43
- when Integer then
44
- field.type.const_get(field.type.name_by_value(val)) rescue nil
45
- when EnumValue then
46
- raise TypeError, "Invalid value: #{val.inspect} for #{field.name}" if val.parent_class != field.type
47
- val
48
- end
49
- raise TypeError, "Invalid value: #{val.inspect} for #{field.name}" unless val
40
+ value = field.type.fetch(value)
41
+ raise TypeError, "Invalid ENUM value: #{orig_value.inspect} for #{field.name}" unless value
50
42
 
51
- @values[field.name] = val
43
+ @values[field.name] = value
52
44
  end
53
45
  end
54
46
  end
@@ -1,23 +1,31 @@
1
1
  module Protobuf
2
2
  module Field
3
- class ExtensionFields < Hash
3
+ class ExtensionFields < Array
4
4
  ##
5
5
  # Constructor
6
6
  #
7
- def initialize(key_range=0..-1)
8
- @key_range = key_range
7
+ def initialize
8
+ @ranges = []
9
9
  end
10
10
 
11
11
  ##
12
12
  # Public Instance Methods
13
13
  #
14
+
15
+ # Append a range to the list of ranges.
16
+ def add_range(range = (0..-1))
17
+ @ranges << range
18
+ end
19
+
20
+ # Set value at tag location, if tag is in a valid range.
14
21
  def []=(key, value)
15
- raise RangeError, "#{key} is not in #{@key_range}" unless @key_range.include?(key)
22
+ raise RangeError, "#{key} is not in #{@ranges.join(', ')}" unless include_tag?(key)
16
23
  super
17
24
  end
18
25
 
26
+ # Check if the given tag exists in any of the defined ranges.
19
27
  def include_tag?(tag)
20
- @key_range.include?(tag)
28
+ @ranges.any? { |range| range.include?(tag) }
21
29
  end
22
30
  end
23
31
  end
@@ -8,7 +8,7 @@ module Protobuf
8
8
  @field = field
9
9
  end
10
10
 
11
- ##
11
+ ##
12
12
  # Public Instance Methods
13
13
  #
14
14
  def []=(nth, val)
@@ -33,21 +33,31 @@ module Protobuf
33
33
  super(val)
34
34
  end
35
35
 
36
+ # Return a hash-representation of the given values for this field type.
37
+ # The value in this case would be an array.
38
+ def to_hash_value
39
+ self.map do |value|
40
+ value.respond_to?(:to_hash_value) ? value.to_hash_value : value
41
+ end
42
+ end
43
+
36
44
  def to_s
37
45
  "[#{@field.name}]"
38
46
  end
39
-
47
+
40
48
  private
41
49
 
42
50
  ##
43
51
  # Private Instance Methods
44
52
  #
45
- def normalize(val)
46
- raise TypeError unless @field.acceptable?(val)
47
- if @field.is_a?(::Protobuf::Field::MessageField) && val.is_a?(Hash)
48
- @field.type.new(val)
53
+ def normalize(value)
54
+ raise TypeError unless @field.acceptable?(value)
55
+ if @field.is_a?(::Protobuf::Field::EnumField)
56
+ @field.type.fetch(value)
57
+ elsif @field.is_a?(::Protobuf::Field::MessageField) && value.is_a?(Hash)
58
+ @field.type.new(value)
49
59
  else
50
- val
60
+ value
51
61
  end
52
62
  end
53
63
  end
@@ -4,8 +4,8 @@ module Protobuf
4
4
  module Field
5
5
  class VarintField < BaseField
6
6
  INT32_MAX = 2**31 - 1
7
- INT32_MIN = -2**31
8
- INT64_MAX = 2**63 - 1
7
+ INT32_MIN = -2**31
8
+ INT64_MAX = 2**63 - 1
9
9
  INT64_MIN = -2**63
10
10
  UINT32_MAX = 2**32 - 1
11
11
  UINT64_MAX = 2**64 - 1
@@ -26,8 +26,8 @@ module Protobuf
26
26
  end
27
27
 
28
28
  def self.encode(value)
29
- raise RangeError, "#{value} is negative" if value < 0
30
29
  return [value].pack('C') if value < 128
30
+
31
31
  bytes = []
32
32
  until value == 0
33
33
  bytes << (0x80 | (value & 0x7f))
@@ -41,9 +41,7 @@ module Protobuf
41
41
  # Public Instance Methods
42
42
  #
43
43
  def acceptable?(val)
44
- raise TypeError, val.class.name unless val.is_a?(Integer)
45
- raise RangeError if val < min || max < val
46
- true
44
+ (val > min || val < max) rescue false
47
45
  end
48
46
 
49
47
  def decode(value)
@@ -8,22 +8,21 @@ module Protobuf
8
8
  class Message
9
9
  STRING_ENCODING = "ASCII-8BIT".freeze
10
10
 
11
- def self.inherited(klass)
12
- @_children ||= Set.new
13
- @_children << klass
14
- end
15
-
16
11
  def self.all_fields
17
12
  @all_fields ||= begin
18
- fields_hash = fields.merge(extension_fields)
19
- ordered_keys = fields_hash.keys.sort
20
- ordered_keys.map { |key| fields_hash[key] }
13
+ all_fields_array = []
14
+ max_fields = fields.size > extension_fields.size ? fields.size : extension_fields.size
15
+ max_fields.times do |field_number|
16
+ all_fields_array << (fields[field_number] || extension_fields[field_number])
17
+ end
18
+ all_fields_array.compact!
19
+ all_fields_array
21
20
  end
22
21
  end
23
22
 
24
23
  # Reserve field numbers for extensions. Don't use this method directly.
25
24
  def self.extensions(range)
26
- @extension_fields = ::Protobuf::Field::ExtensionFields.new(range)
25
+ extension_fields.add_range(range)
27
26
  end
28
27
 
29
28
  # Define a required field. Don't use this method directly.
@@ -43,18 +42,16 @@ module Protobuf
43
42
 
44
43
  # Define a field. Don't use this method directly.
45
44
  def self.define_field(rule, type, fname, tag, options)
46
- field_hash = options[:extension] ? extension_fields : fields
47
- field_name_hash = options[:extension] ? extension_fields_by_name : fields_by_name
48
- repeated_collection = options[:extension] ? repeated_extension_fields : repeated_fields
45
+ field_array = options[:extension] ? extension_fields : fields
46
+ field_name_hash = options[:extension] ? extension_field_name_to_tag : field_name_to_tag
49
47
 
50
- if field_hash.keys.include?(tag)
48
+ if field_array[tag]
51
49
  raise TagCollisionError, %!{Field number #{tag} has already been used in "#{self.name}" by field "#{fname}".!
52
50
  end
53
51
 
54
52
  field_definition = Field.build(self, rule, type, fname, tag, options)
55
- field_name_hash[fname.to_sym] = field_definition
56
- repeated_collection << field_definition if rule == :repeated
57
- field_hash[tag] = field_definition
53
+ field_name_hash[fname] = tag
54
+ field_array[tag] = field_definition
58
55
  end
59
56
 
60
57
  def self.extension_tag?(tag)
@@ -66,31 +63,23 @@ module Protobuf
66
63
  @extension_fields ||= ::Protobuf::Field::ExtensionFields.new
67
64
  end
68
65
 
69
- def self.extension_fields_by_name
66
+ def self.extension_field_name_to_tag
70
67
  @extension_fields_by_name ||= {}
71
68
  end
72
69
 
73
70
  # A collection of field object.
74
71
  def self.fields
75
- @fields ||= {}
72
+ @fields ||= []
76
73
  end
77
74
 
78
- def self.fields_by_name
79
- @field_by_name ||= {}
80
- end
81
-
82
- def self.repeated_fields
83
- @repeated_fields ||= []
84
- end
85
-
86
- def self.repeated_extension_fields
87
- @repeated_extension_fields ||= []
75
+ def self.field_name_to_tag
76
+ @field_name_to_tag ||= {}
88
77
  end
89
78
 
90
79
  # Find a field object by +name+.
91
80
  def self.get_field_by_name(name)
92
81
  # Check if the name has been used before, if not then set it to the sym value
93
- fields_by_name[name] ||= fields_by_name[name.to_sym]
82
+ fields[field_name_to_tag[name]]
94
83
  end
95
84
 
96
85
  # Find a field object by +tag+ number.
@@ -98,62 +87,30 @@ module Protobuf
98
87
  fields[tag]
99
88
  end
100
89
 
101
- def self.field_cache
102
- @field_cache ||= {}
103
- end
104
-
105
- # Find a field object by +tag_or_name+.
106
- def self.get_field(tag_or_name)
107
- field_cache[tag_or_name] ||= case tag_or_name
108
- when Integer then get_field_by_tag(tag_or_name)
109
- when String, Symbol then get_field_by_name(tag_or_name)
110
- else raise TypeError, tag_or_name.class
111
- end
112
- end
113
-
114
90
  def self.get_ext_field_by_name(name)
115
91
  # Check if the name has been used before, if not then set it to the sym value
116
- extension_fields_by_name[name] ||= extension_fields_by_name[name.to_sym]
92
+ extension_fields[extension_field_name_to_tag[name]]
117
93
  end
118
94
 
119
95
  def self.get_ext_field_by_tag(tag)
120
96
  extension_fields[tag]
121
97
  end
122
98
 
123
- def self.get_ext_field(tag_or_name)
124
- case tag_or_name
125
- when Integer then get_ext_field_by_tag(tag_or_name)
126
- when String, Symbol then get_ext_field_by_name(tag_or_name)
127
- else raise TypeError, tag_or_name.class
128
- end
129
- end
130
-
131
99
  ##
132
100
  # Constructor
133
101
  #
134
102
  def initialize(values={})
135
103
  @values = {}
136
104
 
137
- self.class.repeated_fields.each do |field|
138
- @values[field.name] = Field::FieldArray.new(field)
139
- end
140
-
141
- self.class.repeated_extension_fields.each do |field|
142
- @values[field.name] = Field::FieldArray.new(field)
143
- end
144
-
145
- values.each { |tag, val| self[tag] = val}
105
+ values.each { |name, val| self[name] = val}
146
106
  end
147
107
 
148
108
  def initialized?
149
- fields.all? {|tag, field| field.initialized?(self) } && \
150
- extension_fields.all? {|tag, field| field.initialized?(self) }
109
+ all_fields.all? { |field| field.initialized?(self) }
151
110
  end
152
111
 
153
- def has_field?(tag_or_name)
154
- field = get_field(tag_or_name) || get_ext_field(tag_or_name)
155
- raise ArgumentError, "unknown field: #{tag_or_name.inspect}" unless field
156
- @values.has_key?(field.name)
112
+ def has_field?(name)
113
+ @values.has_key?(name)
157
114
  end
158
115
 
159
116
  def ==(obj)
@@ -204,42 +161,8 @@ module Protobuf
204
161
  end
205
162
  private :copy_to
206
163
 
207
- def inspect(indent=0)
208
- result = []
209
- i = ' ' * indent
210
- field_value_to_string = lambda { |field, value|
211
- result << \
212
- if field.optional? && ! has_field?(field.name)
213
- ''
214
- else
215
- case field
216
- when Field::MessageField then
217
- if value.nil?
218
- "#{i}#{field.name} {}\n"
219
- else
220
- "#{i}#{field.name} {\n#{value.inspect(indent + 1)}#{i}}\n"
221
- end
222
- when Field::EnumField then
223
- if value.is_a?(EnumValue)
224
- "#{i}#{field.name}: #{value.name}\n"
225
- else
226
- "#{i}#{field.name}: #{field.type.name_by_value(value)}\n"
227
- end
228
- else
229
- "#{i}#{field.name}: #{value.inspect}\n"
230
- end
231
- end
232
- }
233
- each_field do |field, value|
234
- if field.repeated?
235
- value.each do |v|
236
- field_value_to_string.call(field, v)
237
- end
238
- else
239
- field_value_to_string.call(field, value)
240
- end
241
- end
242
- result.join
164
+ def inspect
165
+ to_hash.inspect
243
166
  end
244
167
 
245
168
  def parse_from_string(string)
@@ -268,30 +191,29 @@ module Protobuf
268
191
  field.set(self, bytes) if field
269
192
  end
270
193
 
271
- def [](tag_or_name)
272
- if field = get_field(tag_or_name) || get_ext_field(tag_or_name)
194
+ def [](name)
195
+ if field = get_field_by_name(name) || get_ext_field_by_name(name)
273
196
  __send__(field.name)
274
197
  else
275
- raise NoMethodError, "No such field: #{tag_or_name.inspect}"
198
+ raise NoMethodError, "No such field: #{name.inspect}"
276
199
  end
277
200
  end
278
201
 
279
- def []=(tag_or_name, value)
280
- if field = get_field(tag_or_name) || get_ext_field(tag_or_name)
281
- # __send__("#{field.name}=", value)
202
+ def []=(name, value)
203
+ if field = get_field_by_name(name) || get_ext_field_by_name(name)
282
204
  __send__(field.setter_method_name, value)
283
205
  else
284
- raise NoMethodError, "No such field: #{tag_or_name.inspect}"
206
+ raise NoMethodError, "No such field: #{name.inspect}"
285
207
  end
286
208
  end
287
209
 
288
210
  # Returns a hash; which key is a tag number, and value is a field object.
289
211
  def all_fields
290
- @_all_fields ||= self.class.all_fields
212
+ self.class.all_fields
291
213
  end
292
214
 
293
215
  def fields
294
- @_fields ||= self.class.fields
216
+ self.class.fields
295
217
  end
296
218
 
297
219
  # Returns field object or +nil+.
@@ -304,11 +226,6 @@ module Protobuf
304
226
  self.class.get_field_by_tag(tag)
305
227
  end
306
228
 
307
- # Returns field object or +nil+.
308
- def get_field(tag_or_name)
309
- self.class.get_field(tag_or_name)
310
- end
311
-
312
229
  # Returns extension fields. See Message#fields method.
313
230
  def extension_fields
314
231
  self.class.extension_fields
@@ -322,10 +239,6 @@ module Protobuf
322
239
  self.class.get_ext_field_by_tag(tag)
323
240
  end
324
241
 
325
- def get_ext_field(tag_or_name) # :nodoc:
326
- self.class.get_ext_field(tag_or_name)
327
- end
328
-
329
242
  # Iterate over a field collection.
330
243
  # message.each_field do |field_object, value|
331
244
  # # do something
@@ -337,40 +250,23 @@ module Protobuf
337
250
  end
338
251
  end
339
252
 
253
+ # Return a hash-representation of the given fields for this message type.
340
254
  def to_hash
341
- result = {}
342
- build_value = lambda { |field, value|
343
- if !field.optional? || (field.optional? && has_field?(field.name))
344
- case field
345
- when Field::MessageField then
346
- value.to_hash
347
- when Field::EnumField then
348
- if value.is_a?(EnumValue)
349
- value.to_i
350
- elsif value.is_a?(Symbol)
351
- field.type[value].to_i
352
- else
353
- value
354
- end
355
- else
356
- value
357
- end
358
- end
359
- }
360
- each_field do |field, value|
361
- if field.repeated?
362
- result[field.name] = value.map do |v|
363
- build_value.call(field, v)
364
- end
365
- else
366
- result[field.name] = build_value.call(field, value)
367
- end
255
+ result = Hash.new
256
+
257
+ @values.keys.each do |field_name|
258
+ value = __send__(field_name)
259
+ hashed_value = value.respond_to?(:to_hash_value) ? value.to_hash_value : value
260
+ result.merge!(field_name => hashed_value)
368
261
  end
369
- result
262
+
263
+ return result
370
264
  end
265
+ alias_method :to_hash_value, :to_hash
371
266
 
372
267
  def to_json
373
268
  to_hash.to_json
374
269
  end
270
+
375
271
  end
376
272
  end