contrast-agent 6.3.0 → 6.4.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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -3
  3. data/.simplecov +1 -0
  4. data/Rakefile +0 -27
  5. data/lib/contrast/agent/assess/policy/propagation_method.rb +0 -2
  6. data/lib/contrast/agent/assess/policy/trigger_method.rb +1 -1
  7. data/lib/contrast/agent/version.rb +1 -1
  8. data/lib/contrast/api/dtm.pb.rb +1 -1
  9. data/lib/contrast/api/settings.pb.rb +1 -1
  10. data/lib/contrast/utils/patching/policy/patch_utils.rb +5 -22
  11. data/lib/contrast.rb +34 -0
  12. data/lib/protobuf/code_generator.rb +129 -0
  13. data/lib/protobuf/decoder.rb +28 -0
  14. data/lib/protobuf/deprecation.rb +117 -0
  15. data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +79 -0
  16. data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +360 -0
  17. data/lib/protobuf/descriptors.rb +3 -0
  18. data/lib/protobuf/encoder.rb +11 -0
  19. data/lib/protobuf/enum.rb +365 -0
  20. data/lib/protobuf/exceptions.rb +9 -0
  21. data/lib/protobuf/field/base_field.rb +380 -0
  22. data/lib/protobuf/field/base_field_object_definitions.rb +504 -0
  23. data/lib/protobuf/field/bool_field.rb +64 -0
  24. data/lib/protobuf/field/bytes_field.rb +67 -0
  25. data/lib/protobuf/field/double_field.rb +25 -0
  26. data/lib/protobuf/field/enum_field.rb +56 -0
  27. data/lib/protobuf/field/field_array.rb +102 -0
  28. data/lib/protobuf/field/field_hash.rb +122 -0
  29. data/lib/protobuf/field/fixed32_field.rb +25 -0
  30. data/lib/protobuf/field/fixed64_field.rb +28 -0
  31. data/lib/protobuf/field/float_field.rb +43 -0
  32. data/lib/protobuf/field/int32_field.rb +21 -0
  33. data/lib/protobuf/field/int64_field.rb +34 -0
  34. data/lib/protobuf/field/integer_field.rb +23 -0
  35. data/lib/protobuf/field/message_field.rb +51 -0
  36. data/lib/protobuf/field/sfixed32_field.rb +27 -0
  37. data/lib/protobuf/field/sfixed64_field.rb +28 -0
  38. data/lib/protobuf/field/signed_integer_field.rb +29 -0
  39. data/lib/protobuf/field/sint32_field.rb +21 -0
  40. data/lib/protobuf/field/sint64_field.rb +21 -0
  41. data/lib/protobuf/field/string_field.rb +51 -0
  42. data/lib/protobuf/field/uint32_field.rb +21 -0
  43. data/lib/protobuf/field/uint64_field.rb +21 -0
  44. data/lib/protobuf/field/varint_field.rb +77 -0
  45. data/lib/protobuf/field.rb +74 -0
  46. data/lib/protobuf/generators/base.rb +85 -0
  47. data/lib/protobuf/generators/enum_generator.rb +39 -0
  48. data/lib/protobuf/generators/extension_generator.rb +27 -0
  49. data/lib/protobuf/generators/field_generator.rb +193 -0
  50. data/lib/protobuf/generators/file_generator.rb +262 -0
  51. data/lib/protobuf/generators/group_generator.rb +122 -0
  52. data/lib/protobuf/generators/message_generator.rb +104 -0
  53. data/lib/protobuf/generators/option_generator.rb +17 -0
  54. data/lib/protobuf/generators/printable.rb +160 -0
  55. data/lib/protobuf/generators/service_generator.rb +50 -0
  56. data/lib/protobuf/lifecycle.rb +33 -0
  57. data/lib/protobuf/logging.rb +39 -0
  58. data/lib/protobuf/message/fields.rb +233 -0
  59. data/lib/protobuf/message/serialization.rb +85 -0
  60. data/lib/protobuf/message.rb +241 -0
  61. data/lib/protobuf/optionable.rb +72 -0
  62. data/lib/protobuf/tasks/compile.rake +80 -0
  63. data/lib/protobuf/tasks.rb +1 -0
  64. data/lib/protobuf/varint.rb +20 -0
  65. data/lib/protobuf/varint_pure.rb +31 -0
  66. data/lib/protobuf/version.rb +3 -0
  67. data/lib/protobuf/wire_type.rb +10 -0
  68. data/lib/protobuf.rb +91 -0
  69. data/proto/dynamic_discovery.proto +46 -0
  70. data/proto/google/protobuf/compiler/plugin.proto +183 -0
  71. data/proto/google/protobuf/descriptor.proto +911 -0
  72. data/proto/rpc.proto +71 -0
  73. data/ruby-agent.gemspec +1 -1
  74. metadata +71 -10
@@ -0,0 +1,262 @@
1
+ require 'set'
2
+ require 'protobuf/generators/base'
3
+ require 'protobuf/generators/group_generator'
4
+
5
+ module Protobuf
6
+ module Generators
7
+ class FileGenerator < Base
8
+
9
+ attr_reader :output_file
10
+
11
+ def initialize(*args)
12
+ super
13
+ @output_file = ::CSGoogle::Protobuf::Compiler::CodeGeneratorResponse::File.new(:name => file_name)
14
+ @extension_fields = Hash.new { |h, k| h[k] = [] }
15
+ @known_messages = {}
16
+ @known_enums = {}
17
+ @dangling_messages = {}
18
+ end
19
+
20
+ def file_name
21
+ convert_filename(descriptor.name, false)
22
+ end
23
+
24
+ def compile
25
+ run_once(:compile) do
26
+ map_extensions(descriptor, [descriptor.package])
27
+
28
+ print_file_comment
29
+ print_generic_requires
30
+ print_import_requires
31
+
32
+ print_package do
33
+ inject_optionable
34
+ group = GroupGenerator.new(current_indent)
35
+ group.add_options(descriptor.options) if descriptor.options
36
+ group.add_enums(descriptor.enum_type, :namespace => [descriptor.package])
37
+ group.add_message_declarations(descriptor.message_type)
38
+ group.add_messages(descriptor.message_type, :extension_fields => @extension_fields, :namespace => [descriptor.package])
39
+ group.add_extended_messages(unknown_extensions)
40
+ group.add_services(descriptor.service)
41
+
42
+ group.add_header(:enum, 'Enum Classes')
43
+ group.add_header(:message_declaration, 'Message Classes')
44
+ group.add_header(:options, 'File Options')
45
+ group.add_header(:message, 'Message Fields')
46
+ group.add_header(:extended_message, 'Extended Message Fields')
47
+ group.add_header(:service, 'Service Classes')
48
+ print group.to_s
49
+ end
50
+
51
+ end
52
+ end
53
+
54
+ def unknown_extensions
55
+ @unknown_extensions ||= @extension_fields.map do |message_name, fields|
56
+ message_klass = modulize(message_name).safe_constantize
57
+ if message_klass
58
+ unknown_fields = fields.reject do |field|
59
+ @known_messages[message_name] && message_klass.get_field(field.name, true)
60
+ end
61
+ [message_name, unknown_fields]
62
+ else
63
+ [message_name, fields]
64
+ end
65
+ end
66
+ end
67
+
68
+ def generate_output_file
69
+ compile
70
+ output_file.content = to_s
71
+ output_file
72
+ end
73
+
74
+ # Recursively map out all extensions known in this file.
75
+ # The key is the type_name of the message being extended, and
76
+ # the value is an array of field descriptors.
77
+ #
78
+ def map_extensions(descriptor, namespaces)
79
+ if fully_qualified_token?(descriptor.name)
80
+ fully_qualified_namespace = descriptor.name
81
+ elsif !(namespace = namespaces.reject(&:empty?).join(".")).empty?
82
+ fully_qualified_namespace = ".#{namespace}"
83
+ end
84
+ # Record all the message descriptor name's we encounter (should be the whole tree).
85
+ if descriptor.is_a?(::CSGoogle::Protobuf::DescriptorProto)
86
+ @known_messages[fully_qualified_namespace || descriptor.name] = descriptor
87
+ elsif descriptor.is_a?(::CSGoogle::Protobuf::EnumDescriptorProto)
88
+ @known_enums[fully_qualified_namespace || descriptor.name] = descriptor
89
+ return
90
+ end
91
+
92
+ descriptor.extension.each do |field_descriptor|
93
+ unless fully_qualified_token?(field_descriptor.name) && fully_qualified_namespace
94
+ field_descriptor.name = "#{fully_qualified_namespace}.#{field_descriptor.name}"
95
+ end
96
+ @extension_fields[field_descriptor.extendee] << field_descriptor
97
+ end
98
+
99
+ [:message_type, :nested_type, :enum_type].each do |type|
100
+ next unless descriptor.respond_to_has_and_present?(type)
101
+
102
+ descriptor.public_send(type).each do |type_descriptor|
103
+ map_extensions(type_descriptor, (namespaces + [type_descriptor.name]))
104
+ end
105
+ end
106
+ end
107
+
108
+ def print_file_comment
109
+ puts "# encoding: utf-8"
110
+ puts
111
+ puts "##"
112
+ puts "# This file is auto-generated. DO NOT EDIT!"
113
+ puts "#"
114
+ end
115
+
116
+ def print_generic_requires
117
+ print_require("protobuf")
118
+ print_require("protobuf/rpc/service") if descriptor.service.count > 0
119
+ puts
120
+ end
121
+
122
+ def print_import_requires
123
+ return if descriptor.dependency.empty?
124
+
125
+ header "Imports"
126
+
127
+ descriptor.dependency.each do |dependency|
128
+ print_require(convert_filename(dependency), ENV.key?('PB_REQUIRE_RELATIVE'))
129
+ end
130
+
131
+ puts
132
+ end
133
+
134
+ def print_package(&block)
135
+ namespaces = descriptor.package.split('.')
136
+ if namespaces.empty? && ENV.key?('PB_ALLOW_DEFAULT_PACKAGE_NAME')
137
+ namespaces = [File.basename(descriptor.name).sub('.proto', '')]
138
+ end
139
+ namespaces.reverse.reduce(block) do |previous, namespace|
140
+ -> { print_module(namespace, &previous) }
141
+ end.call
142
+ end
143
+
144
+ def eval_unknown_extensions!
145
+ @@evaled_dependencies ||= Set.new # rubocop:disable Style/ClassVars
146
+ @@all_messages ||= {} # rubocop:disable Style/ClassVars
147
+ @@all_enums ||= {} # rubocop:disable Style/ClassVars
148
+
149
+ map_extensions(descriptor, [descriptor.package])
150
+ @known_messages.each do |name, descriptor|
151
+ @@all_messages[name] = descriptor
152
+ end
153
+ @known_enums.each do |name, descriptor|
154
+ @@all_enums[name] = descriptor
155
+ end
156
+
157
+ # create package namespace
158
+ print_package {}
159
+ eval_code
160
+
161
+ unknown_extensions.each do |extendee, fields|
162
+ eval_dependencies(extendee)
163
+ fields.each do |field|
164
+ eval_dependencies(field.type_name)
165
+ end
166
+ end
167
+ group = GroupGenerator.new(0)
168
+ group.add_extended_messages(unknown_extensions, false)
169
+ print group.to_s
170
+ eval_code
171
+ rescue => e
172
+ warn "Error loading unknown extensions #{descriptor.name.inspect} error=#{e}"
173
+ raise e
174
+ end
175
+
176
+ private
177
+
178
+ def convert_filename(filename, for_require = true)
179
+ filename.sub(/\.proto/, (for_require ? '.pb' : '.pb.rb'))
180
+ end
181
+
182
+ def fully_qualified_token?(token)
183
+ token[0] == '.'
184
+ end
185
+
186
+ def eval_dependencies(name, namespace = nil)
187
+ name = "#{namespace}.#{name}" if namespace && !fully_qualified_token?(name)
188
+ return if name.empty? || @@evaled_dependencies.include?(name) || modulize(name).safe_constantize
189
+
190
+ # if name = .foo.bar.Baz look for classes / modules named ::Foo::Bar and ::Foo
191
+ # module == pure namespace (e.g. the descriptor package name)
192
+ # class == nested messages
193
+ create_ruby_namespace_heiarchy(name)
194
+
195
+ if (message = @@all_messages[name])
196
+ # Create the blank namespace in case there are nested types
197
+ eval_message_code(name)
198
+
199
+ message.nested_type.each do |nested_type|
200
+ eval_dependencies(nested_type.name, name) unless nested_type.name.empty?
201
+ end
202
+ message.field.each do |field|
203
+ eval_dependencies(field.type_name, name) unless field.type_name.empty?
204
+ end
205
+ message.enum_type.each do |enum_type|
206
+ eval_dependencies(enum_type.name, name)
207
+ end
208
+
209
+ # Check @@evaled_dependencies again in case there was a dependency
210
+ # loop that already loaded this message
211
+ return if @@evaled_dependencies.include?(name)
212
+ eval_message_code(name, message.field)
213
+ @@evaled_dependencies << name
214
+
215
+ elsif (enum = @@all_enums[name])
216
+ # Check @@evaled_dependencies again in case there was a dependency
217
+ # loop that already loaded this enum
218
+ return if @@evaled_dependencies.include?(name)
219
+ namespace = name.split(".")
220
+ eval_enum_code(enum, namespace[0..-2].join("."))
221
+ @@evaled_dependencies << name
222
+ else
223
+ fail "Error loading unknown dependencies, could not find message or enum #{name.inspect}"
224
+ end
225
+ end
226
+
227
+ def eval_message_code(fully_qualified_namespace, fields = [])
228
+ group = GroupGenerator.new(0)
229
+ group.add_extended_messages({ fully_qualified_namespace => fields }, false)
230
+ print group.to_s
231
+ eval_code
232
+ end
233
+
234
+ def eval_enum_code(enum, fully_qualified_namespace)
235
+ group = GroupGenerator.new(0)
236
+ group.add_enums([enum], :namespace => [fully_qualified_namespace])
237
+ print group.to_s
238
+ eval_code(modulize(fully_qualified_namespace).safe_constantize || Object)
239
+ end
240
+
241
+ def eval_code(context = Object)
242
+ warn "#{context.inspect}.module_eval #{print_contents.inspect}" if ENV['PB_DEBUG']
243
+ context.module_eval print_contents.to_s
244
+ @io.truncate(0)
245
+ @io.rewind
246
+ end
247
+
248
+ def create_ruby_namespace_heiarchy(namespace)
249
+ loop do
250
+ namespace, _match, _tail = namespace.rpartition(".")
251
+ break if namespace.empty?
252
+ eval_dependencies(namespace)
253
+ end
254
+ end
255
+
256
+ def inject_optionable
257
+ return if descriptor.package.empty? && !ENV.key?('PB_ALLOW_DEFAULT_PACKAGE_NAME')
258
+ puts "::Protobuf::Optionable.inject(self) { ::CSGoogle::Protobuf::FileOptions }"
259
+ end
260
+ end
261
+ end
262
+ end
@@ -0,0 +1,122 @@
1
+ require 'protobuf/generators/enum_generator'
2
+ require 'protobuf/generators/extension_generator'
3
+ require 'protobuf/generators/field_generator'
4
+ require 'protobuf/generators/message_generator'
5
+ require 'protobuf/generators/option_generator'
6
+ require 'protobuf/generators/service_generator'
7
+
8
+ module Protobuf
9
+ module Generators
10
+ class GroupGenerator
11
+ include ::Protobuf::Generators::Printable
12
+
13
+ attr_reader :groups, :indent_level
14
+ attr_writer :order
15
+
16
+ def initialize(indent_level = 0)
17
+ @groups = Hash.new { |h, k| h[k] = [] }
18
+ @headers = {}
19
+ @comments = {}
20
+ @handlers = {}
21
+ @indent_level = indent_level
22
+ @order = [:enum, :message_declaration, :options, :message, :extended_message, :service]
23
+ init_printer(indent_level)
24
+ end
25
+
26
+ def add_options(option_descriptor)
27
+ @groups[:options] << OptionGenerator.new(option_descriptor, indent_level)
28
+ end
29
+
30
+ def add_enums(enum_descriptors, options)
31
+ enum_descriptors.each do |enum_descriptor|
32
+ @groups[:enum] << EnumGenerator.new(enum_descriptor, indent_level, options)
33
+ end
34
+ end
35
+
36
+ def add_comment(type, message)
37
+ @comments[type] = message
38
+ end
39
+
40
+ def add_extended_messages(extended_messages, skip_empty_fields = true)
41
+ extended_messages.each do |message_type, field_descriptors|
42
+ next if skip_empty_fields && field_descriptors.empty?
43
+ @groups[:extended_message] << ExtensionGenerator.new(message_type, field_descriptors, indent_level)
44
+ end
45
+ end
46
+
47
+ def add_extension_fields(field_descriptors)
48
+ field_descriptors.each do |field_descriptor|
49
+ @groups[:extension_field] << FieldGenerator.new(field_descriptor, nil, indent_level)
50
+ end
51
+ end
52
+
53
+ def add_extension_ranges(extension_ranges, &item_handler)
54
+ @groups[:extension_range] = extension_ranges
55
+ @handlers[:extension_range] = item_handler
56
+ end
57
+
58
+ def add_header(type, message)
59
+ @headers[type] = message
60
+ end
61
+
62
+ def add_message_declarations(descriptors)
63
+ descriptors.each do |descriptor|
64
+ # elide synthetic map entry messages (we handle map fields differently)
65
+ next if descriptor.options.try(:map_entry?) { false }
66
+ @groups[:message_declaration] << MessageGenerator.new(descriptor, indent_level, :declaration => true)
67
+ end
68
+ end
69
+
70
+ def add_message_fields(field_descriptors, msg_descriptor)
71
+ field_descriptors.each do |field_descriptor|
72
+ @groups[:field] << FieldGenerator.new(field_descriptor, msg_descriptor, indent_level)
73
+ end
74
+ end
75
+
76
+ def add_messages(descriptors, options = {})
77
+ descriptors.each do |descriptor|
78
+ # elide synthetic map entry message (we handle map fields differently)
79
+ next if descriptor.options.try(:map_entry?) { false }
80
+ @groups[:message] << MessageGenerator.new(descriptor, indent_level, options)
81
+ end
82
+ end
83
+
84
+ def add_services(service_descriptors)
85
+ service_descriptors.each do |service_descriptor|
86
+ @groups[:service] << ServiceGenerator.new(service_descriptor, indent_level)
87
+ end
88
+ end
89
+
90
+ def compile
91
+ @order.each do |type|
92
+ items = @groups[type]
93
+ next if items.empty?
94
+
95
+ item_handler = @handlers[type]
96
+
97
+ item_header = @headers[type]
98
+ header(item_header) if item_header
99
+
100
+ item_comment = @comments[type]
101
+ comment(item_comment) if item_comment
102
+
103
+ items.each do |item|
104
+ if item_handler
105
+ puts item_handler.call(item)
106
+ else
107
+ print item.to_s
108
+ end
109
+ end
110
+
111
+ puts if type == :message_declaration || type == :options
112
+ end
113
+ end
114
+
115
+ def to_s
116
+ compile
117
+ print_contents
118
+ end
119
+
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,104 @@
1
+ require 'protobuf/generators/base'
2
+ require 'protobuf/generators/group_generator'
3
+
4
+ module Protobuf
5
+ module Generators
6
+ class MessageGenerator < Base
7
+
8
+ def initialize(descriptor, indent_level, options = {})
9
+ super
10
+ @only_declarations = options.fetch(:declaration) { false }
11
+ @extension_fields = options.fetch(:extension_fields) { {} }
12
+ end
13
+
14
+ def compile
15
+ run_once(:compile) do
16
+ if @only_declarations
17
+ compile_declaration
18
+ else
19
+ compile_message
20
+ end
21
+ end
22
+ end
23
+
24
+ def compile_declaration
25
+ run_once(:compile_declaration) do
26
+ if printable?
27
+ print_class(descriptor.name, :message) do
28
+ group = GroupGenerator.new(current_indent)
29
+ group.add_enums(descriptor.enum_type, :namespace => type_namespace)
30
+ group.add_message_declarations(descriptor.nested_type)
31
+ print group.to_s
32
+ end
33
+ else
34
+ print_class(descriptor.name, :message)
35
+ end
36
+ end
37
+ end
38
+
39
+ def compile_message
40
+ run_once(:compile_message) do
41
+ if printable?
42
+ print_class(descriptor.name, nil) do
43
+ group = GroupGenerator.new(current_indent)
44
+ group.add_messages(descriptor.nested_type, :extension_fields => @extension_fields, :namespace => type_namespace)
45
+ group.add_comment(:options, 'Message Options')
46
+ group.add_options(descriptor.options) if options?
47
+ group.add_message_fields(descriptor.field, descriptor)
48
+ self.class.validate_tags(fully_qualified_type_namespace, descriptor.field.map(&:number))
49
+
50
+ group.add_comment(:extension_range, 'Extension Fields')
51
+ group.add_extension_ranges(descriptor.extension_range) do |extension_range|
52
+ "extensions #{extension_range.start}...#{extension_range.end}"
53
+ end
54
+
55
+ group.add_extension_fields(message_extension_fields)
56
+
57
+ group.order = [:message, :options, :field, :extension_range, :extension_field]
58
+ print group.to_s
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ private
65
+
66
+ def extensions?
67
+ !message_extension_fields.empty?
68
+ end
69
+
70
+ def fields?
71
+ descriptor.field.count > 0
72
+ end
73
+
74
+ def options?
75
+ descriptor.options
76
+ end
77
+
78
+ def nested_enums?
79
+ descriptor.enum_type.count > 0
80
+ end
81
+
82
+ def nested_messages?
83
+ descriptor.nested_type.count > 0
84
+ end
85
+
86
+ def nested_types?
87
+ nested_enums? || nested_messages?
88
+ end
89
+
90
+ def printable?
91
+ if @only_declarations
92
+ nested_types?
93
+ else
94
+ fields? || nested_messages? || extensions? || options?
95
+ end
96
+ end
97
+
98
+ def message_extension_fields
99
+ @extension_fields.fetch(fully_qualified_type_namespace) { [] }
100
+ end
101
+
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,17 @@
1
+ require 'protobuf/generators/base'
2
+
3
+ module Protobuf
4
+ module Generators
5
+ class OptionGenerator < Base
6
+ def compile
7
+ run_once(:compile) do
8
+ descriptor.each_field.map do |field, value|
9
+ next unless descriptor.field?(field.name)
10
+ serialized_value = serialize_value(value)
11
+ puts "set_option #{field.fully_qualified_name.inspect}, #{serialized_value}"
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,160 @@
1
+ module Protobuf
2
+ module Generators
3
+ module Printable
4
+
5
+ PARENT_CLASS_MESSAGE = "::Protobuf::Message".freeze
6
+ PARENT_CLASS_ENUM = "::Protobuf::Enum".freeze
7
+ PARENT_CLASS_SERVICE = "::Protobuf::Rpc::Service".freeze
8
+
9
+ # Initialize the printer.
10
+ # Must be called by any class/module that includes the Printable module.
11
+ #
12
+ def init_printer(indent_level)
13
+ @io = ::StringIO.new
14
+ self.current_indent = indent_level.to_i
15
+ end
16
+
17
+ protected
18
+
19
+ attr_accessor :current_indent
20
+
21
+ private
22
+
23
+ # Print a one-line comment.
24
+ #
25
+ def comment(message)
26
+ puts "# #{message}"
27
+ end
28
+
29
+ # Print a "header" comment.
30
+ #
31
+ # header("Lorem ipsum dolor")
32
+ # ##
33
+ # # Lorem ipsum dolor
34
+ # #
35
+ def header(message)
36
+ puts
37
+ puts "##"
38
+ puts "# #{message}"
39
+ puts "#"
40
+ end
41
+
42
+ # Increase the indent level. An outdent will only occur if given a block
43
+ # (after the block is finished).
44
+ #
45
+ def indent
46
+ self.current_indent += 1
47
+ yield
48
+ outdent
49
+ end
50
+
51
+ # Take a string and upcase the first character of each namespace.
52
+ # Due to the nature of varying standards about how class/modules are named
53
+ # (e.g. CamelCase, Underscore_Case, SCREAMING_SNAKE_CASE), we only want
54
+ # to capitalize the first character to ensure ruby will treat the value
55
+ # as a constant. Otherwise we do not attempt to change the
56
+ # token's definition.
57
+ #
58
+ # modulize("foo.bar.Baz") -> "::Foo::Bar::Baz"
59
+ # modulize("foo.bar.baz") -> "::Foo::Bar::Baz"
60
+ # modulize("foo.bar.BAZ") -> "::Foo::Bar::BAZ"
61
+ #
62
+ def modulize(name)
63
+ name = name.gsub(/\./, '::')
64
+ name = name.gsub(/(^(?:::)?[a-z]|::[a-z])/, &:upcase)
65
+ name
66
+ end
67
+
68
+ # Decrease the indent level. Cannot be negative.
69
+ #
70
+ def outdent
71
+ self.current_indent -= 1 unless current_indent.zero?
72
+ end
73
+
74
+ # Return the parent class for a given type.
75
+ # Valid types are :message, :enum, and :service, otherwise an error
76
+ # will be thrown.
77
+ #
78
+ def parent_class(type)
79
+ case type
80
+ when :message then
81
+ PARENT_CLASS_MESSAGE
82
+ when :enum then
83
+ PARENT_CLASS_ENUM
84
+ when :service then
85
+ PARENT_CLASS_SERVICE
86
+ else
87
+ fail "Unknown parent class type #{type}: #{caller[0..5].join("\n")}"
88
+ end
89
+ end
90
+
91
+ # Print a class or module block, indicated by type.
92
+ # If a class, can be given a parent class to inherit from.
93
+ # If a block is given, call the block from within an indent block.
94
+ # Otherwise, end the block on the same line.
95
+ #
96
+ def print_block(name, parent_klass, type)
97
+ name = modulize(name)
98
+ block_def = "#{type} #{name}"
99
+ block_def += " < #{parent_class(parent_klass)}" if parent_klass
100
+
101
+ if block_given?
102
+ puts block_def
103
+ indent { yield }
104
+ puts "end"
105
+ puts
106
+ else
107
+ block_def += "; end"
108
+ puts block_def
109
+ end
110
+ end
111
+
112
+ # Use print_block to print a class, with optional parent class
113
+ # to inherit from. Accepts a block for use with print_block.
114
+ #
115
+ def print_class(name, parent_klass, &block)
116
+ print_block(name, parent_klass, :class, &block)
117
+ end
118
+
119
+ # Use print_block to print a module.
120
+ # Accepts a block for use with print_block.
121
+ #
122
+ def print_module(name, &block)
123
+ print_block(name, nil, :module, &block)
124
+ end
125
+
126
+ # Print a file require.
127
+ #
128
+ # print_require('foo/bar/baz') -> "require 'foo/bar/baz'"
129
+ #
130
+ def print_require(file, relative = false)
131
+ puts "require#{'_relative' if relative} '#{file}'"
132
+ end
133
+
134
+ # Puts the given message prefixed by the indent level.
135
+ # If no message is given print a newline.
136
+ #
137
+ def puts(message = nil)
138
+ if message
139
+ @io.puts((" " * current_indent) + message)
140
+ else
141
+ @io.puts
142
+ end
143
+ end
144
+
145
+ # Print the given message raw, no indent.
146
+ #
147
+ def print(contents)
148
+ @io.print(contents)
149
+ end
150
+
151
+ # Returns the contents of the underlying StringIO object.
152
+ #
153
+ def print_contents
154
+ @io.rewind
155
+ @io.read
156
+ end
157
+
158
+ end
159
+ end
160
+ end