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.
- data/CHANGELOG +4 -0
- data/README +30 -0
- data/lib/si.rb +153 -0
- metadata +47 -0
data/CHANGELOG
ADDED
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.
|
data/lib/si.rb
ADDED
@@ -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
|
+
|