| OLD | NEW |
| 1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
| 2 // Copyright 2008 Google Inc. All rights reserved. | 2 // Copyright 2008 Google Inc. All rights reserved. |
| 3 // https://developers.google.com/protocol-buffers/ | 3 // https://developers.google.com/protocol-buffers/ |
| 4 // | 4 // |
| 5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
| 6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
| 7 // met: | 7 // met: |
| 8 // | 8 // |
| 9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
| 10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
| (...skipping 30 matching lines...) Expand all Loading... |
| 41 | 41 |
| 42 using google::protobuf::internal::scoped_ptr; | 42 using google::protobuf::internal::scoped_ptr; |
| 43 | 43 |
| 44 namespace google { | 44 namespace google { |
| 45 namespace protobuf { | 45 namespace protobuf { |
| 46 namespace compiler { | 46 namespace compiler { |
| 47 namespace ruby { | 47 namespace ruby { |
| 48 | 48 |
| 49 // Forward decls. | 49 // Forward decls. |
| 50 std::string IntToString(int32 value); | 50 std::string IntToString(int32 value); |
| 51 std::string StripDotProto(const std::string& proto_file); | 51 std::string GetRequireName(const std::string& proto_file); |
| 52 std::string LabelForField(google::protobuf::FieldDescriptor* field); | 52 std::string LabelForField(google::protobuf::FieldDescriptor* field); |
| 53 std::string TypeName(google::protobuf::FieldDescriptor* field); | 53 std::string TypeName(google::protobuf::FieldDescriptor* field); |
| 54 void GenerateMessage(const google::protobuf::Descriptor* message, | 54 void GenerateMessage(const google::protobuf::Descriptor* message, |
| 55 google::protobuf::io::Printer* printer); | 55 google::protobuf::io::Printer* printer); |
| 56 void GenerateEnum(const google::protobuf::EnumDescriptor* en, | 56 void GenerateEnum(const google::protobuf::EnumDescriptor* en, |
| 57 google::protobuf::io::Printer* printer); | 57 google::protobuf::io::Printer* printer); |
| 58 void GenerateMessageAssignment( | 58 void GenerateMessageAssignment( |
| 59 const std::string& prefix, | 59 const std::string& prefix, |
| 60 const google::protobuf::Descriptor* message, | 60 const google::protobuf::Descriptor* message, |
| 61 google::protobuf::io::Printer* printer); | 61 google::protobuf::io::Printer* printer); |
| 62 void GenerateEnumAssignment( | 62 void GenerateEnumAssignment( |
| 63 const std::string& prefix, | 63 const std::string& prefix, |
| 64 const google::protobuf::EnumDescriptor* en, | 64 const google::protobuf::EnumDescriptor* en, |
| 65 google::protobuf::io::Printer* printer); | 65 google::protobuf::io::Printer* printer); |
| 66 | 66 |
| 67 std::string IntToString(int32 value) { | 67 std::string IntToString(int32 value) { |
| 68 std::ostringstream os; | 68 std::ostringstream os; |
| 69 os << value; | 69 os << value; |
| 70 return os.str(); | 70 return os.str(); |
| 71 } | 71 } |
| 72 | 72 |
| 73 std::string StripDotProto(const std::string& proto_file) { | 73 std::string GetRequireName(const std::string& proto_file) { |
| 74 int lastindex = proto_file.find_last_of("."); | 74 int lastindex = proto_file.find_last_of("."); |
| 75 return proto_file.substr(0, lastindex); | 75 return proto_file.substr(0, lastindex) + "_pb"; |
| 76 } | 76 } |
| 77 | 77 |
| 78 std::string GetOutputFilename(const std::string& proto_file) { | 78 std::string GetOutputFilename(const std::string& proto_file) { |
| 79 return StripDotProto(proto_file) + ".rb"; | 79 return GetRequireName(proto_file) + ".rb"; |
| 80 } | 80 } |
| 81 | 81 |
| 82 std::string LabelForField(const google::protobuf::FieldDescriptor* field) { | 82 std::string LabelForField(const google::protobuf::FieldDescriptor* field) { |
| 83 switch (field->label()) { | 83 switch (field->label()) { |
| 84 case FieldDescriptor::LABEL_OPTIONAL: return "optional"; | 84 case FieldDescriptor::LABEL_OPTIONAL: return "optional"; |
| 85 case FieldDescriptor::LABEL_REQUIRED: return "required"; | 85 case FieldDescriptor::LABEL_REQUIRED: return "required"; |
| 86 case FieldDescriptor::LABEL_REPEATED: return "repeated"; | 86 case FieldDescriptor::LABEL_REPEATED: return "repeated"; |
| 87 default: assert(false); return ""; | 87 default: assert(false); return ""; |
| 88 } | 88 } |
| 89 } | 89 } |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 230 "value :$name$, $number$\n", | 230 "value :$name$, $number$\n", |
| 231 "name", value->name(), | 231 "name", value->name(), |
| 232 "number", IntToString(value->number())); | 232 "number", IntToString(value->number())); |
| 233 } | 233 } |
| 234 | 234 |
| 235 printer->Outdent(); | 235 printer->Outdent(); |
| 236 printer->Print( | 236 printer->Print( |
| 237 "end\n"); | 237 "end\n"); |
| 238 } | 238 } |
| 239 | 239 |
| 240 // Module names, class names, and enum value names need to be Ruby constants, | 240 // Locale-agnostic utility functions. |
| 241 // which must start with a capital letter. | 241 bool IsLower(char ch) { return ch >= 'a' && ch <= 'z'; } |
| 242 |
| 243 bool IsUpper(char ch) { return ch >= 'A' && ch <= 'Z'; } |
| 244 |
| 245 bool IsAlpha(char ch) { return IsLower(ch) || IsUpper(ch); } |
| 246 |
| 247 char ToUpper(char ch) { return IsLower(ch) ? (ch - 'a' + 'A') : ch; } |
| 248 |
| 249 |
| 250 // Package names in protobuf are snake_case by convention, but Ruby module |
| 251 // names must be PascalCased. |
| 252 // |
| 253 // foo_bar_baz -> FooBarBaz |
| 254 std::string PackageToModule(const std::string& name) { |
| 255 bool next_upper = true; |
| 256 std::string result; |
| 257 result.reserve(name.size()); |
| 258 |
| 259 for (int i = 0; i < name.size(); i++) { |
| 260 if (name[i] == '_') { |
| 261 next_upper = true; |
| 262 } else { |
| 263 if (next_upper) { |
| 264 result.push_back(ToUpper(name[i])); |
| 265 } else { |
| 266 result.push_back(name[i]); |
| 267 } |
| 268 next_upper = false; |
| 269 } |
| 270 } |
| 271 |
| 272 return result; |
| 273 } |
| 274 |
| 275 // Class and enum names in protobuf should be PascalCased by convention, but |
| 276 // since there is nothing enforcing this we need to ensure that they are valid |
| 277 // Ruby constants. That mainly means making sure that the first character is |
| 278 // an upper-case letter. |
| 242 std::string RubifyConstant(const std::string& name) { | 279 std::string RubifyConstant(const std::string& name) { |
| 243 std::string ret = name; | 280 std::string ret = name; |
| 244 if (!ret.empty()) { | 281 if (!ret.empty()) { |
| 245 if (ret[0] >= 'a' && ret[0] <= 'z') { | 282 if (IsLower(ret[0])) { |
| 246 // If it starts with a lowercase letter, capitalize it. | 283 // If it starts with a lowercase letter, capitalize it. |
| 247 ret[0] = ret[0] - 'a' + 'A'; | 284 ret[0] = ToUpper(ret[0]); |
| 248 } else if (ret[0] < 'A' || ret[0] > 'Z') { | 285 } else if (!IsAlpha(ret[0])) { |
| 249 // Otherwise (e.g. if it begins with an underscore), we need to come up | 286 // Otherwise (e.g. if it begins with an underscore), we need to come up |
| 250 // with some prefix that starts with a capital letter. We could be smarter | 287 // with some prefix that starts with a capital letter. We could be smarter |
| 251 // here, e.g. try to strip leading underscores, but this may cause other | 288 // here, e.g. try to strip leading underscores, but this may cause other |
| 252 // problems if the user really intended the name. So let's just prepend a | 289 // problems if the user really intended the name. So let's just prepend a |
| 253 // well-known suffix. | 290 // well-known suffix. |
| 254 ret = "PB_" + ret; | 291 ret = "PB_" + ret; |
| 255 } | 292 } |
| 256 } | 293 } |
| 294 |
| 257 return ret; | 295 return ret; |
| 258 } | 296 } |
| 259 | 297 |
| 260 void GenerateMessageAssignment( | 298 void GenerateMessageAssignment( |
| 261 const std::string& prefix, | 299 const std::string& prefix, |
| 262 const google::protobuf::Descriptor* message, | 300 const google::protobuf::Descriptor* message, |
| 263 google::protobuf::io::Printer* printer) { | 301 google::protobuf::io::Printer* printer) { |
| 264 | 302 |
| 265 // Don't generate MapEntry messages -- we use the Ruby extension's native | 303 // Don't generate MapEntry messages -- we use the Ruby extension's native |
| 266 // support for map fields instead. | 304 // support for map fields instead. |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 307 while (!package_name.empty()) { | 345 while (!package_name.empty()) { |
| 308 size_t dot_index = package_name.find("."); | 346 size_t dot_index = package_name.find("."); |
| 309 string component; | 347 string component; |
| 310 if (dot_index == string::npos) { | 348 if (dot_index == string::npos) { |
| 311 component = package_name; | 349 component = package_name; |
| 312 package_name = ""; | 350 package_name = ""; |
| 313 } else { | 351 } else { |
| 314 component = package_name.substr(0, dot_index); | 352 component = package_name.substr(0, dot_index); |
| 315 package_name = package_name.substr(dot_index + 1); | 353 package_name = package_name.substr(dot_index + 1); |
| 316 } | 354 } |
| 317 component = RubifyConstant(component); | 355 component = PackageToModule(component); |
| 318 printer->Print( | 356 printer->Print( |
| 319 "module $name$\n", | 357 "module $name$\n", |
| 320 "name", component); | 358 "name", component); |
| 321 printer->Indent(); | 359 printer->Indent(); |
| 322 levels++; | 360 levels++; |
| 323 } | 361 } |
| 324 return levels; | 362 return levels; |
| 325 } | 363 } |
| 326 | 364 |
| 327 void EndPackageModules( | 365 void EndPackageModules( |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 384 | 422 |
| 385 // Ok to omit this proto2 dependency -- so we won't print anything. | 423 // Ok to omit this proto2 dependency -- so we won't print anything. |
| 386 GOOGLE_LOG(WARNING) << "Omitting proto2 dependency '" << import->name() | 424 GOOGLE_LOG(WARNING) << "Omitting proto2 dependency '" << import->name() |
| 387 << "' from proto3 output file '" | 425 << "' from proto3 output file '" |
| 388 << GetOutputFilename(from->name()) | 426 << GetOutputFilename(from->name()) |
| 389 << "' because we don't support proto2 and no proto2 " | 427 << "' because we don't support proto2 and no proto2 " |
| 390 "types from that file are being used."; | 428 "types from that file are being used."; |
| 391 return true; | 429 return true; |
| 392 } else { | 430 } else { |
| 393 printer->Print( | 431 printer->Print( |
| 394 "require '$name$'\n", "name", StripDotProto(import->name())); | 432 "require '$name$'\n", "name", GetRequireName(import->name())); |
| 395 return true; | 433 return true; |
| 396 } | 434 } |
| 397 } | 435 } |
| 398 | 436 |
| 399 bool GenerateFile(const FileDescriptor* file, io::Printer* printer, | 437 bool GenerateFile(const FileDescriptor* file, io::Printer* printer, |
| 400 string* error) { | 438 string* error) { |
| 401 printer->Print( | 439 printer->Print( |
| 402 "# Generated by the protocol buffer compiler. DO NOT EDIT!\n" | 440 "# Generated by the protocol buffer compiler. DO NOT EDIT!\n" |
| 403 "# source: $filename$\n" | 441 "# source: $filename$\n" |
| 404 "\n", | 442 "\n", |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 454 generator_context->Open(GetOutputFilename(file->name()))); | 492 generator_context->Open(GetOutputFilename(file->name()))); |
| 455 io::Printer printer(output.get(), '$'); | 493 io::Printer printer(output.get(), '$'); |
| 456 | 494 |
| 457 return GenerateFile(file, &printer, error); | 495 return GenerateFile(file, &printer, error); |
| 458 } | 496 } |
| 459 | 497 |
| 460 } // namespace ruby | 498 } // namespace ruby |
| 461 } // namespace compiler | 499 } // namespace compiler |
| 462 } // namespace protobuf | 500 } // namespace protobuf |
| 463 } // namespace google | 501 } // namespace google |
| OLD | NEW |