kwalify 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/ChangeLog CHANGED
@@ -1,7 +1,18 @@
1
1
  .=title: ChangeLog
2
- .?release: $Release: 0.4.1 $
3
- .?lastupdate: $Date$
4
- .?version: $Rev$
2
+ .?release: $Release: 0.5.0 $
3
+ .?lastupdate: $Date: 2005-12-17 13:49:16 +0900 (Sat, 17 Dec 2005) $
4
+ .?version: $Rev: 42 $
5
+
6
+ .: 2005-12-17 (release 0.5.0)
7
+ .* Enhances:
8
+ .- Meta-validation check for 'max < min', 'max-ex <= min-ex', and so on.
9
+ .- Many test-cases are added
10
+ .* Changes:
11
+ .- 'Parser' class is renamed to 'YamlParser'
12
+ .- 'PlainParser' class is renamed to 'PlainYamlParser'
13
+ .- YamlParser#set_error_linenums() is renamed to set_errors_linenum()
14
+ .- ValidatorError#<=> added
15
+ .- ParseError class is renamed to YamlSyntaxError
5
16
 
6
17
  .: 2005-10-26 (release 0.4.1)
7
18
  .* Bugfix:
data/README.txt CHANGED
@@ -1,7 +1,7 @@
1
1
  .=title: README
2
- .?version: $Rev: 18 $
3
- .?lastupdate: $Date: 2005-09-25 22:36:35 +0900 (Sun, 25 Sep 2005) $
4
- .?release: $Release: 0.4.1 $
2
+ .?version: $Rev: 41 $
3
+ .?lastupdate: $Date: 2005-11-22 03:24:54 +0900 (Tue, 22 Nov 2005) $
4
+ .?release: $Release: 0.5.0 $
5
5
 
6
6
 
7
7
  .$ About Kwalify
@@ -1,24 +1,13 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  ###
4
- ### $Rev: 12 $
5
- ### $Release: 0.4.1 $
4
+ ### $Rev: 42 $
5
+ ### $Release: 0.5.0 $
6
6
  ### copyright(c) 2005 kuwata-lab all rights reserved.
7
7
  ###
8
8
 
9
9
  require 'kwalify'
10
- require 'kwalify/main-program'
11
-
10
+ require 'kwalify/main'
12
11
 
13
12
  command = File.basename($0)
14
- begin
15
- main = Kwalify::MainProgram.new(ARGV, command)
16
- s = main.execute()
17
- print s if s
18
- rescue CommandOptionError => ex
19
- $stderr.puts ex.message
20
- exit 1
21
- rescue Kwalify::KwalifyError => ex
22
- $stderr.puts "ERROR: #{ex.message}"
23
- exit 1
24
- end
13
+ Kwalify::Main.main(command, ARGV)
@@ -2,7 +2,7 @@
2
2
  <html>
3
3
  <head>
4
4
  <meta http-equiv="Content-Type" content="text/html">
5
- <title>Kwalify Users' Guide</title>
5
+ <title>Kwalify Users' Guide (for Ruby and Java)</title>
6
6
  <meta name="author" content="makoto kuwata &lt;kwa(at)kuwata-lab.com&gt;">
7
7
  <meta name="generator" content="kwaser">
8
8
  <meta http-equiv="Content-Style-Type" content="text/css">
@@ -12,18 +12,18 @@
12
12
 
13
13
  <div class="mainbody">
14
14
 
15
- <div align="left"><h1>Kwalify Users' Guide</h1></div>
15
+ <div align="left"><h1>Kwalify Users' Guide (for Ruby and Java)</h1></div>
16
16
  <div align="left">
17
17
  makoto kuwata &lt;kwa(at)kuwata-lab.com&gt;<br>
18
- last update: $Date: 2005-10-26 11:38:26 +0900 (Wed, 26 Oct 2005) $<br>
18
+ last update: $Date: 2005-12-17 13:49:16 +0900 (Sat, 17 Dec 2005) $<br>
19
19
  </div>
20
20
 
21
21
  <a name="preface"></a>
22
22
  <h2 class="section1">Preface</h2>
23
23
  <p>Kwalify<sup>(<a href="#fnref:1" name="fnlink:1">*1</a>)</sup> is a tiny schema validator for YAML and JSON document.
24
24
  </p>
25
- <p>Do you know "80-20 rule" known as Pareto Law? This rule suggests that 20% of the population owns 80% of the wealth.
26
- Kwalify is based on a new "50-5 rule" which suggests that 5% of the population owns 50 of the wealth.
25
+ <p>You know "80-20 rule" known as Pareto Law, don't you? This rule suggests that 20% of the population owns 80% of the wealth.
26
+ Kwalify is based on a new "50-5 rule" which suggests that 5% of the population owns 50% of the wealth.
27
27
  This rule is more aggressive and cost-effective than Pareto Law. The rule is named as "Levi's Law".
28
28
  </p>
29
29
  <div align="center">
@@ -54,7 +54,7 @@ This rule is more aggressive and cost-effective than Pareto Law. The rule is nam
54
54
  </tr>
55
55
  </table>
56
56
  </div>
57
- <p>Kwalify is very small and in fact very poor compared to RelaxNG or XML Schema.
57
+ <p>Kwalify is small and in fact poorer than RelaxNG or XML Schema.
58
58
  I hope you extend/customize Kwalify for your own way.
59
59
  </p>
60
60
  Table of Contents:
@@ -80,7 +80,7 @@ Table of Contents:
80
80
  </li>
81
81
  <li><a href="#schema-map-of-seq">Mapping of Sequence</a>
82
82
  </li>
83
- <li><a href="#schema-rules">Rule and Constraint</a>
83
+ <li><a href="#schema-rules">Rule and Entry</a>
84
84
  </li>
85
85
  <li><a href="#schema-unique">Unique constraint</a>
86
86
  </li>
@@ -121,11 +121,19 @@ Table of Contents:
121
121
  <h3 class="section2">Usage in Command-Line</h3>
122
122
  <div class="terminal_caption">
123
123
  usage1: validate YAML document in command-line</div>
124
- <pre class="terminal">$ kwalify -f schema.yaml document.yaml [document2.yaml ...]
124
+ <pre class="terminal">### kwalify-ruby
125
+ $ kwalify -f schema.yaml document.yaml [document2.yaml ...]
126
+
127
+ ### kwalify-java
128
+ $ java -classpath kwalify.jar kwalify.Main -f schema.yaml document.yaml [document2.yaml ...]
125
129
  </pre>
126
130
  <div class="terminal_caption">
127
131
  usage2: validate schema definition in command-line</div>
128
- <pre class="terminal">$ kwalify -m schema.yaml [schema2.yaml ...]
132
+ <pre class="terminal">### kwalify-ruby
133
+ $ kwalify -m schema.yaml [schema2.yaml ...]
134
+
135
+ ### kwalify-java
136
+ $ java -classpath kwalify.jar kwalify.Main -m schema.yaml [schema2.yaml ...]
129
137
  </pre>
130
138
  <p>Command-line options:
131
139
  </p>
@@ -173,6 +181,8 @@ usage2: validate schema definition in command-line</div>
173
181
 
174
182
  <a name="usage2"></a>
175
183
  <h3 class="section2">Usage in Ruby Script</h3>
184
+ <p>The followings are example scripts for Ruby.
185
+ </p>
176
186
  <div class="program_caption">
177
187
  validate YAML document in Ruby script</div>
178
188
  <pre class="program">require 'kwalify'
@@ -206,14 +216,51 @@ document = parser.parse()
206
216
  ## validate document and show errors
207
217
  error_list = validator.validate(document)
208
218
  unless error_list.empty?
209
- parser.set_error_linenums(error_list) # set linenum on error
210
- error_list.sort { |e1, e2| e1.linenum &lt;=&gt; e2.linenum }.each do |error|
219
+ parser.set_errors_linenum(error_list) # set linenum on error
220
+ error_list.sort.each do |error|
211
221
  puts "(line %d)[%s] %s" % [error.linenum, error.path, error.message]
212
222
  end
213
223
  end
214
224
  </pre>
215
225
  <p>Kwalify's YAML parser is experimental. You should notice that Kwalify's YAML parser is limited only for basic syntax of YAML.
216
226
  </p>
227
+ <p>The followings are example programs of Java.
228
+ </p>
229
+ <div class="program_caption">
230
+ validate YAML document and show linenumber on where error is found.</div>
231
+ <pre class="program">import kwalify.*;
232
+
233
+ public class Test {
234
+
235
+ public static void main(String[] args) throws Exception {
236
+ // read schema
237
+ String schema_str = Util.readFile("schema.yaml");
238
+ Object schema = new YamlParser(schema_str).parse();
239
+
240
+ // read document file
241
+ String document_str = Util.readFile("document.yaml");
242
+ YamlParser parser = new YamlParser(document_str);
243
+ Object document = parser.parse();
244
+
245
+ // create validator and validate
246
+ Validator validator = new Validator(schema);
247
+ List errors = validator.validate(document);
248
+
249
+ // show errors
250
+ if (errors != null &amp;&amp; errors.size() &gt; 0) {
251
+ parser.setErrorsLineNumber(errors);
252
+ Collections.sort(errors);
253
+ for (Iterator it = errors.iterator(); it.hasNext(); ) {
254
+ ValidationException error = (ValidationException)it.next();
255
+ int linenum = error.getLineNumber();
256
+ String path = error.getPath();
257
+ String mesg = error.getMessage();
258
+ System.out.println("- " + linenum + ": [" + path + "] " + mesg);
259
+ }
260
+ }
261
+ }
262
+ }
263
+ </pre>
217
264
  <br>
218
265
 
219
266
 
@@ -430,8 +477,10 @@ document04b.yaml#0: INVALID
430
477
 
431
478
 
432
479
  <a name="schema-rules"></a>
433
- <h3 class="section2">Rule and Constraint</h3>
434
- <p>The followings are constraints.
480
+ <h3 class="section2">Rule and Entry</h3>
481
+ <p>Rule is set of entries. Entry usually represents constraint outside of a few exceptions.
482
+ </p>
483
+ <p>The followings are constraint entries.
435
484
  </p>
436
485
  <dl class="dl3">
437
486
  <dt class="dt3"><strong>
@@ -450,16 +499,6 @@ document04b.yaml#0: INVALID
450
499
  Specifies regular expression pattern of value.
451
500
  </dd>
452
501
  <dt class="dt3"><strong>
453
- <code>name:</code> </strong></dt>
454
- <dd class="dd3">
455
- Name of schema.
456
- </dd>
457
- <dt class="dt3"><strong>
458
- <code>desc:</code> </strong></dt>
459
- <dd class="dd3">
460
- Description. This is not used for validation.
461
- </dd>
462
- <dt class="dt3"><strong>
463
502
  <code>type:</code> </strong></dt>
464
503
  <dd class="dd3">
465
504
  Type of value. The followings are available:
@@ -517,7 +556,7 @@ document04b.yaml#0: INVALID
517
556
  <code>assert:</code> </strong></dt>
518
557
  <dd class="dd3">
519
558
  String which represents validation expression. String should contain variable name <code>val</code> which repsents value.
520
- (This is an experimental function.)
559
+ (This is an experimental function and supported only Kwartz-ruby).
521
560
  </dd>
522
561
  <dt class="dt3"><strong>
523
562
  <code>unique:</code> </strong></dt>
@@ -525,40 +564,55 @@ document04b.yaml#0: INVALID
525
564
  Value is unique for mapping or sequence. See the next subsection for detail.
526
565
  </dd>
527
566
  </dl>
528
- <p>A group of constraints is called "rule". For example, constraints which are element value of 'sequence:' or 'mapping:' are rules.
567
+ <p>The followings are non-constraint entries.
568
+ </p>
569
+ <dl class="dl3">
570
+ <dt class="dt3"><strong>
571
+ <code>name:</code> </strong></dt>
572
+ <dd class="dd3">
573
+ Name of schema.
574
+ </dd>
575
+ <dt class="dt3"><strong>
576
+ <code>desc:</code> </strong></dt>
577
+ <dd class="dd3">
578
+ Description. This is not used for validation.
579
+ </dd>
580
+ </dl>
581
+ <p>Rule contains 'type:' entry. 'sequence:' entry takes a list of rule. 'mapping:' entry takes a hash which values are rules.
529
582
  </p>
530
583
  <a name="schema05.yaml"></a>
531
584
  <div class="program_caption">
532
- <code>schema05.yaml</code> : rules examples</div>
533
- <pre class="program">type: seq
585
+ <code>schema05.yaml</code> : rule examples</div>
586
+ <pre class="program">type: seq # new rule
534
587
  sequence:
535
- - type: map
588
+ -
589
+ type: map # new rule
536
590
  mapping:
537
591
  name:
538
- type: str
592
+ type: str # new rule
539
593
  required: yes
540
594
  email:
541
- type: str
595
+ type: str # new rule
542
596
  required: yes
543
597
  pattern: /@/
544
598
  password:
545
- type: str
599
+ type: text # new rule
546
600
  length: { max: 16, min: 8 }
547
601
  age:
548
- type: int
602
+ type: int # new rule
549
603
  range: { max: 30, min: 18 }
550
604
  # or assert: 18 &lt;= val &amp;&amp; val &lt;= 30
551
605
  blood:
552
- type: str
606
+ type: str # new rule
553
607
  enum:
554
608
  - A
555
609
  - B
556
610
  - O
557
611
  - AB
558
612
  birth:
559
- type: date
613
+ type: date # new rule
560
614
  memo:
561
- type: any
615
+ type: any # new rule
562
616
  </pre>
563
617
  <a name="document05a.yaml"></a>
564
618
  <div class="program_caption">
@@ -615,15 +669,15 @@ document05b.yaml#0: INVALID
615
669
 
616
670
  <a name="schema-unique"></a>
617
671
  <h3 class="section2">Unique constraint</h3>
618
- <p>'<code>unique:</code>' constraint is available with elements of sequence or mapping.
672
+ <p>'<code>unique:</code>' constraint entry is available with elements of sequence or mapping.
619
673
  This is equivalent to unique key or primary key of RDBMS.
620
674
  </p>
621
- <p>Type of a rule which has '<code>unique:</code>' constraint must be scalar (str, int, float, ...).
675
+ <p>Type of rule which has '<code>unique:</code>' entry must be scalar (str, int, float, ...).
622
676
  Type of parent rule must be sequence or mapping.
623
677
  </p>
624
678
  <a name="schema06.yaml"></a>
625
679
  <div class="program_caption">
626
- <code>schema06.yaml</code> : unique constraint with mapping and sequence</div>
680
+ <code>schema06.yaml</code> : unique constraint entry with mapping and sequence</div>
627
681
  <pre class="program">type: seq
628
682
  sequence:
629
683
  - type: map
@@ -697,12 +751,12 @@ document06b.yaml#0: INVALID
697
751
 
698
752
  <a name="schema-hook"></a>
699
753
  <h3 class="section2">Validator#validator_hook()</h3>
700
- <p>You can extend Kwalify::Validator class and override Kwalify::Validator#validator_hook() method.
701
- This method is called by Kwalify::Validator#validate().
754
+ <p>You can extend Kwalify::Validator class (Ruby) or kwalify.Validator class (Java), and override Kwalify::Validator#validator_hook() method (Ruby) or kwalify.Validator#validateHook() method (Java).
755
+ This method is called by Kwalify::Validator#validate() (Ruby) or kwalify.Validator#validate() (Java).
702
756
  </p>
703
- <a name="schema07.yaml"></a>
757
+ <a name="answers-schema.yaml"></a>
704
758
  <div class="program_caption">
705
- schema07.yaml : 'name:' is important.</div>
759
+ answers-schema.yaml : 'name:' is important.</div>
706
760
  <pre class="program">type: map
707
761
  mapping:
708
762
  answers:
@@ -724,9 +778,9 @@ mapping:
724
778
  reason:
725
779
  type: str
726
780
  </pre>
727
- <a name="validate07.rb"></a>
781
+ <a name="answers-validator.rb"></a>
728
782
  <div class="program_caption">
729
- validate07.rb : validate script</div>
783
+ answers-validator.rb : validate script for Ruby</div>
730
784
  <pre class="program">#!/usr/bin/env ruby
731
785
 
732
786
  require 'kwalify'
@@ -736,7 +790,7 @@ require 'yaml'
736
790
  class AnswersValidator &lt; Kwalify::Validator
737
791
 
738
792
  ## load schema definition
739
- @@schema = YAML.load_file('schema07.yaml')
793
+ @@schema = YAML.load_file('answers-schema.yaml')
740
794
 
741
795
  def initialize()
742
796
  super(@@schema)
@@ -792,7 +846,7 @@ end
792
846
  </pre>
793
847
  <div class="terminal_caption">
794
848
  validate</div>
795
- <pre class="terminal">$ ruby validate07.rb document07a.yaml
849
+ <pre class="terminal">$ ruby answers-validator.rb document07a.yaml
796
850
  Valid.
797
851
  </pre>
798
852
  <a name="document07b.yaml"></a>
@@ -800,18 +854,141 @@ Valid.
800
854
  <code>document07b.yaml</code> : invalid document example</div>
801
855
  <pre class="program">answers:
802
856
  - name: Foo
803
- answer: good
857
+ answer: good
804
858
  - name: Bar
805
- answer: bad
859
+ answer: bad
806
860
  - name: Baz
807
- answer: not bad
861
+ answer: not bad
808
862
  </pre>
809
863
  <div class="terminal_caption">
810
864
  validate</div>
811
- <pre class="terminal">$ ruby validate07.rb document07b.yaml
865
+ <pre class="terminal">$ ruby answers-validator.rb document07b.yaml
812
866
  *** INVALID!
813
867
  - [/answers/1] : reason is required when answer is 'bad'.
814
868
  </pre>
869
+ <p>You can validate some document by a Validator instance because Validator class and Validator#validate() method are stateless. If you use instance variables in custom validator_hook() method, it becomes to be stateful.
870
+ </p>
871
+ <p>Here is a Java program equivarent to 'answers-validator.rb'.
872
+ </p>
873
+ <a name="AnswersValidator.java"></a>
874
+ <div class="program_caption">
875
+ AnswersValidator.java : validate program for Java</div>
876
+ <pre class="program">import kwalify.Validator;
877
+ import kwalify.Rule;
878
+ import kwalify.Util;
879
+ import kwalify.YamlUtil;
880
+ import kwalify.YamlParser;
881
+ import kwalify.SyntaxException;
882
+ import kwalify.ValidationException;
883
+
884
+ import java.util.*;
885
+ import java.io.IOException;
886
+
887
+
888
+ /**
889
+ * validator class for answers
890
+ */
891
+ public class AnswersValidator extends Validator {
892
+
893
+ /** schema string */
894
+ private static final String SCHEMA = ""
895
+ + "type: map\n"
896
+ + "mapping:\n"
897
+ + " answers:\n"
898
+ + " type: seq\n"
899
+ + " sequence:\n"
900
+ + " - type: map\n"
901
+ + " name: Answer\n"
902
+ + " mapping:\n"
903
+ + " name:\n"
904
+ + " type: str\n"
905
+ + " required: yes\n"
906
+ + " answer:\n"
907
+ + " type: str\n"
908
+ + " required: yes\n"
909
+ + " enum:\n"
910
+ + " - good\n"
911
+ + " - not bad\n"
912
+ + " - bad\n"
913
+ + " reason:\n"
914
+ + " type: str\n"
915
+ ;
916
+
917
+ /** schema object */
918
+ private static Map schema = null;
919
+ static {
920
+ try {
921
+ schema = (Map)YamlUtil.load(SCHEMA);
922
+ } catch (SyntaxException ex) {
923
+ assert false;
924
+ }
925
+ }
926
+
927
+ /** construnctor */
928
+ public AnswersValidator() {
929
+ super(schema);
930
+ }
931
+
932
+ /** hook method called by Validator#validate() */
933
+ protected void validateHook(Object value, Rule rule, String path, List errors) {
934
+ String rule_name = rule.getName();
935
+ if (rule_name != null &amp;&amp; rule_name.equals("Answer")) {
936
+ assert value instanceof Map;
937
+ Map val = (Map)value;
938
+ assert val.get("answer") != null;
939
+ if (val.get("answer").equals("bad")) {
940
+ String reason = (String)val.get("reason");
941
+ if (reason == null || reason.length() == 0) {
942
+ String msg = "reason is required when answer is 'bad'.";
943
+ errors.add(new ValidationException(msg, path));
944
+ }
945
+ }
946
+ }
947
+ }
948
+
949
+ /** main program */
950
+ public static void main(String[] args) throws IOException, SyntaxException {
951
+ // create validator
952
+ Validator validator = new AnswersValidator();
953
+
954
+ // load YAML document
955
+ String input;
956
+ if (args.length &gt; 0) {
957
+ input = Util.readFile(args[0]);
958
+ } else {
959
+ input = Util.readInputStream(System.in);
960
+ }
961
+ YamlParser parser = new YamlParser(input);
962
+ Object document = parser.parse();
963
+
964
+ // validate and show errors
965
+ List errors = validator.validate(document);
966
+ if (errors == null || errors.size() == 0) {
967
+ System.out.println("Valid.");
968
+ } else {
969
+ System.out.println("*** INVALID!");
970
+ parser.setErrorsLineNumber(errors);
971
+ Collections.sort(errors);
972
+ for (Iterator it = errors.iterator(); it.hasNext(); ) {
973
+ ValidationException error = (ValidationException)it.next();
974
+ int linenum = error.getLineNumber();
975
+ String path = error.getPath();
976
+ String mesg = error.getMessage();
977
+ String s = "- line " + linenum + ": [" + path + "] " + mesg;
978
+ System.out.println(s);
979
+ }
980
+ }
981
+ }
982
+ }
983
+ </pre>
984
+ <div class="terminal_caption">
985
+ validate</div>
986
+ <pre class="terminal">$ java -classpath kwalify.jar AnswersValidator document07a.yaml
987
+ Valid.
988
+ $ java -classpath kwalify.jar AnswersValidator document07b.yaml
989
+ *** INVALID!
990
+ - line 4: [/answers/1] reason is required when answer is 'bad'.
991
+ </pre>
815
992
  <br>
816
993
 
817
994
 
@@ -830,7 +1007,7 @@ require 'kwalify'
830
1007
  require 'yaml'
831
1008
 
832
1009
  ## load schema definition
833
- schema = YAML.load_file('schema06.yaml')
1010
+ schema = YAML.load_file('answers-schema.yaml')
834
1011
 
835
1012
  ## create validator for answers
836
1013
  validator = Kwalify::Validator.new(schema) <strong>{ |value, rule, path, errors|</strong>
@@ -865,14 +1042,13 @@ end
865
1042
  <div class="terminal_caption">
866
1043
  validate</div>
867
1044
  <pre class="terminal">$ ruby validate08.rb document07a.yaml
868
- *** INVALID!
869
- - [/] : not a sequence.
1045
+ Valid.
870
1046
  </pre>
871
1047
  <div class="terminal_caption">
872
1048
  validate</div>
873
1049
  <pre class="terminal">$ ruby validate08.rb document07b.yaml
874
1050
  *** INVALID!
875
- - [/] : not a sequence.
1051
+ - [/answers/1] : reason is required when answer is 'bad'.
876
1052
  </pre>
877
1053
  <br>
878
1054
 
@@ -974,7 +1150,7 @@ document12a.yaml#0: valid.
974
1150
  <a name="document12b.yaml"></a>
975
1151
  <div class="program_caption">
976
1152
  <code>document12b.yaml</code> : invalid JSON document example</div>
977
- <pre class="program">{
1153
+ <pre class="program">{
978
1154
  "mail": "foo@mail.com",
979
1155
  "age": twenty,
980
1156
  "gender": "X",
@@ -1125,11 +1301,11 @@ tmp.update(a1) # merge
1125
1301
  tmp["A"] = 15 # override
1126
1302
  tmp["C"] = 30 # add
1127
1303
  </pre>
1128
- <p>This feature allows Kwalify to merge rules.
1304
+ <p>This feature allows Kwalify to merge rule entries.
1129
1305
  </p>
1130
1306
  <a name="schema15.yaml"></a>
1131
1307
  <div class="program_caption">
1132
- <code>schema15.yaml</code> : default rule example</div>
1308
+ <code>schema15.yaml</code> : merging rule entries example</div>
1133
1309
  <pre class="program">type: map
1134
1310
  mapping:
1135
1311
  "group":
@@ -1146,11 +1322,11 @@ mapping:
1146
1322
  type: map
1147
1323
  mapping:
1148
1324
  "name":
1149
- <strong>&lt;&lt;: *name # merge</strong>
1150
- <strong>length: { max: 16 } # override</strong>
1325
+ <strong>&lt;&lt;: *name</strong> # merge
1326
+ <strong>length: { max: 16 }</strong> # override
1151
1327
  "email":
1152
- <strong>&lt;&lt;: *email # merge</strong>
1153
- <strong>required: yes # add</strong>
1328
+ <strong>&lt;&lt;: *email</strong> # merge
1329
+ <strong>required: yes</strong> # add
1154
1330
  </pre>
1155
1331
  <a name="document15a.yaml"></a>
1156
1332
  <div class="program_caption">