plain_params 0.0.2 → 0.0.5
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -0
- data/LICENSE +21 -0
- data/README.md +205 -1
- data/examples/usage.rb +55 -0
- data/lib/plain_params.rb +36 -31
- metadata +50 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2732e1cfef1a1932dfb6b1b7b829145b3f765bfcd779600fb3ddecf3f324f867
|
4
|
+
data.tar.gz: e41d104a92928e9acfb726dc25fe57ca7cdc8d6c0341e9d90e0ef033154ba7bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4b32b007ab99633269c6d13a6c865d4b01b0a5076920c5a2472893bed145786b61bb91a15d2f61925397fdf62b7c8c2c7ba418e698d30f9f0476b5324087dcd4
|
7
|
+
data.tar.gz: 01ee101b993dbf46d01bb5fc4f02992abb5f81eee616fbb46885e53a4aba13fe53a6aed6994c121eb299c81cd2797f528a5781c9a54ea2790935da654d57b7f6
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
## [0.0.5] - Unreleased
|
6
|
+
|
7
|
+
### Added
|
8
|
+
- Comprehensive test suite with 100% coverage
|
9
|
+
- Example usage files demonstrating practical applications
|
10
|
+
- Rubocop configuration for code quality
|
11
|
+
- Rake tasks for common operations
|
12
|
+
- Support for Ruby 3.4+ implicit block parameter `it`
|
13
|
+
|
14
|
+
### Changed
|
15
|
+
- Refactored main class to use modern Ruby syntax
|
16
|
+
- Improved code organization with separate methods for initialization
|
17
|
+
- Enhanced README with better examples and clearer documentation
|
18
|
+
- Simplified accessor setup logic
|
19
|
+
|
20
|
+
### Fixed
|
21
|
+
- Virtual fields now properly support custom getter methods
|
22
|
+
- Fixed issue with virtual field initialization order
|
23
|
+
|
24
|
+
## [0.0.4] - 2024-11-15
|
25
|
+
|
26
|
+
### Added
|
27
|
+
- Initial release with basic functionality
|
28
|
+
- Support for real and virtual fields
|
29
|
+
- ActiveModel integration
|
30
|
+
- Basic validation support
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2024 Gedean Dias
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
CHANGED
@@ -1 +1,205 @@
|
|
1
|
-
#
|
1
|
+
# PlainParams
|
2
|
+
|
3
|
+
A lightweight Ruby gem for parameter validation and organization using ActiveModel, without the overhead of ActiveRecord or complex validation libraries.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'plain_params'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
```bash
|
16
|
+
$ bundle install
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
```bash
|
22
|
+
$ gem install plain_params
|
23
|
+
```
|
24
|
+
|
25
|
+
## Overview
|
26
|
+
|
27
|
+
PlainParams provides a simple way to handle parameter validation by dividing attributes into two categories:
|
28
|
+
|
29
|
+
- **Real fields**: Required attributes with automatic presence validation
|
30
|
+
- **Virtual fields**: Optional computed attributes that can depend on real fields
|
31
|
+
|
32
|
+
## Basic Usage
|
33
|
+
|
34
|
+
### Simple Example
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
class UserParams < PlainParams
|
38
|
+
@real_fields = %i[name email]
|
39
|
+
@virtual_fields = %i[display_name]
|
40
|
+
|
41
|
+
def display_name
|
42
|
+
name.upcase if name
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Create instance with parameters
|
47
|
+
params = UserParams.new(name: "john", email: "john@example.com")
|
48
|
+
|
49
|
+
# Access attributes
|
50
|
+
params.name # => "john"
|
51
|
+
params.email # => "john@example.com"
|
52
|
+
params.display_name # => "JOHN"
|
53
|
+
|
54
|
+
# Check validity
|
55
|
+
params.valid? # => true
|
56
|
+
|
57
|
+
# Get all values
|
58
|
+
params.values
|
59
|
+
# => {
|
60
|
+
# real: { name: "john", email: "john@example.com" },
|
61
|
+
# virtual: { display_name: "JOHN" }
|
62
|
+
# }
|
63
|
+
```
|
64
|
+
|
65
|
+
### Validation Example
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
class ProductParams < PlainParams
|
69
|
+
@real_fields = %i[name price quantity]
|
70
|
+
@virtual_fields = %i[total_value in_stock]
|
71
|
+
|
72
|
+
validates :price, numericality: { greater_than: 0 }
|
73
|
+
validates :quantity, numericality: { greater_than_or_equal_to: 0 }
|
74
|
+
|
75
|
+
def total_value
|
76
|
+
price * quantity if price && quantity
|
77
|
+
end
|
78
|
+
|
79
|
+
def in_stock
|
80
|
+
quantity && quantity > 0
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Invalid parameters
|
85
|
+
params = ProductParams.new(name: "Widget", price: -10)
|
86
|
+
params.valid? # => false
|
87
|
+
params.errors.full_messages
|
88
|
+
# => ["Price must be greater than 0", "Quantity can't be blank"]
|
89
|
+
```
|
90
|
+
|
91
|
+
### Advanced Example with Dependencies
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
class OrderParams < PlainParams
|
95
|
+
@real_fields = %i[customer_id items_count discount_percentage]
|
96
|
+
@virtual_fields = %i[has_discount order_size discount_multiplier]
|
97
|
+
|
98
|
+
validates :items_count, numericality: { greater_than: 0 }
|
99
|
+
validates :discount_percentage, numericality: {
|
100
|
+
greater_than_or_equal_to: 0,
|
101
|
+
less_than_or_equal_to: 100
|
102
|
+
}
|
103
|
+
|
104
|
+
def has_discount
|
105
|
+
discount_percentage && discount_percentage > 0
|
106
|
+
end
|
107
|
+
|
108
|
+
def order_size
|
109
|
+
return :small if items_count <= 5
|
110
|
+
return :medium if items_count <= 20
|
111
|
+
:large
|
112
|
+
end
|
113
|
+
|
114
|
+
def discount_multiplier
|
115
|
+
1 - (discount_percentage.to_f / 100)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
params = OrderParams.new(
|
120
|
+
customer_id: 123,
|
121
|
+
items_count: 10,
|
122
|
+
discount_percentage: 15
|
123
|
+
)
|
124
|
+
|
125
|
+
params.order_size # => :medium
|
126
|
+
params.has_discount # => true
|
127
|
+
params.discount_multiplier # => 0.85
|
128
|
+
```
|
129
|
+
|
130
|
+
## Features
|
131
|
+
|
132
|
+
### ActiveModel Integration
|
133
|
+
|
134
|
+
PlainParams integrates seamlessly with ActiveModel, providing:
|
135
|
+
|
136
|
+
- Full validation support
|
137
|
+
- Attribute naming conventions
|
138
|
+
- Error handling
|
139
|
+
- Form helper compatibility
|
140
|
+
|
141
|
+
### String Key Support
|
142
|
+
|
143
|
+
Parameters can be passed with either symbol or string keys:
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
# Both work identically
|
147
|
+
UserParams.new(name: "john", age: 30)
|
148
|
+
UserParams.new("name" => "john", "age" => 30)
|
149
|
+
```
|
150
|
+
|
151
|
+
### Error Handling
|
152
|
+
|
153
|
+
PlainParams provides clear error messages for common issues:
|
154
|
+
|
155
|
+
```ruby
|
156
|
+
# Missing field definitions
|
157
|
+
class EmptyParams < PlainParams
|
158
|
+
end
|
159
|
+
EmptyParams.new # => RuntimeError: No @real_fields or @virtual_fields provided
|
160
|
+
|
161
|
+
# Duplicate fields
|
162
|
+
class DuplicateParams < PlainParams
|
163
|
+
@real_fields = %i[name]
|
164
|
+
@virtual_fields = %i[name]
|
165
|
+
end
|
166
|
+
DuplicateParams.new # => RuntimeError: Duplicated field(s) 'name'
|
167
|
+
|
168
|
+
# Invalid fields
|
169
|
+
UserParams.new(invalid: "value") # => RuntimeError: field 'invalid' is not in @real_fields or @virtual_fields
|
170
|
+
```
|
171
|
+
|
172
|
+
## API Reference
|
173
|
+
|
174
|
+
### Class Methods
|
175
|
+
|
176
|
+
- `real_fields` - Returns array of real field names
|
177
|
+
- `virtual_fields` - Returns array of virtual field names
|
178
|
+
|
179
|
+
### Instance Methods
|
180
|
+
|
181
|
+
- `values` - Returns hash with all real and virtual values
|
182
|
+
- `real_values` - Returns hash with only real field values
|
183
|
+
- `virtual_values` - Returns hash with only virtual field values
|
184
|
+
- `valid?` - Validates the instance according to defined validations
|
185
|
+
- `persisted?` - Always returns `false` (ActiveModel compatibility)
|
186
|
+
|
187
|
+
## Best Practices
|
188
|
+
|
189
|
+
1. **Keep virtual fields simple** - They should contain display logic or simple calculations
|
190
|
+
2. **Use real fields for validation** - Put your validation rules on real fields
|
191
|
+
3. **Leverage ActiveModel validations** - Use the full power of ActiveModel validations
|
192
|
+
4. **Virtual fields for computed values** - Use virtual fields for values derived from real fields
|
193
|
+
|
194
|
+
## Requirements
|
195
|
+
|
196
|
+
- Ruby >= 3.0
|
197
|
+
- ActiveModel >= 7.0, < 9.0
|
198
|
+
|
199
|
+
## Contributing
|
200
|
+
|
201
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/gedean/plain_params.
|
202
|
+
|
203
|
+
## License
|
204
|
+
|
205
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/examples/usage.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require_relative '../lib/plain_params'
|
3
|
+
|
4
|
+
class ContactParams < PlainParams
|
5
|
+
@real_fields = %i[name email phone]
|
6
|
+
@virtual_fields = %i[formatted_phone email_domain]
|
7
|
+
|
8
|
+
validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }
|
9
|
+
validates :phone, format: { with: /\A\d{10,11}\z/ }
|
10
|
+
|
11
|
+
def formatted_phone
|
12
|
+
return unless phone
|
13
|
+
if phone.length == 11
|
14
|
+
"(#{phone[0..1]}) #{phone[2..6]}-#{phone[7..10]}"
|
15
|
+
else
|
16
|
+
"(#{phone[0..1]}) #{phone[2..5]}-#{phone[6..9]}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def email_domain
|
21
|
+
email.split('@').last if email
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
puts "=== Valid Contact ==="
|
26
|
+
contact = ContactParams.new(
|
27
|
+
name: "Alice Smith",
|
28
|
+
email: "alice@example.com",
|
29
|
+
phone: "11987654321"
|
30
|
+
)
|
31
|
+
|
32
|
+
if contact.valid?
|
33
|
+
puts "Name: #{contact.name}"
|
34
|
+
puts "Email: #{contact.email}"
|
35
|
+
puts "Phone: #{contact.phone}"
|
36
|
+
puts "Formatted Phone: #{contact.formatted_phone}"
|
37
|
+
puts "Email Domain: #{contact.email_domain}"
|
38
|
+
puts "\nAll values:"
|
39
|
+
p contact.values
|
40
|
+
else
|
41
|
+
puts "Errors: #{contact.errors.full_messages.join(', ')}"
|
42
|
+
end
|
43
|
+
|
44
|
+
puts "\n=== Invalid Contact ==="
|
45
|
+
invalid_contact = ContactParams.new(
|
46
|
+
name: "Bob",
|
47
|
+
email: "invalid-email",
|
48
|
+
phone: "123"
|
49
|
+
)
|
50
|
+
|
51
|
+
if invalid_contact.valid?
|
52
|
+
puts "Valid!"
|
53
|
+
else
|
54
|
+
puts "Errors: #{invalid_contact.errors.full_messages.join(', ')}"
|
55
|
+
end
|
data/lib/plain_params.rb
CHANGED
@@ -6,63 +6,68 @@ class PlainParams
|
|
6
6
|
include ActiveModel::Validations
|
7
7
|
|
8
8
|
def initialize(params_attributes = {})
|
9
|
-
raise 'No @real_fields or @virtual_fields provided in the class definition' if
|
9
|
+
raise 'No @real_fields or @virtual_fields provided in the class definition' if self.class.real_fields.nil? && self.class.virtual_fields.nil?
|
10
10
|
|
11
11
|
self.class.real_fields ||= []
|
12
12
|
self.class.virtual_fields ||= []
|
13
13
|
|
14
|
+
setup_accessors
|
14
15
|
self.attributes = params_attributes
|
15
16
|
end
|
16
17
|
|
17
|
-
|
18
|
-
|
18
|
+
class << self
|
19
|
+
attr_accessor :real_fields, :virtual_fields
|
20
|
+
end
|
19
21
|
|
20
22
|
def values
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
fields_values
|
23
|
+
{
|
24
|
+
real: self.class.real_fields.to_h { [it, send(it)] },
|
25
|
+
virtual: self.class.virtual_fields.to_h { [it, send(it)] }
|
26
|
+
}
|
27
27
|
end
|
28
28
|
|
29
29
|
def real_values = values[:real]
|
30
30
|
def virtual_values = values[:virtual]
|
31
|
-
|
32
31
|
def persisted? = false
|
33
32
|
|
34
33
|
private
|
34
|
+
|
35
|
+
def setup_accessors
|
36
|
+
self.class.real_fields.each do |field|
|
37
|
+
self.class.send(:attr_accessor, field)
|
38
|
+
self.class.send(:validates_presence_of, field)
|
39
|
+
end
|
40
|
+
|
41
|
+
self.class.virtual_fields.each do |field|
|
42
|
+
self.class.send(:attr_writer, field) unless self.class.method_defined?("#{field}=")
|
43
|
+
self.class.send(:attr_reader, field) unless self.class.method_defined?(field)
|
44
|
+
end
|
45
|
+
end
|
35
46
|
|
36
47
|
def attributes=(attributes)
|
37
|
-
duplicated_fields = self.class.real_fields
|
48
|
+
duplicated_fields = self.class.real_fields & self.class.virtual_fields
|
38
49
|
raise "Duplicated field(s) '#{duplicated_fields.join(', ')}' in @real_fields and @virtual_fields" if duplicated_fields.any?
|
39
50
|
|
40
51
|
symbolized_attributes = attributes.symbolize_keys
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
# initialized @real_fields first
|
47
|
-
self.class.real_fields.each do |available_field|
|
48
|
-
(instance_variable_set"@#{available_field.to_s}", symbolized_attributes[available_field])
|
49
|
-
self.class.send(:attr_accessor, available_field)
|
50
|
-
self.class.send(:validates_presence_of, available_field)
|
52
|
+
invalid_fields = symbolized_attributes.keys - (self.class.real_fields + self.class.virtual_fields)
|
53
|
+
|
54
|
+
invalid_fields.each do |invalid_field|
|
55
|
+
raise "field '#{invalid_field}' is not in @real_fields or @virtual_fields"
|
51
56
|
end
|
52
57
|
|
53
|
-
|
54
|
-
|
55
|
-
unless symbolized_attributes[virtual_field].nil?
|
56
|
-
self.send("#{virtual_field.to_s}=", symbolized_attributes[virtual_field])
|
57
|
-
end
|
58
|
-
end
|
58
|
+
initialize_real_fields(symbolized_attributes)
|
59
|
+
initialize_virtual_fields(symbolized_attributes)
|
59
60
|
end
|
60
61
|
|
61
|
-
def
|
62
|
-
|
62
|
+
def initialize_real_fields(attributes)
|
63
|
+
self.class.real_fields.each do |field|
|
64
|
+
instance_variable_set("@#{field}", attributes[field])
|
65
|
+
end
|
63
66
|
end
|
64
67
|
|
65
|
-
def
|
66
|
-
|
68
|
+
def initialize_virtual_fields(attributes)
|
69
|
+
self.class.virtual_fields.each do |field|
|
70
|
+
send("#{field}=", attributes[field]) if attributes.key?(field)
|
71
|
+
end
|
67
72
|
end
|
68
73
|
end
|
metadata
CHANGED
@@ -1,42 +1,81 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: plain_params
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gedean Dias
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-06-28 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: activemodel
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
16
15
|
requirements:
|
17
|
-
- - "
|
16
|
+
- - ">="
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '7.0'
|
19
|
+
- - "<"
|
18
20
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
21
|
+
version: '9.0'
|
20
22
|
type: :runtime
|
21
23
|
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '7.0'
|
29
|
+
- - "<"
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: '9.0'
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: rspec
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - "~>"
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '3.13'
|
39
|
+
type: :development
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - "~>"
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '3.13'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - "~>"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '13.0'
|
53
|
+
type: :development
|
54
|
+
prerelease: false
|
22
55
|
version_requirements: !ruby/object:Gem::Requirement
|
23
56
|
requirements:
|
24
57
|
- - "~>"
|
25
58
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
27
|
-
description:
|
59
|
+
version: '13.0'
|
60
|
+
description: A simple and lightweight parameter validation library that leverages
|
61
|
+
ActiveModel to provide a clean interface for handling parameters with real and virtual
|
62
|
+
fields.
|
28
63
|
email: gedean.dias@gmail.com
|
29
64
|
executables: []
|
30
65
|
extensions: []
|
31
66
|
extra_rdoc_files: []
|
32
67
|
files:
|
68
|
+
- CHANGELOG.md
|
69
|
+
- LICENSE
|
33
70
|
- README.md
|
71
|
+
- examples/usage.rb
|
34
72
|
- lib/plain_params.rb
|
35
73
|
homepage: https://github.com/gedean/plain_params
|
36
74
|
licenses:
|
37
75
|
- MIT
|
38
76
|
metadata: {}
|
39
|
-
post_install_message:
|
77
|
+
post_install_message: Thank you for installing PlainParams! Check out the README for
|
78
|
+
usage examples.
|
40
79
|
rdoc_options: []
|
41
80
|
require_paths:
|
42
81
|
- lib
|
@@ -44,15 +83,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
44
83
|
requirements:
|
45
84
|
- - ">="
|
46
85
|
- !ruby/object:Gem::Version
|
47
|
-
version: '3'
|
86
|
+
version: '3.0'
|
48
87
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
88
|
requirements:
|
50
89
|
- - ">="
|
51
90
|
- !ruby/object:Gem::Version
|
52
91
|
version: '0'
|
53
92
|
requirements: []
|
54
|
-
rubygems_version: 3.
|
55
|
-
signing_key:
|
93
|
+
rubygems_version: 3.6.9
|
56
94
|
specification_version: 4
|
57
|
-
summary:
|
95
|
+
summary: Lightweight parameter validation using ActiveModel
|
58
96
|
test_files: []
|