with_statement 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -5,22 +5,46 @@ with statement.
5
5
 
6
6
  Simple usage:
7
7
 
8
- with expression do |resource|
9
- # ... interact with resource ...
10
- end
8
+ with expression do |resource|
9
+ # ... interact with resource ...
10
+ end
11
11
 
12
- The expression passed must return a context manager. A context manager
13
- is an object which implements two methods: +acquire+ and
14
- +release+. When Kernel#with receives the context manager it calls its
15
- +acquire+ method and grab the result. Then it yields the result to the
16
- block. When the block returns, the context manager send the +release+
17
- message to the context manager.
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.1
1
+ 0.2.0
@@ -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(resource)
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
-
@@ -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 Exception.new "Already acquired" if @locked
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 Exception.new "Not acquired" unless @locked
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 Exception do
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
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{with_statement}
8
- s.version = "0.1.1"
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{2010-12-06}
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: 25
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
9
- - 1
10
- version: 0.1.1
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: 2010-12-06 00:00:00 -05:00
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
- requirement: &id001 !ruby/object:Gem::Requirement
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
- prerelease: false
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
- requirement: &id002 !ruby/object:Gem::Requirement
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
- prerelease: false
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
- requirement: &id003 !ruby/object:Gem::Requirement
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
- prerelease: false
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
- requirement: &id004 !ruby/object:Gem::Requirement
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
- prerelease: false
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: []