otoroshi 0.0.5 → 0.1.0
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 +7 -0
- data/lib/otoroshi/exceptions.rb +89 -0
- data/lib/otoroshi/initializer.rb +183 -0
- data/lib/otoroshi/sanctuary.rb +146 -131
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12cba26aea6aca35ae46692ed5f9e9e4a72c3231651a132c25e793d697c17dbc
|
4
|
+
data.tar.gz: eb24b1df208ef59c64f3a2ea045a52b578969d75fb6cef6907189b6512bb30e1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc8bd50a648a681442722ad6456535d76fe3bc2dfa2bb2e4041a1548f710c64634c9ebc10e5e02fd7b397f608f8abbc34f17a6aa4dc7dd190780e0d77cd9e60a
|
7
|
+
data.tar.gz: ab934b7e39d816afcaae0bb07d0a142904aecb11ece6e75fb4590974483fa9bcc476767583a2c74ae907d2e77afb04501e35044e9e999e89197025881c0a863b
|
data/lib/otoroshi.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './initializer'
|
4
|
+
|
5
|
+
module Otoroshi
|
6
|
+
class Error < StandardError; end
|
7
|
+
|
8
|
+
# Manages errors raised when value is not an instance of the expected class
|
9
|
+
class TypeError < Error
|
10
|
+
# @param property [Symbol] name of the property
|
11
|
+
# @param type [Class] class to match
|
12
|
+
# @example
|
13
|
+
# ":number is not an instance of Integer"
|
14
|
+
def initialize(property, type)
|
15
|
+
super ":#{property} is not an instance of #{type}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Manages errors raised when value is not accepted (not in the "one_of")
|
20
|
+
class OneOfError < Error
|
21
|
+
# @param property [Symbol] name of the property
|
22
|
+
# @param values [Array] accepted values
|
23
|
+
# @example
|
24
|
+
# ":fruit is not in [:apple, :pear]"
|
25
|
+
def initialize(property, values)
|
26
|
+
# reintegrate the colon for symbols which is lost during interpolation
|
27
|
+
to_s = ->(v) { v.is_a?(Symbol) ? ":#{v}" : v }
|
28
|
+
list = values.map { |v| to_s.call(v) }.join(', ')
|
29
|
+
super ":#{property} is not in [#{list}]"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Manages errors raised when value does not pass the assertion
|
34
|
+
class AssertError < Error
|
35
|
+
# @param property [Symbol] name of the property
|
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
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Otoroshi
|
4
|
+
# Drawing of #initialize method
|
5
|
+
#
|
6
|
+
class Initializer
|
7
|
+
class << self
|
8
|
+
# Draw a stringified initialize method
|
9
|
+
#
|
10
|
+
# @param properties [Hash] a description of the class properties
|
11
|
+
#
|
12
|
+
# @return [String]
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# <<-RUBY
|
16
|
+
# def initialize(number: 0, message:, fruits: [])
|
17
|
+
# self.number = number
|
18
|
+
# self.message = message
|
19
|
+
# self.fruits = fruits
|
20
|
+
# bind = self
|
21
|
+
# @fruits.singleton_class.send(:define_method, :<<) do |v|
|
22
|
+
# bind.send(:"validate_fruits!", [v])
|
23
|
+
# push(v)
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
# RUBY
|
27
|
+
def draw(properties)
|
28
|
+
new(properties).draw
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Initialize an instance
|
33
|
+
#
|
34
|
+
# @param properties [Hash] a description of the class properties
|
35
|
+
def initialize(properties = {})
|
36
|
+
@properties = properties
|
37
|
+
end
|
38
|
+
|
39
|
+
# Draws a stringified initialize method
|
40
|
+
#
|
41
|
+
# @return [String]
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
# <<-RUBY
|
45
|
+
# def initialize(foo:, bar: 0)
|
46
|
+
# self.foo = foo
|
47
|
+
# self.bar = bar
|
48
|
+
# end
|
49
|
+
# RUBY
|
50
|
+
def draw
|
51
|
+
<<~RUBY
|
52
|
+
def initialize(#{initialize_parameters})
|
53
|
+
#{initialize_assignments}
|
54
|
+
#{initialize_push_singletons}
|
55
|
+
end
|
56
|
+
RUBY
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
attr_reader :properties
|
62
|
+
|
63
|
+
# Generates initialize method parameters
|
64
|
+
#
|
65
|
+
# @return [String]
|
66
|
+
#
|
67
|
+
# @example
|
68
|
+
# "foo:, bar: 0"
|
69
|
+
def initialize_parameters
|
70
|
+
parameters =
|
71
|
+
properties.map do |key, options|
|
72
|
+
"#{key}:#{default_parameter_for(options)}"
|
73
|
+
end
|
74
|
+
parameters.join(', ')
|
75
|
+
end
|
76
|
+
|
77
|
+
# Generates the default value of a parameter depending on options
|
78
|
+
#
|
79
|
+
# @return [String]
|
80
|
+
#
|
81
|
+
# @example when nil is allowed and default is set
|
82
|
+
# " \"default\""
|
83
|
+
# @example when nil is allowed and default is not set
|
84
|
+
# " nil"
|
85
|
+
# @example when nil is not allowed
|
86
|
+
# ""
|
87
|
+
def default_parameter_for(options)
|
88
|
+
default, allow_nil = options.values_at(:default, :allow_nil)
|
89
|
+
if default.nil?
|
90
|
+
allow_nil ? ' nil' : ''
|
91
|
+
else
|
92
|
+
" #{prefix(default)}#{default}#{suffix(default)}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Generates the characters to put before the value
|
97
|
+
# @note it avoids symbol without colon or string without quotes
|
98
|
+
# which would be interpreted as methods
|
99
|
+
def prefix(default)
|
100
|
+
case default
|
101
|
+
when Symbol then ':'
|
102
|
+
when String then '"'
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Generates the characters to put after the value
|
107
|
+
# @note it avoids string without quotes which would be interpreted as method
|
108
|
+
def suffix(default)
|
109
|
+
case default
|
110
|
+
when String then '"'
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Generates initialize method assignments
|
115
|
+
#
|
116
|
+
# @return [String]
|
117
|
+
#
|
118
|
+
# @example Given properties { foo: { allow_nil: false, default: nil }, { allow_nil: true, default: 0 } }
|
119
|
+
# <<-RUBY
|
120
|
+
# self.foo = foo
|
121
|
+
# self.bar = bar
|
122
|
+
# RUBY
|
123
|
+
def initialize_assignments
|
124
|
+
assignments =
|
125
|
+
properties.keys.map do |name|
|
126
|
+
"self.#{name} = #{name}"
|
127
|
+
end
|
128
|
+
assignments.join("\n ")
|
129
|
+
end
|
130
|
+
|
131
|
+
# Generates push singleton for each array property
|
132
|
+
#
|
133
|
+
# @return [String]
|
134
|
+
#
|
135
|
+
# @example
|
136
|
+
# <<-RUBY
|
137
|
+
# bind = self
|
138
|
+
# @fruits.singleton_class.send(:define_method, :<<) do |v|
|
139
|
+
# bind.send(:"validate_fruits!", [v])
|
140
|
+
# push(v)
|
141
|
+
# end
|
142
|
+
# @numbers.singleton_class.send(:define_method, :<<) do |v|
|
143
|
+
# bind.send(:"validate_numbers!", [v])
|
144
|
+
# push(v)
|
145
|
+
# end
|
146
|
+
# RUBY
|
147
|
+
def initialize_push_singletons
|
148
|
+
collections =
|
149
|
+
properties.select do |_, options|
|
150
|
+
options[:type].is_a?(Array) || options[:type] == Array
|
151
|
+
end
|
152
|
+
return if collections.empty?
|
153
|
+
|
154
|
+
singletons =
|
155
|
+
collections.keys.map do |name|
|
156
|
+
initialize_push_singleton(name)
|
157
|
+
end
|
158
|
+
# assign self to a variable so the instance is accessible from the singleton scope
|
159
|
+
['bind = self', singletons.join].join("\n")
|
160
|
+
end
|
161
|
+
|
162
|
+
# Generates singleton on collection instance variable to overide <<
|
163
|
+
# so value is validated before being added to the collection
|
164
|
+
#
|
165
|
+
# @return [String]
|
166
|
+
#
|
167
|
+
# @example
|
168
|
+
# <<-RUBY
|
169
|
+
# @fruits.singleton_class.send(:define_method, :<<) do |v|
|
170
|
+
# bind.send(:"validate_fruits!", [v])
|
171
|
+
# push(v)
|
172
|
+
# end
|
173
|
+
# RUBY
|
174
|
+
def initialize_push_singleton(name)
|
175
|
+
<<-RUBY
|
176
|
+
@#{name}.singleton_class.send(:define_method, :<<) do |v|
|
177
|
+
bind.send(:"validate_#{name}!", [v])
|
178
|
+
push(v)
|
179
|
+
end
|
180
|
+
RUBY
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
data/lib/otoroshi/sanctuary.rb
CHANGED
@@ -1,16 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'initializer'
|
4
|
+
|
3
5
|
module Otoroshi
|
4
|
-
# This module is designed to be
|
6
|
+
# This module is designed to be in a class. This will provide
|
5
7
|
# the "property" ({Sanctuary::ClassMethods.property}) method for defining class properties.
|
8
|
+
#
|
6
9
|
# @example
|
7
10
|
# class Importer
|
8
11
|
# include Otoroshi::Sanctuary
|
9
12
|
#
|
10
|
-
# property :
|
11
|
-
# property :
|
12
|
-
# property :
|
13
|
-
# property :
|
13
|
+
# property :whatever
|
14
|
+
# property :number, Integer
|
15
|
+
# property :numbers, [Integer]
|
16
|
+
# property :positive_number, Integer, verify: ->(v) { v >= 0 }
|
17
|
+
# property :number_or_nil, Integer, allow_nil: true
|
18
|
+
# property :number_with_default, Integer, default: 42
|
19
|
+
# property :number_in_collection, Integer, one_of: [1, 2, 3, 5, 8, 13, 21, 34]
|
14
20
|
# end
|
15
21
|
module Sanctuary
|
16
22
|
class << self
|
@@ -23,125 +29,187 @@ module Otoroshi
|
|
23
29
|
# Class methods extended for the base class
|
24
30
|
module ClassMethods
|
25
31
|
# Adds a new "property" to the class
|
32
|
+
#
|
26
33
|
# @param name [Symbol] the property name
|
27
|
-
# @param type [Class] the expected value type
|
28
|
-
# @param
|
34
|
+
# @param type [Class, Array<Class>] the expected value or values type
|
35
|
+
# @param one_of [Array] the accepted values
|
36
|
+
# @param assert [Proc] a lambda processing the value and returning true or false
|
29
37
|
# @param allow_nil [true, false] allow nil as a value
|
30
38
|
# @param default [Object] default value if not set on initialization
|
39
|
+
#
|
31
40
|
# @return [void]
|
41
|
+
#
|
32
42
|
# @example
|
33
|
-
# property name, type: String,
|
43
|
+
# property name, type: String, assert: ->(v) { v.length > 3 }, allow_nil: true
|
34
44
|
# @example
|
35
|
-
# property
|
36
|
-
def property(name, type = Object,
|
37
|
-
add_to_properties(name, allow_nil, default)
|
38
|
-
|
39
|
-
|
45
|
+
# property scores, type: [Integer], assert: ->(v) { v >= 0 }, default: []
|
46
|
+
def property(name, type = Object, one_of: nil, assert: ->(_) { true }, allow_nil: false, default: nil)
|
47
|
+
add_to_properties(name, type, allow_nil, default)
|
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)
|
40
54
|
define_getter(name)
|
41
55
|
define_setter(name)
|
42
|
-
|
56
|
+
class_eval Initializer.draw(properties), __FILE__, __LINE__ + 1
|
43
57
|
end
|
44
58
|
|
45
|
-
#
|
59
|
+
# Class properties
|
60
|
+
#
|
46
61
|
# @return [Hash]
|
47
|
-
#
|
62
|
+
#
|
63
|
+
# @example
|
64
|
+
# {
|
65
|
+
# number: { type: Integer, allow_nil: false, default: 0 },
|
66
|
+
# message: { type: Integer, allow_nil: true, default: nil }
|
67
|
+
# }
|
48
68
|
def properties
|
49
69
|
{}
|
50
70
|
end
|
51
71
|
|
52
72
|
private
|
53
73
|
|
54
|
-
#
|
55
|
-
|
56
|
-
def add_to_properties(name, allow_nil, default)
|
74
|
+
# Adds a properties to the {properties}
|
75
|
+
def add_to_properties(name, type, allow_nil, default)
|
57
76
|
current_state = properties
|
58
|
-
current_state[name] = {
|
77
|
+
current_state[name] = {
|
78
|
+
type: type,
|
79
|
+
allow_nil: allow_nil,
|
80
|
+
default: default
|
81
|
+
}
|
59
82
|
define_singleton_method(:properties) { current_state }
|
60
83
|
end
|
61
84
|
|
62
|
-
# Defines a private method that
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
# @return [void]
|
67
|
-
# @example
|
68
|
-
# define_validate_type!(score, Integer, false) => def validate_score_type!(value) ...
|
69
|
-
# @example Generated method
|
85
|
+
# Defines a private method that validates type condition
|
86
|
+
#
|
87
|
+
# Given name = :score, type = Integer, allow_nil = false
|
88
|
+
#
|
70
89
|
# def validate_score_type!(value)
|
71
90
|
# return if Integer.nil? || false && value.nil?
|
72
91
|
# return if value.is_a? Integer
|
73
92
|
#
|
74
|
-
# raise
|
93
|
+
# raise Otoroshi::TypeError, :score, Integer
|
75
94
|
# end
|
76
|
-
def define_validate_type!(name, type, allow_nil)
|
77
|
-
|
95
|
+
def define_validate_type!(name, type, collection, allow_nil)
|
96
|
+
validator = validate_type?(name, type, collection)
|
78
97
|
define_method :"validate_#{name}_type!" do |value|
|
79
|
-
|
80
|
-
return if lambda.call(value)
|
81
|
-
|
82
|
-
raise ArgumentError, ":#{name} does not match required type"
|
98
|
+
allow_nil && value.nil? || validator.call(value)
|
83
99
|
end
|
84
100
|
private :"validate_#{name}_type!"
|
85
101
|
end
|
86
102
|
|
87
|
-
#
|
88
|
-
# @
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
->(v) { type.any? { |t| v.is_a? t } }
|
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
|
97
112
|
else
|
98
|
-
|
113
|
+
# validate (v) is an instance of the type
|
114
|
+
->(v) { v.is_a?(type) || raise(Otoroshi::TypeError.new(name, type)) }
|
99
115
|
end
|
100
116
|
end
|
101
117
|
|
102
|
-
# Defines a private method that
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
#
|
109
|
-
#
|
110
|
-
#
|
118
|
+
# Defines a private method that validates one_of condition
|
119
|
+
#
|
120
|
+
# Given name = :side, collection = false, one_of = [:left, :right], allow_nil = false
|
121
|
+
#
|
122
|
+
# def validate_side_type!(value)
|
123
|
+
# return if false && value.nil?
|
124
|
+
# return if [:left, :right].include? value
|
125
|
+
#
|
126
|
+
# raise Otoroshi::OneOfError, :side, [:left, :right]
|
127
|
+
# end
|
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)
|
132
|
+
end
|
133
|
+
private :"validate_#{name}_one_of!"
|
134
|
+
end
|
135
|
+
|
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
|
140
|
+
|
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
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Defines a private method that validates assert condition
|
153
|
+
#
|
154
|
+
# Given name = :score, assert = ->(v) { v >= 0 }, allow_nil = false
|
155
|
+
#
|
156
|
+
# def validate_score_assertion!(value)
|
111
157
|
# return if false && value.nil?
|
112
158
|
# return if value >= 0
|
113
159
|
#
|
114
|
-
# raise
|
160
|
+
# raise Otoroshi::AssertError, :score
|
115
161
|
# end
|
116
|
-
def
|
117
|
-
|
118
|
-
|
119
|
-
|
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|
|
165
|
+
allow_nil && value.nil? || validator.call(value)
|
166
|
+
end
|
167
|
+
private :"validate_#{name}_assertion!"
|
168
|
+
end
|
120
169
|
|
121
|
-
|
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) }
|
122
177
|
end
|
123
|
-
private :"validate_#{name}_lambda!"
|
124
178
|
end
|
125
179
|
|
126
|
-
# Defines a
|
127
|
-
#
|
128
|
-
#
|
129
|
-
#
|
130
|
-
#
|
131
|
-
#
|
132
|
-
#
|
133
|
-
#
|
134
|
-
#
|
180
|
+
# Defines a private method that calls all validations
|
181
|
+
#
|
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)
|
194
|
+
end
|
195
|
+
private :"validate_#{name}!"
|
196
|
+
end
|
197
|
+
|
198
|
+
# Defines a getter
|
199
|
+
#
|
200
|
+
# Given name = :score
|
201
|
+
#
|
202
|
+
# def score
|
203
|
+
# instance_variable_get(@score)
|
204
|
+
# end
|
135
205
|
def define_getter(name)
|
136
206
|
define_method(name) { instance_variable_get("@#{name}") }
|
137
207
|
end
|
138
208
|
|
139
|
-
# Defines a setter
|
140
|
-
#
|
141
|
-
#
|
142
|
-
#
|
143
|
-
# define_getter(:score) #=> def score=(value) ...
|
144
|
-
# @example Generated instance method
|
209
|
+
# Defines a setter
|
210
|
+
#
|
211
|
+
# Given name = :score
|
212
|
+
#
|
145
213
|
# def score=(value)
|
146
214
|
# validate_score_type!(value)
|
147
215
|
# validate_score!(value)
|
@@ -149,63 +217,10 @@ module Otoroshi
|
|
149
217
|
# end
|
150
218
|
def define_setter(name)
|
151
219
|
define_method :"#{name}=" do |value|
|
152
|
-
__send__(:"validate_#{name}
|
153
|
-
__send__(:"validate_#{name}_lambda!", value)
|
220
|
+
__send__(:"validate_#{name}!", value)
|
154
221
|
instance_variable_set("@#{name}", value)
|
155
222
|
end
|
156
223
|
end
|
157
|
-
|
158
|
-
# Redefines initialize method
|
159
|
-
# @return [void]
|
160
|
-
# @note method is defined with `class_eval`
|
161
|
-
# @example Generated method
|
162
|
-
# def initialize(foo:, bar: 0)
|
163
|
-
# self.foo = foo
|
164
|
-
# self.bar = bar
|
165
|
-
# end
|
166
|
-
def redefine_initialize
|
167
|
-
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
168
|
-
def initialize(#{initialize_parameters})
|
169
|
-
#{initialize_body}
|
170
|
-
end
|
171
|
-
RUBY
|
172
|
-
end
|
173
|
-
|
174
|
-
# Defines initialize method parameters
|
175
|
-
# @return [String]
|
176
|
-
# @example Given properties { foo: { allow_nil: false, default: nil }, { allow_nil: true, default: 0 } }
|
177
|
-
# redefine_initialize #=> "foo:, bar: 0"
|
178
|
-
def initialize_parameters
|
179
|
-
parameters =
|
180
|
-
properties.map do |key, options|
|
181
|
-
allow_nil, default = options.values
|
182
|
-
"#{key}:#{default_parameter_for(allow_nil, default)}"
|
183
|
-
end
|
184
|
-
parameters.join(', ')
|
185
|
-
end
|
186
|
-
|
187
|
-
# Defines the default value of a parameter depending on options
|
188
|
-
# @param options [Hash]
|
189
|
-
# @return [String]
|
190
|
-
# @example when nil is allowed and default is set
|
191
|
-
# default_parameter_for(true, 0) #=> " 0"
|
192
|
-
# @example when nil is allowed and default is not set
|
193
|
-
# default_parameter_for(true, nil) #=> " nil"
|
194
|
-
# @example when nil is not allowed
|
195
|
-
# default_parameter_for(false, nil) #=> ""
|
196
|
-
def default_parameter_for(allow_nil, default)
|
197
|
-
return " #{default}" if default
|
198
|
-
|
199
|
-
allow_nil ? ' nil' : ''
|
200
|
-
end
|
201
|
-
|
202
|
-
# Defines initialize method body
|
203
|
-
# @return [String]
|
204
|
-
# @example Given properties { foo: { allow_nil: false, default: nil }, { allow_nil: true, default: 0 } }
|
205
|
-
# initialize_body #=> "self.foo = foo\nself.bar = bar"
|
206
|
-
def initialize_body
|
207
|
-
properties.keys.map { |key| "self.#{key} = #{key}" }.join("\n")
|
208
|
-
end
|
209
224
|
end
|
210
225
|
end
|
211
226
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: otoroshi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Edouard Piron
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-10-
|
11
|
+
date: 2020-10-16 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Help defining class properties
|
14
14
|
email: ed.piron@gmail.com
|
@@ -16,6 +16,9 @@ executables: []
|
|
16
16
|
extensions: []
|
17
17
|
extra_rdoc_files: []
|
18
18
|
files:
|
19
|
+
- lib/otoroshi.rb
|
20
|
+
- lib/otoroshi/exceptions.rb
|
21
|
+
- lib/otoroshi/initializer.rb
|
19
22
|
- lib/otoroshi/sanctuary.rb
|
20
23
|
homepage: https://rubygems.org/gems/otoroshi
|
21
24
|
licenses:
|