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 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: []