otoroshi 0.0.8 → 0.1.3
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/lib/otoroshi.rb +4 -5
- data/lib/otoroshi/exceptions.rb +68 -52
- data/lib/otoroshi/initializer.rb +41 -52
- data/lib/otoroshi/sanctuary.rb +91 -125
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 631d80a9acb35b29a4f484aaf3ac8939f4aec80266ae85ec3ae1ba8025134789
|
4
|
+
data.tar.gz: 5fbb90ac33bfdd9ab712e5778479d3acca98486ec926761eddd5821c9fe251c2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 886d405d6229444887764ac8b07142e08ca9f78ceeb8f73217ed3a52b3782a303e56f5ec920bf749d7f32057bbc2030a1f0f47df7f33904eba63681d82e01e2f
|
7
|
+
data.tar.gz: d01ba382078e0dac14e9a1e2965c85c659cc6bd14e99a986746c209ff4b8982bbe62e2d2194b15c57919555378aa31e6b42331af32e3208e48155c716b7183a3
|
data/lib/otoroshi.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'otoroshi/sanctuary'
|
4
|
-
require_relative 'otoroshi/exceptions'
|
5
|
-
|
6
3
|
# Otoroshi entry-point
|
7
|
-
|
8
|
-
|
4
|
+
module Otoroshi
|
5
|
+
require_relative 'otoroshi/sanctuary'
|
6
|
+
require_relative 'otoroshi/exceptions'
|
7
|
+
end
|
data/lib/otoroshi/exceptions.rb
CHANGED
@@ -1,73 +1,89 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative './initializer'
|
4
|
+
|
3
5
|
module Otoroshi
|
4
6
|
class Error < StandardError; end
|
5
7
|
|
6
|
-
# Manages errors raised when value
|
7
|
-
class
|
8
|
-
# Initialize an error
|
9
|
-
#
|
8
|
+
# Manages errors raised when value is not an instance of the expected class
|
9
|
+
class TypeError < Error
|
10
10
|
# @param property [Symbol] name of the property
|
11
11
|
# @param type [Class] class to match
|
12
|
-
# @
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
if collection
|
17
|
-
":#{property} contains elements that are not instances of #{expected_type}"
|
18
|
-
else
|
19
|
-
":#{property} is not an instance of #{expected_type}"
|
20
|
-
end
|
21
|
-
super(msg)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
# Manages errors raised when value should be an collection
|
26
|
-
class NotAnArray < Error
|
27
|
-
# Initialize an error
|
28
|
-
#
|
29
|
-
# @param property [Symbol] name of the property
|
30
|
-
def initialize(property)
|
31
|
-
msg = ":#{property} is not an array"
|
32
|
-
super(msg)
|
12
|
+
# @example
|
13
|
+
# ":number is not an instance of Integer"
|
14
|
+
def initialize(property, type)
|
15
|
+
super ":#{property} is not an instance of #{type}"
|
33
16
|
end
|
34
17
|
end
|
35
18
|
|
36
|
-
# Manages errors raised when value is not accepted (not
|
37
|
-
class
|
38
|
-
# Initialize an error
|
39
|
-
#
|
19
|
+
# Manages errors raised when value is not accepted (not in the "one_of")
|
20
|
+
class OneOfError < Error
|
40
21
|
# @param property [Symbol] name of the property
|
41
|
-
# @param
|
42
|
-
# @
|
43
|
-
|
22
|
+
# @param values [Array] accepted values
|
23
|
+
# @example
|
24
|
+
# ":fruit is not in [:apple, :pear]"
|
25
|
+
def initialize(property, values)
|
44
26
|
# reintegrate the colon for symbols which is lost during interpolation
|
45
27
|
to_s = ->(v) { v.is_a?(Symbol) ? ":#{v}" : v }
|
46
|
-
|
47
|
-
|
48
|
-
if collection
|
49
|
-
":#{property} contains elements that are not included in [#{accepted_values_list}]"
|
50
|
-
else
|
51
|
-
":#{property} is not included in [#{accepted_values_list}]"
|
52
|
-
end
|
53
|
-
super(msg)
|
28
|
+
list = values.map { |v| to_s.call(v) }.join(', ')
|
29
|
+
super ":#{property} is not in [#{list}]"
|
54
30
|
end
|
55
31
|
end
|
56
32
|
|
57
33
|
# Manages errors raised when value does not pass the assertion
|
58
|
-
class
|
59
|
-
# Initialize an error
|
60
|
-
#
|
34
|
+
class AssertError < Error
|
61
35
|
# @param property [Symbol] name of the property
|
62
|
-
# @
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
36
|
+
# @example
|
37
|
+
# ":number does not respect the assertion"
|
38
|
+
def initialize(property)
|
39
|
+
super ":#{property} does not respect the assertion"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module Collection
|
44
|
+
# Manages errors raised when value should be an collection
|
45
|
+
class ArrayError < Error
|
46
|
+
# @param property [Symbol] name of the property
|
47
|
+
# @example
|
48
|
+
# ":numbers is not an array"
|
49
|
+
def initialize(property)
|
50
|
+
super ":#{property} is not an array"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Manages errors raised when at least one element of the collection is not an instance of the expected class
|
55
|
+
class TypeError < Error
|
56
|
+
# @param property [Symbol] name of the property
|
57
|
+
# @param type [Class] class to match
|
58
|
+
# @example
|
59
|
+
# ":numbers contains elements that are not instances of Integer"
|
60
|
+
def initialize(property, type)
|
61
|
+
super ":#{property} contains elements that are not instances of #{type}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Manages errors raised when at least one element of the collection is not accepted (not in the "one_of")
|
66
|
+
class OneOfError < Error
|
67
|
+
# @param property [Symbol] name of the property
|
68
|
+
# @param values [Array] accepted values
|
69
|
+
# @example
|
70
|
+
# ":fruits contains elements that are not in [:apple, :pear]"
|
71
|
+
def initialize(property, values)
|
72
|
+
# reintegrate the colon for symbols which is lost during interpolation
|
73
|
+
to_s = ->(v) { v.is_a?(Symbol) ? ":#{v}" : v }
|
74
|
+
list = values.map { |v| to_s.call(v) }.join(', ')
|
75
|
+
super ":#{property} contains elements that are not in [#{list}]"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Manages errors raised when value does not pass the assertion
|
80
|
+
class AssertError < Error
|
81
|
+
# @param property [Symbol] name of the property
|
82
|
+
# @example
|
83
|
+
# ":numbers contains elements that do not respect the assertion"
|
84
|
+
def initialize(property)
|
85
|
+
super ":#{property} contains elements that do not respect the assertion"
|
86
|
+
end
|
71
87
|
end
|
72
88
|
end
|
73
89
|
end
|
data/lib/otoroshi/initializer.rb
CHANGED
@@ -13,9 +13,10 @@ module Otoroshi
|
|
13
13
|
#
|
14
14
|
# @example
|
15
15
|
# <<-RUBY
|
16
|
-
# def initialize(
|
17
|
-
# self.
|
18
|
-
# self.
|
16
|
+
# def initialize(number: 0, message:, fruits: [])
|
17
|
+
# self.number = number
|
18
|
+
# self.message = message
|
19
|
+
# self.fruits = fruits
|
19
20
|
# end
|
20
21
|
# RUBY
|
21
22
|
def draw(properties)
|
@@ -42,10 +43,9 @@ module Otoroshi
|
|
42
43
|
# end
|
43
44
|
# RUBY
|
44
45
|
def draw
|
45
|
-
|
46
|
+
<<~RUBY
|
46
47
|
def initialize(#{initialize_parameters})
|
47
|
-
#{
|
48
|
-
#{initialize_push_singletons}
|
48
|
+
#{initialize_body}
|
49
49
|
end
|
50
50
|
RUBY
|
51
51
|
end
|
@@ -58,8 +58,8 @@ module Otoroshi
|
|
58
58
|
#
|
59
59
|
# @return [String]
|
60
60
|
#
|
61
|
-
# @example
|
62
|
-
#
|
61
|
+
# @example
|
62
|
+
# "foo:, bar: 0"
|
63
63
|
def initialize_parameters
|
64
64
|
parameters =
|
65
65
|
properties.map do |key, options|
|
@@ -68,23 +68,41 @@ module Otoroshi
|
|
68
68
|
parameters.join(', ')
|
69
69
|
end
|
70
70
|
|
71
|
-
#
|
71
|
+
# Generates the default value of a parameter depending on options
|
72
72
|
#
|
73
73
|
# @return [String]
|
74
74
|
#
|
75
75
|
# @example when nil is allowed and default is set
|
76
|
-
#
|
76
|
+
# " \"default\""
|
77
77
|
# @example when nil is allowed and default is not set
|
78
|
-
#
|
78
|
+
# " nil"
|
79
79
|
# @example when nil is not allowed
|
80
|
-
#
|
80
|
+
# ""
|
81
81
|
def default_parameter_for(options)
|
82
82
|
default, allow_nil = options.values_at(:default, :allow_nil)
|
83
|
-
if default
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
83
|
+
return ' nil' if default.nil? && allow_nil
|
84
|
+
return '' if default.nil? && !allow_nil
|
85
|
+
|
86
|
+
" #{prefix(default)}#{default}#{suffix(default)}"
|
87
|
+
end
|
88
|
+
|
89
|
+
# Generates the characters to put before the value
|
90
|
+
# @note it avoids symbol without colon or string without quotes
|
91
|
+
# which would be interpreted as methods
|
92
|
+
def prefix(default)
|
93
|
+
case default
|
94
|
+
when Symbol then ':'
|
95
|
+
when String then '"'
|
96
|
+
when Time, Date, DateTime then '"'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Generates the characters to put after the value
|
101
|
+
# @note it avoids string without quotes which would be interpreted as method
|
102
|
+
def suffix(default)
|
103
|
+
case default
|
104
|
+
when String then '"'
|
105
|
+
when Time, Date, DateTime then '"'
|
88
106
|
end
|
89
107
|
end
|
90
108
|
|
@@ -93,45 +111,16 @@ module Otoroshi
|
|
93
111
|
# @return [String]
|
94
112
|
#
|
95
113
|
# @example Given properties { foo: { allow_nil: false, default: nil }, { allow_nil: true, default: 0 } }
|
96
|
-
#
|
97
|
-
|
114
|
+
# <<-RUBY
|
115
|
+
# self.foo = foo
|
116
|
+
# self.bar = bar
|
117
|
+
# RUBY
|
118
|
+
def initialize_body
|
98
119
|
assignments =
|
99
120
|
properties.keys.map do |name|
|
100
121
|
"self.#{name} = #{name}"
|
101
122
|
end
|
102
|
-
assignments.join("\n")
|
103
|
-
end
|
104
|
-
|
105
|
-
# Generates push singleton for each array property
|
106
|
-
#
|
107
|
-
# @return [String]
|
108
|
-
def initialize_push_singletons
|
109
|
-
collections =
|
110
|
-
properties.select do |_, options|
|
111
|
-
options[:type].is_a?(Array) || options[:type] == Array
|
112
|
-
end
|
113
|
-
singletons =
|
114
|
-
collections.keys.map do |name|
|
115
|
-
initialize_push_singleton(name)
|
116
|
-
end
|
117
|
-
singletons.join("\n")
|
118
|
-
end
|
119
|
-
|
120
|
-
# Generates singleton on collection instance variable to overide <<
|
121
|
-
# so value is validated before being added to the collection
|
122
|
-
#
|
123
|
-
# @return [String]
|
124
|
-
def initialize_push_singleton(name)
|
125
|
-
<<-RUBY
|
126
|
-
bind = self
|
127
|
-
@#{name}.singleton_class.send(:define_method, :<<) do |v|
|
128
|
-
bind.send(:"validate_#{name}_type!", [v])
|
129
|
-
bind.send(:"validate_#{name}_inclusion!", [v])
|
130
|
-
bind.send(:"validate_#{name}_assertion!", [v])
|
131
|
-
|
132
|
-
push(v)
|
133
|
-
end
|
134
|
-
RUBY
|
123
|
+
assignments.join("\n ")
|
135
124
|
end
|
136
125
|
end
|
137
126
|
end
|
data/lib/otoroshi/sanctuary.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require_relative 'initializer'
|
4
4
|
|
5
5
|
module Otoroshi
|
6
|
-
# This module is designed to be
|
6
|
+
# This module is designed to be in a class. This will provide
|
7
7
|
# the "property" ({Sanctuary::ClassMethods.property}) method for defining class properties.
|
8
8
|
#
|
9
9
|
# @example
|
@@ -45,29 +45,33 @@ module Otoroshi
|
|
45
45
|
# property scores, type: [Integer], assert: ->(v) { v >= 0 }, default: []
|
46
46
|
def property(name, type = Object, one_of: nil, assert: ->(_) { true }, allow_nil: false, default: nil)
|
47
47
|
add_to_properties(name, type, allow_nil, default)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
expected_type = type.is_a?(Array) ? type.first || Object : type
|
49
|
+
collection = expected_type == Array || type.is_a?(Array)
|
50
|
+
define_validate_type(name, expected_type, collection, allow_nil)
|
51
|
+
define_validate_one_of(name, collection, one_of, allow_nil)
|
52
|
+
define_validate_assertion(name, collection, assert, allow_nil)
|
53
|
+
define_validate(name)
|
52
54
|
define_getter(name)
|
53
55
|
define_setter(name)
|
54
56
|
class_eval Initializer.draw(properties), __FILE__, __LINE__ + 1
|
55
57
|
end
|
56
58
|
|
57
|
-
#
|
59
|
+
# Class properties
|
58
60
|
#
|
59
61
|
# @return [Hash]
|
60
62
|
#
|
61
|
-
# @
|
63
|
+
# @example
|
64
|
+
# {
|
65
|
+
# number: { type: Integer, allow_nil: false, default: 0 },
|
66
|
+
# message: { type: Integer, allow_nil: true, default: nil }
|
67
|
+
# }
|
62
68
|
def properties
|
63
69
|
{}
|
64
70
|
end
|
65
71
|
|
66
72
|
private
|
67
73
|
|
68
|
-
#
|
69
|
-
#
|
70
|
-
# @return [void]
|
74
|
+
# Adds a properties to the {properties}
|
71
75
|
def add_to_properties(name, type, allow_nil, default)
|
72
76
|
current_state = properties
|
73
77
|
current_state[name] = {
|
@@ -78,180 +82,142 @@ module Otoroshi
|
|
78
82
|
define_singleton_method(:properties) { current_state }
|
79
83
|
end
|
80
84
|
|
81
|
-
# Defines a private method that
|
85
|
+
# Defines a private method that validates type condition
|
82
86
|
#
|
83
|
-
#
|
87
|
+
# Given name = :score, type = Integer, allow_nil = false
|
84
88
|
#
|
85
|
-
#
|
86
|
-
# define_validate_type!(:score, Integer, false) => def validate_score_type!(value) ...
|
87
|
-
# @example Generated method
|
88
|
-
# # given name: :score, type: Integer, allow_nil: false
|
89
|
-
# def validate_score_type!(value)
|
89
|
+
# def validate_score_type(value)
|
90
90
|
# return if Integer.nil? || false && value.nil?
|
91
91
|
# return if value.is_a? Integer
|
92
92
|
#
|
93
|
-
# raise
|
93
|
+
# raise Otoroshi::TypeError, :score, Integer
|
94
94
|
# end
|
95
|
-
def define_validate_type
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
return if allow_nil && value.nil?
|
100
|
-
|
101
|
-
collection && check_collection.call(value)
|
102
|
-
return if lambda.call(value)
|
103
|
-
|
104
|
-
raise Otoroshi::WrongTypeError.new(name, type, collection: collection)
|
95
|
+
def define_validate_type(name, type, collection, allow_nil)
|
96
|
+
validator = validate_type?(name, type, collection)
|
97
|
+
define_method :"validate_#{name}_type" do |value|
|
98
|
+
allow_nil && value.nil? || validator.call(value)
|
105
99
|
end
|
106
|
-
private :"validate_#{name}_type
|
100
|
+
private :"validate_#{name}_type"
|
107
101
|
end
|
108
102
|
|
109
|
-
#
|
110
|
-
#
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
# @note params are used for binding in define_method scope
|
119
|
-
def type_validation(type)
|
120
|
-
if type == Array
|
121
|
-
# no expected type for each element, return nil
|
122
|
-
->(_) {}
|
123
|
-
elsif type.is_a?(Array)
|
124
|
-
# get the real expected type
|
125
|
-
# e.g. if type is [Integer] then element_type should be Integer
|
126
|
-
# e.g. if type is [] then element_type should be Object
|
127
|
-
element_type = type.first || Object
|
128
|
-
# apply type_validation lambda on each element
|
129
|
-
->(v) { v.all? { |e| type_validation(element_type).call(e) } }
|
103
|
+
# Lambda that validates (value) respects the type condition
|
104
|
+
# @return [Proc]
|
105
|
+
def validate_type?(name, type, collection)
|
106
|
+
if collection
|
107
|
+
# validate each element of (v) is an instance of the type
|
108
|
+
lambda do |v|
|
109
|
+
v.is_a?(Array) || raise(Otoroshi::Collection::ArrayError, name)
|
110
|
+
v.all? { |elt| elt.is_a? type } || raise(Otoroshi::Collection::TypeError.new(name, type))
|
111
|
+
end
|
130
112
|
else
|
131
|
-
#
|
132
|
-
->(v) { v.is_a? type }
|
113
|
+
# validate (v) is an instance of the type
|
114
|
+
->(v) { v.is_a?(type) || raise(Otoroshi::TypeError.new(name, type)) }
|
133
115
|
end
|
134
116
|
end
|
135
117
|
|
136
|
-
# Defines a private method that
|
118
|
+
# Defines a private method that validates one_of condition
|
137
119
|
#
|
138
|
-
#
|
120
|
+
# Given name = :side, collection = false, one_of = [:left, :right], allow_nil = false
|
139
121
|
#
|
140
|
-
#
|
141
|
-
# # given @name = :side
|
142
|
-
# define_validate_inclusion!(:side, ...) => def validate_side_type!(value) ...
|
143
|
-
# @example Generated method
|
144
|
-
# # given name: :side, collection: false, one_of: [:left, :right], allow_nil: false
|
145
|
-
# def validate_side_type!(value)
|
122
|
+
# def validate_side_type(value)
|
146
123
|
# return if false && value.nil?
|
147
124
|
# return if [:left, :right].include? value
|
148
125
|
#
|
149
|
-
# raise
|
126
|
+
# raise Otoroshi::OneOfError, :side, [:left, :right]
|
150
127
|
# end
|
151
|
-
def
|
152
|
-
validator =
|
153
|
-
|
154
|
-
|
155
|
-
allow_nil && value.nil? || validator.call(value)
|
156
|
-
end
|
157
|
-
else
|
158
|
-
define_method(:"validate_#{name}_inclusion!") { |_| }
|
128
|
+
def define_validate_one_of(name, collection, one_of, allow_nil)
|
129
|
+
validator = validate_one_of?(name, one_of, collection)
|
130
|
+
define_method(:"validate_#{name}_one_of") do |value|
|
131
|
+
allow_nil && value.nil? || validator.call(value)
|
159
132
|
end
|
160
|
-
private :"validate_#{name}
|
133
|
+
private :"validate_#{name}_one_of"
|
161
134
|
end
|
162
135
|
|
163
|
-
#
|
164
|
-
#
|
165
|
-
|
166
|
-
|
167
|
-
lambda do |v|
|
168
|
-
one_of.include?(v) || raise(Otoroshi::NotAcceptedError.new(name, one_of))
|
169
|
-
end
|
170
|
-
end
|
136
|
+
# Lambda that validates (value) respects the one_of condition
|
137
|
+
# @return [Proc]
|
138
|
+
def validate_one_of?(name, one_of, collection)
|
139
|
+
return ->(_) {} unless one_of
|
171
140
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
141
|
+
if collection
|
142
|
+
lambda do |v|
|
143
|
+
v.all? { |e| one_of.include? e } || raise(Otoroshi::Collection::OneOfError.new(name, one_of))
|
144
|
+
end
|
145
|
+
else
|
146
|
+
lambda do |v|
|
147
|
+
one_of.include?(v) || raise(Otoroshi::OneOfError.new(name, one_of))
|
148
|
+
end
|
178
149
|
end
|
179
150
|
end
|
180
151
|
|
181
|
-
# Defines a private method that
|
152
|
+
# Defines a private method that validates assert condition
|
182
153
|
#
|
183
|
-
#
|
154
|
+
# Given name = :score, assert = ->(v) { v >= 0 }, allow_nil = false
|
184
155
|
#
|
185
|
-
#
|
186
|
-
# define_validate_assertion!(:score, ...) #=> def validate_score_assertion!(value) ...
|
187
|
-
# @example Generated instance method
|
188
|
-
# # given name: :score, assert: >(v) { v >= 0 }, allow_nil: false
|
189
|
-
# def validate_score_assertion!(value)
|
156
|
+
# def validate_score_assertion(value)
|
190
157
|
# return if false && value.nil?
|
191
158
|
# return if value >= 0
|
192
159
|
#
|
193
|
-
# raise
|
160
|
+
# raise Otoroshi::AssertError, :score
|
194
161
|
# end
|
195
|
-
def define_validate_assertion
|
196
|
-
validator =
|
197
|
-
define_method :"validate_#{name}_assertion
|
162
|
+
def define_validate_assertion(name, collection, assert, allow_nil)
|
163
|
+
validator = validate_assert?(name, assert, collection)
|
164
|
+
define_method :"validate_#{name}_assertion" do |value|
|
198
165
|
allow_nil && value.nil? || validator.call(value)
|
199
166
|
end
|
200
|
-
private :"validate_#{name}_assertion
|
167
|
+
private :"validate_#{name}_assertion"
|
201
168
|
end
|
202
169
|
|
203
|
-
#
|
204
|
-
#
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
170
|
+
# Lambda that validates (value) respects the assert condition
|
171
|
+
# @return [Proc]
|
172
|
+
def validate_assert?(name, assert, collection)
|
173
|
+
if collection
|
174
|
+
->(v) { v.all? { |e| instance_exec(e, &assert) } || raise(Otoroshi::Collection::AssertError, name) }
|
175
|
+
else
|
176
|
+
->(v) { instance_exec(v, &assert) || raise(Otoroshi::AssertError, name) }
|
209
177
|
end
|
210
178
|
end
|
211
179
|
|
212
|
-
# Defines a
|
180
|
+
# Defines a private method that calls all validations
|
213
181
|
#
|
214
|
-
#
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
182
|
+
# Given name = :score
|
183
|
+
#
|
184
|
+
# def validate_score!(value)
|
185
|
+
# validate_score_type(value)
|
186
|
+
# validate_score_one_of(value)
|
187
|
+
# validate_score_assert(value)
|
188
|
+
# end
|
189
|
+
def define_validate(name)
|
190
|
+
define_method :"validate_#{name}!" do |value|
|
191
|
+
__send__(:"validate_#{name}_type", value)
|
192
|
+
__send__(:"validate_#{name}_one_of", value)
|
193
|
+
__send__(:"validate_#{name}_assertion", value)
|
219
194
|
end
|
195
|
+
private :"validate_#{name}!"
|
220
196
|
end
|
221
197
|
|
222
|
-
# Defines a getter
|
198
|
+
# Defines a getter
|
223
199
|
#
|
224
|
-
#
|
200
|
+
# Given name = :score
|
225
201
|
#
|
226
|
-
# @example
|
227
|
-
# define_getter(:score) #=> def score ...
|
228
|
-
# @example Generated instance method
|
229
|
-
# # given name: :score
|
230
202
|
# def score
|
231
203
|
# instance_variable_get(@score)
|
232
204
|
# end
|
233
205
|
def define_getter(name)
|
234
|
-
define_method(name) { instance_variable_get("@#{name}") }
|
206
|
+
define_method(name) { instance_variable_get("@#{name}").clone.freeze }
|
235
207
|
end
|
236
208
|
|
237
|
-
# Defines a setter
|
209
|
+
# Defines a setter
|
238
210
|
#
|
239
|
-
#
|
211
|
+
# Given name = :score
|
240
212
|
#
|
241
|
-
# @example
|
242
|
-
# define_setter(:score) #=> def score=(value) ...
|
243
|
-
# @example Generated instance method
|
244
|
-
# # given name: :score
|
245
213
|
# def score=(value)
|
246
|
-
# validate_score_type
|
214
|
+
# validate_score_type(value)
|
247
215
|
# validate_score!(value)
|
248
216
|
# instance_variable_set(@score, value)
|
249
217
|
# end
|
250
218
|
def define_setter(name)
|
251
219
|
define_method :"#{name}=" do |value|
|
252
|
-
__send__(:"validate_#{name}
|
253
|
-
__send__(:"validate_#{name}_inclusion!", value)
|
254
|
-
__send__(:"validate_#{name}_assertion!", value)
|
220
|
+
__send__(:"validate_#{name}!", value)
|
255
221
|
instance_variable_set("@#{name}", value)
|
256
222
|
end
|
257
223
|
end
|