stairs 0.3.0 → 0.4.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.
- checksums.yaml +4 -4
- data/.rspec +2 -0
- data/.rubocop.yml +38 -0
- data/.travis.yml +4 -0
- data/Guardfile +10 -0
- data/README.md +39 -9
- data/Rakefile +5 -0
- data/lib/stairs/configuration.rb +1 -1
- data/lib/stairs/env_adapters/dotenv.rb +2 -2
- data/lib/stairs/env_adapters/rbenv.rb +2 -2
- data/lib/stairs/env_adapters/rvm.rb +2 -2
- data/lib/stairs/env_adapters.rb +2 -2
- data/lib/stairs/interactive_configuration.rb +25 -7
- data/lib/stairs/railtie.rb +7 -0
- data/lib/stairs/script.rb +3 -3
- data/lib/stairs/step.rb +49 -23
- data/lib/stairs/steps/secret_token.rb +1 -1
- data/lib/stairs/steps.rb +1 -1
- data/lib/stairs/tasks.rb +1 -1
- data/lib/stairs/util/cli.rb +50 -0
- data/lib/stairs/util/{file_utils.rb → file_mutation.rb} +10 -5
- data/lib/stairs/util.rb +3 -2
- data/lib/stairs/version.rb +1 -1
- data/lib/stairs.rb +3 -1
- data/spec/lib/configuration_spec.rb +12 -0
- data/spec/lib/stairs/env_adapters/dotenv_spec.rb +38 -0
- data/spec/lib/stairs/env_adapters/rbenv_spec.rb +40 -0
- data/spec/lib/stairs/env_adapters/rvm_spec.rb +40 -0
- data/spec/lib/stairs/env_adapters_spec.rb +28 -0
- data/spec/lib/stairs/interactive_configuration_spec.rb +36 -0
- data/spec/lib/stairs/script_spec.rb +29 -0
- data/spec/lib/stairs/step_spec.rb +293 -0
- data/spec/lib/stairs/steps/secret_token_spec.rb +13 -0
- data/spec/lib/stairs/util/cli_spec.rb +57 -0
- data/spec/lib/stairs/util/file_mutation_spec.rb +98 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/support/mock_stdout.rb +52 -0
- data/stairs.gemspec +8 -1
- metadata +138 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5757c8d2dd7a6f123729557b5ccf99f292f75a9f
|
4
|
+
data.tar.gz: 1a208a280bc33d113efc36aadc00e07213931887
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52a26152b30d4289ac3e73b49dd33ade9ccf9270df0e6b2802f230966a223b3df34902d6cfe07efd9b9962d6b1d33c7aec51fbc13fa89874ea14c204ed5f3ddd
|
7
|
+
data.tar.gz: 0f39e7ab93a8335c98c7a4e1cc186882c6ba49c8c92ad5698c97aac57eeb9bc75e9c622196e97af35cf864a5428eb387873c8392e25f8f313f97c020aca86978
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
StringLiterals:
|
2
|
+
EnforcedStyle: "double_quotes"
|
3
|
+
|
4
|
+
LineLength:
|
5
|
+
Max: 80
|
6
|
+
|
7
|
+
# This offends when not tabbed way out while using case in assignment
|
8
|
+
CaseIndentation:
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
# This was offending when it shouldn't have been, like in util/file_mutation:21
|
12
|
+
UselessAssignment:
|
13
|
+
Enabled: false
|
14
|
+
|
15
|
+
# Seems unnecessary?
|
16
|
+
ReduceArguments:
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
# Not a part of our coding conventions
|
20
|
+
Documentation:
|
21
|
+
Enabled: false
|
22
|
+
|
23
|
+
# Also just not something I've ever done or want to do...
|
24
|
+
SpaceAroundEqualsInParameterDefault:
|
25
|
+
Enabled: false
|
26
|
+
|
27
|
+
# I don't see why... It's shorthand, just know your ruby!
|
28
|
+
SpecialGlobalVars:
|
29
|
+
Enabled: false
|
30
|
+
|
31
|
+
# This was offending for a custom method called `collect` not on an `Enumerable`
|
32
|
+
CollectionMethods:
|
33
|
+
Enabled: false
|
34
|
+
|
35
|
+
# I just don't care so much about clean specs.. Like short methods and short lines
|
36
|
+
AllCops:
|
37
|
+
Excludes:
|
38
|
+
- spec/**
|
data/.travis.yml
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
guard "rspec" do
|
2
|
+
watch(%r{^spec/.+_spec\.rb$})
|
3
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
4
|
+
watch("spec/spec_helper.rb") { "spec" }
|
5
|
+
end
|
6
|
+
|
7
|
+
guard :rubocop do
|
8
|
+
watch(%r{.+\.rb$})
|
9
|
+
watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
|
10
|
+
end
|
data/README.md
CHANGED
@@ -1,20 +1,37 @@
|
|
1
1
|
# Stairs
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
It's a pain to setup new developers. Stairs is a utility and framework from
|
4
|
+
which to write scripts for faster and easier setup of apps in new development
|
5
|
+
environments. Scripts try to automate as much as possible and provide
|
6
|
+
interactive prompts for everything else.
|
7
|
+
|
8
|
+
Stairs currently supports writing environment variables for rbenv-vars, RVM,
|
9
|
+
and dotenv.
|
10
|
+
|
11
|
+
[](https://travis-ci.org/patbenatar/stairs)
|
12
|
+
[](https://codeclimate.com/github/patbenatar/stairs)
|
6
13
|
|
7
14
|
## Setup
|
8
15
|
|
9
|
-
|
16
|
+
### Rails
|
17
|
+
|
18
|
+
Add Stairs to your `Gemfile`:
|
10
19
|
|
11
|
-
1. Require tasks in `Rakefile`
|
12
20
|
```ruby
|
13
|
-
|
21
|
+
gem "stairs"
|
14
22
|
```
|
15
23
|
|
16
|
-
|
17
|
-
|
24
|
+
[Define your script](#defining-scripts) in `setup.rb` at the root of your
|
25
|
+
project.
|
26
|
+
|
27
|
+
### Not Rails
|
28
|
+
|
29
|
+
Same as above, but you'll have to manually add the Stairs Rake tasks to your
|
30
|
+
`Rakefile`.
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
require "stairs/tasks"
|
34
|
+
```
|
18
35
|
|
19
36
|
## Usage
|
20
37
|
|
@@ -172,4 +189,17 @@ extension gems for examples.
|
|
172
189
|
|
173
190
|
[s3]: http://github.com/patbenatar/stairs-steps-s3
|
174
191
|
[balanced]: http://github.com/patbenatar/stairs-steps-balanced
|
175
|
-
[facebook]: http://github.com/patbenatar/stairs-steps-facebook
|
192
|
+
[facebook]: http://github.com/patbenatar/stairs-steps-facebook
|
193
|
+
|
194
|
+
## Credits
|
195
|
+
|
196
|
+
### Contributors
|
197
|
+
|
198
|
+
* [Nick Giancola](https://github.com/patbenatar)
|
199
|
+
* [Brendan Loudermilk](https://github.com/bloudermilk)
|
200
|
+
|
201
|
+
### Sponsor
|
202
|
+
|
203
|
+
[](http://gophilosophie.com)
|
204
|
+
|
205
|
+
This gem is maintained partially during my open source time at [philosophie](http://gophilosophie.com).
|
data/Rakefile
CHANGED
data/lib/stairs/configuration.rb
CHANGED
@@ -6,7 +6,7 @@ module Stairs
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def set(name, value)
|
9
|
-
Util::
|
9
|
+
Util::FileMutation.replace_or_append(
|
10
10
|
Regexp.new("^#{name}=(.*)$"),
|
11
11
|
"#{name}=#{value}",
|
12
12
|
".env",
|
@@ -14,4 +14,4 @@ module Stairs
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
17
|
-
end
|
17
|
+
end
|
@@ -7,7 +7,7 @@ module Stairs
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def set(name, value)
|
10
|
-
Util::
|
10
|
+
Util::FileMutation.replace_or_append(
|
11
11
|
Regexp.new("^#{name}=(.*)$"),
|
12
12
|
"#{name}=#{value}",
|
13
13
|
".rbenv-vars",
|
@@ -15,4 +15,4 @@ module Stairs
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
18
|
-
end
|
18
|
+
end
|
@@ -7,7 +7,7 @@ module Stairs
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def set(name, value)
|
10
|
-
Util::
|
10
|
+
Util::FileMutation.replace_or_append(
|
11
11
|
Regexp.new("^export #{name}=(.*)$"),
|
12
12
|
"export #{name}=#{value}",
|
13
13
|
".rvmrc",
|
@@ -15,4 +15,4 @@ module Stairs
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
18
|
-
end
|
18
|
+
end
|
data/lib/stairs/env_adapters.rb
CHANGED
@@ -4,19 +4,37 @@ module Stairs
|
|
4
4
|
description "Interactive prompt for configuring Stairs"
|
5
5
|
|
6
6
|
def run!
|
7
|
-
|
8
|
-
adapter_name = Stairs::EnvAdapters.name_for_adapter_class(adapter_class)
|
9
|
-
|
10
|
-
choice "Looks like you're using #{adapter_name} to manage environment variables. Is this correct?" do |yes|
|
7
|
+
choice prompt do |yes|
|
11
8
|
if yes
|
12
|
-
Stairs.configuration.env_adapter =
|
9
|
+
Stairs.configuration.env_adapter = recommended_adapter.new
|
13
10
|
else
|
14
|
-
choice "Which would you prefer?",
|
11
|
+
choice "Which would you prefer?", adapter_names do |name|
|
15
12
|
adapter_class = Stairs::EnvAdapters::ADAPTERS[name.to_sym]
|
16
13
|
Stairs.configuration.env_adapter = adapter_class.new
|
17
14
|
end
|
18
15
|
end
|
19
16
|
end
|
20
17
|
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def recommended_adapter
|
22
|
+
@recommended_adapter ||= Stairs::EnvAdapters.recommended_adapter
|
23
|
+
end
|
24
|
+
|
25
|
+
def recommended_adapter_name
|
26
|
+
Stairs::EnvAdapters.name_for_adapter_class(recommended_adapter)
|
27
|
+
end
|
28
|
+
|
29
|
+
def prompt
|
30
|
+
"".tap do |message|
|
31
|
+
message << "Looks like you're using #{recommended_adapter_name} to "
|
32
|
+
message << "manage environment variables. Is this correct?"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def adapter_names
|
37
|
+
Stairs::EnvAdapters::ADAPTERS.map { |n, _a| n.to_s }
|
38
|
+
end
|
21
39
|
end
|
22
|
-
end
|
40
|
+
end
|
data/lib/stairs/script.rb
CHANGED
data/lib/stairs/step.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require "highline/import"
|
2
|
-
|
3
1
|
module Stairs
|
4
2
|
class Step
|
5
3
|
def run!
|
@@ -10,8 +8,6 @@ module Stairs
|
|
10
8
|
|
11
9
|
attr_writer :step_title, :step_description
|
12
10
|
|
13
|
-
private
|
14
|
-
|
15
11
|
class_attribute :step_title, :step_description
|
16
12
|
|
17
13
|
def self.title(title)
|
@@ -38,25 +34,13 @@ module Stairs
|
|
38
34
|
prompt << " (leave blank for #{options[:default]})" if options[:default]
|
39
35
|
prompt << ": "
|
40
36
|
|
41
|
-
|
42
|
-
|
37
|
+
Stairs::Util::CLI.collect(prompt.blue, required: required) ||
|
38
|
+
options[:default]
|
43
39
|
end
|
44
40
|
|
45
41
|
# Prompt user to make a choice
|
46
|
-
|
47
|
-
|
48
|
-
prompt = "#{question} (#{choices.join("/")}): "
|
49
|
-
response = ask(prompt.blue) { |q| q.in = choices }
|
50
|
-
|
51
|
-
case response
|
52
|
-
when "Y"
|
53
|
-
response = true
|
54
|
-
when "N"
|
55
|
-
response = false
|
56
|
-
end
|
57
|
-
|
58
|
-
yield response if block_given?
|
59
|
-
response
|
42
|
+
def choice(*args, &block)
|
43
|
+
Choice.new(*args, &block).run
|
60
44
|
end
|
61
45
|
|
62
46
|
def bundle
|
@@ -73,17 +57,18 @@ module Stairs
|
|
73
57
|
|
74
58
|
# Set or update env var
|
75
59
|
def env(name, value)
|
60
|
+
ENV[name] = value
|
76
61
|
Stairs.configuration.env_adapter.set name, value
|
77
62
|
end
|
78
63
|
|
79
64
|
# Replace contents of file
|
80
65
|
def write(string, filename)
|
81
|
-
Util::
|
66
|
+
Util::FileMutation.write(string, filename)
|
82
67
|
end
|
83
68
|
|
84
69
|
# Append line to file
|
85
70
|
def write_line(string, filename)
|
86
|
-
Util::
|
71
|
+
Util::FileMutation.write_line(string, filename)
|
87
72
|
end
|
88
73
|
|
89
74
|
# Embed a step where step_name is a symbol that can be resolved to a class
|
@@ -109,5 +94,46 @@ module Stairs
|
|
109
94
|
def stairs_info(message)
|
110
95
|
puts message.light_black
|
111
96
|
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
class Choice
|
101
|
+
# TODO: shouldn't care about case?
|
102
|
+
def initialize(question, choices=%w[Y N], &block)
|
103
|
+
@question = question
|
104
|
+
@choices = choices
|
105
|
+
@block = block
|
106
|
+
end
|
107
|
+
|
108
|
+
def run
|
109
|
+
block.call processed_response if block
|
110
|
+
processed_response
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
attr_reader :question, :choices, :block
|
116
|
+
|
117
|
+
def prompt
|
118
|
+
"#{question} (#{choices.join("/")}): "
|
119
|
+
end
|
120
|
+
|
121
|
+
def processed_response
|
122
|
+
@processed_response ||= case response
|
123
|
+
when "Y"
|
124
|
+
true
|
125
|
+
when "N"
|
126
|
+
false
|
127
|
+
else
|
128
|
+
response
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def response
|
133
|
+
@reponse ||= Stairs::Util::CLI.collect prompt.blue do |value, i|
|
134
|
+
choices.include? value
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
112
138
|
end
|
113
|
-
end
|
139
|
+
end
|
data/lib/stairs/steps.rb
CHANGED
data/lib/stairs/tasks.rb
CHANGED
@@ -0,0 +1,50 @@
|
|
1
|
+
module Stairs
|
2
|
+
module Util
|
3
|
+
module CLI
|
4
|
+
class << self
|
5
|
+
def get(prompt)
|
6
|
+
print prompt
|
7
|
+
response = $stdin.gets.strip
|
8
|
+
response.present? ? response : nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def collect(*args, &block)
|
12
|
+
Collector.new(*args, &block).run
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
class Collector
|
19
|
+
def initialize(prompt, options={}, &block)
|
20
|
+
@prompt = prompt
|
21
|
+
@options = options.reverse_merge required: true
|
22
|
+
@validator = block
|
23
|
+
end
|
24
|
+
|
25
|
+
def run
|
26
|
+
times, value = 0, nil
|
27
|
+
|
28
|
+
until valid?(value, times)
|
29
|
+
value = CLI.get(prompt.blue)
|
30
|
+
times += 1
|
31
|
+
end
|
32
|
+
|
33
|
+
value
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def valid?(value, times)
|
39
|
+
if validator
|
40
|
+
validator.call(value, times)
|
41
|
+
else
|
42
|
+
!!value || (!options[:required] && times > 0)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
attr_reader :prompt, :options, :validator
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Stairs
|
2
2
|
module Util
|
3
|
-
module
|
3
|
+
module FileMutation
|
4
4
|
class << self
|
5
5
|
def replace_or_append(pattern, string, filename)
|
6
6
|
if File.exists? filename
|
@@ -16,16 +16,21 @@ module Stairs
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def write_line(string, filename)
|
19
|
-
File.open filename, "a" do |file|
|
19
|
+
File.open filename, "a+" do |file|
|
20
|
+
# ensure file ends with newline before appending
|
21
|
+
last_line = file.each_line.reduce("") { |m, l| m = l }
|
22
|
+
file.puts "" unless last_line.index /(.*)\n/
|
23
|
+
|
20
24
|
file.puts string
|
21
25
|
end
|
22
26
|
end
|
23
27
|
|
24
28
|
def write(string, filename)
|
25
|
-
File.
|
26
|
-
|
29
|
+
File.open filename, "w+" do |file|
|
30
|
+
file.puts string
|
31
|
+
end
|
27
32
|
end
|
28
33
|
end
|
29
34
|
end
|
30
35
|
end
|
31
|
-
end
|
36
|
+
end
|
data/lib/stairs/util.rb
CHANGED
data/lib/stairs/version.rb
CHANGED
data/lib/stairs.rb
CHANGED
@@ -0,0 +1,12 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Stairs::Configuration do
|
4
|
+
subject { described_class.new }
|
5
|
+
|
6
|
+
describe "attributes" do
|
7
|
+
it "allows for configuration of env_adapter" do
|
8
|
+
subject.env_adapter = "test"
|
9
|
+
expect(subject.env_adapter).to eq "test"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Stairs::EnvAdapters::Dotenv do
|
4
|
+
subject { described_class.new }
|
5
|
+
|
6
|
+
describe ".present?" do
|
7
|
+
context "when rvm is installed" do
|
8
|
+
before { stub_const "Dotenv", double("dotenv") }
|
9
|
+
|
10
|
+
it "returns true" do
|
11
|
+
expect(described_class.present?).to be_true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context "when rvm is not installed" do
|
16
|
+
before { Object.send(:remove_const, :Dotenv) if defined? ::Dotenv }
|
17
|
+
|
18
|
+
it "returns true" do
|
19
|
+
expect(described_class.present?).to be_false
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#set" do
|
25
|
+
it "delegates to the well tested FileMutation util" do
|
26
|
+
name = "VAR_NAME"
|
27
|
+
value = "the_value"
|
28
|
+
|
29
|
+
Stairs::Util::FileMutation.should_receive(:replace_or_append).with(
|
30
|
+
Regexp.new("^#{name}=(.*)$"),
|
31
|
+
"#{name}=#{value}",
|
32
|
+
".env",
|
33
|
+
)
|
34
|
+
|
35
|
+
subject.set(name, value)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Stairs::EnvAdapters::Rbenv do
|
4
|
+
subject { described_class.new }
|
5
|
+
|
6
|
+
describe ".present?" do
|
7
|
+
before { described_class.should_receive(:`).with("which rbenv-vars") }
|
8
|
+
|
9
|
+
context "when rbenv-vars is installed" do
|
10
|
+
before { $?.stub success?: true }
|
11
|
+
|
12
|
+
it "returns true" do
|
13
|
+
expect(described_class.present?).to be_true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when rbenv-vars is not installed" do
|
18
|
+
before { $?.stub success?: false }
|
19
|
+
|
20
|
+
it "returns true" do
|
21
|
+
expect(described_class.present?).to be_false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#set" do
|
27
|
+
it "delegates to the well tested FileMutation util" do
|
28
|
+
name = "VAR_NAME"
|
29
|
+
value = "the_value"
|
30
|
+
|
31
|
+
Stairs::Util::FileMutation.should_receive(:replace_or_append).with(
|
32
|
+
Regexp.new("^#{name}=(.*)$"),
|
33
|
+
"#{name}=#{value}",
|
34
|
+
".rbenv-vars",
|
35
|
+
)
|
36
|
+
|
37
|
+
subject.set(name, value)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Stairs::EnvAdapters::RVM do
|
4
|
+
subject { described_class.new }
|
5
|
+
|
6
|
+
describe ".present?" do
|
7
|
+
before { described_class.should_receive(:`).with("which rvm") }
|
8
|
+
|
9
|
+
context "when rvm is installed" do
|
10
|
+
before { $?.stub success?: true }
|
11
|
+
|
12
|
+
it "returns true" do
|
13
|
+
expect(described_class.present?).to be_true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when rvm is not installed" do
|
18
|
+
before { $?.stub success?: false }
|
19
|
+
|
20
|
+
it "returns true" do
|
21
|
+
expect(described_class.present?).to be_false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#set" do
|
27
|
+
it "delegates to the well tested FileMutation util" do
|
28
|
+
name = "VAR_NAME"
|
29
|
+
value = "the_value"
|
30
|
+
|
31
|
+
Stairs::Util::FileMutation.should_receive(:replace_or_append).with(
|
32
|
+
Regexp.new("^export #{name}=(.*)$"),
|
33
|
+
"export #{name}=#{value}",
|
34
|
+
".rvmrc",
|
35
|
+
)
|
36
|
+
|
37
|
+
subject.set(name, value)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|