forked from andrewplummer/Sugar
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprototype.js
1195 lines (1192 loc) · 53 KB
/
prototype.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Compatibility index:
//
// 0 - Does not exist.
// 1 - Exists but does not support all functionality.
// 2 - Exists and supports all functionality.
// 3 - Exists and supports all functionality plus more.
var SugarPrototypeMethods = [
{
// Global namespace
type: 'class',
namespace: 'Global',
methods: [
{
name: 'Hash',
description: 'Creates a hash object with methods specific to working with hashes.',
sugar_compatibility: 1,
sugar_notes: 'The Hash class does not exist in Sugar, however hash-like objects exist through Object.extended, which will return an extended object with instance methods on it similar to hashes in Prototype. Keep in mind, however, that the instance methods available to extended objects in Sugar do not 100% match those of Prototype.',
original_code: "$H({ 0: 'a', 1: 'b', 2: 'c' })",
sugar_code: "Object.extended({ 0: 'a', 1: 'b', 2: 'c' })",
ref: 'Object/extended'
},
{
name: '$A',
description: 'Creates an array from an array-like collection',
sugar_compatibility: 1,
sugar_notes: '$A exists in Sugar as Array.create. Be aware, however, that when a Javascript primitive is passed, it will simply be added to the array. If, for example, you need a string to be split into the array, then use the standard String#split instead. The most common use of this method, converting an arguments object into an actual array, will work, however.',
original_code: '$A(arguments)',
sugar_code: 'Array.create(arguments)',
ref: 'Array/create'
},
{
name: '$H',
description: 'Creates a hash object with methods specific to working with hashes.',
sugar_compatibility: 1,
sugar_notes: '$H exists in Sugar as Object.extended. This will return an extended object with instance methods on it similar to hashes in Prototype. Keep in mind, however, that the instance methods available to extended objects in Sugar do not 100% match those of Prototype.',
original_code: "$H({ 0: 'a', 1: 'b', 2: 'c' })",
sugar_code: "Object.extended({ 0: 'a', 1: 'b', 2: 'c' })",
ref: 'Object/extended'
},
{
name: '$R',
description: 'Creates an ObjectRange object that represents a range of consecutive values.',
sugar_compatibility: 0,
sugar_notes: '$R (ObjectRanges) do not exist in Sugar. However, Number#upto or Number#downto achieve a very similar effect by directly creating arrays that contain that range.',
original_code: "$R(0, 10)",
sugar_code: "(0).upto(10)",
ref: 'Number/upto'
},
{
name: '$w',
description: 'Splits a string into an array with all whitespace treated as a delimiter',
sugar_compatibility: 0,
sugar_notes: '$w does not exist in Sugar. Use native String#split instead.',
original_code: "$w('apples and oranges')",
sugar_code: "'apples and oranges'.split(' ')"
}
]
},
{
namespace: 'Number',
type: 'instance',
methods: [
{
name: 'succ',
description: 'Returns the successor (+1) of the current number.',
sugar_compatibility: 0,
sugar_notes: 'Number#succ does not exist in Sugar. This is often done with the + operator :)',
original_code: "num.succ()",
sugar_code: "num + 1"
},
{
name: 'times',
description: 'Calls the passed iterator n times, where n is the number.',
sugar_compatibility: 1,
sugar_notes: 'Number#times exists in Sugar but does not take a context argument. Use Function#bind for this purpose instead.',
original_code: "(8).times(function(){}, 'barf')",
sugar_code: "(8).times(function(){}.bind('barf'))",
live_notes: 'Number#times does not accept a second argument, but found {1}. If you need to bind context, use Function#bind instead.',
conflict: function() {
var type = typeof arguments[1];
return [arguments.length > 1 && type != 'number', arguments[1]];
},
ref: 'Function/bind'
},
{
name: 'toColorPart',
description: 'Returns a 2 digit hexadecimal representation of the number.',
sugar_compatibility: 2,
sugar_notes: 'Number#toColorPart exists in Sugar as Number#hex (pad to 2 places).',
original_code: "(255).toColorPart()",
sugar_code: "(255).hex(2)",
ref: 'Number/hex'
},
{
name: 'toPaddedString',
description: 'Returns a string representation of the number padded with zeros.',
sugar_compatibility: 2,
sugar_notes: 'Number#toPaddedString exists in Sugar as Number#pad. Note that in Sugar, the radix is the third argument, as the second is to force the sign.',
original_code: "(20).toPaddedString(4, 2)",
sugar_code: "(20).pad(4, false, 2)",
ref: 'Number/pad'
},
{
name: 'abs',
description: 'Returns the absolute value of the number.',
sugar_compatibility: 2,
sugar_notes: 'Number#abs exists in Sugar and is identical.',
conflict: false,
ref: 'Number/abs'
},
{
name: 'ceil',
description: 'Rounds then number up.',
sugar_compatibility: 3,
sugar_notes: 'Number#ceil exists in Sugar. It can additionally round to a precision, specified in the first argument.',
conflict: false,
ref: 'Number/ceil'
},
{
name: 'floor',
description: 'Rounds then number down.',
sugar_compatibility: 3,
sugar_notes: 'Number#floor exists in Sugar. It can additionally round to a precision, specified in the first argument.',
conflict: false,
ref: 'Number/floor'
},
{
name: 'round',
description: 'Rounds then number.',
sugar_compatibility: 3,
sugar_notes: 'Number#round exists in Sugar. It can additionally round to a precision, specified in the first argument.',
conflict: false,
ref: 'Number/round'
}
]
},
{
namespace: 'String',
type: 'class',
methods: [
{
name: 'interpret',
description: 'Coerces the value into a string.',
sugar_compatibility: 0,
sugar_notes: 'String.interpret does not exist in Sugar. Use String() instead. Note, however that this will not convert null/undefined into a blank string, as is the case with String.interpret.',
original_code: "String.interpret(156)",
sugar_code: "String(156)"
}
]
},
{
namespace: 'String',
type: 'instance',
methods: [
{
name: 'blank',
description: 'Checks if the string is empty or contains only whitespace.',
sugar_compatibility: 2,
sugar_notes: 'String#blank exists in Sugar as String#isBlank.',
original_code: "'hello'.blank()",
sugar_code: "'hello'.isBlank()",
ref: 'String/isBlank'
},
{
name: 'camelize',
description: 'Converts a string to its camelCase equivalent.',
sugar_compatibility: 3,
sugar_notes: 'String#camelize exists and will also operate on whitespace and underscores as well as dashes.',
live_notes: 'String#camelize found white space or underscores! Note that #camelize in Sugar will remove whitespace and operate on underscores the same as dashes.',
conflict: function() {
return /[ _]/.test(this);
},
ref: 'String/camelize'
},
{
name: 'dasherize',
description: 'Replaces underscores with dashes.',
sugar_compatibility: 3,
sugar_notes: 'Sugar#dasherize will also remove whitespace and convert camelCase as well.',
conflict: function() {
return /[A-Z\s]/.test(this);
},
live_notes: 'String#dasherize found white space or capital letters! Note that #dasherize in Sugar will remove whitespace and operate on capital letters the same as underscores.',
ref: 'String/dasherize'
},
{
name: 'empty',
description: 'Checks if the string is empty.',
sugar_compatibility: 0,
sugar_notes: 'String#empty does not exist in Sugar. Use a straight comparison instead.',
original_code: "str.empty()",
sugar_code: "str === ''"
},
{
name: 'evalJSON',
description: 'Evaluates the string as JSON and returns the resulting object.',
sugar_compatibility: 0,
sugar_notes: 'String#evalJSON does not exist in Sugar. JSON.parse may work as an alternative, but it is not available in all browsers. If you absolutely require JSON support, consider adding in a separate library such as: https://github.com/douglascrockford/JSON-js',
original_code: "str.evalJSON()",
sugar_code: "JSON.parse(str)"
},
{
name: 'evalScripts',
description: 'Evaluates the content of any <script> block in the string.',
sugar_compatibility: 0,
sugar_notes: "String#evalScripts does not exist in Sugar. It's highly unlikely that you should be doing something like this anyway, (and even if you are, libraries like jQuery should perform this automatically), but if you really need to in a pinch, something like this may work:",
original_code: "str.evalScripts()",
sugar_code: "str.match(/<script.*?>.+?<\/script>/g).map(function(m){ return eval(m.replace(/<\/?script.*?>/g, '')); })"
},
{
name: 'extractScripts',
description: 'Extracts <script> blocks in the string and returns them as an array.',
sugar_compatibility: 0,
sugar_notes: 'String#extractScripts does not exist in Sugar. If you really need to do this, then in a pinch something like this may work.',
original_code: "str.extractScripts()",
sugar_code: "str.match(/<script.*?>.+?<\/script>/g).map(function(m){ return m.replace(/<\/?script.*?>/g, ''); })"
},
{
name: 'gsub',
description: 'Returns the string with every occurrence of the passed regex replaced.',
sugar_compatibility: 0,
sugar_notes: 'String#gsub does not exist in Sugar. Just use the native .replace function instead. Note that Javascript allows functions to be passed to .replace just like gsub.',
original_code: "'Image: (img.png)'.gsub(/Image: \(.+\)/, function(match, src){ return '<img src=\"' + src + '\" />'; })",
sugar_code: "'Image: (img.png)'.replace(/Image: \(.+\)/, function(match, src){ return '<img src=\"' + src + '\" />'; })"
},
{
name: 'include',
description: 'Checks if the string contains the substring.',
sugar_compatibility: 2,
sugar_notes: 'String#include exists in Sugar as String#has.',
original_code: "'foobar'.include('bar')",
sugar_code: "'foobar'.has('bar')",
ref: 'String/has'
},
{
name: 'inspect',
description: 'Returns a debug oriented version of the string.',
sugar_compatibility: 0,
sugar_notes: 'String#inspect does not exist in Sugar. Consider using JSON.stringify(str) instead. The JSON global does not exist in all implementations but should be enough to get you through a debug session.',
original_code: "'foofa'.inspect()",
sugar_code: "JSON.stringify('foofa')"
},
{
name: 'interpolate',
description: 'Fills the string with properties of an object, using the syntax #{}.',
sugar_compatibility: 3,
sugar_notes: 'String#interpolate exists in Sugar as String#assign, with a slightly different syntax.',
original_code: "'i like #{fruit}'.interpolate({ fruit: 'peaches' })",
sugar_code: "'i like {fruit}'.assign({ fruit: 'peaches' })",
ref: 'String/assign'
},
{
name: 'isJSON',
description: 'Checks if the string is valid JSON.',
sugar_compatibility: 0,
sugar_notes: 'String#isJSON does not exist in Sugar. The simplest way of determining if a value is JSON or not is to attempt parsing and catch errors. If you absolutely require full JSON support, consider adding in a separate library such as: https://github.com/douglascrockford/JSON-js',
original_code: "valid = str.isJSON()",
sugar_code: "try { JSON.parse(str); valid = true; } catch(e){ valid = false; }"
},
{
name: 'scan',
description: 'Iterates over every occurrence of the passed regex pattern.',
sugar_compatibility: 3,
sugar_notes: 'String#scan exists in Sugar as String#each. It additionally returns an array of the matched patterns.',
original_code: "'apple, pear & orange'.scan(/\w+/, console.log)",
sugar_code: "'apple, pear & orange'.each(/\w+/, console.log)",
ref: 'String/each'
},
{
name: 'strip',
description: 'Removes leading and trailing whitespace from the string.',
sugar_compatibility: 2,
sugar_notes: 'String#strip exists in Sugar as String#trim. This is an ES5 standard method that Sugar provides a shim for when unavailable.',
original_code: "' howdy '.strip()",
sugar_code: "' howdy '.trim()",
ref: 'String/trim'
},
{
name: 'stripScripts',
description: 'Strips HTML <script> tags from the string.',
sugar_compatibility: 3,
sugar_notes: 'String#stripScripts can be achieved in Sugar with String#removeTags.',
original_code: "'<script>doEvilStuff();</script>'.stripScripts()",
sugar_code: "'<script>doEvilStuff();</script>'.removeTags('script')",
ref: 'String/removeTags'
},
{
name: 'stripTags',
description: 'Strips the string of any HTML tags.',
sugar_notes: 'String#stripTags exists in Sugar and will additionally strip tags like <xsl:template>.',
sugar_compatibility: 3,
live_notes: 'String#stripTags found namespaced tags such as <xsl:template>. Be aware that Sugar will strip these tags too!',
conflict: function() {
return arguments.length == 0 && /<.*?:.*?>/.test(this);
},
ref: 'String/stripTags'
},
{
name: 'sub',
description: 'Returns a string with the first occurrence of the regex pattern replaced.',
sugar_compatibility: 0,
sugar_notes: 'String#sub does not exist in Sugar. Standard Javascript .replace is the closest approximation. If you need to replace more than one occurrence of a pattern (but not all), your best bet is to set a counter and test against it.',
original_code: "'one two three four'.sub(' ', ', ', 2)",
sugar_code: "var c = 0; 'one two three four'.replace(/\s/g, function(m, i){ c++; return c < 3 ? ', ' : ' '; })"
},
{
name: 'succ',
description: 'Returns the next character in the Unicode table.',
sugar_compatibility: 3,
sugar_notes: 'String#succ exists in Sugar as String#shift, which can move up or down the Unicode range by a number which is the first argument passed.',
original_code: "'a'.succ()",
sugar_code: "'a'.shift(1);",
ref: 'String/shift'
},
{
name: 'times',
description: 'Concatenates the string n times, where n is the first argument.',
sugar_compatibility: 2,
sugar_notes: 'String#times exists in Sugar as String#repeat.',
original_code: "'echo '.times(3)",
sugar_code: "'echo '.repeat(3);",
ref: 'String/repeat'
},
{
name: 'toArray',
description: 'Returns the string as an array of characters.',
sugar_compatibility: 3,
sugar_notes: 'String#toArray exists in Sugar as String#chars, which can also run a function against each character.',
original_code: "'howdy'.toArray()",
sugar_code: "'howdy'.chars();",
ref: 'String/chars'
},
{
name: 'toQueryParams',
description: 'Parses a URI-like query string and returns an object of key/value pairs.',
sugar_compatibility: 3,
sugar_notes: 'String#toQueryParams exists in Sugar but from an inverted perspective as Object.fromQueryString. Note that by default this will also parse out nested params with the non-standard "[]" syntax, however this can be turned off.',
original_code: "'section=blog&id=45'.toQueryParams()",
sugar_code: "Object.fromQueryString('section=blog&id=45')",
ref: 'Object/fromQueryString'
},
{
name: 'truncate',
description: 'Truncates a string to the given length and adds a suffix to it.',
sugar_compatibility: 3,
sugar_notes: 'String#truncate exists in Sugar but will not split words by default. If you want words to be split, pass true as the last argument.',
original_code: "longString.truncate(10, '...')",
sugar_code: "longString.truncate(10, '...', true)",
ref: 'String/truncate'
},
{
name: 'underscore',
description: 'Converts a camelized string into words separated by an underscore.',
sugar_compatibility: 3,
sugar_notes: 'String#underscore exists in Sugar and will additionally remove all white space.',
conflict: function() {
return /\s/.test(this);
},
live_notes: 'String#underscore found white space! Note that underscore in Sugar will remove all whitespace.',
ref: 'String/underscore'
},
{
name: 'unfilterJSON',
description: 'Strips comment delimiters around Ajax JSON or Javascript responses.',
sugar_compatibility: 0,
sugar_notes: 'String#unfilterJSON does not exist in Sugar.'
},
{
name: 'capitalize',
description: 'Capitalizes the first letter of the string and downcases the others.',
sugar_compatibility: 3,
sugar_notes: 'String#capitalize exists in Sugar. Passing true as the first argument will additionally capitalize all words.',
conflict: false,
ref: 'String/capitalize'
},
{
name: 'startsWith',
description: 'Checks if the string starts with the passed substring.',
sugar_compatibility: 3,
sugar_notes: 'String#startsWith exists in Sugar and will not break. Sugar additionally accepts an argument for case sensitivity (default is true).',
conflict: false,
ref: 'String/startsWith'
},
{
name: 'endsWith',
description: 'Checks if the string ends with the passed substring.',
sugar_compatibility: 3,
sugar_notes: 'String#endsWith exists in Sugar and will not break. Sugar additionally accepts an argument for case sensitivity (default is true).',
conflict: false,
ref: 'String/endsWith'
},
{
name: 'escapeHTML',
description: 'Converts HTML special characters to their entity equivalents.',
sugar_compatibility: 2,
sugar_notes: 'String#escapeHTML exists in Sugar is identical.',
conflict: false,
ref: 'String/escapeHTML'
},
{
name: 'unescapeHTML',
description: 'Converts HTML entities to their normal form.',
sugar_compatibility: 2,
sugar_notes: 'String#unescapeHTML exists in Sugar is identical.',
ref: 'String/unescapeHTML'
}
]
},
{
namespace: 'Hash',
type: 'instance',
methods: [
{
name: 'each',
description: 'Iterates over each key/value entry in the hash.',
sugar_notes: 'Extended objects in Sugar function like hashes and have an identical each method.',
sugar_compatibility: 2,
conflict: function() {
var type = typeof arguments[1];
return [arguments.length > 1 && type != 'number', arguments[1]];
},
live_notes: 'Second argument to .each found. If you need to bind context, use Function#bind instead.',
original_code: "new Hash().each(function(){}, 'context')",
sugar_code: "Object.extended().each(function(){}.bind('context'))",
ref: 'Object/each'
},
{
name: 'get',
description: 'Retrieves the hash value for the given key.',
sugar_notes: 'Sugar extended objects do not have a "get" method. Simply access the property as you would a normal object literal.',
sugar_compatibility: 0,
original_code: "var h = new Hash({ foo: 'bar' }); h.get('foo')",
sugar_code: "var h = Object.extended({ foo: 'bar' }); h['foo']",
ref: 'Object/extended'
},
{
name: 'index',
description: 'Returns the first key in the hash whose value matches the passed value.',
sugar_compatibility: 0,
sugar_notes: 'Sugar extended objects do not have an "index" method. Object.keys can provide help to get this.',
original_code: "var key = new Hash({ foo: 'bar' }).index('bar')",
sugar_code: "var key; Object.extended({ foo: 'bar' }).keys(function(k){ if(this[k] == 'bar') key = k; })"
},
{
name: 'inspect',
description: 'Returns a debug-oriented string representation of the hash.',
sugar_compatibility: 0,
sugar_notes: 'Sugar extended objects do not have an "inspect" method. Consider using JSON.stringify() instead. The JSON global does not exist in all implementations but should be enough to get you through a debug session.',
original_code: "new Hash({ foo: 'bar' }).inspect()",
sugar_code: "JSON.stringify(Object.extended({ foo: 'bar' }))"
},
{
name: 'merge',
description: "Returns a new hash with the passed object's key/value pairs merged in.",
sugar_compatibility: 3,
sugar_notes: 'Sugar extended objects have a "merge" method, and have additional functionality such as specifying deep/shallow merges and resolution of conflicts. Unlike prototype they will modify the object. If you need to create a clone, use the "clone" method first.',
original_code: "new Hash({ foo: 'bar' }).merge({ moo: 'car' })",
sugar_code: "Object.extended({ foo: 'bar' }).clone().merge({ moo: 'car' })",
ref: 'Object/merge'
},
{
name: 'set',
description: 'Sets a value in the hash for the given key.',
sugar_compatibility: 0,
sugar_notes: 'Sugar extended objects do not have a "set" method. Simply set the property as you would a normal object literal.',
original_code: "var h = new Hash({ foo: 'bar' }); h.set('moo', 'car')",
sugar_code: "var h = Object.extended({ foo: 'bar' }); h['moo'] = 'car'",
ref: 'Object/extended'
},
{
name: 'toJSON',
description: 'Returns a JSON representation of the hash.',
sugar_compatibility: 0,
sugar_notes: 'Sugar extended objects do not have a "toJSON" method. JSON.stringify may work as an alternative, but it is not available in all browsers. If you absolutely require JSON support, consider adding in a separate library such as: https://github.com/douglascrockford/JSON-js',
original_code: "Object.toJSON(obj)",
sugar_code: "JSON.stringify(obj)"
},
{
name: 'toObject',
description: 'Returns a cloned, vanilla object with the same properties as the hash.',
sugar_compatibility: 0,
sugar_notes: 'Sugar extended objects do not have a "toObject" method, as they already behave like vanilla objects.',
ref: 'Object/extended'
},
{
name: 'toTemplateReplacements',
description: 'Returns a vanilla object, alias of Hash#toObject.',
sugar_compatibility: 0,
sugar_notes: 'Sugar extended objects do not have a "toTemplateReplacements" method. This method is not necessary as extended objects already behave like vanilla objects.',
ref: 'Object/extended'
},
{
name: 'unset',
description: 'Deletes the property in the hash for the given key.',
sugar_compatibility: 0,
sugar_notes: 'Sugar extended objects do not have an "unset" method. Simply delete the property as you would a normal object literal.',
original_code: "var h = new Hash({ foo: 'bar' }); h.unset('foo')",
sugar_code: "var h = Object.extended({ foo: 'bar' }); delete h.foo",
ref: 'Object/extended'
},
{
name: 'update',
description: 'Updates the hash in place by merging in the passed object.',
sugar_compatibility: 2,
sugar_notes: 'Hash#update exists in Sugar as "merge" on extended objects.',
original_code: "new Hash({ foo: 'bar' }).merge({ moo: 'car' })",
sugar_code: "Object.extended({ foo: 'bar' }).merge({ moo: 'car' })",
ref: 'Object/merge'
},
{
name: 'clone',
description: 'Returns a clone of the hash.',
sugar_compatibility: 2,
sugar_notes: 'Hash#clone exists on Sugar extended objects, and is identical.',
original_code: "new Hash({ foo: 'bar' }).clone()",
sugar_code: "Object.extended({ foo: 'bar' }).clone()",
conflict: false,
ref: 'Object/clone'
},
{
name: 'keys',
description: 'Returns an array of all keys defined on the hash.',
sugar_compatibility: 2,
sugar_notes: 'Hash#keys exists on Sugar extended objects, and is identical.',
original_code: "new Hash({ foo: 'bar' }).keys()",
sugar_code: "Object.extended({ foo: 'bar' }).keys()",
conflict: false,
ref: 'Object/keys'
},
{
name: 'values',
description: 'Returns an array of all values in the hash.',
sugar_compatibility: 2,
sugar_notes: 'Hash#values exists on Sugar extended objects, and is identical.',
original_code: "new Hash({ foo: 'bar' }).values()",
sugar_code: "Object.extended({ foo: 'bar' }).values()",
conflict: false,
ref: 'Object/values'
},
{
name: 'toQueryString',
description: 'Returns a URL-encoded string representing the contents of the hash.',
sugar_compatibility: 0,
sugar_notes: 'Hash#toQueryString does not exist in Sugar, and requires a workaround when using extended objects.',
original_code: "hash.toQueryString()",
sugar_code: "obj.keys().map(function(key){ return key + '=' + obj[key]; }).join('&').escapeURL();"
}
]
},
{
namespace: 'Object',
type: 'class',
methods: [
{
name: 'clone',
description: 'Returns a shallow copy of the object.',
sugar_compatibility: 3,
sugar_notes: 'Object.clone exists in Sugar and additionally can create deep clones as well.',
conflict: false,
ref: 'Object/clone'
},
{
name: 'extend',
description: 'Copies all properties from the source to the destination object.',
sugar_compatibility: 3,
sugar_notes: 'Object.extend exists in Sugar as Object.merge. It can optionally do deep merges as well as intelligent conflict resolution.',
original_code: "Object.extend({ a: 1 }, { b: 2 })",
sugar_code: "Object.merge({ a: 1 }, { b: 2 })",
ref: 'Object/merge'
},
{
name: 'inspect',
description: 'Returns a debug-oriented representation of the object.',
sugar_compatibility: 0,
sugar_notes: 'Object.inspect does not exist in Sugar. Consider using JSON.stringify(object) instead. The JSON global does not exist in all implementations but should be enough to get you through a debug session.',
original_code: "Object.inspect([1,2,3])",
sugar_code: "JSON.stringify([1,2,3])"
},
{
name: 'isHash',
description: 'Returns true if the object is a hash.',
sugar_compatibility: 2,
sugar_notes: 'Object.isHash does not exist in Sugar. Use Object.isObject instead.',
original_code: "Object.isHash({ a: 1 })",
sugar_code: "Object.isObject({ a: 1 })",
ref: 'Object/isObject'
},
{
name: 'isUndefined',
description: 'Returns true if the object is undefined.',
sugar_compatibility: 0,
sugar_notes: 'Object.isUndefined does not exist in Sugar. Use straight Javascript instead.',
original_code: "Object.isUndefined(obj)",
sugar_code: "obj === undefined"
},
{
name: 'toJSON',
description: 'Returns a JSON representation of the object.',
sugar_compatibility: 0,
sugar_notes: 'Object.toJSON does not exist in Sugar. JSON.stringify may work as an alternative, but it is not available in all browsers. If you absolutely require JSON support, consider adding in a separate library such as: https://github.com/douglascrockford/JSON-js',
original_code: "Object.toJSON(obj)",
sugar_code: "JSON.stringify(obj)"
},
{
name: 'isArray',
description: 'Returns true if the object is an array.',
sugar_compatibility: 2,
sugar_notes: 'Object.isArray and is an alias of browser native Array.isArray, which is shimmed if it does not exist.',
conflict: false,
ref: 'Object/isArray'
},
{
name: 'isDate',
description: 'Returns true if the object is a date.',
sugar_compatibility: 2,
sugar_notes: 'Object.isDate exists in Sugar and is identical.',
conflict: false,
ref: 'Object/isDate'
},
{
name: 'isFunction',
description: 'Returns true if the object is a function.',
sugar_compatibility: 2,
sugar_notes: 'Object.isFunction exists in Sugar and is identical.',
conflict: false,
ref: 'Object/isFunction'
},
{
name: 'isNumber',
description: 'Returns true if the object is a number.',
sugar_compatibility: 2,
sugar_notes: 'Object.isNumber exists in Sugar and is identical.',
conflict: false,
ref: 'Object/isNumber'
},
{
name: 'isString',
description: 'Returns true if the object is a string.',
sugar_compatibility: 2,
sugar_notes: 'Object.isString exists in Sugar and is identical.',
conflict: false,
ref: 'Object/isString'
},
{
name: 'keys',
description: 'Returns an array of the keys in the object.',
sugar_compatibility: 2,
sugar_notes: 'Object.keys is a browser native method, which Sugar provides a shim for if it does not exist.',
conflict: false,
ref: 'Object/keys'
},
{
name: 'values',
description: 'Returns an array of the values in the object.',
sugar_compatibility: 2,
sugar_notes: 'Object.values exists in Sugar and is identical.',
conflict: false,
ref: 'Object/values'
},
{
name: 'isElement',
description: 'Returns true if the object is a DOM element.',
sugar_compatibility: 0,
sugar_notes: "Sugar, which has no direct association with the DOM, does not provide this method. However, this functionality can be easily replicated (taken from Prototype's own implementation).",
original_code: 'Object.isElement(obj)',
sugar_code: 'Object.extend({ isElement: function(obj){ return !!(obj && obj.nodeType == 1); }}, false, false);'
},
{
name: 'toHTML',
description: 'Returns an HTML representation of the object.',
sugar_compatibility: 0,
sugar_notes: "Object.toHTML does not exist in Sugar. You'll have to define this one yourself!"
},
{
name: 'toQueryString',
description: 'Returns a URL-encoded string representing the contents of the object.',
sugar_compatibility: 0,
sugar_notes: 'Object.toQueryString does not exist in Sugar, and requires a workaround.',
original_code: "Object.toQueryString(obj)",
sugar_code: "Object.keys(obj).map(function(key){ return key + '=' + obj[key]; }).join('&').escapeURL();"
}
]
},
{
namespace: 'Array',
type: 'class',
methods: [
{
name: 'from',
description: 'Creates an array from an array-like collection.',
sugar_compatibility: 2,
sugar_notes: 'Array.from exists in Sugar as Array.create. Be aware, however, that when a Javascript primitive is passed, it will simply be added to the array. If, for example, you need a string to be split into the array, then use the standard String#split instead. The most common use of this method, converting an arguments object into an actual array, will work, however.',
original_code: "Array.from(arguments)",
sugar_code: "Array.create(arguments)",
ref: 'Array.create'
}
]
},
{
namespace: 'Array',
type: 'instance',
methods: [
{
name: 'collect',
description: 'Returns the result of applying an iterator to the array.',
sugar_compatibility: 3,
sugar_notes: 'Enumerable#collect exists Sugar as Array#map, and can additionally pass a shortcut string for a function that returns a property of the same name.',
original_code: "[1,2,3].collect(function(n){ return n * 2; })",
sugar_code: "[1,2,3].map(function(n){ return n * 2; })",
ref: 'Array/map'
},
{
name: 'detect',
description: 'Returns the first element for which the iterator returns a truthy value.',
sugar_compatibility: 3,
sugar_notes: 'Enumerable#detect exists in Sugar as Array#find. Some semantic differences exist including the ability to pass a starting index in the place of in-line context binding.',
original_code: "[1,2,3].detect(function(n){ return n > 1; })",
sugar_code: "[1,2,3].find(function(n){ return n > 1; })",
ref: 'Array/find'
},
{
name: 'each',
description: 'Iterates over the key/value pairs in the hash.',
sugar_compatibility: 3,
sugar_notes: 'Array#each exists in Sugar and can additionally pass a starting index and loop from the beginning of the array. If context needs to be bound, use Function#bind instead.',
conflict: function() {
var type = typeof arguments[1];
return [arguments.length > 1 && type != 'number', arguments[1]];
},
live_notes: 'Second argument to .each should be a number but instead was {1}. If you need to bind context, use Function#bind instead.',
original_code: "['a','b','c'].each(function(){}, 'context')",
sugar_code: "['a','b','c'].each(function(){}.bind('context'))",
ref: 'Array/each'
},
{
name: 'eachSlice',
description: 'Groups array elements into chunks of a given size and iterates over them.',
sugar_compatibility: 2,
sugar_notes: 'Enumerable#eachSlice exists in Sugar as Array#inGroupsOf instead.',
original_code: "[1,2,3,4].eachSlice(2, function(){})",
sugar_code: "[1,2,3,4].inGroupsOf(2).each(function(){})",
ref: 'Array/inGroupsOf'
},
{
name: 'entries',
description: 'alias of enumerable#toarray.',
sugar_compatibility: 2,
sugar_notes: 'Enumerable#entries is not necessary in Sugar, but its behavior of effectively cloning the array can be achieved with Array#clone.',
original_code: "[1,2,3].entries()",
sugar_code: "[1,2,3].clone()",
ref: 'Array/clone'
},
{
name: 'find',
description: 'Returns the first element for which the iterator returns a truthy value.',
sugar_notes: 'Array#find also exists in Sugar. Some semantic differences exist including the ability to pass a starting index in the place of in-line context binding.',
sugar_compatibility: 3,
conflict: function() {
var type = typeof arguments[1];
return [arguments.length > 1 && type != 'number', arguments[1]];
},
live_notes: 'Second argument to Array#find should be a number but instead was {1}. If you need to bind context, use Function#bind instead.',
original_code: "['a','b','c'].find(function(){}, 'context')",
sugar_code: "['a','b','c'].find(function(){}.bind('context'))",
ref: 'Function/bind'
},
{
name: 'findAll',
description: 'Returns all elements for which the iterator returns a truthy value.',
sugar_notes: 'Array#findAll also exists in Sugar. Some semantic differences exist including the ability to pass a starting index in the place of in-line context binding.',
sugar_compatibility: 3,
conflict: function() {
var type = typeof arguments[1];
return [arguments.length > 1 && type != 'number', arguments[1]];
},
live_notes: 'Second argument to Array#findAll should be a number but instead was {1}. If you need to bind context, use Function#bind instead.',
original_code: "['a','b','c'].findAll(function(){}, 'context')",
sugar_code: "['a','b','c'].findAll(function(){}.bind('context'))",
ref: 'Function/bind'
},
{
name: 'grep',
description: 'Returns all elements for which the passed regex matches.',
sugar_compatibility: 3,
sugar_notes: 'Enumerable#grep exists in Sugar as Array#findAll with slightly different semantics.',
original_code: "['a','b','c'].grep(/[ab]/)",
sugar_code: "['a','b','c'].findAll(/[ab]/)",
ref: 'Array/findAll'
},
{
name: 'include',
description: 'Returns true if the array contains the given element.',
sugar_compatibility: 3,
sugar_notes: 'Enumerable#include exists in Sugar as Array#has. Array#include in Sugar instead the passed argument to the array without modifying it. Array#include is a reciprocal of Array#exclude, and a non-destructive version of Array#add. Use Array#has instead for equivalent functionality.',
conflict: function(f) {
return typeof f !== 'object' && arguments.length == 1;
},
original_code: "[1,2,3].include(1)",
sugar_code: "[1,2,3].has(1)",
ref: 'Array/has'
},
{
name: 'inject',
description: 'Incrementally builds a return value by successively iterating over the array.',
sugar_compatibility: 2,
sugar_notes: 'Enumerable#inject in Javascript as native Array#reduce. Sugar provides a shim for this method when it does not exist.',
original_code: '[1,2,3,4].inject(100, function(a, b){ return a + b; });',
sugar_code: '[1,2,3,4].reduce(function(a, b){ return a + b; }, 100);'
},
{
name: 'invoke',
description: 'Invokes the same method for each element in the array.',
sugar_compatibility: 2,
sugar_notes: 'Sugar allows a string shortcut to be passed to Array#map, which achieves the same effect as Array#invoke.',
original_code: "['hello','world'].invoke('toUpperCase')",
sugar_code: "['hello','world'].map('toUpperCase')",
ref: 'Array/map'
},
{
name: 'max',
description: 'Returns the element of the array with the highest value.',
sugar_compatibility: 2,
sugar_notes: 'Array#max exists in Sugar but returns an array, as more than one maximum value may exist. Sugar also returns the actual array element instead of the return value of the iterator. Sugar also does not allow a context parameter, use Function#bind instead.',
live_notes: 'Use caution when using Enumerable#max: (1) Sugar will return an array of maximum values (as there can be more than one), where Prototype only returns the first value. (2) When using iterators, Prototype will return the value compared, where Sugar will return the actual array element itself. (3) Finally, Sugar does not allow a context to be passed. Use Function#bind instead to bind context.',
original_code: "[{ a: 5 },{ a: 10 }].max(function(el){ return el['a']; }, 'context')",
sugar_code: "[{ a: 5 },{ a: 10 }].max(function(el){ return el['a']; }.bind('context')).first().a",
ref: 'Array/max'
},
{
name: 'member',
description: 'Returns true if the array contains the given element. Alias of Enumerable#include.',
sugar_compatibility: 2,
sugar_notes: 'Enumerable#member exists in Sugar as Array#has.',
original_code: "[1,2,3].member(1)",
sugar_code: "[1,2,3].has(1)",
ref: 'Array/has'
},
{
name: 'min',
description: 'Returns the element of the array with the lowest value.',
sugar_compatibility: 2,
sugar_notes: 'Array#min exists in Sugar but returns an array, as more than one minimum value may exist. Sugar also returns the actual array element instead of the return value of the iterator. Sugar also does not allow a context parameter, use Function#bind instead.',
live_notes: 'Use caution when using Enumerable#min: (1) Sugar will return an array of minimum values (as there can be more than one), where Prototype only returns the first value. (2) When using iterators, Prototype will return the value compared, where Sugar will return the actual array element itself. (3) Finally, Sugar does not allow a context to be passed.',
original_code: "[{ a: 5 },{ a: 10 }].min(function(el){ return el['a']; }, 'context')",
sugar_code: "[{ a: 5 },{ a: 10 }].min(function(el){ return el['a']; }.bind('context')).first().a",
ref: 'Array/min'
},
{
name: 'partition',
description: 'Partitions the array into two groups, one for which the iterator passed returns true, and one for which the iterator returns false.',
sugar_compatibility: 3,
sugar_notes: "Enumerable#partition does not exist in Sugar. Array#groupBy however has similar functionality, and may be a suitable alternative. It will create a hash with keys based on the return values of the iterator, with each grouping as the value. Instead of accessing the split array, you can access the hash by these keys. This method has the added advantage that it can also split into more than two groups.",
original_code: "[1,2,3,4,5,6].partition(function(n){ return n % 2 === 0; })",
sugar_code: "[1,2,3,4,5,6].group(function(n){ return n % 2 === 0 ? 'even' : 'odd'; })",
ref: 'Array/groupBy'
},
{
name: 'pluck',
description: 'Returns a mapped array of the same property of each element in the array.',
sugar_compatibility: 2,
sugar_notes: 'Sugar allows a string shortcut to Array#map, making it effectively identical to Enumerable#pluck.',
original_code: "['hello','world'].pluck('length')",
sugar_code: "['hello','world'].map('length')",
ref: 'Array/map'
},
{
name: 'reject',
description: 'Returns all elements for which the iterator returns a falsy value.',
sugar_compatibility: 3,
sugar_notes: "Enumerable#reject does not exist in Sugar. Its equivalent is Array#exclude. This is a non-destructive way to remove elements from an array. If you want a destructive version, use Array#remove instead. Also note these methods' reciprocals: Array#include and Array#add.",
original_code: "[1,2,3].reject(function(n){ n < 3; })",
sugar_code: "[1,2,3].exclude(function(n){ n < 3; })",
ref: 'Array/exclude'
},
{
name: 'select',
description: 'Returns all elements for which the iterator returns a truthy value. Alias of Enumerable#findAll.',
sugar_compatibility: 3,
sugar_notes: 'Enumerable#select exists in Sugar as Array#findAll.',
original_code: "[1,2,3].select(function(n){ n < 3; })",
sugar_code: "[1,2,3].findAll(function(n){ n < 3; })",
ref: 'Array/findAll'
},
{
name: 'sortBy',
description: 'Returns an array sorted on the value returned by the iterator.',
sugar_compatibility: 3,
sugar_notes: 'Array#sortBy in Sugar additionally allows a flag for descending order and also has a mechanism for intelligent alphanumeric sorting of string properties. For binding of context, use Function#bind instead.',
conflict: function(f, scope) {
var type = typeof arguments[1];
return [arguments.length > 1 && type != 'boolean', arguments[1]];
},
live_notes: 'Second argument to .sortBy should be a boolean but instead was {1}. If you need to bind context, use Function#bind instead.',
original_code: "[{ a: 5 },{ a: 10 }].sortBy(function(el){ return el['a']; })",
sugar_code: "[{ a: 5 },{ a: 10 }].sortBy(function(el){ return el['a']; }.bind('context'))",
ref: 'Function/bind'
},
{
name: 'size',
description: 'Returns the length of the array.',
sugar_compatibility: 2,
sugar_notes: 'Enumerable#size does not exist in Sugar. Just use array.length!',
original_code: "[1,2,3].size()",
sugar_code: "[1,2,3].length"
},
{
name: 'toArray',
description: 'Returns a clone of the array.',
sugar_compatibility: 2,
sugar_notes: 'Enumerable#toArray does not exist in Sugar. Use Array#clone instead.',
original_code: "[1,2,3].toArray()",
sugar_code: "[1,2,3].clone()",
ref: 'Array/clone'
},
{
name: 'zip',
description: '"zips" together multiple arrays into a single multi-dimensional array.',
sugar_compatibility: 2,
sugar_notes: 'Enumerable#zip exists in Sugar and is identical.',
original_code: "firstNames.zip(lastNames)",
sugar_code: "firstNames.zip(lastNames)",
ref: 'Array/zip'
},
{
name: 'compact',
description: 'Returns a copy of the array with all undefined and null values removed.',
sugar_compatibility: 3,
sugar_notes: 'Array#compact exists and is nearly identical except that it will also remove any values which are NaN from the array as well. It additionally has a flag to remove all falsy values.',
conflict: function() {
for(var i = 0; i < this.length; i++){
if(isNaN(this[i])) return true;
}
return false;
},
live_notes: 'Caution: Array#compact was called on an array that contains NaN values. Sugar will remove these from the array while Prototype leaves them alone.',
ref: 'Array/compact'
},
{
name: 'clear',
description: 'Removes all elements from the array.',
sugar_compatibility: 0,
sugar_notes: 'Array#clear does not exist in Sugar. Use array.length = 0 or simply set array = [] instead.',
original_code: "f.clear()",
sugar_code: "f = []"
},
{
name: 'inspect',
description: 'Returns a debug-oriented string representing the array.',
sugar_compatibility: 0,
sugar_notes: 'Array#inspect does not exist in Sugar. Consider using JSON.stringify(array) instead. The JSON global does not exist in all implementations but should be enough to get you through a debug session.',
original_code: "[1,2,3].inspect()",
sugar_code: "JSON.stringify([1,2,3])"
},
{
name: 'reverse',
description: 'Reverses the arrays contents.',
sugar_compatibility: 2,
conflict: function(inline) {
return inline === false;
},
sugar_notes: 'Array#reverse exists in native Javascript, but is destructive. For a non-destructive version use Array#clone first.',
original_code: "array.reverse(false)",
sugar_code: "array.clone().reverse()",
ref: 'Array.clone'
},
{
name: 'uniq',
description: 'Returns a new array without duplicates.',
sugar_compatibility: 3,
sugar_notes: 'Array#uniq exists in Sugar as Array#unique and can also operate on arrays of objects. Additionally it accepts a mapping function to indicate the field to uniquify on.',
original_code: "[1,1,1].uniq()",
sugar_code: "[1,1,1].unique()",
ref: 'Array/unique'
},
{
name: 'without',
description: 'Creates a new array that does not contain the specified values.',
sugar_compatibility: 3,
sugar_notes: 'Array#without exists in Sugar as Array#exclude.',
original_code: "[1,2,3].without(3)",
sugar_code: "[1,2,3].exclude(3)",
ref: 'Array/exclude'
},
{
name: 'indexOf',
description: 'Returns the index of the first occurence of the item in the array.',
sugar_compatibility: 2,
sugar_notes: 'Array#indexOf exists natively in modern browsing engines. Sugar provides this method when it is not supported.',
conflict: false,
ref: 'Array/indexOf'
},
{
name: 'lastIndexOf',
description: 'Returns the index of the last occurence of the item in the array.',
sugar_compatibility: 2,
sugar_notes: 'Array#lastIndexOf exists natively in modern browsing engines. Sugar provides this method when it is not supported.',
conflict: false,
ref: 'Array/lastIndexOf'
},