functional 0.1.1 → 0.1.3
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 +82 -2
- data/VERSION +1 -1
- data/lib/functional.rb +211 -45
- metadata +8 -6
data/README.md
CHANGED
@@ -8,8 +8,88 @@ Usage
|
|
8
8
|
|
9
9
|
require 'functional'
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
# To demonstrate Functional, we create a Class with a infinite loop:
|
12
|
+
class Sequence
|
13
|
+
include Enumerable
|
14
|
+
def initialize first = 0, step = 1
|
15
|
+
@i, @step = first, step
|
16
|
+
end
|
17
|
+
def each
|
18
|
+
# Our infinite loop:
|
19
|
+
loop do
|
20
|
+
yield @i
|
21
|
+
@i += @step
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
Functional.new( Sequence.new).
|
27
|
+
select {|i| i.even? }.
|
28
|
+
collect {|i| i/3 }.
|
29
|
+
select {|i| i.even?}.
|
30
|
+
collect {|i| [[[[[[i.even?, i.odd?]]], i, [[[[[[i.class]]]]]]]]] }.
|
31
|
+
flatten. # It flattens everything! Not like: collect {|i| i.flatten }.
|
32
|
+
p
|
33
|
+
|
34
|
+
# Without Functional... Bye bye.
|
35
|
+
Sequence.new.
|
36
|
+
select {|i| i.even? }.
|
37
|
+
collect {|i| i/3 }.
|
38
|
+
select {|i| i.even?}.
|
39
|
+
collect {|i| [[[[[[i.even?, i.odd?]]], i, [[[[[[i.class]]]]]]]]] }.
|
40
|
+
flatten. # It flattens everything! Not like: collect {|i| i.flatten }.
|
41
|
+
p
|
42
|
+
|
43
|
+
It will never realize, that #p doesn't exists, because the first select runs endless.
|
44
|
+
Functional#p prints everything to stdout.
|
45
|
+
|
46
|
+
(0..100000).to_fun.
|
47
|
+
collect {|i| i*3 }.
|
48
|
+
select {|i| i%5 == 2 }.
|
49
|
+
to_a
|
50
|
+
|
51
|
+
Thanks to `Symbol#to_proc`:
|
52
|
+
|
53
|
+
Sequence.new.to_fun.
|
54
|
+
select( &:even?).
|
55
|
+
collect {|i| i/3 }.
|
56
|
+
select( &:even?).
|
57
|
+
collect {|i| [[[[[[i.even?, i.odd?]]], i, [[[[[[i.class]]]]]]]]] }.
|
58
|
+
flatten. # It flattens everything! Not like: collect {|i| i.flatten }.
|
59
|
+
p
|
60
|
+
|
61
|
+
If you know methodphitamine, combine it:
|
62
|
+
|
63
|
+
require 'methodphitamine'
|
64
|
+
|
65
|
+
Sequence.new.to_fun.
|
66
|
+
select( &it.even?).
|
67
|
+
collect( &it/3).
|
68
|
+
select( &it.even?).
|
69
|
+
collect {|i| [[[[[[i.even?, i.odd?]]], i, [[[[[[i.class]]]]]]]]] }.
|
70
|
+
flatten.
|
71
|
+
p
|
72
|
+
|
73
|
+
(0..100000).to_fun.
|
74
|
+
collect( &it*3).
|
75
|
+
select( &it%5 == 2).
|
76
|
+
to_a
|
77
|
+
|
78
|
+
Makros
|
79
|
+
======
|
80
|
+
|
81
|
+
seq = Sequence.new.to_fun
|
82
|
+
seq = seq.select &it.even? if must_be_even
|
83
|
+
seq = seq.
|
84
|
+
collect( &it/3).
|
85
|
+
select( &it.even?).
|
86
|
+
collect {|i| [[[[[[i.even?, i.odd?]]], i, [[[[[[i.class]]]]]]]]] }
|
87
|
+
seq = seq.flatten if please_flatten
|
88
|
+
if print_it
|
89
|
+
seq.p
|
90
|
+
else
|
91
|
+
seq_to_a
|
92
|
+
end
|
13
93
|
|
14
94
|
What's with _#map_?
|
15
95
|
=================
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.3
|
data/lib/functional.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
class ::Regexp
|
3
2
|
class NegRegexp
|
4
3
|
def initialize r
|
@@ -21,57 +20,100 @@ class ::Regexp
|
|
21
20
|
end
|
22
21
|
|
23
22
|
class ::Object
|
24
|
-
def
|
23
|
+
def to_fun meth = nil
|
25
24
|
Functional.new self, meth
|
26
25
|
end
|
27
|
-
|
26
|
+
end
|
27
|
+
|
28
|
+
class Counter
|
29
|
+
include Enumerable
|
30
|
+
attr_reader :c
|
31
|
+
|
32
|
+
def initialize first = nil, step = nil
|
33
|
+
@c, @step = first || 0, step || 1
|
34
|
+
end
|
35
|
+
|
36
|
+
def next; @c += @step end
|
37
|
+
def to_i; c.to_i end
|
38
|
+
def to_f; c.to_f end
|
39
|
+
|
40
|
+
def + i
|
41
|
+
@c += @step*i
|
42
|
+
end
|
43
|
+
|
44
|
+
def each &e
|
45
|
+
loop { e.call self; self.next }
|
46
|
+
end
|
28
47
|
end
|
29
48
|
|
30
49
|
class Functional
|
31
50
|
include Enumerable
|
32
51
|
|
52
|
+
class DEFAULT
|
53
|
+
end
|
54
|
+
|
33
55
|
class Base
|
34
56
|
attr_reader :exe
|
35
57
|
attr_accessor :next
|
58
|
+
attr_reader :caller
|
59
|
+
|
36
60
|
def initialize &e
|
61
|
+
@caller = Kernel.caller.first
|
37
62
|
@exe = e
|
38
63
|
end
|
39
64
|
|
40
|
-
def
|
65
|
+
def base_fun *a
|
41
66
|
@next.call *a
|
42
67
|
end
|
68
|
+
alias call base_fun
|
43
69
|
|
44
70
|
def end
|
45
71
|
@next.end
|
46
72
|
end
|
47
73
|
|
74
|
+
def clean
|
75
|
+
@next.clean
|
76
|
+
end
|
77
|
+
|
48
78
|
def to_proc
|
49
79
|
method( :call).to_proc
|
50
80
|
end
|
51
81
|
end
|
52
82
|
|
53
83
|
class Collect <Base
|
54
|
-
def
|
84
|
+
def collect_fun *a
|
55
85
|
@next.call *@exe.call( *a)
|
56
86
|
end
|
87
|
+
alias call collect_fun
|
88
|
+
end
|
89
|
+
|
90
|
+
class Tap <Base
|
91
|
+
def tap_fun *a
|
92
|
+
@exe.call *a
|
93
|
+
@next.call *a
|
94
|
+
end
|
95
|
+
alias call tap_fun
|
57
96
|
end
|
58
97
|
|
59
98
|
class Select <Base
|
60
|
-
def
|
99
|
+
def select_fun *a
|
61
100
|
@next.call *a if @exe.call *a
|
62
101
|
end
|
102
|
+
alias call select_fun
|
63
103
|
end
|
64
104
|
|
65
|
-
class
|
66
|
-
def
|
105
|
+
class Filter <Base
|
106
|
+
def filter_fun *a
|
67
107
|
@next.call *a unless @exe.call *a
|
68
108
|
end
|
109
|
+
alias call filter_fun
|
69
110
|
end
|
70
111
|
|
71
112
|
class Compact <Base
|
72
|
-
def
|
113
|
+
def compact_fun *a
|
73
114
|
@next.call *a unless a.empty? || [nil] == a
|
74
115
|
end
|
116
|
+
alias call compact_fun
|
75
117
|
end
|
76
118
|
|
77
119
|
class BottomUp <Base
|
@@ -80,7 +122,7 @@ class Functional
|
|
80
122
|
@buffer, @start = nil, start
|
81
123
|
end
|
82
124
|
|
83
|
-
def
|
125
|
+
def bottom_up_fun a
|
84
126
|
if @exe.call a
|
85
127
|
@next.call @buffer+a
|
86
128
|
@buffer = @start.dup
|
@@ -88,6 +130,7 @@ class Functional
|
|
88
130
|
@buffer += a
|
89
131
|
end
|
90
132
|
end
|
133
|
+
alias call bottom_up_fun
|
91
134
|
|
92
135
|
def end
|
93
136
|
@next.call @buffer
|
@@ -101,7 +144,7 @@ class Functional
|
|
101
144
|
@buffer, @start = nil, start
|
102
145
|
end
|
103
146
|
|
104
|
-
def
|
147
|
+
def top_down_fun a
|
105
148
|
if @exe.call a
|
106
149
|
@next.call @buffer
|
107
150
|
@buffer = @start.dup+a
|
@@ -109,6 +152,7 @@ class Functional
|
|
109
152
|
@buffer += a
|
110
153
|
end
|
111
154
|
end
|
155
|
+
alias call top_down_fun
|
112
156
|
|
113
157
|
def end
|
114
158
|
@next.call @buffer
|
@@ -120,6 +164,7 @@ class Functional
|
|
120
164
|
def end
|
121
165
|
nil
|
122
166
|
end
|
167
|
+
alias :clean :end
|
123
168
|
end
|
124
169
|
|
125
170
|
class P <Each
|
@@ -130,16 +175,17 @@ class Functional
|
|
130
175
|
|
131
176
|
class Inject <Base
|
132
177
|
attr_reader :it
|
178
|
+
alias :end :it
|
179
|
+
|
133
180
|
def initialize start, *a, &e
|
134
181
|
super *a, &e
|
135
182
|
@it = start
|
136
183
|
end
|
137
|
-
|
184
|
+
|
185
|
+
def inject_fun *a
|
138
186
|
@it = @exe.call @it, *a
|
139
187
|
end
|
140
|
-
|
141
|
-
@it
|
142
|
-
end
|
188
|
+
alias call inject_fun
|
143
189
|
end
|
144
190
|
|
145
191
|
class To_a <Inject
|
@@ -149,21 +195,36 @@ class Functional
|
|
149
195
|
end
|
150
196
|
|
151
197
|
class Map <Collect
|
152
|
-
def
|
198
|
+
def map_fun *a
|
153
199
|
@exe.call *a, &@next
|
154
200
|
end
|
201
|
+
alias call map_fun
|
202
|
+
end
|
203
|
+
|
204
|
+
class Flatten <Base
|
205
|
+
def flatten_fun *a
|
206
|
+
a.each &@next.method( :call)
|
207
|
+
end
|
208
|
+
alias call flatten_fun
|
155
209
|
end
|
156
210
|
|
157
211
|
class Reduce <Base
|
158
|
-
def initialize iv, *a, &
|
159
|
-
super *a, &
|
160
|
-
|
161
|
-
@buf
|
212
|
+
def initialize iv = ::Functional::DEFAULT, *a, &exe
|
213
|
+
super *a, &exe
|
214
|
+
iv = Array.method :new if ::Functional::DEFAULT == iv
|
215
|
+
@buf = if iv.kind_of?( ::Proc) || iv.kind_of?( ::Method)
|
216
|
+
p default: :proc, iv: iv
|
217
|
+
Hash.new {|h,k| h[k] = iv.call }
|
218
|
+
else
|
219
|
+
p default: :value, iv: iv
|
220
|
+
{}.tap {|h| h.default = iv }
|
221
|
+
end
|
162
222
|
end
|
163
223
|
|
164
|
-
def
|
224
|
+
def reduce_fun *a
|
165
225
|
@buf[ a[0]] = @exe.call @buf[ a[0]], *a[1..-1]
|
166
226
|
end
|
227
|
+
alias call reduce_fun
|
167
228
|
|
168
229
|
def end
|
169
230
|
@buf.each {|i| @next.call *i}
|
@@ -171,6 +232,83 @@ class Functional
|
|
171
232
|
end
|
172
233
|
end
|
173
234
|
|
235
|
+
class Slice <Base
|
236
|
+
def initialize n
|
237
|
+
@buf, @n = [], n
|
238
|
+
end
|
239
|
+
|
240
|
+
def slice_fun *a
|
241
|
+
@buf.push a
|
242
|
+
unless @n > @buf.size
|
243
|
+
@next.call @buf
|
244
|
+
@buf.clear
|
245
|
+
end
|
246
|
+
end
|
247
|
+
alias call slice_fun
|
248
|
+
|
249
|
+
def end
|
250
|
+
@next.call @buf
|
251
|
+
@next.end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
class Cons <Base
|
256
|
+
def initialize n
|
257
|
+
@buf, @n = [], n
|
258
|
+
end
|
259
|
+
|
260
|
+
def cons_fun *a
|
261
|
+
@buf.push a
|
262
|
+
unless @n > @buf.size
|
263
|
+
class <<self
|
264
|
+
def call *a
|
265
|
+
@buf.push a
|
266
|
+
@next.call @buf
|
267
|
+
@buf.shift
|
268
|
+
end
|
269
|
+
end
|
270
|
+
@next.call @buf
|
271
|
+
@buf.shift
|
272
|
+
end
|
273
|
+
end
|
274
|
+
alias call cons_fun
|
275
|
+
|
276
|
+
def end
|
277
|
+
@next.call @buf unless @n > @buf.size
|
278
|
+
@next.end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
class Pager <Base
|
283
|
+
def initialize *opts
|
284
|
+
@pager = IO.popen ENV['PAGER'] || 'less', 'w'
|
285
|
+
opts.each do |opt|
|
286
|
+
case opt.to_s
|
287
|
+
when *%w[inspect i] then alias call call_inspect
|
288
|
+
else raise ArgumentError, "Unknown opt: #{opt}"
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
def call_inspect *a
|
294
|
+
@pager.puts a.inspect
|
295
|
+
end
|
296
|
+
|
297
|
+
def pager_fun *a
|
298
|
+
@pager.puts a
|
299
|
+
end
|
300
|
+
alias call pager_fun
|
301
|
+
|
302
|
+
def clean
|
303
|
+
@pager.close
|
304
|
+
end
|
305
|
+
|
306
|
+
def end
|
307
|
+
clean
|
308
|
+
nil
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
174
312
|
attr_accessor :next, :stack, :obj, :func, :args
|
175
313
|
|
176
314
|
def initialize obj = nil, func = nil, *args
|
@@ -190,7 +328,7 @@ class Functional
|
|
190
328
|
push Map.new( &exe)
|
191
329
|
end
|
192
330
|
|
193
|
-
def reduce iv, &exe
|
331
|
+
def reduce iv = ::Functional::DEFAULT, &exe
|
194
332
|
push Reduce.new( iv, &exe)
|
195
333
|
end
|
196
334
|
|
@@ -202,8 +340,8 @@ class Functional
|
|
202
340
|
push Select.new( &re.method( :match))
|
203
341
|
end
|
204
342
|
|
205
|
-
def
|
206
|
-
push
|
343
|
+
def filter &exe
|
344
|
+
push Filter.new( &exe)
|
207
345
|
end
|
208
346
|
|
209
347
|
def compact
|
@@ -218,6 +356,10 @@ class Functional
|
|
218
356
|
push TopDown.new( init, &exe)
|
219
357
|
end
|
220
358
|
|
359
|
+
def flatten &exe
|
360
|
+
push Flatten.new
|
361
|
+
end
|
362
|
+
|
221
363
|
def each &exe
|
222
364
|
return self unless exe
|
223
365
|
push Each.new
|
@@ -233,37 +375,61 @@ class Functional
|
|
233
375
|
def run
|
234
376
|
@obj.send @func||:each, *@args, &@next #.method(:call)
|
235
377
|
@next.end
|
378
|
+
rescue Object
|
379
|
+
@next.clean
|
380
|
+
raise $!
|
236
381
|
end
|
237
382
|
|
238
383
|
def p
|
239
|
-
each
|
384
|
+
each &Kernel.method( :p)
|
240
385
|
end
|
241
|
-
end
|
242
386
|
|
243
|
-
|
244
|
-
|
387
|
+
def pager *opts
|
388
|
+
push Pager.new( *opts)
|
389
|
+
run
|
390
|
+
end
|
245
391
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
alias emit putdup
|
250
|
-
alias call emit
|
251
|
-
end
|
392
|
+
def sort &exe
|
393
|
+
to_a.sort &exe
|
394
|
+
end
|
252
395
|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
396
|
+
def sort_by &exe
|
397
|
+
to_a.sort_by &exe
|
398
|
+
end
|
399
|
+
|
400
|
+
# [ _A, _B, ..., _C, ..., _D ] ==> [ [0, _A], [1, _B], ..., [_I, _C], ..., [_N, _D]]
|
401
|
+
# [ [_A|_As], [_B|_Bs], ..., [_C|_Cs], ..., [_D|_Ds] ] ==> [ [0,_A|_As], [1,_B|_Bs], ..., [_I,_C|_Cs], ..., [_N,_D|_Ds] ]
|
402
|
+
def with_index &exe
|
403
|
+
i = 0
|
404
|
+
exe ||= Array.method :[]
|
405
|
+
push Collect.new {|*a| exe.call i, *a }
|
406
|
+
end
|
407
|
+
|
408
|
+
def slice n, &e
|
409
|
+
push Slice.new( n)
|
410
|
+
push Collect.new( &e) if e
|
411
|
+
self
|
412
|
+
end
|
413
|
+
|
414
|
+
def cons n, &e
|
415
|
+
push Cons.new( n)
|
416
|
+
push Collect.new( &e) if e
|
417
|
+
self
|
418
|
+
end
|
419
|
+
|
420
|
+
class Save < Base
|
421
|
+
attr_reader :db
|
257
422
|
|
258
|
-
def
|
259
|
-
|
423
|
+
def initialize db
|
424
|
+
@db = db
|
260
425
|
end
|
261
426
|
|
262
|
-
def
|
263
|
-
|
427
|
+
def call k, *v
|
428
|
+
@db[ k] = v.length == 1 ? v.first : v
|
264
429
|
end
|
265
430
|
end
|
266
431
|
|
267
|
-
|
268
|
-
|
269
|
-
end
|
432
|
+
def save db
|
433
|
+
push Save.new( db)
|
434
|
+
end
|
435
|
+
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 3
|
9
|
+
version: 0.1.3
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Denis Knauf
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date:
|
17
|
+
date: 2011-11-24 00:00:00 +01:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|
@@ -38,11 +38,12 @@ homepage: http://github.com/DenisKnauf/functional
|
|
38
38
|
licenses: []
|
39
39
|
|
40
40
|
post_install_message:
|
41
|
-
rdoc_options:
|
42
|
-
|
41
|
+
rdoc_options: []
|
42
|
+
|
43
43
|
require_paths:
|
44
44
|
- lib
|
45
45
|
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
none: false
|
46
47
|
requirements:
|
47
48
|
- - ">="
|
48
49
|
- !ruby/object:Gem::Version
|
@@ -50,6 +51,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
50
51
|
- 0
|
51
52
|
version: "0"
|
52
53
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
53
55
|
requirements:
|
54
56
|
- - ">="
|
55
57
|
- !ruby/object:Gem::Version
|
@@ -59,7 +61,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
59
61
|
requirements: []
|
60
62
|
|
61
63
|
rubyforge_project:
|
62
|
-
rubygems_version: 1.3.
|
64
|
+
rubygems_version: 1.3.7
|
63
65
|
signing_key:
|
64
66
|
specification_version: 3
|
65
67
|
summary: Makes big functional operations possible
|