Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,30 @@
# @return [Object] Returns the model itself
def self.build_from_hash(attributes)
return nil unless attributes.is_a?(Hash)
{{#parent}}
super(attributes)
{{/parent}}
attributes = attributes.transform_keys(&:to_sym)
# collect the attributes this model knows about, including the ones
# defined in its parent(s), so an allOf child also maps its inherited
# attributes (the child's own declaration wins on a name clash)
types = openapi_types
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
map = attribute_map
klass = superclass
while klass.respond_to?(:openapi_types)
types = klass.openapi_types.merge(types)
map = klass.attribute_map.merge(map)
klass = klass.superclass
end
transformed_hash = {}
openapi_types.each_pair do |key, type|
if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
types.each_pair do |key, type|
if attributes.key?(map[key]) && attributes[map[key]].nil?
transformed_hash["#{key}"] = nil
elsif type =~ /\AArray<(.*)>/i
# check to ensure the input is an array given that the attribute
# is documented as an array but the input is not
if attributes[attribute_map[key]].is_a?(Array)
transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
if attributes[map[key]].is_a?(Array)
transformed_hash["#{key}"] = attributes[map[key]].map { |v| _deserialize($1, v) }
end
elsif !attributes[attribute_map[key]].nil?
transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
elsif !attributes[map[key]].nil?
transformed_hash["#{key}"] = _deserialize(type, attributes[map[key]])
end
end
new(transformed_hash)
Expand All @@ -27,11 +35,24 @@
# Returns the object in the form of hash
# @return [Hash] Returns the object in the form of hash
def to_hash
hash = {{^parent}}{}{{/parent}}{{#parent}}super{{/parent}}
self.class.attribute_map.each_pair do |attr, param|
# collect the attributes this model knows about, including the ones defined
# in its parent(s): attribute_map and openapi_nullable resolve to the child
# class in every ancestor frame, so the inherited super chain only repeated
# the child's own attributes and dropped the inherited ones
map = self.class.attribute_map
nullable = self.class.openapi_nullable
klass = self.class.superclass
while klass.respond_to?(:openapi_types)
# an ancestor's nullability only applies to attributes no nearer class redeclares
nullable |= klass.openapi_nullable & (klass.attribute_map.keys - map.keys)
map = klass.attribute_map.merge(map)
klass = klass.superclass
end
hash = {}
map.each_pair do |attr, param|
value = self.send(attr)
if value.nil?
is_nullable = self.class.openapi_nullable.include?(attr)
is_nullable = nullable.include?(attr)
next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
=end

require 'date'
require 'set'
require 'time'

module {{moduleName}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -762,4 +762,50 @@ public void testQueryParamJsonSerializationSetsQueryIsJsonMimeType() {
assertTrue(op.queryParams.stream().allMatch(p -> p.queryIsJsonMimeType),
"All content:application/json query params should have queryIsJsonMimeType=true");
}

@Test(description = "an allOf child's build_from_hash maps the attributes inherited from its parents")
public void testBuildFromHashMapsInheritedAttributes() throws Exception {
final File output = Files.createTempDirectory("test").toFile();
output.deleteOnExit();

final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/allOf_composition_discriminator.yaml");
CodegenConfig codegenConfig = new RubyClientCodegen();
codegenConfig.setOutputDir(output.getAbsolutePath());

ClientOptInput clientOptInput = new ClientOptInput().openAPI(openAPI).config(codegenConfig);
new DefaultGenerator().opts(clientOptInput).generate();

// Lizard < Reptile < Pet: the walk has to collect openapi_types and
// attribute_map from the whole ancestry, not just the child's own
java.nio.file.Path lizard = new File(output, "lib/openapi_client/models/lizard.rb").toPath();
TestUtils.assertFileContains(lizard,
"types = openapi_types\n" +
" map = attribute_map\n" +
" klass = superclass\n" +
" while klass.respond_to?(:openapi_types)\n" +
" types = klass.openapi_types.merge(types)\n" +
" map = klass.attribute_map.merge(map)\n" +
" klass = klass.superclass\n" +
" end");
// the discarded-result super call is gone: openapi_types/attribute_map
// dispatch on the child class in the parent's frame too, so it never
// contributed the parent's attributes - it only built a second instance
TestUtils.assertFileNotContains(lizard, "super(attributes)\n attributes = attributes.transform_keys(&:to_sym)");
// to_hash walks the same ancestry: attribute_map/openapi_nullable dispatch on the
// child in every ancestor frame, so the old super chain only repeated the child's
// own attributes and a round-tripped model lost its inherited fields
TestUtils.assertFileContains(lizard,
"map = self.class.attribute_map\n" +
" nullable = self.class.openapi_nullable\n" +
" klass = self.class.superclass\n" +
" while klass.respond_to?(:openapi_types)\n" +
" # an ancestor's nullability only applies to attributes no nearer class redeclares\n" +
" nullable |= klass.openapi_nullable & (klass.attribute_map.keys - map.keys)\n" +
" map = klass.attribute_map.merge(map)\n" +
" klass = klass.superclass\n" +
" end");
// the walk evaluates openapi_nullable eagerly, so Set must be loaded on rubies
// where it is not yet a builtin autoload
TestUtils.assertFileContains(lizard, "require 'set'");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
=end

require 'date'
require 'set'
require 'time'

module OpenapiClient
Expand Down Expand Up @@ -118,18 +119,29 @@ def hash
def self.build_from_hash(attributes)
return nil unless attributes.is_a?(Hash)
attributes = attributes.transform_keys(&:to_sym)
# collect the attributes this model knows about, including the ones
# defined in its parent(s), so an allOf child also maps its inherited
# attributes (the child's own declaration wins on a name clash)
types = openapi_types
map = attribute_map
klass = superclass
while klass.respond_to?(:openapi_types)
types = klass.openapi_types.merge(types)
map = klass.attribute_map.merge(map)
klass = klass.superclass
end
transformed_hash = {}
openapi_types.each_pair do |key, type|
if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
types.each_pair do |key, type|
if attributes.key?(map[key]) && attributes[map[key]].nil?
transformed_hash["#{key}"] = nil
elsif type =~ /\AArray<(.*)>/i
# check to ensure the input is an array given that the attribute
# is documented as an array but the input is not
if attributes[attribute_map[key]].is_a?(Array)
transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
if attributes[map[key]].is_a?(Array)
transformed_hash["#{key}"] = attributes[map[key]].map { |v| _deserialize($1, v) }
end
elsif !attributes[attribute_map[key]].nil?
transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
elsif !attributes[map[key]].nil?
transformed_hash["#{key}"] = _deserialize(type, attributes[map[key]])
end
end
new(transformed_hash)
Expand All @@ -138,11 +150,24 @@ def self.build_from_hash(attributes)
# Returns the object in the form of hash
# @return [Hash] Returns the object in the form of hash
def to_hash
# collect the attributes this model knows about, including the ones defined
# in its parent(s): attribute_map and openapi_nullable resolve to the child
# class in every ancestor frame, so the inherited super chain only repeated
# the child's own attributes and dropped the inherited ones
map = self.class.attribute_map
nullable = self.class.openapi_nullable
klass = self.class.superclass
while klass.respond_to?(:openapi_types)
# an ancestor's nullability only applies to attributes no nearer class redeclares
nullable |= klass.openapi_nullable & (klass.attribute_map.keys - map.keys)
map = klass.attribute_map.merge(map)
klass = klass.superclass
end
hash = {}
self.class.attribute_map.each_pair do |attr, param|
map.each_pair do |attr, param|
value = self.send(attr)
if value.nil?
is_nullable = self.class.openapi_nullable.include?(attr)
is_nullable = nullable.include?(attr)
next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
=end

require 'date'
require 'set'
require 'time'

module OpenapiClient
Expand Down Expand Up @@ -118,18 +119,29 @@ def hash
def self.build_from_hash(attributes)
return nil unless attributes.is_a?(Hash)
attributes = attributes.transform_keys(&:to_sym)
# collect the attributes this model knows about, including the ones
# defined in its parent(s), so an allOf child also maps its inherited
# attributes (the child's own declaration wins on a name clash)
types = openapi_types
map = attribute_map
klass = superclass
while klass.respond_to?(:openapi_types)
types = klass.openapi_types.merge(types)
map = klass.attribute_map.merge(map)
klass = klass.superclass
end
transformed_hash = {}
openapi_types.each_pair do |key, type|
if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
types.each_pair do |key, type|
if attributes.key?(map[key]) && attributes[map[key]].nil?
transformed_hash["#{key}"] = nil
elsif type =~ /\AArray<(.*)>/i
# check to ensure the input is an array given that the attribute
# is documented as an array but the input is not
if attributes[attribute_map[key]].is_a?(Array)
transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
if attributes[map[key]].is_a?(Array)
transformed_hash["#{key}"] = attributes[map[key]].map { |v| _deserialize($1, v) }
end
elsif !attributes[attribute_map[key]].nil?
transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
elsif !attributes[map[key]].nil?
transformed_hash["#{key}"] = _deserialize(type, attributes[map[key]])
end
end
new(transformed_hash)
Expand All @@ -138,11 +150,24 @@ def self.build_from_hash(attributes)
# Returns the object in the form of hash
# @return [Hash] Returns the object in the form of hash
def to_hash
# collect the attributes this model knows about, including the ones defined
# in its parent(s): attribute_map and openapi_nullable resolve to the child
# class in every ancestor frame, so the inherited super chain only repeated
# the child's own attributes and dropped the inherited ones
map = self.class.attribute_map
nullable = self.class.openapi_nullable
klass = self.class.superclass
while klass.respond_to?(:openapi_types)
# an ancestor's nullability only applies to attributes no nearer class redeclares
nullable |= klass.openapi_nullable & (klass.attribute_map.keys - map.keys)
map = klass.attribute_map.merge(map)
klass = klass.superclass
end
hash = {}
self.class.attribute_map.each_pair do |attr, param|
map.each_pair do |attr, param|
value = self.send(attr)
if value.nil?
is_nullable = self.class.openapi_nullable.include?(attr)
is_nullable = nullable.include?(attr)
next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
=end

require 'date'
require 'set'
require 'time'

module OpenapiClient
Expand Down Expand Up @@ -161,20 +162,30 @@ def hash
# @return [Object] Returns the model itself
def self.build_from_hash(attributes)
return nil unless attributes.is_a?(Hash)
super(attributes)
attributes = attributes.transform_keys(&:to_sym)
# collect the attributes this model knows about, including the ones
# defined in its parent(s), so an allOf child also maps its inherited
# attributes (the child's own declaration wins on a name clash)
types = openapi_types
map = attribute_map
klass = superclass
while klass.respond_to?(:openapi_types)
types = klass.openapi_types.merge(types)
map = klass.attribute_map.merge(map)
klass = klass.superclass
end
transformed_hash = {}
openapi_types.each_pair do |key, type|
if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
types.each_pair do |key, type|
if attributes.key?(map[key]) && attributes[map[key]].nil?
transformed_hash["#{key}"] = nil
elsif type =~ /\AArray<(.*)>/i
# check to ensure the input is an array given that the attribute
# is documented as an array but the input is not
if attributes[attribute_map[key]].is_a?(Array)
transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
if attributes[map[key]].is_a?(Array)
transformed_hash["#{key}"] = attributes[map[key]].map { |v| _deserialize($1, v) }
end
elsif !attributes[attribute_map[key]].nil?
transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
elsif !attributes[map[key]].nil?
transformed_hash["#{key}"] = _deserialize(type, attributes[map[key]])
end
end
new(transformed_hash)
Expand All @@ -183,11 +194,24 @@ def self.build_from_hash(attributes)
# Returns the object in the form of hash
# @return [Hash] Returns the object in the form of hash
def to_hash
hash = super
self.class.attribute_map.each_pair do |attr, param|
# collect the attributes this model knows about, including the ones defined
# in its parent(s): attribute_map and openapi_nullable resolve to the child
# class in every ancestor frame, so the inherited super chain only repeated
# the child's own attributes and dropped the inherited ones
map = self.class.attribute_map
nullable = self.class.openapi_nullable
klass = self.class.superclass
while klass.respond_to?(:openapi_types)
# an ancestor's nullability only applies to attributes no nearer class redeclares
nullable |= klass.openapi_nullable & (klass.attribute_map.keys - map.keys)
map = klass.attribute_map.merge(map)
klass = klass.superclass
end
hash = {}
map.each_pair do |attr, param|
value = self.send(attr)
if value.nil?
is_nullable = self.class.openapi_nullable.include?(attr)
is_nullable = nullable.include?(attr)
next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
end

Expand Down
Loading
Loading