with_statement 0.1.1 → 0.2.0
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/README.rdoc +34 -10
- data/VERSION +1 -1
- data/lib/with_statement.rb +17 -2
- data/test/test_with_statement.rb +67 -4
- data/with_statement.gemspec +2 -2
- metadata +21 -21
data/README.rdoc
CHANGED
@@ -5,22 +5,46 @@ with statement.
|
|
5
5
|
|
6
6
|
Simple usage:
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
with expression do |resource|
|
9
|
+
# ... interact with resource ...
|
10
|
+
end
|
11
11
|
|
12
|
-
The expression
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
block
|
17
|
-
|
12
|
+
The expression must return a context manager. A context manager is an
|
13
|
+
object which implements two methods: +acquire+ and +release+. When
|
14
|
+
Kernel#with receives the context manager it calls its +acquire+ method
|
15
|
+
and grab the result. Then it yields the result to the block. When the
|
16
|
+
block returns, the context manager send the +release+ message to the
|
17
|
+
context manager.
|
18
18
|
|
19
19
|
Kernel#with by itself does not attempt to run +acquire+ or +release+
|
20
20
|
atomically; the context manager should ensure that if required.
|
21
21
|
|
22
|
+
Since 0.2.0 release you can put several context managers in a single
|
23
|
+
with sentence:
|
24
|
+
|
25
|
+
with exp1, exp2 do |r1, r2|
|
26
|
+
# do something with the acquired resources
|
27
|
+
end
|
28
|
+
|
29
|
+
That sentence it's semantically equivalent to:
|
30
|
+
|
31
|
+
with exp1 do |r1|
|
32
|
+
with exp2 do }r2|
|
33
|
+
# do something with the acquired resources
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
The general syntax for the Kernel#with method is:
|
38
|
+
|
39
|
+
with(*managers){|*resources|
|
40
|
+
#code
|
41
|
+
}
|
42
|
+
|
43
|
+
If any of the context managers fails to enter (acquire), the block is
|
44
|
+
never executed and any previous acquired resource is released.
|
45
|
+
|
22
46
|
== Contributing to with_statement
|
23
|
-
|
47
|
+
|
24
48
|
* Check out the latest master to make sure the feature hasn't been
|
25
49
|
implemented or the bug hasn't been fixed yet
|
26
50
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/lib/with_statement.rb
CHANGED
@@ -3,7 +3,23 @@ module Kernel
|
|
3
3
|
# Similar to Python's with statement. This statement enters the
|
4
4
|
# context of an object +resource+, executes the block, and exits the
|
5
5
|
# context.
|
6
|
-
def with(
|
6
|
+
def with(*resources, &block)
|
7
|
+
raise SyntaxError, 'with statement called with no arguments' if resources.size == 0
|
8
|
+
if resources.size == 1
|
9
|
+
simple_with(resources.shift, &block)
|
10
|
+
else
|
11
|
+
simple_with(resources.shift) do |what|
|
12
|
+
with(*resources) {|*rs|
|
13
|
+
args = [what] + rs
|
14
|
+
block.call(*args)
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def simple_with(resource, &block)
|
7
23
|
what = resource.acquire
|
8
24
|
begin
|
9
25
|
yield(what)
|
@@ -12,4 +28,3 @@ module Kernel
|
|
12
28
|
end
|
13
29
|
end
|
14
30
|
end
|
15
|
-
|
data/test/test_with_statement.rb
CHANGED
@@ -2,6 +2,8 @@ require 'helper'
|
|
2
2
|
|
3
3
|
class TestWithStatement < Test::Unit::TestCase
|
4
4
|
context "A simple non-reentrant resource class" do
|
5
|
+
class ResourceException < Exception; end
|
6
|
+
|
5
7
|
class Resource
|
6
8
|
attr_reader :locked
|
7
9
|
|
@@ -10,13 +12,13 @@ class TestWithStatement < Test::Unit::TestCase
|
|
10
12
|
end
|
11
13
|
|
12
14
|
def acquire
|
13
|
-
raise
|
15
|
+
raise ResourceException.new "Already acquired" if @locked
|
14
16
|
@locked = true
|
15
17
|
self
|
16
18
|
end
|
17
19
|
|
18
20
|
def release
|
19
|
-
raise
|
21
|
+
raise ResourceException.new "Not acquired" unless @locked
|
20
22
|
@locked = false
|
21
23
|
end
|
22
24
|
|
@@ -25,20 +27,37 @@ class TestWithStatement < Test::Unit::TestCase
|
|
25
27
|
end
|
26
28
|
end
|
27
29
|
|
30
|
+
class LockedResource < Resource
|
31
|
+
def initialize
|
32
|
+
super
|
33
|
+
@locked = true
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class WeirdException < Exception; end
|
38
|
+
|
28
39
|
setup do
|
29
40
|
@resource = Resource.new
|
41
|
+
@inner = Resource.new
|
42
|
+
@locked = LockedResource.new
|
30
43
|
end
|
31
44
|
|
32
45
|
should "be locked within with statement, and release outside it" do
|
33
|
-
with @resource do
|
46
|
+
with @resource do
|
34
47
|
assert @resource.locked
|
35
48
|
end
|
36
49
|
assert !@resource.locked
|
37
50
|
end
|
38
51
|
|
52
|
+
should 'raise an exception on a locked resource' do
|
53
|
+
assert_raise ResourceException do
|
54
|
+
with @locked do; end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
39
58
|
should "raise an exception when double locked" do
|
40
59
|
with @resource do
|
41
|
-
assert_raise
|
60
|
+
assert_raise ResourceException do
|
42
61
|
with @resource do; end
|
43
62
|
end
|
44
63
|
end
|
@@ -50,5 +69,49 @@ class TestWithStatement < Test::Unit::TestCase
|
|
50
69
|
assert what.do_something
|
51
70
|
end
|
52
71
|
end
|
72
|
+
|
73
|
+
should "allow nested withs" do
|
74
|
+
with @resource do |a|
|
75
|
+
with @inner do |b|
|
76
|
+
assert @resource.locked
|
77
|
+
assert @inner.locked
|
78
|
+
end
|
79
|
+
assert @resource.locked
|
80
|
+
assert !@inner.locked
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
should "allow multiple context managers" do
|
85
|
+
with @resource, @inner do |a, b, *others|
|
86
|
+
assert a == @resource
|
87
|
+
assert b == @inner
|
88
|
+
assert others == [], 'no more resources'
|
89
|
+
assert @resource.locked
|
90
|
+
assert @inner.locked
|
91
|
+
end
|
92
|
+
assert !@resource.locked
|
93
|
+
assert !@inner.locked
|
94
|
+
end
|
95
|
+
|
96
|
+
should 'release the first resource if the second fails to enter' do
|
97
|
+
assert_raise ResourceException do
|
98
|
+
with @resource, @locked do
|
99
|
+
raise StandardError, 'This exception should not be raised; because this code should never be called'
|
100
|
+
end
|
101
|
+
end
|
102
|
+
assert !@resource.locked
|
103
|
+
end
|
104
|
+
|
105
|
+
should 'raise a SyntaxError when no context managers are given' do
|
106
|
+
assert_raise SyntaxError do
|
107
|
+
with {}
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
should 'raise an exception if no block is given' do
|
112
|
+
assert_raise LocalJumpError do
|
113
|
+
with @resource
|
114
|
+
end
|
115
|
+
end
|
53
116
|
end
|
54
117
|
end
|
data/with_statement.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{with_statement}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Manuel V\303\241zquez Acosta"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2011-01-02}
|
13
13
|
s.description = %q{With statements opens the Kernel and defines a with method which behaves similar to Python with statement}
|
14
14
|
s.email = %q{mva.led@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: with_statement
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- "Manuel V\xC3\xA1zquez Acosta"
|
@@ -15,12 +15,14 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2011-01-02 00:00:00 -05:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
22
24
|
name: shoulda
|
23
|
-
|
25
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
24
26
|
none: false
|
25
27
|
requirements:
|
26
28
|
- - ">="
|
@@ -29,12 +31,12 @@ dependencies:
|
|
29
31
|
segments:
|
30
32
|
- 0
|
31
33
|
version: "0"
|
32
|
-
|
33
|
-
type: :development
|
34
|
-
version_requirements: *id001
|
34
|
+
requirement: *id001
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
|
+
type: :development
|
37
|
+
prerelease: false
|
36
38
|
name: bundler
|
37
|
-
|
39
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
38
40
|
none: false
|
39
41
|
requirements:
|
40
42
|
- - ~>
|
@@ -45,12 +47,12 @@ dependencies:
|
|
45
47
|
- 0
|
46
48
|
- 0
|
47
49
|
version: 1.0.0
|
48
|
-
|
49
|
-
type: :development
|
50
|
-
version_requirements: *id002
|
50
|
+
requirement: *id002
|
51
51
|
- !ruby/object:Gem::Dependency
|
52
|
+
type: :development
|
53
|
+
prerelease: false
|
52
54
|
name: jeweler
|
53
|
-
|
55
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
54
56
|
none: false
|
55
57
|
requirements:
|
56
58
|
- - ~>
|
@@ -61,12 +63,12 @@ dependencies:
|
|
61
63
|
- 5
|
62
64
|
- 1
|
63
65
|
version: 1.5.1
|
64
|
-
|
65
|
-
type: :development
|
66
|
-
version_requirements: *id003
|
66
|
+
requirement: *id003
|
67
67
|
- !ruby/object:Gem::Dependency
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
68
70
|
name: rcov
|
69
|
-
|
71
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
70
72
|
none: false
|
71
73
|
requirements:
|
72
74
|
- - ">="
|
@@ -75,9 +77,7 @@ dependencies:
|
|
75
77
|
segments:
|
76
78
|
- 0
|
77
79
|
version: "0"
|
78
|
-
|
79
|
-
type: :development
|
80
|
-
version_requirements: *id004
|
80
|
+
requirement: *id004
|
81
81
|
description: With statements opens the Kernel and defines a with method which behaves similar to Python with statement
|
82
82
|
email: mva.led@gmail.com
|
83
83
|
executables: []
|