SI 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/CHANGELOG +4 -0
  2. data/README +30 -0
  3. data/lib/si.rb +153 -0
  4. metadata +47 -0
@@ -0,0 +1,4 @@
1
+ - Version: 0.0.1
2
+ Date: 2006-06-05
3
+ Changes:
4
+ - Initial release.
data/README ADDED
@@ -0,0 +1,30 @@
1
+ = SI -- Sather iterators for Ruby
2
+
3
+ This library allows one to write code of the form:
4
+
5
+ require 'si'
6
+ si_loop
7
+ x = somearray.si.each
8
+ y = anotherarray.si.each
9
+ # Process x and y
10
+ end
11
+
12
+ Full sather iterators provide much more. See the documentation for si.rb for
13
+ details. This extension was written as proof of concept to promote RCR 335 but
14
+ it is usable on its own. So if you like it, vote for it at http://www.rcrchive.net/rcr/show/335
15
+
16
+ == Installation
17
+
18
+ This is just a single ruby file, si.rb, that you can include in your project
19
+ and require as usual. It is cleaner to install it as a gem. It would be cleaner
20
+ yet if Ruby supported this out of the box (with a better syntax of course).
21
+ Did I mention you should vote for RCR 335?
22
+
23
+ == License
24
+
25
+ Active Record is released under the MIT license.
26
+
27
+ == Support
28
+
29
+ You can check out http://ben-kiki.org/oren/si for the latest news about this
30
+ gem.
@@ -0,0 +1,153 @@
1
+ #
2
+ # si.rb - Sather-like iterators for Ruby
3
+ #
4
+ # Author: Oren Ben-Kiki 2006
5
+ #
6
+ # == Overview
7
+ #
8
+ # This file extends Ruby with very basic support for sather-like iterators.
9
+ # Simply use "si_loop" instead of "loop" and prefix each iterator call with
10
+ # ".si".
11
+ #
12
+ # === Example
13
+ #
14
+ # a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
15
+ # h = { :A => :a, :B => :b, :C => :c, :D => :d }
16
+ # si_loop do
17
+ # puts "---"
18
+ # v1 = a.si(:foo1).each
19
+ # v2 = a.si(:foo1).each
20
+ # p [ v1, v2 ]
21
+ # p a.si.each
22
+ # p h.si.each
23
+ # end
24
+ #
25
+ # Produces:
26
+ #
27
+ # ---
28
+ # [0, 1]
29
+ # 0
30
+ # [:D, :d]
31
+ # ---
32
+ # [2, 3]
33
+ # 1
34
+ # [:A, :a]
35
+ # ---
36
+ # [4, 5]
37
+ # 2
38
+ # [:B, :b]
39
+ # ---
40
+ # [6, 7]
41
+ # 3
42
+ # [:C, :c]
43
+ # ---
44
+ # [8, 9]
45
+ # 4
46
+
47
+ # Context for Sather iteration loops.
48
+ #
49
+ # This class is not meant to be used directly. See the documentation for si.rb
50
+ # for an overview.
51
+ class SiContext
52
+
53
+ # Push a new context on the stack when a new loop begins.
54
+ def SiContext.push
55
+ @@maps ||= []
56
+ @@maps.push({})
57
+ end
58
+
59
+ # Pop the current context from the stack when a loop ends.
60
+ def SiContext.pop
61
+ @@maps.pop
62
+ end
63
+
64
+ # Access an SiInterator in the current scope. The +id+ uniquely identifies
65
+ # the iterator instance, and +object+ is the one that has the iterator
66
+ # method that will be wrapped.
67
+ def SiContext.iterator(id, object)
68
+ @@maps.last[id] ||= SiIterator.new(object)
69
+ end
70
+
71
+ end
72
+
73
+ # Wrap a Ruby iterator for a Sather iteration loop.
74
+ #
75
+ # This class is not meant to be used directly. Instances are created by calls
76
+ # to SiContext.iterator. See the documentation for si.rb for an overview.
77
+ class SiIterator
78
+
79
+ # Create a new iterator wrapper.
80
+ #
81
+ # +object+ is the object that provides the Ruby iterator method.
82
+ def initialize(object)
83
+ @object = object
84
+ @is_first_fetch = true
85
+ @to_call_out = true
86
+ @to_call_in = false
87
+ end
88
+
89
+ # Capture a call to a ruby iterator.
90
+ #
91
+ # It is implicitly assumed that the missing method is actually the call
92
+ # to the Ruby iterator meant for the original object. As usual, +symbol+ is
93
+ # the missing method name, and +args+ are the arguments passed to it.
94
+ def method_missing(symbol, *args)
95
+ si_fetch { |b| @object.send(symbol, *args, &b) }
96
+ end
97
+
98
+ # Fetch the next value from a Ruby iterator.
99
+ def si_fetch
100
+ callcc { |@out_cont| }
101
+ if @is_first_fetch
102
+ @is_first_fetch = false
103
+ yield Proc.new { |value| si_capture(value) }
104
+ si_break
105
+ elsif @to_call_in
106
+ @to_call_in = false
107
+ @in_cont.call
108
+ else
109
+ @to_call_in = true
110
+ end
111
+ @value
112
+ end
113
+
114
+ # Capture the value yielded by a Ruby iterator.
115
+ def si_capture(v)
116
+ @value = v
117
+ callcc { |@in_cont| }
118
+ if @to_call_out
119
+ @to_call_out = false
120
+ @out_cont.call
121
+ else
122
+ @to_call_out = true
123
+ end
124
+ end
125
+
126
+ end
127
+
128
+ module Kernel
129
+
130
+ # Return a Sather iterator wrapper for an iterator method. The optional +id+
131
+ # parameter identifies the iterator. If it is not provided, the source file
132
+ # and line number of the call serve as a unique id. This means that two calls
133
+ # in the same line for the same object will be treated as a single iterator
134
+ # unless explicitly given explicit +id+.
135
+ def si(id = caller[0])
136
+ SiContext.iterator(id, self)
137
+ end
138
+
139
+ # Begin a Sather iterator loop.
140
+ def si_loop(&block)
141
+ SiContext.push
142
+ catch(:si_break) { loop(&block) }
143
+ ensure
144
+ SiContext.pop
145
+ end
146
+
147
+ # Break a Sather iteration loop. A normal break statement will also work, but
148
+ # this one will work even if called from a sub-function, which may be useful.
149
+ def si_break
150
+ throw :si_break
151
+ end
152
+
153
+ end
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11
3
+ specification_version: 1
4
+ name: SI
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.1
7
+ date: 2006-06-06 00:00:00 -07:00
8
+ summary: Sather Iterators for Ruby
9
+ require_paths:
10
+ - lib
11
+ email: oren@ben-kiki.org
12
+ homepage: http://www.ben-kiki.org/oren/si
13
+ rubyforge_project:
14
+ description:
15
+ autorequire: si
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ authors:
29
+ - Oren Ben-Kiki
30
+ files:
31
+ - README
32
+ - CHANGELOG
33
+ - lib/si.rb
34
+ test_files: []
35
+
36
+ rdoc_options: []
37
+
38
+ extra_rdoc_files:
39
+ - README
40
+ executables: []
41
+
42
+ extensions: []
43
+
44
+ requirements: []
45
+
46
+ dependencies: []
47
+