Skip to content

Commit 3d42ba1

Browse files
committed
New Promises documentation and updates
- evaluator of ruby code in markdown files added - document all public methods with YARD (and macros) - hide properly everything private - better OO structure, Future is no longer an Event's child, they share common parent instead, private callback methods simplified - flat_future and flat_event added - schedule fixed on event - CompletableFuture API simplified - removed bad aliases: :complete?, :async - run method added to support green-threads like usage - rewrite new MD guide remains
1 parent 23d3cdf commit 3d42ba1

File tree

8 files changed

+1393
-772
lines changed

8 files changed

+1393
-772
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ We also have a [mailing list](http://groups.google.com/group/concurrent-ruby) an
6666
#### General-purpose Concurrency Abstractions
6767

6868
* [Async](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Async.html): A mixin module that provides simple asynchronous behavior to a class. Loosely based on Erlang's [gen_server](http://www.erlang.org/doc/man/gen_server.html).
69-
* [Promises Framework](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Promises/FutureFactoryMethods.html):
69+
* [Promises Framework](http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Promises.html):
7070
Unified implementation of futures and promises which combines features of previous `Future`,
7171
`Promise`, `IVar`, `Event`, `dataflow`, `Delay`, and `TimerTask` into a single framework. It extensively uses the
7272
new synchronization layer to make all the features **non-blocking** and **lock-free**, with the exception of obviously blocking

doc/format-md.rb

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
require 'rubygems'
2+
require 'bundler/setup'
3+
require 'pry'
4+
require 'pp'
5+
6+
class MDFormatter
7+
8+
def initialize(input_file, environment)
9+
@input_path = input_file
10+
@environment = environment
11+
@output = ''
12+
13+
process_file input_file
14+
end
15+
16+
def evaluate (code, line)
17+
eval(code, @environment, @input_path, line)
18+
end
19+
20+
def process_ruby(part, start_line)
21+
lines = part.lines
22+
chunks = []
23+
line = ''
24+
25+
while !lines.empty?
26+
line += lines.shift
27+
if Pry::Code.complete_expression? line
28+
chunks << line
29+
line = ''
30+
end
31+
end
32+
33+
raise unless line.empty?
34+
35+
chunk_lines = chunks.map { |chunk| [chunk, [chunk.split($/).size, 1].max] }
36+
indent = 40
37+
38+
line_count = start_line
39+
output = ''
40+
chunk_lines.each do |chunk, lines|
41+
result = evaluate(chunk, line_count)
42+
if chunk.strip.empty? || chunk.include?('#')
43+
output << chunk
44+
else
45+
pre_lines = chunk.lines.to_a
46+
last_line = pre_lines.pop
47+
output << pre_lines.join
48+
49+
if last_line =~ /\#$/
50+
output << last_line.gsub(/\#$/, '')
51+
else
52+
if last_line.size < indent && result.inspect.size < indent
53+
output << "%-#{indent}s %s" % [last_line.chomp, "# => #{result.inspect}\n"]
54+
else
55+
inspect_lines = result.pretty_inspect.lines
56+
output << last_line << "# => #{inspect_lines[0]}" << inspect_lines[1..-1].map { |l| format '# %s', l }.join
57+
end
58+
end
59+
end
60+
line_count += lines
61+
end
62+
output
63+
end
64+
65+
def process_file(input_path)
66+
output_path = input_path.gsub /\.in\.md$/, '.out.md'
67+
input = File.read(input_path)
68+
parts = input.split(/^(```\w*\n)/)
69+
70+
# pp parts.map(&:lines)
71+
72+
code_block = nil
73+
line_count = 1
74+
75+
parts.each do |part|
76+
if part =~ /^```(\w+)$/
77+
code_block = $1
78+
@output << part
79+
line_count += 1
80+
next
81+
end
82+
83+
if part =~ /^```$/
84+
code_block = nil
85+
@output << part
86+
line_count += 1
87+
next
88+
end
89+
90+
if code_block == 'ruby'
91+
@output << process_ruby(part, line_count)
92+
line_count += part.lines.size
93+
next
94+
end
95+
96+
@output << part
97+
line_count += part.lines.size
98+
end
99+
100+
puts "#{input_path}\n -> #{output_path}"
101+
File.write(output_path, @output)
102+
rescue => ex
103+
puts "#{ex} (#{ex.class})\n#{ex.backtrace * "\n"}"
104+
105+
end
106+
end
107+
108+
input_paths = if ARGV.empty?
109+
Dir.glob("#{File.dirname(__FILE__)}/*.in.md")
110+
else
111+
ARGV
112+
end.map { |p| File.expand_path p }
113+
114+
input_paths.each_with_index do |input_path, i|
115+
116+
pid = fork do
117+
require_relative 'init.rb'
118+
MDFormatter.new input_path, binding
119+
end
120+
121+
Process.wait pid
122+
end

doc/init.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
require 'concurrent-edge'
2+
3+
def do_stuff
4+
:stuff
5+
end
6+
7+
Concurrent.use_stdlib_logger Logger::DEBUG

examples/promises.in.rb renamed to doc/promises.in.md

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,57 @@
1-
# Adds factory methods like: future, event, delay, schedule, zip, ...
2-
# otherwise they can be called on Promises module
3-
include Concurrent::Promises::FactoryMethods #
1+
# Promises Framework
2+
3+
Promises is a new framework unifying former `Concurrent::Future`, `Concurrent::Promise`, `Concurrent::IVar`,
4+
`Concurrent::Event`, `Concurrent.dataflow`, `Delay`, and `TimerTask`. It extensively uses the new
5+
synchronization layer to make all the features **non-blocking** and
6+
**lock-free**, with the exception of obviously blocking operations like
7+
`#wait`, `#value`. As a result it lowers a danger of deadlocking and offers
8+
better performance.
9+
10+
## Overview
11+
12+
There are two central classes ... TODO
13+
14+
## Where does it executes?
15+
16+
- TODO Explain `_on` `_using` sufixes.
17+
18+
## Old examples follow
419

20+
*TODO rewrite into md with examples*
521

6-
### Simple asynchronous task
22+
Adds factory methods like: future, event, delay, schedule, zip, etc. Otherwise
23+
they can be called on Promises module.
724

25+
```ruby
26+
Concurrent::Promises::FactoryMethods.instance_methods false
27+
28+
include Concurrent::Promises::FactoryMethods #
29+
```
30+
31+
Simple asynchronous task:
32+
33+
```ruby
834
future = future(0.1) { |duration| sleep duration; :result } # evaluation starts immediately
935
future.completed?
1036
# block until evaluated
1137
future.value
1238
future.completed?
39+
```
1340

41+
Failing asynchronous task
1442

15-
### Failing asynchronous task
16-
43+
```ruby
1744
future = future { raise 'Boom' }
1845
future.value
1946
future.value! rescue $!
2047
future.reason
2148
# re-raising
2249
raise future rescue $!
50+
```
2351

52+
Direct creation of completed futures
2453

25-
### Direct creation of completed futures
26-
54+
```ruby
2755
succeeded_future(Object.new)
2856
failed_future(StandardError.new("boom"))
2957

@@ -129,7 +157,7 @@
129157

130158
future.success 1
131159
future.success 1 rescue $!
132-
future.try_success 2
160+
future.success 2, false
133161
event.complete
134162

135163
# The threads can be joined now
@@ -158,7 +186,7 @@
158186
# executed on :fast executor, only short and non-blocking tasks can go there
159187
future_on(:fast) { 2 }.
160188
# executed on executor for blocking and long operations
161-
then_on(:io) { File.read __FILE__ }.
189+
then_using(:io) { File.read __FILE__ }.
162190
wait
163191

164192

@@ -288,3 +316,4 @@ def schedule_job(interval, &job)
288316
end #
289317

290318
zip(*concurrent_jobs).value!
319+
```

0 commit comments

Comments
 (0)