climate_control 1.0.0 → 1.1.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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +1 -1
- data/CHANGELOG.md +45 -0
- data/CODEOWNERS +1 -0
- data/README.md +51 -1
- data/climate_control.gemspec +8 -6
- data/lib/climate_control/version.rb +1 -1
- data/lib/climate_control.rb +39 -7
- data/spec/acceptance/climate_control_spec.rb +49 -1
- metadata +27 -26
- data/NEWS +0 -19
- data/lib/climate_control/environment.rb +0 -33
- data/lib/climate_control/modifier.rb +0 -92
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1052215413e209a2ce0531a9b293d56f51df36db70688af69ae15e70571a043d
|
4
|
+
data.tar.gz: ed855bfdddc57fc46532edc296d9a8de6a2a3653f5b148ab10849433aeb61026
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e292d7055db48aaa3cf664f447c6826d3ccf59cc1142dc71a89e8b8e97dbac26d553ebd2912a1f8b2a15b3f75b71de5f3345244cc0cb2f4dd8970f47b73b12c1
|
7
|
+
data.tar.gz: 96f9e0f2e8193c29d708f94c1cdced3d7a1b305ae0cb781729895b838be70233a0082f767f840a5d943e5b206cc55539606de156e4b301bab787e29ab45507b4
|
data/.github/workflows/ci.yml
CHANGED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
|
+
|
8
|
+
## Unreleased
|
9
|
+
|
10
|
+
## 1.1.0 / 2022-05-26
|
11
|
+
|
12
|
+
- Refactor to use `Monitor` instead of `Mutex`
|
13
|
+
- Add documentation about thread-safety
|
14
|
+
- Allow ClimateControl.modify to be called without environment variables
|
15
|
+
- Add test for concurrent access needed to be inside block
|
16
|
+
- Relax development dependencies
|
17
|
+
|
18
|
+
## 1.0.1 / 2021-05-26
|
19
|
+
|
20
|
+
- Require minimum Ruby version of 2.5.0
|
21
|
+
|
22
|
+
# 1.0.0 / 2021-03-06
|
23
|
+
|
24
|
+
- Commit to supporting latest patch versions of Ruby 2.5+
|
25
|
+
- Improve documentation
|
26
|
+
- Format code with StandardRB
|
27
|
+
- Bump gem dependencies
|
28
|
+
|
29
|
+
# 0.2.0 / 2017-05-12
|
30
|
+
|
31
|
+
- Allow nested environment changes in the same thread
|
32
|
+
|
33
|
+
# 0.1.0 / 2017-01-07
|
34
|
+
|
35
|
+
- Remove ActiveSupport dependency
|
36
|
+
|
37
|
+
# 0.0.4 / 2017-01-06
|
38
|
+
|
39
|
+
- Improved thread safety
|
40
|
+
- Handle TypeErrors during assignment
|
41
|
+
- Improve documentation
|
42
|
+
|
43
|
+
# 0.0.1 / 2012-11-28
|
44
|
+
|
45
|
+
- Initial release
|
data/CODEOWNERS
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
* @dorianmariefr
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Climate Control
|
2
2
|
|
3
|
+

|
4
|
+
|
3
5
|
Easily manage your environment.
|
4
6
|
|
5
7
|
## Installation
|
@@ -48,7 +50,7 @@ end
|
|
48
50
|
To use with RSpec, you could define this in your spec:
|
49
51
|
|
50
52
|
```ruby
|
51
|
-
def with_modified_env(options, &block)
|
53
|
+
def with_modified_env(options = {}, &block)
|
52
54
|
ClimateControl.modify(options, &block)
|
53
55
|
end
|
54
56
|
```
|
@@ -105,6 +107,39 @@ manner becomes more difficult:
|
|
105
107
|
Climate Control modifies environment variables only within the context of the
|
106
108
|
block, ensuring values are managed properly and consistently.
|
107
109
|
|
110
|
+
## Thread-safety
|
111
|
+
|
112
|
+
When using threads, for instance when running tests concurrently in the same
|
113
|
+
process, you may need to wrap your code inside `ClimateControl.modify` blocks,
|
114
|
+
e.g.:
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
first_thread = Thread.new do
|
118
|
+
ClimateControl.modify(SECRET: "1") do
|
119
|
+
p ENV["SECRET"] # => "1"
|
120
|
+
sleep 2
|
121
|
+
p ENV["SECRET"] # => "1"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
second_thread = Thread.new do
|
126
|
+
ClimateControl.modify({}) do
|
127
|
+
sleep 1
|
128
|
+
p ENV["SECRET"] # => nil
|
129
|
+
sleep 1
|
130
|
+
p ENV["SECRET"] # => nil
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
first_thread.join
|
135
|
+
second_thread.join
|
136
|
+
```
|
137
|
+
|
138
|
+
> The modification wraps ENV in a mutex. If there's contention (the env being used - including potentially mutating values), it blocks until the value is freed (we shift out of the Ruby block).
|
139
|
+
>
|
140
|
+
> <cite><a href="https://github.com/thoughtbot/climate_control/issues/32#issuecomment-800713686">Josh Clayton</a></cite>
|
141
|
+
|
142
|
+
|
108
143
|
## Contributing
|
109
144
|
|
110
145
|
1. Fork it
|
@@ -118,3 +153,18 @@ This project uses [StandardRB](https://github.com/testdouble/standard) to ensure
|
|
118
153
|
## License
|
119
154
|
|
120
155
|
climate_control is copyright 2012-2021 Joshua Clayton and thoughtbot, inc. It is free software and may be redistributed under the terms specified in the [LICENSE](https://github.com/thoughtbot/climate_control/blob/main/LICENSE) file.
|
156
|
+
|
157
|
+
About thoughtbot
|
158
|
+
----------------
|
159
|
+
|
160
|
+

|
161
|
+
|
162
|
+
climate_control is maintained and funded by thoughtbot, inc.
|
163
|
+
The names and logos for thoughtbot are trademarks of thoughtbot, inc.
|
164
|
+
|
165
|
+
We love open source software!
|
166
|
+
See [our other projects][community] or
|
167
|
+
[hire us][hire] to design, develop, and grow your product.
|
168
|
+
|
169
|
+
[community]: https://thoughtbot.com/community?utm_source=github
|
170
|
+
[hire]: https://thoughtbot.com/hire-us?utm_source=github
|
data/climate_control.gemspec
CHANGED
@@ -5,8 +5,8 @@ require "climate_control/version"
|
|
5
5
|
Gem::Specification.new do |gem|
|
6
6
|
gem.name = "climate_control"
|
7
7
|
gem.version = ClimateControl::VERSION
|
8
|
-
gem.authors = ["Joshua Clayton"]
|
9
|
-
gem.email = ["joshua.clayton@gmail.com"]
|
8
|
+
gem.authors = ["Joshua Clayton", "Dorian Marié"]
|
9
|
+
gem.email = ["joshua.clayton@gmail.com", "dorian@dorianmarie.fr"]
|
10
10
|
gem.description = "Modify your ENV"
|
11
11
|
gem.summary = "Modify your ENV easily with ClimateControl"
|
12
12
|
gem.homepage = "https://github.com/thoughtbot/climate_control"
|
@@ -16,8 +16,10 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
17
17
|
gem.require_paths = ["lib"]
|
18
18
|
|
19
|
-
gem.
|
20
|
-
|
21
|
-
gem.add_development_dependency "
|
22
|
-
gem.add_development_dependency "
|
19
|
+
gem.required_ruby_version = ">= 2.5.0"
|
20
|
+
|
21
|
+
gem.add_development_dependency "rspec"
|
22
|
+
gem.add_development_dependency "rake"
|
23
|
+
gem.add_development_dependency "simplecov"
|
24
|
+
gem.add_development_dependency "standard"
|
23
25
|
end
|
data/lib/climate_control.rb
CHANGED
@@ -1,16 +1,48 @@
|
|
1
|
-
require "climate_control/environment"
|
2
1
|
require "climate_control/errors"
|
3
|
-
require "climate_control/modifier"
|
4
2
|
require "climate_control/version"
|
3
|
+
require "monitor"
|
5
4
|
|
6
5
|
module ClimateControl
|
7
|
-
|
6
|
+
extend self
|
8
7
|
|
9
|
-
|
10
|
-
|
8
|
+
SEMAPHORE = Monitor.new
|
9
|
+
private_constant :SEMAPHORE
|
10
|
+
|
11
|
+
def modify(environment_overrides = {}, &block)
|
12
|
+
environment_overrides = environment_overrides.transform_keys(&:to_s)
|
13
|
+
|
14
|
+
SEMAPHORE.synchronize do
|
15
|
+
previous = ENV.to_hash
|
16
|
+
|
17
|
+
begin
|
18
|
+
copy environment_overrides
|
19
|
+
ensure
|
20
|
+
middle = ENV.to_hash
|
21
|
+
end
|
22
|
+
|
23
|
+
block.call
|
24
|
+
ensure
|
25
|
+
after = ENV
|
26
|
+
(previous.keys | middle.keys | after.keys).each do |key|
|
27
|
+
if previous[key] != after[key] && middle[key] == after[key]
|
28
|
+
ENV[key] = previous[key]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
11
32
|
end
|
12
33
|
|
13
|
-
def
|
14
|
-
|
34
|
+
def env
|
35
|
+
ENV
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def copy(overrides)
|
41
|
+
overrides.each do |key, value|
|
42
|
+
ENV[key] = value
|
43
|
+
rescue TypeError => e
|
44
|
+
raise UnassignableValueError,
|
45
|
+
"attempted to assign #{value} to #{key} but failed (#{e.message})"
|
46
|
+
end
|
15
47
|
end
|
16
48
|
end
|
@@ -113,6 +113,39 @@ describe "Climate control" do
|
|
113
113
|
expect(ENV["BAZ"]).to be_nil
|
114
114
|
end
|
115
115
|
|
116
|
+
it "handles threads accessing the same key wrapped in a block" do
|
117
|
+
first_thread = Thread.new {
|
118
|
+
with_modified_env do
|
119
|
+
with_modified_env CONFLICTING_KEY: "1" do
|
120
|
+
sleep 0.5
|
121
|
+
expect(ENV["CONFLICTING_KEY"]).to eq("1")
|
122
|
+
end
|
123
|
+
|
124
|
+
expect(ENV["CONFLICTING_KEY"]).to be_nil
|
125
|
+
end
|
126
|
+
}
|
127
|
+
|
128
|
+
second_thread = Thread.new {
|
129
|
+
with_modified_env do
|
130
|
+
sleep 0.25
|
131
|
+
expect(ENV["CONFLICTING_KEY"]).to be_nil
|
132
|
+
|
133
|
+
with_modified_env CONFLICTING_KEY: "2" do
|
134
|
+
expect(ENV["CONFLICTING_KEY"]).to eq("2")
|
135
|
+
sleep 0.5
|
136
|
+
expect(ENV["CONFLICTING_KEY"]).to eq("2")
|
137
|
+
end
|
138
|
+
|
139
|
+
expect(ENV["CONFLICTING_KEY"]).to be_nil
|
140
|
+
end
|
141
|
+
}
|
142
|
+
|
143
|
+
first_thread.join
|
144
|
+
second_thread.join
|
145
|
+
|
146
|
+
expect(ENV["CONFLICTING_KEY"]).to be_nil
|
147
|
+
end
|
148
|
+
|
116
149
|
it "is re-entrant" do
|
117
150
|
ret = with_modified_env(FOO: "foo") {
|
118
151
|
with_modified_env(BAR: "bar") do
|
@@ -134,7 +167,22 @@ describe "Climate control" do
|
|
134
167
|
}.to raise_error ClimateControl::UnassignableValueError, /attempted to assign .*Thing.* to FOO but failed \(#{message}\)$/
|
135
168
|
end
|
136
169
|
|
137
|
-
|
170
|
+
it "restores the ENV even when an error was raised when assigning values" do
|
171
|
+
ENV["KEY_TO_OVERRIDE"] = "initial_value_1"
|
172
|
+
ENV["KEY_THAT_WILL_ERROR_OUT"] = "initial_value_2"
|
173
|
+
|
174
|
+
expect {
|
175
|
+
with_modified_env(
|
176
|
+
KEY_TO_OVERRIDE: "overwriten_value_1",
|
177
|
+
KEY_THAT_WILL_ERROR_OUT: :value_that_will_error_out
|
178
|
+
) {}
|
179
|
+
}.to raise_error ClimateControl::UnassignableValueError
|
180
|
+
|
181
|
+
expect(ENV["KEY_TO_OVERRIDE"]).to eq("initial_value_1")
|
182
|
+
expect(ENV["KEY_THAT_WILL_ERROR_OUT"]).to eq("initial_value_2")
|
183
|
+
end
|
184
|
+
|
185
|
+
def with_modified_env(options = {}, &block)
|
138
186
|
ClimateControl.modify(options, &block)
|
139
187
|
end
|
140
188
|
|
metadata
CHANGED
@@ -1,91 +1,92 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: climate_control
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joshua Clayton
|
8
|
-
|
8
|
+
- Dorian Marié
|
9
|
+
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date:
|
12
|
+
date: 2022-05-28 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: rspec
|
15
16
|
requirement: !ruby/object:Gem::Requirement
|
16
17
|
requirements:
|
17
|
-
- - "
|
18
|
+
- - ">="
|
18
19
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
20
|
+
version: '0'
|
20
21
|
type: :development
|
21
22
|
prerelease: false
|
22
23
|
version_requirements: !ruby/object:Gem::Requirement
|
23
24
|
requirements:
|
24
|
-
- - "
|
25
|
+
- - ">="
|
25
26
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
27
|
+
version: '0'
|
27
28
|
- !ruby/object:Gem::Dependency
|
28
29
|
name: rake
|
29
30
|
requirement: !ruby/object:Gem::Requirement
|
30
31
|
requirements:
|
31
|
-
- - "
|
32
|
+
- - ">="
|
32
33
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
34
|
+
version: '0'
|
34
35
|
type: :development
|
35
36
|
prerelease: false
|
36
37
|
version_requirements: !ruby/object:Gem::Requirement
|
37
38
|
requirements:
|
38
|
-
- - "
|
39
|
+
- - ">="
|
39
40
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
41
|
+
version: '0'
|
41
42
|
- !ruby/object:Gem::Dependency
|
42
43
|
name: simplecov
|
43
44
|
requirement: !ruby/object:Gem::Requirement
|
44
45
|
requirements:
|
45
|
-
- - "
|
46
|
+
- - ">="
|
46
47
|
- !ruby/object:Gem::Version
|
47
|
-
version: 0
|
48
|
+
version: '0'
|
48
49
|
type: :development
|
49
50
|
prerelease: false
|
50
51
|
version_requirements: !ruby/object:Gem::Requirement
|
51
52
|
requirements:
|
52
|
-
- - "
|
53
|
+
- - ">="
|
53
54
|
- !ruby/object:Gem::Version
|
54
|
-
version: 0
|
55
|
+
version: '0'
|
55
56
|
- !ruby/object:Gem::Dependency
|
56
57
|
name: standard
|
57
58
|
requirement: !ruby/object:Gem::Requirement
|
58
59
|
requirements:
|
59
|
-
- - "
|
60
|
+
- - ">="
|
60
61
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
62
|
+
version: '0'
|
62
63
|
type: :development
|
63
64
|
prerelease: false
|
64
65
|
version_requirements: !ruby/object:Gem::Requirement
|
65
66
|
requirements:
|
66
|
-
- - "
|
67
|
+
- - ">="
|
67
68
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
69
|
+
version: '0'
|
69
70
|
description: Modify your ENV
|
70
71
|
email:
|
71
72
|
- joshua.clayton@gmail.com
|
73
|
+
- dorian@dorianmarie.fr
|
72
74
|
executables: []
|
73
75
|
extensions: []
|
74
76
|
extra_rdoc_files: []
|
75
77
|
files:
|
76
78
|
- ".github/workflows/ci.yml"
|
77
79
|
- ".gitignore"
|
80
|
+
- CHANGELOG.md
|
81
|
+
- CODEOWNERS
|
78
82
|
- CODE_OF_CONDUCT.md
|
79
83
|
- Gemfile
|
80
84
|
- LICENSE
|
81
|
-
- NEWS
|
82
85
|
- README.md
|
83
86
|
- Rakefile
|
84
87
|
- climate_control.gemspec
|
85
88
|
- lib/climate_control.rb
|
86
|
-
- lib/climate_control/environment.rb
|
87
89
|
- lib/climate_control/errors.rb
|
88
|
-
- lib/climate_control/modifier.rb
|
89
90
|
- lib/climate_control/version.rb
|
90
91
|
- spec/acceptance/climate_control_spec.rb
|
91
92
|
- spec/spec_helper.rb
|
@@ -93,7 +94,7 @@ homepage: https://github.com/thoughtbot/climate_control
|
|
93
94
|
licenses:
|
94
95
|
- MIT
|
95
96
|
metadata: {}
|
96
|
-
post_install_message:
|
97
|
+
post_install_message:
|
97
98
|
rdoc_options: []
|
98
99
|
require_paths:
|
99
100
|
- lib
|
@@ -101,15 +102,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
101
102
|
requirements:
|
102
103
|
- - ">="
|
103
104
|
- !ruby/object:Gem::Version
|
104
|
-
version:
|
105
|
+
version: 2.5.0
|
105
106
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
107
|
requirements:
|
107
108
|
- - ">="
|
108
109
|
- !ruby/object:Gem::Version
|
109
110
|
version: '0'
|
110
111
|
requirements: []
|
111
|
-
rubygems_version: 3.
|
112
|
-
signing_key:
|
112
|
+
rubygems_version: 3.3.13
|
113
|
+
signing_key:
|
113
114
|
specification_version: 4
|
114
115
|
summary: Modify your ENV easily with ClimateControl
|
115
116
|
test_files:
|
data/NEWS
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
1.0.0 (March 6, 2021)
|
2
|
-
Commit to supporting latest patch versions of Ruby 2.5+
|
3
|
-
Improve documentation
|
4
|
-
Format code with StandardRB
|
5
|
-
Bump gem dependencies
|
6
|
-
|
7
|
-
0.2.0 (May 12, 2017)
|
8
|
-
Allow nested environment changes in the same thread
|
9
|
-
|
10
|
-
0.1.0 (January 7, 2017)
|
11
|
-
Remove ActiveSupport dependency
|
12
|
-
|
13
|
-
0.0.4 (January 6, 2017)
|
14
|
-
Improved thread safety
|
15
|
-
Handle TypeErrors during assignment
|
16
|
-
Improve documentation
|
17
|
-
|
18
|
-
0.0.1 (November 28, 2012)
|
19
|
-
Initial release
|
@@ -1,33 +0,0 @@
|
|
1
|
-
require "forwardable"
|
2
|
-
|
3
|
-
module ClimateControl
|
4
|
-
class Environment
|
5
|
-
extend Forwardable
|
6
|
-
|
7
|
-
def initialize
|
8
|
-
@semaphore = Mutex.new
|
9
|
-
@owner = nil
|
10
|
-
end
|
11
|
-
|
12
|
-
def_delegators :env, :[]=, :to_hash, :[], :delete
|
13
|
-
|
14
|
-
def synchronize
|
15
|
-
if @owner == Thread.current
|
16
|
-
return yield if block_given?
|
17
|
-
end
|
18
|
-
|
19
|
-
@semaphore.synchronize do
|
20
|
-
@owner = Thread.current
|
21
|
-
yield if block_given?
|
22
|
-
ensure
|
23
|
-
@owner = nil
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def env
|
30
|
-
ENV
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
@@ -1,92 +0,0 @@
|
|
1
|
-
module ClimateControl
|
2
|
-
class Modifier
|
3
|
-
def initialize(env, environment_overrides = {}, &block)
|
4
|
-
@environment_overrides = stringify_keys(environment_overrides)
|
5
|
-
@block = block
|
6
|
-
@env = env
|
7
|
-
end
|
8
|
-
|
9
|
-
def process
|
10
|
-
@env.synchronize do
|
11
|
-
prepare_environment_for_block
|
12
|
-
run_block
|
13
|
-
ensure
|
14
|
-
cache_environment_after_block
|
15
|
-
delete_keys_that_do_not_belong
|
16
|
-
revert_changed_keys
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def prepare_environment_for_block
|
23
|
-
@original_env = clone_environment
|
24
|
-
copy_overrides_to_environment
|
25
|
-
@env_with_overrides_before_block = clone_environment
|
26
|
-
end
|
27
|
-
|
28
|
-
def run_block
|
29
|
-
@block.call
|
30
|
-
end
|
31
|
-
|
32
|
-
def copy_overrides_to_environment
|
33
|
-
@environment_overrides.each do |key, value|
|
34
|
-
@env[key] = value
|
35
|
-
rescue TypeError => e
|
36
|
-
raise UnassignableValueError,
|
37
|
-
"attempted to assign #{value} to #{key} but failed (#{e.message})"
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def keys_to_remove
|
42
|
-
@environment_overrides.keys
|
43
|
-
end
|
44
|
-
|
45
|
-
def keys_changed_by_block
|
46
|
-
@keys_changed_by_block ||= OverlappingKeysWithChangedValues.new(@env_with_overrides_before_block, @env_after_block).keys
|
47
|
-
end
|
48
|
-
|
49
|
-
def cache_environment_after_block
|
50
|
-
@env_after_block = clone_environment
|
51
|
-
end
|
52
|
-
|
53
|
-
def delete_keys_that_do_not_belong
|
54
|
-
(keys_to_remove - keys_changed_by_block).each { |key| @env.delete(key) }
|
55
|
-
end
|
56
|
-
|
57
|
-
def revert_changed_keys
|
58
|
-
(@original_env.keys - keys_changed_by_block).each do |key|
|
59
|
-
@env[key] = @original_env[key]
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def clone_environment
|
64
|
-
@env.to_hash
|
65
|
-
end
|
66
|
-
|
67
|
-
def stringify_keys(env)
|
68
|
-
env.each_with_object({}) do |(key, value), hash|
|
69
|
-
hash[key.to_s] = value
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
class OverlappingKeysWithChangedValues
|
74
|
-
def initialize(hash_1, hash_2)
|
75
|
-
@hash_1 = hash_1 || {}
|
76
|
-
@hash_2 = hash_2
|
77
|
-
end
|
78
|
-
|
79
|
-
def keys
|
80
|
-
overlapping_keys.select do |overlapping_key|
|
81
|
-
@hash_1[overlapping_key] != @hash_2[overlapping_key]
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
private
|
86
|
-
|
87
|
-
def overlapping_keys
|
88
|
-
@hash_2.keys & @hash_1.keys
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|