fancy 0.7.0 → 0.8.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.
- 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
|
}
|