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