functional 0.1.1 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/README.md +82 -2
  2. data/VERSION +1 -1
  3. data/lib/functional.rb +211 -45
  4. metadata +8 -6
data/README.md CHANGED
@@ -8,8 +8,88 @@ Usage
8
8
 
9
9
  require 'functional'
10
10
 
11
- obj = 0 .. 10**12
12
- Functional.new( obj).select {|i| i.even? }.collect {|i| i/3 }.select {|i| i.even? }.each &method( :puts)
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
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 functional meth = nil
23
+ def to_fun meth = nil
25
24
  Functional.new self, meth
26
25
  end
27
- alias to_fun functional
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 call *a
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 call *a
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 call *a
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 DeleteIf <Base
66
- def call *a
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 call *a
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 call a
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 call a
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
- def call *a
184
+
185
+ def inject_fun *a
138
186
  @it = @exe.call @it, *a
139
187
  end
140
- def end
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 call *a
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, &e
159
- super *a, &e
160
- @buf = {}
161
- @buf.default = iv
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 call *a
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 delete_if &exe
206
- push DeleteIf.new( &exe)
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 {|*a|Kernel.p a}
384
+ each &Kernel.method( :p)
240
385
  end
241
- end
242
386
 
243
- begin
244
- require 'tokyocabinet'
387
+ def pager *opts
388
+ push Pager.new( *opts)
389
+ run
390
+ end
245
391
 
246
- class Functional
247
- class Map <Base
248
- class Emit < TokyoCabinet::BDB
249
- alias emit putdup
250
- alias call emit
251
- end
392
+ def sort &exe
393
+ to_a.sort &exe
394
+ end
252
395
 
253
- def call *a
254
- @exe.call( *a).each &@next
255
- end
256
- end
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 map name, &e
259
- push Map.new( name, &e)
423
+ def initialize db
424
+ @db = db
260
425
  end
261
426
 
262
- def Reduce name, &e
263
- push Reduce.new( name, &e)
427
+ def call k, *v
428
+ @db[ k] = v.length == 1 ? v.first : v
264
429
  end
265
430
  end
266
431
 
267
- rescue MissingSourceFile
268
- # TokyoCabinet not installed?
269
- end if false
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
- - 1
9
- version: 0.1.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: 2010-05-25 00:00:00 +02:00
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
- - --charset=UTF-8
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.6
64
+ rubygems_version: 1.3.7
63
65
  signing_key:
64
66
  specification_version: 3
65
67
  summary: Makes big functional operations possible