temporaries 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,3 @@
1
+ == 0.0.1 2011-03-29
2
+
3
+ * Hi.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License
2
+
3
+ Copyright (c) George Ogata
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,102 @@
1
+ # Temporaries
2
+
3
+ Set things temporarily and declaratively. Best way to test.
4
+
5
+ * Set values of constants.
6
+ * Set values of attributes.
7
+ * Set values of hash keys.
8
+ * Set values of instance variables.
9
+ * Set values of class variables.
10
+ * Set values of globals.
11
+ * Set a temporary directory.
12
+
13
+ Do it for the length of a test, or within a specific block in your
14
+ code. Nest them arbitrarily; the innermost one applies.
15
+
16
+ ## How
17
+
18
+ ### In RSpec
19
+
20
+ describe MyClass do
21
+ # Mylib.foo will be 5 within these examples.
22
+ use_temporary_attribute_value MyLib, :foo, 5
23
+
24
+ describe MyClass do
25
+ # In this nested example group, it will be 7.
26
+ use_temporary_attribute_value MyLib, :foo, 7
27
+ end
28
+ end
29
+
30
+ Here's the full list of methods you can use:
31
+
32
+ use_temporary_hash_value(hash, key, value)
33
+ use_temporary_constant_value(module, :constant, value)
34
+ use_temporary_attribute_value(object, :attribute, value)
35
+ use_temporary_instance_variable_value(object, :name, value)
36
+ use_temporary_class_variable_value(object, :name, value)
37
+ use_temporary_global_value(:name, value)
38
+
39
+ Sigils in the `name` are unnecessary in the last 3 (unlike
40
+ `instance_variable_get`, for instance).
41
+
42
+ ### In Test::Unit
43
+
44
+ class MyTest < Test::Unit::TestCase
45
+ use_temporary_attribute_value MyLib, :foo, 5
46
+ end
47
+
48
+ ## Digging Deeper
49
+
50
+ You may also set the temporary for the duration of a particular block:
51
+
52
+ with_hash_value hash, key, value do
53
+ ...
54
+ end
55
+
56
+ with_constant_value module, :constant, value do
57
+ ...
58
+ end
59
+
60
+ with_attribute_value object, :attribute, value do
61
+ ...
62
+ end
63
+
64
+ with_instance_variable_value object, :name, value do
65
+ ...
66
+ end
67
+
68
+ with_class_variable_value object, :name, value do
69
+ ...
70
+ end
71
+
72
+ with_global_value :name, value do
73
+ ...
74
+ end
75
+
76
+ with_temporary_directory path do
77
+ # `tmp' refers to the directory.
78
+ end
79
+
80
+ Or push and pop temporary values onto the stack yourself:
81
+
82
+ push_hash_value hash, key, value
83
+ pop_hash_value hash, key
84
+
85
+ push_constant_value module, :constant, value
86
+ pop_constant_value module, :constant
87
+
88
+ # etc.
89
+
90
+ Keep 'em balanced, maestro.
91
+
92
+ ## Contributing
93
+
94
+ * [Source](https://github.com/oggy/temporaries)
95
+ * [Bug reports](https://github.com/oggy/temporaries/issues)
96
+ * Patches: Fork on Github, send pull request.
97
+ * Include tests where practical.
98
+ * Leave the version alone, or bump it in a separate commit.
99
+
100
+ ## Copyright
101
+
102
+ Copyright (c) George Ogata. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'ritual'
@@ -0,0 +1,25 @@
1
+ Feature: Rspec Integration
2
+
3
+ As a developer using RSpec
4
+ I want to define temporary values
5
+ So I can run my tests in isolation
6
+
7
+ Scenario: Using temporary values with RSpec
8
+ Given I have a file "rspec.rb" containing:
9
+ """
10
+ require 'temporaries'
11
+
12
+ module Mod
13
+ X = 2
14
+ end
15
+
16
+ describe Mod do
17
+ use_constant_value Mod, :X, 5
18
+
19
+ it "should have X = 5 inside each example" do
20
+ Mod::X.should == 5
21
+ end
22
+ end
23
+ """
24
+ When I run "rspec rspec.rb"
25
+ Then I should see "1 example, 0 failures"
@@ -0,0 +1,14 @@
1
+ Given /^I have a file "(.*?)" containing:$/ do |path, content|
2
+ open(path, 'w') do |file|
3
+ file.puts "$:.unshift '#{LIB}'"
4
+ file.print content
5
+ end
6
+ end
7
+
8
+ When /^I run "(.*?)"$/ do |command|
9
+ @output = `bundle exec #{command} 2>&1`
10
+ end
11
+
12
+ Then /^I should see "(.*?)"$/ do |expected|
13
+ @output.should include(expected)
14
+ end
@@ -0,0 +1,24 @@
1
+ ROOT = File.expand_path('../..', File.dirname(__FILE__))
2
+ $:.unshift File.expand_path('../../lib', File.dirname(__FILE__))
3
+ ENV['BUNDLE_GEMFILE'] = "#{ROOT}/Gemfile"
4
+
5
+ $TEMPORARIES_TEST = true
6
+ require 'temporaries'
7
+ require 'fileutils'
8
+ require 'rspec/expectations'
9
+
10
+ TMP = File.expand_path(File.dirname(__FILE__) + '/../tmp')
11
+ LIB = File.expand_path(File.dirname(__FILE__) + '/../../lib')
12
+
13
+ original_pwd = nil
14
+
15
+ Before do
16
+ FileUtils.mkdir_p TMP
17
+ original_pwd = Dir.pwd
18
+ Dir.chdir TMP
19
+ end
20
+
21
+ After do
22
+ Dir.chdir original_pwd
23
+ FileUtils.rm_rf TMP
24
+ end
@@ -0,0 +1,26 @@
1
+ Feature: Test::Unit Integration
2
+
3
+ As a developer using Test::Unit
4
+ I want to define temporary values
5
+ So I can run my tests in isolation
6
+
7
+ Scenario: Using temporary values with Test::Unit
8
+ Given I have a file "test_unit.rb" containing:
9
+ """
10
+ require 'test/unit'
11
+ require 'temporaries'
12
+
13
+ module Mod
14
+ X = 2
15
+ end
16
+
17
+ class MyTest < Test::Unit::TestCase
18
+ use_constant_value Mod, :X, 5
19
+
20
+ def test_should_have_x_set_to_5_in_each_test
21
+ assert_equal 5, Mod::X
22
+ end
23
+ end
24
+ """
25
+ When I run "ruby test_unit.rb"
26
+ Then I should see "1 tests, 1 assertions, 0 failures, 0 errors"
@@ -0,0 +1,19 @@
1
+ module Temporaries
2
+ module Adapters
3
+ class Base
4
+ def initialize(context)
5
+ @context = context
6
+ end
7
+
8
+ attr_reader :context
9
+
10
+ def before
11
+ raise NotImplementedError, 'abstract'
12
+ end
13
+
14
+ def after
15
+ raise NotImplementedError, 'abstract'
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,27 @@
1
+ module Temporaries
2
+ module Adapters
3
+ class RSpec < Base
4
+ def self.install
5
+ ::RSpec.configure do |config|
6
+ config.extend Extension
7
+ config.include Values
8
+ config.include Directory
9
+ end
10
+ end
11
+
12
+ def before(&block)
13
+ context.before(&block)
14
+ end
15
+
16
+ def after(&block)
17
+ context.after(&block)
18
+ end
19
+
20
+ module Extension
21
+ def temporaries_adapter
22
+ RSpec.new(self)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,56 @@
1
+ module Temporaries
2
+ module Adapters
3
+ class TestUnit < Base
4
+ def self.install
5
+ Test::Unit::TestCase.class_eval do
6
+ extend Extension
7
+ include Values
8
+ include Directory
9
+ end
10
+ end
11
+
12
+ def before(&block)
13
+ context.send(:include, self.module)
14
+ context.befores << block
15
+ end
16
+
17
+ def after(&block)
18
+ context.send(:include, self.module)
19
+ context.afters << block
20
+ end
21
+
22
+ def module
23
+ @module ||= Module.new do
24
+ def self.included(base)
25
+ base.extend self::ClassMethods
26
+ end
27
+
28
+ mod = Module.new do
29
+ def befores
30
+ @befores ||= []
31
+ end
32
+
33
+ def afters
34
+ @afters ||= []
35
+ end
36
+ end
37
+ const_set(:ClassMethods, mod)
38
+
39
+ def setup
40
+ self.class.befores.each{|proc| instance_eval(&proc)}
41
+ end
42
+
43
+ def teardown
44
+ self.class.afters.each{|proc| instance_eval(&proc)}
45
+ end
46
+ end
47
+ end
48
+
49
+ module Extension
50
+ def temporaries_adapter
51
+ TestUnit.new(self)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,7 @@
1
+ module Temporaries
2
+ module Adapters
3
+ autoload :Base, 'temporaries/adapters/base'
4
+ autoload :RSpec, 'temporaries/adapters/rspec'
5
+ autoload :TestUnit, 'temporaries/adapters/test_unit'
6
+ end
7
+ end
@@ -0,0 +1,21 @@
1
+ module Temporaries
2
+ module Core
3
+ protected
4
+
5
+ def push_temporary(key, value)
6
+ temporaries[key].push(value)
7
+ end
8
+
9
+ def pop_temporary(key)
10
+ temporaries[key].pop
11
+ end
12
+
13
+ def top_temporary(key)
14
+ temporaries[key].last
15
+ end
16
+
17
+ def temporaries
18
+ @temporaries ||= Hash.new{|h,k| h[k] = []}
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,48 @@
1
+ require 'fileutils'
2
+
3
+ module Temporaries
4
+ module Directory
5
+ include Core
6
+
7
+ def self.included(base)
8
+ base.extend ClassMethods
9
+ end
10
+
11
+ module ClassMethods
12
+ def use_temporary_directory(directory)
13
+ temporaries_adapter.before do
14
+ push_temporary_directory(directory)
15
+ end
16
+
17
+ temporaries_adapter.after do
18
+ pop_temporary_directory
19
+ end
20
+ end
21
+ end
22
+
23
+ def push_temporary_directory(directory)
24
+ exists = File.exist?(directory)
25
+ push_temporary(:directory, [directory, exists])
26
+ FileUtils.mkdir_p directory unless exists
27
+ end
28
+
29
+ def pop_temporary_directory
30
+ directory, existed = pop_temporary(:directory)
31
+ FileUtils.rm_rf directory unless existed
32
+ end
33
+
34
+ def with_temporary_directory(directory)
35
+ push_temporary_directory(directory)
36
+ begin
37
+ yield
38
+ ensure
39
+ pop_temporary_directory
40
+ end
41
+ end
42
+
43
+ def tmp
44
+ top = top_temporary(:directory) and
45
+ top.first
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,198 @@
1
+ #
2
+ # Set temporary values for the duration of a block. These may be
3
+ # arbitrarily nested; the innermost definition applies.
4
+ #
5
+ # with_hash_value hash, key, value do
6
+ # ...
7
+ # end
8
+ #
9
+ # with_constant_value module, :constant, value do
10
+ # ...
11
+ # end
12
+ #
13
+ # with_attribute_value object, :attribute, value do
14
+ # ...
15
+ # end
16
+ #
17
+ # with_instance_variable_value object, :name, value do
18
+ # ...
19
+ # end
20
+ #
21
+ # with_class_variable_value object, :name, value do
22
+ # ...
23
+ # end
24
+ #
25
+ # with_global_value :name, value do
26
+ # ...
27
+ # end
28
+ #
29
+ # There are also the lower level:
30
+ #
31
+ # push_hash_value hash, key, value
32
+ # pop_hash_value hash, key
33
+ #
34
+ # push_constant_value Module, :Constant, value
35
+ # pop_constant_value Module, :Constant
36
+ #
37
+ # push_attribute_value object, :attribute, value
38
+ # pop_attribute_value object :attribute
39
+ #
40
+ # push_instance_variable_value object, :name, value
41
+ # pop_instance_variable_value object :name
42
+ #
43
+ # push_class_variable_value klass, :name, value
44
+ # pop_class_variable_value klass, :name
45
+ #
46
+ # push_global_variable_value :name, value
47
+ # pop_global_variable_value :name
48
+ #
49
+ module Temporaries
50
+ module Values
51
+ include Core
52
+
53
+ UNDEFINED = RUBY_VERSION < '1.9' ? Object.new : BasicObject.new
54
+ class << UNDEFINED
55
+ def inspect
56
+ '<UNDEFINED>'
57
+ end
58
+ alias to_s inspect
59
+ end
60
+
61
+ class Helpers
62
+ def initialize(name)
63
+ @name = name
64
+ end
65
+ attr_reader :name
66
+
67
+ def signature(signature = nil)
68
+ if signature
69
+ @signature = signature
70
+ else
71
+ @signature
72
+ end
73
+ end
74
+
75
+ [:exists, :get, :set, :remove].each do |name|
76
+ attr_reader name
77
+ class_eval <<-EOS
78
+ def #{name}(source=nil)
79
+ if source
80
+ @#{name} = '(' + source + ')'
81
+ else
82
+ @#{name}
83
+ end
84
+ end
85
+ EOS
86
+ end
87
+
88
+ def stack_key
89
+ sig_ids = signature.split(/\s*,\s*/).map{|s| s + '.__id__'}.join(', ')
90
+ "[:#{name}, #{sig_ids}]"
91
+ end
92
+
93
+ def define(mod)
94
+ if exists
95
+ save = "original_value = #{exists} ? #{get} : Temporaries::Values::UNDEFINED"
96
+ restore = "value == Temporaries::Values::UNDEFINED ? #{remove} : #{set}"
97
+ else
98
+ save = "original_value = #{get}"
99
+ restore = set
100
+ end
101
+
102
+ mod.class_eval <<-EOS, __FILE__, __LINE__ + 1
103
+ def push_#{name}_value(#{signature}, value)
104
+ #{save}
105
+ push_temporary(#{stack_key}, original_value)
106
+ #{set}
107
+ end
108
+
109
+ def pop_#{name}_value(#{signature})
110
+ value = pop_temporary(#{stack_key})
111
+ #{restore}
112
+ end
113
+
114
+ def with_#{name}_value(#{signature}, value)
115
+ push_#{name}_value(#{signature}, value)
116
+ begin
117
+ yield
118
+ ensure
119
+ pop_#{name}_value(#{signature})
120
+ end
121
+ end
122
+ EOS
123
+
124
+ mod::ClassMethods.module_eval <<-EOS, __FILE__, __LINE__ + 1
125
+ def use_#{name}_value(#{signature}, value)
126
+ temporaries_adapter.before do
127
+ push_#{name}_value(#{signature}, value)
128
+ end
129
+
130
+ temporaries_adapter.after do
131
+ pop_#{name}_value(#{signature})
132
+ end
133
+ end
134
+ EOS
135
+ end
136
+ end
137
+
138
+ def self.included(base)
139
+ base.extend ClassMethods
140
+ end
141
+
142
+ module ClassMethods
143
+ end
144
+
145
+ def self.define_helpers_for(name, &block)
146
+ helpers = Helpers.new(name)
147
+ helpers.instance_eval(&block)
148
+ helpers.define(self)
149
+ end
150
+
151
+ define_helpers_for :constant do
152
+ signature 'mod, constant'
153
+ exists 'mod.const_defined?(constant)'
154
+ get 'mod.const_get(constant)'
155
+ set <<-EOS
156
+ mod.instance_eval{remove_const(constant) if const_defined?(constant)
157
+ const_set(constant, value)}
158
+ EOS
159
+ remove 'mod.send :remove_const, constant'
160
+ end
161
+
162
+ define_helpers_for :attribute do
163
+ signature 'object, attribute'
164
+ get 'object.send(attribute)'
165
+ set 'object.send("#{attribute}=", value)'
166
+ end
167
+
168
+ define_helpers_for :hash do
169
+ signature 'hash, key'
170
+ exists 'hash.key?(key)'
171
+ get 'hash[key]'
172
+ set 'hash[key] = value'
173
+ remove 'hash.delete(key)'
174
+ end
175
+
176
+ define_helpers_for :instance_variable do
177
+ signature 'object, name'
178
+ exists 'object.instance_variable_defined?("@#{name}")'
179
+ get 'object.instance_variable_get "@#{name}"'
180
+ set 'object.instance_variable_set "@#{name}", value'
181
+ remove 'object.send :remove_instance_variable, "@#{name}"'
182
+ end
183
+
184
+ define_helpers_for :class_variable do
185
+ signature 'klass, name'
186
+ exists 'klass.class_variable_defined?("@@#{name}")'
187
+ get 'klass.send :class_variable_get, "@@#{name}"'
188
+ set 'klass.send :class_variable_set, "@@#{name}", value'
189
+ remove 'klass.send :remove_class_variable, "@@#{name}"'
190
+ end
191
+
192
+ define_helpers_for :global do
193
+ signature 'name'
194
+ get 'eval("$#{name}")'
195
+ set 'eval("$#{name} = value")'
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,11 @@
1
+ module Temporaries
2
+ VERSION = [0, 0, 1]
3
+
4
+ class << VERSION
5
+ include Comparable
6
+
7
+ def to_s
8
+ join('.')
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ module Temporaries
2
+ autoload :Core, 'temporaries/core'
3
+ autoload :Values, 'temporaries/values'
4
+ autoload :Directory, 'temporaries/directory'
5
+ autoload :Adapters, 'temporaries/adapters'
6
+ end
7
+
8
+ if defined?($TEMPORARIES_TEST)
9
+ # Testing this library. Don't install anything.
10
+ elsif defined?(RSpec)
11
+ Temporaries::Adapters::RSpec.install
12
+ elsif defined?(Test::Unit)
13
+ Temporaries::Adapters::TestUnit.install
14
+ end
@@ -0,0 +1,5 @@
1
+ $TEMPORARIES_TEST = true
2
+ require 'temporaries'
3
+ require 'support/test_context'
4
+
5
+ TMP = File.dirname(__FILE__) + '/tmp'
@@ -0,0 +1,46 @@
1
+ #
2
+ # Represents a group of tests, such as a subclass of Test::Unit or
3
+ # Spec::Example::ExampleGroup.
4
+ #
5
+ class TestContext
6
+ class << self
7
+ def temporaries_adapter
8
+ @temporaries_adapter ||= Adapter.new(self)
9
+ end
10
+
11
+ def before(&block)
12
+ befores << block
13
+ end
14
+
15
+ def after(&block)
16
+ afters << block
17
+ end
18
+
19
+ def befores
20
+ @befores ||= []
21
+ end
22
+
23
+ def afters
24
+ @afters ||= []
25
+ end
26
+ end
27
+
28
+ def run
29
+ self.class.befores.each{|proc| instance_eval(&proc)}
30
+ begin
31
+ yield
32
+ ensure
33
+ self.class.afters.each{|proc| instance_eval(&proc)}
34
+ end
35
+ end
36
+
37
+ class Adapter < Temporaries::Adapters::Base
38
+ def before(&block)
39
+ context.before(&block)
40
+ end
41
+
42
+ def after(&block)
43
+ context.after(&block)
44
+ end
45
+ end
46
+ end