fancy 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +38 -86
- data/bin/fdoc +2 -22
- data/bin/fspec +8 -3
- data/bin/ifancy +1 -1
- data/boot/fancy_ext.rb +1 -0
- data/boot/fancy_ext/array.rb +19 -0
- data/boot/fancy_ext/class.rb +2 -4
- data/boot/fancy_ext/module.rb +2 -0
- data/boot/fancy_ext/object.rb +0 -17
- data/boot/rbx-compiler/compiler/ast/method_def.rb +0 -4
- data/boot/rbx-compiler/compiler/ast/singleton_method_def.rb +0 -7
- data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
- data/boot/rbx-compiler/parser/fancy_parser.c +1 -0
- data/doc/api/fancy.css +10 -1
- data/doc/api/fancy.jsonp +1 -1
- data/doc/api/fdoc.js +22 -9
- data/doc/api/octocat.png +0 -0
- data/doc/features.md +1 -2
- data/examples/actors.fy +1 -2
- data/examples/armstrong_numbers.fy +7 -3
- data/examples/blocks.fy +3 -3
- data/examples/distributing_proxy.fy +31 -0
- data/examples/future_sends.fy +15 -0
- data/examples/person.fy +1 -2
- data/lib/argv.fy +1 -7
- data/lib/array.fy +7 -11
- data/lib/block.fy +15 -0
- data/lib/boot.fy +4 -3
- data/lib/class.fy +354 -10
- data/lib/compiler.fy +1 -1
- data/lib/compiler/ast/assign.fy +4 -8
- data/lib/compiler/ast/async_send.fy +1 -2
- data/lib/compiler/ast/block.fy +5 -0
- data/lib/compiler/ast/class_def.fy +2 -1
- data/lib/compiler/ast/expression_list.fy +1 -2
- data/lib/compiler/ast/future_send.fy +1 -2
- data/lib/compiler/ast/identifier.fy +34 -17
- data/lib/compiler/ast/literals.fy +31 -19
- data/lib/compiler/ast/match.fy +5 -4
- data/lib/compiler/ast/message_send.fy +3 -5
- data/lib/compiler/ast/method_def.fy +0 -3
- data/lib/compiler/ast/range.fy +2 -4
- data/lib/compiler/ast/return.fy +2 -4
- data/lib/compiler/ast/script.fy +2 -4
- data/lib/compiler/ast/singleton_method_def.fy +0 -3
- data/lib/compiler/ast/string_interpolation.fy +2 -2
- data/lib/compiler/ast/super.fy +2 -4
- data/lib/compiler/ast/try_catch.fy +13 -9
- data/lib/compiler/ast/tuple_literal.fy +1 -2
- data/lib/compiler/compiler.fy +2 -2
- data/lib/compiler/stages.fy +3 -6
- data/lib/contracts.fy +89 -57
- data/lib/dynamic_slot_object.fy +21 -3
- data/lib/enumerable.fy +140 -4
- data/lib/enumerator.fy +1 -1
- data/lib/eval.fy +23 -9
- data/lib/exception.fy +16 -0
- data/lib/false_class.fy +36 -5
- data/lib/fancy_spec.fy +64 -34
- data/lib/fdoc.fy +85 -24
- data/lib/file.fy +19 -0
- data/lib/future.fy +4 -46
- data/lib/hash.fy +113 -0
- data/lib/integer.fy +25 -6
- data/lib/iteration.fy +3 -3
- data/lib/main.fy +5 -0
- data/lib/matchers.fy +79 -0
- data/lib/nil_class.fy +8 -0
- data/lib/object.fy +109 -18
- data/lib/option_parser.fy +118 -0
- data/lib/package/dependency.fy +4 -8
- data/lib/package/dependency_installer.fy +1 -1
- data/lib/package/handler.fy +6 -0
- data/lib/package/installer.fy +43 -16
- data/lib/package/list.fy +1 -2
- data/lib/package/specification.fy +5 -5
- data/lib/package/uninstaller.fy +9 -2
- data/lib/parser.fy +1 -3
- data/lib/parser/ext/ext.c +1 -0
- data/lib/parser/ext/lexer.lex +5 -0
- data/lib/parser/methods.fy +48 -46
- data/lib/proxies.fy +151 -0
- data/lib/rbx.fy +1 -0
- data/lib/rbx/actor.fy +16 -18
- data/lib/rbx/array.fy +18 -3
- data/lib/rbx/block.fy +1 -7
- data/lib/rbx/class.fy +54 -9
- data/lib/rbx/code_loader.fy +2 -5
- data/lib/rbx/compiled_method.fy +31 -0
- data/lib/rbx/debugger.fy +66 -0
- data/lib/rbx/directory.fy +8 -3
- data/lib/rbx/documentation.fy +1 -1
- data/lib/rbx/file.fy +22 -0
- data/lib/rbx/integer.fy +1 -1
- data/lib/rbx/match_data.fy +2 -1
- data/lib/rbx/method.fy +26 -0
- data/lib/rbx/object.fy +8 -3
- data/lib/rbx/regexp.fy +6 -3
- data/lib/rbx/string.fy +9 -1
- data/lib/rbx/stringio.fy +12 -0
- data/lib/rbx/symbol.fy +4 -0
- data/lib/stack.fy +1 -1
- data/lib/string.fy +34 -0
- data/lib/stringio.fy +1 -1
- data/lib/symbol.fy +6 -2
- data/lib/system.fy +15 -1
- data/lib/tuple.fy +5 -2
- data/lib/version.fy +1 -1
- data/ruby_lib/fdoc +2 -22
- data/tests/array.fy +3 -17
- data/tests/class.fy +312 -10
- data/tests/contracts.fy +51 -0
- data/tests/distributing_proxy.fy +28 -0
- data/tests/enumerable.fy +104 -1
- data/tests/exception.fy +35 -0
- data/tests/fixnum.fy +1 -1
- data/tests/hash.fy +81 -1
- data/tests/integer.fy +9 -0
- data/tests/matchers.fy +18 -0
- data/tests/method.fy +8 -14
- data/tests/object.fy +76 -2
- data/tests/option_parser.fy +80 -0
- data/tests/string.fy +21 -0
- data/tests/stringio.fy +1 -1
- data/tests/tuple.fy +1 -1
- metadata +21 -44
- data/examples/arithmetic.fy +0 -7
- data/examples/array.fy +0 -50
- data/examples/boolean.fy +0 -24
- data/examples/class.fy +0 -68
- data/examples/constant_access.fy +0 -15
- data/examples/default_args.fy +0 -20
- data/examples/define_methods.fy +0 -15
- data/examples/dynamic_output.fy +0 -15
- data/examples/empty_catch.fy +0 -4
- data/examples/exception.fy +0 -9
- data/examples/files.fy +0 -23
- data/examples/finally.fy +0 -5
- data/examples/future.fy +0 -30
- data/examples/future_composition.fy +0 -20
- data/examples/futures.fy +0 -9
- data/examples/game_of_life.fy +0 -148
- data/examples/html_generator.fy +0 -84
- data/examples/implicit_return.fy +0 -3
- data/examples/matchers.fy +0 -6
- data/examples/nested_try.fy +0 -9
- data/examples/numbers.fy +0 -12
- data/examples/rbx/and_or.fy +0 -7
- data/examples/rbx/blocks.fy +0 -22
- data/examples/rbx/classes.fy +0 -32
- data/examples/rbx/hello.fy +0 -8
- data/examples/rbx/include.fy +0 -12
- data/examples/rbx/inherit.fy +0 -11
- data/examples/rbx/methods.fy +0 -15
- data/examples/rbx/nested_classes.fy +0 -9
- data/examples/rbx/require.fy +0 -3
- data/examples/rbx/strings.fy +0 -5
- data/examples/require.fy +0 -7
- data/examples/return.fy +0 -13
- data/examples/singleton_methods.fy +0 -21
- data/examples/threads.fy +0 -18
- data/examples/tuple.fy +0 -8
- data/examples/webserver/webserver.fy +0 -15
- data/lib/proxy.fy +0 -86
- data/lib/thread_pool.fy +0 -102
data/lib/compiler/ast/script.fy
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
class Fancy AST {
|
2
2
|
class Script : Node {
|
3
|
-
read_slots:
|
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)
|
@@ -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:
|
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
|
data/lib/compiler/ast/super.fy
CHANGED
@@ -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
|
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
|
-
#
|
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)
|
data/lib/compiler/compiler.fy
CHANGED
@@ -37,7 +37,7 @@ class Fancy {
|
|
37
37
|
result = nil
|
38
38
|
try {
|
39
39
|
result = compiler run()
|
40
|
-
} catch
|
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
|
66
|
+
} catch StandardError => e {
|
67
67
|
compiler_error("Error trying to compile " ++ file, e)
|
68
68
|
}
|
69
69
|
}
|
data/lib/compiler/stages.fy
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
class Fancy Compiler Stages {
|
2
2
|
class Stage : Rubinius Compiler Stage {
|
3
|
-
initialize
|
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
|
data/lib/contracts.fy
CHANGED
@@ -1,57 +1,89 @@
|
|
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
|
-
|
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
|
+
}
|
data/lib/dynamic_slot_object.fy
CHANGED
@@ -7,7 +7,8 @@ class DynamicSlotObject : Fancy BasicObject {
|
|
7
7
|
dso name: \"Chris\"
|
8
8
|
dso age: 25
|
9
9
|
dso country: \"Germany\"
|
10
|
-
|
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
|
-
|
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
|
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
|
|
data/lib/enumerable.fy
CHANGED
@@ -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
|
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
|
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
|
}
|