methodic 1.1 → 1.2
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.
- data/COPYRIGHT +1 -1
- data/ChangeLog +4 -0
- data/Rakefile +1 -1
- data/doc/manual.rdoc +28 -2
- data/lib/methodic.rb +74 -20
- data/methodic.gemspec +2 -2
- data/spec/methodic_spec.rb +102 -6
- metadata +12 -5
data/COPYRIGHT
CHANGED
data/ChangeLog
CHANGED
data/Rakefile
CHANGED
data/doc/manual.rdoc
CHANGED
@@ -35,6 +35,8 @@ In a valid Ruby environment :
|
|
35
35
|
myOptions = Methodic::get_options(_options) do |m|
|
36
36
|
m.specify_default_value_of :country => 'France'
|
37
37
|
m.specify_classes_of :name => String, :surname => String, :age => Fixnum, :country => String
|
38
|
+
aCond = Proc::new {|option| case options when 'Doe' then true else false end }
|
39
|
+
m.specify_condition_for :name => aCond
|
38
40
|
m.specify_presence_of :name
|
39
41
|
m.specify_presence_of :surname
|
40
42
|
m.specify_formats_of :name => /\w+/, :surname => /\w+/, :country => /\w+/
|
@@ -53,7 +55,9 @@ In a valid Ruby environment :
|
|
53
55
|
def amethod ( _options = {})
|
54
56
|
myOptions = Methodic::get_options(_options,true) do |m|
|
55
57
|
# all others definitions MUST be included in known options list (explained in Spec), so : m.specify_known_options [:country,:name,:surname, :age]
|
56
|
-
m.specify_default_value_of :country => 'France'
|
58
|
+
m.specify_default_value_of :country => 'France'
|
59
|
+
aCond = Proc::new {|option| case options when 'Doe' then true else false end }
|
60
|
+
m.specify_condition_for :name => aCond
|
57
61
|
m.specify_classes_of :name => String, :surname => String, :age => Fixnum, :country => String
|
58
62
|
m.specify_presence_of :name
|
59
63
|
m.specify_presence_of :surname
|
@@ -64,8 +68,30 @@ In a valid Ruby environment :
|
|
64
68
|
end
|
65
69
|
[...]
|
66
70
|
|
71
|
+
=== Remarque about conditions
|
72
|
+
|
73
|
+
|
74
|
+
* Condition MUST :
|
75
|
+
|
76
|
+
- be ruby code
|
77
|
+
- be a Proc Object
|
78
|
+
- have an argument |option| who provide the option symbol, like :an_option
|
79
|
+
- return true or false
|
80
|
+
|
81
|
+
* Make your condition like
|
82
|
+
|
83
|
+
|
84
|
+
aCond = Proc::new do |option|
|
85
|
+
case options
|
86
|
+
when .... then ...
|
87
|
+
when .... then ...
|
88
|
+
else ...
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
|
67
93
|
|
68
94
|
== Copyright
|
69
95
|
|
70
|
-
<pre>Methodic (c) 2012 Romain GEORGES <romain@ultragreen.net> for Ultragreen Software </pre>
|
96
|
+
<pre>Methodic (c) 2012-2013 Romain GEORGES <romain@ultragreen.net> for Ultragreen Software </pre>
|
71
97
|
|
data/lib/methodic.rb
CHANGED
@@ -1,11 +1,35 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
#
|
2
|
+
# -*- coding: undecided -*-
|
3
|
+
# Copyright Ultragreen (c) 2012-2�013
|
3
4
|
#---
|
4
5
|
# Author : Romain GEORGES
|
5
6
|
# type : gem component library
|
6
7
|
# obj : Methodic Module
|
7
8
|
#---
|
8
9
|
|
10
|
+
# inherited List class from Array to patch push for uniqness carateristique
|
11
|
+
class List < Array
|
12
|
+
|
13
|
+
# override of push for uniqness and flatten return
|
14
|
+
def push(*value)
|
15
|
+
super(value)
|
16
|
+
self.flatten!
|
17
|
+
self.uniq!
|
18
|
+
return self
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
# override of << for uniqness and flatten return
|
23
|
+
def <<(*value)
|
24
|
+
super(value)
|
25
|
+
self.flatten!
|
26
|
+
self.uniq!
|
27
|
+
return self
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
|
9
33
|
# module Methodic
|
10
34
|
# @author Romain GEORGES <romain@ultragreen.net>
|
11
35
|
# @see http://www.ultragreen.net/projects/methodic
|
@@ -20,6 +44,8 @@
|
|
20
44
|
# myOptions = Methodic::get_options(_options,true) do |m|
|
21
45
|
# m.specify_known_options [:country,:name,:surname,:age]
|
22
46
|
# m.specify_default_value :country => 'France'
|
47
|
+
# aCond = Proc::new {|option| case options when 'Doe' then true else false end }
|
48
|
+
# m.specify_condition_for :name => aCond
|
23
49
|
# m.specify_classes_of :name => String, :surname => String, :age => Fixnum, :country => String
|
24
50
|
# m.specify_presence_of :name
|
25
51
|
# m.specify_presence_of :surname
|
@@ -43,6 +69,8 @@ module Methodic
|
|
43
69
|
# myOptions = Methodic::get_options(_options,true) do |m|
|
44
70
|
# m.specify_known_options [:country,:name,:surname,:age]
|
45
71
|
# m.specify_default_value :country => 'France'
|
72
|
+
# aCond = Proc::new {|option| case options when 'Doe' then true else false end }
|
73
|
+
# m.specify_condition_for :name => aCond
|
46
74
|
# m.specify_classes_of :name => String, :surname => String, :age => Fixnum, :country => String
|
47
75
|
# m.specify_presence_of :name
|
48
76
|
# m.specify_presence_of :surname
|
@@ -98,12 +126,22 @@ module Methodic
|
|
98
126
|
# @example writing
|
99
127
|
# myOptions = Methodic::get_options(options)
|
100
128
|
# myOptions.formats = {:name => /\w+/ }
|
101
|
-
# myOptions.
|
129
|
+
# myOptions.formats[:surname] = /\w+/
|
102
130
|
# @example reading
|
103
131
|
# p myOptions.defaults
|
104
132
|
# => { :name => /\w+/, :surname => /\w+/ }
|
105
133
|
attr_accessor :formats
|
106
134
|
|
135
|
+
# @attr [Hash] conditions a hash table of some conditions with their corresponding
|
136
|
+
# @example writing
|
137
|
+
# myOptions = Methodic::get_options(options)
|
138
|
+
# myOptions.conditions = {:name => aProcObject }
|
139
|
+
# myOptions.conditions[:surname] = aProcObject
|
140
|
+
# @example reading
|
141
|
+
# p myOptions.defaults
|
142
|
+
# => { :name => /\w+/, :surname => /\w+/ }
|
143
|
+
attr_accessor :conditions
|
144
|
+
|
107
145
|
# initializer for [Options]
|
108
146
|
# @note please do not use standalone, build from module method Methodic::get_options
|
109
147
|
# @param [Hash] _options the options hash (define for the method you would prototype)
|
@@ -116,11 +154,12 @@ module Methodic
|
|
116
154
|
raise ArgumentError::new('Argument _options must be a Hash') unless _options.class == Hash or _options.class == Methodic::Options # ;) reintrance and cascading
|
117
155
|
raise ArgumentError::new('keys must be Symbol') unless _options.keys.select{|i| i.class == Symbol }.size == _options.keys.size
|
118
156
|
self.replace _options
|
157
|
+
@conditions = Hash::new
|
119
158
|
@defaults = Hash::new
|
120
159
|
@formats = Hash::new
|
121
160
|
@classes = Hash::new
|
122
|
-
@known =
|
123
|
-
@mandatories =
|
161
|
+
@known = List::new
|
162
|
+
@mandatories = List::new
|
124
163
|
@validate_known_options = _validate_known_options
|
125
164
|
yield self if block_given?
|
126
165
|
end
|
@@ -161,13 +200,27 @@ module Methodic
|
|
161
200
|
# myOptions.specify_class_of :name => String
|
162
201
|
# myOptions.specify_classes_of :name => String, :surname => String
|
163
202
|
def specify_class_of(values)
|
164
|
-
|
165
203
|
@classes.merge! values
|
166
|
-
|
167
204
|
return @classes
|
168
|
-
|
169
205
|
end
|
170
206
|
alias :specify_classes_of :specify_class_of
|
207
|
+
|
208
|
+
# pretty accessor for specifying conditions for options
|
209
|
+
# @param [Hash] values a Conditions Proc definition, keys are symbols
|
210
|
+
# @return [hash] @conditions merged with values
|
211
|
+
# @note Conditions must be precised in Ruby as a Proc Object returning a boolean
|
212
|
+
# @note Convention : Proc MUST return true or false ONLY ( false trigged the exception raising )
|
213
|
+
# @example usage
|
214
|
+
# myOptions = Methodic::get_options(_options)
|
215
|
+
# myOptions.specify_condition_for :name => aProcObject
|
216
|
+
# myOptions.specify_conditions_for :name => aProcObject, :surname => aProcObject
|
217
|
+
def specify_condition_for(values)
|
218
|
+
@conditions.merge! values
|
219
|
+
return @conditions
|
220
|
+
end
|
221
|
+
alias :specify_conditions_for :specify_condition_for
|
222
|
+
|
223
|
+
|
171
224
|
|
172
225
|
# pretty accessor for specifying mandatories options
|
173
226
|
# @param [Array] values a Array of symbols or a unique symbol
|
@@ -176,7 +229,7 @@ module Methodic
|
|
176
229
|
# myOptions = Methodic::get_options(_options)
|
177
230
|
# myOptions.specify_presence_of :name
|
178
231
|
# myOptions.specify_presences_of [ :name, :surname ]
|
179
|
-
def specify_presence_of(values)
|
232
|
+
def specify_presence_of(*values)
|
180
233
|
@mandatories << values
|
181
234
|
@mandatories.flatten!
|
182
235
|
@mandatories.uniq!
|
@@ -192,7 +245,7 @@ module Methodic
|
|
192
245
|
# myOptions = Methodic::get_options(_options)
|
193
246
|
# myOptions.specify_known_option :name
|
194
247
|
# myOptions.specify_known_options [ :name, :surname ]
|
195
|
-
def specify_known_option(values)
|
248
|
+
def specify_known_option(*values)
|
196
249
|
@known << values
|
197
250
|
@known.flatten!
|
198
251
|
@known.uniq!
|
@@ -214,12 +267,6 @@ module Methodic
|
|
214
267
|
end
|
215
268
|
alias :specify_formats_of :specify_format_of
|
216
269
|
|
217
|
-
# pretty accessor for specifying condition for options
|
218
|
-
# @todo implementation of conditions
|
219
|
-
def specify_condition_for
|
220
|
-
raise NotYetImplemented
|
221
|
-
end
|
222
|
-
alias :specify_conditions_for :specify_condition_for
|
223
270
|
|
224
271
|
# default values merge method
|
225
272
|
# merge @defaults with self
|
@@ -248,7 +295,7 @@ module Methodic
|
|
248
295
|
table.push validate_classes unless @classes.empty?
|
249
296
|
table.push validate_presences unless @mandatories.empty?
|
250
297
|
table.push validate_formats unless @formats.empty?
|
251
|
-
|
298
|
+
table.push validate_conditions unless @conditions.empty?
|
252
299
|
return true unless table.include?(false)
|
253
300
|
end
|
254
301
|
alias :validate! :validate
|
@@ -289,10 +336,20 @@ module Methodic
|
|
289
336
|
end
|
290
337
|
return true
|
291
338
|
end
|
292
|
-
|
339
|
+
|
340
|
+
# private method for conditions validation step
|
341
|
+
def validate_conditions
|
342
|
+
@conditions.each do |option,cond|
|
343
|
+
raise ArgumentError::new("Option : #{option} condition failed") and return false unless cond.call(self[option]) == true
|
344
|
+
end
|
345
|
+
return true
|
346
|
+
end
|
347
|
+
|
348
|
+
|
293
349
|
# private method for classes validation step
|
294
350
|
def validate_classes
|
295
351
|
@classes.each do |option,value|
|
352
|
+
|
296
353
|
raise ArgumentError::new("Option : #{option} type mismatch must be a #{value}") and return false unless self[option].class == value
|
297
354
|
end
|
298
355
|
return true
|
@@ -311,8 +368,5 @@ module Methodic
|
|
311
368
|
return Methodic::Options::new(_options,_validate_known_options)
|
312
369
|
end
|
313
370
|
|
314
|
-
# Exception Class for not yet implemented methods Exceptions
|
315
|
-
class NotYetImplemented < Exception; end
|
316
|
-
|
317
371
|
|
318
372
|
end
|
data/methodic.gemspec
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = %q{methodic}
|
3
3
|
s.author = "Romain GEORGES"
|
4
|
-
s.version = "1.
|
5
|
-
s.date = %q{2013-02-
|
4
|
+
s.version = "1.2"
|
5
|
+
s.date = %q{2013-02-18}
|
6
6
|
s.summary = %q{Methodic : Hash table options specification and validation componant}
|
7
7
|
s.email = %q{romain@ultragreen.net}
|
8
8
|
s.homepage = %q{http://www.ultragreen.net}
|
data/spec/methodic_spec.rb
CHANGED
@@ -9,7 +9,7 @@ describe Methodic do
|
|
9
9
|
$test_methodic_options_with_known_options = Methodic::get_options({:name => 'Doe', :surname => 'John'},true)
|
10
10
|
end
|
11
11
|
before :each do
|
12
|
-
$test_methodic_options.mandatories
|
12
|
+
$test_methodic_options.mandatories.clear
|
13
13
|
$test_methodic_options.formats = {}
|
14
14
|
$test_methodic_options.defaults = {}
|
15
15
|
$test_methodic_options.classes = {}
|
@@ -91,33 +91,70 @@ describe Methodic do
|
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
94
|
+
context "#conditions R/W" do
|
95
|
+
it { $test_methodic_options.should respond_to("conditions") }
|
96
|
+
it { $test_methodic_options.should respond_to("conditions=") }
|
97
|
+
|
98
|
+
it "should be true that #conditions must return a Hash" do
|
99
|
+
$test_methodic_options.conditions.class.should eq(Hash)
|
100
|
+
end
|
101
|
+
it "#formats[] affectation must be possible and #formats must respond this affectation" do
|
102
|
+
aCond = Proc::new do |option| case option
|
103
|
+
when 'Doe' then true
|
104
|
+
else false
|
105
|
+
end
|
106
|
+
end
|
107
|
+
$test_methodic_options.conditions[:name] = aCond
|
108
|
+
$test_methodic_options.conditions.should eq({ :name => aCond })
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
94
112
|
context "#mandatories R/W" do
|
95
113
|
it { $test_methodic_options.should respond_to("mandatories") }
|
96
114
|
it { $test_methodic_options.should respond_to("mandatories=") }
|
97
115
|
|
98
|
-
it "should be true that #mandatories must return a Array" do
|
99
|
-
$test_methodic_options.mandatories.class.should eq(
|
116
|
+
it "should be true that #mandatories must return a List < Array" do
|
117
|
+
$test_methodic_options.mandatories.class.should eq(List)
|
100
118
|
end
|
101
119
|
it "#mandatories.push affectation must be possible and #mandatories must respond this affectation" do
|
102
120
|
$test_methodic_options.mandatories.push :test
|
103
121
|
$test_methodic_options.mandatories.should eq([:test])
|
104
122
|
end
|
123
|
+
context "#mandatories.push" do
|
124
|
+
it "should not duplicate entry"do
|
125
|
+
$test_methodic_options.mandatories.push :test
|
126
|
+
$test_methodic_options.mandatories.push :test
|
127
|
+
$test_methodic_options.mandatories.count(:test).should eq 1
|
128
|
+
end
|
129
|
+
end
|
105
130
|
end
|
131
|
+
|
132
|
+
|
106
133
|
context "#known R/W" do
|
107
134
|
it { $test_methodic_options.should respond_to("known") }
|
108
135
|
it { $test_methodic_options.should respond_to("known=") }
|
109
136
|
|
110
|
-
it "should be true that #known must return a Array" do
|
111
|
-
$test_methodic_options.known.class.should eq(
|
137
|
+
it "should be true that #known must return a List < Array" do
|
138
|
+
$test_methodic_options.known.class.should eq(List)
|
112
139
|
end
|
113
140
|
it "#known.push affectation must be possible and #known must respond this affectation" do
|
114
141
|
$test_methodic_options.known.push :test
|
115
142
|
$test_methodic_options.known.should include :test
|
116
143
|
end
|
144
|
+
context "#known.push" do
|
145
|
+
it "should not duplicate entry" do
|
146
|
+
$test_methodic_options.known.push :test
|
147
|
+
$test_methodic_options.known.push :test
|
148
|
+
$test_methodic_options.known.count(:test).should eq 1
|
149
|
+
end
|
150
|
+
end
|
117
151
|
end
|
118
152
|
end
|
119
153
|
context "Instance methods" do
|
120
154
|
|
155
|
+
|
156
|
+
|
157
|
+
|
121
158
|
context "#options" do
|
122
159
|
it { $test_methodic_options.should respond_to("options") }
|
123
160
|
it "should be true that #options must return a Array" do
|
@@ -172,7 +209,33 @@ describe Methodic do
|
|
172
209
|
context "#specify_condition_for" do
|
173
210
|
it { $test_methodic_options.should respond_to("specify_condition_for") }
|
174
211
|
it { $test_methodic_options.should respond_to("specify_conditions_for") }
|
175
|
-
it
|
212
|
+
it "should merge condition hash record in conditions attribut" do
|
213
|
+
aCond = Proc::new do |option| case option
|
214
|
+
when "Doe" then true
|
215
|
+
else false
|
216
|
+
end
|
217
|
+
end
|
218
|
+
$test_methodic_options.specify_condition_for :name => aCond
|
219
|
+
$test_methodic_options.conditions[:name].should eq aCond
|
220
|
+
$test_methodic_options.conditions.count.should eq 1
|
221
|
+
end
|
222
|
+
it "should redefine a new class value for a previous key" do
|
223
|
+
aCond = Proc::new do |option| case option
|
224
|
+
when "Doe" then true
|
225
|
+
else false
|
226
|
+
end
|
227
|
+
end
|
228
|
+
newCond = Proc::new do |option| case option
|
229
|
+
when "DoeLittle" then true
|
230
|
+
else false
|
231
|
+
end
|
232
|
+
end
|
233
|
+
$test_methodic_options.specify_condition_for :name => aCond
|
234
|
+
$test_methodic_options.conditions[:name].should eq aCond
|
235
|
+
$test_methodic_options.specify_condition_for :name => newCond
|
236
|
+
$test_methodic_options.conditions[:name].should eq newCond
|
237
|
+
$test_methodic_options.conditions = {}
|
238
|
+
end
|
176
239
|
end
|
177
240
|
|
178
241
|
context "#specify_format_of" do
|
@@ -203,6 +266,10 @@ describe Methodic do
|
|
203
266
|
$test_methodic_options.mandatories.should include(:test)
|
204
267
|
$test_methodic_options.mandatories.count.should eq 1
|
205
268
|
end
|
269
|
+
it "should be possible to give arguments list of symbols" do
|
270
|
+
$test_methodic_options.specify_presences_of :test2, :test3, :test4
|
271
|
+
$test_methodic_options.specify_presences_of [ :test5, :test6 ], :test7
|
272
|
+
end
|
206
273
|
end
|
207
274
|
|
208
275
|
context "#specify_known_option" do
|
@@ -216,6 +283,11 @@ describe Methodic do
|
|
216
283
|
$test_methodic_options.known.should include(:test)
|
217
284
|
$test_methodic_options.known.count.should eq 1
|
218
285
|
end
|
286
|
+
it "should be possible to give arguments list of symbols" do
|
287
|
+
$test_methodic_options.specify_known_options :test2, :test3, :test4
|
288
|
+
$test_methodic_options.specify_known_options [ :test5, :test6 ], :test7
|
289
|
+
|
290
|
+
end
|
219
291
|
end
|
220
292
|
|
221
293
|
context "#validate" do
|
@@ -337,6 +409,30 @@ describe Methodic do
|
|
337
409
|
lambda{$test_methodic_options.validate!}.should_not raise_error ArgumentError
|
338
410
|
end
|
339
411
|
end
|
412
|
+
context "5/ validate conditions" do
|
413
|
+
it "should raise ArgumentError if an option in options list not validate a registered condition" do
|
414
|
+
$test_methodic_options.conditions = {}
|
415
|
+
aCond = Proc::new do |option| case option
|
416
|
+
when 'DoeLittle' then true
|
417
|
+
else false
|
418
|
+
end
|
419
|
+
end
|
420
|
+
$test_methodic_options.specify_condition_for :name => aCond
|
421
|
+
lambda{$test_methodic_options.validate!}.should raise_error ArgumentError
|
422
|
+
|
423
|
+
end
|
424
|
+
it "should not raise if all options in options list match formats definitions " do
|
425
|
+
$test_methodic_options.conditions = {}
|
426
|
+
aCond = Proc::new do |option| case option
|
427
|
+
when 'Doe' then true
|
428
|
+
else false
|
429
|
+
end
|
430
|
+
end
|
431
|
+
$test_methodic_options.specify_condition_for :name => aCond
|
432
|
+
lambda{$test_methodic_options.validate!}.should_not raise_error ArgumentError
|
433
|
+
end
|
434
|
+
end
|
435
|
+
|
340
436
|
|
341
437
|
|
342
438
|
end
|
metadata
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: methodic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 11
|
5
|
+
prerelease:
|
5
6
|
segments:
|
6
7
|
- 1
|
7
|
-
-
|
8
|
-
version: "1.
|
8
|
+
- 2
|
9
|
+
version: "1.2"
|
9
10
|
platform: ruby
|
10
11
|
authors:
|
11
12
|
- Romain GEORGES
|
@@ -13,16 +14,18 @@ autorequire:
|
|
13
14
|
bindir:
|
14
15
|
cert_chain: []
|
15
16
|
|
16
|
-
date: 2013-02-
|
17
|
+
date: 2013-02-18 00:00:00 +01:00
|
17
18
|
default_executable:
|
18
19
|
dependencies:
|
19
20
|
- !ruby/object:Gem::Dependency
|
20
21
|
name: rspec
|
21
22
|
prerelease: false
|
22
23
|
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
23
25
|
requirements:
|
24
26
|
- - ">="
|
25
27
|
- !ruby/object:Gem::Version
|
28
|
+
hash: 15
|
26
29
|
segments:
|
27
30
|
- 2
|
28
31
|
- 0
|
@@ -67,25 +70,29 @@ rdoc_options:
|
|
67
70
|
require_paths:
|
68
71
|
- lib
|
69
72
|
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
70
74
|
requirements:
|
71
75
|
- - ">="
|
72
76
|
- !ruby/object:Gem::Version
|
77
|
+
hash: 53
|
73
78
|
segments:
|
74
79
|
- 1
|
75
80
|
- 8
|
76
81
|
- 1
|
77
82
|
version: 1.8.1
|
78
83
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
79
85
|
requirements:
|
80
86
|
- - ">="
|
81
87
|
- !ruby/object:Gem::Version
|
88
|
+
hash: 3
|
82
89
|
segments:
|
83
90
|
- 0
|
84
91
|
version: "0"
|
85
92
|
requirements: []
|
86
93
|
|
87
94
|
rubyforge_project: nowarning
|
88
|
-
rubygems_version: 1.
|
95
|
+
rubygems_version: 1.4.2
|
89
96
|
signing_key:
|
90
97
|
specification_version: 3
|
91
98
|
summary: "Methodic : Hash table options specification and validation componant"
|