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