rupture 0.1.0 → 0.2.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/.gitignore +3 -0
- data/.rbenv-version +1 -0
- data/Gemfile +3 -0
- data/README.md +4 -1
- data/Rakefile +2 -28
- data/VERSION +1 -1
- data/lib/rupture/array_seq.rb +0 -1
- data/lib/rupture/cons.rb +1 -1
- data/lib/rupture/core_ext.rb +14 -0
- data/lib/rupture/fn.rb +31 -5
- data/lib/rupture/function.rb +77 -17
- data/lib/rupture/hash_map.rb +47 -0
- data/lib/rupture/lazy_seq.rb +2 -3
- data/lib/rupture/list.rb +3 -5
- data/lib/rupture/map.rb +38 -0
- data/lib/rupture/meta.rb +1 -1
- data/lib/rupture/rails_ext.rb +20 -0
- data/lib/rupture/reader.rb +11 -11
- data/lib/rupture/seq.rb +15 -20
- data/lib/rupture/sequence.rb +57 -16
- data/lib/rupture.rb +2 -0
- data/rupture.gemspec +18 -59
- data/test/fn_test.rb +5 -0
- data/test/function_test.rb +66 -0
- data/test/map_test.rb +37 -0
- data/test/seq_test.rb +22 -4
- data/test/test_helper.rb +1 -1
- metadata +86 -16
- data/init.rb +0 -1
data/.gitignore
ADDED
data/.rbenv-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ree-1.8.7-2012.02
|
data/Gemfile
ADDED
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -1,36 +1,10 @@
|
|
1
|
-
require 'rake'
|
2
1
|
require 'rake/testtask'
|
3
|
-
require '
|
4
|
-
|
5
|
-
begin
|
6
|
-
require 'jeweler'
|
7
|
-
Jeweler::Tasks.new do |s|
|
8
|
-
s.name = "rupture"
|
9
|
-
s.summary = %Q{Clojure sequence functions for Ruby.}
|
10
|
-
s.email = "code@justinbalthrop.com"
|
11
|
-
s.homepage = "http://github.com/flatland/rupture"
|
12
|
-
s.description = "Clojure sequence functions for Ruby."
|
13
|
-
s.authors = ["Justin Balthrop"]
|
14
|
-
end
|
15
|
-
Jeweler::GemcutterTasks.new
|
16
|
-
rescue LoadError
|
17
|
-
puts "Jeweler not available. Install it with: sudo gem install jeweler"
|
18
|
-
end
|
2
|
+
require 'bundler/gem_tasks'
|
19
3
|
|
20
4
|
Rake::TestTask.new do |t|
|
21
|
-
t.libs
|
5
|
+
t.libs = ['lib']
|
22
6
|
t.pattern = 'test/**/*_test.rb'
|
23
7
|
t.verbose = false
|
24
8
|
end
|
25
9
|
|
26
|
-
begin
|
27
|
-
require 'rcov/rcovtask'
|
28
|
-
Rcov::RcovTask.new do |t|
|
29
|
-
t.libs << 'test'
|
30
|
-
t.test_files = FileList['test/**/*_test.rb']
|
31
|
-
t.verbose = true
|
32
|
-
end
|
33
|
-
rescue LoadError
|
34
|
-
end
|
35
|
-
|
36
10
|
task :default => :test
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/lib/rupture/array_seq.rb
CHANGED
data/lib/rupture/cons.rb
CHANGED
data/lib/rupture/core_ext.rb
CHANGED
data/lib/rupture/fn.rb
CHANGED
@@ -17,8 +17,28 @@ module Rupture
|
|
17
17
|
alias * comp
|
18
18
|
|
19
19
|
def partial(*partials)
|
20
|
+
lambda do |*args, &block|
|
21
|
+
call(*(partials + args), &block)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def rpartial(*partials)
|
26
|
+
lambda do |*args, &block|
|
27
|
+
call(*(args + partials), &block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def <<(partials)
|
32
|
+
partial(*partials)
|
33
|
+
end
|
34
|
+
|
35
|
+
def >>(partials)
|
36
|
+
rpartial(*partials)
|
37
|
+
end
|
38
|
+
|
39
|
+
def block(&block)
|
20
40
|
lambda do |*args|
|
21
|
-
call(*
|
41
|
+
call(*args, &block)
|
22
42
|
end
|
23
43
|
end
|
24
44
|
|
@@ -27,9 +47,15 @@ module Rupture
|
|
27
47
|
# call(*F.concat(args, last))
|
28
48
|
# end
|
29
49
|
|
50
|
+
def fnil(*defaults)
|
51
|
+
lambda do |*args|
|
52
|
+
call(*F.map(args, defaults) {|a,d| a.nil? ? d : a})
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
30
56
|
def to_proc
|
31
57
|
lambda do |key|
|
32
|
-
|
58
|
+
call(key)
|
33
59
|
end
|
34
60
|
end
|
35
61
|
|
@@ -50,8 +76,8 @@ end
|
|
50
76
|
class Symbol
|
51
77
|
include Rupture::Fn
|
52
78
|
|
53
|
-
def call(object
|
54
|
-
object.method(self)
|
79
|
+
def call(object, *args, &block)
|
80
|
+
object.method(self).call(*args, &block)
|
55
81
|
end
|
56
82
|
alias [] call
|
57
83
|
|
@@ -82,7 +108,7 @@ end
|
|
82
108
|
class Module
|
83
109
|
def [](method_name, *partials)
|
84
110
|
lambda do |*args|
|
85
|
-
self.send(method_name, *(
|
111
|
+
self.send(method_name, *(partials + args))
|
86
112
|
end
|
87
113
|
end
|
88
114
|
end
|
data/lib/rupture/function.rb
CHANGED
@@ -1,15 +1,12 @@
|
|
1
1
|
module Rupture
|
2
2
|
module Function
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
firsts = seqs.collect(&:first)
|
11
|
-
rests = seqs.collect(&:rest)
|
12
|
-
cons(f[*firsts], map(*rests, &f))
|
3
|
+
def map(*colls, &fn)
|
4
|
+
fn ||= colls.shift
|
5
|
+
lazy_loop(colls.seq.map(:seq)) do |recur, seqs|
|
6
|
+
if seqs.every?
|
7
|
+
firsts = seqs.map(:first)
|
8
|
+
nexts = seqs.map(:next)
|
9
|
+
cons(fn[*firsts], recur[nexts])
|
13
10
|
end
|
14
11
|
end
|
15
12
|
end
|
@@ -25,9 +22,9 @@ module Rupture
|
|
25
22
|
end
|
26
23
|
end
|
27
24
|
|
28
|
-
def mapcat(*colls, &
|
29
|
-
|
30
|
-
concat(*map(*colls, &
|
25
|
+
def mapcat(*colls, &fn)
|
26
|
+
fn ||= colls.shift
|
27
|
+
concat(*map(*colls, &fn))
|
31
28
|
end
|
32
29
|
|
33
30
|
def zip(*colls)
|
@@ -41,6 +38,20 @@ module Rupture
|
|
41
38
|
end
|
42
39
|
end
|
43
40
|
|
41
|
+
def filter(pred, coll)
|
42
|
+
lazy_seq do
|
43
|
+
if s = coll.seq
|
44
|
+
e = s.first
|
45
|
+
tail = filter(pred, s.rest)
|
46
|
+
pred[e] ? cons(e, tail) : tail
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def remove(pred, coll)
|
52
|
+
filter(pred.complement, coll)
|
53
|
+
end
|
54
|
+
|
44
55
|
def loop(*vals)
|
45
56
|
more = true
|
46
57
|
recur = lambda {|*vals| more = true}
|
@@ -52,12 +63,19 @@ module Rupture
|
|
52
63
|
result
|
53
64
|
end
|
54
65
|
|
55
|
-
def
|
56
|
-
|
66
|
+
def lazy_loop(*vals, &block)
|
67
|
+
recur = lambda do |*v|
|
68
|
+
lazy_seq {block[recur, *v]}
|
69
|
+
end
|
70
|
+
recur[*vals]
|
71
|
+
end
|
72
|
+
|
73
|
+
def iterate(*args, &fn)
|
74
|
+
fn ||= args.shift
|
57
75
|
Utils.verify_args(args, 1)
|
58
76
|
x = args.first
|
59
77
|
lazy_seq do
|
60
|
-
cons(x, iterate(
|
78
|
+
cons(x, iterate(fn[x], &fn))
|
61
79
|
end
|
62
80
|
end
|
63
81
|
|
@@ -83,7 +101,7 @@ module Rupture
|
|
83
101
|
|
84
102
|
def lazy_seq(f = nil, &fn)
|
85
103
|
fn ||= f
|
86
|
-
LazySeq.new(
|
104
|
+
LazySeq.new(fn)
|
87
105
|
end
|
88
106
|
|
89
107
|
def cons(head, tail)
|
@@ -94,6 +112,19 @@ module Rupture
|
|
94
112
|
List.new(*xs)
|
95
113
|
end
|
96
114
|
|
115
|
+
def hash_map(*kvs, &block)
|
116
|
+
h = block_given? ? HashMap.new(&block) : HashMap.empty
|
117
|
+
if kvs.size == 1
|
118
|
+
h.into(kvs.first)
|
119
|
+
else
|
120
|
+
h.assoc(*kvs)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def constantly(x)
|
125
|
+
lambda {x}
|
126
|
+
end
|
127
|
+
|
97
128
|
def identity(x)
|
98
129
|
x
|
99
130
|
end
|
@@ -108,6 +139,35 @@ module Rupture
|
|
108
139
|
juxt(identity, *args)
|
109
140
|
end
|
110
141
|
|
142
|
+
def let(*vals)
|
143
|
+
yield(*vals)
|
144
|
+
end
|
145
|
+
|
146
|
+
def fix(val, pred, f = nil, &fn)
|
147
|
+
fn ||= f
|
148
|
+
pred = pred.to_proc[val] if pred.respond_to?(:to_proc)
|
149
|
+
pred ? fn[val] : val
|
150
|
+
end
|
151
|
+
|
152
|
+
def when_let(val)
|
153
|
+
yield(val) if val
|
154
|
+
end
|
155
|
+
|
156
|
+
def for(s, *seqs, &fn)
|
157
|
+
if seqs.empty?
|
158
|
+
s.seq.map(&fn)
|
159
|
+
else
|
160
|
+
lazy_seq do
|
161
|
+
tails = self.for(*seqs) {|*args| args}
|
162
|
+
s.seq.mapcat do |head|
|
163
|
+
tails.map do |tail|
|
164
|
+
fn[head, *tail]
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
111
171
|
extend Function
|
112
172
|
F = Function
|
113
173
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'hamster'
|
2
|
+
|
3
|
+
module Rupture
|
4
|
+
class HashMap < Hamster::Hash
|
5
|
+
include Map
|
6
|
+
|
7
|
+
def as_map
|
8
|
+
self
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.empty
|
12
|
+
@empty ||= HashMap.new
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Hash
|
18
|
+
include Rupture::Map
|
19
|
+
|
20
|
+
def as_map
|
21
|
+
F.hash_map(self)
|
22
|
+
end
|
23
|
+
alias ~ as_map
|
24
|
+
|
25
|
+
def assoc!(*vals)
|
26
|
+
vals.each_slice(2) do |k,v|
|
27
|
+
self[k] = v
|
28
|
+
end
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def update!(key, fn = nil, *args, &block)
|
33
|
+
self[key] = if fn
|
34
|
+
fn.call(self[key], *args, &block)
|
35
|
+
else
|
36
|
+
yield(self[key])
|
37
|
+
end
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def update_each!(keys, *args, &block)
|
42
|
+
keys.each do |key|
|
43
|
+
update!(key, *args, &block)
|
44
|
+
end
|
45
|
+
self
|
46
|
+
end
|
47
|
+
end
|
data/lib/rupture/lazy_seq.rb
CHANGED
data/lib/rupture/list.rb
CHANGED
@@ -6,17 +6,13 @@ module Rupture
|
|
6
6
|
private_class_method :create
|
7
7
|
attr_reader :seq, :size
|
8
8
|
|
9
|
-
def self.empty
|
10
|
-
@empty ||= create(nil, 0)
|
11
|
-
end
|
12
|
-
|
13
9
|
def initialize(seq, size)
|
14
10
|
@seq = seq.seq
|
15
11
|
@size = size
|
16
12
|
end
|
17
13
|
|
18
14
|
def self.new(*args)
|
19
|
-
list =
|
15
|
+
list = Empty
|
20
16
|
args.reverse_each do |x|
|
21
17
|
list = list.conj(x)
|
22
18
|
end
|
@@ -27,5 +23,7 @@ module Rupture
|
|
27
23
|
def conj(x)
|
28
24
|
self.class.send(:create, Cons.new(x, @seq), @size.inc)
|
29
25
|
end
|
26
|
+
|
27
|
+
Empty = create(nil, 0)
|
30
28
|
end
|
31
29
|
end
|
data/lib/rupture/map.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
module Rupture
|
2
|
+
module Map
|
3
|
+
def map?
|
4
|
+
true
|
5
|
+
end
|
6
|
+
|
7
|
+
def assoc(*kvs)
|
8
|
+
into(kvs.seq.partition(2))
|
9
|
+
end
|
10
|
+
|
11
|
+
def into(other)
|
12
|
+
other.seq.reduce(as_map) do |map, (k,v)|
|
13
|
+
map.put(k,v)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def update(key, fn = nil, *args, &block)
|
18
|
+
if fn
|
19
|
+
assoc(key, fn.call(self[key], *args, &block))
|
20
|
+
else
|
21
|
+
assoc(key, yield(self[key]))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def update_each(keys, *args, &block)
|
26
|
+
map = as_map
|
27
|
+
keys.each do |key|
|
28
|
+
update(key, *args, &block)
|
29
|
+
end
|
30
|
+
map
|
31
|
+
end
|
32
|
+
|
33
|
+
def destruct(*keys)
|
34
|
+
vals = keys.seq.map(self)
|
35
|
+
block_given? ? yield(*vals) : vals
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/rupture/meta.rb
CHANGED
@@ -5,7 +5,7 @@ module Rupture::Meta
|
|
5
5
|
|
6
6
|
def clone(meta = nil)
|
7
7
|
meta ||= @_meta.clone if @_meta
|
8
|
-
raise "meta must be of type Hash, it is #{meta.class}" unless meta.nil? or meta.kind_of?(Hash)
|
8
|
+
raise "meta must be of type Hash, it is #{meta.class}" unless meta.nil? or meta.kind_of?(Hash) or meta.kind_of?(Rupture::HashMap)
|
9
9
|
copy = super()
|
10
10
|
copy.instance_variable_set(:@_meta, meta)
|
11
11
|
copy
|
data/lib/rupture/rails_ext.rb
CHANGED
@@ -36,3 +36,23 @@ class Hash
|
|
36
36
|
dup.stringify_keys!
|
37
37
|
end
|
38
38
|
end
|
39
|
+
|
40
|
+
if defined?(HashWithIndifferentAccess)
|
41
|
+
class HashWithIndifferentAccess
|
42
|
+
def to_hash
|
43
|
+
Hash.new(default).merge(self).with_meta(meta)
|
44
|
+
end
|
45
|
+
|
46
|
+
def symbolize_keys
|
47
|
+
to_hash.symbolize_keys!
|
48
|
+
end
|
49
|
+
|
50
|
+
def deep_symbolize_keys
|
51
|
+
to_hash.deep_symbolize_keys!
|
52
|
+
end
|
53
|
+
|
54
|
+
def stringify_keys
|
55
|
+
to_hash.stringify_keys!
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/rupture/reader.rb
CHANGED
@@ -33,22 +33,22 @@ module Rupture
|
|
33
33
|
|
34
34
|
def read
|
35
35
|
case c = getc
|
36
|
-
when '('
|
37
|
-
when '['
|
38
|
-
when '{'
|
39
|
-
when '"'
|
40
|
-
when ':'
|
41
|
-
when ' '
|
42
|
-
when /\d/
|
43
|
-
when /\w/
|
36
|
+
when '(' then read_list
|
37
|
+
when '[' then read_list(Array, ']')
|
38
|
+
when '{' then read_map
|
39
|
+
when '"' then read_string
|
40
|
+
when ':' then read_keyword
|
41
|
+
when ' ' then read
|
42
|
+
when /\d/ then ungetc(c); read_number
|
43
|
+
when /\w/ then ungetc(c); read_symbol
|
44
44
|
when '-'
|
45
45
|
case c = getc
|
46
|
-
when /\d/
|
47
|
-
else
|
46
|
+
when /\d/ then ungetc(c); -read_number
|
47
|
+
else ungetc('-', c); read_symbol
|
48
48
|
end
|
49
49
|
when '#'
|
50
50
|
case c = getc
|
51
|
-
when '{'
|
51
|
+
when '{' then read_list(Set, '}')
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
data/lib/rupture/seq.rb
CHANGED
@@ -1,17 +1,10 @@
|
|
1
1
|
module Rupture
|
2
|
-
class Seq
|
2
|
+
class Seq
|
3
|
+
include Enumerable
|
3
4
|
include Sequence
|
4
5
|
|
5
|
-
def
|
6
|
-
|
7
|
-
end
|
8
|
-
|
9
|
-
def each
|
10
|
-
s = self
|
11
|
-
while s = s.seq
|
12
|
-
yield s.first
|
13
|
-
s = s.rest
|
14
|
-
end
|
6
|
+
def inspect
|
7
|
+
"(#{to_a.collect(&:inspect).join(',')})"
|
15
8
|
end
|
16
9
|
|
17
10
|
def [](index)
|
@@ -22,7 +15,9 @@ module Rupture
|
|
22
15
|
to_a
|
23
16
|
end
|
24
17
|
|
25
|
-
def
|
18
|
+
def eql?(other)
|
19
|
+
return false unless other.respond_to?(:seq)
|
20
|
+
|
26
21
|
s = self.seq
|
27
22
|
o = other.seq
|
28
23
|
while s && o
|
@@ -30,18 +25,18 @@ module Rupture
|
|
30
25
|
s = s.next
|
31
26
|
o = o.next
|
32
27
|
end
|
28
|
+
|
33
29
|
s.nil? and o.nil?
|
34
30
|
end
|
31
|
+
alias == eql?
|
35
32
|
|
36
|
-
|
37
|
-
|
33
|
+
class EmptySeq < Seq
|
34
|
+
def seq
|
35
|
+
nil
|
36
|
+
end
|
38
37
|
end
|
39
|
-
end
|
40
38
|
|
41
|
-
|
42
|
-
def seq
|
43
|
-
nil
|
44
|
-
end
|
39
|
+
Empty = EmptySeq.new
|
45
40
|
end
|
46
41
|
end
|
47
42
|
|
@@ -57,6 +52,6 @@ class NilClass
|
|
57
52
|
end
|
58
53
|
|
59
54
|
def rest
|
60
|
-
Rupture::Seq
|
55
|
+
Rupture::Seq::Empty
|
61
56
|
end
|
62
57
|
end
|
data/lib/rupture/sequence.rb
CHANGED
@@ -24,6 +24,18 @@ module Rupture
|
|
24
24
|
self if seq
|
25
25
|
end
|
26
26
|
|
27
|
+
def divide
|
28
|
+
[first, rest]
|
29
|
+
end
|
30
|
+
|
31
|
+
def each
|
32
|
+
s = self
|
33
|
+
while s = s.seq
|
34
|
+
yield s.first
|
35
|
+
s = s.rest
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
27
39
|
def count
|
28
40
|
F.loop(0, self) do |recur, i, s|
|
29
41
|
if s.empty?
|
@@ -36,10 +48,6 @@ module Rupture
|
|
36
48
|
end
|
37
49
|
end
|
38
50
|
|
39
|
-
def inspect
|
40
|
-
"(#{to_a.collect(&:inspect).join(' ')})"
|
41
|
-
end
|
42
|
-
|
43
51
|
def conj(item)
|
44
52
|
F.cons(item, self)
|
45
53
|
end
|
@@ -49,7 +57,7 @@ module Rupture
|
|
49
57
|
end
|
50
58
|
|
51
59
|
def reverse
|
52
|
-
Seq.
|
60
|
+
Seq::Empty.into(self)
|
53
61
|
end
|
54
62
|
|
55
63
|
def take(n)
|
@@ -77,7 +85,7 @@ module Rupture
|
|
77
85
|
if lead
|
78
86
|
recur[s.next, lead.next]
|
79
87
|
else
|
80
|
-
s || Seq
|
88
|
+
s || Seq::Empty
|
81
89
|
end
|
82
90
|
end
|
83
91
|
end
|
@@ -124,18 +132,12 @@ module Rupture
|
|
124
132
|
|
125
133
|
def filter(p = nil, &pred)
|
126
134
|
pred ||= p
|
127
|
-
F.
|
128
|
-
if s = seq
|
129
|
-
i = s.first
|
130
|
-
tail = s.rest.filter(pred)
|
131
|
-
pred[i] ? F.cons(i, tail) : tail
|
132
|
-
end
|
133
|
-
end
|
135
|
+
F.filter(pred, self)
|
134
136
|
end
|
135
137
|
|
136
138
|
def remove(p = nil, &pred)
|
137
139
|
pred ||= p
|
138
|
-
|
140
|
+
F.remove(pred, self)
|
139
141
|
end
|
140
142
|
|
141
143
|
def separate(p = nil, &pred)
|
@@ -154,7 +156,16 @@ module Rupture
|
|
154
156
|
|
155
157
|
def map(f = nil, &fn)
|
156
158
|
fn ||= f
|
157
|
-
F.
|
159
|
+
F.lazy_loop(seq) do |recur, s|
|
160
|
+
F.cons(fn[s.first], recur[s.next]) if s
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def map_indexed(f = nil, &fn)
|
165
|
+
fn ||= f
|
166
|
+
F.lazy_loop(0, seq) do |recur, i, s|
|
167
|
+
F.cons(fn[i, s.first], recur[i.inc, s.next]) if s
|
168
|
+
end
|
158
169
|
end
|
159
170
|
|
160
171
|
def concat(*colls)
|
@@ -179,6 +190,19 @@ module Rupture
|
|
179
190
|
end
|
180
191
|
end
|
181
192
|
|
193
|
+
def reductions(*args, &fn)
|
194
|
+
fn ||= args.shift
|
195
|
+
Utils.verify_args(args, 0, 1)
|
196
|
+
acc, coll = (args.empty? ? divide : [args.first, self])
|
197
|
+
|
198
|
+
F.lazy_loop(acc, coll) do |recur, acc, coll|
|
199
|
+
if coll.seq
|
200
|
+
acc = fn[acc, coll.first]
|
201
|
+
F.cons(acc, recur[acc, coll.rest])
|
202
|
+
end
|
203
|
+
end.conj(acc)
|
204
|
+
end
|
205
|
+
|
182
206
|
def foldr(*args, &fn)
|
183
207
|
fn ||= args.shift
|
184
208
|
reverse.reduce(*args) {|a,b| fn[b,a]}
|
@@ -253,12 +277,29 @@ module Rupture
|
|
253
277
|
fn ||= f
|
254
278
|
F.lazy_seq do
|
255
279
|
if s = seq
|
256
|
-
run = F.cons(s.first,
|
280
|
+
run = F.cons(s.first,
|
281
|
+
s.partition(2,1).take_while {|i| not fn[*i]}.map(:second))
|
257
282
|
F.cons(run, s.drop(run.count).partition_between(fn))
|
258
283
|
end
|
259
284
|
end
|
260
285
|
end
|
261
286
|
|
287
|
+
def sort(c = nil, &cmp)
|
288
|
+
cmp||= c
|
289
|
+
super(&cmp).seq
|
290
|
+
end
|
291
|
+
|
292
|
+
def sort_by(f = nil, &fn)
|
293
|
+
fn ||= f
|
294
|
+
sort {|a,b| fn[a] <=> fn[b]}
|
295
|
+
end
|
296
|
+
|
297
|
+
def frequencies
|
298
|
+
reduce(Hash.new(0)) do |counts, x|
|
299
|
+
counts.update!(x, :inc)
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
262
303
|
def doall(n = nil)
|
263
304
|
if n
|
264
305
|
loop(n, seq) do |recur, n, s|
|
data/lib/rupture.rb
CHANGED
data/rupture.gemspec
CHANGED
@@ -1,63 +1,22 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
-
# -*- encoding: utf-8 -*-
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
3
|
|
6
|
-
Gem::Specification.new do |
|
7
|
-
|
8
|
-
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.name = "rupture"
|
6
|
+
gem.version = IO.read('VERSION')
|
7
|
+
gem.authors = ["Justin Balthrop", "Alan Malloy"]
|
8
|
+
gem.email = ["git@justinbalthrop.com"]
|
9
|
+
gem.description = %q{Clojure sequence functions for Ruby.}
|
10
|
+
gem.summary = gem.description
|
11
|
+
gem.homepage = "https://github.com/flatland/rupture"
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
s.email = %q{code@justinbalthrop.com}
|
15
|
-
s.extra_rdoc_files = [
|
16
|
-
"LICENSE",
|
17
|
-
"README.md"
|
18
|
-
]
|
19
|
-
s.files = [
|
20
|
-
"LICENSE",
|
21
|
-
"README.md",
|
22
|
-
"Rakefile",
|
23
|
-
"VERSION",
|
24
|
-
"init.rb",
|
25
|
-
"lib/rupture.rb",
|
26
|
-
"lib/rupture/array_seq.rb",
|
27
|
-
"lib/rupture/cons.rb",
|
28
|
-
"lib/rupture/core_ext.rb",
|
29
|
-
"lib/rupture/fn.rb",
|
30
|
-
"lib/rupture/function.rb",
|
31
|
-
"lib/rupture/lazy_seq.rb",
|
32
|
-
"lib/rupture/list.rb",
|
33
|
-
"lib/rupture/lookup.rb",
|
34
|
-
"lib/rupture/meta.rb",
|
35
|
-
"lib/rupture/rails_ext.rb",
|
36
|
-
"lib/rupture/reader.rb",
|
37
|
-
"lib/rupture/seq.rb",
|
38
|
-
"lib/rupture/sequence.rb",
|
39
|
-
"lib/rupture/symbol.rb",
|
40
|
-
"lib/rupture/utils.rb",
|
41
|
-
"rupture.gemspec",
|
42
|
-
"test/fn_test.rb",
|
43
|
-
"test/list_test.rb",
|
44
|
-
"test/meta_test.rb",
|
45
|
-
"test/seq_test.rb",
|
46
|
-
"test/test_helper.rb"
|
47
|
-
]
|
48
|
-
s.homepage = %q{http://github.com/flatland/rupture}
|
49
|
-
s.require_paths = ["lib"]
|
50
|
-
s.rubygems_version = %q{1.3.7}
|
51
|
-
s.summary = %q{Clojure sequence functions for Ruby.}
|
13
|
+
gem.add_development_dependency 'shoulda', '3.0.1'
|
14
|
+
gem.add_development_dependency 'mocha'
|
15
|
+
gem.add_development_dependency 'hamster'
|
16
|
+
gem.add_development_dependency 'rake'
|
52
17
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
58
|
-
else
|
59
|
-
end
|
60
|
-
else
|
61
|
-
end
|
18
|
+
gem.files = `git ls-files`.split($/)
|
19
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
20
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
21
|
+
gem.require_paths = ["lib"]
|
62
22
|
end
|
63
|
-
|
data/test/fn_test.rb
CHANGED
@@ -13,6 +13,11 @@ class FnTest < Test::Unit::TestCase
|
|
13
13
|
# assert_equal [1,2,3,4,5,6].seq, F[:concat].apply([1],[2],[[3,4],[5,6]])
|
14
14
|
# end
|
15
15
|
|
16
|
+
should "fnil replaces nil args" do
|
17
|
+
assert_equal [2,3,4,1,5].seq, [1,2,3,nil,4].seq.map(:inc.fnil(0))
|
18
|
+
assert_equal [1,2,nil,1].seq, [:a,:b,:c,nil].seq.map({:a => 1, :b => 2}.fnil(:a))
|
19
|
+
end
|
20
|
+
|
16
21
|
should "use hash as fn" do
|
17
22
|
assert_equal [1, 2, 3, nil].seq, [:foo, :bar, :baz, :bam].seq.map({:foo => 1, :bar => 2, :baz => 3})
|
18
23
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class FunctionTest < Test::Unit::TestCase
|
4
|
+
should "loop" do
|
5
|
+
n = F.loop(0) do |recur, i|
|
6
|
+
if i < 10
|
7
|
+
recur[i.inc]
|
8
|
+
else
|
9
|
+
i
|
10
|
+
end
|
11
|
+
end
|
12
|
+
assert_equal 10, n
|
13
|
+
end
|
14
|
+
|
15
|
+
should "loop lazily" do
|
16
|
+
s = F.lazy_loop(0) do |recur, i|
|
17
|
+
if i != 10
|
18
|
+
F.cons(i, recur[i.inc])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
assert_equal (0..9).seq, s
|
22
|
+
end
|
23
|
+
|
24
|
+
should "comprehend lists" do
|
25
|
+
assert_equal [[1,3],[1,4],[1,5],[2,3],[2,4],[2,5],[3,3],[3,4],[3,5]].seq,
|
26
|
+
F.for([1,2,3], [3,4,5]) {|a, b| [a,b]}
|
27
|
+
end
|
28
|
+
|
29
|
+
should "let stuff" do
|
30
|
+
a = 0
|
31
|
+
c = F.let(1,2) do |a,b|
|
32
|
+
assert_equal 1, a
|
33
|
+
assert_equal 2, b
|
34
|
+
a + b
|
35
|
+
end
|
36
|
+
assert_equal 3, c
|
37
|
+
|
38
|
+
assert_equal a, 0 if RUBY_VERSION =~ /1.9/ # 1.8 only has lexical scope for functions.
|
39
|
+
|
40
|
+
c = 1.let(2) do |a,b|
|
41
|
+
assert_equal 1, a
|
42
|
+
assert_equal 2, b
|
43
|
+
a + b
|
44
|
+
end
|
45
|
+
assert_equal 3, c
|
46
|
+
|
47
|
+
assert_equal a, 0 if RUBY_VERSION =~ /1.9/ # 1.8 only has lexical scope for functions.
|
48
|
+
end
|
49
|
+
|
50
|
+
should "when_let" do
|
51
|
+
assert_equal nil, F.when_let(false) {|a| a + 1}
|
52
|
+
assert_equal nil, F.when_let(nil) {|a| a + 1}
|
53
|
+
assert_equal 2, F.when_let(1) {|a| a + 1}
|
54
|
+
end
|
55
|
+
|
56
|
+
should "fix stuff" do
|
57
|
+
assert_equal 1, F.fix(1,:even?,:inc)
|
58
|
+
assert_equal 1, 1.fix(:even?,:inc)
|
59
|
+
|
60
|
+
assert_equal 3, F.fix(2,:even?,:inc)
|
61
|
+
assert_equal 3, 2.fix(:even?,:inc)
|
62
|
+
|
63
|
+
assert_equal 12, F.fix(2,:even?) {|i| i + 10}
|
64
|
+
assert_equal 12, 2.fix(:even?) {|i| i + 10}
|
65
|
+
end
|
66
|
+
end
|
data/test/map_test.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class MapTest < Test::Unit::TestCase
|
4
|
+
should "destructure" do
|
5
|
+
a,b,c,d = {:foo => 1, :bar => 3}.destruct(:bar, :foo, :bar, :baz)
|
6
|
+
|
7
|
+
assert_equal 3, a
|
8
|
+
assert_equal 1, b
|
9
|
+
assert_equal 3, c
|
10
|
+
assert_equal nil, d
|
11
|
+
|
12
|
+
{:foo => 1, :bar => 3}.destruct(:bar, :foo, :bar, :baz) do |*args|
|
13
|
+
assert_equal [3, 1, 3, nil], args
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
should "update!" do
|
18
|
+
h = {:foo => 1, :bar => [1,2,3].seq}
|
19
|
+
h.update!(:foo, :inc)
|
20
|
+
|
21
|
+
assert_equal({:foo => 2, :bar => [1,2,3].seq}, h)
|
22
|
+
|
23
|
+
h.update!(:bar, :map) {|i| i + 10}
|
24
|
+
assert_equal({:foo => 2, :bar => [11,12,13].seq}, h)
|
25
|
+
|
26
|
+
h.update!(:foo) {|i| i + 10}
|
27
|
+
assert_equal({:foo => 12, :bar => [11,12,13].seq}, h)
|
28
|
+
end
|
29
|
+
|
30
|
+
should "update" do
|
31
|
+
h = ~{:foo => 1, :bar => [1,2,3].seq}
|
32
|
+
|
33
|
+
assert_equal ~{:foo => 2, :bar => [1,2,3].seq}, h.update(:foo, :inc)
|
34
|
+
assert_equal ~{:foo => 1, :bar => [11,12,13].seq}, h.update(:bar, :map) {|i| i + 10}
|
35
|
+
assert_equal ~{:foo => 11, :bar => [1,2,3].seq}, h.update(:foo) {|i| i + 10}
|
36
|
+
end
|
37
|
+
end
|
data/test/seq_test.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/test_helper'
|
2
2
|
|
3
3
|
class SeqTest < Test::Unit::TestCase
|
4
|
-
empty_seqs = [nil, [], Rupture::Seq
|
4
|
+
empty_seqs = [nil, [], Rupture::Seq::Empty, F.lazy_seq{nil}, F.lazy_seq{[]}]
|
5
5
|
|
6
6
|
def numbers(i)
|
7
7
|
F.lazy_seq { F.cons(i, numbers(i.inc))}
|
@@ -56,9 +56,9 @@ class SeqTest < Test::Unit::TestCase
|
|
56
56
|
end
|
57
57
|
|
58
58
|
should "reverse and rseq" do
|
59
|
-
assert_equal [1,2,3,4].seq,
|
60
|
-
assert_equal [1,2,3,4].seq,
|
61
|
-
assert_equal Rupture::Seq
|
59
|
+
assert_equal [1,2,3,4].seq, [4,3,2,1].seq.reverse
|
60
|
+
assert_equal [1,2,3,4].seq, [4,3,2,1].rseq
|
61
|
+
assert_equal Rupture::Seq::Empty, [].seq.reverse
|
62
62
|
end
|
63
63
|
|
64
64
|
should "count" do
|
@@ -80,6 +80,10 @@ class SeqTest < Test::Unit::TestCase
|
|
80
80
|
assert_equal [9,12,15].seq, [3,4,5].seq.map {|a| a * 3}
|
81
81
|
end
|
82
82
|
|
83
|
+
should "map_indexed" do
|
84
|
+
assert_equal [2,4,6,8].seq, [2,3,4,5].seq.map_indexed {|i, a| i + a}
|
85
|
+
end
|
86
|
+
|
83
87
|
should "concat" do
|
84
88
|
assert_equal [1,2,3,4,5,6].seq, F.concat([1,2],[3,4,5],[6])
|
85
89
|
assert_equal [1,2,3,4,5,6].seq, [1,2].seq.concat([3,4,5],[6])
|
@@ -99,6 +103,11 @@ class SeqTest < Test::Unit::TestCase
|
|
99
103
|
assert_equal 240, [1,2,3,4].seq.reduce(:*, 10)
|
100
104
|
end
|
101
105
|
|
106
|
+
should "reducutions" do
|
107
|
+
assert_equal [1,3,6,10].seq, [1,2,3,4].seq.reductions(:+)
|
108
|
+
assert_equal [10,10,20,60,240].seq, [1,2,3,4].seq.reductions(:*, 10)
|
109
|
+
end
|
110
|
+
|
102
111
|
should "foldr" do
|
103
112
|
assert_equal F.list(1,2,3,4), [1,2,3,4].seq.foldr(F[:cons], nil)
|
104
113
|
end
|
@@ -252,4 +261,13 @@ class SeqTest < Test::Unit::TestCase
|
|
252
261
|
should "partition_between" do
|
253
262
|
assert_equal [[1], [nil, 4, 3], [nil, 8]].seq.map(:seq), [1,nil,4,3,nil,8].seq.partition_between {|a,b| b == nil}
|
254
263
|
end
|
264
|
+
|
265
|
+
should "sort_by" do
|
266
|
+
assert_equal [[:foo,1],[:baz,2],[:bar,5]].seq,
|
267
|
+
[[:foo,1],[:bar,5],[:baz,2]].seq.sort_by(:last)
|
268
|
+
end
|
269
|
+
|
270
|
+
should "calculate frequencies" do
|
271
|
+
assert_equal({1=>3, nil=>2, 2=>1}, [1,nil,2,1,nil,1].seq.frequencies)
|
272
|
+
end
|
255
273
|
end
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,48 +1,110 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rupture
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
5
|
-
prerelease:
|
4
|
+
hash: 23
|
5
|
+
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 2
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Justin Balthrop
|
14
|
+
- Alan Malloy
|
14
15
|
autorequire:
|
15
16
|
bindir: bin
|
16
17
|
cert_chain: []
|
17
18
|
|
18
|
-
date:
|
19
|
+
date: 2013-08-13 00:00:00 -07:00
|
19
20
|
default_executable:
|
20
|
-
dependencies:
|
21
|
-
|
21
|
+
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
name: shoulda
|
24
|
+
prerelease: false
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - "="
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 5
|
31
|
+
segments:
|
32
|
+
- 3
|
33
|
+
- 0
|
34
|
+
- 1
|
35
|
+
version: 3.0.1
|
36
|
+
type: :development
|
37
|
+
version_requirements: *id001
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: mocha
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
hash: 3
|
47
|
+
segments:
|
48
|
+
- 0
|
49
|
+
version: "0"
|
50
|
+
type: :development
|
51
|
+
version_requirements: *id002
|
52
|
+
- !ruby/object:Gem::Dependency
|
53
|
+
name: hamster
|
54
|
+
prerelease: false
|
55
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
hash: 3
|
61
|
+
segments:
|
62
|
+
- 0
|
63
|
+
version: "0"
|
64
|
+
type: :development
|
65
|
+
version_requirements: *id003
|
66
|
+
- !ruby/object:Gem::Dependency
|
67
|
+
name: rake
|
68
|
+
prerelease: false
|
69
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
hash: 3
|
75
|
+
segments:
|
76
|
+
- 0
|
77
|
+
version: "0"
|
78
|
+
type: :development
|
79
|
+
version_requirements: *id004
|
22
80
|
description: Clojure sequence functions for Ruby.
|
23
|
-
email:
|
81
|
+
email:
|
82
|
+
- git@justinbalthrop.com
|
24
83
|
executables: []
|
25
84
|
|
26
85
|
extensions: []
|
27
86
|
|
28
|
-
extra_rdoc_files:
|
29
|
-
|
30
|
-
- README.md
|
87
|
+
extra_rdoc_files: []
|
88
|
+
|
31
89
|
files:
|
90
|
+
- .gitignore
|
91
|
+
- .rbenv-version
|
92
|
+
- Gemfile
|
32
93
|
- LICENSE
|
33
94
|
- README.md
|
34
95
|
- Rakefile
|
35
96
|
- VERSION
|
36
|
-
- init.rb
|
37
97
|
- lib/rupture.rb
|
38
98
|
- lib/rupture/array_seq.rb
|
39
99
|
- lib/rupture/cons.rb
|
40
100
|
- lib/rupture/core_ext.rb
|
41
101
|
- lib/rupture/fn.rb
|
42
102
|
- lib/rupture/function.rb
|
103
|
+
- lib/rupture/hash_map.rb
|
43
104
|
- lib/rupture/lazy_seq.rb
|
44
105
|
- lib/rupture/list.rb
|
45
106
|
- lib/rupture/lookup.rb
|
107
|
+
- lib/rupture/map.rb
|
46
108
|
- lib/rupture/meta.rb
|
47
109
|
- lib/rupture/rails_ext.rb
|
48
110
|
- lib/rupture/reader.rb
|
@@ -52,12 +114,14 @@ files:
|
|
52
114
|
- lib/rupture/utils.rb
|
53
115
|
- rupture.gemspec
|
54
116
|
- test/fn_test.rb
|
117
|
+
- test/function_test.rb
|
55
118
|
- test/list_test.rb
|
119
|
+
- test/map_test.rb
|
56
120
|
- test/meta_test.rb
|
57
121
|
- test/seq_test.rb
|
58
122
|
- test/test_helper.rb
|
59
123
|
has_rdoc: true
|
60
|
-
homepage:
|
124
|
+
homepage: https://github.com/flatland/rupture
|
61
125
|
licenses: []
|
62
126
|
|
63
127
|
post_install_message:
|
@@ -86,9 +150,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
86
150
|
requirements: []
|
87
151
|
|
88
152
|
rubyforge_project:
|
89
|
-
rubygems_version: 1.
|
153
|
+
rubygems_version: 1.5.2
|
90
154
|
signing_key:
|
91
155
|
specification_version: 3
|
92
156
|
summary: Clojure sequence functions for Ruby.
|
93
|
-
test_files:
|
94
|
-
|
157
|
+
test_files:
|
158
|
+
- test/fn_test.rb
|
159
|
+
- test/function_test.rb
|
160
|
+
- test/list_test.rb
|
161
|
+
- test/map_test.rb
|
162
|
+
- test/meta_test.rb
|
163
|
+
- test/seq_test.rb
|
164
|
+
- test/test_helper.rb
|
data/init.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'rupture'
|