otoroshi 0.0.1

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.
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: []