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