seielit-figaro 1.1.2

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.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +30 -0
  5. data/CHANGELOG.md +122 -0
  6. data/CONTRIBUTING.md +48 -0
  7. data/Gemfile +14 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +350 -0
  10. data/Rakefile +6 -0
  11. data/bin/figaro +5 -0
  12. data/gemfiles/rails41.gemfile +12 -0
  13. data/gemfiles/rails42.gemfile +12 -0
  14. data/gemfiles/rails50.gemfile +13 -0
  15. data/gemfiles/rails51.gemfile +13 -0
  16. data/gemfiles/rails52.gemfile +14 -0
  17. data/gemfiles/rails60.gemfile +14 -0
  18. data/lib/figaro.rb +33 -0
  19. data/lib/figaro/application.rb +91 -0
  20. data/lib/figaro/cli.rb +42 -0
  21. data/lib/figaro/cli/heroku_set.rb +33 -0
  22. data/lib/figaro/cli/install.rb +32 -0
  23. data/lib/figaro/cli/install/application.yml +11 -0
  24. data/lib/figaro/cli/task.rb +33 -0
  25. data/lib/figaro/env.rb +45 -0
  26. data/lib/figaro/error.rb +17 -0
  27. data/lib/figaro/rails.rb +7 -0
  28. data/lib/figaro/rails/application.rb +21 -0
  29. data/lib/figaro/rails/railtie.rb +10 -0
  30. data/lib/figaro/rails/tasks.rake +6 -0
  31. data/lib/figaro/settings.rb +124 -0
  32. data/seielit-figaro.gemspec +23 -0
  33. data/spec/figaro/application_spec.rb +262 -0
  34. data/spec/figaro/cli/heroku_set_spec.rb +67 -0
  35. data/spec/figaro/cli/install_spec.rb +49 -0
  36. data/spec/figaro/env_spec.rb +195 -0
  37. data/spec/figaro/rails/application_spec.rb +47 -0
  38. data/spec/figaro/settings_spec.rb +109 -0
  39. data/spec/figaro_spec.rb +106 -0
  40. data/spec/rails_spec.rb +50 -0
  41. data/spec/spec_helper.rb +13 -0
  42. data/spec/support/aruba.rb +19 -0
  43. data/spec/support/bin/heroku +5 -0
  44. data/spec/support/command_helpers.rb +17 -0
  45. data/spec/support/command_interceptor.rb +33 -0
  46. data/spec/support/reset.rb +13 -0
  47. metadata +145 -0
@@ -0,0 +1,7 @@
1
+ # at require-time, we need Rails to be defined to initialize the railtie
2
+ # and set the default adapter to the Rails::Application adapter
3
+ if defined?(Rails)
4
+ require "figaro/rails/application"
5
+ require "figaro/rails/railtie"
6
+ Figaro.adapter = Figaro::Rails::Application
7
+ end
@@ -0,0 +1,21 @@
1
+ module Figaro
2
+ module Rails
3
+ class Application < Figaro::Application
4
+ private
5
+
6
+ def default_path
7
+ rails_not_initialized! unless ::Rails.root
8
+
9
+ ::Rails.root.join("config", "application.yml")
10
+ end
11
+
12
+ def default_environment
13
+ ::Rails.env
14
+ end
15
+
16
+ def rails_not_initialized!
17
+ raise RailsNotInitialized
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ module Figaro
2
+ module Rails
3
+ class Railtie < ::Rails::Railtie
4
+ config.before_configuration do
5
+ Figaro.load
6
+ end
7
+ config.file_watcher = nil
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,6 @@
1
+ namespace :figaro do
2
+ desc "Configure Heroku according to application.yml"
3
+ task :heroku, [:app] => :environment do |_, args|
4
+ Figaro::Tasks::Heroku.new(args[:app]).invoke
5
+ end
6
+ end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bigdecimal'
4
+
5
+ module Figaro
6
+ #
7
+ # This class should be extended in your own application to provide a higher
8
+ # level API for use in your application.
9
+ #
10
+ # Your app shouldn't use ENV, Figaro.env not Settings#[]. It also shouldn't
11
+ # fiddle with data conversion in settings.
12
+ #
13
+ # class Settings < Figaro::Settings
14
+ # requires :per_page # makes it fail on startup
15
+ # requires :port,
16
+ # :int
17
+ #
18
+ # def per_page
19
+ # self[:per_page].int
20
+ # end
21
+ # end
22
+ #
23
+ class Settings
24
+ attr_reader :namespace
25
+
26
+ NAMESPACE_SEPARATOR = '__'.freeze
27
+
28
+ module ClassMethods
29
+ def [](key)
30
+ new(key)
31
+ end
32
+
33
+ def requires(key, type = nil)
34
+ setting = self[key]
35
+ if type
36
+ setting.as type,
37
+ raises: true
38
+ else
39
+ setting.value || raise(MissingKey, key)
40
+ end
41
+ end
42
+ end
43
+ extend ClassMethods
44
+
45
+ def initialize(namespace)
46
+ @namespace = [namespace]
47
+ end
48
+
49
+ def [](key)
50
+ self.class.new(namespace + [key])
51
+ end
52
+
53
+ def key
54
+ ns = namespace || []
55
+ ns.join NAMESPACE_SEPARATOR
56
+ end
57
+
58
+ def value
59
+ env.send key
60
+ end
61
+
62
+ def to_str
63
+ value
64
+ end
65
+
66
+ def to_s
67
+ value
68
+ end
69
+
70
+ def inspect
71
+ "Setting: #{key} => #{value.inspect}"
72
+ end
73
+
74
+ module DataTypes
75
+ FALSY_VALUES = %w[no off false disabled].freeze
76
+
77
+ NULLABLE_TYPES = {
78
+ int: method(:Integer),
79
+ float: method(:Float),
80
+ decimal: method(:BigDecimal),
81
+ string: ->(itself) { itself || raise(ArgumentError) }
82
+ }.freeze
83
+
84
+ class InvalidKey < Error
85
+ def initialize(setting, type)
86
+ super("Invalid configuration key: can't convert #{setting.inspect} to #{type}")
87
+ end
88
+ end
89
+
90
+ def as(type, raises: false)
91
+ case type
92
+ when :bool
93
+ bool
94
+ else
95
+ conversion = NULLABLE_TYPES[type]
96
+ conversion.call value
97
+ end
98
+ rescue ArgumentError, TypeError
99
+ raise InvalidKey.new(self, type) if raises
100
+ end
101
+
102
+ def bool
103
+ !FALSY_VALUES.include? value&.downcase
104
+ end
105
+
106
+ NULLABLE_TYPES.each do |method, _conversion|
107
+ define_method method do
108
+ as method
109
+ end
110
+
111
+ define_method "#{method}!" do
112
+ as method,
113
+ raises: true
114
+ end
115
+ end
116
+ end
117
+ include DataTypes
118
+
119
+ private
120
+ def env
121
+ Figaro.env
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "seielit-figaro"
5
+ gem.version = "1.1.2"
6
+
7
+ gem.author = "Steve Richert"
8
+ gem.email = "steve.richert@gmail.com"
9
+ gem.summary = "Simple Rails app configuration"
10
+ gem.description = "Simple, Heroku-friendly Rails app configuration using ENV and a single YAML file (fork of https://github.com/laserlemon/figaro)"
11
+ gem.homepage = "https://github.com/seielit/figaro"
12
+ gem.license = "MIT"
13
+
14
+ gem.add_dependency "thor", "~> 0.14"
15
+
16
+ gem.add_development_dependency "bundler"
17
+ gem.add_development_dependency "rake", "~> 10.4"
18
+
19
+ gem.files = `git ls-files`.split($\)
20
+ gem.test_files = gem.files.grep(/^spec/)
21
+
22
+ gem.executables << "figaro"
23
+ end
@@ -0,0 +1,262 @@
1
+ require "tempfile"
2
+
3
+ module Figaro
4
+ describe Application do
5
+ before do
6
+ allow_any_instance_of(Application).to receive(:default_path) { "/path/to/app/config/application.yml" }
7
+ allow_any_instance_of(Application).to receive(:default_environment) { "development" }
8
+ end
9
+
10
+ describe "#path" do
11
+ it "uses the default" do
12
+ application = Application.new
13
+
14
+ expect(application.path).to eq("/path/to/app/config/application.yml")
15
+ end
16
+
17
+ it "is configurable via initialization" do
18
+ application = Application.new(path: "/app/env.yml")
19
+
20
+ expect(application.path).to eq("/app/env.yml")
21
+ end
22
+
23
+ it "is configurable via setter" do
24
+ application = Application.new
25
+ application.path = "/app/env.yml"
26
+
27
+ expect(application.path).to eq("/app/env.yml")
28
+ end
29
+
30
+ it "casts to string" do
31
+ application = Application.new(path: Pathname.new("/app/env.yml"))
32
+
33
+ expect(application.path).to eq("/app/env.yml")
34
+ expect(application.environment).not_to be_a(Pathname)
35
+ end
36
+
37
+ it "follows a changing default" do
38
+ application = Application.new
39
+
40
+ expect {
41
+ allow(application).to receive(:default_path) { "/app/env.yml" }
42
+ }.to change {
43
+ application.path
44
+ }.from("/path/to/app/config/application.yml").to("/app/env.yml")
45
+ end
46
+ end
47
+
48
+ describe "#environment" do
49
+ it "uses the default" do
50
+ application = Application.new
51
+
52
+ expect(application.environment).to eq("development")
53
+ end
54
+
55
+ it "is configurable via initialization" do
56
+ application = Application.new(environment: "test")
57
+
58
+ expect(application.environment).to eq("test")
59
+ end
60
+
61
+ it "is configurable via setter" do
62
+ application = Application.new
63
+ application.environment = "test"
64
+
65
+ expect(application.environment).to eq("test")
66
+ end
67
+
68
+ it "casts to string" do
69
+ application = Application.new(environment: :test)
70
+
71
+ expect(application.environment).to eq("test")
72
+ expect(application.environment).not_to be_a(Symbol)
73
+ end
74
+
75
+ it "respects nil" do
76
+ application = Application.new(environment: nil)
77
+
78
+ expect(application.environment).to eq(nil)
79
+ end
80
+
81
+ it "follows a changing default" do
82
+ application = Application.new
83
+
84
+ expect {
85
+ allow(application).to receive(:default_environment) { "test" }
86
+ }.to change {
87
+ application.environment
88
+ }.from("development").to("test")
89
+ end
90
+ end
91
+
92
+ describe "#configuration" do
93
+ def yaml_to_path(yaml)
94
+ Tempfile.open("figaro") do |file|
95
+ file.write(yaml)
96
+ file.path
97
+ end
98
+ end
99
+
100
+ it "loads values from YAML" do
101
+ application = Application.new(path: yaml_to_path(<<-YAML))
102
+ foo: bar
103
+ YAML
104
+
105
+ expect(application.configuration).to eq("foo" => "bar")
106
+ end
107
+
108
+ it "merges environment-specific values" do
109
+ application = Application.new(path: yaml_to_path(<<-YAML), environment: "test")
110
+ foo: bar
111
+ test:
112
+ foo: baz
113
+ YAML
114
+
115
+ expect(application.configuration).to eq("foo" => "baz")
116
+ end
117
+
118
+ it "drops unused environment-specific values" do
119
+ application = Application.new(path: yaml_to_path(<<-YAML), environment: "test")
120
+ foo: bar
121
+ test:
122
+ foo: baz
123
+ production:
124
+ foo: bad
125
+ YAML
126
+
127
+ expect(application.configuration).to eq("foo" => "baz")
128
+ end
129
+
130
+ it "is empty when no YAML file is present" do
131
+ application = Application.new(path: "/path/to/nowhere")
132
+
133
+ expect(application.configuration).to eq({})
134
+ end
135
+
136
+ it "is empty when the YAML file is blank" do
137
+ application = Application.new(path: yaml_to_path(""))
138
+
139
+ expect(application.configuration).to eq({})
140
+ end
141
+
142
+ it "is empty when the YAML file contains only comments" do
143
+ application = Application.new(path: yaml_to_path(<<-YAML))
144
+ # Comment
145
+ YAML
146
+
147
+ expect(application.configuration).to eq({})
148
+ end
149
+
150
+ it "processes ERB" do
151
+ application = Application.new(path: yaml_to_path(<<-YAML))
152
+ foo: <%= "bar".upcase %>
153
+ YAML
154
+
155
+ expect(application.configuration).to eq("foo" => "BAR")
156
+ end
157
+
158
+ it "handles an empty environment block" do
159
+ application = Application.new(path: yaml_to_path("development:"))
160
+
161
+ expect {
162
+ application.configuration
163
+ }.not_to raise_error
164
+ end
165
+
166
+ it "follows a changing default path" do
167
+ path_1 = yaml_to_path("foo: bar")
168
+ path_2 = yaml_to_path("foo: baz")
169
+
170
+ application = Application.new
171
+ allow(application).to receive(:default_path) { path_1 }
172
+
173
+ expect {
174
+ allow(application).to receive(:default_path) { path_2 }
175
+ }.to change {
176
+ application.configuration
177
+ }.from("foo" => "bar").to("foo" => "baz")
178
+ end
179
+
180
+ it "follows a changing default environment" do
181
+ application = Application.new(path: yaml_to_path(<<-YAML))
182
+ foo: bar
183
+ test:
184
+ foo: baz
185
+ YAML
186
+ allow(application).to receive(:default_environment) { "development" }
187
+
188
+ expect {
189
+ allow(application).to receive(:default_environment) { "test" }
190
+ }.to change {
191
+ application.configuration
192
+ }.from("foo" => "bar").to("foo" => "baz")
193
+ end
194
+ end
195
+
196
+ describe "#load" do
197
+ let!(:application) { Application.new }
198
+
199
+ before do
200
+ allow(application).to receive(:configuration) { { "foo" => "bar" } }
201
+ end
202
+
203
+ it "merges values into ENV" do
204
+ expect {
205
+ application.load
206
+ }.to change {
207
+ ::ENV["foo"]
208
+ }.from(nil).to("bar")
209
+ end
210
+
211
+ it "skips keys (and warns) that have already been set externally" do
212
+ ::ENV["foo"] = "baz"
213
+
214
+ expect(application).to receive(:warn)
215
+
216
+ expect {
217
+ application.load
218
+ }.not_to change {
219
+ ::ENV["foo"]
220
+ }
221
+ end
222
+
223
+ it "sets keys that have already been set internally" do
224
+ application.load
225
+
226
+ allow(application).to receive(:configuration) { { "foo" => "baz" } }
227
+
228
+ expect {
229
+ application.load
230
+ }.to change {
231
+ ::ENV["foo"]
232
+ }.from("bar").to("baz")
233
+ end
234
+
235
+ it "warns when a key isn't a string" do
236
+ allow(application).to receive(:configuration) { { foo: "bar" } }
237
+
238
+ expect(application).to receive(:warn)
239
+
240
+ application.load
241
+ end
242
+
243
+ it "warns when a value isn't a string" do
244
+ allow(application).to receive(:configuration) { { "foo" => ["bar"] } }
245
+
246
+ expect(application).to receive(:warn)
247
+
248
+ application.load
249
+ end
250
+
251
+ it "allows nil values" do
252
+ allow(application).to receive(:configuration) { { "foo" => nil } }
253
+
254
+ expect {
255
+ application.load
256
+ }.not_to change {
257
+ ::ENV["foo"]
258
+ }
259
+ end
260
+ end
261
+ end
262
+ end