figjam 1.2.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ef230ae6ec36d15a5f04e18d1161544166313f02919d5174ef4a73fc6fae38e2
4
+ data.tar.gz: b75eef364afba9fe6d50f8ccc1bb4e3cc1c10e13a8dd7a351dc14cddbaa16e46
5
+ SHA512:
6
+ metadata.gz: a865580ea79bef3ff770573f20d7b6d3a66f97eb9eb8e526201342973c80e9fa8307640298e2dd29825656b6e77c65f9ed0998f64bf976f926d30c4558ad17f8
7
+ data.tar.gz: 3b6b0196e4fe1a80e18e9232764133c29ff4a323fd2bd864a94cf1390c796b87ad049dce634b7494d264523fadba4ec38a1eabae279c1cd235859b0fde90e7e2
data/README.md ADDED
@@ -0,0 +1,184 @@
1
+ figjam
2
+ ================
3
+
4
+ Figjam makes it easy to configure ruby and Rails apps `ENV` values by just using a single YAML file.
5
+
6
+ PRs to applications often need to come with default configuration values, but hardcoding these into
7
+ software makes them impossible to change at runtime. However supplying them separately to an
8
+ orchestration framework introduces deploy coordination that can be tricky to get right.
9
+
10
+ Figjam encourages you to commit default ENV values to a yaml file in your PRs. These are then
11
+ loaded at runtime, but, crucially, can be overridden at any time by supplying a real ENV. This
12
+ brings the ease of PR creation with the flexibility of runtime ENV changes.
13
+
14
+
15
+ ### Usage
16
+
17
+ Add Figjam to your Gemfile and `bundle install`:
18
+
19
+ ```ruby
20
+ gem "figjam"
21
+ ```
22
+
23
+ Then:
24
+
25
+ ```bash
26
+ $ bundle exec figjam install
27
+ ```
28
+
29
+ This creates a commented `config/application.yml` file which you can add default ENV to.
30
+ Add your own configuration to this file for all environments, and any specific environment
31
+ overrides.
32
+
33
+ ### Example
34
+
35
+ Given the following configuration file, the default value at the top will be used unless
36
+ RAILS_ENV matches any of the subsequent keys (like `test`, `prelive`, `produciton`).
37
+
38
+ ```yaml
39
+ # config/application.yml
40
+
41
+ GOOGLE_TAG_MANAGER_ID: GTM-12345
42
+
43
+ test:
44
+ # Use ~ for "nil"
45
+ GOOGLE_TAG_MANAGER_ID: ~
46
+
47
+ prelive:
48
+ GOOGLE_TAG_MANAGER_ID: GTM-45678
49
+
50
+ production:
51
+ GOOGLE_TAG_MANAGER_ID: GTM-98765
52
+ ```
53
+
54
+ You can then use those values in your app in an initializer, or in any other ruby code.
55
+
56
+ eg:
57
+ ```
58
+ # app/views/layouts/application.html.erb
59
+
60
+ <script>
61
+ var gtm_id = <%= ENV.fetch("GOOGLE_TAG_MANAGER_ID") %>
62
+ </script>
63
+ ```
64
+
65
+ Note, secrets are not to be provided by figjam, so do not add them to your `application.yml`.
66
+
67
+ **Please note:** `ENV` is a simple key/value store. All values will be converted
68
+ to strings. Deeply nested configuration structures are not possible.
69
+
70
+ ### Using `Figjam.env`
71
+
72
+ `Figjam.env` is a convenience that acts as a proxy to `ENV`.
73
+
74
+ In testing, it is sometimes more convenient to stub and unstub `Figjam.env` than
75
+ to set and reset `ENV`. Whether your application uses `ENV` or `Figjam.env` is
76
+ entirely a matter of personal preference.
77
+
78
+ ```yaml
79
+ # config/application.yml
80
+
81
+ GOOGLE_TAG_MANAGER_ID: "GTM-456789"
82
+ ```
83
+
84
+ ```ruby
85
+ ENV["GOOGLE_TAG_MANAGER_ID"] # => "GTM-456789"
86
+ ENV.key?("GOOGLE_TAG_MANAGER_ID") # => true
87
+ ENV["SOMETHING_ELSE"] # => nil
88
+ ENV.key?("SOMETHING_ELSE") # => false
89
+
90
+ Figjam.env.google_tag_manager_id # => "GTM-456789"
91
+ Figjam.env.google_tag_manager_id? # => true
92
+ Figjam.env.something_else # => nil
93
+ Figjam.env.something_else? # => false
94
+ ```
95
+
96
+ ### Required Keys
97
+
98
+ If a particular configuration value is required but not set, it's appropriate to
99
+ raise an error. With Figjam, you can either raise these errors proactively or
100
+ lazily.
101
+
102
+ To proactively require configuration keys:
103
+
104
+ ```ruby
105
+ # config/initializers/figjam.rb
106
+
107
+ Figjam.require_keys("GOOGLE_TAG_MANAGER_ID")
108
+ ```
109
+
110
+ If any of the configuration keys above are not set, your application will raise
111
+ an error during initialization. This method is preferred because it prevents
112
+ runtime errors in a production application due to improper configuration.
113
+
114
+ To require configuration keys lazily, reference the variables via "bang" methods
115
+ on `Figjam.env`:
116
+
117
+ ```ruby
118
+ gtm_id = Figjam.env.google_tag_manager_id!
119
+ ```
120
+
121
+ ## Is Figjam like [dotenv](https://github.com/bkeepers/dotenv)?
122
+
123
+ Figjam and dotenv are similar:
124
+
125
+ ### Similarities
126
+
127
+ * Both libraries are useful for Ruby application configuration.
128
+ * Both are inspired by Twelve-Factor App's concept of proper [configuration](http://12factor.net/config).
129
+ * Both store configuration values in `ENV`.
130
+ * Both can be used in and out of Rails.
131
+
132
+ ### Differences
133
+
134
+ * Configuration File
135
+ * Figjam expects a single file.
136
+ * Dotenv supports separate files for each environment.
137
+ * Configuration File Format
138
+ * Figjam expects YAML containing key/value pairs.
139
+ * Dotenv convention is a collection of `KEY=VALUE` pairs.
140
+
141
+ If you prefer your default configuration in one place, where you can scan one file to see
142
+ differences between environments, then you may prefer `figjam` over `dotenv`.
143
+
144
+ ## Is application.yml like [secrets.yml](https://github.com/rails/rails/blob/v4.1.0/railties/lib/rails/generators/rails/app/templates/config/secrets.yml)?
145
+
146
+ No. Do not put secrets in `figjam` `application.yml` files! That file supposed to be committed
147
+ to source control, and should never contain secrets.
148
+
149
+ ### Spring Configuration
150
+
151
+ If you're using Spring add `config/application.yml` to the watch list:
152
+
153
+ ```rb
154
+ # config/spring.rb
155
+
156
+ %w(
157
+ ...
158
+ config/application.yml
159
+ ).each { |path| Spring.watch(path) }
160
+ ```
161
+
162
+ ## Figjam origins
163
+
164
+ Figjam started as a direct fork of the [figaro](https://github.com/laserlemon/figaro) rubygem.
165
+
166
+ There are some key differences in philosophy:
167
+
168
+ 1. Figjam chooses not to go down the more "use ruby for configuration" 2.x path that gem was taking,
169
+ preferring to keep using hierarchical yaml files.
170
+ 2. Figjam prefers that you *do* commit your application.yml to your repository, as long as you don't
171
+ put any credentials or other secrets in it. It encourages an ENV-with-code-change PR flow
172
+ that simplifies providing default ENV values for an application, as well as codified
173
+ overrides per environment. These all, of course, can be overridden by a real ENV.
174
+
175
+ Given (2), it doesn't make sense to push ENV to Heroku from the application.yml file, so Heroku
176
+ support has been removed.
177
+
178
+ With those caveats, it can be used as a drop-in replacement for the `figaro` gem.
179
+ It even aliases the `Figaro` to `Figjam` module namespace for drop-in compatibility.
180
+
181
+ ## How can I help?
182
+
183
+ Figjam is open source and contributions from the community are encouraged! No
184
+ contribution is too small.
data/bin/figaro ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "figjam"
data/bin/figjam ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "figjam/cli"
4
+
5
+ Figjam::CLI.start
@@ -0,0 +1 @@
1
+ require "figjam/application"
@@ -0,0 +1 @@
1
+ require "figjam/rails"
data/lib/figaro.rb ADDED
@@ -0,0 +1 @@
1
+ require "figjam"
@@ -0,0 +1,91 @@
1
+ require "erb"
2
+ require "yaml"
3
+
4
+ module Figjam
5
+ class Application
6
+ FIGARO_ENV_PREFIX = "_FIGARO_"
7
+
8
+ include Enumerable
9
+
10
+ def initialize(options = {})
11
+ @options = options.inject({}) { |m, (k, v)| m[k.to_sym] = v; m }
12
+ end
13
+
14
+ def path
15
+ @options.fetch(:path) { default_path }.to_s
16
+ end
17
+
18
+ def path=(path)
19
+ @options[:path] = path
20
+ end
21
+
22
+ def environment
23
+ environment = @options.fetch(:environment) { default_environment }
24
+ environment.nil? ? nil : environment.to_s
25
+ end
26
+
27
+ def environment=(environment)
28
+ @options[:environment] = environment
29
+ end
30
+
31
+ def configuration
32
+ global_configuration.merge(environment_configuration)
33
+ end
34
+
35
+ def load
36
+ each do |key, value|
37
+ skip?(key) ? key_skipped!(key) : set(key, value)
38
+ end
39
+ end
40
+
41
+ def each(&block)
42
+ configuration.each(&block)
43
+ end
44
+
45
+ private
46
+
47
+ def default_path
48
+ raise NotImplementedError
49
+ end
50
+
51
+ def default_environment
52
+ nil
53
+ end
54
+
55
+ def raw_configuration
56
+ (@parsed ||= Hash.new { |hash, path| hash[path] = parse(path) })[path]
57
+ end
58
+
59
+ def parse(path)
60
+ File.exist?(path) && YAML.load(ERB.new(File.read(path)).result) || {}
61
+ end
62
+
63
+ def global_configuration
64
+ raw_configuration.reject { |_, value| value.is_a?(Hash) }
65
+ end
66
+
67
+ def environment_configuration
68
+ raw_configuration[environment] || {}
69
+ end
70
+
71
+ def set(key, value)
72
+ non_string_configuration!(key) unless key.is_a?(String)
73
+ non_string_configuration!(value) unless value.is_a?(String) || value.nil?
74
+
75
+ ::ENV[key.to_s] = value.nil? ? nil : value.to_s
76
+ ::ENV[FIGARO_ENV_PREFIX + key.to_s] = value.nil? ? nil: value.to_s
77
+ end
78
+
79
+ def skip?(key)
80
+ ::ENV.key?(key.to_s) && !::ENV.key?(FIGARO_ENV_PREFIX + key.to_s)
81
+ end
82
+
83
+ def non_string_configuration!(value)
84
+ warn "WARNING: Use strings for Figjam configuration. #{value.inspect} was converted to #{value.to_s.inspect}."
85
+ end
86
+
87
+ def key_skipped!(key)
88
+ warn "WARNING: Skipping key #{key.inspect}. Already set in ENV."
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,13 @@
1
+ # Add configuration values here, as shown below.
2
+ #
3
+ # GOOGLE_TAG_MANAGER_ID: GTM-12345
4
+ #
5
+ # test:
6
+ # # Use ~ for "nil"
7
+ # GOOGLE_TAG_MANAGER_ID: ~
8
+ #
9
+ # prelive:
10
+ # GOOGLE_TAG_MANAGER_ID: GTM-45678
11
+ #
12
+ # production:
13
+ # GOOGLE_TAG_MANAGER_ID: GTM-98765
@@ -0,0 +1,22 @@
1
+ require "thor/group"
2
+
3
+ module Figjam
4
+ class CLI < Thor
5
+ class Install < Thor::Group
6
+ include Thor::Actions
7
+
8
+ class_option "path",
9
+ aliases: ["-p"],
10
+ default: "config/application.yml",
11
+ desc: "Specify a configuration file path"
12
+
13
+ def self.source_root
14
+ File.expand_path("../install", __FILE__)
15
+ end
16
+
17
+ def create_configuration
18
+ copy_file("application.yml", options[:path])
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,37 @@
1
+ require "figjam/application"
2
+
3
+ module Figjam
4
+ class CLI < Thor
5
+ class Task
6
+ attr_reader :options
7
+
8
+ def self.run(options = {})
9
+ new(options).run
10
+ end
11
+
12
+ def initialize(options = {})
13
+ @options = options
14
+ end
15
+
16
+ private
17
+
18
+ def env
19
+ ENV.to_hash.update(configuration)
20
+ end
21
+
22
+ def configuration
23
+ application.configuration
24
+ end
25
+
26
+ def application
27
+ @application ||= Figjam::Application.new(options)
28
+ end
29
+
30
+ if defined? Bundler
31
+ def system(*)
32
+ Bundler.with_clean_env { super }
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
data/lib/figjam/cli.rb ADDED
@@ -0,0 +1,19 @@
1
+ require "thor"
2
+
3
+ module Figjam
4
+ class CLI < Thor
5
+ # figjam install
6
+
7
+ desc "install", "Install Figjam"
8
+
9
+ method_option "path",
10
+ aliases: ["-p"],
11
+ default: "config/application.yml",
12
+ desc: "Specify a configuration file path"
13
+
14
+ def install
15
+ require "figjam/cli/install"
16
+ Install.start
17
+ end
18
+ end
19
+ end
data/lib/figjam/env.rb ADDED
@@ -0,0 +1,45 @@
1
+ module Figjam
2
+ module ENV
3
+ extend self
4
+
5
+ def respond_to?(method, *)
6
+ key, punctuation = extract_key_from_method(method)
7
+
8
+ case punctuation
9
+ when "!" then has_key?(key) || super
10
+ when "?", nil then true
11
+ else super
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def method_missing(method, *)
18
+ key, punctuation = extract_key_from_method(method)
19
+
20
+ case punctuation
21
+ when "!" then send(key) || missing_key!(key)
22
+ when "?" then !!send(key)
23
+ when nil then get_value(key)
24
+ else super
25
+ end
26
+ end
27
+
28
+ def extract_key_from_method(method)
29
+ method.to_s.downcase.match(/^(.+?)([!?=])?$/).captures
30
+ end
31
+
32
+ def has_key?(key)
33
+ ::ENV.any? { |k, _| k.downcase == key }
34
+ end
35
+
36
+ def missing_key!(key)
37
+ raise MissingKey.new(key)
38
+ end
39
+
40
+ def get_value(key)
41
+ _, value = ::ENV.detect { |k, _| k.downcase == key }
42
+ value
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,17 @@
1
+ module Figjam
2
+ class Error < StandardError; end
3
+
4
+ class RailsNotInitialized < Error; end
5
+
6
+ class MissingKey < Error
7
+ def initialize(key)
8
+ super("Missing required configuration key: #{key.inspect}")
9
+ end
10
+ end
11
+
12
+ class MissingKeys < Error
13
+ def initialize(keys)
14
+ super("Missing required configuration keys: #{keys.inspect}")
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ module Figjam
2
+ module Rails
3
+ class Application < Figjam::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,9 @@
1
+ module Figjam
2
+ module Rails
3
+ class Railtie < ::Rails::Railtie
4
+ config.before_configuration do
5
+ Figjam.load
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ begin
2
+ require "rails"
3
+ rescue LoadError
4
+ else
5
+ require "figjam/rails/application"
6
+ require "figjam/rails/railtie"
7
+
8
+ Figjam.adapter = Figjam::Rails::Application
9
+ end
10
+
@@ -0,0 +1,6 @@
1
+ module Figjam
2
+ VERSION = "1.2.0"
3
+ end
4
+
5
+ # Alias for drop-in replacement support
6
+ Figaro = Figjam
data/lib/figjam.rb ADDED
@@ -0,0 +1,36 @@
1
+ if Gem.loaded_specs.key?("figaro")
2
+ raise "The gem figjam is a replacement for figaro. Remove figaro from your Gemfile."
3
+ end
4
+
5
+ require "figjam/error"
6
+ require "figjam/env"
7
+ require "figjam/application"
8
+
9
+ module Figjam
10
+ extend self
11
+
12
+ attr_writer :adapter, :application
13
+
14
+ def env
15
+ Figjam::ENV
16
+ end
17
+
18
+ def adapter
19
+ @adapter ||= Figjam::Application
20
+ end
21
+
22
+ def application
23
+ @application ||= adapter.new
24
+ end
25
+
26
+ def load
27
+ application.load
28
+ end
29
+
30
+ def require_keys(*keys)
31
+ missing_keys = keys.flatten - ::ENV.keys
32
+ raise MissingKeys.new(missing_keys) if missing_keys.any?
33
+ end
34
+ end
35
+
36
+ require "figjam/rails"
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: figjam
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Harry Lascelles
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-11-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.14.0
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '2'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 0.14.0
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '2'
33
+ - !ruby/object:Gem::Dependency
34
+ name: bundler
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 1.7.0
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '3'
43
+ type: :development
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 1.7.0
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '3'
53
+ - !ruby/object:Gem::Dependency
54
+ name: rake
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: 10.4.0
60
+ - - "<"
61
+ - !ruby/object:Gem::Version
62
+ version: '14'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: 10.4.0
70
+ - - "<"
71
+ - !ruby/object:Gem::Version
72
+ version: '14'
73
+ description: ENV configuration for ruby using hierarchical environment yaml files
74
+ email:
75
+ - harry@harrylascelles.com
76
+ executables:
77
+ - figjam
78
+ extensions: []
79
+ extra_rdoc_files: []
80
+ files:
81
+ - README.md
82
+ - bin/figaro
83
+ - bin/figjam
84
+ - lib/figaro.rb
85
+ - lib/figaro/application.rb
86
+ - lib/figaro/rails.rb
87
+ - lib/figjam.rb
88
+ - lib/figjam/application.rb
89
+ - lib/figjam/cli.rb
90
+ - lib/figjam/cli/install.rb
91
+ - lib/figjam/cli/install/application.yml
92
+ - lib/figjam/cli/task.rb
93
+ - lib/figjam/env.rb
94
+ - lib/figjam/error.rb
95
+ - lib/figjam/rails.rb
96
+ - lib/figjam/rails/application.rb
97
+ - lib/figjam/rails/railtie.rb
98
+ - lib/figjam/version.rb
99
+ homepage: https://github.com/hlascelles/figjam
100
+ licenses:
101
+ - MIT
102
+ metadata:
103
+ homepage_uri: https://github.com/hlascelles/figjam
104
+ documentation_uri: https://github.com/hlascelles/figjam
105
+ changelog_uri: https://github.com/hlascelles/figjam/blob/master/CHANGELOG.md
106
+ source_code_uri: https://github.com/hlascelles/figjam/
107
+ bug_tracker_uri: https://github.com/hlascelles/figjam/issues
108
+ rubygems_mfa_required: 'true'
109
+ post_install_message:
110
+ rdoc_options: []
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ requirements: []
124
+ rubygems_version: 3.1.6
125
+ signing_key:
126
+ specification_version: 4
127
+ summary: ENV configuration for ruby using yaml files
128
+ test_files: []