contextr 0.0.1

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.
@@ -0,0 +1,117 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ class ContextRApiFoo
4
+ def non_contextified_method
5
+ "non_contextified_method"
6
+ end
7
+ def foo
8
+ "foo"
9
+ end
10
+ end
11
+
12
+ context 'Each class' do
13
+ specify 'should provide a method to enable a single layer' do
14
+ lambda do
15
+ class ContextRApiFoo
16
+ layer :bar
17
+ end
18
+ end.should_not raise_error
19
+ end
20
+
21
+ specify 'should provide a method to access these layers by name' do
22
+ begin
23
+ class ContextRApiFoo
24
+ bar
25
+ end
26
+ end.layer.should == ContextR::BarLayer
27
+ end
28
+ end
29
+
30
+ context 'Each layer in a class' do
31
+ specify 'should allow the definition of pre method wrappers ' +
32
+ 'with `pre`' do
33
+ lambda do
34
+ class ContextRApiFoo
35
+ bar.pre :foo do
36
+ @pre_visited = true
37
+ @pre_count = ( @pre_count || 0 ) + 1
38
+ end
39
+ end
40
+ end.should_not raise_error
41
+ end
42
+ specify 'should allow the definition of post method wrappers ' +
43
+ 'with `post`' do
44
+ lambda do
45
+ class ContextRApiFoo
46
+ bar.post :foo do
47
+ @post_visited = true
48
+ @post_count = ( @post_count || 0 ) + 1
49
+ end
50
+ end
51
+ end.should_not raise_error
52
+ end
53
+ specify 'should allow the definition of around method wrappers ' +
54
+ 'with `around`' do
55
+ lambda do
56
+ class ContextRApiFoo
57
+ bar.around :foo do | method_nature |
58
+ @around_visited = true
59
+ @around_count = ( @around_count || 0 ) + 1
60
+ method_nature.call_next
61
+ end
62
+ end
63
+ end.should_not raise_error
64
+ end
65
+ specify 'should allow the definition of around method wrappers ' +
66
+ 'with `wrap`' do
67
+ lambda do
68
+ class ContextRApiFoo
69
+ bar.wrap :foo do | method_nature |
70
+ @around_visited = true
71
+ @around_count = ( @around_count || 0 ) + 1
72
+ method_nature.call_next
73
+ end
74
+ end
75
+ end.should_not raise_error
76
+ end
77
+ end
78
+
79
+ context "An instance of a contextified class" do
80
+ setup do
81
+ @instance = ContextRApiFoo.new
82
+ end
83
+
84
+ specify "should run a simple method " +
85
+ "*normally* when all layers are deactivated" do
86
+ @instance.non_contextified_method.should == "non_contextified_method"
87
+ end
88
+
89
+ specify "should run a simple method " +
90
+ "*normally* when any layer is activated" do
91
+ ContextR.with_layers( :bar ) do
92
+ @instance.non_contextified_method.should == "non_contextified_method"
93
+ end
94
+ end
95
+
96
+ specify "should run a contextified method " +
97
+ "*normally* when all layers are deactivated" do
98
+ @instance.foo.should == "foo"
99
+ end
100
+
101
+ specify "should run a contextified method " +
102
+ "*normally* when any layer is activated" do
103
+ ContextR.with_layers( :baz ) do
104
+ @instance.foo.should == "foo"
105
+ end
106
+ end
107
+
108
+ specify "should run a contextified method with " +
109
+ "additional behaviour when a specific layer is activated" do
110
+ ContextR.with_layers( :bar ) do
111
+ @instance.foo.should == "foo"
112
+ end
113
+ @instance.instance_variable_get( :@pre_visited ).should == true
114
+ @instance.instance_variable_get( :@post_visited ).should == true
115
+ @instance.instance_variable_get( :@around_visited ).should == true
116
+ end
117
+ end
@@ -0,0 +1,99 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ context 'Each first level module' do
4
+ specify 'should have the same name and namespace_free_name' do
5
+ Math.namespace_free_name.should == Math.name
6
+ Kernel.namespace_free_name.should == Kernel.name
7
+ end
8
+
9
+ specify 'should have a namespace_free_name matching their constant' do
10
+ Kernel.namespace_free_name.should == Kernel.to_s
11
+ Kernel.namespace_free_name.should == "Kernel"
12
+ end
13
+ end
14
+
15
+ context 'Each sublevel module' do
16
+ setup do
17
+ module ModuleTestA
18
+ module B
19
+ module C
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ specify 'should have a namespace free namespace_free_name' do
26
+ ModuleTestA::B.namespace_free_name.should == "B"
27
+ ModuleTestA::B::C.namespace_free_name.should == "C"
28
+ end
29
+ end
30
+
31
+ context "Each module" do
32
+ specify "should have a attr_accessor_with_default_setter" do
33
+ lambda do
34
+ class ClassSpecA
35
+ attr_accessor_with_default_setter :miau do
36
+ {}
37
+ end
38
+ end
39
+ end.should_not raise_error
40
+ end
41
+ end
42
+
43
+ context "Each instance" do
44
+ setup do
45
+ @instance = ClassSpecA.new
46
+ @instance2 = ClassSpecA.new
47
+ end
48
+ specify "should provide a getter method" do
49
+ @instance.should_respond_to :miau
50
+ end
51
+ specify "should provide a setter method" do
52
+ @instance.should_respond_to :miau=
53
+ end
54
+
55
+ end
56
+
57
+ context "A getter method" do
58
+ setup do
59
+ @getter = ClassSpecA.instance_method( :miau )
60
+ @instance = ClassSpecA.new
61
+ @instance2 = ClassSpecA.new
62
+ end
63
+
64
+ specify "should not expect a parameter" do
65
+ @getter.arity.should == 0
66
+ end
67
+
68
+ specify "should provide the default value" do
69
+ @instance.miau.should == Hash.new
70
+ end
71
+
72
+ specify "should provide the default value also multiple times" do
73
+ @instance.miau.object_id.should == @instance.miau.object_id
74
+ end
75
+
76
+ specify "should provide the different default values for different " +
77
+ "instances" do
78
+ @instance2.miau.object_id.should_not == @instance.miau.object_id
79
+ end
80
+ end
81
+
82
+ context "A setter method" do
83
+ setup do
84
+ @setter = ClassSpecA.instance_method( :miau= )
85
+ @instance = ClassSpecA.new
86
+ @instance2 = ClassSpecA.new
87
+ end
88
+
89
+ specify "should not expect a parameter" do
90
+ @setter.arity.should == 1
91
+ end
92
+
93
+ specify "should allow the setting of the corresonding instance variable" do
94
+ begin
95
+ @instance.miau = "blue"
96
+ end.should == "blue"
97
+ @instance.instance_variable_get( :@miau ).should == "blue"
98
+ end
99
+ end
@@ -0,0 +1,61 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ class ProcSpecFoo
4
+ def non_contextified_method
5
+ "non_contextified_method"
6
+ end
7
+ def foo
8
+ "foo"
9
+ end
10
+ end
11
+
12
+ context "A Proc" do
13
+ setup do
14
+ @a = lambda do @a = true; "a" end
15
+ @b = lambda do @b = true; "b" end
16
+ @foo = ProcSpecFoo.new
17
+ end
18
+
19
+ specify "should convert itself to an unbound method" do
20
+ @b.to_unbound_method( ProcSpecFoo ).should_be_kind_of UnboundMethod
21
+ end
22
+
23
+ specify "which should be bindable to an instance of the specified class" do
24
+ lambda do
25
+ @b.to_unbound_method( ProcSpecFoo ).bind( @foo )
26
+ end.should_not raise_error
27
+ end
28
+
29
+ specify "which should execute the proc in turn" do
30
+ @b.to_unbound_method( ProcSpecFoo ).bind( @foo ).call.should == "b"
31
+ @foo.instance_variable_get( :@b ).should == true
32
+ end
33
+
34
+ specify "should respond to `+`" do
35
+ @b.should_respond_to :+
36
+ end
37
+
38
+ specify "should build a joined block with `self.+( other_proc)`" do
39
+ (@a + @b).should_be_kind_of Proc
40
+ end
41
+ end
42
+
43
+ context "The result of `+` of two Procs" do
44
+ setup do
45
+ @a = lambda do | arg |
46
+ arg || "a"
47
+ end
48
+ @b = lambda do | arg |
49
+ arg || "b"
50
+ end
51
+ end
52
+
53
+ specify "should give the correct return value" do
54
+ (@a + @b).call( nil ).should == "b"
55
+ (@b + @a).call( nil ).should == "a"
56
+ end
57
+
58
+ specify "should pass through given parameters" do
59
+ (@a + @b).call( 1 ).should == 1
60
+ end
61
+ end
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + '/../lib/contextr'
@@ -0,0 +1,107 @@
1
+ # The following copyright applies to this File
2
+ # which we borrowed from rails.
3
+ #
4
+ # Copyright (c) 2004 David Heinemeier Hansson
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining
7
+ # a copy of this software and associated documentation files (the
8
+ # "Software"), to deal in the Software without restriction, including
9
+ # without limitation the rights to use, copy, modify, merge, publish,
10
+ # distribute, sublicense, and/or sell copies of the Software, and to
11
+ # permit persons to whom the Software is furnished to do so, subject to
12
+ # the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be
15
+ # included in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+ class SourceAnnotationExtractor
25
+ class Annotation < Struct.new(:line, :tag, :text)
26
+ def to_s(options={})
27
+ s = "[%3d] " % line
28
+ s << "[#{tag}] " if options[:tag]
29
+ s << text
30
+ end
31
+ end
32
+
33
+ def self.enumerate(tag, options={})
34
+ extractor = new(tag)
35
+ extractor.display(extractor.find, options)
36
+ end
37
+
38
+ attr_reader :tag
39
+
40
+ def initialize(tag)
41
+ @tag = tag
42
+ end
43
+
44
+ def find(dirs=%w(app lib test))
45
+ dirs.inject({}) { |h, dir| h.update(find_in(dir)) }
46
+ end
47
+
48
+ def find_in(dir)
49
+ results = {}
50
+
51
+ Dir.glob("#{dir}/*") do |item|
52
+ next if File.basename(item)[0] == ?.
53
+
54
+ if File.directory?(item)
55
+ results.update(find_in(item))
56
+ elsif item =~ /\.r(?:b|xml|js)$/
57
+ results.update(extract_annotations_from(item, /#\s*(#{tag}):?\s*(.*)$/))
58
+ elsif item =~ /\.rhtml$/
59
+ results.update(extract_annotations_from(item, /<%\s*#\s*(#{tag}):?\s*(.*?)\s*%>/))
60
+ end
61
+ end
62
+
63
+ results
64
+ end
65
+
66
+ def extract_annotations_from(file, pattern)
67
+ lineno = 0
68
+ result = File.readlines(file).inject([]) do |list, line|
69
+ lineno += 1
70
+ next list unless line =~ pattern
71
+ list << Annotation.new(lineno, $1, $2)
72
+ end
73
+ result.empty? ? {} : { file => result }
74
+ end
75
+
76
+ def display(results, options={})
77
+ results.keys.sort.each do |file|
78
+ puts "#{file}:"
79
+ results[file].each do |note|
80
+ puts " * #{note.to_s(options)}"
81
+ end
82
+ puts
83
+ end
84
+ end
85
+ end
86
+
87
+ desc "Enumerate all annotations"
88
+ task :notes do
89
+ SourceAnnotationExtractor.enumerate "OPTIMIZE|FIXME|TODO", :tag => true
90
+ end
91
+
92
+ namespace :notes do
93
+ desc "Enumerate all OPTIMIZE annotations"
94
+ task :optimize do
95
+ SourceAnnotationExtractor.enumerate "OPTIMIZE"
96
+ end
97
+
98
+ desc "Enumerate all FIXME annotations"
99
+ task :fixme do
100
+ SourceAnnotationExtractor.enumerate "FIXME"
101
+ end
102
+
103
+ desc "Enumerate all TODO annotations"
104
+ task :todo do
105
+ SourceAnnotationExtractor.enumerate "TODO"
106
+ end
107
+ end
@@ -0,0 +1,165 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class UnitContextRFoo
4
+ layer :pre, :post, :wrap
5
+ layer :stop_wrap, :stop_pre, :stop_post
6
+ layer :order_wrap, :order_pre, :order_post
7
+ layer :group_pre, :group_post
8
+
9
+ def bar( sum )
10
+ sum + 0b00100
11
+ end
12
+
13
+ pre.pre :bar do | nature |
14
+ nature.arguments[ 0 ] += 0b00010
15
+ end
16
+
17
+ post.post :bar do | nature |
18
+ nature.return_value += 0b01000
19
+ end
20
+
21
+ wrap.wrap :bar do | nature |
22
+ nature.arguments[ 0 ] += 0b00001
23
+ nature.call_next
24
+ nature.return_value += 0b10000
25
+ end
26
+
27
+ stop_pre.pre :bar do | nature |
28
+ nature.break! nature.arguments[0]
29
+ end
30
+ stop_wrap.wrap :bar do | nature |
31
+ nature.break! nature.arguments[0]
32
+ end
33
+ stop_post.post :bar do | nature |
34
+ nature.break! nature.return_value
35
+ end
36
+
37
+ order_pre.pre :bar do | nature |
38
+ nature.break! :pre
39
+ end
40
+
41
+ order_post.post :bar do | nature |
42
+ nature.break! :post
43
+ end
44
+
45
+ order_wrap.wrap :bar do | nature |
46
+ nature.break! :wrap
47
+ end
48
+
49
+ group_pre.pre :bar do | nature |
50
+ nature.return_value = :pre
51
+ end
52
+
53
+ group_pre.pre :bar do | nature |
54
+ nature.break! nature.return_value
55
+ end
56
+
57
+ group_post.post :bar do | nature |
58
+ nature.return_value = :post
59
+ end
60
+
61
+ group_post.post :bar do | nature |
62
+ nature.break! nature.return_value
63
+ end
64
+ end
65
+
66
+
67
+ class ContextRTest < Test::Unit::TestCase
68
+ def setup
69
+ @foo = UnitContextRFoo.new
70
+ end
71
+
72
+ def test_01_layer_activiation
73
+ assert_equal 0b00100, @foo.bar( 0 )
74
+
75
+ ContextR.with_layers :wrap do
76
+ assert_equal 0b10101, @foo.bar( 0 )
77
+
78
+ ContextR.without_layers :wrap do
79
+ assert_equal 0b00100, @foo.bar( 0 )
80
+ end
81
+
82
+ assert_equal 0b10101, @foo.bar( 0 )
83
+ end
84
+
85
+ assert_equal 0b00100, @foo.bar( 0 )
86
+ end
87
+
88
+ def test_02_cascading_layers
89
+ assert_equal 0b00100, @foo.bar( 0 )
90
+
91
+ ContextR.with_layers :pre do
92
+ assert_equal 0b00110, @foo.bar( 0 )
93
+
94
+ ContextR.with_layers :post do
95
+ assert_equal 0b01110, @foo.bar( 0 )
96
+
97
+ ContextR.with_layers :wrap do
98
+ assert_equal 0b11111, @foo.bar( 0 )
99
+ end
100
+
101
+ assert_equal 0b01110, @foo.bar( 0 )
102
+ end
103
+
104
+ assert_equal 0b00110, @foo.bar( 0 )
105
+ end
106
+
107
+ assert_equal 0b00100, @foo.bar( 0 )
108
+ end
109
+
110
+ def test_03_breaking_behaviour
111
+ ContextR.with_layers :pre, :post, :stop_wrap do
112
+ assert_equal 0b00010, @foo.bar( 0 )
113
+ end
114
+ end
115
+
116
+ def test_04_ordering_by_selectors
117
+ # pre before post
118
+ ContextR.with_layers :order_pre, :order_post do
119
+ assert_equal :pre, @foo.bar( 0 )
120
+ end
121
+ # pre before wrap
122
+ ContextR.with_layers :order_wrap, :order_pre do
123
+ assert_equal :pre, @foo.bar( 0 )
124
+ end
125
+ # wrap before body
126
+ ContextR.with_layers :order_wrap do
127
+ assert_equal :wrap, @foo.bar( 0 )
128
+ end
129
+ # wrap before post
130
+ ContextR.with_layers :order_wrap, :order_post do
131
+ assert_equal :wrap, @foo.bar( 0 )
132
+ end
133
+ # To be completed...
134
+ end
135
+
136
+ def test_05_ordering_by_layers
137
+ ContextR.with_layers :wrap, :stop_wrap do
138
+ assert_equal 0b00000, @foo.bar( 0 )
139
+ end
140
+ ContextR.with_layers :stop_wrap, :wrap do
141
+ assert_equal 0b00001, @foo.bar( 0 )
142
+ end
143
+ ContextR.with_layers :pre, :stop_pre do
144
+ assert_equal 0b00000, @foo.bar( 0 )
145
+ end
146
+ ContextR.with_layers :stop_pre, :pre do
147
+ assert_equal 0b00010, @foo.bar( 0 )
148
+ end
149
+ ContextR.with_layers :post, :stop_post do
150
+ assert_equal 0b01100, @foo.bar( 0 )
151
+ end
152
+ ContextR.with_layers :stop_post, :post do
153
+ assert_equal 0b00100, @foo.bar( 0 )
154
+ end
155
+ end
156
+
157
+ def test_06_ordering_within_groups
158
+ ContextR.with_layers :group_pre do
159
+ assert_equal nil, @foo.bar( 0 )
160
+ end
161
+ ContextR.with_layers :group_post do
162
+ assert_equal :post, @foo.bar( 0 )
163
+ end
164
+ end
165
+ end