rupture 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,7 @@
1
+ module Rupture
2
+ module Utils
3
+ def self.verify_args(args, *sizes)
4
+ raise ArgumentError, "wrong number of arguments (#{args.size} for 2)" unless sizes.include?(args.size)
5
+ end
6
+ end
7
+ 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.0.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-07-19}
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.rdoc"
17
+ "README.md"
18
18
  ]
19
19
  s.files = [
20
20
  "LICENSE",
21
- "README.rdoc",
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.gemspec"
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.5.2}
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