statinize 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/statinize/attribute.rb +40 -0
- data/lib/statinize/caster.rb +48 -0
- data/lib/statinize/errors.rb +19 -0
- data/lib/statinize/statinizable.rb +54 -0
- data/lib/statinize/statinizer.rb +27 -0
- data/lib/statinize/validator.rb +112 -0
- data/lib/statinize/validators/presence_validator.rb +29 -0
- data/lib/statinize/validators/type_validator.rb +11 -0
- data/lib/statinize.rb +10 -0
- metadata +52 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 51c0c480de402d268d6d85db85624f112019e8ee9456e7f32553dac8f42821d5
|
4
|
+
data.tar.gz: fd177fd2e864c68370840a2c5cdbc0725b7eaa8eeff9358d2a14061176a16de5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a262a3f5f8afee169fab603fbc1530f4f84052d7786d47f3eb2bfbed4b3a2c939e15175e800a0aee1c9ce6f47cc0d4627395fe8c8c2862d40cc1d155754278b0
|
7
|
+
data.tar.gz: 752cb938cef235da3efdf2da7be11b96a3319cab0ee6eda7f58c8a3326d9c8b33c7622d8da7163f9e71a5e9341eb679904e82ef77184de62a0c64033b00da528
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Statinize
|
2
|
+
class Attribute
|
3
|
+
include Comparable
|
4
|
+
|
5
|
+
attr_reader :klass, :name, :options, :validators
|
6
|
+
|
7
|
+
def initialize(klass, name, options)
|
8
|
+
@klass = klass
|
9
|
+
@name = name
|
10
|
+
@options = options
|
11
|
+
@validators = options.keys
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.create(klass, name, options)
|
15
|
+
new(klass, name, options).create
|
16
|
+
end
|
17
|
+
|
18
|
+
def create
|
19
|
+
statinizer.add_attribute(self) unless attribute_exists?
|
20
|
+
klass.send(:attr_accessor, name)
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def <=>(other)
|
25
|
+
name == other.name &&
|
26
|
+
options == other.options &&
|
27
|
+
klass == other.klass
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def statinizer
|
33
|
+
klass.statinizer
|
34
|
+
end
|
35
|
+
|
36
|
+
def attribute_exists?
|
37
|
+
statinizer.attribute_exists?(self)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Statinize
|
2
|
+
class Caster
|
3
|
+
TYPE_CASTINGS = {
|
4
|
+
Integer => :to_i,
|
5
|
+
String => :to_s,
|
6
|
+
Float => :to_f,
|
7
|
+
Complex => :to_c,
|
8
|
+
Rational => :to_r,
|
9
|
+
Symbol => :to_sym,
|
10
|
+
Enumerator => :to_enum,
|
11
|
+
Proc => :to_proc
|
12
|
+
}.freeze
|
13
|
+
|
14
|
+
def initialize(instance, attr_name, attr_value, validator_value)
|
15
|
+
@instance = instance
|
16
|
+
@attr_name = attr_name
|
17
|
+
@attr_value = attr_value
|
18
|
+
@validator_value = validator_value
|
19
|
+
end
|
20
|
+
|
21
|
+
def cast
|
22
|
+
return false unless castable?
|
23
|
+
|
24
|
+
instance.public_send("#{attr_name}=", casted)
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.cast(instance, attr_name, attr_value, validator_value)
|
29
|
+
new(instance, attr_name, attr_value, validator_value).cast
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_reader :instance, :attr_name, :attr_value, :validator_value
|
35
|
+
|
36
|
+
def castable?
|
37
|
+
attr_value.respond_to? casting
|
38
|
+
end
|
39
|
+
|
40
|
+
def casting
|
41
|
+
@casting ||= TYPE_CASTINGS[validator_value]
|
42
|
+
end
|
43
|
+
|
44
|
+
def casted
|
45
|
+
@casted ||= attr_value.public_send(casting)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Statinize
|
2
|
+
class NotStatinizableError < StandardError; end
|
3
|
+
|
4
|
+
class ValidationError < StandardError; end
|
5
|
+
|
6
|
+
class NoSuchValidatorError < StandardError; end
|
7
|
+
|
8
|
+
class UncastableAttributeError < StandardError; end
|
9
|
+
|
10
|
+
class Errors < Array
|
11
|
+
def to_s
|
12
|
+
nice_errors = map do |i|
|
13
|
+
"#{i.keys.first.to_s.capitalize} #{i.values.first}"
|
14
|
+
end.join(', ')
|
15
|
+
|
16
|
+
"ValidationError: #{nice_errors}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Statinize
|
2
|
+
module Statinizable
|
3
|
+
def self.included(klass)
|
4
|
+
klass.extend(ClassMethods)
|
5
|
+
klass.prepend(PrependedMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module PrependedMethods
|
9
|
+
def initialize(*args, **kwargs)
|
10
|
+
self.class.statinizer.attrs.map(&:name).each do |attr|
|
11
|
+
instance_variable_set("@#{attr}", kwargs.delete(attr)) if kwargs.key?(attr)
|
12
|
+
end
|
13
|
+
|
14
|
+
validator.validate
|
15
|
+
|
16
|
+
super(*args, **kwargs)
|
17
|
+
end
|
18
|
+
|
19
|
+
def valid?
|
20
|
+
validator.valid?
|
21
|
+
end
|
22
|
+
|
23
|
+
def errors
|
24
|
+
validator.errors
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def validator
|
30
|
+
Validator.new(self)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module ClassMethods
|
35
|
+
def statinize(force: false, &block)
|
36
|
+
instance_variable_set('@statinizer', Statinizer.new(self, force))
|
37
|
+
|
38
|
+
class_eval do
|
39
|
+
def self.statinizer
|
40
|
+
@statinizer
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
block.call
|
45
|
+
end
|
46
|
+
|
47
|
+
def attributes(*attrs, **options)
|
48
|
+
attrs.each do |attr|
|
49
|
+
Attribute.create(self, attr, options)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Statinize
|
2
|
+
class Statinizer
|
3
|
+
attr_reader :attrs, :force
|
4
|
+
|
5
|
+
def initialize(klass, force)
|
6
|
+
@klass = klass
|
7
|
+
@force = force
|
8
|
+
@attrs = Set.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_attribute(attribute)
|
12
|
+
@attrs.add(attribute)
|
13
|
+
end
|
14
|
+
|
15
|
+
def forced_attributes
|
16
|
+
attrs.select { |attr| attr.validators.include? :force }
|
17
|
+
end
|
18
|
+
|
19
|
+
def casted_attributes
|
20
|
+
attrs.select { |attr| attr.validators.include? :cast }
|
21
|
+
end
|
22
|
+
|
23
|
+
def attribute_exists?(attribute)
|
24
|
+
attrs.include? attribute
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module Statinize
|
2
|
+
class Validator
|
3
|
+
NOT_VALIDATORS = %i[force cast].freeze
|
4
|
+
|
5
|
+
def initialize(instance)
|
6
|
+
@instance = instance
|
7
|
+
|
8
|
+
raise NotStatinizableError unless instance&.class&.statinizer.is_a?(Statinizer)
|
9
|
+
raise NoSuchValidatorError unless validators_exist?
|
10
|
+
|
11
|
+
@errors = Errors.new
|
12
|
+
@erroneous_attrs = Set.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def valid?
|
16
|
+
validate
|
17
|
+
return false unless errors.empty?
|
18
|
+
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
22
|
+
def invalid?
|
23
|
+
!valid?
|
24
|
+
end
|
25
|
+
|
26
|
+
def validate
|
27
|
+
attrs.each do |attr|
|
28
|
+
attr.options.each do |validator, validator_value|
|
29
|
+
next if NOT_VALIDATORS.include? validator
|
30
|
+
|
31
|
+
attr_name = attr.name
|
32
|
+
|
33
|
+
validator_class = Object.const_get("Statinize::#{validator.to_s.capitalize}Validator")
|
34
|
+
|
35
|
+
validator_instance = validator_class.new(instance)
|
36
|
+
|
37
|
+
validator_class.public_send(
|
38
|
+
:attr_accessor,
|
39
|
+
*%i[attr_name attr_value validator_value]
|
40
|
+
)
|
41
|
+
|
42
|
+
attr_value = instance.public_send attr_name
|
43
|
+
|
44
|
+
validator_instance.instance_variable_set('@attr_name', attr_name)
|
45
|
+
validator_instance.instance_variable_set('@attr_value', attr_value)
|
46
|
+
validator_instance.instance_variable_set('@validator_value', validator_value)
|
47
|
+
|
48
|
+
next if validator_instance.valid?
|
49
|
+
next if should_cast?(validator, attr_name) && casted?(attr_name, attr_value, validator_value)
|
50
|
+
|
51
|
+
@erroneous_attrs.add attr_name
|
52
|
+
add_error validator_instance.error
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
raise ValidationError, errors.to_s if should_raise?
|
57
|
+
end
|
58
|
+
|
59
|
+
protected
|
60
|
+
|
61
|
+
attr_reader :instance, :errors
|
62
|
+
|
63
|
+
def statinizer
|
64
|
+
@statinizer ||= instance.class.statinizer
|
65
|
+
end
|
66
|
+
|
67
|
+
def attrs
|
68
|
+
statinizer.attrs
|
69
|
+
end
|
70
|
+
|
71
|
+
def force?
|
72
|
+
statinizer.force
|
73
|
+
end
|
74
|
+
|
75
|
+
def should_raise?
|
76
|
+
force? || @erroneous_attrs.intersect?(forced_attributes.map(&:name))
|
77
|
+
end
|
78
|
+
|
79
|
+
def forced_attributes
|
80
|
+
statinizer.forced_attributes
|
81
|
+
end
|
82
|
+
|
83
|
+
def casted_attributes
|
84
|
+
statinizer.casted_attributes
|
85
|
+
end
|
86
|
+
|
87
|
+
def add_error(error)
|
88
|
+
return if error.nil?
|
89
|
+
|
90
|
+
@errors << error
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def validators_exist?
|
96
|
+
attrs
|
97
|
+
.flat_map(&:validators).uniq
|
98
|
+
.reject { |validator| NOT_VALIDATORS.include? validator }
|
99
|
+
.map(&:to_s).map(&:capitalize)
|
100
|
+
.all? { |validator| Object.const_defined?("Statinize::#{validator}Validator") }
|
101
|
+
end
|
102
|
+
|
103
|
+
def should_cast?(validator, attr_name)
|
104
|
+
validator == :type &&
|
105
|
+
statinizer.casted_attributes.map(&:name).include?(attr_name)
|
106
|
+
end
|
107
|
+
|
108
|
+
def casted?(attr_name, attr_value, validator_value)
|
109
|
+
::Statinize::Caster.cast(instance, attr_name, attr_value, validator_value)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Statinize
|
2
|
+
class PresenceValidator < Validator
|
3
|
+
def valid?
|
4
|
+
validator_value &&
|
5
|
+
!empty_array? &&
|
6
|
+
!empty_hash? &&
|
7
|
+
!empty_string? &&
|
8
|
+
!attr_value.nil?
|
9
|
+
end
|
10
|
+
|
11
|
+
def error
|
12
|
+
{ attr_name => 'is blank' }
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def empty_array?
|
18
|
+
attr_value == []
|
19
|
+
end
|
20
|
+
|
21
|
+
def empty_hash?
|
22
|
+
attr_value == {}
|
23
|
+
end
|
24
|
+
|
25
|
+
def empty_string?
|
26
|
+
attr_value == ''
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/statinize.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'pry'
|
3
|
+
require_relative 'statinize/validator'
|
4
|
+
require_relative 'statinize/caster'
|
5
|
+
require_relative 'statinize/errors'
|
6
|
+
require_relative 'statinize/validators/type_validator'
|
7
|
+
require_relative 'statinize/validators/presence_validator'
|
8
|
+
require_relative 'statinize/attribute'
|
9
|
+
require_relative 'statinize/statinizer'
|
10
|
+
require_relative 'statinize/statinizable'
|
metadata
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: statinize
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Barseek
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-07-01 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Statinization gem. Allows for creation of attributes for a class with
|
14
|
+
a given type.
|
15
|
+
email: sergey.b@hey.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/statinize.rb
|
21
|
+
- lib/statinize/attribute.rb
|
22
|
+
- lib/statinize/caster.rb
|
23
|
+
- lib/statinize/errors.rb
|
24
|
+
- lib/statinize/statinizable.rb
|
25
|
+
- lib/statinize/statinizer.rb
|
26
|
+
- lib/statinize/validator.rb
|
27
|
+
- lib/statinize/validators/presence_validator.rb
|
28
|
+
- lib/statinize/validators/type_validator.rb
|
29
|
+
homepage:
|
30
|
+
licenses:
|
31
|
+
- MIT
|
32
|
+
metadata: {}
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
requirements: []
|
48
|
+
rubygems_version: 3.3.3
|
49
|
+
signing_key:
|
50
|
+
specification_version: 4
|
51
|
+
summary: Statinize!
|
52
|
+
test_files: []
|