class FileDescriptorToRuby

Constants

LABEL_MAPPING
TYPE_MAPPING

Public Class Methods

new(descriptor) click to toggle source
Calls superclass method
# File lib/protocol_buffers/compiler/file_descriptor_to_ruby.rb, line 9
def initialize(descriptor)
  super
  @package_modules = descriptor.package ? descriptor.package.split('.') : []
  @ns = []
end

Public Instance Methods

write(io) click to toggle source
# File lib/protocol_buffers/compiler/file_descriptor_to_ruby.rb, line 15
  def write(io)
    @io = io

    @io.write <<HEADER
#!/usr/bin/env ruby
# Generated by the protocol buffer compiler. DO NOT EDIT!

require 'protocol_buffers'

HEADER

    descriptor.dependency.each do |dep|
      dir      = File.dirname(dep)
      filename = File.basename(dep, ".proto") + ".pb"
      path = if dir == '.'
        filename
      else
        File.join(dir, filename)
      end
      @io.write("begin; require '#{path}'; rescue LoadError; end\n")
    end
    @io.write("\n") unless descriptor.dependency.empty?

    in_namespace("module", @package_modules) do
      declare(descriptor.package, descriptor.message_type, descriptor.enum_type)

      descriptor.message_type.each do |message|
        dump_message(descriptor.package, message)
      end

      descriptor.service.each do |service|
        dump_service(descriptor.package, service)
      end
    end
    
  end

Protected Instance Methods

camelize(lower_case_and_underscored_word) click to toggle source
# File lib/protocol_buffers/compiler/file_descriptor_to_ruby.rb, line 215
def camelize(lower_case_and_underscored_word)
  lower_case_and_underscored_word.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }
end
capfirst(s) click to toggle source
# File lib/protocol_buffers/compiler/file_descriptor_to_ruby.rb, line 211
def capfirst(s)
  "#{s[0,1].capitalize}#{s[1..-1]}" if s
end
declare(package, messages, enums) click to toggle source
# File lib/protocol_buffers/compiler/file_descriptor_to_ruby.rb, line 54
def declare(package, messages, enums)
  return if messages.empty? && enums.empty?

  line %{# forward declarations}
  messages.each do |message|
    line %{class #{name([@package_modules, message.name].flatten)} < ::ProtocolBuffers::Message; end}
  end

  if enums.empty?
    line
  else
    line
    line %{# enums}
    enums.each do |enum|
      dump_enum(package, enum)
    end
  end
end
default_value(field) click to toggle source

TODO: this probably doesn’t work for all default values, expand

# File lib/protocol_buffers/compiler/file_descriptor_to_ruby.rb, line 193
def default_value(field)
  case field.type
  when TYPE_STRING, TYPE_BYTES
    %{"#{field.default_value}"}
  when TYPE_BOOL
    field.default_value
  when TYPE_ENUM
    typename = field_typename(field)
    %{#{typename}::#{field.default_value}}
  else
    field.default_value
  end
end
dump_enum(package, enum) click to toggle source
# File lib/protocol_buffers/compiler/file_descriptor_to_ruby.rb, line 158
def dump_enum(package, enum)
  in_namespace("module", enum.name) do
    line %{include ::ProtocolBuffers::Enum}
    line

    line %{set_fully_qualified_name "#{fully_qualified_name(package, enum.name)}"}
    line

    enum.value.each do |value|
      line %{#{capfirst(value.name)} = #{value.number}}
    end
  end
  line
end
dump_message(package, message) click to toggle source
# File lib/protocol_buffers/compiler/file_descriptor_to_ruby.rb, line 126
def dump_message(package, message)
  in_namespace("class", message.name, " < ::ProtocolBuffers::Message") do
    fully_qualified_name = fully_qualified_name(package, message.name)
    declare(fully_qualified_name, message.nested_type, message.enum_type)

    line %{set_fully_qualified_name "#{fully_qualified_name}"}
    line

    line %{# nested messages} unless message.nested_type.empty?
    message.nested_type.each { |inner| dump_message(fully_qualified_name, inner) }

    message.field.each do |field|
      typename = field_typename(field)
      fieldline = %{#{LABEL_MAPPING[field.label]} #{typename}, :#{field.name}, #{field.number}}
      if field.type == TYPE_GROUP
        fieldline << %{, :group => true}
      end
      if field.default_value && field.default_value != ""
        fieldline << %{, :default => #{default_value(field)}}
      end

      # Dont need to check for 'repeated' attribute or type, protoc will take care of this.
      if field.options.packed
        fieldline << %{, :packed => true }
      end

      line fieldline
    end
  end
  line
end
dump_service(package, service) click to toggle source
# File lib/protocol_buffers/compiler/file_descriptor_to_ruby.rb, line 173
def dump_service(package, service)
  in_namespace("class", service.name, " < ::ProtocolBuffers::Service") do
    fully_qualified_name = fully_qualified_name(package, service.name)
    line %{set_fully_qualified_name "#{fully_qualified_name}"}
    line
    service.method.each do |method|
      line %{rpc :#{underscore(method.name)}, "#{method.name}", #{service_typename(method.input_type)}, #{service_typename(method.output_type)}}
    end
  end
end
field_typename(field) click to toggle source
# File lib/protocol_buffers/compiler/file_descriptor_to_ruby.rb, line 184
def field_typename(field)
  TYPE_MAPPING[field.type] || service_typename(field.type_name)
end
fully_qualified_name(package, name) click to toggle source
# File lib/protocol_buffers/compiler/file_descriptor_to_ruby.rb, line 207
def fully_qualified_name(package, name)
  package == nil || package.empty? ? name : "#{package}.#{name}"
end
in_namespace(type, namespace, rest = "") { || ... } click to toggle source
# File lib/protocol_buffers/compiler/file_descriptor_to_ruby.rb, line 81
def in_namespace(type, namespace, rest = "")
  
  namespace_array = [namespace].flatten
  
  namespace_array.each do |n|
    line "#{type} #{camelize(n)}#{rest}"
    @ns.push n
  end
  yield
  namespace_array.each do |n|
    @ns.pop
    line "end"
  end
end
line(str = nil) click to toggle source
# File lib/protocol_buffers/compiler/file_descriptor_to_ruby.rb, line 73
def line(str = nil)
  if str
    @ns.size.times { @io.write("  ") }
    @io.write(str)
  end
  @io.write("\n")
end
name(parts) click to toggle source
# File lib/protocol_buffers/compiler/file_descriptor_to_ruby.rb, line 96
def name(parts)
  ns = @ns.dup
  (parts.shift; ns.shift) while !parts.empty? && parts.first == ns.first
  parts.map { |p| camelize(p) }.join("::")
end
service_typename(type_name) click to toggle source
# File lib/protocol_buffers/compiler/file_descriptor_to_ruby.rb, line 188
def service_typename(type_name)
  type_name.split(".").map { |t| camelize(t) }.join("::")
end
underscore(camelized_word) click to toggle source
# File lib/protocol_buffers/compiler/file_descriptor_to_ruby.rb, line 219
def underscore(camelized_word)
  word = camelized_word.to_s.dup
  word.gsub!(/::/, '/')
  word.gsub!(/(?:([A-Za-z\d])|^)((?=\a)\b)(?=\b|[^a-z])/) { "#{$1}#{$1 && '_'}#{$2.downcase}" }
  word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
  word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
  word.tr!("-", "_")
  word.downcase!
  word
end