activemodel 5.2.7.1 → 6.1.4.6
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 +65 -111
- data/MIT-LICENSE +1 -1
- data/README.rdoc +6 -4
- data/lib/active_model/attribute/user_provided_default.rb +1 -2
- data/lib/active_model/attribute.rb +21 -21
- data/lib/active_model/attribute_assignment.rb +4 -6
- data/lib/active_model/attribute_methods.rb +117 -40
- data/lib/active_model/attribute_mutation_tracker.rb +90 -33
- data/lib/active_model/attribute_set/builder.rb +81 -16
- data/lib/active_model/attribute_set/yaml_encoder.rb +1 -2
- data/lib/active_model/attribute_set.rb +20 -28
- data/lib/active_model/attributes.rb +65 -44
- data/lib/active_model/callbacks.rb +11 -9
- data/lib/active_model/conversion.rb +1 -1
- data/lib/active_model/dirty.rb +51 -101
- data/lib/active_model/error.rb +207 -0
- data/lib/active_model/errors.rb +347 -155
- data/lib/active_model/gem_version.rb +4 -4
- data/lib/active_model/lint.rb +1 -1
- data/lib/active_model/naming.rb +22 -7
- data/lib/active_model/nested_error.rb +22 -0
- data/lib/active_model/railtie.rb +6 -0
- data/lib/active_model/secure_password.rb +54 -55
- data/lib/active_model/serialization.rb +9 -7
- data/lib/active_model/serializers/json.rb +17 -9
- data/lib/active_model/translation.rb +1 -1
- data/lib/active_model/type/big_integer.rb +0 -1
- data/lib/active_model/type/binary.rb +1 -1
- data/lib/active_model/type/boolean.rb +0 -1
- data/lib/active_model/type/date.rb +0 -5
- data/lib/active_model/type/date_time.rb +3 -8
- data/lib/active_model/type/decimal.rb +0 -1
- data/lib/active_model/type/float.rb +2 -3
- data/lib/active_model/type/helpers/accepts_multiparameter_time.rb +14 -6
- data/lib/active_model/type/helpers/numeric.rb +17 -6
- data/lib/active_model/type/helpers/time_value.rb +37 -15
- data/lib/active_model/type/helpers/timezone.rb +1 -1
- data/lib/active_model/type/immutable_string.rb +14 -11
- data/lib/active_model/type/integer.rb +15 -18
- data/lib/active_model/type/registry.rb +16 -16
- data/lib/active_model/type/string.rb +12 -3
- data/lib/active_model/type/time.rb +1 -6
- data/lib/active_model/type/value.rb +9 -2
- data/lib/active_model/validations/absence.rb +2 -2
- data/lib/active_model/validations/acceptance.rb +34 -27
- data/lib/active_model/validations/callbacks.rb +15 -16
- data/lib/active_model/validations/clusivity.rb +6 -3
- data/lib/active_model/validations/confirmation.rb +4 -4
- data/lib/active_model/validations/exclusion.rb +1 -1
- data/lib/active_model/validations/format.rb +2 -3
- data/lib/active_model/validations/inclusion.rb +2 -2
- data/lib/active_model/validations/length.rb +3 -3
- data/lib/active_model/validations/numericality.rb +58 -44
- data/lib/active_model/validations/presence.rb +1 -1
- data/lib/active_model/validations/validates.rb +7 -6
- data/lib/active_model/validations.rb +6 -9
- data/lib/active_model/validator.rb +8 -3
- data/lib/active_model.rb +2 -1
- metadata +14 -9
@@ -13,6 +13,8 @@ module ActiveModel
|
|
13
13
|
|
14
14
|
INTEGER_REGEX = /\A[+-]?\d+\z/
|
15
15
|
|
16
|
+
HEXADECIMAL_REGEX = /\A[+-]?0[xX]/
|
17
|
+
|
16
18
|
def check_validity!
|
17
19
|
keys = CHECKS.keys - [:odd, :even]
|
18
20
|
options.slice(*keys).each do |option, value|
|
@@ -22,44 +24,24 @@ module ActiveModel
|
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
25
|
-
def validate_each(record, attr_name, value)
|
26
|
-
|
27
|
-
|
28
|
-
if record.respond_to?(came_from_user)
|
29
|
-
if record.public_send(came_from_user)
|
30
|
-
raw_value = record.read_attribute_before_type_cast(attr_name)
|
31
|
-
elsif record.respond_to?(:read_attribute)
|
32
|
-
raw_value = record.read_attribute(attr_name)
|
33
|
-
end
|
34
|
-
else
|
35
|
-
before_type_cast = :"#{attr_name}_before_type_cast"
|
36
|
-
if record.respond_to?(before_type_cast)
|
37
|
-
raw_value = record.public_send(before_type_cast)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
raw_value ||= value
|
41
|
-
|
42
|
-
if record_attribute_changed_in_place?(record, attr_name)
|
43
|
-
raw_value = value
|
44
|
-
end
|
45
|
-
|
46
|
-
unless is_number?(raw_value)
|
47
|
-
record.errors.add(attr_name, :not_a_number, filtered_options(raw_value))
|
27
|
+
def validate_each(record, attr_name, value, precision: Float::DIG, scale: nil)
|
28
|
+
unless is_number?(value, precision, scale)
|
29
|
+
record.errors.add(attr_name, :not_a_number, **filtered_options(value))
|
48
30
|
return
|
49
31
|
end
|
50
32
|
|
51
|
-
if allow_only_integer?(record) && !is_integer?(
|
52
|
-
record.errors.add(attr_name, :not_an_integer, filtered_options(
|
33
|
+
if allow_only_integer?(record) && !is_integer?(value)
|
34
|
+
record.errors.add(attr_name, :not_an_integer, **filtered_options(value))
|
53
35
|
return
|
54
36
|
end
|
55
37
|
|
56
|
-
value = parse_as_number(
|
38
|
+
value = parse_as_number(value, precision, scale)
|
57
39
|
|
58
40
|
options.slice(*CHECKS.keys).each do |option, option_value|
|
59
41
|
case option
|
60
42
|
when :odd, :even
|
61
|
-
unless value.to_i.
|
62
|
-
record.errors.add(attr_name, option, filtered_options(value))
|
43
|
+
unless value.to_i.public_send(CHECKS[option])
|
44
|
+
record.errors.add(attr_name, option, **filtered_options(value))
|
63
45
|
end
|
64
46
|
else
|
65
47
|
case option_value
|
@@ -69,41 +51,50 @@ module ActiveModel
|
|
69
51
|
option_value = record.send(option_value)
|
70
52
|
end
|
71
53
|
|
72
|
-
option_value = parse_as_number(option_value)
|
54
|
+
option_value = parse_as_number(option_value, precision, scale)
|
73
55
|
|
74
|
-
unless value.
|
75
|
-
record.errors.add(attr_name, option, filtered_options(value).merge!(count: option_value))
|
56
|
+
unless value.public_send(CHECKS[option], option_value)
|
57
|
+
record.errors.add(attr_name, option, **filtered_options(value).merge!(count: option_value))
|
76
58
|
end
|
77
59
|
end
|
78
60
|
end
|
79
61
|
end
|
80
62
|
|
81
63
|
private
|
82
|
-
|
83
|
-
def is_number?(raw_value)
|
84
|
-
!parse_as_number(raw_value).nil?
|
85
|
-
rescue ArgumentError, TypeError
|
86
|
-
false
|
87
|
-
end
|
88
|
-
|
89
|
-
def parse_as_number(raw_value)
|
64
|
+
def parse_as_number(raw_value, precision, scale)
|
90
65
|
if raw_value.is_a?(Float)
|
91
|
-
raw_value
|
66
|
+
parse_float(raw_value, precision, scale)
|
67
|
+
elsif raw_value.is_a?(BigDecimal)
|
68
|
+
round(raw_value, scale)
|
92
69
|
elsif raw_value.is_a?(Numeric)
|
93
70
|
raw_value
|
94
71
|
elsif is_integer?(raw_value)
|
95
72
|
raw_value.to_i
|
96
73
|
elsif !is_hexadecimal_literal?(raw_value)
|
97
|
-
Kernel.Float(raw_value)
|
74
|
+
parse_float(Kernel.Float(raw_value), precision, scale)
|
98
75
|
end
|
99
76
|
end
|
100
77
|
|
78
|
+
def parse_float(raw_value, precision, scale)
|
79
|
+
round(raw_value, scale).to_d(precision)
|
80
|
+
end
|
81
|
+
|
82
|
+
def round(raw_value, scale)
|
83
|
+
scale ? raw_value.round(scale) : raw_value
|
84
|
+
end
|
85
|
+
|
86
|
+
def is_number?(raw_value, precision, scale)
|
87
|
+
!parse_as_number(raw_value, precision, scale).nil?
|
88
|
+
rescue ArgumentError, TypeError
|
89
|
+
false
|
90
|
+
end
|
91
|
+
|
101
92
|
def is_integer?(raw_value)
|
102
|
-
INTEGER_REGEX
|
93
|
+
INTEGER_REGEX.match?(raw_value.to_s)
|
103
94
|
end
|
104
95
|
|
105
96
|
def is_hexadecimal_literal?(raw_value)
|
106
|
-
|
97
|
+
HEXADECIMAL_REGEX.match?(raw_value.to_s)
|
107
98
|
end
|
108
99
|
|
109
100
|
def filtered_options(value)
|
@@ -123,6 +114,27 @@ module ActiveModel
|
|
123
114
|
end
|
124
115
|
end
|
125
116
|
|
117
|
+
def prepare_value_for_validation(value, record, attr_name)
|
118
|
+
return value if record_attribute_changed_in_place?(record, attr_name)
|
119
|
+
|
120
|
+
came_from_user = :"#{attr_name}_came_from_user?"
|
121
|
+
|
122
|
+
if record.respond_to?(came_from_user)
|
123
|
+
if record.public_send(came_from_user)
|
124
|
+
raw_value = record.public_send(:"#{attr_name}_before_type_cast")
|
125
|
+
elsif record.respond_to?(:read_attribute)
|
126
|
+
raw_value = record.read_attribute(attr_name)
|
127
|
+
end
|
128
|
+
else
|
129
|
+
before_type_cast = :"#{attr_name}_before_type_cast"
|
130
|
+
if record.respond_to?(before_type_cast)
|
131
|
+
raw_value = record.public_send(before_type_cast)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
raw_value || value
|
136
|
+
end
|
137
|
+
|
126
138
|
def record_attribute_changed_in_place?(record, attr_name)
|
127
139
|
record.respond_to?(:attribute_changed_in_place?) &&
|
128
140
|
record.attribute_changed_in_place?(attr_name.to_s)
|
@@ -133,7 +145,8 @@ module ActiveModel
|
|
133
145
|
# Validates whether the value of the specified attribute is numeric by
|
134
146
|
# trying to convert it to a float with Kernel.Float (if <tt>only_integer</tt>
|
135
147
|
# is +false+) or applying it to the regular expression <tt>/\A[\+\-]?\d+\z/</tt>
|
136
|
-
# (if <tt>only_integer</tt> is set to +true+).
|
148
|
+
# (if <tt>only_integer</tt> is set to +true+). Precision of Kernel.Float values
|
149
|
+
# are guaranteed up to 15 digits.
|
137
150
|
#
|
138
151
|
# class Person < ActiveRecord::Base
|
139
152
|
# validates_numericality_of :value, on: :create
|
@@ -174,6 +187,7 @@ module ActiveModel
|
|
174
187
|
# * <tt>:less_than</tt>
|
175
188
|
# * <tt>:less_than_or_equal_to</tt>
|
176
189
|
# * <tt>:only_integer</tt>
|
190
|
+
# * <tt>:other_than</tt>
|
177
191
|
#
|
178
192
|
# For example:
|
179
193
|
#
|
@@ -4,7 +4,7 @@ module ActiveModel
|
|
4
4
|
module Validations
|
5
5
|
class PresenceValidator < EachValidator # :nodoc:
|
6
6
|
def validate_each(record, attr_name, value)
|
7
|
-
record.errors.add(attr_name, :blank, options) if value.blank?
|
7
|
+
record.errors.add(attr_name, :blank, **options) if value.blank?
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
@@ -12,6 +12,7 @@ module ActiveModel
|
|
12
12
|
#
|
13
13
|
# Examples of using the default rails validators:
|
14
14
|
#
|
15
|
+
# validates :username, absence: true
|
15
16
|
# validates :terms, acceptance: true
|
16
17
|
# validates :password, confirmation: true
|
17
18
|
# validates :username, exclusion: { in: %w(admin superuser) }
|
@@ -27,7 +28,7 @@ module ActiveModel
|
|
27
28
|
# class EmailValidator < ActiveModel::EachValidator
|
28
29
|
# def validate_each(record, attribute, value)
|
29
30
|
# record.errors.add attribute, (options[:message] || "is not an email") unless
|
30
|
-
#
|
31
|
+
# /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i.match?(value)
|
31
32
|
# end
|
32
33
|
# end
|
33
34
|
#
|
@@ -47,7 +48,7 @@ module ActiveModel
|
|
47
48
|
#
|
48
49
|
# class TitleValidator < ActiveModel::EachValidator
|
49
50
|
# def validate_each(record, attribute, value)
|
50
|
-
# record.errors.add attribute, "must start with 'the'" unless
|
51
|
+
# record.errors.add attribute, "must start with 'the'" unless /\Athe/i.match?(value)
|
51
52
|
# end
|
52
53
|
# end
|
53
54
|
#
|
@@ -63,7 +64,7 @@ module ActiveModel
|
|
63
64
|
# and strings in shortcut form.
|
64
65
|
#
|
65
66
|
# validates :email, format: /@/
|
66
|
-
# validates :
|
67
|
+
# validates :role, inclusion: %w(admin contributor)
|
67
68
|
# validates :password, length: 6..20
|
68
69
|
#
|
69
70
|
# When using shortcut form, ranges and arrays are passed to your
|
@@ -112,15 +113,16 @@ module ActiveModel
|
|
112
113
|
defaults[:attributes] = attributes
|
113
114
|
|
114
115
|
validations.each do |key, options|
|
115
|
-
next unless options
|
116
116
|
key = "#{key.to_s.camelize}Validator"
|
117
117
|
|
118
118
|
begin
|
119
|
-
validator = key.include?("::"
|
119
|
+
validator = key.include?("::") ? key.constantize : const_get(key)
|
120
120
|
rescue NameError
|
121
121
|
raise ArgumentError, "Unknown validator: '#{key}'"
|
122
122
|
end
|
123
123
|
|
124
|
+
next unless options
|
125
|
+
|
124
126
|
validates_with(validator, defaults.merge(_parse_validates_options(options)))
|
125
127
|
end
|
126
128
|
end
|
@@ -150,7 +152,6 @@ module ActiveModel
|
|
150
152
|
end
|
151
153
|
|
152
154
|
private
|
153
|
-
|
154
155
|
# When creating custom validators, it might be useful to be able to specify
|
155
156
|
# additional default keys. This can be done by overwriting this method.
|
156
157
|
def _validates_default_keys
|
@@ -1,8 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/core_ext/array/extract_options"
|
4
|
-
require "active_support/core_ext/hash/keys"
|
5
|
-
require "active_support/core_ext/hash/except"
|
6
4
|
|
7
5
|
module ActiveModel
|
8
6
|
# == Active \Model \Validations
|
@@ -17,7 +15,7 @@ module ActiveModel
|
|
17
15
|
# attr_accessor :first_name, :last_name
|
18
16
|
#
|
19
17
|
# validates_each :first_name, :last_name do |record, attr, value|
|
20
|
-
# record.errors.add attr,
|
18
|
+
# record.errors.add attr, "starts with z." if value.start_with?("z")
|
21
19
|
# end
|
22
20
|
# end
|
23
21
|
#
|
@@ -63,7 +61,7 @@ module ActiveModel
|
|
63
61
|
# attr_accessor :first_name, :last_name
|
64
62
|
#
|
65
63
|
# validates_each :first_name, :last_name, allow_blank: true do |record, attr, value|
|
66
|
-
# record.errors.add attr,
|
64
|
+
# record.errors.add attr, "starts with z." if value.start_with?("z")
|
67
65
|
# end
|
68
66
|
# end
|
69
67
|
#
|
@@ -165,10 +163,10 @@ module ActiveModel
|
|
165
163
|
if options.key?(:on)
|
166
164
|
options = options.dup
|
167
165
|
options[:on] = Array(options[:on])
|
168
|
-
options[:if] =
|
169
|
-
|
170
|
-
|
171
|
-
|
166
|
+
options[:if] = [
|
167
|
+
->(o) { !(options[:on] & Array(o.validation_context)).empty? },
|
168
|
+
*options[:if]
|
169
|
+
]
|
172
170
|
end
|
173
171
|
|
174
172
|
set_callback(:validate, *args, options, &block)
|
@@ -404,7 +402,6 @@ module ActiveModel
|
|
404
402
|
alias :read_attribute_for_validation :send
|
405
403
|
|
406
404
|
private
|
407
|
-
|
408
405
|
def run_validations!
|
409
406
|
_run_validate_callbacks
|
410
407
|
errors.empty?
|
@@ -85,12 +85,12 @@ module ActiveModel
|
|
85
85
|
#
|
86
86
|
# It can be useful to access the class that is using that validator when there are prerequisites such
|
87
87
|
# as an +attr_accessor+ being present. This class is accessible via <tt>options[:class]</tt> in the constructor.
|
88
|
-
# To
|
88
|
+
# To set up your validator override the constructor.
|
89
89
|
#
|
90
90
|
# class MyValidator < ActiveModel::Validator
|
91
91
|
# def initialize(options={})
|
92
92
|
# super
|
93
|
-
# options[:class].
|
93
|
+
# options[:class].attr_accessor :custom_attribute
|
94
94
|
# end
|
95
95
|
# end
|
96
96
|
class Validator
|
@@ -149,6 +149,7 @@ module ActiveModel
|
|
149
149
|
attributes.each do |attribute|
|
150
150
|
value = record.read_attribute_for_validation(attribute)
|
151
151
|
next if (value.nil? && options[:allow_nil]) || (value.blank? && options[:allow_blank])
|
152
|
+
value = prepare_value_for_validation(value, record, attribute)
|
152
153
|
validate_each(record, attribute, value)
|
153
154
|
end
|
154
155
|
end
|
@@ -164,6 +165,11 @@ module ActiveModel
|
|
164
165
|
# +ArgumentError+ when invalid options are supplied.
|
165
166
|
def check_validity!
|
166
167
|
end
|
168
|
+
|
169
|
+
private
|
170
|
+
def prepare_value_for_validation(value, record, attr_name)
|
171
|
+
value
|
172
|
+
end
|
167
173
|
end
|
168
174
|
|
169
175
|
# +BlockValidator+ is a special +EachValidator+ which receives a block on initialization
|
@@ -175,7 +181,6 @@ module ActiveModel
|
|
175
181
|
end
|
176
182
|
|
177
183
|
private
|
178
|
-
|
179
184
|
def validate_each(record, attribute, value)
|
180
185
|
@block.call(record, attribute, value)
|
181
186
|
end
|
data/lib/active_model.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright (c) 2004-
|
4
|
+
# Copyright (c) 2004-2020 David Heinemeier Hansson
|
5
5
|
#
|
6
6
|
# Permission is hereby granted, free of charge, to any person obtaining
|
7
7
|
# a copy of this software and associated documentation files (the
|
@@ -53,6 +53,7 @@ module ActiveModel
|
|
53
53
|
|
54
54
|
eager_autoload do
|
55
55
|
autoload :Errors
|
56
|
+
autoload :Error
|
56
57
|
autoload :RangeError, "active_model/errors"
|
57
58
|
autoload :StrictValidationFailed, "active_model/errors"
|
58
59
|
autoload :UnknownAttributeError, "active_model/errors"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activemodel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 6.1.4.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-02-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 6.1.4.6
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 6.1.4.6
|
27
27
|
description: A toolkit for building modeling frameworks like Active Record. Rich support
|
28
28
|
for attributes, callbacks, validations, serialization, internationalization, and
|
29
29
|
testing.
|
@@ -48,6 +48,7 @@ files:
|
|
48
48
|
- lib/active_model/callbacks.rb
|
49
49
|
- lib/active_model/conversion.rb
|
50
50
|
- lib/active_model/dirty.rb
|
51
|
+
- lib/active_model/error.rb
|
51
52
|
- lib/active_model/errors.rb
|
52
53
|
- lib/active_model/forbidden_attributes_protection.rb
|
53
54
|
- lib/active_model/gem_version.rb
|
@@ -55,6 +56,7 @@ files:
|
|
55
56
|
- lib/active_model/locale/en.yml
|
56
57
|
- lib/active_model/model.rb
|
57
58
|
- lib/active_model/naming.rb
|
59
|
+
- lib/active_model/nested_error.rb
|
58
60
|
- lib/active_model/railtie.rb
|
59
61
|
- lib/active_model/secure_password.rb
|
60
62
|
- lib/active_model/serialization.rb
|
@@ -97,12 +99,15 @@ files:
|
|
97
99
|
- lib/active_model/validations/with.rb
|
98
100
|
- lib/active_model/validator.rb
|
99
101
|
- lib/active_model/version.rb
|
100
|
-
homepage:
|
102
|
+
homepage: https://rubyonrails.org
|
101
103
|
licenses:
|
102
104
|
- MIT
|
103
105
|
metadata:
|
104
|
-
|
105
|
-
changelog_uri: https://github.com/rails/rails/blob/
|
106
|
+
bug_tracker_uri: https://github.com/rails/rails/issues
|
107
|
+
changelog_uri: https://github.com/rails/rails/blob/v6.1.4.6/activemodel/CHANGELOG.md
|
108
|
+
documentation_uri: https://api.rubyonrails.org/v6.1.4.6/
|
109
|
+
mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
|
110
|
+
source_code_uri: https://github.com/rails/rails/tree/v6.1.4.6/activemodel
|
106
111
|
post_install_message:
|
107
112
|
rdoc_options: []
|
108
113
|
require_paths:
|
@@ -111,14 +116,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
111
116
|
requirements:
|
112
117
|
- - ">="
|
113
118
|
- !ruby/object:Gem::Version
|
114
|
-
version: 2.
|
119
|
+
version: 2.5.0
|
115
120
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
121
|
requirements:
|
117
122
|
- - ">="
|
118
123
|
- !ruby/object:Gem::Version
|
119
124
|
version: '0'
|
120
125
|
requirements: []
|
121
|
-
rubygems_version: 3.
|
126
|
+
rubygems_version: 3.2.22
|
122
127
|
signing_key:
|
123
128
|
specification_version: 4
|
124
129
|
summary: A toolkit for building modeling frameworks (part of Rails).
|