Skip to content

[Ruby] Add more validation rules to Ruby models #2695

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Apr 25, 2016
Merged
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 @@ -42,6 +42,7 @@ public class CodegenProperty {
public Map<String, Object> allowableValues;
public CodegenProperty items;
public Map<String, Object> vendorExtensions;
public Boolean hasValidation; // true if pattern, maximum, etc are set (only used in the mustache template)

@Override
public int hashCode()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,16 @@ public void setEnsureUniqueParams(Boolean ensureUniqueParams) {
this.ensureUniqueParams = ensureUniqueParams;
}

/**
* Return the JSON schema pattern (http://json-schema.org/latest/json-schema-validation.html#anchor33)
*
* @param pattern the pattern (regular expression)
* @return properly-escaped pattern
*/
public String toJSONSchemaPattern(String pattern) {
return escapeText(pattern);
}

/**
* Return the file name of the Api Test
*
Expand Down Expand Up @@ -1094,6 +1104,10 @@ public CodegenProperty fromProperty(String name, Property p) {
property.exclusiveMinimum = np.getExclusiveMinimum();
property.exclusiveMaximum = np.getExclusiveMaximum();

// check if any validation rule defined
if (property.minimum != null || property.maximum != null || property.exclusiveMinimum != null || property.exclusiveMaximum != null)
property.hasValidation = true;

// legacy support
Map<String, Object> allowableValues = new HashMap<String, Object>();
if (np.getMinimum() != null) {
Expand All @@ -1111,7 +1125,12 @@ public CodegenProperty fromProperty(String name, Property p) {
StringProperty sp = (StringProperty) p;
property.maxLength = sp.getMaxLength();
property.minLength = sp.getMinLength();
property.pattern = sp.getPattern();
property.pattern = toJSONSchemaPattern(sp.getPattern());

// check if any validation rule defined
if (property.pattern != null || property.minLength != null || property.maxLength != null)
property.hasValidation = true;

property.isString = true;
if (sp.getEnum() != null) {
List<String> _enum = sp.getEnum();
Expand Down Expand Up @@ -1802,17 +1821,14 @@ public CodegenParameter fromParameter(Parameter param, Set<String> imports) {
if (model.complexType != null) {
imports.add(model.complexType);
}
p.maxLength = qp.getMaxLength();
p.minLength = qp.getMinLength();
p.pattern = qp.getPattern();

p.maximum = qp.getMaximum();
p.exclusiveMaximum = qp.isExclusiveMaximum();
p.minimum = qp.getMinimum();
p.exclusiveMinimum = qp.isExclusiveMinimum();
p.maxLength = qp.getMaxLength();
p.minLength = qp.getMinLength();
p.pattern = qp.getPattern();
p.pattern = toJSONSchemaPattern(qp.getPattern());
p.maxItems = qp.getMaxItems();
p.minItems = qp.getMinItems();
p.uniqueItems = qp.isUniqueItems();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Then either install the gem locally:
```shell
gem install ./{{{gemName}}}-{{{gemVersion}}}.gem
```
(for development, run `gem install --dev ./{{{gemName}}}-{{{gemVersion}}}.gem` to install the development dependencies)

or publish the gem to a gem hosting service, e.g. [RubyGems](https://rubygems.org/).

Expand Down
169 changes: 163 additions & 6 deletions modules/swagger-codegen/src/main/resources/ruby/model.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -39,25 +39,182 @@ module {{moduleName}}{{#models}}{{#model}}{{#description}}

{{#vars}}
if attributes[:'{{{baseName}}}']
{{#isContainer}}if (value = attributes[:'{{{baseName}}}']).is_a?(Array)
{{#isContainer}}
if (value = attributes[:'{{{baseName}}}']).is_a?(Array)
self.{{{name}}} = value
end{{/isContainer}}{{^isContainer}}self.{{{name}}} = attributes[:'{{{baseName}}}']{{/isContainer}}{{#defaultValue}}
end
{{/isContainer}}
{{^isContainer}}
self.{{{name}}} = attributes[:'{{{baseName}}}']
{{/isContainer}}
{{#defaultValue}}
else
self.{{{name}}} = {{{defaultValue}}}{{/defaultValue}}
self.{{{name}}} = {{{defaultValue}}}
{{/defaultValue}}
end

{{/vars}}
end

# Show invalid properties with the reasons. Usually used together with valid?
# @return Array for valid properies with the reasons
def list_invalid_properties
invalid_properties = Array.new
{{#isEnum}}
allowed_values = [{{#allowableValues}}{{#values}}"{{{this}}}"{{^-last}}, {{/-last}}{{/values}}{{/allowableValues}}]
if @{{{name}}} && !allowed_values.include?({{{name}}})
invalid_properties.push("invalid value for '{{{name}}}', must be one of #{allowed_values}.")
end

{{/isEnum}}
{{#hasValidation}}
if @{{{name}}}.nil?
fail ArgumentError, "{{{name}}} cannot be nil"
end

{{#minLength}}
if @{{{name}}}.to_s.length > {{{maxLength}}}
invalid_properties.push("invalid value for '{{{name}}}', the character length must be smaller than or equal to {{{maxLength}}}.")
end

{{/minLength}}
{{#maxLength}}
if @{{{name}}}.to_s.length < {{{minLength}}}
invalid_properties.push("invalid value for '{{{name}}}', the character length must be great than or equal to {{{minLength}}}.")
end

{{/maxLength}}
{{#maximum}}
if @{{{name}}} > {{{maximum}}}
invalid_properties.push("invalid value for '{{{name}}}', must be smaller than or equal to {{{maximum}}}.")
end

{{/maximum}}
{{#minimum}}
if @{{{name}}} < {{{minimum}}}
invalid_properties.push("invalid value for '{{{name}}}', must be greater than or equal to {{{minimum}}}.")
end

{{/minimum}}
{{#pattern}}
if @{{{name}}} !~ Regexp.new({{{pattern}}})
invalid_properties.push("invalid value for '{{{name}}}', must conform to the pattern {{{pattern}}}.")
end

{{/pattern}}
{{/hasValidation}}
return invalid_properties
end

# Check to see if the all the properties in the model are valid
# @return true if the model is valid
def valid?
{{#vars}}
{{#required}}
if @{{{name}}}.nil?
return false
end

{{/required}}
{{#isEnum}}
allowed_values = [{{#allowableValues}}{{#values}}"{{{this}}}"{{^-last}}, {{/-last}}{{/values}}{{/allowableValues}}]
if @{{{name}}} && !allowed_values.include?(@{{{name}}})
return false
end
{{/isEnum}}
{{#hasValidation}}
{{#minLength}}
if @{{{name}}}.to_s.length > {{{maxLength}}}
return false
end

{{/minLength}}
{{#maxLength}}
if @{{{name}}}.to_s.length < {{{minLength}}}
return false
end

{{/maxLength}}
{{#maximum}}
if @{{{name}}} > {{{maximum}}}
return false
end

{{/maximum}}
{{#minimum}}
if @{{{name}}} < {{{minimum}}}
return false
end

{{/minimum}}
{{#pattern}}
if @{{{name}}} !~ Regexp.new({{{pattern}}})
return false
end

{{/pattern}}
{{/hasValidation}}
{{/vars}}
end
{{#vars}}{{#isEnum}}

{{#vars}}
{{#isEnum}}
# Custom attribute writer method checking allowed values (enum).
# @param [Object] {{{name}}} Object to be assigned
def {{{name}}}=({{{name}}})
allowed_values = [{{#allowableValues}}{{#values}}"{{{this}}}"{{^-last}}, {{/-last}}{{/values}}{{/allowableValues}}]
if {{{name}}} && !allowed_values.include?({{{name}}})
fail "invalid value for '{{{name}}}', must be one of #{allowed_values}"
fail ArgumentError, "invalid value for '{{{name}}}', must be one of #{allowed_values}."
end
@{{{name}}} = {{{name}}}
end
{{/isEnum}}{{/vars}}

{{/isEnum}}
{{^isEnum}}
{{#hasValidation}}
# Custom attribute writer method with validation
# @param [Object] {{{name}}} Value to be assigned
def {{{name}}}=({{{name}}})
if {{{name}}}.nil?
fail ArgumentError, "{{{name}}} cannot be nil"
end

{{#minLength}}
if {{{name}}}.to_s.length > {{{maxLength}}}
fail ArgumentError, "invalid value for '{{{name}}}', the character length must be smaller than or equal to {{{maxLength}}}."
end

{{/minLength}}
{{#maxLength}}
if {{{name}}}.to_s.length < {{{minLength}}}
fail ArgumentError, "invalid value for '{{{name}}}', the character length must be great than or equal to {{{minLength}}}."
end

{{/maxLength}}
{{#maximum}}
if {{{name}}} > {{{maximum}}}
fail ArgumentError, "invalid value for '{{{name}}}', must be smaller than or equal to {{{maximum}}}."
end

{{/maximum}}
{{#minimum}}
if {{{name}}} < {{{minimum}}}
fail ArgumentError, "invalid value for '{{{name}}}', must be greater than or equal to {{{minimum}}}."
end

{{/minimum}}
{{#pattern}}
if @{{{name}}} !~ Regexp.new({{{pattern}}})
fail ArgumentError, "invalid value for '{{{name}}}', must conform to the pattern {{{pattern}}}."
end

{{/pattern}}
@{{{name}}} = {{{name}}}
end

{{/hasValidation}}
{{/isEnum}}
{{/vars}}
# Checks equality by comparing each attribute.
# @param [Object] Object to be compared
def ==(o)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -761,22 +761,33 @@ definitions:
properties:
integer:
type: integer
maximum: 100
minimum: 10
int32:
type: integer
format: int32
maximum: 200
minimum: 20
int64:
type: integer
format: int64
number:
maximum: 543.2
minimum: 32.1
type: number
float:
type: number
format: float
maximum: 987.6
minimum: 54.3
double:
type: number
format: double
maximum: 123.4
minimum: 67.8
string:
type: string
pattern: /[a-z]/i
byte:
type: string
format: byte
Expand All @@ -792,6 +803,8 @@ definitions:
password:
type: string
format: password
maxLength: 64
minLength: 10
externalDocs:
description: Find out more about Swagger
url: 'http://swagger.io'
34 changes: 18 additions & 16 deletions samples/client/petstore/ruby/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,31 @@ GEM
ethon (0.8.1)
ffi (>= 1.3.0)
ffi (1.9.8)
hashdiff (0.3.0)
json (1.8.3)
rspec (3.2.0)
rspec-core (~> 3.2.0)
rspec-expectations (~> 3.2.0)
rspec-mocks (~> 3.2.0)
rspec-core (3.2.2)
rspec-support (~> 3.2.0)
rspec-expectations (3.2.0)
rspec (3.4.0)
rspec-core (~> 3.4.0)
rspec-expectations (~> 3.4.0)
rspec-mocks (~> 3.4.0)
rspec-core (3.4.4)
rspec-support (~> 3.4.0)
rspec-expectations (3.4.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.2.0)
rspec-mocks (3.2.1)
rspec-support (~> 3.4.0)
rspec-mocks (3.4.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.2.0)
rspec-support (3.2.2)
rspec-support (~> 3.4.0)
rspec-support (3.4.1)
safe_yaml (1.0.4)
sys-uname (0.9.2)
ffi (>= 1.0.0)
typhoeus (1.0.1)
ethon (>= 0.8.0)
vcr (2.9.3)
webmock (1.21.0)
vcr (3.0.1)
webmock (1.24.5)
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff

PLATFORMS
ruby
Expand All @@ -55,6 +57,6 @@ DEPENDENCIES
autotest-growl (~> 0.2, >= 0.2.16)
autotest-rails-pure (~> 4.1, >= 4.1.2)
petstore!
rspec (~> 3.2, >= 3.2.0)
vcr (~> 2.9, >= 2.9.3)
webmock (~> 1.6, >= 1.6.2)
rspec (~> 3.4, >= 3.4.0)
vcr (~> 3.0, >= 3.0.1)
webmock (~> 1.24, >= 1.24.3)
3 changes: 2 additions & 1 deletion samples/client/petstore/ruby/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ This SDK is automatically generated by the [Swagger Codegen](https://github.com/

- API version: 1.0.0
- Package version: 1.0.0
- Build date: 2016-04-20T18:46:00.664+08:00
- Build date: 2016-04-25T22:22:56.750+08:00
- Build package: class io.swagger.codegen.languages.RubyClientCodegen

## Installation
Expand All @@ -26,6 +26,7 @@ Then either install the gem locally:
```shell
gem install ./petstore-1.0.0.gem
```
(for development, run `gem install --dev ./petstore-1.0.0.gem` to install the development dependencies)

or publish the gem to a gem hosting service, e.g. [RubyGems](https://rubygems.org/).

Expand Down
6 changes: 3 additions & 3 deletions samples/client/petstore/ruby/docs/FormatTest.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ Name | Type | Description | Notes
**float** | **Float** | | [optional]
**double** | **Float** | | [optional]
**string** | **String** | | [optional]
**byte** | **String** | | [optional]
**byte** | **String** | |
**binary** | **String** | | [optional]
**date** | **Date** | | [optional]
**date** | **Date** | |
**date_time** | **DateTime** | | [optional]
**password** | **String** | | [optional]
**password** | **String** | |


Loading