Skip to content

Commit becfc06

Browse files
authored
Allow config option to disable ERB in YAML (#303)
* Allow config option to disable ERB in YAML * Set ERB config per YAMLSource with fallback to global config
1 parent 618c839 commit becfc06

6 files changed

Lines changed: 75 additions & 5 deletions

File tree

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,9 @@ You may pass a hash to `prepend_source!` as well.
205205

206206
## Embedded Ruby (ERB)
207207

208-
Embedded Ruby is allowed in the configuration files. Consider the two following config files.
208+
Embedded Ruby is allowed in the YAML configuration files. ERB will be evaluated at load time by default, and when the `evaluate_erb_in_yaml` configuration is set to `true`.
209+
210+
Consider the two following config files.
209211

210212
* ```#{Rails.root}/config/settings.yml```
211213

@@ -266,6 +268,7 @@ After installing `Config` in Rails, you will find automatically generated file t
266268
### General
267269

268270
* `const_name` - name of the object holing you settings. Default: `'Settings'`
271+
* `evaluate_erb_in_yaml` - evaluate ERB in YAML config files. Set to false if the config file contains ERB that should not be evaluated at load time. Default: `true`
269272

270273
### Merge customization
271274

lib/config.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ module Config
2424
merge_nil_values: true,
2525
overwrite_arrays: true,
2626
merge_hash_arrays: false,
27-
validation_contract: nil
27+
validation_contract: nil,
28+
evaluate_erb_in_yaml: true
2829
)
2930

3031
def self.setup

lib/config/sources/yaml_source.rb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,20 @@ module Config
55
module Sources
66
class YAMLSource
77
attr_accessor :path
8+
attr_reader :evaluate_erb
89

9-
def initialize(path)
10+
def initialize(path, evaluate_erb: Config.evaluate_erb_in_yaml)
1011
@path = path.to_s
12+
@evaluate_erb = !!evaluate_erb
1113
end
1214

1315
# returns a config hash from the YML file
1416
def load
15-
result = YAML.load(ERB.new(IO.read(@path)).result) if @path and File.exist?(@path)
17+
if @path and File.exist?(@path)
18+
file_contents = IO.read(@path)
19+
file_contents = ERB.new(file_contents).result if evaluate_erb
20+
result = YAML.load(file_contents)
21+
end
1622

1723
result || {}
1824

lib/generators/config/templates/config.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,7 @@
5252
# required(:email).filled(format?: EMAIL_REGEX)
5353
# end
5454

55+
# Evaluate ERB in YAML config files at load time.
56+
#
57+
# config.evaluate_erb_yaml = true
5558
end
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
malformed_erb: <%= = %>

spec/sources/yaml_source_spec.rb

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ module Config::Sources
2727

2828
context "yml file with erb tags" do
2929
let(:source) do
30-
YAMLSource.new "#{fixture_path}/with_erb.yml"
30+
YAMLSource.new("#{fixture_path}/with_erb.yml")
3131
end
3232

3333
it "should properly evaluate the erb" do
@@ -40,6 +40,62 @@ module Config::Sources
4040
expect(results["section"]["computed1"]).to eq(1)
4141
expect(results["section"]["computed2"]).to eq(2)
4242
end
43+
44+
context "with malformed erb tags" do
45+
let(:source) do
46+
YAMLSource.new("#{fixture_path}/with_malformed_erb.yml")
47+
end
48+
49+
it "should properly evaluate the erb" do
50+
expect {
51+
source.load
52+
}.to raise_error(SyntaxError)
53+
end
54+
end
55+
end
56+
57+
context "yaml file with erb tags but erb disabled" do
58+
let(:source) do
59+
YAMLSource.new("#{fixture_path}/with_erb.yml", evaluate_erb: false)
60+
end
61+
62+
it "should load the file and leave the erb without being evaluated" do
63+
results = source.load
64+
expect(results["computed"]).to eq("<%= 1 + 2 + 3 %>")
65+
expect(results["section"]["computed1"]).to eq("<%= \"1\" %>")
66+
end
67+
68+
context "with global config" do
69+
let(:source) do
70+
YAMLSource.new("#{fixture_path}/with_erb.yml")
71+
end
72+
73+
around do |example|
74+
original_evaluate_erb_in_yaml = Config.evaluate_erb_in_yaml
75+
Config.evaluate_erb_in_yaml = false
76+
example.run
77+
Config.evaluate_erb_in_yaml = original_evaluate_erb_in_yaml
78+
end
79+
80+
it "should load the file and leave the erb without being evaluated" do
81+
results = source.load
82+
expect(results["computed"]).to eq("<%= 1 + 2 + 3 %>")
83+
expect(results["section"]["computed1"]).to eq("<%= \"1\" %>")
84+
end
85+
end
86+
87+
context "with malformed erb tags" do
88+
let(:source) do
89+
YAMLSource.new("#{fixture_path}/with_malformed_erb.yml", evaluate_erb: false)
90+
end
91+
92+
it "should properly evaluate the erb" do
93+
expect {
94+
results = source.load
95+
expect(results["malformed_erb"]).to eq("<%= = %>")
96+
}.to_not raise_error
97+
end
98+
end
4399
end
44100

45101
context "missing yml file" do

0 commit comments

Comments
 (0)