ruby-protocol-buffers 1.5.1 → 1.6.0

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.
@@ -2,6 +2,8 @@ require 'stringio'
2
2
  require 'protocol_buffers/runtime/field'
3
3
  require 'protocol_buffers/runtime/encoder'
4
4
  require 'protocol_buffers/runtime/decoder'
5
+ require 'protocol_buffers/runtime/text_formatter'
6
+ require 'protocol_buffers/runtime/text_parser'
5
7
 
6
8
  module ProtocolBuffers
7
9
 
@@ -257,6 +259,19 @@ module ProtocolBuffers
257
259
  end
258
260
  alias_method :to_s, :serialize_to_string
259
261
 
262
+ # Format this message into the given IO stream using the text format of Protocol Buffers.
263
+ def text_format(io, options = nil)
264
+ formatter = TextFormatter.new(options)
265
+ formatter.format(io, self)
266
+ end
267
+
268
+ # Format this message into a text and return it.
269
+ def text_format_to_string(options = nil)
270
+ sio = ProtocolBuffers.utf8_sio
271
+ text_format(sio, options)
272
+ return sio.string
273
+ end
274
+
260
275
  def to_hash
261
276
  self.class.to_hash(self)
262
277
  end
@@ -296,6 +311,19 @@ module ProtocolBuffers
296
311
  self.new.parse(io)
297
312
  end
298
313
 
314
+ # Parse the text as a text representation of this class, and merge the parsed fields
315
+ # into the current message.
316
+ def parse_from_text(text)
317
+ parser = TextParser.new
318
+ parser.parse_text(text, self)
319
+ return self
320
+ end
321
+
322
+ # Shortcut, simply calls self.new.parse_from_text(text)
323
+ def self.parse_from_text(text)
324
+ self.new.parse_from_text(text)
325
+ end
326
+
299
327
  # Merge the attribute values from +obj+ into this Message, which must be of
300
328
  # the same class.
301
329
  #
@@ -426,6 +454,41 @@ module ProtocolBuffers
426
454
  @set_fields[tag] || false
427
455
  end
428
456
 
457
+ # Gets the field, returning nil if not set
458
+ # If a block is given, this block is called and it's
459
+ # return value returned if the value is not set
460
+ def get(*nested_field_names, &b)
461
+ if nested_field_names.size == 1
462
+ field_name = nested_field_names.first
463
+ field = self.class.field_for_name(field_name)
464
+ raise ArgumentError.new unless field
465
+ unless self.value_for_tag?(field.tag)
466
+ return b ? b.call : nil
467
+ end
468
+ return self.value_for_tag(field.tag)
469
+ end
470
+ last_proto = nested_field_names[0..-2].inject(self) do |sub_proto, ifield_name|
471
+ sub_field = sub_proto.class.field_for_name(ifield_name)
472
+ raise ArgumentError.new unless sub_field
473
+ raise ArgumentError.new unless sub_field.is_a?(ProtocolBuffers::Field::MessageField)
474
+ unless sub_proto.value_for_tag?(sub_field.tag)
475
+ return b ? b.call : nil
476
+ end
477
+ sub_proto.value_for_tag(sub_field.tag)
478
+ end
479
+ last_field_name = nested_field_names.last
480
+ last_field = last_proto.class.field_for_name(last_field_name)
481
+ unless last_proto.value_for_tag?(last_field.tag)
482
+ return b ? b.call : nil
483
+ end
484
+ last_proto.value_for_tag(last_field.tag)
485
+ end
486
+
487
+ # Gets the field, throwing ArgumentError if not set
488
+ def get!(*nested_field_names)
489
+ get(*nested_field_names) { raise ArgumentError.new("#{nested_field_names} is not set") }
490
+ end
491
+
429
492
  def inspect
430
493
  ret = ProtocolBuffers.bin_sio
431
494
  ret << "#<#{self.class.name}"
@@ -0,0 +1,116 @@
1
+ module ProtocolBuffers
2
+ class TextFormatter
3
+ def initialize(options = nil)
4
+ @options = options || {}
5
+ end
6
+
7
+ def format(io, message, options = nil)
8
+ message.validate!
9
+ options ||= {}
10
+ options = options.merge(@options)
11
+ options[:nest] ||= 0
12
+
13
+ if options[:short]
14
+ indent = ""
15
+ newline = " "
16
+ else
17
+ indent = " " * options[:nest]
18
+ newline = "\n"
19
+ end
20
+
21
+ sep = ""
22
+ message.fields.each do |tag, field|
23
+ next unless message.value_for_tag?(tag)
24
+ value = message.value_for_tag(tag)
25
+ if field.repeated?
26
+ next if value.size == 0
27
+ value.each do |v|
28
+ io.write sep; sep = newline
29
+
30
+ format_field(io, field, v, indent, newline, options)
31
+ end
32
+ else
33
+ io.write sep; sep = newline
34
+
35
+ format_field(io, field, value, indent, newline, options)
36
+ end
37
+ end
38
+
39
+ message.each_unknown_field do |tag_int, value|
40
+ io.write sep; sep = newline
41
+
42
+ wire_type = tag_int & 0x7
43
+ id = tag_int >> 3
44
+ format_unknown_field(io, wire_type, id, value, options)
45
+ end
46
+
47
+ io.write sep if !options[:short]
48
+
49
+ io
50
+ end
51
+
52
+ def format_field(io, field, value, indent, newline, options)
53
+ if field.kind_of? Field::GroupField
54
+ name = value.class.name.sub(/\A.*::/, '')
55
+ else
56
+ name = field.name
57
+ end
58
+
59
+ io.write "#{indent}#{name}"
60
+ if field.kind_of? Field::AggregateField
61
+ io.write " "
62
+ else
63
+ io.write ": "
64
+ end
65
+ field.text_format(io, value, options)
66
+ end
67
+
68
+ def format_unknown_field(io, wire_type, id, value, options)
69
+ options = options.dup
70
+ options[:nest] ||= 0
71
+
72
+ if options[:short]
73
+ indent = ""
74
+ newline = " "
75
+ else
76
+ indent = " " * options[:nest]
77
+ newline = "\n"
78
+ end
79
+
80
+ if wire_type == 3
81
+ options[:nest] += 1
82
+
83
+ io.write "#{indent}#{id} {#{newline}"
84
+ else
85
+ io.write "#{indent}#{id}: "
86
+ end
87
+
88
+ case wire_type
89
+ when 0 # VARINT
90
+ io.write "#{value}"
91
+
92
+ when 1 # FIXED64
93
+ lo, hi = value.unpack("V2")
94
+ io.write "0x%016x" % (hi << 32 | lo)
95
+
96
+ when 5 # FIXED32
97
+ io.write "0x%08x" % value.unpack("V")
98
+
99
+ when 2 # LENGTH_DELIMITED
100
+ value = value.unpack("C*").map { |b| "\\x%02x" % b }.join(nil)
101
+ io.write "\"#{value}\""
102
+
103
+ when 3 # START_GROUP
104
+ format(io, value, options)
105
+
106
+ when 4 # END_GROUP: never appear
107
+ raise(EncodeError, "Unexpected wire type END_GROUP")
108
+ else
109
+ raise(EncodeError, "unknown wire type: #{wire_type}")
110
+ end
111
+ if wire_type == 3
112
+ io.write "#{indent}}"
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,136 @@
1
+ # vim: set ft=racc fenc=us-ascii : -*- mode: racc coding: US-ASCII -*-
2
+ class ProtocolBuffers::TextParser
3
+ token identifier string integer bool float
4
+ rule
5
+ message : /* none */
6
+ {
7
+ result = current_message
8
+ }
9
+ | message field
10
+
11
+ field : field_name ':' primitive_value
12
+ {
13
+ set_field(val[0], val[2])
14
+ }
15
+ | field_name ':' identifier
16
+ {
17
+ field, enum_symbol = val[0], val[2]
18
+ unless field.kind_of?(ProtocolBuffers::Field::EnumField)
19
+ raise Racc::ParseError, "not a enum field: %s" % field.name
20
+ end
21
+ value = field.value_from_name(enum_symbol)
22
+ unless value
23
+ raise Racc::ParseError, "enum type %s has no value named %s" % [field.name, enum_symbol]
24
+ end
25
+ set_field(field, value)
26
+ }
27
+ | message_field_head '<'
28
+ {
29
+ field = _values[-2]
30
+ push_message(field.proxy_class.new)
31
+ }
32
+ message '>'
33
+ {
34
+ pop_message
35
+ set_field(val[0], val[3])
36
+ }
37
+ | message_field_head '{'
38
+ {
39
+ field = _values[-2]
40
+ push_message(field.proxy_class.new)
41
+ }
42
+ message '}'
43
+ {
44
+ pop_message
45
+ set_field(val[0], val[3])
46
+ }
47
+
48
+ message_field_head : field_name
49
+ | field_name ':'
50
+
51
+ field_name : identifier
52
+ {
53
+ field = current_message.class.field_for_name(val[0])
54
+ if field
55
+ return field
56
+ end
57
+
58
+ # fallback for case mismatch in group fields.
59
+ field = current_message.fields.find { |tag,field| field.name.to_s.downcase == val[0].downcase }
60
+ field &&= field.last
61
+ if field && field.kind_of?(ProtocolBuffers::Field::GroupField)
62
+ return field
63
+ end
64
+
65
+ raise Racc::ParseError, "no such field %s in %s" % [val[0], current_message.class]
66
+ }
67
+ | '[' qualified_name ']'
68
+ {
69
+ raise NotImplementedError, "extension is not yet supported"
70
+ }
71
+
72
+ qualified_name : identifier
73
+ {
74
+ result = [val[0]]
75
+ }
76
+ | qualified_name '.' identifier
77
+ {
78
+ result = (val[0] << val[2])
79
+ }
80
+
81
+ primitive_value : concat_string
82
+ | integer
83
+ | float
84
+ | bool
85
+ concat_string : string
86
+ | concat_string string
87
+ {
88
+ result = val[0] + val[1]
89
+ }
90
+ end
91
+
92
+ ---- header
93
+ require 'protocol_buffers/runtime/text_scanner'
94
+
95
+ ---- inner
96
+ def initialize
97
+ @msgstack = []
98
+ end
99
+
100
+ attr_accessor :yydebug
101
+
102
+ def parse_text(text, message)
103
+ scanner = ProtocolBuffers::TextScanner.new(text)
104
+ parse_from_scanner(scanner.enum_for(:scan), message)
105
+ end
106
+
107
+ def parse_from_scanner(scanner, message)
108
+ @msgstack.clear
109
+ push_message(message)
110
+ yyparse(scanner, :each)
111
+ pop_message
112
+ end
113
+
114
+ private :yyparse, :do_parse
115
+ private
116
+ def current_message
117
+ @msgstack.last
118
+ end
119
+
120
+ def push_message(message)
121
+ @msgstack.push(message)
122
+ end
123
+
124
+ def pop_message
125
+ @msgstack.pop
126
+ end
127
+
128
+ def set_field(field, value)
129
+ msg = current_message
130
+ if field.repeated?
131
+ msg.value_for_tag(field.tag) << value
132
+ else
133
+ msg.set_value_for_tag(field.tag, value)
134
+ end
135
+ msg
136
+ end
@@ -0,0 +1,94 @@
1
+ # -*- coding: UTF-8 -*-
2
+
3
+ require 'strscan'
4
+ require 'racc/parser'
5
+
6
+ module ProtocolBuffers; end
7
+
8
+ class ProtocolBuffers::TextScanner
9
+ def initialize(text)
10
+ @text = text.encode(Encoding::UTF_8)
11
+ @scanner = StringScanner.new(@text)
12
+ @lineno = 1
13
+ end
14
+
15
+ attr_reader :lineno
16
+
17
+ def scan
18
+ while @scanner.rest?
19
+ case
20
+ when @scanner.skip(/[ \t\v]+/)
21
+ next
22
+ when @scanner.skip(/#.*?$/)
23
+ next
24
+ when @scanner.skip(/\r?\n|\r/)
25
+ @lineno += 1
26
+ next
27
+ when @scanner.scan(/[.:<>{}\[\]]/)
28
+ c = @scanner[0]
29
+ yield [c, c]
30
+ when @scanner.scan(/true/)
31
+ yield [:bool, true]
32
+ when @scanner.scan(/false/)
33
+ yield [:bool, false]
34
+ when @scanner.scan(/["']/)
35
+ quote = @scanner[0]
36
+ line = lineno
37
+ if @scanner.scan(/(.*?)(?<!\\)#{quote}/)
38
+ str = @scanner[1]
39
+ yield [:string, unescape(str)]
40
+ else
41
+ raise Racc::ParseError, "unterminated string from line #{line}"
42
+ end
43
+ when @scanner.scan(/([+-])?[0-9]+\.[0-9]+([Ee][+-]?[0-9]+)?/)
44
+ yield [:float, Float(@scanner[0])]
45
+ when @scanner.scan(/([+-])?0[Bb]([01]+)/)
46
+ yield [:integer, Integer(@scanner[0], 2)]
47
+ when @scanner.scan(/([+-])?0[Xx]([[:xdigit:]]+)/)
48
+ yield [:integer, Integer(@scanner[0], 16)]
49
+ when @scanner.scan(/([+-])?0[Oo]?([0-7]+)/)
50
+ yield [:integer, Integer(@scanner[0], 8)]
51
+ when @scanner.scan(/([+-])?(?:0[Dd])?([0-9]+)/)
52
+ yield [:integer, Integer(@scanner[0], 10)]
53
+ when @scanner.scan(/[[:alpha:]_][[:alnum:]_]*/)
54
+ yield [:identifier, @scanner[0]]
55
+ else
56
+ line = lineno
57
+ raise Racc::ParseError, "unexpected character at: line #{line}: #{@scanner.rest.inspect}"
58
+ end
59
+ end
60
+ yield [false, nil]
61
+ end
62
+
63
+ private
64
+ ESCAPE_SEQUENCE = {
65
+ 'a' => "\a",
66
+ 'b' => "\b",
67
+ 'f' => "\f",
68
+ 'n' => "\n",
69
+ 'r' => "\r",
70
+ 't' => "\t",
71
+ 'v' => "\v",
72
+ '\\' => "\\",
73
+ '"' => '"',
74
+ "'" => "'",
75
+ }.freeze
76
+
77
+ def unescape(str)
78
+ str.gsub(%r!
79
+ \\ (?:
80
+ [Xx]([[:xdigit:]]{1,2}) |
81
+ ([0-7]{1,3}) |
82
+ ([abfnrtv\\'"])
83
+ )!x) do
84
+ case
85
+ when $1
86
+ Integer($1, 16).chr
87
+ when $2
88
+ Integer($2, 8).chr
89
+ when $3
90
+ ESCAPE_SEQUENCE[$3]
91
+ end
92
+ end
93
+ end
94
+ end
@@ -1,3 +1,3 @@
1
1
  module ProtocolBuffers
2
- VERSION = "1.5.1"
2
+ VERSION = "1.6.0"
3
3
  end
@@ -25,6 +25,7 @@ Gem::Specification.new do |gem|
25
25
  gem.add_development_dependency "rake"
26
26
  gem.add_development_dependency "rake-compiler"
27
27
  gem.add_development_dependency "simplecov"
28
- gem.add_development_dependency "rspec", "~> 2.5"
28
+ gem.add_development_dependency "rspec", "~> 2.14"
29
29
  gem.add_development_dependency "yard"
30
+ gem.add_development_dependency "racc", "~> 1.4.12"
30
31
  end