rupture 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,17 @@
1
+ It's hard to go back to Ruby once you've gotten used to programming in Clojure. Rupture makes the
2
+ transition easier by giving you the power of Clojure's sequence library and higher order functions
3
+ in Ruby.
4
+
5
+ ## Installation
6
+
7
+ gem install rupture
8
+
9
+ ## Usage
10
+
11
+ require 'rupture'
12
+ # see the tests for examples
13
+
14
+ ## Coming soon
15
+
16
+ * improved README
17
+ * hamster-based persistent data structures
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'rake'
2
2
  require 'rake/testtask'
3
- require 'rdoc/task'
3
+ require 'rubygems'
4
4
 
5
5
  begin
6
6
  require 'jeweler'
@@ -14,7 +14,7 @@ begin
14
14
  end
15
15
  Jeweler::GemcutterTasks.new
16
16
  rescue LoadError
17
- puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
17
+ puts "Jeweler not available. Install it with: sudo gem install jeweler"
18
18
  end
19
19
 
20
20
  Rake::TestTask.new do |t|
@@ -23,14 +23,6 @@ Rake::TestTask.new do |t|
23
23
  t.verbose = false
24
24
  end
25
25
 
26
- Rake::RDocTask.new do |rdoc|
27
- rdoc.rdoc_dir = 'rdoc'
28
- rdoc.title = 'model_set'
29
- rdoc.options << '--line-numbers' << '--inline-source'
30
- rdoc.rdoc_files.include('README*')
31
- rdoc.rdoc_files.include('lib/**/*.rb')
32
- end
33
-
34
26
  begin
35
27
  require 'rcov/rcovtask'
36
28
  Rcov::RcovTask.new do |t|
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.0
1
+ 0.1.0
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'rupture'
@@ -0,0 +1,65 @@
1
+ module Rupture
2
+ class ArraySeq < Seq
3
+ def initialize(array, index = 0)
4
+ @array = array
5
+ @index = index
6
+ super()
7
+ end
8
+
9
+ def first
10
+ @array[@index]
11
+ end
12
+
13
+ def rest
14
+ ArraySeq.new(@array, @index.inc)
15
+ end
16
+
17
+ def seq
18
+ self if @index < @array.size
19
+ end
20
+
21
+ def size
22
+ @array.size - @index
23
+ end
24
+ end
25
+
26
+ class RArraySeq < ArraySeq
27
+ def initialize(array, index = array.size - 1)
28
+ super(array, index)
29
+ end
30
+
31
+ def rest
32
+ RArraySeq.new(@array, @index.dec)
33
+ end
34
+
35
+ def seq
36
+ self if @index >= 0
37
+ end
38
+
39
+ def size
40
+ @index.inc
41
+ end
42
+ end
43
+
44
+ module ArraySeqable
45
+ def seq
46
+ Rupture::ArraySeq.new(self).seq
47
+ end
48
+
49
+ def rseq
50
+ Rupture::RArraySeq.new(self).seq
51
+ end
52
+
53
+ def not_empty
54
+ self if seq
55
+ end
56
+ end
57
+ end
58
+
59
+ class Array
60
+ include Rupture::ArraySeqable
61
+ end
62
+
63
+ class String
64
+ include Rupture::ArraySeqable
65
+ end
@@ -0,0 +1,18 @@
1
+ module Rupture
2
+ class Cons < Seq
3
+ attr_reader :first
4
+
5
+ def initialize(first, rest)
6
+ @first, @rest = first, rest
7
+ super()
8
+ end
9
+
10
+ def seq
11
+ self
12
+ end
13
+
14
+ def rest
15
+ @rest ||= Seq.empty
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ class Numeric
2
+ def inc
3
+ self + 1
4
+ end
5
+
6
+ def dec
7
+ self - 1
8
+ end
9
+
10
+ def pos?
11
+ self > 0
12
+ end
13
+
14
+ def neg?
15
+ self < 0
16
+ end
17
+
18
+ def zero?
19
+ self == 0
20
+ end
21
+ end
data/lib/rupture/fn.rb ADDED
@@ -0,0 +1,88 @@
1
+ require 'set'
2
+
3
+ module Rupture
4
+ module Fn
5
+ def complement
6
+ lambda do |*args|
7
+ not call(*args)
8
+ end
9
+ end
10
+ alias -@ complement
11
+
12
+ def comp(fn)
13
+ lambda do |*args|
14
+ call(fn[*args])
15
+ end
16
+ end
17
+ alias * comp
18
+
19
+ def partial(*partials)
20
+ lambda do |*args|
21
+ call(*(partials + args))
22
+ end
23
+ end
24
+
25
+ # def apply(*args)
26
+ # last = args.pop
27
+ # call(*F.concat(args, last))
28
+ # end
29
+
30
+ def to_proc
31
+ lambda do |key|
32
+ self[key]
33
+ end
34
+ end
35
+
36
+ def arity
37
+ -1
38
+ end
39
+ end
40
+ end
41
+
42
+ class Proc
43
+ include Rupture::Fn
44
+ end
45
+
46
+ class Method
47
+ include Rupture::Fn
48
+ end
49
+
50
+ class Symbol
51
+ include Rupture::Fn
52
+
53
+ def call(object = nil, *args)
54
+ object.method(self)[*args]
55
+ end
56
+ alias [] call
57
+
58
+ def arity
59
+ -2
60
+ end
61
+ end
62
+
63
+ class Hash
64
+ include Rupture::Fn
65
+ alias call []
66
+ end
67
+
68
+ class Array
69
+ include Rupture::Fn
70
+ alias call []
71
+ end
72
+
73
+ class Set
74
+ include Rupture::Fn
75
+
76
+ def [](key)
77
+ key if include?(key)
78
+ end
79
+ alias call []
80
+ end
81
+
82
+ class Module
83
+ def [](method_name, *partials)
84
+ lambda do |*args|
85
+ self.send(method_name, *(args + partials))
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,114 @@
1
+ module Rupture
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))
13
+ end
14
+ end
15
+ end
16
+
17
+ def concat(*colls)
18
+ lazy_seq do
19
+ head, *tail = colls.collect(&:seq)
20
+ if head
21
+ cons(head.first, concat(head.rest, *tail))
22
+ elsif tail.any?
23
+ concat(*tail)
24
+ end
25
+ end
26
+ end
27
+
28
+ def mapcat(*colls, &f)
29
+ f ||= colls.shift
30
+ concat(*map(*colls, &f))
31
+ end
32
+
33
+ def zip(*colls)
34
+ lazy_seq do
35
+ seqs = colls.collect(&:seq)
36
+ if seqs.any?
37
+ firsts = seqs.collect(&:first)
38
+ rests = seqs.collect(&:rest)
39
+ cons(firsts, zip(*rests))
40
+ end
41
+ end
42
+ end
43
+
44
+ def loop(*vals)
45
+ more = true
46
+ recur = lambda {|*vals| more = true}
47
+
48
+ while more
49
+ more = nil
50
+ result = yield(recur, *vals)
51
+ end
52
+ result
53
+ end
54
+
55
+ def iterate(*args, &f)
56
+ f ||= args.shift
57
+ Utils.verify_args(args, 1)
58
+ x = args.first
59
+ lazy_seq do
60
+ cons(x, iterate(f[x], &f))
61
+ end
62
+ end
63
+
64
+ def repeatedly(*args, &fn)
65
+ fn ||= args.pop
66
+ Utils.verify_args(args, 0, 1)
67
+ n = args.first
68
+
69
+ lazy_seq do
70
+ if n.nil?
71
+ cons(fn[], repeatedly(n, fn))
72
+ elsif n > 0
73
+ cons(fn[], repeatedly(n.dec, fn))
74
+ end
75
+ end
76
+ end
77
+
78
+ def repeat(*args)
79
+ Utils.verify_args(args, 1, 2)
80
+ x, n = args.reverse
81
+ repeatedly(n) {x}
82
+ end
83
+
84
+ def lazy_seq(f = nil, &fn)
85
+ fn ||= f
86
+ LazySeq.new(&fn)
87
+ end
88
+
89
+ def cons(head, tail)
90
+ Cons.new(head, tail)
91
+ end
92
+
93
+ def list(*xs)
94
+ List.new(*xs)
95
+ end
96
+
97
+ def identity(x)
98
+ x
99
+ end
100
+
101
+ def juxt(*fs)
102
+ lambda do |*args|
103
+ fs.collect {|f| f[*args]}
104
+ end
105
+ end
106
+
107
+ def decorate(*args)
108
+ juxt(identity, *args)
109
+ end
110
+
111
+ extend Function
112
+ F = Function
113
+ end
114
+ end
@@ -0,0 +1,35 @@
1
+ module Rupture
2
+ class LazySeq < Seq
3
+ def initialize(b = nil, &block)
4
+ @block = block || b
5
+ super()
6
+ end
7
+
8
+ def seq
9
+ return @seq unless @block
10
+ @seq = @block.call.seq
11
+ @block = nil
12
+ @seq
13
+ end
14
+ end
15
+ end
16
+
17
+ module Enumerable
18
+ def seq
19
+ F.lazy_seq do
20
+ callcc do |external|
21
+ each do |item|
22
+ external = callcc do |internal|
23
+ rest = F.lazy_seq do
24
+ callcc do |external|
25
+ internal.call(external)
26
+ end
27
+ end
28
+ external.call(F.cons(item, rest))
29
+ end
30
+ end
31
+ external.call(nil)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,31 @@
1
+ module Rupture
2
+ class List < Seq
3
+ class << self
4
+ alias create new
5
+ end
6
+ private_class_method :create
7
+ attr_reader :seq, :size
8
+
9
+ def self.empty
10
+ @empty ||= create(nil, 0)
11
+ end
12
+
13
+ def initialize(seq, size)
14
+ @seq = seq.seq
15
+ @size = size
16
+ end
17
+
18
+ def self.new(*args)
19
+ list = self.empty
20
+ args.reverse_each do |x|
21
+ list = list.conj(x)
22
+ end
23
+
24
+ list
25
+ end
26
+
27
+ def conj(x)
28
+ self.class.send(:create, Cons.new(x, @seq), @size.inc)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,24 @@
1
+ module Rupture
2
+ module Lookup
3
+ def lookup
4
+ lambda do |a|
5
+ a[self]
6
+ end
7
+ end
8
+ end
9
+ end
10
+
11
+ class Symbol
12
+ include Rupture::Lookup
13
+
14
+ alias ~ lookup
15
+ end
16
+
17
+ class String
18
+ include Rupture::Lookup
19
+ end
20
+
21
+ class Numeric
22
+ include Rupture::Lookup
23
+ end
24
+
@@ -0,0 +1,22 @@
1
+ module Rupture::Meta
2
+ def meta
3
+ @_meta ||= {}
4
+ end
5
+
6
+ def clone(meta = nil)
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)
9
+ copy = super()
10
+ copy.instance_variable_set(:@_meta, meta)
11
+ copy
12
+ end
13
+
14
+ def with_meta(meta)
15
+ clone(meta)
16
+ end
17
+
18
+ def vary_meta(*args, &fn)
19
+ fn ||= args.shift
20
+ with_meta(fn[meta, *args])
21
+ end
22
+ end
@@ -0,0 +1,38 @@
1
+ class Hash
2
+ def symbolize_keys!
3
+ keys.each do |key|
4
+ self[(key.to_sym rescue key) || key] = delete(key)
5
+ end
6
+ self
7
+ end
8
+
9
+ def symbolize_keys
10
+ dup.symbolize_keys!
11
+ end
12
+
13
+ def deep_symbolize_keys!
14
+ values.each do |val|
15
+ val.deep_symbolize_keys! if val.is_a?(Hash)
16
+ end
17
+ symbolize_keys!
18
+ end
19
+
20
+ def deep_symbolize_keys
21
+ copy = symbolize_keys
22
+ copy.each do |key, val|
23
+ copy[key] = val.deep_symbolize_keys if val.is_a?(Hash)
24
+ end
25
+ copy
26
+ end
27
+
28
+ def stringify_keys!
29
+ keys.each do |key|
30
+ self[key.to_s] = delete(key)
31
+ end
32
+ self
33
+ end
34
+
35
+ def stringify_keys
36
+ dup.stringify_keys!
37
+ end
38
+ end
@@ -0,0 +1,110 @@
1
+ require 'set'
2
+
3
+ module Rupture
4
+ class Reader
5
+ def initialize(input)
6
+ @input = input
7
+ @buffer = []
8
+ end
9
+
10
+ def ungetc(*chars)
11
+ @buffer.concat(chars)
12
+ @space = false
13
+ chars.last
14
+ end
15
+
16
+ def getc
17
+ while c = (@buffer.shift || @input.getc.chr)
18
+ if c =~ /[\s,;]/
19
+ next if @space
20
+ @space = true
21
+ @input.gets if c == ';'
22
+ return ' '
23
+ else
24
+ @space = false
25
+ return c
26
+ end
27
+ end
28
+ end
29
+
30
+ def peekc
31
+ unget(getc)
32
+ end
33
+
34
+ def read
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
44
+ when '-'
45
+ case c = getc
46
+ when /\d/ : ungetc(c); -read_number
47
+ else ungetc('-', c); read_symbol
48
+ end
49
+ when '#'
50
+ case c = getc
51
+ when '{' : read_list(Set, '}')
52
+ end
53
+ end
54
+ end
55
+
56
+ def read_list(klass = List, terminator = ')')
57
+ list = klass.new
58
+ while c = getc
59
+ return list if c == terminator
60
+ ungetc(c)
61
+ list << read
62
+ end
63
+ end
64
+
65
+ def read_map
66
+ map = {}
67
+ while c = getc
68
+ return map if c == '}'
69
+ ungetc(c)
70
+ list[read] = read
71
+ end
72
+ end
73
+
74
+ def read_string
75
+ string = ''
76
+ while c = getc
77
+ return string if c == '"'
78
+ string << c
79
+ end
80
+ end
81
+
82
+ def read_while(pattern, token = '')
83
+ while c = getc
84
+ if c !~ pattern
85
+ ungetc(c)
86
+ return token
87
+ end
88
+ token << c
89
+ end
90
+ end
91
+
92
+ def read_symbol(prefix = '@')
93
+ read_while(/[^\s{}\[\]()]/, prefix).to_sym
94
+ end
95
+
96
+ def read_keyword
97
+ read_symbol('')
98
+ end
99
+
100
+ def read_number
101
+ number = read_while(/[-\d]/)
102
+ if (c = getc) == '.'
103
+ read_while(/\d/, number << '.').to_f
104
+ else
105
+ ungetc(c)
106
+ number.to_i
107
+ end
108
+ end
109
+ end
110
+ end
data/lib/rupture/seq.rb CHANGED
@@ -0,0 +1,62 @@
1
+ module Rupture
2
+ class Seq < Enumerable::Enumerator
3
+ include Sequence
4
+
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
15
+ end
16
+
17
+ def [](index)
18
+ nth(index)
19
+ end
20
+
21
+ def to_ary
22
+ to_a
23
+ end
24
+
25
+ def ==(other)
26
+ s = self.seq
27
+ o = other.seq
28
+ while s && o
29
+ return false if s.first != o.first
30
+ s = s.next
31
+ o = o.next
32
+ end
33
+ s.nil? and o.nil?
34
+ end
35
+
36
+ def self.empty
37
+ @empty ||= EmptySeq.new
38
+ end
39
+ end
40
+
41
+ class EmptySeq < Seq
42
+ def seq
43
+ nil
44
+ end
45
+ end
46
+ end
47
+
48
+ class NilClass
49
+ include Rupture::Sequence
50
+
51
+ def seq
52
+ nil
53
+ end
54
+
55
+ def first
56
+ nil
57
+ end
58
+
59
+ def rest
60
+ Rupture::Seq.empty
61
+ end
62
+ end