Class: Gapic::Schema::Api

Inherits:
Object
  • Object
show all
Defined in:
lib/gapic/schema/api.rb

Overview

A representation of a full API.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(request) ⇒ Api

Initializes an API object with the file descriptors that represent the API.

Parameters:

  • The request object.



47
48
49
50
51
52
53
54
# File 'lib/gapic/schema/api.rb', line 47

def initialize request
  @request = request
  loader = Loader.new
  @files = request.proto_file.map do |fd|
    loader.load_file fd, request.file_to_generate.include?(fd.name)
  end
  @files.each { |f| f.parent = self }
end

Instance Attribute Details

#enums ⇒ Array<Enum> (readonly)

Returns The top level enums seen across all files in this API.

Returns:

  • The top level enums seen across all files in this API.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/gapic/schema/api.rb', line 39

class Api
  attr_accessor :request, :files

  # Initializes an API object with the file descriptors that represent the
  # API.
  #
  # @param request [Google::Protobuf::Compiler::CodeGeneratorRequest]
  #   The request object.
  def initialize request
    @request = request
    loader = Loader.new
    @files = request.proto_file.map do |fd|
      loader.load_file fd, request.file_to_generate.include?(fd.name)
    end
    @files.each { |f| f.parent = self }
  end

  def containing_api
    self
  end

  def containing_file
    nil
  end

  def lookup address
    address = address.join "." if address.is_a? Array
    @files.each do |f|
      lookup = f.lookup address
      return lookup if lookup
    end
    nil
  end

  def file_for address
    address = address.join "." if address.is_a? Array
    matching_files = @files.select { |f| f.lookup address }
    matching_files.first
  end

  def fix_file_path str
    str = String str
    return str if configuration[:overrides].nil?
    return str if configuration[:overrides][:file_path].nil?
    configuration[:overrides][:file_path].fetch str, str
  end

  def fix_namespace str
    str = String str
    return str if configuration[:overrides].nil?
    return str if configuration[:overrides][:namespace].nil?
    configuration[:overrides][:namespace].fetch str, str
  end

  def generate_files
    @files.select(&:generate?)
  end

  def services
    @files.map(&:services).flatten
  end

  def messages
    @files.map(&:messages).flatten
  end

  # Structured Hash representation of the parameter values.
  # @return [Hash]
  #   A Hash of the request parameters.
  def protoc_options
    @protoc_options ||= begin
      result = {}
      parameters = parse_parameter request.parameter
      parameters.each do |param_array|
        key = param_array.first
        next if key.empty?
        value = param_array[1..-1]
        value = value.first if value.size == 1
        value = nil if value.empty?
        result[str_to_key(key)] = value
      end
      result
    end
  end

  # Reconstructed string representation of the protoc options
  # @return [String]
  def protoc_parameter
    protoc_options.map do |k, v|
      v = Array(v).map do |s|
        s.gsub("\\", "\\\\\\\\").gsub(",", "\\\\,").gsub("=", "\\\\=")
      end.join("=")
      k = key_to_str k
      "#{k}=#{v}"
    end.join ","
  end

  # Structured representation of the samples configuration files.
  # @return [Array<Hash>]
  #   An array of the sample file hashes.
  def samples
    @samples ||= begin
      protoc_options["samples"].to_s.split(";").flat_map do |sample_path|
        YAML.load_file sample_path
      end.compact
    end
  end

  # Structured representation of the standalone samples configuration files.
  # @return [Array<Hash>]
  #   An array of the standalone sample configuration hashes.
  def standalone_samples
    @standalone_samples ||= begin
      supported_types = [
        "com.google.api.codegen.SampleConfigProto",
        "com.google.api.codegen.samplegen.v1p2.SampleConfigProto"
      ]
      supported_sample_types = [nil, "standalone"]
      samples.select { |sample_file| supported_types.include? sample_file["type"] }
             .select { |sample_file| sample_file["schema_version"] == "1.2.0" }
             .map { |sample_file| sample_file["samples"] }
             .flatten.compact
             .select { |sample_config| supported_sample_types.include? sample_config["sample_type"] }
    end
  end

  # Structured representation of the standalone test samples configuration files.
  # @return [Array<Hash>]
  #   An array of the standalone sample configuration hashes.
  def standalone_test_samples
    @standalone_test_samples ||= begin
      samples.select { |sample| sample["type"] == "test/samples" }
             .select { |sample| sample["schema_version"] == "1" || sample["schema_version"] == 1 }
             .map { |sample| sample["samples"] }
             .flatten.compact
    end
  end

  # Structured representation of the inline samples configuration files.
  # @return [Array<Hash>]
  #   An array of the incode sample configuration hashes, sorted by sample_type.
  def incode_samples
    @incode_samples ||= begin
      supported_types = [
        "com.google.api.codegen.SampleConfigProto",
        "com.google.api.codegen.samplegen.v1p2.SampleConfigProto"
      ]
      samples.select { |sample_file| supported_types.include? sample_file["type"] }
             .select { |sample_file| sample_file["schema_version"] == "1.2.0" }
             .map { |sample_file| sample_file["samples"] }
             .flatten.compact
             .select { |sample_config| sample_config["sample_type"]&.start_with? "incode/" }
             .sort_by { |sample_config| sample_config["sample_type"] }
    end
  end

  # Structured Hash representation of the configuration file.
  # @return [Hash]
  #   A Hash of the configuration values.
  def configuration
    @configuration ||= begin
      config_file = protoc_options["configuration"]
      config = config_file ? YAML.load_file(config_file) : {}
      protoc_options.each do |k, v|
        next if k == "configuration"
        branch = key_to_str(k).split(".").reverse.inject(v) { |m, s| { str_to_key(s) => m } }
        config = deep_merge config, branch
      end
      config
    end
  end

  # Whether the generate_path_helpers_output parameter was given in the configuration
  def generate_path_helpers_output_defined?
    configuration.key? :generate_path_helpers_output
  end

  # Sets the generate_path_helpers_output parameter in the configuration
  def generate_path_helpers_output= value
    configuration[:generate_path_helpers_output] = value
  end

  # Whether to generate path helpers for output as well as input messages
  def generate_path_helpers_output?
    # if not set in configuration, false by default
    configuration[:generate_path_helpers_output] ||= false
  end

  # Raw parsed json of the combined grpc service config files if provided
  # or an empty hash if no config was provided
  def grpc_service_config_raw
    @grpc_service_config_raw ||= begin
      filenames = protoc_options["grpc_service_config"].to_s.split ";"
      filenames.inject({}) do |running_hash, filename|
        file_hash = JSON.parse ::File.read filename
        deep_merge running_hash, file_hash
      end
    end
  end

  # Parsed grpc service config
  def grpc_service_config
    @grpc_service_config ||= begin
      Gapic::GrpcServiceConfig::Parser.parse grpc_service_config_raw
    end
  end

  private

  def parse_parameter str
    str.scan(/\\.|,|=|[^\\,=]+/)
       .each_with_object([[String.new]]) do |tok, arr|
         if tok == ","
           arr.append [String.new]
         elsif tok == "="
           arr.last.append String.new
         elsif tok.start_with? "\\"
           arr.last.last << tok[1]
         else
           arr.last.last << tok
         end
         arr
       end
  end

  def str_to_key str
    str = str.to_s
    str.start_with?(":") ? str[1..-1].to_sym : str
  end

  def key_to_str key
    key.is_a?(::Symbol) ? ":#{key}" : key.to_s
  end

  def deep_merge left, right
    left.merge right do |_k, lt, rt|
      if lt.is_a?(Hash) && rt.is_a?(Hash)
        deep_merge lt, rt
      elsif lt.is_a?(Array) && rt.is_a?(Array)
        lt + rt
      else
        rt
      end
    end
  end
end

#files ⇒ Array<File>

Returns The files represented by this API.

Returns:

  • The files represented by this API.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/gapic/schema/api.rb', line 39

class Api
  attr_accessor :request, :files

  # Initializes an API object with the file descriptors that represent the
  # API.
  #
  # @param request [Google::Protobuf::Compiler::CodeGeneratorRequest]
  #   The request object.
  def initialize request
    @request = request
    loader = Loader.new
    @files = request.proto_file.map do |fd|
      loader.load_file fd, request.file_to_generate.include?(fd.name)
    end
    @files.each { |f| f.parent = self }
  end

  def containing_api
    self
  end

  def containing_file
    nil
  end

  def lookup address
    address = address.join "." if address.is_a? Array
    @files.each do |f|
      lookup = f.lookup address
      return lookup if lookup
    end
    nil
  end

  def file_for address
    address = address.join "." if address.is_a? Array
    matching_files = @files.select { |f| f.lookup address }
    matching_files.first
  end

  def fix_file_path str
    str = String str
    return str if configuration[:overrides].nil?
    return str if configuration[:overrides][:file_path].nil?
    configuration[:overrides][:file_path].fetch str, str
  end

  def fix_namespace str
    str = String str
    return str if configuration[:overrides].nil?
    return str if configuration[:overrides][:namespace].nil?
    configuration[:overrides][:namespace].fetch str, str
  end

  def generate_files
    @files.select(&:generate?)
  end

  def services
    @files.map(&:services).flatten
  end

  def messages
    @files.map(&:messages).flatten
  end

  # Structured Hash representation of the parameter values.
  # @return [Hash]
  #   A Hash of the request parameters.
  def protoc_options
    @protoc_options ||= begin
      result = {}
      parameters = parse_parameter request.parameter
      parameters.each do |param_array|
        key = param_array.first
        next if key.empty?
        value = param_array[1..-1]
        value = value.first if value.size == 1
        value = nil if value.empty?
        result[str_to_key(key)] = value
      end
      result
    end
  end

  # Reconstructed string representation of the protoc options
  # @return [String]
  def protoc_parameter
    protoc_options.map do |k, v|
      v = Array(v).map do |s|
        s.gsub("\\", "\\\\\\\\").gsub(",", "\\\\,").gsub("=", "\\\\=")
      end.join("=")
      k = key_to_str k
      "#{k}=#{v}"
    end.join ","
  end

  # Structured representation of the samples configuration files.
  # @return [Array<Hash>]
  #   An array of the sample file hashes.
  def samples
    @samples ||= begin
      protoc_options["samples"].to_s.split(";").flat_map do |sample_path|
        YAML.load_file sample_path
      end.compact
    end
  end

  # Structured representation of the standalone samples configuration files.
  # @return [Array<Hash>]
  #   An array of the standalone sample configuration hashes.
  def standalone_samples
    @standalone_samples ||= begin
      supported_types = [
        "com.google.api.codegen.SampleConfigProto",
        "com.google.api.codegen.samplegen.v1p2.SampleConfigProto"
      ]
      supported_sample_types = [nil, "standalone"]
      samples.select { |sample_file| supported_types.include? sample_file["type"] }
             .select { |sample_file| sample_file["schema_version"] == "1.2.0" }
             .map { |sample_file| sample_file["samples"] }
             .flatten.compact
             .select { |sample_config| supported_sample_types.include? sample_config["sample_type"] }
    end
  end

  # Structured representation of the standalone test samples configuration files.
  # @return [Array<Hash>]
  #   An array of the standalone sample configuration hashes.
  def standalone_test_samples
    @standalone_test_samples ||= begin
      samples.select { |sample| sample["type"] == "test/samples" }
             .select { |sample| sample["schema_version"] == "1" || sample["schema_version"] == 1 }
             .map { |sample| sample["samples"] }
             .flatten.compact
    end
  end

  # Structured representation of the inline samples configuration files.
  # @return [Array<Hash>]
  #   An array of the incode sample configuration hashes, sorted by sample_type.
  def incode_samples
    @incode_samples ||= begin
      supported_types = [
        "com.google.api.codegen.SampleConfigProto",
        "com.google.api.codegen.samplegen.v1p2.SampleConfigProto"
      ]
      samples.select { |sample_file| supported_types.include? sample_file["type"] }
             .select { |sample_file| sample_file["schema_version"] == "1.2.0" }
             .map { |sample_file| sample_file["samples"] }
             .flatten.compact
             .select { |sample_config| sample_config["sample_type"]&.start_with? "incode/" }
             .sort_by { |sample_config| sample_config["sample_type"] }
    end
  end

  # Structured Hash representation of the configuration file.
  # @return [Hash]
  #   A Hash of the configuration values.
  def configuration
    @configuration ||= begin
      config_file = protoc_options["configuration"]
      config = config_file ? YAML.load_file(config_file) : {}
      protoc_options.each do |k, v|
        next if k == "configuration"
        branch = key_to_str(k).split(".").reverse.inject(v) { |m, s| { str_to_key(s) => m } }
        config = deep_merge config, branch
      end
      config
    end
  end

  # Whether the generate_path_helpers_output parameter was given in the configuration
  def generate_path_helpers_output_defined?
    configuration.key? :generate_path_helpers_output
  end

  # Sets the generate_path_helpers_output parameter in the configuration
  def generate_path_helpers_output= value
    configuration[:generate_path_helpers_output] = value
  end

  # Whether to generate path helpers for output as well as input messages
  def generate_path_helpers_output?
    # if not set in configuration, false by default
    configuration[:generate_path_helpers_output] ||= false
  end

  # Raw parsed json of the combined grpc service config files if provided
  # or an empty hash if no config was provided
  def grpc_service_config_raw
    @grpc_service_config_raw ||= begin
      filenames = protoc_options["grpc_service_config"].to_s.split ";"
      filenames.inject({}) do |running_hash, filename|
        file_hash = JSON.parse ::File.read filename
        deep_merge running_hash, file_hash
      end
    end
  end

  # Parsed grpc service config
  def grpc_service_config
    @grpc_service_config ||= begin
      Gapic::GrpcServiceConfig::Parser.parse grpc_service_config_raw
    end
  end

  private

  def parse_parameter str
    str.scan(/\\.|,|=|[^\\,=]+/)
       .each_with_object([[String.new]]) do |tok, arr|
         if tok == ","
           arr.append [String.new]
         elsif tok == "="
           arr.last.append String.new
         elsif tok.start_with? "\\"
           arr.last.last << tok[1]
         else
           arr.last.last << tok
         end
         arr
       end
  end

  def str_to_key str
    str = str.to_s
    str.start_with?(":") ? str[1..-1].to_sym : str
  end

  def key_to_str key
    key.is_a?(::Symbol) ? ":#{key}" : key.to_s
  end

  def deep_merge left, right
    left.merge right do |_k, lt, rt|
      if lt.is_a?(Hash) && rt.is_a?(Hash)
        deep_merge lt, rt
      elsif lt.is_a?(Array) && rt.is_a?(Array)
        lt + rt
      else
        rt
      end
    end
  end
end

#messages ⇒ Array<Message> (readonly)

Returns The top level messages seen across all files in this API.

Returns:

  • The top level messages seen across all files in this API.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/gapic/schema/api.rb', line 39

class Api
  attr_accessor :request, :files

  # Initializes an API object with the file descriptors that represent the
  # API.
  #
  # @param request [Google::Protobuf::Compiler::CodeGeneratorRequest]
  #   The request object.
  def initialize request
    @request = request
    loader = Loader.new
    @files = request.proto_file.map do |fd|
      loader.load_file fd, request.file_to_generate.include?(fd.name)
    end
    @files.each { |f| f.parent = self }
  end

  def containing_api
    self
  end

  def containing_file
    nil
  end

  def lookup address
    address = address.join "." if address.is_a? Array
    @files.each do |f|
      lookup = f.lookup address
      return lookup if lookup
    end
    nil
  end

  def file_for address
    address = address.join "." if address.is_a? Array
    matching_files = @files.select { |f| f.lookup address }
    matching_files.first
  end

  def fix_file_path str
    str = String str
    return str if configuration[:overrides].nil?
    return str if configuration[:overrides][:file_path].nil?
    configuration[:overrides][:file_path].fetch str, str
  end

  def fix_namespace str
    str = String str
    return str if configuration[:overrides].nil?
    return str if configuration[:overrides][:namespace].nil?
    configuration[:overrides][:namespace].fetch str, str
  end

  def generate_files
    @files.select(&:generate?)
  end

  def services
    @files.map(&:services).flatten
  end

  def messages
    @files.map(&:messages).flatten
  end

  # Structured Hash representation of the parameter values.
  # @return [Hash]
  #   A Hash of the request parameters.
  def protoc_options
    @protoc_options ||= begin
      result = {}
      parameters = parse_parameter request.parameter
      parameters.each do |param_array|
        key = param_array.first
        next if key.empty?
        value = param_array[1..-1]
        value = value.first if value.size == 1
        value = nil if value.empty?
        result[str_to_key(key)] = value
      end
      result
    end
  end

  # Reconstructed string representation of the protoc options
  # @return [String]
  def protoc_parameter
    protoc_options.map do |k, v|
      v = Array(v).map do |s|
        s.gsub("\\", "\\\\\\\\").gsub(",", "\\\\,").gsub("=", "\\\\=")
      end.join("=")
      k = key_to_str k
      "#{k}=#{v}"
    end.join ","
  end

  # Structured representation of the samples configuration files.
  # @return [Array<Hash>]
  #   An array of the sample file hashes.
  def samples
    @samples ||= begin
      protoc_options["samples"].to_s.split(";").flat_map do |sample_path|
        YAML.load_file sample_path
      end.compact
    end
  end

  # Structured representation of the standalone samples configuration files.
  # @return [Array<Hash>]
  #   An array of the standalone sample configuration hashes.
  def standalone_samples
    @standalone_samples ||= begin
      supported_types = [
        "com.google.api.codegen.SampleConfigProto",
        "com.google.api.codegen.samplegen.v1p2.SampleConfigProto"
      ]
      supported_sample_types = [nil, "standalone"]
      samples.select { |sample_file| supported_types.include? sample_file["type"] }
             .select { |sample_file| sample_file["schema_version"] == "1.2.0" }
             .map { |sample_file| sample_file["samples"] }
             .flatten.compact
             .select { |sample_config| supported_sample_types.include? sample_config["sample_type"] }
    end
  end

  # Structured representation of the standalone test samples configuration files.
  # @return [Array<Hash>]
  #   An array of the standalone sample configuration hashes.
  def standalone_test_samples
    @standalone_test_samples ||= begin
      samples.select { |sample| sample["type"] == "test/samples" }
             .select { |sample| sample["schema_version"] == "1" || sample["schema_version"] == 1 }
             .map { |sample| sample["samples"] }
             .flatten.compact
    end
  end

  # Structured representation of the inline samples configuration files.
  # @return [Array<Hash>]
  #   An array of the incode sample configuration hashes, sorted by sample_type.
  def incode_samples
    @incode_samples ||= begin
      supported_types = [
        "com.google.api.codegen.SampleConfigProto",
        "com.google.api.codegen.samplegen.v1p2.SampleConfigProto"
      ]
      samples.select { |sample_file| supported_types.include? sample_file["type"] }
             .select { |sample_file| sample_file["schema_version"] == "1.2.0" }
             .map { |sample_file| sample_file["samples"] }
             .flatten.compact
             .select { |sample_config| sample_config["sample_type"]&.start_with? "incode/" }
             .sort_by { |sample_config| sample_config["sample_type"] }
    end
  end

  # Structured Hash representation of the configuration file.
  # @return [Hash]
  #   A Hash of the configuration values.
  def configuration
    @configuration ||= begin
      config_file = protoc_options["configuration"]
      config = config_file ? YAML.load_file(config_file) : {}
      protoc_options.each do |k, v|
        next if k == "configuration"
        branch = key_to_str(k).split(".").reverse.inject(v) { |m, s| { str_to_key(s) => m } }
        config = deep_merge config, branch
      end
      config
    end
  end

  # Whether the generate_path_helpers_output parameter was given in the configuration
  def generate_path_helpers_output_defined?
    configuration.key? :generate_path_helpers_output
  end

  # Sets the generate_path_helpers_output parameter in the configuration
  def generate_path_helpers_output= value
    configuration[:generate_path_helpers_output] = value
  end

  # Whether to generate path helpers for output as well as input messages
  def generate_path_helpers_output?
    # if not set in configuration, false by default
    configuration[:generate_path_helpers_output] ||= false
  end

  # Raw parsed json of the combined grpc service config files if provided
  # or an empty hash if no config was provided
  def grpc_service_config_raw
    @grpc_service_config_raw ||= begin
      filenames = protoc_options["grpc_service_config"].to_s.split ";"
      filenames.inject({}) do |running_hash, filename|
        file_hash = JSON.parse ::File.read filename
        deep_merge running_hash, file_hash
      end
    end
  end

  # Parsed grpc service config
  def grpc_service_config
    @grpc_service_config ||= begin
      Gapic::GrpcServiceConfig::Parser.parse grpc_service_config_raw
    end
  end

  private

  def parse_parameter str
    str.scan(/\\.|,|=|[^\\,=]+/)
       .each_with_object([[String.new]]) do |tok, arr|
         if tok == ","
           arr.append [String.new]
         elsif tok == "="
           arr.last.append String.new
         elsif tok.start_with? "\\"
           arr.last.last << tok[1]
         else
           arr.last.last << tok
         end
         arr
       end
  end

  def str_to_key str
    str = str.to_s
    str.start_with?(":") ? str[1..-1].to_sym : str
  end

  def key_to_str key
    key.is_a?(::Symbol) ? ":#{key}" : key.to_s
  end

  def deep_merge left, right
    left.merge right do |_k, lt, rt|
      if lt.is_a?(Hash) && rt.is_a?(Hash)
        deep_merge lt, rt
      elsif lt.is_a?(Array) && rt.is_a?(Array)
        lt + rt
      else
        rt
      end
    end
  end
end

#request ⇒ Object

Returns the value of attribute request.



40
41
42
# File 'lib/gapic/schema/api.rb', line 40

def request
  @request
end

#services ⇒ <Array<Service>] The services seen across all files in this API. (readonly)

Returns <Array] The services seen across all files in this API.

Returns:

  • <Array] The services seen across all files in this API.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/gapic/schema/api.rb', line 39

class Api
  attr_accessor :request, :files

  # Initializes an API object with the file descriptors that represent the
  # API.
  #
  # @param request [Google::Protobuf::Compiler::CodeGeneratorRequest]
  #   The request object.
  def initialize request
    @request = request
    loader = Loader.new
    @files = request.proto_file.map do |fd|
      loader.load_file fd, request.file_to_generate.include?(fd.name)
    end
    @files.each { |f| f.parent = self }
  end

  def containing_api
    self
  end

  def containing_file
    nil
  end

  def lookup address
    address = address.join "." if address.is_a? Array
    @files.each do |f|
      lookup = f.lookup address
      return lookup if lookup
    end
    nil
  end

  def file_for address
    address = address.join "." if address.is_a? Array
    matching_files = @files.select { |f| f.lookup address }
    matching_files.first
  end

  def fix_file_path str
    str = String str
    return str if configuration[:overrides].nil?
    return str if configuration[:overrides][:file_path].nil?
    configuration[:overrides][:file_path].fetch str, str
  end

  def fix_namespace str
    str = String str
    return str if configuration[:overrides].nil?
    return str if configuration[:overrides][:namespace].nil?
    configuration[:overrides][:namespace].fetch str, str
  end

  def generate_files
    @files.select(&:generate?)
  end

  def services
    @files.map(&:services).flatten
  end

  def messages
    @files.map(&:messages).flatten
  end

  # Structured Hash representation of the parameter values.
  # @return [Hash]
  #   A Hash of the request parameters.
  def protoc_options
    @protoc_options ||= begin
      result = {}
      parameters = parse_parameter request.parameter
      parameters.each do |param_array|
        key = param_array.first
        next if key.empty?
        value = param_array[1..-1]
        value = value.first if value.size == 1
        value = nil if value.empty?
        result[str_to_key(key)] = value
      end
      result
    end
  end

  # Reconstructed string representation of the protoc options
  # @return [String]
  def protoc_parameter
    protoc_options.map do |k, v|
      v = Array(v).map do |s|
        s.gsub("\\", "\\\\\\\\").gsub(",", "\\\\,").gsub("=", "\\\\=")
      end.join("=")
      k = key_to_str k
      "#{k}=#{v}"
    end.join ","
  end

  # Structured representation of the samples configuration files.
  # @return [Array<Hash>]
  #   An array of the sample file hashes.
  def samples
    @samples ||= begin
      protoc_options["samples"].to_s.split(";").flat_map do |sample_path|
        YAML.load_file sample_path
      end.compact
    end
  end

  # Structured representation of the standalone samples configuration files.
  # @return [Array<Hash>]
  #   An array of the standalone sample configuration hashes.
  def standalone_samples
    @standalone_samples ||= begin
      supported_types = [
        "com.google.api.codegen.SampleConfigProto",
        "com.google.api.codegen.samplegen.v1p2.SampleConfigProto"
      ]
      supported_sample_types = [nil, "standalone"]
      samples.select { |sample_file| supported_types.include? sample_file["type"] }
             .select { |sample_file| sample_file["schema_version"] == "1.2.0" }
             .map { |sample_file| sample_file["samples"] }
             .flatten.compact
             .select { |sample_config| supported_sample_types.include? sample_config["sample_type"] }
    end
  end

  # Structured representation of the standalone test samples configuration files.
  # @return [Array<Hash>]
  #   An array of the standalone sample configuration hashes.
  def standalone_test_samples
    @standalone_test_samples ||= begin
      samples.select { |sample| sample["type"] == "test/samples" }
             .select { |sample| sample["schema_version"] == "1" || sample["schema_version"] == 1 }
             .map { |sample| sample["samples"] }
             .flatten.compact
    end
  end

  # Structured representation of the inline samples configuration files.
  # @return [Array<Hash>]
  #   An array of the incode sample configuration hashes, sorted by sample_type.
  def incode_samples
    @incode_samples ||= begin
      supported_types = [
        "com.google.api.codegen.SampleConfigProto",
        "com.google.api.codegen.samplegen.v1p2.SampleConfigProto"
      ]
      samples.select { |sample_file| supported_types.include? sample_file["type"] }
             .select { |sample_file| sample_file["schema_version"] == "1.2.0" }
             .map { |sample_file| sample_file["samples"] }
             .flatten.compact
             .select { |sample_config| sample_config["sample_type"]&.start_with? "incode/" }
             .sort_by { |sample_config| sample_config["sample_type"] }
    end
  end

  # Structured Hash representation of the configuration file.
  # @return [Hash]
  #   A Hash of the configuration values.
  def configuration
    @configuration ||= begin
      config_file = protoc_options["configuration"]
      config = config_file ? YAML.load_file(config_file) : {}
      protoc_options.each do |k, v|
        next if k == "configuration"
        branch = key_to_str(k).split(".").reverse.inject(v) { |m, s| { str_to_key(s) => m } }
        config = deep_merge config, branch
      end
      config
    end
  end

  # Whether the generate_path_helpers_output parameter was given in the configuration
  def generate_path_helpers_output_defined?
    configuration.key? :generate_path_helpers_output
  end

  # Sets the generate_path_helpers_output parameter in the configuration
  def generate_path_helpers_output= value
    configuration[:generate_path_helpers_output] = value
  end

  # Whether to generate path helpers for output as well as input messages
  def generate_path_helpers_output?
    # if not set in configuration, false by default
    configuration[:generate_path_helpers_output] ||= false
  end

  # Raw parsed json of the combined grpc service config files if provided
  # or an empty hash if no config was provided
  def grpc_service_config_raw
    @grpc_service_config_raw ||= begin
      filenames = protoc_options["grpc_service_config"].to_s.split ";"
      filenames.inject({}) do |running_hash, filename|
        file_hash = JSON.parse ::File.read filename
        deep_merge running_hash, file_hash
      end
    end
  end

  # Parsed grpc service config
  def grpc_service_config
    @grpc_service_config ||= begin
      Gapic::GrpcServiceConfig::Parser.parse grpc_service_config_raw
    end
  end

  private

  def parse_parameter str
    str.scan(/\\.|,|=|[^\\,=]+/)
       .each_with_object([[String.new]]) do |tok, arr|
         if tok == ","
           arr.append [String.new]
         elsif tok == "="
           arr.last.append String.new
         elsif tok.start_with? "\\"
           arr.last.last << tok[1]
         else
           arr.last.last << tok
         end
         arr
       end
  end

  def str_to_key str
    str = str.to_s
    str.start_with?(":") ? str[1..-1].to_sym : str
  end

  def key_to_str key
    key.is_a?(::Symbol) ? ":#{key}" : key.to_s
  end

  def deep_merge left, right
    left.merge right do |_k, lt, rt|
      if lt.is_a?(Hash) && rt.is_a?(Hash)
        deep_merge lt, rt
      elsif lt.is_a?(Array) && rt.is_a?(Array)
        lt + rt
      else
        rt
      end
    end
  end
end

Instance Method Details

#configuration ⇒ Hash

Structured Hash representation of the configuration file.

Returns:

  • A Hash of the configuration values.



198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/gapic/schema/api.rb', line 198

def configuration
  @configuration ||= begin
    config_file = protoc_options["configuration"]
    config = config_file ? YAML.load_file(config_file) : {}
    protoc_options.each do |k, v|
      next if k == "configuration"
      branch = key_to_str(k).split(".").reverse.inject(v) { |m, s| { str_to_key(s) => m } }
      config = deep_merge config, branch
    end
    config
  end
end

#containing_api ⇒ Object



56
57
58
# File 'lib/gapic/schema/api.rb', line 56

def containing_api
  self
end

#containing_file ⇒ Object



60
61
62
# File 'lib/gapic/schema/api.rb', line 60

def containing_file
  nil
end

#file_for(address) ⇒ Object



73
74
75
76
77
# File 'lib/gapic/schema/api.rb', line 73

def file_for address
  address = address.join "." if address.is_a? Array
  matching_files = @files.select { |f| f.lookup address }
  matching_files.first
end

#fix_file_path(str) ⇒ Object



79
80
81
82
83
84
# File 'lib/gapic/schema/api.rb', line 79

def fix_file_path str
  str = String str
  return str if configuration[:overrides].nil?
  return str if configuration[:overrides][:file_path].nil?
  configuration[:overrides][:file_path].fetch str, str
end

#fix_namespace(str) ⇒ Object



86
87
88
89
90
91
# File 'lib/gapic/schema/api.rb', line 86

def fix_namespace str
  str = String str
  return str if configuration[:overrides].nil?
  return str if configuration[:overrides][:namespace].nil?
  configuration[:overrides][:namespace].fetch str, str
end

#generate_files ⇒ Object



93
94
95
# File 'lib/gapic/schema/api.rb', line 93

def generate_files
  @files.select(&:generate?)
end

#generate_path_helpers_output=(value) ⇒ Object

Sets the generate_path_helpers_output parameter in the configuration



217
218
219
# File 'lib/gapic/schema/api.rb', line 217

def generate_path_helpers_output= value
  configuration[:generate_path_helpers_output] = value
end

#generate_path_helpers_output? ⇒ Boolean

Whether to generate path helpers for output as well as input messages

Returns:



222
223
224
225
# File 'lib/gapic/schema/api.rb', line 222

def generate_path_helpers_output?
  # if not set in configuration, false by default
  configuration[:generate_path_helpers_output] ||= false
end

#generate_path_helpers_output_defined? ⇒ Boolean

Whether the generate_path_helpers_output parameter was given in the configuration

Returns:



212
213
214
# File 'lib/gapic/schema/api.rb', line 212

def generate_path_helpers_output_defined?
  configuration.key? :generate_path_helpers_output
end

#grpc_service_config ⇒ Object

Parsed grpc service config



240
241
242
243
244
# File 'lib/gapic/schema/api.rb', line 240

def grpc_service_config
  @grpc_service_config ||= begin
    Gapic::GrpcServiceConfig::Parser.parse grpc_service_config_raw
  end
end

#grpc_service_config_raw ⇒ Object

Raw parsed json of the combined grpc service config files if provided or an empty hash if no config was provided



229
230
231
232
233
234
235
236
237
# File 'lib/gapic/schema/api.rb', line 229

def grpc_service_config_raw
  @grpc_service_config_raw ||= begin
    filenames = protoc_options["grpc_service_config"].to_s.split ";"
    filenames.inject({}) do |running_hash, filename|
      file_hash = JSON.parse ::File.read filename
      deep_merge running_hash, file_hash
    end
  end
end

#incode_samples ⇒ Array<Hash>

Structured representation of the inline samples configuration files.

Returns:

  • An array of the incode sample configuration hashes, sorted by sample_type.



180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/gapic/schema/api.rb', line 180

def incode_samples
  @incode_samples ||= begin
    supported_types = [
      "com.google.api.codegen.SampleConfigProto",
      "com.google.api.codegen.samplegen.v1p2.SampleConfigProto"
    ]
    samples.select { |sample_file| supported_types.include? sample_file["type"] }
           .select { |sample_file| sample_file["schema_version"] == "1.2.0" }
           .map { |sample_file| sample_file["samples"] }
           .flatten.compact
           .select { |sample_config| sample_config["sample_type"]&.start_with? "incode/" }
           .sort_by { |sample_config| sample_config["sample_type"] }
  end
end

#lookup(address) ⇒ Object



64
65
66
67
68
69
70
71
# File 'lib/gapic/schema/api.rb', line 64

def lookup address
  address = address.join "." if address.is_a? Array
  @files.each do |f|
    lookup = f.lookup address
    return lookup if lookup
  end
  nil
end

#protoc_options ⇒ Hash

Structured Hash representation of the parameter values.

Returns:

  • A Hash of the request parameters.



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/gapic/schema/api.rb', line 108

def protoc_options
  @protoc_options ||= begin
    result = {}
    parameters = parse_parameter request.parameter
    parameters.each do |param_array|
      key = param_array.first
      next if key.empty?
      value = param_array[1..-1]
      value = value.first if value.size == 1
      value = nil if value.empty?
      result[str_to_key(key)] = value
    end
    result
  end
end

#protoc_parameter ⇒ String

Reconstructed string representation of the protoc options

Returns:



126
127
128
129
130
131
132
133
134
# File 'lib/gapic/schema/api.rb', line 126

def protoc_parameter
  protoc_options.map do |k, v|
    v = Array(v).map do |s|
      s.gsub("\\", "\\\\\\\\").gsub(",", "\\\\,").gsub("=", "\\\\=")
    end.join("=")
    k = key_to_str k
    "#{k}=#{v}"
  end.join ","
end

#samples ⇒ Array<Hash>

Structured representation of the samples configuration files.

Returns:

  • An array of the sample file hashes.



139
140
141
142
143
144
145
# File 'lib/gapic/schema/api.rb', line 139

def samples
  @samples ||= begin
    protoc_options["samples"].to_s.split(";").flat_map do |sample_path|
      YAML.load_file sample_path
    end.compact
  end
end

#standalone_samples ⇒ Array<Hash>

Structured representation of the standalone samples configuration files.

Returns:

  • An array of the standalone sample configuration hashes.



150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/gapic/schema/api.rb', line 150

def standalone_samples
  @standalone_samples ||= begin
    supported_types = [
      "com.google.api.codegen.SampleConfigProto",
      "com.google.api.codegen.samplegen.v1p2.SampleConfigProto"
    ]
    supported_sample_types = [nil, "standalone"]
    samples.select { |sample_file| supported_types.include? sample_file["type"] }
           .select { |sample_file| sample_file["schema_version"] == "1.2.0" }
           .map { |sample_file| sample_file["samples"] }
           .flatten.compact
           .select { |sample_config| supported_sample_types.include? sample_config["sample_type"] }
  end
end

#standalone_test_samples ⇒ Array<Hash>

Structured representation of the standalone test samples configuration files.

Returns:

  • An array of the standalone sample configuration hashes.



168
169
170
171
172
173
174
175
# File 'lib/gapic/schema/api.rb', line 168

def standalone_test_samples
  @standalone_test_samples ||= begin
    samples.select { |sample| sample["type"] == "test/samples" }
           .select { |sample| sample["schema_version"] == "1" || sample["schema_version"] == 1 }
           .map { |sample| sample["samples"] }
           .flatten.compact
  end
end