ru.Bee 2.1.0 → 2.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c12dfae68f0595266581855939b1d4b80468ad9e4298438a0125b709e96c3fa3
4
- data.tar.gz: 6fb74be8efa80754b66f603bbe41b2ba5cc9cbc26eddfcb55ee24f7073c31a74
3
+ metadata.gz: cc6a4fbeb28a460ca66f75ccf1f5c97fe1572f422392f9ee1b72d082e05cb287
4
+ data.tar.gz: f4dbeaf7338af243f6e225a2a798a87de75b001fa4196bed94345d78887ba8ea
5
5
  SHA512:
6
- metadata.gz: 463291b6a407cc39fa1b26620416da495598aa56332091e37eb5c8545e0d1f1a35bbb23586b43958bd7c83d59c66663b382b7c54c7b45a5496803365ee1e1623
7
- data.tar.gz: 9bc34459746bc4a060f1fdb697f332cc35246cc104cf1a211ec9533f92a301573f0270e98582d86c64bfe72585fb233170befbc7e5719cb7d88d76a465945d3f
6
+ metadata.gz: 996510c80521425797e17a1b641d767d6319877e127883692d519457c7573835ae2670a8ed17950f302b1934a0aae1270d8b065acfee079341935ddb8964a26f
7
+ data.tar.gz: 75a8ab899d3c98fd492a30ec5501982526318387c9214b78ebdf57ec2c39a91778268283db82cbeb5ae9072aa4c62507b1d175423e7f86beec892cddfea0bb90
@@ -31,44 +31,73 @@ module Rubee
31
31
  @optional = false
32
32
  end
33
33
 
34
- def required(error_hash)
34
+ def required(error_message = nil)
35
35
  value = @instance.send(@attribute)
36
+
37
+ error_hash = assemble_error_hash(error_message, :required, attribute: @attribute)
36
38
  if value.nil? || (value.respond_to?(:empty?) && value.empty?)
37
39
  @state.add_error(@attribute, error_hash)
38
40
  end
41
+
39
42
  self
40
43
  end
41
44
 
42
45
  def optional(*)
43
46
  @optional = true
47
+
44
48
  self
45
49
  end
46
50
 
47
- def type(expected_class, error_hash)
48
- return self if @state.has_errors_for?(@attribute)
51
+ def attribute
52
+ self
53
+ end
49
54
 
55
+ def type(expected_class, error_message = nil)
56
+ return self if @state.has_errors_for?(@attribute)
50
57
  value = @instance.send(@attribute)
51
58
  return self if @optional && value.nil?
52
59
 
60
+ error_hash = assemble_error_hash(error_message, :type, class: expected_class)
53
61
  unless value.is_a?(expected_class)
54
62
  @state.add_error(@attribute, error_hash)
55
63
  end
64
+
56
65
  self
57
66
  end
58
67
 
59
- def condition(handler, error_message)
68
+ def condition(handler, error_message = nil)
60
69
  return self if @state.has_errors_for?(@attribute)
61
70
  value = @instance.send(@attribute)
62
71
  return self if @optional && value.nil?
63
72
 
73
+ error_hash = assemble_error_hash(error_message, :condition)
64
74
  if handler.respond_to?(:call)
65
- @state.add_error(@attribute, error_message) unless handler.call
75
+ @state.add_error(@attribute, error_hash) unless handler.call
66
76
  else
67
77
  @instance.send(handler)
68
78
  end
69
79
 
70
80
  self
71
81
  end
82
+
83
+ private
84
+
85
+ def assemble_error_hash(error_message, error_type, **options)
86
+ error_message ||= default_message(error_type, **options)
87
+ if error_message.is_a?(String)
88
+ error_message = { message: error_message }
89
+ end
90
+
91
+ error_message
92
+ end
93
+
94
+ def default_message(type, **options)
95
+ {
96
+ condition: "condition is not met",
97
+ required: "attribute '#{options[:attribute]}' is required",
98
+ type: "attribute must be #{options[:class]}",
99
+ }[type]
100
+ end
72
101
  end
73
102
 
74
103
  def self.included(base)
@@ -102,7 +131,17 @@ module Rubee
102
131
 
103
132
  def run_validations
104
133
  @__validation_state = State.new
105
- self.class&.validation_block&.call(self)
134
+ if (block = self.class.validation_block)
135
+ instance_exec(&block)
136
+ end
137
+ end
138
+
139
+ def subject
140
+ @__validation_state.instance
141
+ end
142
+
143
+ def attribute(name)
144
+ RuleChain.new(self, name, @__validation_state).attribute
106
145
  end
107
146
 
108
147
  def required(attribute, options)
data/lib/rubee.rb CHANGED
@@ -17,7 +17,7 @@ module Rubee
17
17
  CSS_DIR = File.join(APP_ROOT, LIB, 'css') unless defined?(CSS_DIR)
18
18
  ROOT_PATH = File.expand_path(File.join(__dir__, '..')) unless defined?(ROOT_PATH)
19
19
 
20
- VERSION = '2.1.0'
20
+ VERSION = '2.1.1'
21
21
 
22
22
  require_relative 'rubee/router'
23
23
  require_relative 'rubee/logger'
@@ -18,9 +18,8 @@ describe 'Account model' do
18
18
 
19
19
  describe '#validate_before_persist' do
20
20
  it 'rasies error if account is not valid' do
21
- Account.validate do |account|
22
- account
23
- .required(:addres, required: "address is required")
21
+ Account.validate do
22
+ required(:addres, required: "address is required")
24
23
  .type(String, type: "address must be string")
25
24
  end
26
25
  Account.validate_before_persist!
@@ -47,17 +47,17 @@ describe 'Comment model' do
47
47
 
48
48
  describe 'validatable' do
49
49
  def include_and_validate(required: true)
50
- # Comment.include(Rubee::Validatable)
51
50
  required_or_optional = required ? :required : :optional
52
- required_or_optional_args = required ? [:text, required: "text filed is required"] : [:text]
53
- Comment.validate do |comment|
54
- comment.send(
51
+ required_or_optional_args = required ? [required: "text filed is required"] : []
52
+ Comment.validate do
53
+ attribute(:text).send(
55
54
  required_or_optional, *required_or_optional_args
56
55
  )
57
56
  .type(String, type: "text field must be string")
58
- .condition(proc { comment.text.length > 4 }, { length: "text length must be greater than 4" })
57
+ .condition(proc { text.length > 4 }, { length: "text length must be greater than 4" })
59
58
  end
60
59
  end
60
+
61
61
  it 'is valid' do
62
62
  include_and_validate
63
63
  comment = Comment.new(text: 'test it as valid')
@@ -180,5 +180,47 @@ describe 'Comment model' do
180
180
  assert_equal('testerter', comment.text)
181
181
  end
182
182
  end
183
+
184
+ describe 'default errors as error' do
185
+ it 'assembles error hash' do
186
+ Comment.validate do
187
+ attribute(:text).required.type(String).condition(-> { text.length > 4 })
188
+ end
189
+
190
+ comment = Comment.new(text: 'test')
191
+ _(comment.valid?).must_equal(false)
192
+ _(comment.errors[:text]).must_equal({ message: "condition is not met" })
193
+
194
+ comment = Comment.new(text: 123)
195
+ _(comment.valid?).must_equal(false)
196
+ _(comment.errors[:text]).must_equal({ message: "attribute must be String" })
197
+
198
+ comment = Comment.new(user_id: User.last)
199
+ _(comment.valid?).must_equal(false)
200
+ _(comment.errors[:text]).must_equal({ message: "attribute 'text' is required" })
201
+ end
202
+ end
203
+
204
+ describe 'message instead hash as error' do
205
+ it 'assembles error hash' do
206
+ Comment.validate do
207
+ attribute(:text)
208
+ .required("Text is a mandatory field").type(String, "Text must be a string")
209
+ .condition(-> { text.length > 4 }, "Text length must be greater than 4")
210
+ end
211
+
212
+ comment = Comment.new(text: 'test')
213
+ _(comment.valid?).must_equal(false)
214
+ _(comment.errors[:text]).must_equal({ message: "Text length must be greater than 4" })
215
+
216
+ comment = Comment.new(text: 123)
217
+ _(comment.valid?).must_equal(false)
218
+ _(comment.errors[:text]).must_equal({ message: "Text must be a string" })
219
+
220
+ comment = Comment.new(user_id: User.last)
221
+ _(comment.valid?).must_equal(false)
222
+ _(comment.errors[:text]).must_equal({ message: "Text is a mandatory field" })
223
+ end
224
+ end
183
225
  end
184
226
  end
data/lib/tests/test.db CHANGED
Binary file
data/readme.md CHANGED
@@ -881,70 +881,88 @@ class Foo
881
881
  @age = age
882
882
  end
883
883
 
884
- validate do |foo|
885
- foo
886
- .required(:name, required: 'Name is required')
887
- .type(String, type: 'must be a string')
888
- .condition(->{ foo.name.length > 2 }, length: 'Name must be at least 3 characters long')
889
-
890
- foo
891
- .required(:age, required: 'Age is required')
892
- .type(Integer, type: 'must be an integer')
893
- .condition(->{ foo.age > 18 }, age: 'You must be at least 18 years old')
884
+ validate do
885
+ attribute(:name).required.type(String).condition(->{ name.length > 2 })
886
+
887
+ attribute(:age)
888
+ .required('Age is a manadatory field')
889
+ .type(Integer, error_message: 'Must be an integerRRRRRRrrr!')
890
+ .condition(->{ age > 18 }, fancy_error: 'You must be at least 18 years old, dude!')
894
891
  end
895
892
  end
896
893
  ```
894
+ Then we can evaluate it in the ru.Bee console
897
895
  ```bash
898
- irb(main):068> Foo.new("Joe", "20")
899
- =>
900
- #<Foo:0x0000000120d7f778
901
- @__validation_state=#<Rubee::Validatable::State:0x0000000120d7f700 @errors={age: {type: "must be an integer"}}, @valid=false>,
902
- @age="20",
903
- @name="Joe">
904
- irb(main):069> foo = Foo.new("Joe", 11)
905
- =>
906
- #<Foo:0x0000000105f2b0b0
907
- ...
908
- irb(main):070> foo.valid?
909
- => false
910
- irb(main):071> foo.errors
911
- => {age: {age: "You must be at least 18 years old"}}
912
- irb(main):072> foo.age=20
913
- => 20
914
- irb(main):073> foo.valid?
915
- => true
896
+ => #<Proc:0x000000010d389d80 (irb):32>
897
+ irb(main):041> Foo.new("Test", 20)
898
+ => #<Foo:0x000000010d383fc0 @__validation_state=#<Rubee::Validatable::State:0x000000010d383de0 @errors={}, @valid=true>, @age=20, @name="Test">
899
+ irb(main):042> Foo.new("Test", 1)
900
+ =>
901
+ #<Foo:0x000000010ce61c40
902
+ @__validation_state=#<Rubee::Validatable::State:0x000000010ce61bc8 @errors={age: {fancy_error: "You must be at least 18 years old, dude!"}}, @valid=false>,
903
+ @age=1,
904
+ @name="Test">
905
+ irb(main):043> Foo.new("Test", nil)
906
+ =>
907
+ #<Foo:0x000000010c46f200
908
+ @__validation_state=#<Rubee::Validatable::State:0x000000010c46f070 @errors={age: {message: "Age is a manadatory field"}}, @valid=false>,
909
+ @age=nil,
910
+ @name="Test">
911
+ irb(main):044> Foo.new("Te", 20)
912
+ =>
913
+ #<Foo:0x000000010cfe9270
914
+ @__validation_state=#<Rubee::Validatable::State:0x000000010cfe91f8 @errors={name: {message: "condition is not met"}}, @valid=false>,
915
+ @age=20,
916
+ @name="Te">
917
+ irb(main):045> foo = Foo.new("Joe", "wrong")
918
+ =>
919
+ #<Foo:0x000000010d32eb38
920
+ ...
921
+ irb(main):046> foo.valid?
922
+ => false
923
+ irb(main):047> foo.errors
924
+ => {age: {error_message: "Must be an integerRRRRRRrrr!"}}
916
925
  ```
917
926
  Model example
918
927
  ```ruby
919
928
  class User < Rubee::SequelObject
920
929
  attr_accessor :id, :email, :password, :created, :updated
921
930
 
922
- validate do |user|
923
- user
924
- .required(:email, required: 'Email is required')
925
- .condition(
926
- ->{ user.email.match?(/\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i) }, email: 'Wrong email format'
927
- )
928
- end
929
- validate_before_persist! # This will validate and raise error in case invalid before saving to DB
931
+ validate_before_persist! # This will validate and raise error in case invalid before saving to DB
932
+ validate do
933
+ attribute(:email).required
934
+ .condition(
935
+ ->{ email.match?(/\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i) }, error: 'Wrong email format'
936
+ )
937
+ end
930
938
  end
931
939
  ```
932
940
  ```bash
933
- irb(main):089> user = User.new(email: "wrong", password: 123)
934
- => #<User:0x000000010cda23b8 @email="wrong", @password=123>
935
- irb(main):090> user.valid?
941
+ irb(main):074> user = User.new(email: "wrong", password: 123)
942
+ =>
943
+ #<User:0x000000010d2c3e78
944
+ ...
945
+ irb(main):075> user.valid?
936
946
  => false
937
- irb(main):091> user.errors
938
- => {email: {email: "Wrong email format"}}
939
- irb(main):091> user.save
940
- ...sequel_object.rb:229:in 'block in Rubee::SequelObject.validate_before_persist!': {email: {email: "Wrong email format"}} (Rubee::Validatable::Error)
941
- irb(main):092> user.email = "ok@ok.com"
947
+ irb(main):076> user.errors
948
+ => {email: {error: "Wrong email format"}}
949
+ irb(main):077> user.save
950
+ =>{email: {error: "Wrong email format"}} (Rubee::Validatable::Error) ..
951
+ irb(main):078> user.email = "ok@ok.com"
942
952
  => "ok@ok.com"
943
- irb(main):094> user.valid?
953
+ irb(main):079> user.valid?
944
954
  => true
945
- irb(main):095> user.save
955
+ irb(main):080> user.save
946
956
  => true
947
-
957
+ irb(main):081> user
958
+ =>
959
+ #<User:0x000000010d2c3e78
960
+ @__validation_state=#<Rubee::Validatable::State:0x000000010cb28628 @errors={}, @valid=true>,
961
+ @created=2025-11-30 17:18:52.254197 -0500,
962
+ @email="ok@ok.com",
963
+ @id=2260,
964
+ @password=123,
965
+ @updated=2025-11-30 17:18:52.254206 -0500>
948
966
  ```
949
967
  [Back to content](#content)
950
968
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ru.Bee
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oleg Saltykov