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 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'