lazy 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,46 @@
1
+ --- %YAML:1.0
2
+ - version: 0.9.6
3
+ date: 2006-06-16
4
+ changes:
5
+ lib/lazy/threadsafe.rb: moved into lib directory, minor tweaks
6
+ lib/lazy/future.rb: moved into lib directory
7
+ lib/lazy.rb: moved into lib directory, documentation updates
8
+ Rakefile: rakefile to do it all from Daniel Harple
9
+ lazy.gemspec: retired
10
+
11
+ - version: 0.9.5
12
+ date: 2006-02-18
13
+ changes:
14
+ lazy/stream.rb: Nuked. No lazy stream API for now, until I can find a more stetic way to do it.
15
+ lazy.rb:
16
+ - get rid of Kernel.force
17
+ - introduce locking API for threadsafety
18
+ - many documentation tweaks
19
+ - split Lazy::DivergenceError and Lazy::LazyException
20
+ - include real promise class in inspect output
21
+ lazy/threadsafe.rb: adds locking to promises to make them threadsafe
22
+ lazy/future.rb: transparent futures, built atop promises
23
+
24
+ - version: 0.2
25
+ date: 2005-12-10
26
+ changes:
27
+ lazy/stream.rb: added lazy streams with an Enumerable wrapper
28
+ lazy.rb:
29
+ - Lazy::Thunk becomes Lazy::Promise
30
+ - Lazy::Promise#inspect won't force evaluation anymore, but becomes
31
+ transparent once it is evaluated. This makes life in irb much
32
+ easier. Thanks to Tom Payne for the idea.
33
+ - rename force to demand (force is still available as an alias)
34
+ - rdoc tweaks
35
+ - dup reason backtrace rather than using it directly in DivergenceError
36
+ README: added
37
+ COPYING: added
38
+ CHANGELOG: added
39
+
40
+ - version: 0.1
41
+ date: 2005-10-05
42
+ changes:
43
+ lazy.rb:
44
+ - trap diverging computations and terminate with DivergenceError
45
+ - make thunks mostly transparent
46
+
data/COPYING ADDED
@@ -0,0 +1,2 @@
1
+ You may redistribute and/or modify this software under the same terms as Ruby.
2
+
data/README ADDED
@@ -0,0 +1,18 @@
1
+ lazy.rb provides lazy evaluation and futures in Ruby.
2
+
3
+ For lazy evaluation, the facilities are similar to those provided by R5 Scheme. There are two functions: Kernel.promise (similar to Scheme's delay) which takes a block for later evaluation, and Kernel.demand (similar to Scheme's force), which forces its evaluation (if necessary) and returns its cached result.
4
+
5
+ Unlike some Scheme implementations, it is safe to pass ordinary values to demand. Promises are also transparent, meaning that in most cases an evaluated promise is not distinguishable from the actual result object it wraps.
6
+
7
+ Originally, promises were not threadsafe unless you required 'lazy/threadsafe',
8
+ but today they are threadsafe by default. This does entail some amount of
9
+ synchronization overhead, which in Ruby 1.8 can be reduced by using fastthread.
10
+ (Other Ruby implementations like JRuby and 1.9 should have lower
11
+ synchronization overhead to start with.)
12
+
13
+ Additionally, the library provides futures, where a computation is run
14
+ optimistically in a background thread. Futures can be constructed using
15
+ Kernel.future. Based on promises, they are also transparent. An attempt to
16
+ demand the result of a future will block until the computation completes.
17
+
18
+ lazy.rb is made available under the same license as Ruby.
@@ -0,0 +1,3 @@
1
+ task :build do
2
+ system "gem build lazy.gemspec"
3
+ end
@@ -0,0 +1,223 @@
1
+ # = lazy.rb -- Lazy evaluation in Ruby
2
+ #
3
+ # Author:: MenTaLguY
4
+ #
5
+ # Copyright 2005-2006 MenTaLguY <mental@rydia.net>
6
+ #
7
+ # You may redistribute it and/or modify it under the same terms as Ruby.
8
+ #
9
+
10
+ require 'thread'
11
+
12
+ module Lazy
13
+
14
+ # Raised when a forced computation diverges (e.g. if it tries to directly
15
+ # use its own result)
16
+ #
17
+ class DivergenceError < Exception
18
+ def initialize( message="Computation diverges" )
19
+ super( message )
20
+ end
21
+ end
22
+
23
+ # Wraps an exception raised by a lazy computation.
24
+ #
25
+ # The reason we wrap such exceptions in LazyException is that they need to
26
+ # be distinguishable from similar exceptions which might normally be raised
27
+ # by whatever strict code we happen to be in at the time.
28
+ #
29
+ class LazyException < DivergenceError
30
+ # the original exception
31
+ attr_reader :reason
32
+
33
+ def initialize( reason )
34
+ @reason = reason
35
+ super( "Exception in lazy computation: #{ reason } (#{ reason.class })" )
36
+ set_backtrace( reason.backtrace.dup ) if reason
37
+ end
38
+ end
39
+
40
+ # A promise is just a magic object that springs to life when it is actually
41
+ # used for the first time, running the provided block and assuming the
42
+ # identity of the resulting object.
43
+ #
44
+ # This impersonation isn't perfect -- a promise wrapping nil or false will
45
+ # still be considered true by Ruby -- but it's good enough for most purposes.
46
+ # If you do need to unwrap the result object for some reason (e.g. for truth
47
+ # testing or for simple efficiency), you may do so via Kernel.demand.
48
+ #
49
+ # Formally, a promise is a placeholder for the result of a deferred computation.
50
+ #
51
+ class Promise
52
+ alias __class__ class #:nodoc:
53
+ instance_methods.each { |m| undef_method m unless m =~ /^__/ }
54
+
55
+ def initialize( &computation ) #:nodoc:
56
+ @mutex = Mutex.new
57
+ @computation = computation
58
+ end
59
+
60
+ # create this once here, rather than creating a proc object for
61
+ # every evaluation
62
+ DIVERGES = lambda { raise DivergenceError.new } #:nodoc:
63
+ def DIVERGES.inspect #:nodoc:
64
+ "DIVERGES"
65
+ end
66
+
67
+ def __result__ #:nodoc:
68
+ @mutex.synchronize do
69
+ if @computation
70
+ raise LazyException.new( @exception ) if @exception
71
+
72
+ computation = @computation
73
+ @computation = DIVERGES # trap divergence due to over-eager recursion
74
+
75
+ begin
76
+ @result = Lazy.demand( computation.call( self ) )
77
+ @computation = nil
78
+ rescue DivergenceError
79
+ raise
80
+ rescue Exception => exception
81
+ # handle exceptions
82
+ @exception = exception
83
+ raise LazyException.new( @exception )
84
+ end
85
+ end
86
+
87
+ @result
88
+ end
89
+ end
90
+
91
+ def inspect #:nodoc:
92
+ @mutex.synchronize do
93
+ if @computation
94
+ "#<#{ __class__ } computation=#{ @computation.inspect }>"
95
+ else
96
+ @result.inspect
97
+ end
98
+ end
99
+ end
100
+
101
+ def marshal_dump
102
+ __result__
103
+ Marshal.dump( [ @exception, @result ] )
104
+ end
105
+
106
+ def marshal_load( str )
107
+ @mutex = Mutex.new
108
+ ( @exception, @result ) = Marshal.load( str )
109
+ @computation = DIVERGES if @exception
110
+ end
111
+
112
+ def respond_to?( message ) #:nodoc:
113
+ message = message.to_sym
114
+ message == :__result__ or
115
+ message == :inspect or
116
+ message == :marshal_dump or
117
+ message == :marshal_load or
118
+ __result__.respond_to? message
119
+ end
120
+
121
+ def method_missing( *args, &block ) #:nodoc:
122
+ __result__.__send__( *args, &block )
123
+ end
124
+ end
125
+
126
+ Promise.ancestors.each do |c|
127
+ class << c
128
+ alias lazy_rb_method_added method_added
129
+ def method_added( name )
130
+ lazy_rb_method_added( name )
131
+ return unless Lazy::Promise < self
132
+ end
133
+ end
134
+ end
135
+
136
+ # A promise whose computation runs asynchronously in the background.
137
+ #
138
+ class Future < Promise
139
+ def initialize( scheduler=Thread, &computation ) #:nodoc:
140
+ task = scheduler.new { computation.call self }
141
+ super() do
142
+ raise DivergenceError if scheduler.current == task
143
+ task.value
144
+ end
145
+ end
146
+ end
147
+
148
+ module Methods
149
+ private
150
+
151
+ # Used together with Lazy::Methods#demand to implement
152
+ # lazy evaluation. It returns a promise to evaluate the provided
153
+ # block at a future time. Evaluation can be forced and the block's
154
+ # result obtained via
155
+ #
156
+ # Implicit evaluation is also supported: the first message sent to it will
157
+ # force evaluation, after which that message and any subsequent messages
158
+ # will be forwarded to the result object.
159
+ #
160
+ # As an aid to circular programming, the block will be passed a promise
161
+ # for its own result when it is evaluated. Be careful not to force
162
+ # that promise during the computation, lest the computation diverge.
163
+ #
164
+ def promise( &computation ) #:yields: own_result
165
+ Lazy::Promise.new &computation
166
+ end
167
+
168
+ # Forces the result of a promise to be computed (if necessary) and returns
169
+ # the bare result object. Once evaluated, the result of the promise will
170
+ # be cached. Nested promises will be evaluated together, until the first
171
+ # non-promise result.
172
+ #
173
+ # If called on a value that is not a promise, it will simply return it.
174
+ #
175
+ def demand( promise )
176
+ if promise.respond_to? :__result__
177
+ promise.__result__
178
+ else # not really a promise
179
+ promise
180
+ end
181
+ end
182
+
183
+ # Schedules a computation to be run asynchronously and returns a promise
184
+ # for its result. An attempt to force the result of the promise will
185
+ # block until the computation finishes.
186
+ #
187
+ # If +scheduler+ is not specified, the computation is run in a background
188
+ # thread which is joined when the result is forced. A scheduler should
189
+ # provide a method, new, which takes a block and returns a task
190
+ # object. The task object should provide a method, value, which awaits
191
+ # completion of the task, returning its result or raising the exception that
192
+ # terminated the task. The Thread class trivially satisfies this
193
+ # protocol.
194
+ #
195
+ # As with Lazy::Methods#demand, this passes the block a promise for its own
196
+ # result. Use wisely.
197
+ #
198
+ def future( scheduler=Thread, &computation ) #:yields: own_result
199
+ Lazy::Future.new scheduler, &computation
200
+ end
201
+
202
+ end
203
+
204
+ extend Methods
205
+ class << self
206
+ public :promise, :demand, :future
207
+ end
208
+
209
+ end
210
+
211
+ class Module
212
+ alias lazy_rb_method_added method_added
213
+ def method_added( name )
214
+ lazy_rb_method_added( name )
215
+ if Lazy::Promise < self
216
+ unless Lazy::Promise.instance_methods( true ).include? name.to_s
217
+ Lazy::Promise.class_eval { undef_method name }
218
+ end
219
+ end
220
+ nil
221
+ end
222
+ end
223
+
@@ -0,0 +1,10 @@
1
+ # = lazy/futures.rb -- Stub for backwards-compatibility
2
+ #
3
+ # Author:: MenTaLguY
4
+ #
5
+ # Copyright 2010 MenTaLguY <mental@rydia.net>
6
+ #
7
+ # You may redistribute it and/or modify it under the same terms as Ruby.
8
+ #
9
+
10
+ require 'lazy/threadsafe'
@@ -0,0 +1,10 @@
1
+ # = lazy/threadsafe.rb -- Stub for backwards-compatibility
2
+ #
3
+ # Author:: MenTaLguY
4
+ #
5
+ # Copyright 2010 MenTaLguY <mental@rydia.net>
6
+ #
7
+ # You may redistribute it and/or modify it under the same terms as Ruby.
8
+ #
9
+
10
+ require 'lazy'
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lazy
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 9
8
+ - 6
9
+ version: 0.9.6
10
+ platform: ruby
11
+ authors:
12
+ - MenTaLguY
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-09-15 00:00:00 -07:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: lazy.rb is a library providing transparent lazy evaluation and futures for Ruby.
22
+ email: mental@rydia.net
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - README
29
+ files:
30
+ - README
31
+ - COPYING
32
+ - Rakefile
33
+ - CHANGELOG
34
+ - lib/lazy.rb
35
+ - lib/lazy/futures.rb
36
+ - lib/lazy/threadsafe.rb
37
+ has_rdoc: true
38
+ homepage: http://moonbase.rydia.net/software/lazy.rb/
39
+ licenses: []
40
+
41
+ post_install_message:
42
+ rdoc_options:
43
+ - --main
44
+ - README
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ segments:
52
+ - 0
53
+ version: "0"
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ requirements: []
62
+
63
+ rubyforge_project:
64
+ rubygems_version: 1.3.6
65
+ signing_key:
66
+ specification_version: 3
67
+ summary: Lazy evaluation for Ruby
68
+ test_files: []
69
+