rupture 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ *~
2
+ Gemfile.lock
3
+ pkg/
data/.rbenv-version ADDED
@@ -0,0 +1 @@
1
+ ree-1.8.7-2012.02
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://www.rubygems.org"
2
+
3
+ gemspec
data/README.md CHANGED
@@ -14,4 +14,7 @@ in Ruby.
14
14
  ## Coming soon
15
15
 
16
16
  * improved README
17
- * hamster-based persistent data structures
17
+ * Hash Array Mapped Tries
18
+ * Bitmapped Array Tries
19
+ * Native Implementations
20
+ * Chunked seqs
data/Rakefile CHANGED
@@ -1,36 +1,10 @@
1
- require 'rake'
2
1
  require 'rake/testtask'
3
- require 'rubygems'
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 << 'lib'
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
1
+ 0.2.0
@@ -3,7 +3,6 @@ module Rupture
3
3
  def initialize(array, index = 0)
4
4
  @array = array
5
5
  @index = index
6
- super()
7
6
  end
8
7
 
9
8
  def first
data/lib/rupture/cons.rb CHANGED
@@ -12,7 +12,7 @@ module Rupture
12
12
  end
13
13
 
14
14
  def rest
15
- @rest ||= Seq.empty
15
+ @rest ||= Seq::Empty
16
16
  end
17
17
  end
18
18
  end
@@ -19,3 +19,17 @@ class Numeric
19
19
  self == 0
20
20
  end
21
21
  end
22
+
23
+ class Object
24
+ def map?
25
+ false
26
+ end
27
+
28
+ def let(*vals)
29
+ yield(self, *vals)
30
+ end
31
+
32
+ def fix(pred, f = nil, &fn)
33
+ Rupture::Function.fix(self, pred, fn || f)
34
+ end
35
+ end
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(*(partials + args))
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
- self[key]
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 = nil, *args)
54
- object.method(self)[*args]
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, *(args + partials))
111
+ self.send(method_name, *(partials + args))
86
112
  end
87
113
  end
88
114
  end
@@ -1,15 +1,12 @@
1
1
  module Rupture
2
2
  module Function
3
- # FIXME isn't totally lazy when working with > 1 collection
4
- # If the first is empty, the second is still seq'd
5
- def map(*colls, &f)
6
- f ||= colls.shift
7
- lazy_seq do
8
- seqs = colls.collect(&:seq)
9
- if seqs.all?
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, &f)
29
- f ||= colls.shift
30
- concat(*map(*colls, &f))
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 iterate(*args, &f)
56
- f ||= args.shift
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(f[x], &f))
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(&fn)
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
@@ -1,8 +1,7 @@
1
1
  module Rupture
2
2
  class LazySeq < Seq
3
- def initialize(b = nil, &block)
4
- @block = block || b
5
- super()
3
+ def initialize(block = nil)
4
+ @block = block
6
5
  end
7
6
 
8
7
  def seq
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 = self.empty
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
@@ -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
@@ -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
@@ -33,22 +33,22 @@ module Rupture
33
33
 
34
34
  def read
35
35
  case c = getc
36
- when '(' : read_list
37
- when '[' : read_list(Array, ']')
38
- when '{' : read_map
39
- when '"' : read_string
40
- when ':' : read_keyword
41
- when ' ' : read
42
- when /\d/ : ungetc(c); read_number
43
- when /\w/ : ungetc(c); read_symbol
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/ : ungetc(c); -read_number
47
- else ungetc('-', c); read_symbol
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 '{' : read_list(Set, '}')
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 < Enumerable::Enumerator
2
+ class Seq
3
+ include Enumerable
3
4
  include Sequence
4
5
 
5
- def initialize
6
- super(self)
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 ==(other)
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
- def self.empty
37
- @empty ||= EmptySeq.new
33
+ class EmptySeq < Seq
34
+ def seq
35
+ nil
36
+ end
38
37
  end
39
- end
40
38
 
41
- class EmptySeq < Seq
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.empty
55
+ Rupture::Seq::Empty
61
56
  end
62
57
  end
@@ -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.empty.into(self)
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.empty
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.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
135
+ F.filter(pred, self)
134
136
  end
135
137
 
136
138
  def remove(p = nil, &pred)
137
139
  pred ||= p
138
- filter(pred.complement)
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.map(fn, self)
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, s.partition(2,1).take_while {|i| not fn[*i]}.map(:second))
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
@@ -14,6 +14,8 @@ require 'rupture/lazy_seq'
14
14
  require 'rupture/cons'
15
15
  require 'rupture/array_seq'
16
16
  require 'rupture/list'
17
+ require 'rupture/map'
18
+ require 'rupture/hash_map'
17
19
 
18
20
  F = Rupture::Function
19
21
 
data/rupture.gemspec CHANGED
@@ -1,63 +1,22 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
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 |s|
7
- s.name = %q{rupture}
8
- s.version = "0.1.0"
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
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Justin Balthrop"]
12
- s.date = %q{2011-09-09}
13
- s.description = %q{Clojure sequence functions for Ruby.}
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
- if s.respond_to? :specification_version then
54
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
55
- s.specification_version = 3
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.empty, F.lazy_seq{nil}, F.lazy_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, [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
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
@@ -1,7 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'test/unit'
3
3
  require 'shoulda'
4
- require 'mocha'
4
+ require 'mocha/setup'
5
5
  require 'pp'
6
6
 
7
7
  $LOAD_PATH.unshift File.dirname(__FILE__) + "/../lib"
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: 27
5
- prerelease: false
4
+ hash: 23
5
+ prerelease:
6
6
  segments:
7
7
  - 0
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 0.1.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: 2011-09-09 00:00:00 -07:00
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: code@justinbalthrop.com
81
+ email:
82
+ - git@justinbalthrop.com
24
83
  executables: []
25
84
 
26
85
  extensions: []
27
86
 
28
- extra_rdoc_files:
29
- - LICENSE
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: http://github.com/flatland/rupture
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.3.7
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'