SI 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|