fancy 0.8.0 → 0.9.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.
Files changed (111) hide show
  1. data/LICENSE +1 -1
  2. data/README.md +5 -4
  3. data/bin/fspec +19 -1
  4. data/bin/ifancy +139 -35
  5. data/boot/README +2 -9
  6. data/boot/extconf.rb +0 -1
  7. data/boot/fancy_ext/module.rb +5 -15
  8. data/boot/fancy_ext/thread.rb +22 -9
  9. data/boot/rbx-compiler/README +0 -4
  10. data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
  11. data/boot/rbx-compiler/parser/parser.y +1 -0
  12. data/doc/api/fancy.css +1 -6
  13. data/doc/api/fancy.jsonp +1 -1
  14. data/doc/api/fdoc.js +2 -4
  15. data/doc/api/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  16. data/doc/api/images/ui-bg_flat_0_eeeeee_40x100.png +0 -0
  17. data/doc/api/images/ui-bg_flat_55_ffffff_40x100.png +0 -0
  18. data/doc/api/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  19. data/doc/api/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  20. data/doc/api/images/ui-bg_highlight-soft_100_f6f6f6_1x100.png +0 -0
  21. data/doc/api/images/ui-bg_highlight-soft_25_0073ea_1x100.png +0 -0
  22. data/doc/api/images/ui-bg_highlight-soft_50_dddddd_1x100.png +0 -0
  23. data/doc/api/images/ui-icons_0073ea_256x240.png +0 -0
  24. data/doc/api/images/ui-icons_454545_256x240.png +0 -0
  25. data/doc/api/images/ui-icons_666666_256x240.png +0 -0
  26. data/doc/api/images/ui-icons_ff0084_256x240.png +0 -0
  27. data/doc/api/images/ui-icons_ffffff_256x240.png +0 -0
  28. data/doc/api/index.html +5 -4
  29. data/doc/api/jquery-1.8.2.min.js +2 -0
  30. data/doc/api/jquery-ui-1.9.0.custom.min.css +5 -0
  31. data/doc/api/jquery-ui-1.9.0.custom.min.js +6 -0
  32. data/doc/features.md +8 -3
  33. data/examples/argv.fy +1 -1
  34. data/examples/closures.fy +1 -4
  35. data/examples/echo.fy +2 -2
  36. data/examples/guess_number.fy +18 -0
  37. data/examples/nested_classes.fy +3 -15
  38. data/lib/argv.fy +23 -18
  39. data/lib/array.fy +18 -37
  40. data/lib/block.fy +125 -0
  41. data/lib/boot.fy +1 -0
  42. data/lib/compiler/ast/block.fy +1 -1
  43. data/lib/compiler/ast/identifier.fy +1 -1
  44. data/lib/compiler/ast/message_send.fy +0 -13
  45. data/lib/compiler/ast/method_def.fy +1 -1
  46. data/lib/compiler/ast/singleton_method_def.fy +1 -0
  47. data/lib/compiler/ast/tuple_literal.fy +1 -1
  48. data/lib/compiler/command.fy +1 -1
  49. data/lib/compiler/compiler.fy +8 -6
  50. data/lib/contracts.fy +1 -1
  51. data/lib/directory.fy +1 -1
  52. data/lib/dynamic_slot_object.fy +1 -1
  53. data/lib/enumerable.fy +316 -25
  54. data/lib/enumerator.fy +11 -8
  55. data/lib/eval.fy +0 -3
  56. data/lib/fancy_spec.fy +27 -0
  57. data/lib/fdoc.fy +8 -8
  58. data/lib/file.fy +25 -1
  59. data/lib/hash.fy +91 -0
  60. data/lib/html.fy +40 -11
  61. data/lib/integer.fy +4 -0
  62. data/lib/main.fy +18 -11
  63. data/lib/object.fy +33 -7
  64. data/lib/option_parser.fy +20 -1
  65. data/lib/package/dependency.fy +8 -0
  66. data/lib/package/dependency_installer.fy +3 -6
  67. data/lib/package/handler.fy +4 -4
  68. data/lib/package/installer.fy +2 -5
  69. data/lib/package/list.fy +3 -4
  70. data/lib/parser/ext/parser.y +1 -0
  71. data/lib/proxies.fy +0 -2
  72. data/lib/queue.fy +7 -0
  73. data/lib/rbx.fy +1 -0
  74. data/lib/rbx/actor.fy +3 -1
  75. data/lib/rbx/alpha.fy +24 -0
  76. data/lib/rbx/array.fy +3 -1
  77. data/lib/rbx/class.fy +5 -8
  78. data/lib/rbx/date_time.fy +14 -0
  79. data/lib/rbx/file.fy +6 -0
  80. data/lib/rbx/hash.fy +42 -0
  81. data/lib/rbx/thread.fy +5 -7
  82. data/lib/string.fy +56 -4
  83. data/lib/symbol.fy +29 -1
  84. data/lib/time.fy +17 -0
  85. data/lib/vars.fy +4 -3
  86. data/lib/version.fy +1 -1
  87. data/ruby_lib/interactive/hilight.rb +125 -0
  88. data/tests/array.fy +19 -7
  89. data/tests/block.fy +103 -4
  90. data/tests/class.fy +31 -26
  91. data/tests/control_flow.fy +0 -1
  92. data/tests/dynamic_key_hash.fy +22 -1
  93. data/tests/enumerable.fy +239 -7
  94. data/tests/enumerator.fy +7 -0
  95. data/tests/file.fy +16 -0
  96. data/tests/future.fy +1 -11
  97. data/tests/future_proxy.fy +8 -0
  98. data/tests/hash.fy +132 -9
  99. data/tests/html.fy +30 -13
  100. data/tests/integer.fy +3 -0
  101. data/tests/method.fy +6 -11
  102. data/tests/object.fy +12 -5
  103. data/tests/option_parser.fy +12 -3
  104. data/tests/string.fy +69 -1
  105. data/tests/symbol.fy +24 -0
  106. metadata +42 -12
  107. data/boot/rsexp_pretty_printer.rb +0 -76
  108. data/doc/api/jquery-ui.min.js +0 -401
  109. data/doc/api/jquery.tools.min.js +0 -192
  110. data/doc/api/themeswitchertool.js +0 -250
  111. data/examples/future_sends.fy +0 -15
data/lib/boot.fy CHANGED
@@ -42,6 +42,7 @@ require: "future"
42
42
  require: "struct"
43
43
  require: "message_sink"
44
44
  require: "kvo"
45
+ require: "time"
45
46
 
46
47
  # version holds fancy's version number
47
48
  require: "version"
@@ -14,7 +14,7 @@ class Fancy AST {
14
14
  @arguments prelude=(nil)
15
15
  }
16
16
 
17
- if: (@args.total_args > 1) then: {
17
+ if: (@args total_args > 1) then: {
18
18
  @arguments prelude=('multi)
19
19
  }
20
20
 
@@ -148,7 +148,7 @@ class Fancy AST {
148
148
  thread bytecode: g
149
149
  g send('current, 0, false)
150
150
  @varname bytecode: g
151
- g send(':[], 1, false)
151
+ g send('dynamic_var:, 1, false)
152
152
  }
153
153
  }
154
154
  }
@@ -42,19 +42,6 @@ class Fancy AST {
42
42
  return nil
43
43
  }
44
44
 
45
- # check if we might have a block invocation using block(x,y) syntax.
46
- if: ruby_send? then: {
47
- if: (@receiver is_a?: Self) then: {
48
- if: (g state() scope() search_local(@name name)) then: {
49
- @name bytecode: g
50
- args = ArrayLiteral new: @line array: (@args args)
51
- args bytecode: g
52
- g send('call:, 1, false)
53
- return nil
54
- }
55
- }
56
- }
57
-
58
45
  @receiver bytecode: g
59
46
  @args bytecode: g
60
47
  pos(g)
@@ -83,7 +83,7 @@ class Fancy AST {
83
83
 
84
84
  class MethodArgs : Rubinius AST FormalArguments {
85
85
  def initialize: @line args: @array ([]) {
86
- initialize(@line, @array map() |a| { a to_sym() }, nil, nil)
86
+ initialize(@line, @array map: @{ to_sym }, nil, nil)
87
87
  }
88
88
  }
89
89
  }
@@ -13,6 +13,7 @@ class Fancy AST {
13
13
 
14
14
  class SingletonMethodDefScope : Rubinius AST DefineSingletonScope {
15
15
  def initialize: @line name: @name args: @arguments body: @body {
16
+ { @body = ExpressionList new: @line } unless: @body
16
17
  if: (@body empty?) then: {
17
18
  @body unshift_expression: $ NilLiteral new: @line
18
19
  }
@@ -17,7 +17,7 @@ class Fancy AST {
17
17
 
18
18
  ms bytecode: g
19
19
 
20
- @elements each_with_index() |e i| {
20
+ @elements each_with_index: |e i| {
21
21
  g dup()
22
22
  ary = [FixnumLiteral new: @line value: i, e]
23
23
 
@@ -33,7 +33,7 @@ class Fancy {
33
33
  size = argv size()
34
34
  files = "file"
35
35
  { files = files + "s" } if: (size > 1)
36
- "Compiled " ++ (argv size()) ++ " " ++ files ++ "." . println
36
+ "Compiled " ++ (argv size) ++ " " ++ files ++ "." . println
37
37
  }
38
38
  }
39
39
 
@@ -3,12 +3,12 @@ class Fancy {
3
3
  read_write_slots: [ 'parser, 'generator, 'packager, 'writer ]
4
4
 
5
5
  def self compiled_name: file {
6
- """
7
- Returns a the compiled filename for @file
6
+ """
7
+ Returns a the compiled filename for @file
8
8
 
9
- If file ends with .fy extention the will return with .fyc extension
10
- Otherwise it will append .compiled.fyc to the filename.
11
- """
9
+ If file ends with .fy extention the will return with .fyc extension
10
+ Otherwise it will append .compiled.fyc to the filename.
11
+ """
12
12
 
13
13
  if: (file suffix?(".fy")) then: {
14
14
  file + "c"
@@ -18,7 +18,9 @@ class Fancy {
18
18
  }
19
19
 
20
20
  def self from: first_stage to: last_stage {
21
- "Creates a new compiler from @first_stage to @last_stage"
21
+ """
22
+ Creates a new compiler from @first_stage to @last_stage.
23
+ """
22
24
 
23
25
  new(first_stage, last_stage)
24
26
  }
data/lib/contracts.fy CHANGED
@@ -57,7 +57,7 @@ class Class {
57
57
  """
58
58
 
59
59
  pim = Set new: $ provided_interface_methods map: @{ message_name to_s } + instance_methods
60
- methods all?: |m| { pim includes?: (m message_name to_s) }
60
+ methods to_a all?: |m| { pim includes?: (m message_name to_s) }
61
61
  }
62
62
 
63
63
  def missing_methods_for_interface: methods {
data/lib/directory.fy CHANGED
@@ -12,6 +12,6 @@ class Directory {
12
12
  Indicates, if a Directory exists with a given pathname.
13
13
  """
14
14
 
15
- (File exists?: dirname) and: (File directory?: dirname)
15
+ (File exists?: dirname) && { File directory?: dirname }
16
16
  }
17
17
  }
@@ -65,7 +65,7 @@ class DynamicKeyHash : Fancy BasicObject {
65
65
  val = p[idx]
66
66
  if: @deep then: {
67
67
  match val {
68
- case Block -> val = val to_hash
68
+ case Block -> val = val to_hash_deep
69
69
  }
70
70
  }
71
71
  @hash[slotname to_sym]: val
data/lib/enumerable.fy CHANGED
@@ -42,6 +42,7 @@ class Fancy {
42
42
  """
43
43
  @return The first element in the @Fancy::Enumerable@.
44
44
  """
45
+
45
46
  at: 0
46
47
  }
47
48
 
@@ -49,6 +50,7 @@ class Fancy {
49
50
  """
50
51
  @return The second element in the @Fancy::Enumerable@.
51
52
  """
53
+
52
54
  at: 1
53
55
  }
54
56
 
@@ -56,6 +58,7 @@ class Fancy {
56
58
  """
57
59
  @return The third element in the @Fancy::Enumerable@.
58
60
  """
61
+
59
62
  at: 2
60
63
  }
61
64
 
@@ -63,6 +66,7 @@ class Fancy {
63
66
  """
64
67
  @return The fourth element in the @Fancy::Enumerable@.
65
68
  """
69
+
66
70
  at: 3
67
71
  }
68
72
 
@@ -136,6 +140,15 @@ class Fancy {
136
140
  """
137
141
  Similar to @each:@ but calls an additional @Block@ between
138
142
  calling the first @Block@ for each element in self.
143
+
144
+ Example:
145
+ result = \"\"
146
+ [1,2,3,4,5] each: |i| {
147
+ result << i
148
+ } in_between: {
149
+ result << \"-\"
150
+ }
151
+ result # => \"1-2-3-4-5\"
139
152
  """
140
153
 
141
154
  between = { between = between_block }
@@ -152,6 +165,7 @@ class Fancy {
152
165
 
153
166
  Joins a collection with a @String@ between each element, returning a new @String@.
154
167
 
168
+ Example:
155
169
  \"hello, world\" join: \"-\" # => \"h-e-l-l-o-,- -w-o-r-l-d\"
156
170
  """
157
171
 
@@ -172,7 +186,7 @@ class Fancy {
172
186
  Works similar to @Fancy::Enumerable#inject:into:@ but uses first element as value injected.
173
187
 
174
188
  Example:
175
- (1,2,3) reduce_by: '+ # => same as: (2,3) inject: 1 into: '+
189
+ (1,2,3) join_by: '+ # => same as: (2,3) inject: 1 into: '+
176
190
  """
177
191
 
178
192
  first, *rest = self
@@ -232,6 +246,79 @@ class Fancy {
232
246
  }
233
247
  }
234
248
 
249
+ def find: item do: block {
250
+ """
251
+ @item Item to find in @self.
252
+ @block @Block@ to be called with @item if found in @self.
253
+
254
+ Calls @block with @item, if found.
255
+ If @item is not in @self, @block is not called.
256
+ """
257
+
258
+ if: (find: item) then: block
259
+ }
260
+
261
+ def find_with_index: item do: block {
262
+ """
263
+ @item Item to find in @self.
264
+ @block @Block@ to be called with @item and its index in @self.
265
+
266
+ Calls @block with @item and its index in @self, if found.
267
+ If @item is not in @self, @block is not called.
268
+ """
269
+
270
+ for_every: item with_index_do: |x i| {
271
+ return block call: [x, i]
272
+ }
273
+ nil
274
+ }
275
+
276
+ def for_every: item with_index_do: block {
277
+ """
278
+ @item Item to call @block with.
279
+ @block @Block@ to be called with @item and each of its indexes in @self.
280
+
281
+ Calls @block with @item and each of its indexes in @self, if @item is in @self.
282
+ """
283
+
284
+ each_with_index: |x i| {
285
+ if: (item == x) then: {
286
+ block call: [x, i]
287
+ }
288
+ }
289
+ }
290
+
291
+ def for_every: item do: block {
292
+ """
293
+ @item Item to call @block with.
294
+ @block @Block@ to be called with @item for every occurance of @item in @self.
295
+
296
+ Calls @block with @item for each occurance of @item in @self.
297
+
298
+ Example:
299
+ count = 0
300
+ [1,2,3,2,1] for_every: 1 do: { count = count + 1 }
301
+ # count is now 2
302
+ """
303
+
304
+ each: |x| {
305
+ if: (item == x) then: { block call: [x] }
306
+ }
307
+ }
308
+
309
+ def last_index_of: item {
310
+ """
311
+ @item Item for which the last index in @self should be found.
312
+ @return Last index of @item in @self, or @nil (if not in @self).
313
+
314
+ Returns the last index for @item in @self, or @nil, if @item is not in @self.
315
+ """
316
+
317
+ last_idx = nil
318
+ for_every: item with_index_do: |_ i| { last_idx = i }
319
+ last_idx
320
+ }
321
+
235
322
  def find_by: block {
236
323
  """
237
324
  Similar to @find:@ but takes a block that is called for each element to find it.
@@ -292,6 +379,14 @@ class Fancy {
292
379
  }
293
380
  }
294
381
 
382
+ def flat_map: block {
383
+ """
384
+ Similar to @Fancy::Enumerable#map:@ but returns the result @Array@ flattened.
385
+ """
386
+
387
+ map: block . tap: @{ flatten! }
388
+ }
389
+
295
390
  def select: condition {
296
391
  """
297
392
  @condition A @Block@ that is used as a filter on all elements in @self.
@@ -307,6 +402,24 @@ class Fancy {
307
402
  coll
308
403
  }
309
404
 
405
+ def select_with_index: condition {
406
+ """
407
+ @condition A @Block@ that is used as a filter on all elements in @self.
408
+ @return An @Array@ containing all elements and their indices in @self that yield @true when called with @condition.
409
+
410
+ Returns a new @Array@ with all elements and their indices that meet the given
411
+ condition block. @condition is called with each element and its index in @self.
412
+ """
413
+
414
+ tmp = []
415
+ each_with_index: |obj idx| {
416
+ if: (condition call: [obj, idx]) then: {
417
+ tmp << [obj, idx]
418
+ }
419
+ }
420
+ tmp
421
+ }
422
+
310
423
  def reject: condition {
311
424
  """
312
425
  Similar to @select:@ but inverse.
@@ -354,14 +467,14 @@ class Fancy {
354
467
  """
355
468
 
356
469
  coll = []
357
- drop = nil
358
- first_check = true
470
+ drop? = false
471
+ first_check? = true
359
472
  each: |x| {
360
- if: (drop or: first_check) then: {
361
- drop = condition call: [x]
362
- first_check = nil
473
+ if: (drop? or: first_check?) then: {
474
+ drop? = condition call: [x]
475
+ first_check? = false
363
476
  # check, if we actually have to insert this one:
364
- unless: drop do: {
477
+ unless: drop? do: {
365
478
  coll << x
366
479
  }
367
480
  } else: {
@@ -405,6 +518,18 @@ class Fancy {
405
518
 
406
519
  alias_method: 'skip: for: 'drop:
407
520
 
521
+ def drop_last: amount (1) {
522
+ """
523
+ @amount Amount of elements to drop from the end.
524
+ @return New @Array@ without last @amount elements.
525
+
526
+ Example:
527
+ [1,2,3,4] drop_last: 2 # => [1,2]
528
+ """
529
+
530
+ first: (size - amount)
531
+ }
532
+
408
533
  def reduce: block init_val: init_val {
409
534
  """
410
535
  Calculates a value based on a given block to be called on an accumulator
@@ -416,7 +541,7 @@ class Fancy {
416
541
 
417
542
  acc = init_val
418
543
  each: |x| {
419
- acc = (block call: [acc, x])
544
+ acc = block call: [acc, x]
420
545
  }
421
546
  acc
422
547
  }
@@ -507,18 +632,19 @@ class Fancy {
507
632
  [[1,2], [2,3,4], [-1]] superior_by: '< taking: 'first # => [-1]
508
633
  """
509
634
 
635
+ { return nil } if: empty?
510
636
 
511
- pairs = self map: |val| {
512
- (val, selection_block call: [val])
513
- }
637
+ retval = first
638
+ retval_cmp = selection_block call: [retval]
514
639
 
515
- retval = pairs first
516
- pairs each: |p| {
517
- if: (comparison_block call: [p second, retval second]) then: {
518
- retval = p
640
+ rest each: |p| {
641
+ cmp = selection_block call: [p]
642
+ if: (comparison_block call: [cmp, retval_cmp]) then: {
643
+ retval = p
644
+ retval_cmp = cmp
519
645
  }
520
646
  }
521
- retval first
647
+ retval
522
648
  }
523
649
 
524
650
  def max {
@@ -531,6 +657,20 @@ class Fancy {
531
657
  superior_by: '>
532
658
  }
533
659
 
660
+ def max_by: block {
661
+ """
662
+ @block @Block@ by which to calculate the maximum value in @self.
663
+ @return Maximum value in @self based on @block.
664
+
665
+ Returns the maximum value in the Enumerable (via the '>' comparison message).
666
+
667
+ Example:
668
+ [[1,2,3], [1,2], [1]] max_by: @{ size } # => [1,2,3]
669
+ """
670
+
671
+ superior_by: '> taking: block
672
+ }
673
+
534
674
  def min {
535
675
  """
536
676
  @return Minimum value in @self.
@@ -541,6 +681,57 @@ class Fancy {
541
681
  superior_by: '<
542
682
  }
543
683
 
684
+ def min_by: block {
685
+ """
686
+ @block @Block@ by which to calculate the minimum value in @self.
687
+ @return Minimum value in @self based on @block.
688
+
689
+ Returns the minimum value in the Enumerable (via the '<' comparison message).
690
+
691
+ Example:
692
+ [[1,2,3], [1,2], [1]] min_by: @{ size } # => [1]
693
+ """
694
+
695
+ superior_by: '< taking: block
696
+ }
697
+
698
+ def min_max {
699
+ """
700
+ @return @Tuple@ of min and max value in @self.
701
+
702
+ If @self is empty, returns (nil, nil).
703
+
704
+ Example:
705
+ (1,2,3,4) min_max # => (1, 3)
706
+ """
707
+
708
+ min_max_by: @{ identity }
709
+ }
710
+
711
+ def min_max_by: block {
712
+ """
713
+ @block @Block@ to calculate the min and max value by.
714
+ @return @Tuple@ of min and max value based on @block in @self.
715
+
716
+ Calls @block with each element in @self to determine min and max values.
717
+ If @self is empty, returns (nil, nil).
718
+
719
+ Example:
720
+ (\"a\", \”bc\", \”def\") min_max_by: 'size # => (1, 3)
721
+ """
722
+
723
+ min, max = nil, nil
724
+ min_val, max_val = nil, nil
725
+ each: |x| {
726
+ val = block call: [x]
727
+ { min = val; min_val = x } unless: min
728
+ { min = val; min_val = x } if: (val < min)
729
+ { max = val; max_val = x } unless: max
730
+ { max = val; max_val = x } if: (val > max)
731
+ }
732
+ (min_val, max_val)
733
+ }
734
+
544
735
  def sum {
545
736
  """
546
737
  Calculates the sum of all the elements in the @Enumerable
@@ -564,7 +755,7 @@ class Fancy {
564
755
  @return Average value in @self (expecting @Number@s or Objects implementing @+ and @*).
565
756
  """
566
757
 
567
- { return 0 } if: (size == 0)
758
+ { return 0 } if: empty?
568
759
  sum to_f / size
569
760
  }
570
761
 
@@ -593,6 +784,40 @@ class Fancy {
593
784
  coll
594
785
  }
595
786
 
787
+ def chunk_by: block {
788
+ """
789
+ @block @Block@ to chunk @self by.
790
+ @return @Array@ of chunks, each including the return value of calling @block with elements in the chunk, as well as the elements themselves (within another @Array@).
791
+
792
+ Similar to @Fancy::Enumerable#partition_by:@ but includes the value of
793
+ calling @block with an element within the chunk.
794
+
795
+ Example:
796
+ [1,3,4,5,6,8,10] chunk_by: 'odd?
797
+ # => [[true, [1,3]], [false, [4]], [true, [5]], [false, [6,8,10]]]
798
+ """
799
+
800
+ { return [] } if: empty?
801
+
802
+ chunks = []
803
+ curr_chunk = []
804
+ initial = first
805
+ last_val = block call: [initial]
806
+ curr_chunk << initial
807
+
808
+ rest each: |x| {
809
+ val = block call: [x]
810
+ if: (val != last_val) then: {
811
+ chunks << [last_val, curr_chunk]
812
+ curr_chunk = []
813
+ }
814
+ curr_chunk << x
815
+ last_val = val
816
+ }
817
+ { chunks << [last_val, curr_chunk] } unless: $ curr_chunk empty?
818
+ chunks
819
+ }
820
+
596
821
  def random {
597
822
  """
598
823
  @return Random element in @self.
@@ -601,20 +826,32 @@ class Fancy {
601
826
  at: $ size random
602
827
  }
603
828
 
604
- def sort_by: block {
829
+ def sort: comparison_block {
605
830
  """
606
- @block @Block@ taking 2 arguments used to compare elements in a collection.
831
+ @comparison_block @Block@ taking 2 arguments used to compare elements in a collection.
607
832
  @return Sorted @Array@ of elements in @self.
608
833
 
609
834
  Sorts a collection by a given comparison block.
610
835
  """
611
836
 
612
- if: (block is_a?: Symbol) then: {
613
- sort() |a b| {
614
- a receive_message: block . <=> (b receive_message: block)
615
- }
616
- } else: {
617
- sort(&block)
837
+ sort(&comparison_block)
838
+ }
839
+
840
+ def sort_by: block {
841
+ """
842
+ @block @Block@ taking 1 argument used to extract a value to use for comparison.
843
+ @return Sorted @Array@ of elements in @self based on @block.
844
+
845
+ Sorts a collection by calling a @Block@ with every element
846
+ and using the return values for comparison.
847
+
848
+ Example:
849
+ [\"abc\", \"abcd\", \"ab\", \"a\", \"\"] sort_by: @{ size }
850
+ # => [\"\", \"a\", \"ab\", \"abc\", \"abcd\"]
851
+ """
852
+
853
+ sort_by() |x| {
854
+ block call: [x]
618
855
  }
619
856
  }
620
857
 
@@ -650,6 +887,27 @@ class Fancy {
650
887
  groups
651
888
  }
652
889
 
890
+ def group_by: block {
891
+ """
892
+ @block @Block@ used to group elements in @self by.
893
+ @return @Hash@ with elements in @self grouped by return value of calling @block with them.
894
+
895
+ Returns the elements grouped by @block in a @Hash@ (the keys being the
896
+ value of calling @block with the elements).
897
+
898
+ Example:
899
+ ('foo, 1, 2, 'bar) group_by: @{ class }
900
+ # => <[Symbol => ['foo, 'bar], Fixnum => [1,2]]>
901
+ """
902
+
903
+ h = <[]>
904
+ each: |x| {
905
+ group = h at: (block call: [x]) else_put: { [] }
906
+ group << x
907
+ }
908
+ h
909
+ }
910
+
653
911
  def reverse {
654
912
  """
655
913
  @return @self in reverse order.
@@ -800,5 +1058,38 @@ class Fancy {
800
1058
  }
801
1059
  result
802
1060
  }
1061
+
1062
+ def one?: block {
1063
+ """
1064
+ @block @Block@ to be used to check for a condition expected only once in @self.
1065
+ @return @true if @block yields @true only once for all elements in @self.
1066
+
1067
+ Example:
1068
+ (0,1,2) one?: 'odd? # => true
1069
+ (0,1,2) one?: 'even? # => false
1070
+ """
1071
+
1072
+ got_one? = false
1073
+ each: |x| {
1074
+ if: (block call: [x]) then: {
1075
+ { return false } if: got_one?
1076
+ got_one? = true
1077
+ }
1078
+ }
1079
+ return got_one?
1080
+ }
1081
+
1082
+ def none?: block {
1083
+ """
1084
+ @block @Block@ to be used to check for a condition expected not once in @self.
1085
+ @return @true if none of the elements in @self called with @block yield @true.
1086
+
1087
+ Example:
1088
+ (0,2,4) none?: 'odd? # => true
1089
+ (0,2,5) none?: 'odd? # => false
1090
+ """
1091
+
1092
+ any?: block . not
1093
+ }
803
1094
  }
804
1095
  }