otoroshi 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/otoroshi/sanctuary.rb +165 -0
  3. metadata +43 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2993a278f341533c1590cd6bdea9291033167104f94018808577f67cbcd2f0ae
4
+ data.tar.gz: 725a187567625f428485a80edd5025b0ae7e3a859bebd4d73ea14557353a89ad
5
+ SHA512:
6
+ metadata.gz: c14d31b349b599ff5ef0db40dbaed8723b47bd53de648589ace6ac8ccfeba85b926d263070fe7d13a0746168399508127cd4e3a33df032ff8cfef5d5a9d5380c
7
+ data.tar.gz: 19311d09a63ee50e89bd3b3c7dead8faeaba0bd1a4803dfba363c422b0c13704fbeb3bb60799cfac9d681736e209d1587b44be76840bc5736aff4822c6cf9c24
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Otoroshi
4
+ # help setting and validating instance arguments
5
+ class Sanctuary
6
+ class << self
7
+ # Add a new property to the class (called by inherited class)
8
+ # Example: property name, type: String, validate: ->(v) { v.length > 3 }, optional: true
9
+ def property(name, type = Object, validate: ->(_) { true }, optional: false, default: nil)
10
+ define_default(name, default)
11
+ define_validate_type!(name, type, optional)
12
+ define_validate!(name, validate, optional)
13
+ define_getter(name)
14
+ define_setter(name)
15
+ add_to_properties(name)
16
+ end
17
+
18
+ # Return the (inherited) class properties
19
+ # (this method will be updated by ::add_to_properties(name))
20
+ def properties
21
+ []
22
+ end
23
+
24
+ private
25
+
26
+ # Update the ::properties method to add new property to the current list
27
+ def add_to_properties(name)
28
+ current = properties
29
+ define_singleton_method :properties do
30
+ current << name
31
+ end
32
+ end
33
+
34
+ # Define a private method that returns the default value
35
+ #
36
+ # ::define_default("score", 0)
37
+ # --------------------------
38
+ # def default_score
39
+ # 0
40
+ # end
41
+ #
42
+ def define_default(name, default)
43
+ define_method(:"default_#{name}") { default }
44
+ private :"default_#{name}"
45
+ end
46
+
47
+ # Define a private method that raises an error if type is not respected
48
+ #
49
+ # ::define_validate_type!("score", Integer, false)
50
+ # ----------------------------------------------
51
+ # def validate_score_type!(value)
52
+ # return if optional && value.nil?
53
+ # return if value.is_a?(Integer)
54
+ #
55
+ # raise ArgumentError, ":score does not match type validation"
56
+ # end
57
+ #
58
+ def define_validate_type!(name, type, optional)
59
+ lambda = type_validation(type)
60
+ define_method :"validate_#{name}_type!" do |value|
61
+ return if type.nil? || optional && value.nil?
62
+ return if lambda.call(value)
63
+
64
+ raise ArgumentError, ":#{name} does not match type validation"
65
+ end
66
+ private :"validate_#{name}_type!"
67
+ end
68
+
69
+ # Define a lambda to be call to validate that value match the type
70
+ #
71
+ # ::type_validation(Integer)
72
+ # ----------------------------------------------
73
+ # ->(v) { v.is_a? Integer }
74
+ #
75
+ def type_validation(type)
76
+ if type.is_a? Array
77
+ ->(v) { type.any? { |t| v.is_a? t } }
78
+ else
79
+ ->(v) { v.is_a? type }
80
+ end
81
+ end
82
+
83
+ # Define a private method that raises an error if validate block returns false
84
+ #
85
+ # ::define_validate!("score", ->(v) { v >= 0 }, false)
86
+ # --------------------------------------------------
87
+ # def validate_score!(value)
88
+ # return if false && value.nil?
89
+ # return if value >= 0
90
+ #
91
+ # raise ArgumentError, ":score does not match validation"
92
+ # end
93
+ #
94
+ def define_validate!(name, validate, optional)
95
+ define_method :"validate_#{name}!" do |value|
96
+ return if optional && value.nil?
97
+ return if instance_exec(value, &validate)
98
+
99
+ raise ArgumentError, ":#{name} does not match validation"
100
+ end
101
+ private :"validate_#{name}!"
102
+ end
103
+
104
+ # Define a getter method for the property
105
+ #
106
+ # ::define_getter("score")
107
+ # ----------------------
108
+ # def score
109
+ # @score
110
+ # end
111
+ #
112
+ def define_getter(name)
113
+ define_method(name) { instance_variable_get("@#{name}") }
114
+ end
115
+
116
+ # Define a setter method for the property
117
+ #
118
+ # ::define_setter("score")
119
+ # ----------------------
120
+ # def score=(value)
121
+ # validate_score_type!(value)
122
+ # validate_score!(value)
123
+ # @score = value
124
+ # end
125
+ #
126
+ def define_setter(name)
127
+ define_method :"#{name}=" do |value|
128
+ __send__(:"validate_#{name}_type!", value)
129
+ __send__(:"validate_#{name}!", value)
130
+ instance_variable_set("@#{name}", value)
131
+ end
132
+ end
133
+ end
134
+
135
+ # Initialize an instance and validate provided args
136
+ def initialize(args = {}) # rubocop:disable Style/OptionHash
137
+ validate_keys!(args.keys)
138
+ assign_values(args)
139
+ end
140
+
141
+ private
142
+
143
+ # validate that provided keys match class properties
144
+ def validate_keys!(keys)
145
+ errors = keys.reject { |key| self.class.properties.include? key }
146
+ return if errors.empty?
147
+
148
+ message =
149
+ if errors.one?
150
+ ":#{errors[0]} is not a valid property"
151
+ else
152
+ ":#{errors.join(', :')} are not valid properties"
153
+ end
154
+ raise ArgumentError, message
155
+ end
156
+
157
+ # assign value to each property
158
+ def assign_values(args)
159
+ self.class.properties.each do |property|
160
+ value = args.key?(property) ? args[property] : __send__(:"default_#{property}")
161
+ public_send(:"#{property}=", value)
162
+ end
163
+ end
164
+ end
165
+ end
metadata ADDED
@@ -0,0 +1,43 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: otoroshi
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Edouard Piron
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-10-10 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Help setting and validating instance arguments
14
+ email: ed.piron@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/otoroshi/sanctuary.rb
20
+ homepage: https://rubygems.org/gems/otoroshi
21
+ licenses:
22
+ - MIT
23
+ metadata: {}
24
+ post_install_message:
25
+ rdoc_options: []
26
+ require_paths:
27
+ - lib
28
+ required_ruby_version: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '2.6'
33
+ required_rubygems_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ requirements: []
39
+ rubygems_version: 3.1.4
40
+ signing_key:
41
+ specification_version: 4
42
+ summary: Otoroshi
43
+ test_files: []