rupture 0.0.0 → 0.1.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/README.md +17 -0
- data/Rakefile +2 -10
- data/VERSION +1 -1
- data/init.rb +1 -0
- data/lib/rupture/array_seq.rb +65 -0
- data/lib/rupture/cons.rb +18 -0
- data/lib/rupture/core_ext.rb +21 -0
- data/lib/rupture/fn.rb +88 -0
- data/lib/rupture/function.rb +114 -0
- data/lib/rupture/lazy_seq.rb +35 -0
- data/lib/rupture/list.rb +31 -0
- data/lib/rupture/lookup.rb +24 -0
- data/lib/rupture/meta.rb +22 -0
- data/lib/rupture/rails_ext.rb +38 -0
- data/lib/rupture/reader.rb +110 -0
- data/lib/rupture/seq.rb +62 -0
- data/lib/rupture/sequence.rb +274 -0
- data/lib/rupture/symbol.rb +32 -0
- data/lib/rupture/utils.rb +7 -0
- data/lib/rupture.rb +20 -0
- data/rupture.gemspec +28 -6
- data/test/fn_test.rb +41 -0
- data/test/list_test.rb +20 -0
- data/test/meta_test.rb +43 -0
- data/test/seq_test.rb +255 -0
- data/test/test_helper.rb +11 -0
- metadata +29 -8
- data/README.rdoc +0 -0
@@ -0,0 +1,274 @@
|
|
1
|
+
module Rupture
|
2
|
+
module Sequence
|
3
|
+
def first
|
4
|
+
seq.first
|
5
|
+
end
|
6
|
+
|
7
|
+
def rest
|
8
|
+
seq.rest
|
9
|
+
end
|
10
|
+
|
11
|
+
def next
|
12
|
+
rest.seq
|
13
|
+
end
|
14
|
+
|
15
|
+
def second
|
16
|
+
rest.first
|
17
|
+
end
|
18
|
+
|
19
|
+
def empty?
|
20
|
+
not seq
|
21
|
+
end
|
22
|
+
|
23
|
+
def not_empty
|
24
|
+
self if seq
|
25
|
+
end
|
26
|
+
|
27
|
+
def count
|
28
|
+
F.loop(0, self) do |recur, i, s|
|
29
|
+
if s.empty?
|
30
|
+
i
|
31
|
+
elsif s.respond_to?(:size)
|
32
|
+
s.size + i
|
33
|
+
else
|
34
|
+
recur[i.inc, s.rest]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def inspect
|
40
|
+
"(#{to_a.collect(&:inspect).join(' ')})"
|
41
|
+
end
|
42
|
+
|
43
|
+
def conj(item)
|
44
|
+
F.cons(item, self)
|
45
|
+
end
|
46
|
+
|
47
|
+
def into(coll)
|
48
|
+
coll.seq.reduce(:conj, self)
|
49
|
+
end
|
50
|
+
|
51
|
+
def reverse
|
52
|
+
Seq.empty.into(self)
|
53
|
+
end
|
54
|
+
|
55
|
+
def take(n)
|
56
|
+
F.lazy_seq do
|
57
|
+
if n.pos? and s = seq
|
58
|
+
F.cons(s.first, s.rest.take(n.dec))
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def drop(n)
|
64
|
+
F.lazy_seq do
|
65
|
+
F.loop(n, seq) do |recur, n, s|
|
66
|
+
if s and n.pos?
|
67
|
+
recur[n.dec, s.next]
|
68
|
+
else
|
69
|
+
s
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def take_last(n)
|
76
|
+
F.loop(seq, drop(n).seq) do |recur, s, lead|
|
77
|
+
if lead
|
78
|
+
recur[s.next, lead.next]
|
79
|
+
else
|
80
|
+
s || Seq.empty
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def drop_last(n)
|
86
|
+
F.map(self, drop(n)) {|x,_| x}
|
87
|
+
end
|
88
|
+
|
89
|
+
def last
|
90
|
+
take_last(1).first
|
91
|
+
end
|
92
|
+
|
93
|
+
def split_at(n)
|
94
|
+
[take(n), drop(n)]
|
95
|
+
end
|
96
|
+
|
97
|
+
def take_while(p = nil, &pred)
|
98
|
+
pred ||= p
|
99
|
+
F.lazy_seq do
|
100
|
+
if s = seq
|
101
|
+
i = s.first
|
102
|
+
F.cons(i, s.rest.take_while(pred)) if pred[i]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def drop_while(p = nil, &pred)
|
108
|
+
pred ||= p
|
109
|
+
F.lazy_seq do
|
110
|
+
F.loop(seq) do |recur, s|
|
111
|
+
if s and pred[s.first]
|
112
|
+
recur[s.next]
|
113
|
+
else
|
114
|
+
s
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def split_with(p = nil, &pred)
|
121
|
+
pred ||= p
|
122
|
+
[take_while(pred), drop_while(pred)]
|
123
|
+
end
|
124
|
+
|
125
|
+
def filter(p = nil, &pred)
|
126
|
+
pred ||= p
|
127
|
+
F.lazy_seq do
|
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
|
134
|
+
end
|
135
|
+
|
136
|
+
def remove(p = nil, &pred)
|
137
|
+
pred ||= p
|
138
|
+
filter(pred.complement)
|
139
|
+
end
|
140
|
+
|
141
|
+
def separate(p = nil, &pred)
|
142
|
+
pred ||= p
|
143
|
+
[filter(pred), remove(pred)]
|
144
|
+
end
|
145
|
+
|
146
|
+
def sequential?
|
147
|
+
true
|
148
|
+
end
|
149
|
+
|
150
|
+
def flatten
|
151
|
+
sequential = lambda {|x| x.class <= Seq or x.class == Array}
|
152
|
+
tree_seq(sequential, :seq).remove(sequential)
|
153
|
+
end
|
154
|
+
|
155
|
+
def map(f = nil, &fn)
|
156
|
+
fn ||= f
|
157
|
+
F.map(fn, self)
|
158
|
+
end
|
159
|
+
|
160
|
+
def concat(*colls)
|
161
|
+
F.concat(self, *colls)
|
162
|
+
end
|
163
|
+
|
164
|
+
def mapcat(f = nil, &fn)
|
165
|
+
fn ||= f
|
166
|
+
F.mapcat(fn, self)
|
167
|
+
end
|
168
|
+
|
169
|
+
def reduce(*args, &fn)
|
170
|
+
fn ||= args.shift
|
171
|
+
Utils.verify_args(args, 0, 1)
|
172
|
+
|
173
|
+
if s = seq
|
174
|
+
inject(*args, &fn)
|
175
|
+
elsif args.size == 1
|
176
|
+
args.first
|
177
|
+
else
|
178
|
+
fn[] if fn.arity == -1
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def foldr(*args, &fn)
|
183
|
+
fn ||= args.shift
|
184
|
+
reverse.reduce(*args) {|a,b| fn[b,a]}
|
185
|
+
end
|
186
|
+
|
187
|
+
def tree_seq(branch, children, &f)
|
188
|
+
branch ||= f
|
189
|
+
children ||= f
|
190
|
+
walk = lambda do |node|
|
191
|
+
F.lazy_seq do
|
192
|
+
rest = children[node].mapcat(walk) if branch[node]
|
193
|
+
F.cons(node, rest)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
walk[self]
|
197
|
+
end
|
198
|
+
|
199
|
+
def every?(p = nil, &pred)
|
200
|
+
pred ||= p || F[:identity]
|
201
|
+
all?(&pred)
|
202
|
+
end
|
203
|
+
|
204
|
+
def some(f = nil, &fn)
|
205
|
+
fn ||= f || F[:identity]
|
206
|
+
F.loop(seq) do |recur, s|
|
207
|
+
if s
|
208
|
+
if val = fn[s.first]
|
209
|
+
val
|
210
|
+
else
|
211
|
+
recur[s.next]
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def nth(n)
|
218
|
+
drop(n.dec).first
|
219
|
+
end
|
220
|
+
|
221
|
+
def partition(n, step = n, pad = nil)
|
222
|
+
F.lazy_seq do
|
223
|
+
if s = seq
|
224
|
+
p = take(n)
|
225
|
+
if n == p.count
|
226
|
+
F.cons(p, drop(step).partition(n, step, pad))
|
227
|
+
elsif pad
|
228
|
+
F.cons(p.concat(pad).take(n), nil)
|
229
|
+
else
|
230
|
+
nil
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def partition_all(n, step = n)
|
237
|
+
partition(n, step, [])
|
238
|
+
end
|
239
|
+
|
240
|
+
def partition_by(f = nil, &fn)
|
241
|
+
fn ||= f
|
242
|
+
F.lazy_seq do
|
243
|
+
if s = seq
|
244
|
+
head = s.first
|
245
|
+
val = fn[head]
|
246
|
+
run = F.cons(head, s.rest.take_while {|i| val == fn[i]})
|
247
|
+
F.cons(run, s.drop(run.count).partition_by(fn))
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def partition_between(f = nil, &fn)
|
253
|
+
fn ||= f
|
254
|
+
F.lazy_seq do
|
255
|
+
if s = seq
|
256
|
+
run = F.cons(s.first, s.partition(2,1).take_while {|i| not fn[*i]}.map(:second))
|
257
|
+
F.cons(run, s.drop(run.count).partition_between(fn))
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
def doall(n = nil)
|
263
|
+
if n
|
264
|
+
loop(n, seq) do |recur, n, s|
|
265
|
+
recur[n.dec, s.next] if s and n.pos?
|
266
|
+
end
|
267
|
+
else
|
268
|
+
loop(seq) do |recur, s|
|
269
|
+
recur[s.next] if s
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
class Rupture::Symbol # Use for symbols
|
4
|
+
extend Forwardable
|
5
|
+
def_delegators :@symbol, :to_s, :name, :namespace
|
6
|
+
|
7
|
+
def initialize(*args)
|
8
|
+
Utils.verify_args(args, 1, 2)
|
9
|
+
@symbol = args.join("/").to_sym
|
10
|
+
end
|
11
|
+
|
12
|
+
alias inspect to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
class Symbol # Use for keywords
|
16
|
+
def name
|
17
|
+
parse_namespace unless @name
|
18
|
+
@name
|
19
|
+
end
|
20
|
+
|
21
|
+
def namespace
|
22
|
+
parse_namespace unless @name
|
23
|
+
@namespace
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def parse_namespace
|
29
|
+
@name, *ns = to_s.split('/').reverse
|
30
|
+
@namespace = ns.join('/')
|
31
|
+
end
|
32
|
+
end
|
data/lib/rupture.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Rupture; end
|
2
|
+
|
3
|
+
require 'rupture/core_ext'
|
4
|
+
require 'rupture/rails_ext'
|
5
|
+
require 'rupture/utils'
|
6
|
+
require 'rupture/function'
|
7
|
+
require 'rupture/fn'
|
8
|
+
require 'rupture/lookup'
|
9
|
+
require 'rupture/symbol'
|
10
|
+
require 'rupture/meta'
|
11
|
+
require 'rupture/sequence'
|
12
|
+
require 'rupture/seq'
|
13
|
+
require 'rupture/lazy_seq'
|
14
|
+
require 'rupture/cons'
|
15
|
+
require 'rupture/array_seq'
|
16
|
+
require 'rupture/list'
|
17
|
+
|
18
|
+
F = Rupture::Function
|
19
|
+
|
20
|
+
Object.send(:include, Rupture::Meta)
|
data/rupture.gemspec
CHANGED
@@ -5,31 +5,53 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{rupture}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Justin Balthrop"]
|
12
|
-
s.date = %q{2011-
|
12
|
+
s.date = %q{2011-09-09}
|
13
13
|
s.description = %q{Clojure sequence functions for Ruby.}
|
14
14
|
s.email = %q{code@justinbalthrop.com}
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE",
|
17
|
-
"README.
|
17
|
+
"README.md"
|
18
18
|
]
|
19
19
|
s.files = [
|
20
20
|
"LICENSE",
|
21
|
-
"README.
|
21
|
+
"README.md",
|
22
22
|
"Rakefile",
|
23
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",
|
24
37
|
"lib/rupture/seq.rb",
|
25
|
-
"rupture.
|
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"
|
26
47
|
]
|
27
48
|
s.homepage = %q{http://github.com/flatland/rupture}
|
28
49
|
s.require_paths = ["lib"]
|
29
|
-
s.rubygems_version = %q{1.
|
50
|
+
s.rubygems_version = %q{1.3.7}
|
30
51
|
s.summary = %q{Clojure sequence functions for Ruby.}
|
31
52
|
|
32
53
|
if s.respond_to? :specification_version then
|
54
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
33
55
|
s.specification_version = 3
|
34
56
|
|
35
57
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
data/test/fn_test.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class FnTest < Test::Unit::TestCase
|
4
|
+
should "identity" do
|
5
|
+
assert_equal [1,2,3].seq, [1,2,3].seq.map(F[:identity])
|
6
|
+
end
|
7
|
+
|
8
|
+
should "juxt" do
|
9
|
+
assert_equal [[2,0],[3,1],[4,2]].seq, [1,2,3].seq.map(F.juxt(:inc, :dec))
|
10
|
+
end
|
11
|
+
|
12
|
+
# should "apply" do
|
13
|
+
# assert_equal [1,2,3,4,5,6].seq, F[:concat].apply([1],[2],[[3,4],[5,6]])
|
14
|
+
# end
|
15
|
+
|
16
|
+
should "use hash as fn" do
|
17
|
+
assert_equal [1, 2, 3, nil].seq, [:foo, :bar, :baz, :bam].seq.map({:foo => 1, :bar => 2, :baz => 3})
|
18
|
+
end
|
19
|
+
|
20
|
+
should "use set and sorted set as fn" do
|
21
|
+
assert_equal [:foo, 2, nil, :baz, nil].seq, [:foo, 2, :bar, :baz, :bam].seq.map(Set[:foo, 2, :baz])
|
22
|
+
assert_equal [:foo, 2, nil, :baz, nil].seq, [:foo, 2, :bar, :baz, :bam].seq.map(SortedSet[:foo, 2, :baz])
|
23
|
+
end
|
24
|
+
|
25
|
+
should "use array as fn" do
|
26
|
+
assert_equal [:foo, :bar, nil, :baz, :bar].seq, [0, 1, 3, 2, 1].seq.map([:foo, :bar, :baz])
|
27
|
+
end
|
28
|
+
|
29
|
+
should "use symbol lookup as fn" do
|
30
|
+
assert_equal [3, nil, 7, nil].seq, [{:foo => 3}, {}, {:foo => 7}, {:bar => 1}].seq.map(:foo.lookup)
|
31
|
+
assert_equal [3, nil, 7, nil].seq, [{:foo => 3}, {}, {:foo => 7}, {:bar => 1}].seq.map(~:foo)
|
32
|
+
end
|
33
|
+
|
34
|
+
should "use string lookup as fn" do
|
35
|
+
assert_equal [3, nil, 7, nil].seq, [{'foo' => 3}, {}, {'foo' => 7}, {'bar' => 1}].seq.map('foo'.lookup)
|
36
|
+
end
|
37
|
+
|
38
|
+
should "use numeric lookup as fn" do
|
39
|
+
assert_equal [3, nil, 7, nil].seq, [[0,3], {}, {1 => 7}, {'bar' => 1}].seq.map(1.lookup)
|
40
|
+
end
|
41
|
+
end
|
data/test/list_test.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class ListTest < Test::Unit::TestCase
|
4
|
+
should "act like a seq" do
|
5
|
+
list = F.list(1, 2, 3, 4)
|
6
|
+
assert_equal list.count, 4
|
7
|
+
assert_equal list.first, 1
|
8
|
+
assert_equal list.rest.next.rest.first, 4
|
9
|
+
assert_nil list.next.next.next.next
|
10
|
+
end
|
11
|
+
|
12
|
+
should "count quickly" do
|
13
|
+
list = F.list(1, 2, 3, 4)
|
14
|
+
def list.each
|
15
|
+
raise "Tried to compute count by doing O(N) walk"
|
16
|
+
end
|
17
|
+
|
18
|
+
assert_equal list.count, 4
|
19
|
+
end
|
20
|
+
end
|
data/test/meta_test.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class MetaTest < Test::Unit::TestCase
|
4
|
+
should "have meta data" do
|
5
|
+
a = "foo"
|
6
|
+
|
7
|
+
assert_equal({}, a.meta)
|
8
|
+
|
9
|
+
a.meta[:foo] = 1
|
10
|
+
a.meta[:bar] = 2
|
11
|
+
assert_equal({:foo => 1, :bar => 2}, a.meta)
|
12
|
+
|
13
|
+
b = a.clone
|
14
|
+
b.meta[:foo] = 3
|
15
|
+
assert_equal({:foo => 1, :bar => 2}, a.meta)
|
16
|
+
assert_equal({:foo => 3, :bar => 2}, b.meta)
|
17
|
+
end
|
18
|
+
|
19
|
+
should "change meta using with_meta" do
|
20
|
+
a = [1,2,3]
|
21
|
+
assert_equal({}, a.meta)
|
22
|
+
|
23
|
+
b = a.with_meta(:foo => 1)
|
24
|
+
assert_equal({:foo => 1}, b.meta)
|
25
|
+
|
26
|
+
c = b.with_meta(:baz => 1)
|
27
|
+
assert_equal({:baz => 1}, c.meta)
|
28
|
+
end
|
29
|
+
|
30
|
+
should "change meta using vary_meta" do
|
31
|
+
a = [1,2,3]
|
32
|
+
assert_equal({}, a.meta)
|
33
|
+
|
34
|
+
b = a.vary_meta do |m|
|
35
|
+
m[:foo] = 1
|
36
|
+
m
|
37
|
+
end
|
38
|
+
assert_equal({:foo => 1}, b.meta)
|
39
|
+
|
40
|
+
c = b.vary_meta(:merge, :bar => 3)
|
41
|
+
assert_equal({:foo => 1, :bar => 3}, c.meta)
|
42
|
+
end
|
43
|
+
end
|