SI 0.0.1

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