fancy 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +2 -0
- data/README.md +6 -1
- data/bin/fancy +6 -0
- data/bin/ifancy +44 -3
- data/boot/fancy_ext/module.rb +4 -0
- data/boot/fancy_ext/object.rb +4 -0
- data/boot/rbx-compiler/compiler/ast/block.rb +29 -1
- data/boot/rbx-compiler/compiler/ast/identifier.rb +6 -0
- data/boot/rbx-compiler/compiler/ast/message_send.rb +1 -0
- data/boot/rbx-compiler/parser/fancy_parser.bundle +0 -0
- data/boot/rbx-compiler/parser/lexer.lex +2 -0
- data/boot/rbx-compiler/parser/parser.rb +6 -0
- data/boot/rbx-compiler/parser/parser.y +14 -1
- data/doc/api/fancy.jsonp +1 -1
- data/doc/features.md +24 -0
- data/examples/99bottles.fy +5 -0
- data/examples/conditions_exceptions.fy +9 -0
- data/examples/conditions_parsing.fy +68 -0
- data/examples/greeter.fy +9 -0
- data/examples/html_generator.fy +59 -29
- data/examples/webserver/webserver.fy +8 -11
- data/lib/argv.fy +6 -0
- data/lib/array.fy +17 -35
- data/lib/block.fy +82 -1
- data/lib/boot.fy +4 -2
- data/lib/compiler.fy +2 -2
- data/lib/compiler/ast/block.fy +24 -20
- data/lib/compiler/ast/message_send.fy +11 -0
- data/lib/contracts.fy +60 -0
- data/lib/dynamic_slot_object.fy +61 -0
- data/lib/enumerable.fy +432 -394
- data/lib/enumerator.fy +152 -150
- data/lib/fdoc.fy +4 -17
- data/lib/fiber.fy +4 -10
- data/lib/file.fy +33 -25
- data/lib/future.fy +59 -5
- data/lib/hash.fy +54 -1
- data/lib/html.fy +107 -0
- data/lib/kvo.fy +173 -0
- data/lib/main.fy +6 -2
- data/lib/message_sink.fy +19 -0
- data/lib/number.fy +48 -0
- data/lib/object.fy +65 -13
- data/lib/package.fy +12 -2
- data/lib/package/dependency.fy +13 -0
- data/lib/package/dependency_installer.fy +27 -0
- data/lib/package/installer.fy +4 -10
- data/lib/package/uninstaller.fy +1 -3
- data/lib/parser/ext/lexer.lex +8 -3
- data/lib/parser/ext/parser.y +4 -1
- data/lib/parser/methods.fy +7 -3
- data/lib/range.fy +1 -1
- data/lib/rbx.fy +2 -1
- data/lib/rbx/array.fy +28 -12
- data/lib/rbx/bignum.fy +1 -1
- data/lib/rbx/block.fy +27 -0
- data/lib/rbx/console.fy +6 -6
- data/lib/rbx/date.fy +6 -1
- data/lib/rbx/documentation.fy +8 -3
- data/lib/rbx/exception.fy +5 -0
- data/lib/rbx/file.fy +40 -7
- data/lib/rbx/fixnum.fy +12 -1
- data/lib/rbx/method.fy +9 -2
- data/lib/rbx/module.fy +24 -0
- data/lib/rbx/regexp.fy +8 -0
- data/lib/rbx/string.fy +23 -7
- data/lib/rbx/tcp_server.fy +4 -2
- data/lib/rbx/tcp_socket.fy +14 -0
- data/lib/remote_object.fy +59 -0
- data/lib/set.fy +15 -4
- data/lib/string.fy +38 -5
- data/lib/stringio.fy +1 -0
- data/lib/symbol.fy +4 -0
- data/lib/system.fy +22 -0
- data/lib/thread_pool.fy +2 -2
- data/lib/tuple.fy +18 -1
- data/lib/vars.fy +17 -0
- data/lib/version.fy +1 -1
- data/ruby_lib/fancy +6 -0
- data/tests/array.fy +30 -0
- data/tests/block.fy +106 -0
- data/tests/class.fy +19 -0
- data/tests/enumerable.fy +1 -1
- data/tests/enumerator.fy +5 -5
- data/tests/file.fy +28 -0
- data/tests/fixnum.fy +0 -50
- data/tests/future.fy +9 -24
- data/tests/hash.fy +35 -0
- data/tests/html.fy +33 -0
- data/tests/kvo.fy +101 -0
- data/tests/number.fy +75 -0
- data/tests/object.fy +50 -3
- data/tests/string.fy +19 -10
- data/tests/symbol.fy +5 -0
- data/tests/tuple.fy +7 -0
- data/tools/fancy-mode.el +5 -1
- metadata +22 -21
- data/boot/compiler/parser/ext/fancy_parser.bundle +0 -0
- data/boot/rbx-compiler/parser/Makefile +0 -156
- data/boot/rbx-compiler/parser/lexer.c +0 -2310
- data/boot/rbx-compiler/parser/lexer.h +0 -315
- data/boot/rbx-compiler/parser/parser.c +0 -2946
- data/boot/rbx-compiler/parser/parser.h +0 -151
- data/lib/fiber_pool.fy +0 -78
- data/lib/method.fy +0 -6
- data/lib/parser/ext/Makefile +0 -156
- data/lib/parser/ext/fancy_parser.bundle +0 -0
- data/lib/parser/ext/lexer.c +0 -2392
- data/lib/parser/ext/lexer.h +0 -315
- data/lib/parser/ext/parser.c +0 -3251
- data/lib/parser/ext/parser.h +0 -161
data/lib/future.fy
CHANGED
@@ -5,6 +5,7 @@ class FutureSend {
|
|
5
5
|
@condvar = ConditionVariable new
|
6
6
|
@completed = false
|
7
7
|
@failed = false
|
8
|
+
@continuations = []
|
8
9
|
@actor ! ('future, (@message, @params), self)
|
9
10
|
}
|
10
11
|
|
@@ -26,11 +27,19 @@ class FutureSend {
|
|
26
27
|
|
27
28
|
def completed! {
|
28
29
|
@condvar broadcast
|
30
|
+
unless: @failed do: {
|
31
|
+
@continuations each: @{ call: [@value] }
|
32
|
+
}
|
33
|
+
@continuations = []
|
29
34
|
}
|
30
35
|
|
31
36
|
private: 'completed!
|
32
37
|
|
33
38
|
def completed? {
|
39
|
+
"""
|
40
|
+
@return @true if FutureSend completed (success or failure), @false otherwise.
|
41
|
+
"""
|
42
|
+
|
34
43
|
completed = false
|
35
44
|
@completed_mutex synchronize: {
|
36
45
|
completed = @completed
|
@@ -38,7 +47,25 @@ class FutureSend {
|
|
38
47
|
return completed true?
|
39
48
|
}
|
40
49
|
|
50
|
+
def succeeded? {
|
51
|
+
"""
|
52
|
+
@return @true if FutureSend completed without failure, @false otherwise.
|
53
|
+
"""
|
54
|
+
|
55
|
+
completed = false
|
56
|
+
failed = false
|
57
|
+
@completed_mutex synchronize: {
|
58
|
+
completed = @completed
|
59
|
+
failed = @failed
|
60
|
+
}
|
61
|
+
return completed true? && (failed false?)
|
62
|
+
}
|
63
|
+
|
41
64
|
def failed? {
|
65
|
+
"""
|
66
|
+
@return @true if FutureSend failed, @false otherwise.
|
67
|
+
"""
|
68
|
+
|
42
69
|
failed = false
|
43
70
|
@completed_mutex synchronize: {
|
44
71
|
failed = @failed
|
@@ -47,6 +74,13 @@ class FutureSend {
|
|
47
74
|
}
|
48
75
|
|
49
76
|
def failure {
|
77
|
+
"""
|
78
|
+
@return @Exception@ that caused the FutureSend to fail, or @nil, if no failure.
|
79
|
+
|
80
|
+
Returns the @Exception@ that caused @self to fail, or @nil, if it didn't fail.
|
81
|
+
Will block the calling @Thread@ if @self hasn't completed or failed yet.
|
82
|
+
"""
|
83
|
+
|
50
84
|
@completed_mutex synchronize: {
|
51
85
|
if: @failed then: {
|
52
86
|
return @fail_reason
|
@@ -58,6 +92,13 @@ class FutureSend {
|
|
58
92
|
}
|
59
93
|
|
60
94
|
def value {
|
95
|
+
"""
|
96
|
+
@return Return value of performing @self.
|
97
|
+
|
98
|
+
Returns the value returned by performing @self.
|
99
|
+
Will block the calling @Thread@ if @self hasn't completed or failed yet.
|
100
|
+
"""
|
101
|
+
|
61
102
|
@completed_mutex synchronize: {
|
62
103
|
if: @completed then: {
|
63
104
|
return @value
|
@@ -73,9 +114,24 @@ class FutureSend {
|
|
73
114
|
}
|
74
115
|
|
75
116
|
def when_done: block {
|
76
|
-
|
117
|
+
"""
|
118
|
+
@block @Block@ to be registered as a continuation when @self succeeds.
|
119
|
+
|
120
|
+
Registers @block as a continuation to be called with @self's value on success.
|
121
|
+
"""
|
122
|
+
|
123
|
+
{ return nil } if: failed?
|
124
|
+
@completed_mutex synchronize: {
|
125
|
+
if: @completed then: {
|
126
|
+
block call: [@value]
|
127
|
+
} else: {
|
128
|
+
@continuations << block
|
129
|
+
}
|
130
|
+
}
|
77
131
|
}
|
78
132
|
|
133
|
+
alias_method: 'with_value: for: 'when_done:
|
134
|
+
|
79
135
|
def && block {
|
80
136
|
when_done: block
|
81
137
|
}
|
@@ -132,15 +188,13 @@ class PooledFuture {
|
|
132
188
|
}
|
133
189
|
|
134
190
|
class FutureCollection {
|
135
|
-
include:
|
191
|
+
include: Fancy Enumerable
|
136
192
|
|
137
193
|
def initialize: @futures {
|
138
194
|
}
|
139
195
|
|
140
196
|
def each: block {
|
141
|
-
@futures each:
|
142
|
-
f when_done: block
|
143
|
-
}
|
197
|
+
@futures each: @{ when_done: block }
|
144
198
|
}
|
145
199
|
|
146
200
|
def await_all {
|
data/lib/hash.fy
CHANGED
@@ -4,7 +4,7 @@ class Hash {
|
|
4
4
|
Maps a key to a value.
|
5
5
|
"""
|
6
6
|
|
7
|
-
include:
|
7
|
+
include: Fancy Enumerable
|
8
8
|
|
9
9
|
def [key] {
|
10
10
|
"""
|
@@ -17,6 +17,21 @@ class Hash {
|
|
17
17
|
at: key
|
18
18
|
}
|
19
19
|
|
20
|
+
def at: key else: else_block {
|
21
|
+
"""
|
22
|
+
@key Key of the value to get.
|
23
|
+
@else_block @Block@ to be called if @key is not found.
|
24
|
+
@return Value for @key or value of calling @else_block, if @key is not found.
|
25
|
+
|
26
|
+
Returns the value for a given key.
|
27
|
+
If the key is not found, calls @else_block and returns the value it yields.
|
28
|
+
"""
|
29
|
+
|
30
|
+
if: (includes?: key) then: {
|
31
|
+
at: key
|
32
|
+
} else: else_block
|
33
|
+
}
|
34
|
+
|
20
35
|
def each: block {
|
21
36
|
"""
|
22
37
|
@block @Block@ to be called with each key and value in @self.
|
@@ -80,6 +95,26 @@ class Hash {
|
|
80
95
|
to_a to_s
|
81
96
|
}
|
82
97
|
|
98
|
+
def to_object {
|
99
|
+
"""
|
100
|
+
@return New @Object@ with slots defined by keys and values in @self.
|
101
|
+
|
102
|
+
Creates and returns a new @Object@ with slot names and values based on keys and values in @self.
|
103
|
+
|
104
|
+
Example:
|
105
|
+
o = <['name => \"Christopher Bertels\", 'interest => \"programming languages\"]> to_object
|
106
|
+
o name # => \"Christopher Bertels\"
|
107
|
+
o interest # => 42
|
108
|
+
"""
|
109
|
+
|
110
|
+
o = Object new
|
111
|
+
self each: |k v| {
|
112
|
+
o set_slot: k value: v
|
113
|
+
}
|
114
|
+
o metaclass read_write_slots: keys
|
115
|
+
o
|
116
|
+
}
|
117
|
+
|
83
118
|
def inspect {
|
84
119
|
str = "<["
|
85
120
|
each: |key val| {
|
@@ -104,4 +139,22 @@ class Hash {
|
|
104
139
|
|
105
140
|
keys map: |k| { at: k }
|
106
141
|
}
|
142
|
+
|
143
|
+
def fetch: key else: else_block {
|
144
|
+
"""
|
145
|
+
@key Key of value to get.
|
146
|
+
@else_block @Block@ that gets called if @key not in @self.
|
147
|
+
|
148
|
+
Example:
|
149
|
+
<['foo => 'bar]> fetch: 'foo else: { 42 } # => 'bar
|
150
|
+
<['foo => 'bar]> fetch: 'unknown else: { 42 } # => 42
|
151
|
+
<['nil => nil]> fetch: 'nil else: { 'not_found } # => nil
|
152
|
+
"""
|
153
|
+
|
154
|
+
if: (includes?: key) then: {
|
155
|
+
at: key
|
156
|
+
} else: {
|
157
|
+
else_block call: [key]
|
158
|
+
}
|
159
|
+
}
|
107
160
|
}
|
data/lib/html.fy
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
class HTML {
|
2
|
+
"""
|
3
|
+
HTML generator class.
|
4
|
+
|
5
|
+
Example:
|
6
|
+
require: \"html\"
|
7
|
+
html = HTML new: @{
|
8
|
+
html: @{
|
9
|
+
head: @{ title: \"My Fancy Website\" }
|
10
|
+
body: @{
|
11
|
+
div: { id: \”main\” } with: \"Hello, Fancy World!\"
|
12
|
+
}
|
13
|
+
}
|
14
|
+
} . to_s
|
15
|
+
|
16
|
+
# html is now:
|
17
|
+
\"\"\"
|
18
|
+
<html>
|
19
|
+
<head>
|
20
|
+
<title>
|
21
|
+
My Fancy Website
|
22
|
+
</title>
|
23
|
+
</head>
|
24
|
+
<body>
|
25
|
+
<div id=\"main\">
|
26
|
+
Hello, Fancy World!
|
27
|
+
</div>
|
28
|
+
</body>
|
29
|
+
</html>
|
30
|
+
\"\"\"
|
31
|
+
|
32
|
+
"""
|
33
|
+
|
34
|
+
def initialize {
|
35
|
+
@buf = ""
|
36
|
+
@indent = 0
|
37
|
+
}
|
38
|
+
|
39
|
+
def initialize: block {
|
40
|
+
initialize
|
41
|
+
block call: [self]
|
42
|
+
}
|
43
|
+
|
44
|
+
def open_tag: name attrs: attrs (<[]>) indent: indent (true) {
|
45
|
+
@buf << "\n"
|
46
|
+
@buf << (" " * @indent)
|
47
|
+
@indent = @indent + 2
|
48
|
+
|
49
|
+
@buf << "<" << name
|
50
|
+
unless: (attrs empty?) do: {
|
51
|
+
@buf << " "
|
52
|
+
attrs each: |k v| {
|
53
|
+
@buf << k << "=" << (v to_s inspect)
|
54
|
+
} in_between: {
|
55
|
+
@buf << " "
|
56
|
+
}
|
57
|
+
}
|
58
|
+
@buf << ">"
|
59
|
+
|
60
|
+
{ @indent = @indent - 2 } unless: indent
|
61
|
+
}
|
62
|
+
|
63
|
+
def close_tag: name {
|
64
|
+
@buf << "\n"
|
65
|
+
@indent = @indent - 2
|
66
|
+
@buf << (" " * @indent)
|
67
|
+
|
68
|
+
@buf << "</" << name << ">"
|
69
|
+
}
|
70
|
+
|
71
|
+
def html_block: tag body: body attrs: attrs (<[]>) {
|
72
|
+
tag = tag from: 0 to: -2
|
73
|
+
open_tag: tag attrs: attrs
|
74
|
+
match body first {
|
75
|
+
case Block -> @buf << (body first call: [self])
|
76
|
+
case _ -> @buf << "\n" << (" " * @indent) << (body first)
|
77
|
+
}
|
78
|
+
close_tag: tag
|
79
|
+
nil
|
80
|
+
}
|
81
|
+
|
82
|
+
def unknown_message: m with_params: p {
|
83
|
+
match m to_s {
|
84
|
+
case /with:$/ ->
|
85
|
+
tag = m to_s substitute: /with:$/ with: ""
|
86
|
+
html_block: tag body: (p rest) attrs: (p first to_hash)
|
87
|
+
case _ ->
|
88
|
+
html_block: (m to_s) body: p
|
89
|
+
}
|
90
|
+
nil
|
91
|
+
}
|
92
|
+
|
93
|
+
def br {
|
94
|
+
@buf << "\n" << (" " * @indent)
|
95
|
+
@buf << "<br/>"
|
96
|
+
nil
|
97
|
+
}
|
98
|
+
|
99
|
+
def input: attrs {
|
100
|
+
open_tag: "input" attrs: (attrs to_hash) indent: false
|
101
|
+
nil
|
102
|
+
}
|
103
|
+
|
104
|
+
def to_s {
|
105
|
+
@buf from: 1 to: -1 . to_s
|
106
|
+
}
|
107
|
+
}
|
data/lib/kvo.fy
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
class KVO {
|
2
|
+
"""
|
3
|
+
Key-Value Observing Mixin class.
|
4
|
+
Include this Class into any class to add support for Key-Value Observing.
|
5
|
+
Inspired by Objective-C's KVO, but using @Block@s, as it fits nicer
|
6
|
+
with Fancy's semantics.
|
7
|
+
|
8
|
+
Example:
|
9
|
+
class Person {
|
10
|
+
include: KVO
|
11
|
+
read_write_slots: ('name, 'age, 'city)
|
12
|
+
}
|
13
|
+
|
14
|
+
tom = Person new tap: @{
|
15
|
+
name: \"Tom Cruise\"
|
16
|
+
age: 55
|
17
|
+
city: \"Hollywood\"
|
18
|
+
}
|
19
|
+
|
20
|
+
tom observe: 'name with: |new old| {
|
21
|
+
new println
|
22
|
+
}
|
23
|
+
tom name: \"Tommy Cruise\" # will cause \"Tommy Cruise\" to be printed
|
24
|
+
tom age: 56 # No observer Blocks defined, so nothing will happen
|
25
|
+
"""
|
26
|
+
|
27
|
+
class ClassMethods {
|
28
|
+
def define_slot_writer: slotname {
|
29
|
+
slotname = slotname to_sym
|
30
|
+
define_method: "#{slotname}:" with: |new_val| {
|
31
|
+
old_val = get_slot: slotname
|
32
|
+
set_slot: slotname value: new_val
|
33
|
+
match new_val {
|
34
|
+
case old_val -> nil # do nothing if no change
|
35
|
+
case _ ->
|
36
|
+
__kvo_slot_change__: slotname new: new_val old: old_val
|
37
|
+
}
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
def define_slot_reader: slotname {
|
42
|
+
slotname = slotname to_sym
|
43
|
+
define_method: slotname with: {
|
44
|
+
val = get_slot: slotname
|
45
|
+
if: (val is_a?: Fancy Enumerable) then: {
|
46
|
+
unless: (val get_slot: '__kvo_wrappers_defined?__) do: {
|
47
|
+
__kvo_wrap_collection_methods__: val for_slot: slotname
|
48
|
+
}
|
49
|
+
}
|
50
|
+
val
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
def KVO included: class {
|
56
|
+
class extend: ClassMethods
|
57
|
+
}
|
58
|
+
|
59
|
+
def observe: slotname with: block {
|
60
|
+
"""
|
61
|
+
@slotname Name of slot to be observed with @block.
|
62
|
+
@block @Block@ to be called with old and new value of @slotname in @self.
|
63
|
+
|
64
|
+
Registers a new observer @Block@ for @slotname in @self.
|
65
|
+
"""
|
66
|
+
|
67
|
+
__kvo_add_observer__: block for: slotname to: __kvo_slot_observers__
|
68
|
+
}
|
69
|
+
|
70
|
+
def observe_insertion: slotname with: block {
|
71
|
+
"""
|
72
|
+
@slotname Name of collection slot to be observed with @block.
|
73
|
+
@block @Block@ to be called with value inserted in collection named @slotname in @self.
|
74
|
+
|
75
|
+
Registers a new insertion observer @Block@ for collection named @slotname in @self.
|
76
|
+
"""
|
77
|
+
|
78
|
+
__kvo_add_observer__: block for: slotname to: __kvo_insertion_observers__
|
79
|
+
}
|
80
|
+
|
81
|
+
def observe_removal: slotname with: block {
|
82
|
+
"""
|
83
|
+
@slotname Name of collection slot to be observed with @block.
|
84
|
+
@block @Block@ to be called with value removed from collection named @slotname in @self.
|
85
|
+
|
86
|
+
Registers a new removal observer @Block@ for collection named @slotname in @self.
|
87
|
+
"""
|
88
|
+
|
89
|
+
__kvo_add_observer__: block for: slotname to: __kvo_removal_observers__
|
90
|
+
}
|
91
|
+
|
92
|
+
# PRIVATE METHODS
|
93
|
+
# OMG this looks FUGLY but this shall never be seen anyway
|
94
|
+
|
95
|
+
def __kvo_slot_observers__ {
|
96
|
+
{ @__kvo_slot_observers__ = <[]> } unless: @__kvo_slot_observers__
|
97
|
+
@__kvo_slot_observers__
|
98
|
+
}
|
99
|
+
|
100
|
+
private: '__kvo_slot_observers__
|
101
|
+
|
102
|
+
def __kvo_insertion_observers__ {
|
103
|
+
{ @__kvo_insertion_observers__ = <[]> } unless: @__kvo_insertion_observers__
|
104
|
+
@__kvo_insertion_observers__
|
105
|
+
}
|
106
|
+
private: '__kvo_insertion_observers__
|
107
|
+
|
108
|
+
def __kvo_removal_observers__ {
|
109
|
+
{ @__kvo_removal_observers__ = <[]> } unless: @__kvo_removal_observers__
|
110
|
+
@__kvo_removal_observers__
|
111
|
+
}
|
112
|
+
private: '__kvo_removal_observers__
|
113
|
+
|
114
|
+
def __kvo_add_observer__: block for: slotname to: observer_list {
|
115
|
+
slotname = slotname to_sym
|
116
|
+
if: (observer_list[slotname]) then: |set| {
|
117
|
+
set << block
|
118
|
+
} else: {
|
119
|
+
observer_list[slotname]: $ Set new: [block]
|
120
|
+
}
|
121
|
+
}
|
122
|
+
private: '__kvo_add_observer__:for:to:
|
123
|
+
|
124
|
+
def __kvo_slot_change__: slotname new: new_val old: old_val {
|
125
|
+
if: (__kvo_slot_observers__[slotname]) then: @{
|
126
|
+
each: @{ call: [new_val, old_val] }
|
127
|
+
}
|
128
|
+
}
|
129
|
+
private: '__kvo_slot_change__:new:old:
|
130
|
+
|
131
|
+
def __kvo_insertion__: value for_slot: slotname {
|
132
|
+
if: (__kvo_insertion_observers__[slotname]) then: @{
|
133
|
+
each: @{ call: [value] }
|
134
|
+
}
|
135
|
+
}
|
136
|
+
|
137
|
+
def __kvo_removal__: value for_slot: slotname {
|
138
|
+
if: (__kvo_removal_observers__[slotname]) then: @{
|
139
|
+
each: @{ call: [value] }
|
140
|
+
}
|
141
|
+
}
|
142
|
+
|
143
|
+
def __kvo_wrap_collection_methods__: collection for_slot: slotname {
|
144
|
+
object = self
|
145
|
+
collection metaclass tap: |c| {
|
146
|
+
try {
|
147
|
+
c alias_method: '__insert__: for: '<<
|
148
|
+
c define_method: '<< with: |val| {
|
149
|
+
__insert__: val
|
150
|
+
object __kvo_insertion__: val for_slot: slotname
|
151
|
+
}
|
152
|
+
} catch {}
|
153
|
+
|
154
|
+
try {
|
155
|
+
c alias_method: '__remove__: for: 'remove:
|
156
|
+
c define_method: 'remove: with: |val| {
|
157
|
+
__remove__: val
|
158
|
+
object __kvo_removal__: val for_slot: slotname
|
159
|
+
}
|
160
|
+
} catch {}
|
161
|
+
|
162
|
+
try {
|
163
|
+
c alias_method: '__remove_at__: for: 'remove_at:
|
164
|
+
c define_method: 'remove_at: with: |index| {
|
165
|
+
obj = __remove_at__: index
|
166
|
+
object __kvo_removal__: obj for_slot: slotname
|
167
|
+
}
|
168
|
+
} catch {}
|
169
|
+
}
|
170
|
+
collection set_slot: '__kvo_wrappers_defined?__ value: true
|
171
|
+
}
|
172
|
+
private: '__kvo_wrap_collection_methods__:for_slot:
|
173
|
+
}
|