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.
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