fancy 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (165) hide show
  1. data/README.md +38 -86
  2. data/bin/fdoc +2 -22
  3. data/bin/fspec +8 -3
  4. data/bin/ifancy +1 -1
  5. data/boot/fancy_ext.rb +1 -0
  6. data/boot/fancy_ext/array.rb +19 -0
  7. data/boot/fancy_ext/class.rb +2 -4
  8. data/boot/fancy_ext/module.rb +2 -0
  9. data/boot/fancy_ext/object.rb +0 -17
  10. data/boot/rbx-compiler/compiler/ast/method_def.rb +0 -4
  11. data/boot/rbx-compiler/compiler/ast/singleton_method_def.rb +0 -7
  12. data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
  13. data/boot/rbx-compiler/parser/fancy_parser.c +1 -0
  14. data/doc/api/fancy.css +10 -1
  15. data/doc/api/fancy.jsonp +1 -1
  16. data/doc/api/fdoc.js +22 -9
  17. data/doc/api/octocat.png +0 -0
  18. data/doc/features.md +1 -2
  19. data/examples/actors.fy +1 -2
  20. data/examples/armstrong_numbers.fy +7 -3
  21. data/examples/blocks.fy +3 -3
  22. data/examples/distributing_proxy.fy +31 -0
  23. data/examples/future_sends.fy +15 -0
  24. data/examples/person.fy +1 -2
  25. data/lib/argv.fy +1 -7
  26. data/lib/array.fy +7 -11
  27. data/lib/block.fy +15 -0
  28. data/lib/boot.fy +4 -3
  29. data/lib/class.fy +354 -10
  30. data/lib/compiler.fy +1 -1
  31. data/lib/compiler/ast/assign.fy +4 -8
  32. data/lib/compiler/ast/async_send.fy +1 -2
  33. data/lib/compiler/ast/block.fy +5 -0
  34. data/lib/compiler/ast/class_def.fy +2 -1
  35. data/lib/compiler/ast/expression_list.fy +1 -2
  36. data/lib/compiler/ast/future_send.fy +1 -2
  37. data/lib/compiler/ast/identifier.fy +34 -17
  38. data/lib/compiler/ast/literals.fy +31 -19
  39. data/lib/compiler/ast/match.fy +5 -4
  40. data/lib/compiler/ast/message_send.fy +3 -5
  41. data/lib/compiler/ast/method_def.fy +0 -3
  42. data/lib/compiler/ast/range.fy +2 -4
  43. data/lib/compiler/ast/return.fy +2 -4
  44. data/lib/compiler/ast/script.fy +2 -4
  45. data/lib/compiler/ast/singleton_method_def.fy +0 -3
  46. data/lib/compiler/ast/string_interpolation.fy +2 -2
  47. data/lib/compiler/ast/super.fy +2 -4
  48. data/lib/compiler/ast/try_catch.fy +13 -9
  49. data/lib/compiler/ast/tuple_literal.fy +1 -2
  50. data/lib/compiler/compiler.fy +2 -2
  51. data/lib/compiler/stages.fy +3 -6
  52. data/lib/contracts.fy +89 -57
  53. data/lib/dynamic_slot_object.fy +21 -3
  54. data/lib/enumerable.fy +140 -4
  55. data/lib/enumerator.fy +1 -1
  56. data/lib/eval.fy +23 -9
  57. data/lib/exception.fy +16 -0
  58. data/lib/false_class.fy +36 -5
  59. data/lib/fancy_spec.fy +64 -34
  60. data/lib/fdoc.fy +85 -24
  61. data/lib/file.fy +19 -0
  62. data/lib/future.fy +4 -46
  63. data/lib/hash.fy +113 -0
  64. data/lib/integer.fy +25 -6
  65. data/lib/iteration.fy +3 -3
  66. data/lib/main.fy +5 -0
  67. data/lib/matchers.fy +79 -0
  68. data/lib/nil_class.fy +8 -0
  69. data/lib/object.fy +109 -18
  70. data/lib/option_parser.fy +118 -0
  71. data/lib/package/dependency.fy +4 -8
  72. data/lib/package/dependency_installer.fy +1 -1
  73. data/lib/package/handler.fy +6 -0
  74. data/lib/package/installer.fy +43 -16
  75. data/lib/package/list.fy +1 -2
  76. data/lib/package/specification.fy +5 -5
  77. data/lib/package/uninstaller.fy +9 -2
  78. data/lib/parser.fy +1 -3
  79. data/lib/parser/ext/ext.c +1 -0
  80. data/lib/parser/ext/lexer.lex +5 -0
  81. data/lib/parser/methods.fy +48 -46
  82. data/lib/proxies.fy +151 -0
  83. data/lib/rbx.fy +1 -0
  84. data/lib/rbx/actor.fy +16 -18
  85. data/lib/rbx/array.fy +18 -3
  86. data/lib/rbx/block.fy +1 -7
  87. data/lib/rbx/class.fy +54 -9
  88. data/lib/rbx/code_loader.fy +2 -5
  89. data/lib/rbx/compiled_method.fy +31 -0
  90. data/lib/rbx/debugger.fy +66 -0
  91. data/lib/rbx/directory.fy +8 -3
  92. data/lib/rbx/documentation.fy +1 -1
  93. data/lib/rbx/file.fy +22 -0
  94. data/lib/rbx/integer.fy +1 -1
  95. data/lib/rbx/match_data.fy +2 -1
  96. data/lib/rbx/method.fy +26 -0
  97. data/lib/rbx/object.fy +8 -3
  98. data/lib/rbx/regexp.fy +6 -3
  99. data/lib/rbx/string.fy +9 -1
  100. data/lib/rbx/stringio.fy +12 -0
  101. data/lib/rbx/symbol.fy +4 -0
  102. data/lib/stack.fy +1 -1
  103. data/lib/string.fy +34 -0
  104. data/lib/stringio.fy +1 -1
  105. data/lib/symbol.fy +6 -2
  106. data/lib/system.fy +15 -1
  107. data/lib/tuple.fy +5 -2
  108. data/lib/version.fy +1 -1
  109. data/ruby_lib/fdoc +2 -22
  110. data/tests/array.fy +3 -17
  111. data/tests/class.fy +312 -10
  112. data/tests/contracts.fy +51 -0
  113. data/tests/distributing_proxy.fy +28 -0
  114. data/tests/enumerable.fy +104 -1
  115. data/tests/exception.fy +35 -0
  116. data/tests/fixnum.fy +1 -1
  117. data/tests/hash.fy +81 -1
  118. data/tests/integer.fy +9 -0
  119. data/tests/matchers.fy +18 -0
  120. data/tests/method.fy +8 -14
  121. data/tests/object.fy +76 -2
  122. data/tests/option_parser.fy +80 -0
  123. data/tests/string.fy +21 -0
  124. data/tests/stringio.fy +1 -1
  125. data/tests/tuple.fy +1 -1
  126. metadata +21 -44
  127. data/examples/arithmetic.fy +0 -7
  128. data/examples/array.fy +0 -50
  129. data/examples/boolean.fy +0 -24
  130. data/examples/class.fy +0 -68
  131. data/examples/constant_access.fy +0 -15
  132. data/examples/default_args.fy +0 -20
  133. data/examples/define_methods.fy +0 -15
  134. data/examples/dynamic_output.fy +0 -15
  135. data/examples/empty_catch.fy +0 -4
  136. data/examples/exception.fy +0 -9
  137. data/examples/files.fy +0 -23
  138. data/examples/finally.fy +0 -5
  139. data/examples/future.fy +0 -30
  140. data/examples/future_composition.fy +0 -20
  141. data/examples/futures.fy +0 -9
  142. data/examples/game_of_life.fy +0 -148
  143. data/examples/html_generator.fy +0 -84
  144. data/examples/implicit_return.fy +0 -3
  145. data/examples/matchers.fy +0 -6
  146. data/examples/nested_try.fy +0 -9
  147. data/examples/numbers.fy +0 -12
  148. data/examples/rbx/and_or.fy +0 -7
  149. data/examples/rbx/blocks.fy +0 -22
  150. data/examples/rbx/classes.fy +0 -32
  151. data/examples/rbx/hello.fy +0 -8
  152. data/examples/rbx/include.fy +0 -12
  153. data/examples/rbx/inherit.fy +0 -11
  154. data/examples/rbx/methods.fy +0 -15
  155. data/examples/rbx/nested_classes.fy +0 -9
  156. data/examples/rbx/require.fy +0 -3
  157. data/examples/rbx/strings.fy +0 -5
  158. data/examples/require.fy +0 -7
  159. data/examples/return.fy +0 -13
  160. data/examples/singleton_methods.fy +0 -21
  161. data/examples/threads.fy +0 -18
  162. data/examples/tuple.fy +0 -8
  163. data/examples/webserver/webserver.fy +0 -15
  164. data/lib/proxy.fy +0 -86
  165. data/lib/thread_pool.fy +0 -102
@@ -1,7 +1,6 @@
1
1
  class Fancy AST {
2
2
  class Script : Node {
3
- read_slots: ['file, 'line, 'body]
4
-
3
+ read_slots: ('file, 'line, 'body)
5
4
  @@stack = []
6
5
 
7
6
  def push_script {
@@ -16,8 +15,7 @@ class Fancy AST {
16
15
  @@stack last()
17
16
  }
18
17
 
19
- def initialize: @line file: @file body: @body {
20
- }
18
+ def initialize: @line file: @file body: @body
21
19
 
22
20
  def bytecode: g {
23
21
  pos(g)
@@ -7,9 +7,6 @@ class Fancy AST {
7
7
 
8
8
  def bytecode: g {
9
9
  pos(g)
10
- g push_self()
11
- g send(@access, 0)
12
- g pop()
13
10
  bytecode(g)
14
11
  }
15
12
  }
@@ -6,9 +6,9 @@ class Fancy AST {
6
6
  It works...
7
7
  """
8
8
 
9
- def initialize: @line code: @code
9
+ def initialize: @line code: @code filename: @filename
10
10
  def parse_code {
11
- Fancy Parser parse_code: @code file: ("<<StringInterpolation: " ++ (@code inspect) ++ ">>") line: @line
11
+ Fancy Parser parse_code: @code file: @filename line: @line
12
12
  }
13
13
  def bytecode: g {
14
14
  parse_code body expressions first bytecode: g
@@ -1,12 +1,10 @@
1
1
  class Fancy AST {
2
2
  class Super : Node {
3
- def initialize: @line {
4
- }
3
+ def initialize: @line
5
4
  }
6
5
 
7
6
  class SuperSend : Node {
8
- def initialize: @line message: @name args: @args {
9
- }
7
+ def initialize: @line message: @name args: @args
10
8
 
11
9
  def bytecode: g {
12
10
  pos(g)
@@ -28,7 +28,7 @@ class Fancy AST {
28
28
  finally_ = g new_label()
29
29
  done = g new_label()
30
30
 
31
- g setup_unwind(handler, Rubinius AST RescueType)
31
+ g setup_unwind(handler, Rubinius AST EnsureType)
32
32
 
33
33
  # make a break available to use
34
34
  current_break = g break()
@@ -42,9 +42,11 @@ class Fancy AST {
42
42
  if: current_redo then: { g redo=(g new_label()) }
43
43
 
44
44
  @body bytecode(g)
45
+ retval = g new_stack_local()
46
+ g set_stack_local(retval)
47
+ g pop()
45
48
 
46
49
  g pop_unwind()
47
- g pop()
48
50
  g goto(finally_)
49
51
 
50
52
  if: current_break then: {
@@ -109,7 +111,7 @@ class Fancy AST {
109
111
 
110
112
  reraise set!()
111
113
 
112
- # execte the finally block before propagating the exception
114
+ # execute the finally block before propagating the exception
113
115
  @ensure bytecode: g
114
116
 
115
117
  # remove the exception so we have the state
@@ -120,6 +122,7 @@ class Fancy AST {
120
122
  g reraise()
121
123
 
122
124
  finally_ set!()
125
+
123
126
  @ensure bytecode: g
124
127
 
125
128
  done set!()
@@ -127,12 +130,15 @@ class Fancy AST {
127
130
  g push_stack_local(outer_ex)
128
131
  g restore_exception_state()
129
132
  g pop_modifiers()
133
+
134
+ g pop()
135
+
136
+ g push_stack_local(retval)
130
137
  }
131
138
  }
132
139
 
133
140
  class ExceptionHandler : Node {
134
- def initialize: @line condition: @condition var: @var body: @body {
135
- }
141
+ def initialize: @line condition: @condition var: @var body: @body
136
142
 
137
143
  def bytecode: g final_tag: final_tag {
138
144
  pos(g)
@@ -160,8 +166,7 @@ class Fancy AST {
160
166
  }
161
167
 
162
168
  class CurrentException : Node {
163
- def initialize: @line {
164
- }
169
+ def initialize: @line
165
170
 
166
171
  def bytecode: g {
167
172
  pos(g)
@@ -170,8 +175,7 @@ class Fancy AST {
170
175
  }
171
176
 
172
177
  class Retry : Node {
173
- def initialize: @line {
174
- }
178
+ def initialize: @line
175
179
 
176
180
  def bytecode: g {
177
181
  pos(g)
@@ -1,7 +1,6 @@
1
1
  class Fancy AST {
2
2
  class TupleLiteral : Node {
3
- def initialize: @line entries: @elements {
4
- }
3
+ def initialize: @line entries: @elements
5
4
 
6
5
  def bytecode: g {
7
6
  pos(g)
@@ -37,7 +37,7 @@ class Fancy {
37
37
  result = nil
38
38
  try {
39
39
  result = compiler run()
40
- } catch Exception => e {
40
+ } catch StandardError => e {
41
41
  compiler_error("Error trying to compile " ++ file, e)
42
42
  }
43
43
  result
@@ -63,7 +63,7 @@ class Fancy {
63
63
  compiler run()
64
64
  } catch Fancy Parser ParseError => e {
65
65
  e raise!
66
- } catch Exception => e {
66
+ } catch StandardError => e {
67
67
  compiler_error("Error trying to compile " ++ file, e)
68
68
  }
69
69
  }
@@ -1,11 +1,10 @@
1
1
  class Fancy Compiler Stages {
2
2
  class Stage : Rubinius Compiler Stage {
3
- initialize = |compiler, last| {
3
+ define_method('initialize) |compiler last| {
4
4
  sup = Rubinius Compiler Stage instance_method('initialize)
5
5
  sup bind(self) call(compiler, last)
6
6
  initialize: compiler last: last
7
7
  }
8
- define_method('initialize, &initialize)
9
8
 
10
9
  def self stage: name next: next (nil) {
11
10
  stage(name)
@@ -41,8 +40,7 @@ class Fancy Compiler Stages {
41
40
  compiler parser: self
42
41
  }
43
42
 
44
- def input: @code file: @filename line: @line (1) {
45
- }
43
+ def input: @code file: @filename line: @line (1);
46
44
 
47
45
  def run {
48
46
  ast = Fancy Parser parse_code: @code file: @filename line: @line
@@ -60,8 +58,7 @@ class Fancy Compiler Stages {
60
58
  compiler parser: self
61
59
  }
62
60
 
63
- def input: @filename line: @line (1) {
64
- }
61
+ def input: @filename line: @line (1);
65
62
 
66
63
  def run {
67
64
  ast = Fancy Parser parse_file: @filename line: @line
@@ -1,57 +1,89 @@
1
- # class Class {
2
- # class Contracts {
3
- # class ConditionBuilder : Proxy {
4
- # def initialize: block for: @method class: @class {
5
- # @conditions = <[]>
6
- # block call: [self]
7
- # insert_validations
8
- # }
9
-
10
- # def unknown_message: m with_params: p {
11
- # if: (p size > 0 ) then: {
12
- # @conditions[m to_s[[0,-2]]]: $ p first
13
- # }
14
- # }
15
-
16
- # def insert_validations {
17
- # name = @method name()
18
- # alias_name = "__#{name}__orig__"
19
- # conditions = @conditions
20
-
21
- # @class alias_method: alias_name for: name
22
- # @class define_method: name with: |p| {
23
- # conditions each: |attr block| {
24
- # # TODO
25
- # }
26
- # receive_message: alias_name with_params: p
27
- # }
28
- # }
29
- # }
30
- # }
31
-
32
- # def preconditions: block for: method {
33
- # Contracts ConditionBuilder new: block for: method class: self
34
- # }
35
-
36
- # def postconditions: block for: method {
37
- # Contracts ConditionBuilder new: block for: method class: self
38
- # }
39
- # }
40
-
41
- # # example
42
-
43
- # class Person {
44
- # read_slots: ('name, 'age)
45
-
46
- # preconditions: @{
47
- # name: @{ blank? not }
48
- # age: @{ > 0 }
49
- # } for: $ def initialize: @name age: @age
50
- # }
51
-
52
-
53
- # p = Person new: "chris" age: 25
54
- # p inspect println
55
-
56
-
57
- nil
1
+ class Class {
2
+ class Contracts {
3
+ class InterfaceNotImplementedError : ArgumentError {
4
+ """
5
+ Exception class that gets raised during @Class@ inclusion
6
+ whenever a class doesn't implement another class' required
7
+ interface.
8
+ """
9
+
10
+ read_slots: ('methods, 'interface, 'including_class)
11
+ def initialize: @methods interface: @interface including_class: @including_class {
12
+ initialize: \
13
+ "Methods #{@methods inspect} not implemented for interface: #{@interface name} required in class: #{@including_class name}"
14
+ }
15
+ }
16
+ }
17
+
18
+ lazy_slot: 'expected_interface_methods value: { [] }
19
+ lazy_slot: 'provided_interface_methods value: { [] }
20
+
21
+ def expects_interface_on_inclusion: methods {
22
+ """
23
+ @methods Collection of method signatures to expect on inclusion into another @Class@.
24
+
25
+ Declares a required interface (collection of method signatures) an including class has to provide.
26
+
27
+ Example:
28
+ class Enumerable {
29
+ expects_interface_on_inclusion: ['each:]
30
+ }
31
+ """
32
+
33
+ @expected_interface_methods = methods to_a
34
+ }
35
+
36
+ alias_method: 'expects_interface: for: 'expects_interface_on_inclusion:
37
+
38
+ def provides_interface: methods {
39
+ """
40
+ @methods Collection of method signatures this class explicitly declares to provide.
41
+
42
+ Example:
43
+ class MyCollection {
44
+ # you can skip this if you actually define each: before you include Fancy Enumerable.
45
+ provides_interface: ['each]
46
+ includes: Fancy Enumerable
47
+ }
48
+ """
49
+
50
+ provided_interface_methods append: (methods to_a)
51
+ }
52
+
53
+ def provides_interface?: methods {
54
+ """
55
+ @methods Collection of method signatures (an interface) to check for.
56
+ @return @true if all methods in @methods are provided by @self, @false otherwise.
57
+ """
58
+
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) }
61
+ }
62
+
63
+ def missing_methods_for_interface: methods {
64
+ """
65
+ @methods Collection of method signatures to check.
66
+ @return Collection of methods in @methods this class doesn't provide.
67
+ """
68
+
69
+ pim = Set new: $ provided_interface_methods map: @{ message_name to_s } + instance_methods
70
+ methods select: |m| { pim includes?: (m message_name to_s) . not }
71
+ }
72
+
73
+ def included: class {
74
+ """
75
+ @class @Class@ to be included in @self. Checks possible interface requirements.
76
+
77
+ Default include hook. Make sure to call this via `super included: class`.
78
+ """
79
+
80
+ class provides_interface?: expected_interface_methods
81
+ unless: (class provides_interface?: expected_interface_methods) do: {
82
+ not_implemented_methods = class missing_methods_for_interface: expected_interface_methods
83
+ if: (not_implemented_methods size > 0) then: {
84
+ Contracts InterfaceNotImplementedError new: not_implemented_methods interface: self including_class: class . raise!
85
+ }
86
+ }
87
+ true
88
+ }
89
+ }
@@ -7,7 +7,8 @@ class DynamicSlotObject : Fancy BasicObject {
7
7
  dso name: \"Chris\"
8
8
  dso age: 25
9
9
  dso country: \"Germany\"
10
- dso object # => Object with slots 'name, 'age and 'country defined
10
+
11
+ dso object # => Object with slots 'name, 'age and 'country defined
11
12
  """
12
13
 
13
14
  def initialize {
@@ -15,6 +16,10 @@ class DynamicSlotObject : Fancy BasicObject {
15
16
  }
16
17
 
17
18
  def object {
19
+ """
20
+ @return @Object@ with slots defined dynamically by sending messages to @self.
21
+ """
22
+
18
23
  @object metaclass read_write_slots: (@object slots)
19
24
  @object
20
25
  }
@@ -35,14 +40,23 @@ class DynamicKeyHash : Fancy BasicObject {
35
40
  dkh name: \"Chris\"
36
41
  dkh age: 25
37
42
  dkh country: \"Germany\"
38
- dkh hash # => <['name => \"Chris\", 'age => 25, 'country => \"Germany\"]>
43
+
44
+ dkh hash # => <['name => \"Chris\", 'age => 25, 'country => \"Germany\"]>
39
45
  """
40
46
 
41
47
  def initialize: @deep (false) {
48
+ """
49
+ @deep If @true, recursively sends @to_hash to any value passed as an argument to @self that is a @Block@ (dynamically creating nested @Hash@es).
50
+ """
51
+
42
52
  @hash = <[]>
43
53
  }
44
54
 
45
55
  def hash {
56
+ """
57
+ @return @Hash@ generated dynamically by sending messages to @self.
58
+ """
59
+
46
60
  @hash
47
61
  }
48
62
 
@@ -70,7 +84,7 @@ class DynamicValueArray : Fancy BasicObject {
70
84
  dva country: \"Germany\"
71
85
  dva something_else
72
86
 
73
- dva array # => [['name, \"Chris\"], ['age, 25], ['country, \"Germany\"], 'something_else]
87
+ dva array # => [['name, \"Chris\"], ['age, 25], ['country, \"Germany\"], 'something_else]
74
88
  """
75
89
 
76
90
  def initialize {
@@ -78,6 +92,10 @@ class DynamicValueArray : Fancy BasicObject {
78
92
  }
79
93
 
80
94
  def array {
95
+ """
96
+ @return @Array@ generated dynamically by sending messages to @self.
97
+ """
98
+
81
99
  @arr
82
100
  }
83
101
 
@@ -4,6 +4,8 @@ class Fancy {
4
4
  Mixin-Class with useful methods for collections that implement an @each:@ method.
5
5
  """
6
6
 
7
+ expects_interface: 'each:
8
+
7
9
  def at: index {
8
10
  """
9
11
  @index @Fixnum@ that is the 0-based index into @self.
@@ -14,10 +16,8 @@ class Fancy {
14
16
  \"foo\” at: 3 # => nil
15
17
  """
16
18
 
17
- i = 0
18
- each: |x| {
19
+ each_with_index: |x i| {
19
20
  { return x } if: $ i == index
20
- i = i + 1
21
21
  }
22
22
  return nil
23
23
  }
@@ -80,6 +80,47 @@ class Fancy {
80
80
  item
81
81
  }
82
82
 
83
+ def rest {
84
+ """
85
+ @return @Array@ of all but the first element in @self.
86
+ """
87
+
88
+ drop: 1
89
+ }
90
+
91
+ def first: amount {
92
+ """
93
+ @amount Amount of first elements to take from @self.
94
+ @return @Array@ of first @amount elements in @self.
95
+
96
+ Example:
97
+ (1,2,3,4) first: 2 # => [1,2]
98
+ """
99
+
100
+ i = 0
101
+ take_while: {
102
+ i = i + 1
103
+ i <= amount
104
+ }
105
+ }
106
+
107
+ def last: amount {
108
+ """
109
+ @amount Amount of last elements to take from @self.
110
+ @return @Array@ of last @amount elements in @self.
111
+
112
+ Example:
113
+ (1,2,3,4) last: 2 # => [3,4]
114
+ """
115
+
116
+ start_index = size - amount
117
+ i = 0
118
+ drop_while: {
119
+ i = i + 1
120
+ i <= start_index
121
+ }
122
+ }
123
+
83
124
  def includes?: item {
84
125
  """
85
126
  @item Item to check if it's included in @self.
@@ -123,6 +164,21 @@ class Fancy {
123
164
  s
124
165
  }
125
166
 
167
+ def join_by: block {
168
+ """
169
+ @block @Block@ to be called pair-wise to produce a single value.
170
+ @return Result of calling @block pairwise (similar to using @Fancy::Enumerable#reduce:into:@).
171
+
172
+ Works similar to @Fancy::Enumerable#inject:into:@ but uses first element as value injected.
173
+
174
+ Example:
175
+ (1,2,3) reduce_by: '+ # => same as: (2,3) inject: 1 into: '+
176
+ """
177
+
178
+ first, *rest = self
179
+ rest inject: first into: block
180
+ }
181
+
126
182
  def any?: condition {
127
183
  """
128
184
  @condition @Block@ (or @Callable) that is used to check if any element in @self yields true for it.
@@ -318,7 +374,7 @@ class Fancy {
318
374
  def take: amount {
319
375
  """
320
376
  @amount Amount of elements to take from @self.
321
- @return First @amount elements of @self in an @Array@.
377
+ @return @Array@ of first @amount elements in @self.
322
378
 
323
379
  Example:
324
380
  [1,2,3,4] take: 2 # => [1,2]
@@ -575,6 +631,8 @@ class Fancy {
575
631
  tmp = []
576
632
  enum = to_enum
577
633
 
634
+ { return groups } if: (size <= 0)
635
+
578
636
  loop: {
579
637
  size times: {
580
638
  tmp << (enum next)
@@ -664,5 +722,83 @@ class Fancy {
664
722
 
665
723
  join
666
724
  }
725
+
726
+ def sorted? {
727
+ """
728
+ @return @true if @self is sorted, @false otherwise.
729
+
730
+ Example:
731
+ (1,2,3) sorted? # => true
732
+ (2,1,3) sorted? # => false
733
+ \"abc\" sorted? # => true
734
+ \"bac\" sorted? # => false
735
+ """
736
+
737
+ last = nil
738
+ each: |x| {
739
+ if: last then: {
740
+ { return false } unless: $ last <= x
741
+ }
742
+ last = x
743
+ }
744
+ true
745
+ }
746
+
747
+ def split_at: index {
748
+ """
749
+ @index Index at which @self should be split.
750
+ @return @Array@ of 2 @Array@s of elements in self splitted at @index.
751
+
752
+ Example:
753
+ [1,2,3,4,5] split_at: 2 # => [[1,2], [3,4,5]]
754
+ """
755
+
756
+ [take: index, drop: index]
757
+ }
758
+
759
+ def split_with: predicate_block {
760
+ """
761
+ @predicate_block @Block@ to be used as a predicate on where to split in @self.
762
+ @return @Array@ of 2 @Array@s of elements split based on @predicate_block.
763
+
764
+ Example:
765
+ [1,2,3,4,5] split_with: @{ < 3 } # => [[1, 2], [3, 4, 5]]
766
+ """
767
+
768
+ [take_while: predicate_block, drop_while: predicate_block]
769
+ }
770
+
771
+ def grep: pattern {
772
+ """
773
+ @pattern Pattern to be filtered by (via @Object#===@)
774
+ @return Elements in @self for which @pattern matches.
775
+
776
+ Example:
777
+ \"hello world\" grep: /[a-h]/ # => [\"h\", \"e\", \"d\"]
778
+ [\"hello\", \"world\", 1, 2, 3] grep: String # => [\"hello\", \"world\"]
779
+ """
780
+
781
+ select: |x| { pattern === x }
782
+ }
783
+
784
+ def grep: pattern taking: block {
785
+ """
786
+ @pattern Pattern to be filtered by (via @Object#===@)
787
+ @block @Block@ to be called with each element for which @pattern matches.
788
+ @return Return values of elements in @self called with @block for which @pattern matches.
789
+
790
+ Example:
791
+ \"hello world\" grep: /[a-h]/ taking: @{ upcase } # => [\"H\", \"E\", \"D\"]
792
+ [\"hello\", \"world\", 1, 2, 3] grep: String taking: 'upcase # => [\"HELLO\", \"WORLD\"]
793
+ """
794
+
795
+ result = []
796
+ each: |x| {
797
+ match x {
798
+ case pattern -> result << (block call: [x])
799
+ }
800
+ }
801
+ result
802
+ }
667
803
  }
668
804
  }