| 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 GetRequireName(const std::string& proto_file); | 51 std::string StripDotProto(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 GetRequireName(const std::string& proto_file) { | 73 std::string StripDotProto(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) + "_pb"; | 75 return proto_file.substr(0, lastindex); |
| 76 } | 76 } |
| 77 | 77 |
| 78 std::string GetOutputFilename(const std::string& proto_file) { | 78 std::string GetOutputFilename(const std::string& proto_file) { |
| 79 return GetRequireName(proto_file) + ".rb"; | 79 return StripDotProto(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 // Locale-agnostic utility functions. | 240 // Module names, class names, and enum value names need to be Ruby constants, |
| 241 bool IsLower(char ch) { return ch >= 'a' && ch <= 'z'; } | 241 // which must start with a capital letter. |
| 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. | |
| 279 std::string RubifyConstant(const std::string& name) { | 242 std::string RubifyConstant(const std::string& name) { |
| 280 std::string ret = name; | 243 std::string ret = name; |
| 281 if (!ret.empty()) { | 244 if (!ret.empty()) { |
| 282 if (IsLower(ret[0])) { | 245 if (ret[0] >= 'a' && ret[0] <= 'z') { |
| 283 // If it starts with a lowercase letter, capitalize it. | 246 // If it starts with a lowercase letter, capitalize it. |
| 284 ret[0] = ToUpper(ret[0]); | 247 ret[0] = ret[0] - 'a' + 'A'; |
| 285 } else if (!IsAlpha(ret[0])) { | 248 } else if (ret[0] < 'A' || ret[0] > 'Z') { |
| 286 // Otherwise (e.g. if it begins with an underscore), we need to come up | 249 // Otherwise (e.g. if it begins with an underscore), we need to come up |
| 287 // with some prefix that starts with a capital letter. We could be smarter | 250 // with some prefix that starts with a capital letter. We could be smarter |
| 288 // here, e.g. try to strip leading underscores, but this may cause other | 251 // here, e.g. try to strip leading underscores, but this may cause other |
| 289 // problems if the user really intended the name. So let's just prepend a | 252 // problems if the user really intended the name. So let's just prepend a |
| 290 // well-known suffix. | 253 // well-known suffix. |
| 291 ret = "PB_" + ret; | 254 ret = "PB_" + ret; |
| 292 } | 255 } |
| 293 } | 256 } |
| 294 | |
| 295 return ret; | 257 return ret; |
| 296 } | 258 } |
| 297 | 259 |
| 298 void GenerateMessageAssignment( | 260 void GenerateMessageAssignment( |
| 299 const std::string& prefix, | 261 const std::string& prefix, |
| 300 const google::protobuf::Descriptor* message, | 262 const google::protobuf::Descriptor* message, |
| 301 google::protobuf::io::Printer* printer) { | 263 google::protobuf::io::Printer* printer) { |
| 302 | 264 |
| 303 // Don't generate MapEntry messages -- we use the Ruby extension's native | 265 // Don't generate MapEntry messages -- we use the Ruby extension's native |
| 304 // support for map fields instead. | 266 // support for map fields instead. |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 345 while (!package_name.empty()) { | 307 while (!package_name.empty()) { |
| 346 size_t dot_index = package_name.find("."); | 308 size_t dot_index = package_name.find("."); |
| 347 string component; | 309 string component; |
| 348 if (dot_index == string::npos) { | 310 if (dot_index == string::npos) { |
| 349 component = package_name; | 311 component = package_name; |
| 350 package_name = ""; | 312 package_name = ""; |
| 351 } else { | 313 } else { |
| 352 component = package_name.substr(0, dot_index); | 314 component = package_name.substr(0, dot_index); |
| 353 package_name = package_name.substr(dot_index + 1); | 315 package_name = package_name.substr(dot_index + 1); |
| 354 } | 316 } |
| 355 component = PackageToModule(component); | 317 component = RubifyConstant(component); |
| 356 printer->Print( | 318 printer->Print( |
| 357 "module $name$\n", | 319 "module $name$\n", |
| 358 "name", component); | 320 "name", component); |
| 359 printer->Indent(); | 321 printer->Indent(); |
| 360 levels++; | 322 levels++; |
| 361 } | 323 } |
| 362 return levels; | 324 return levels; |
| 363 } | 325 } |
| 364 | 326 |
| 365 void EndPackageModules( | 327 void EndPackageModules( |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 422 | 384 |
| 423 // Ok to omit this proto2 dependency -- so we won't print anything. | 385 // Ok to omit this proto2 dependency -- so we won't print anything. |
| 424 GOOGLE_LOG(WARNING) << "Omitting proto2 dependency '" << import->name() | 386 GOOGLE_LOG(WARNING) << "Omitting proto2 dependency '" << import->name() |
| 425 << "' from proto3 output file '" | 387 << "' from proto3 output file '" |
| 426 << GetOutputFilename(from->name()) | 388 << GetOutputFilename(from->name()) |
| 427 << "' because we don't support proto2 and no proto2 " | 389 << "' because we don't support proto2 and no proto2 " |
| 428 "types from that file are being used."; | 390 "types from that file are being used."; |
| 429 return true; | 391 return true; |
| 430 } else { | 392 } else { |
| 431 printer->Print( | 393 printer->Print( |
| 432 "require '$name$'\n", "name", GetRequireName(import->name())); | 394 "require '$name$'\n", "name", StripDotProto(import->name())); |
| 433 return true; | 395 return true; |
| 434 } | 396 } |
| 435 } | 397 } |
| 436 | 398 |
| 437 bool GenerateFile(const FileDescriptor* file, io::Printer* printer, | 399 bool GenerateFile(const FileDescriptor* file, io::Printer* printer, |
| 438 string* error) { | 400 string* error) { |
| 439 printer->Print( | 401 printer->Print( |
| 440 "# Generated by the protocol buffer compiler. DO NOT EDIT!\n" | 402 "# Generated by the protocol buffer compiler. DO NOT EDIT!\n" |
| 441 "# source: $filename$\n" | 403 "# source: $filename$\n" |
| 442 "\n", | 404 "\n", |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 492 generator_context->Open(GetOutputFilename(file->name()))); | 454 generator_context->Open(GetOutputFilename(file->name()))); |
| 493 io::Printer printer(output.get(), '$'); | 455 io::Printer printer(output.get(), '$'); |
| 494 | 456 |
| 495 return GenerateFile(file, &printer, error); | 457 return GenerateFile(file, &printer, error); |
| 496 } | 458 } |
| 497 | 459 |
| 498 } // namespace ruby | 460 } // namespace ruby |
| 499 } // namespace compiler | 461 } // namespace compiler |
| 500 } // namespace protobuf | 462 } // namespace protobuf |
| 501 } // namespace google | 463 } // namespace google |
| OLD | NEW |