to_source 0.1.3 → 0.2.0

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.
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rspec'
4
+
5
+ # require spec support files and shared behavior
6
+ Dir[File.expand_path('../{support,shared}/**/*.rb', __FILE__)].each { |f| require f }
7
+
8
+ require 'to_source'
9
+
10
+ RSpec.configure do |config|
11
+ end
@@ -0,0 +1,999 @@
1
+ require 'spec_helper'
2
+
3
+ describe ToSource::Visitor,'.run' do
4
+ subject { described_class.run(node) }
5
+
6
+ def compress(code)
7
+ lines = code.split("\n")
8
+ match = /\A( *)/.match(lines.first)
9
+ whitespaces = match[1].to_s.length
10
+ stripped = lines.map do |line|
11
+ line[whitespaces..-1]
12
+ end
13
+ joined = stripped.join("\n")
14
+ end
15
+
16
+ shared_examples_for 'a source generation method' do
17
+ it 'should create original source' do
18
+ should eql(compress(expected_source))
19
+ end
20
+ end
21
+
22
+ def self.assert_source(source)
23
+ let(:node) { source.to_ast }
24
+ let(:source) { source }
25
+ let(:expected_source) { source }
26
+
27
+ it_should_behave_like 'a source generation method'
28
+ end
29
+
30
+ def self.assert_converts(converted, source)
31
+ let(:node) { source.to_ast }
32
+ let(:source) { source }
33
+ let(:expected_source) { converted }
34
+ it_should_behave_like 'a source generation method'
35
+ end
36
+
37
+ context 'class' do
38
+ context 'simple' do
39
+ assert_source <<-RUBY
40
+ class TestClass
41
+ end
42
+ RUBY
43
+ end
44
+
45
+ context 'singleton class inheritance' do
46
+ assert_source <<-RUBY
47
+ class << some_object
48
+ the_body
49
+ end
50
+ RUBY
51
+ end
52
+
53
+ context 'scoped' do
54
+ assert_source <<-RUBY
55
+ class SomeNameSpace::TestClass
56
+ end
57
+ RUBY
58
+ end
59
+
60
+ context 'deeply scoped' do
61
+ assert_source <<-RUBY
62
+ class Some::Name::Space::TestClass
63
+ end
64
+ RUBY
65
+ end
66
+
67
+ context 'with subclass' do
68
+ assert_source <<-RUBY
69
+ class TestClass < Object
70
+ end
71
+ RUBY
72
+ end
73
+
74
+ context 'with scoped superclass' do
75
+ assert_source <<-RUBY
76
+ class TestClass < SomeNameSpace::Object
77
+ end
78
+ RUBY
79
+ end
80
+
81
+ context 'with body' do
82
+ assert_source <<-RUBY
83
+ class TestClass
84
+ def foo
85
+ :bar
86
+ end
87
+ end
88
+ RUBY
89
+ end
90
+
91
+ context 'toplevel' do
92
+ assert_source <<-RUBY
93
+ class ::TestClass
94
+ end
95
+ RUBY
96
+ end
97
+ end
98
+
99
+ context 'module nodes' do
100
+ context 'simple' do
101
+ assert_source <<-RUBY
102
+ module TestModule
103
+ end
104
+ RUBY
105
+ end
106
+
107
+ context 'scoped' do
108
+ assert_source <<-RUBY
109
+ module SomeNameSpace::TestModule
110
+ end
111
+ RUBY
112
+ end
113
+
114
+ context 'deeply scoped' do
115
+ assert_source <<-RUBY
116
+ module Some::Name::Space::TestModule
117
+ end
118
+ RUBY
119
+ end
120
+
121
+ context 'with body' do
122
+ assert_source <<-RUBY
123
+ module TestModule
124
+ def foo
125
+ :bar
126
+ end
127
+ end
128
+ RUBY
129
+ end
130
+ end
131
+
132
+ context 'single assignment' do
133
+ context 'to local variable' do
134
+ assert_source 'foo = 1'
135
+ end
136
+
137
+ context 'to instance variable' do
138
+ assert_source '@foo = 1'
139
+ end
140
+
141
+ context 'to global variable' do
142
+ assert_source '$foo = 1'
143
+ end
144
+
145
+ context 'to class variable' do
146
+ assert_source '@@foo = 1'
147
+ end
148
+
149
+
150
+ context 'to constant' do
151
+ assert_source 'SOME_CONSTANT = 1'
152
+ end
153
+ end
154
+
155
+ context 'conditional element assignment' do
156
+ assert_source 'foo[key] ||= bar'
157
+ end
158
+
159
+ context 'attribute assignment on merge' do
160
+ assert_source 'self.foo |= bar'
161
+ end
162
+
163
+
164
+ context 'element assignment' do
165
+ assert_source 'array[index] = value'
166
+ end
167
+
168
+ context 'multiple assignment' do
169
+ context 'to local variable' do
170
+ assert_source 'a, b = 1, 2'
171
+ end
172
+
173
+ context 'to instance variable' do
174
+ assert_source '@a, @b = 1, 2'
175
+ end
176
+
177
+ context 'to class variable' do
178
+ assert_source '@@a, @@b = 1, 2'
179
+ end
180
+
181
+ context 'to global variable' do
182
+ assert_source '$a, $b = 1, 2'
183
+ end
184
+
185
+ context 'unbalanced' do
186
+ assert_source 'a, b = foo'
187
+ end
188
+ end
189
+
190
+ context 'defined' do
191
+ context 'with instance varialbe' do
192
+ assert_source <<-RUBY
193
+ defined?(@foo)
194
+ RUBY
195
+ end
196
+
197
+ context 'with constant' do
198
+ assert_source <<-RUBY
199
+ defined?(Foo)
200
+ RUBY
201
+ end
202
+ end
203
+
204
+ context 'access' do
205
+ context 'on local variable' do
206
+ assert_source <<-RUBY
207
+ foo = 1
208
+ foo
209
+ RUBY
210
+ end
211
+
212
+ context 'on class variable' do
213
+ assert_source '@@foo'
214
+ end
215
+
216
+ context 'on nth ref global variable' do
217
+ assert_source '$1'
218
+ end
219
+
220
+ context 'on global variable' do
221
+ assert_source '$foo'
222
+ end
223
+
224
+ context 'on instance variable' do
225
+ assert_source '@foo'
226
+ end
227
+
228
+ context 'toplevel constant' do
229
+ assert_source '::Rubinius'
230
+ end
231
+
232
+ context 'constant' do
233
+ assert_source 'Rubinius'
234
+ end
235
+
236
+ context 'scoped constant' do
237
+ assert_source 'Rubinius::Debugger'
238
+ end
239
+ end
240
+
241
+ context 'literal' do
242
+ context 'fixnum' do
243
+ assert_source '1'
244
+ end
245
+
246
+ context 'float' do
247
+ assert_source '1.0'
248
+ end
249
+
250
+ context 'negated numeric' do
251
+ assert_source '-1'
252
+ end
253
+
254
+ context 'string' do
255
+ assert_source '"foo"'
256
+ end
257
+
258
+ context 'execute string' do
259
+ assert_source '`foo`'
260
+ end
261
+
262
+ context 'symbol' do
263
+ assert_source ':foo'
264
+ end
265
+
266
+ context 'true' do
267
+ assert_source 'true'
268
+ end
269
+
270
+ context 'false' do
271
+ assert_source 'false'
272
+ end
273
+
274
+ context 'nil' do
275
+ assert_source 'nil'
276
+ end
277
+
278
+ context 'empty array' do
279
+ assert_source '[]'
280
+ end
281
+
282
+ context 'array' do
283
+ context 'simple' do
284
+ assert_source '[1, 2, 3]'
285
+ end
286
+
287
+ context 'with splat' do
288
+ assert_source '[1, *foo]'
289
+ end
290
+ end
291
+
292
+ context 'empty hash' do
293
+ assert_source '{}'
294
+ end
295
+
296
+ context 'hash' do
297
+ assert_source '{:answer => 42, :bar => :baz}'
298
+ end
299
+
300
+ context 'inclusive range' do
301
+ assert_source '20..34'
302
+ end
303
+
304
+ context 'exclusive range' do
305
+ assert_source '20...34'
306
+ end
307
+
308
+ context 'regexp' do
309
+ context 'simple' do
310
+ assert_source '/.*/'
311
+ end
312
+
313
+ context 'with escapes' do
314
+ assert_source '/\//'
315
+ end
316
+ end
317
+
318
+ context 'dynamic string' do
319
+ context 'simple' do
320
+ assert_source '"foo#{bar}baz"'
321
+ end
322
+
323
+ context 'with escapes' do
324
+ assert_source '"fo\no#{bar}b\naz"'
325
+ end
326
+ end
327
+
328
+ context 'dynamic symbol' do
329
+ context 'simple' do
330
+ assert_source ':"foo#{bar}baz"'
331
+ end
332
+
333
+ context 'with escapes' do
334
+ assert_source ':"fo\no#{bar}b\naz"'
335
+ end
336
+ end
337
+
338
+ context 'dynamic execute' do
339
+ context 'simple' do
340
+ assert_source '`foo#{bar}baz`'
341
+ end
342
+
343
+ context 'with escapes' do
344
+ assert_source '`fo\no#{bar}b\naz`'
345
+ end
346
+ end
347
+
348
+ context 'dynamic regexp' do
349
+ context 'simple' do
350
+ assert_source '/foo#{bar}baz/'
351
+ end
352
+
353
+ context 'with escapes' do
354
+ assert_source '/fo\no#{bar}b\naz/'
355
+ end
356
+ end
357
+ end
358
+
359
+ context 'send' do
360
+ context 'as element reference' do
361
+ assert_source 'foo[index]'
362
+ end
363
+
364
+ context 'without arguments' do
365
+ assert_source 'foo.bar'
366
+ end
367
+
368
+ context 'with arguments' do
369
+ assert_source 'foo.bar(:baz, :yeah)'
370
+ end
371
+
372
+ context 'with block' do
373
+ assert_source <<-RUBY
374
+ foo.bar do
375
+ 3
376
+ 4
377
+ end
378
+ RUBY
379
+ end
380
+
381
+ context 'to self' do
382
+ context 'explicitly' do
383
+ assert_source 'self.foo'
384
+ end
385
+
386
+ context 'implicitly' do
387
+ assert_source 'foo'
388
+ end
389
+
390
+ context 'with arguments' do
391
+ context 'implicitly' do
392
+ assert_source 'bar(:baz, :yeah)'
393
+ end
394
+
395
+ context 'explicitly' do
396
+ assert_source 'self.bar(:baz, :yeah)'
397
+ end
398
+ end
399
+ end
400
+
401
+ context 'with block that takes arguments' do
402
+ assert_source <<-RUBY
403
+ foo.bar do |a|
404
+ 3
405
+ 4
406
+ end
407
+ RUBY
408
+ end
409
+
410
+ context 'with splat argument' do
411
+ assert_source 'foo.bar(*args)'
412
+ end
413
+
414
+ context 'with formal and splat argument' do
415
+ assert_source 'foo.bar(foo, *args)'
416
+ end
417
+
418
+ context 'with formal splat and block argument' do
419
+ assert_source 'foo.bar(foo, *args, &block)'
420
+ end
421
+
422
+ context 'with formal splat and block' do
423
+ assert_source <<-RUBY
424
+ foo.bar(foo, *args) do
425
+ some_stuff
426
+ end
427
+ RUBY
428
+ end
429
+
430
+
431
+ context 'with passing block argument' do
432
+ assert_source 'foo.bar(&baz)'
433
+ end
434
+
435
+ context 'with formal and block argument' do
436
+ assert_source 'foo.bar(:baz, &baz)'
437
+ end
438
+
439
+ context 'attribute assignment' do
440
+ context 'on foreign object' do
441
+ assert_source 'foo.bar= :baz'
442
+ end
443
+
444
+ context 'on self' do
445
+ assert_source 'self.foo= :bar'
446
+ end
447
+ end
448
+ end
449
+
450
+ context 'lambda' do
451
+ assert_source <<-RUBY
452
+ lambda do |a, b|
453
+ a
454
+ end
455
+ RUBY
456
+ end
457
+
458
+ context 'super' do
459
+ context 'without arguments' do
460
+ assert_source 'super'
461
+ end
462
+
463
+ context 'with argument' do
464
+ assert_source 'super(a)'
465
+ end
466
+
467
+ context 'with arguments' do
468
+ assert_source 'super(a, b)'
469
+ end
470
+
471
+ context 'with block argument' do
472
+ assert_source 'super(&block)'
473
+ end
474
+
475
+ context 'with formal and block argument' do
476
+ assert_source 'super(a, &block)'
477
+ end
478
+ end
479
+
480
+ context 'break' do
481
+ assert_source 'break'
482
+ end
483
+
484
+ context 'next' do
485
+ assert_source 'next'
486
+ end
487
+
488
+ context 'match operator' do
489
+ assert_source <<-RUBY
490
+ foo =~ /bar/
491
+ RUBY
492
+ end
493
+
494
+ context 'alias' do
495
+ assert_source <<-RUBY
496
+ alias foo bar
497
+ RUBY
498
+ end
499
+
500
+ context 'yield' do
501
+ context 'without arguments' do
502
+ assert_source 'yield'
503
+ end
504
+
505
+ context 'with argument' do
506
+ assert_source 'yield(a)'
507
+ end
508
+
509
+ context 'with arguments' do
510
+ assert_source 'yield(a, b)'
511
+ end
512
+ end
513
+
514
+ context 'binary operators' do
515
+ %w(+ - * / & | && || << >> == === != <= < <=> > >= =~ !~ ^ **).each do |operator|
516
+ context "on literals #{operator}" do
517
+ assert_source "1 #{operator} 2"
518
+ end
519
+
520
+ context "on self #{operator}" do
521
+ assert_source "self #{operator} b"
522
+ end
523
+
524
+ context "on calls #{operator}" do
525
+ assert_source "a #{operator} b"
526
+ end
527
+ end
528
+ end
529
+
530
+ context 'expansion of shortcuts' do
531
+ context 'on += operator' do
532
+ assert_converts 'a = a + 2', 'a += 2'
533
+ end
534
+
535
+ context 'on -= operator' do
536
+ assert_converts 'a = a - 2', 'a -= 2'
537
+ end
538
+
539
+ context 'on **= operator' do
540
+ assert_converts 'a = a ** 2', 'a **= 2'
541
+ end
542
+
543
+ context 'on *= operator' do
544
+ assert_converts 'a = a * 2', 'a *= 2'
545
+ end
546
+
547
+ context 'on /= operator' do
548
+ assert_converts 'a = a / 2', 'a /= 2'
549
+ end
550
+
551
+ context 'on &&= operator' do
552
+ assert_converts 'a && a = 2', 'a &&= 2'
553
+ end
554
+
555
+ context 'on ||= operator' do
556
+ assert_converts 'a || a = 2', 'a ||= 2'
557
+ end
558
+ end
559
+
560
+ context 'unary operators' do
561
+ context 'negation' do
562
+ assert_source '!1'
563
+ end
564
+
565
+ context 'double negation' do
566
+ assert_source '!!1'
567
+ end
568
+ end
569
+
570
+ context 'if statement' do
571
+ context 'without else branch' do
572
+ context 'single statement in branch' do
573
+ assert_source <<-RUBY
574
+ if 3
575
+ 9
576
+ end
577
+ RUBY
578
+ end
579
+
580
+ context 'multiple statements in branch' do
581
+ assert_source <<-RUBY
582
+ if 3
583
+ 9
584
+ 10
585
+ end
586
+ RUBY
587
+ end
588
+ end
589
+
590
+ context 'with else branch' do
591
+ context 'single expression in branch' do
592
+ assert_source <<-RUBY
593
+ if 4
594
+ 5
595
+ else
596
+ 6
597
+ end
598
+ RUBY
599
+ end
600
+
601
+ context 'multiple expressions in branch' do
602
+ assert_source <<-RUBY
603
+ if 4
604
+ 5
605
+ else
606
+ 6
607
+ 7
608
+ end
609
+ RUBY
610
+ end
611
+ end
612
+
613
+ context 'unless' do
614
+ context 'single statement in branch' do
615
+ assert_source <<-RUBY
616
+ unless 3
617
+ 9
618
+ end
619
+ RUBY
620
+ end
621
+
622
+ context 'single statement in branch' do
623
+ assert_source <<-RUBY
624
+ unless 3
625
+ 9
626
+ 10
627
+ end
628
+ RUBY
629
+ end
630
+ end
631
+ end
632
+
633
+ context 'case statement' do
634
+ context 'without else branch' do
635
+ assert_source <<-RUBY
636
+ case foo
637
+ when bar
638
+ baz
639
+ when baz
640
+ bar
641
+ end
642
+ RUBY
643
+ end
644
+
645
+ context 'with multivalued conditions' do
646
+ assert_source <<-RUBY
647
+ case foo
648
+ when bar, baz
649
+ :other
650
+ end
651
+ RUBY
652
+ end
653
+
654
+ context 'with splat operator' do
655
+ assert_source <<-RUBY
656
+ case foo
657
+ when *bar
658
+ :value
659
+ end
660
+ RUBY
661
+ end
662
+
663
+ context 'with else branch' do
664
+ assert_source <<-RUBY
665
+ case foo
666
+ when bar
667
+ baz
668
+ else
669
+ :foo
670
+ end
671
+ RUBY
672
+ end
673
+ end
674
+
675
+ context 'while' do
676
+ context 'single statement in body' do
677
+ assert_source <<-RUBY
678
+ while false
679
+ 3
680
+ end
681
+ RUBY
682
+ end
683
+
684
+ context 'multiple expressions in body' do
685
+ assert_source <<-RUBY
686
+ while false
687
+ 3
688
+ 5
689
+ end
690
+ RUBY
691
+ end
692
+ end
693
+
694
+ context 'until' do
695
+ context 'with single expression in body' do
696
+ assert_source <<-RUBY
697
+ until false
698
+ 3
699
+ end
700
+ RUBY
701
+ end
702
+
703
+ context 'with multiple expressions in body' do
704
+ assert_source <<-RUBY
705
+ while false
706
+ 3
707
+ 5
708
+ end
709
+ RUBY
710
+ end
711
+ end
712
+
713
+ # Note:
714
+ #
715
+ # Do not remove method_call from
716
+ #
717
+ # begin
718
+ # stuff
719
+ # end.method_call
720
+ #
721
+ # As 19mode would optimize begin end blocks away
722
+ #
723
+ context 'begin' do
724
+ context 'simple' do
725
+ assert_source <<-RUBY
726
+ begin
727
+ foo
728
+ bar
729
+ end.some_method
730
+ RUBY
731
+ end
732
+
733
+ context 'with rescue condition' do
734
+ assert_source <<-RUBY
735
+ x = begin
736
+ foo
737
+ rescue
738
+ bar
739
+ end.some_method
740
+ RUBY
741
+ end
742
+
743
+ context 'with with ensure' do
744
+ assert_source <<-RUBY
745
+ begin
746
+ foo
747
+ ensure
748
+ bar
749
+ end.some_method
750
+ RUBY
751
+ end
752
+ end
753
+
754
+ context 'rescue' do
755
+ context 'without rescue condition' do
756
+ assert_source <<-RUBY
757
+ def foo
758
+ bar
759
+ rescue
760
+ baz
761
+ end
762
+ RUBY
763
+ end
764
+
765
+ context 'with rescue condition' do
766
+ context 'without assignment' do
767
+ assert_source <<-RUBY
768
+ def foo
769
+ bar
770
+ rescue SomeError
771
+ baz
772
+ end
773
+ RUBY
774
+ end
775
+
776
+ context 'with assignment' do
777
+ assert_source <<-RUBY
778
+ def foo
779
+ bar
780
+ rescue SomeError => exception
781
+ baz
782
+ end
783
+ RUBY
784
+ end
785
+ end
786
+
787
+ context 'with multivalued rescue condition' do
788
+ context 'without assignment' do
789
+ assert_source <<-RUBY
790
+ def foo
791
+ bar
792
+ rescue SomeError, SomeOtherError
793
+ baz
794
+ end
795
+ RUBY
796
+ end
797
+
798
+ context 'with assignment' do
799
+ assert_source <<-RUBY
800
+ def foo
801
+ bar
802
+ rescue SomeError, SomeOther => exception
803
+ baz
804
+ end
805
+ RUBY
806
+ end
807
+ end
808
+
809
+ context 'with multiple rescue conditions' do
810
+ assert_source <<-RUBY
811
+ def foo
812
+ foo
813
+ rescue SomeError
814
+ bar
815
+ rescue
816
+ baz
817
+ end
818
+ RUBY
819
+ end
820
+
821
+ context 'with normal and splat condition' do
822
+ context 'without assignment' do
823
+ assert_source <<-RUBY
824
+ def foo
825
+ bar
826
+ rescue SomeError, *bar
827
+ baz
828
+ end
829
+ RUBY
830
+ end
831
+
832
+ context 'with assignment' do
833
+ assert_source <<-RUBY
834
+ def foo
835
+ bar
836
+ rescue SomeError, *bar => exception
837
+ baz
838
+ end
839
+ RUBY
840
+ end
841
+ end
842
+
843
+ context 'with splat condition' do
844
+ context 'without assignment' do
845
+ assert_source <<-RUBY
846
+ def foo
847
+ bar
848
+ rescue *bar
849
+ baz
850
+ end
851
+ RUBY
852
+ end
853
+
854
+ context 'with assignment' do
855
+ assert_source <<-RUBY
856
+ def foo
857
+ bar
858
+ rescue *bar => exception
859
+ baz
860
+ end
861
+ RUBY
862
+ end
863
+ end
864
+ end
865
+
866
+ context '__FILE__' do
867
+ assert_source '__FILE__'
868
+ end
869
+
870
+ context 'ensure' do
871
+ assert_source <<-RUBY
872
+ def foo
873
+ bar
874
+ ensure
875
+ baz
876
+ end
877
+ RUBY
878
+ end
879
+
880
+ context 'return' do
881
+ context 'with expression' do
882
+ assert_source 'return 9'
883
+ end
884
+
885
+ context 'without expression' do
886
+ assert_source 'return'
887
+ end
888
+ end
889
+
890
+ context 'define' do
891
+ context 'on instance' do
892
+ context 'without arguments' do
893
+ assert_source <<-RUBY
894
+ def foo
895
+ bar
896
+ end
897
+ RUBY
898
+ end
899
+
900
+ context 'with single argument' do
901
+ assert_source <<-RUBY
902
+ def foo(bar)
903
+ bar
904
+ end
905
+ RUBY
906
+ end
907
+
908
+ context 'with multiple arguments' do
909
+ assert_source <<-RUBY
910
+ def foo(bar, baz)
911
+ bar
912
+ end
913
+ RUBY
914
+ end
915
+
916
+ context 'with optional argument' do
917
+ assert_source <<-RUBY
918
+ def foo(bar = true)
919
+ bar
920
+ end
921
+ RUBY
922
+ end
923
+
924
+ context 'with required and optional arguments' do
925
+ assert_source <<-RUBY
926
+ def foo(bar, baz = true)
927
+ bar
928
+ end
929
+ RUBY
930
+ end
931
+
932
+ context 'with unnamed splat argument' do
933
+ assert_source <<-RUBY
934
+ def foo(*)
935
+ bar
936
+ end
937
+ RUBY
938
+ end
939
+
940
+ context 'with splat argument' do
941
+ assert_source <<-RUBY
942
+ def foo(*bar)
943
+ bar
944
+ end
945
+ RUBY
946
+ end
947
+
948
+ context 'with required and splat arguments' do
949
+ assert_source <<-RUBY
950
+ def foo(bar, *baz)
951
+ bar
952
+ end
953
+ RUBY
954
+ end
955
+
956
+ context 'with required optional and splat argument' do
957
+ assert_source <<-RUBY
958
+ def foo(bar, baz = true, *bor)
959
+ bar
960
+ end
961
+ RUBY
962
+ end
963
+
964
+ context 'with block argument' do
965
+ assert_source <<-RUBY
966
+ def foor(&block)
967
+ bar
968
+ end
969
+ RUBY
970
+ end
971
+
972
+ context 'with required and block arguments' do
973
+ assert_source <<-RUBY
974
+ def foor(bar, &block)
975
+ bar
976
+ end
977
+ RUBY
978
+ end
979
+ end
980
+
981
+ context 'on singleton' do
982
+ context 'on self' do
983
+ assert_source <<-RUBY
984
+ def self.foo
985
+ bar
986
+ end
987
+ RUBY
988
+ end
989
+
990
+ context 'on constant' do
991
+ assert_source <<-RUBY
992
+ def Foo.bar
993
+ bar
994
+ end
995
+ RUBY
996
+ end
997
+ end
998
+ end
999
+ end