variant 0.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5730da4f5a0da8d3054369aeb2ce625008a8b2eb2edce3048b624c4bf2249e62
4
+ data.tar.gz: 0e2090643dff445a506ce733d5dd2bd517bbdf264cd97d43dcb552759efde140
5
+ SHA512:
6
+ metadata.gz: a9b48ab48027324be95a91dbbd878a12e033f2737a179ebf80747b0b524b49cb8edd3760cdfc0f01d624ef7998d8f833ac11bf72c293447992835bb16a5fc3a0
7
+ data.tar.gz: 94bdf23c7aa5a3dd4cd6f0e390486c395fa3b229045700a40ba5c50f6d2383c77300e2173929e4cf285fe835c4eb07dcca2b228ea9f0fe4fe64f2346bfd7285b
@@ -0,0 +1,34 @@
1
+ name: Development
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ test:
7
+ strategy:
8
+ matrix:
9
+ os:
10
+ - ubuntu
11
+ - macos
12
+
13
+ ruby:
14
+ - 2.4
15
+ - 2.5
16
+ - 2.6
17
+ - 2.7
18
+
19
+ include:
20
+ - os: 'ubuntu'
21
+ ruby: '2.6'
22
+ env: COVERAGE=PartialSummary,Coveralls
23
+
24
+ runs-on: ${{matrix.os}}-latest
25
+
26
+ steps:
27
+ - uses: actions/checkout@v1
28
+ - uses: ruby/setup-ruby@v1
29
+ with:
30
+ ruby-version: ${{matrix.ruby}}
31
+ - name: Install dependencies
32
+ run: bundle install
33
+ - name: Run tests
34
+ run: ${{matrix.env}} bundle exec rspec
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
12
+ Gemfile.lock
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in variant.gemspec
4
+ gemspec
@@ -0,0 +1,105 @@
1
+ # Variant
2
+
3
+ Provides a model for application variants, including documenting behaviour like `RACK_ENV` and `APP_ENV`.
4
+
5
+ [![Development](https://github.com/socketry/variant/workflows/Development/badge.svg?branch=master)](https://github.com/socketry/variant/actions?workflow=Development)
6
+
7
+ ## Installation
8
+
9
+ ```
10
+ bundle add variant
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ Variants are used to indicate the default configuration for an application. There are four suggested variants:
16
+
17
+ | Variant | Data | Usage |
18
+ |-------------|-------------------------------------|----------------------------------------|
19
+ | Production | Persistent, real data & interfaces. | Instance/cluster. |
20
+ | Staging | Duplicate/subset of production. | Instance/cluster. |
21
+ | Development | Fixtures, sample data. | Local machine. **Default** variant. |
22
+ | Testing | Fixtures, mocked interfaces. | Local machine, continuous integration. |
23
+
24
+ ### Environment Variables
25
+
26
+ The general mechanism for specifying a variant is on the command line before running the application:
27
+
28
+ ```
29
+ VARIANT=production falcon serve
30
+ ```
31
+
32
+ In your code, you access this like so:
33
+
34
+ ```ruby
35
+ Variant.default # => :production
36
+ Variant.for(:database) # => :production
37
+ ```
38
+
39
+ ### System-specific Variants
40
+
41
+ You can specify system-specific variants. These are useful when you have e.g. 2 different database clusters, or you want to run a development instance connected to a production database.
42
+
43
+ ```
44
+ VARIANT=production DATABASE_VARIANT=production-aws
45
+ ```
46
+
47
+ In your code, you access this like so:
48
+
49
+ ```ruby
50
+ Variant.default # => :production
51
+ Variant.for(:database) # => :'production-aws'
52
+ ```
53
+
54
+ If you don't specify a system-specific variant, it will be the same as the default variant.
55
+
56
+ ### Bake Integration
57
+
58
+ This gem provides [bake](https://github.com/socketry/bake) recipes for setting the variants as outlined above.
59
+
60
+ ```
61
+ bake variant:production ...
62
+ bake variant:staging ...
63
+ bake variant:development ...
64
+ bake variant:testing ...
65
+ ```
66
+
67
+ In addition, the tasks also support specifying overrides:
68
+
69
+ ```
70
+ % bake variant:development database=production variant:show
71
+ 0.01s info: Environment [pid=417910] [2020-02-29 11:43:25 +1300]
72
+ | {"VARIANT"=>"development", "DATABASE_VARIANT"=>"production"}
73
+ ```
74
+
75
+ ## Contributing
76
+
77
+ 1. Fork it
78
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
79
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
80
+ 4. Push to the branch (`git push origin my-new-feature`)
81
+ 5. Create new Pull Request
82
+
83
+ ## License
84
+
85
+ Released under the MIT license.
86
+
87
+ Copyright, 2020, by [Samuel G. D. Williams](https://www.codeotaku.com).
88
+
89
+ Permission is hereby granted, free of charge, to any person obtaining a copy
90
+ of this software and associated documentation files (the "Software"), to deal
91
+ in the Software without restriction, including without limitation the rights
92
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
93
+ copies of the Software, and to permit persons to whom the Software is
94
+ furnished to do so, subject to the following conditions:
95
+
96
+ The above copyright notice and this permission notice shall be included in
97
+ all copies or substantial portions of the Software.
98
+
99
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
100
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
101
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
102
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
103
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
104
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
105
+ THE SOFTWARE.
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,42 @@
1
+
2
+ require_relative '../lib/variant'
3
+
4
+ # Select the production variant.
5
+ # @param overrides [Hash] any specific variant overrides.
6
+ def production(**overrides)
7
+ Variant.force!(:production, **overrides)
8
+ end
9
+
10
+ # Select the staging variant.
11
+ # @param overrides [Hash] any specific variant overrides.
12
+ def staging(**overrides)
13
+ Variant.force!(:staging, **overrides)
14
+ end
15
+
16
+ # Select the development variant.
17
+ # @param overrides [Hash] any specific variant overrides.
18
+ def development(**overrides)
19
+ Variant.force!(:development, **overrides)
20
+ end
21
+
22
+ # Select the testing variant.
23
+ # @param overrides [Hash] any specific variant overrides.
24
+ def testing(**overrides)
25
+ Variant.force!(:testing, **overrides)
26
+ end
27
+
28
+ # Force a specific variant.
29
+ # @param name [Symbol] the default variant.
30
+ # @param overrides [Hash] any specific variant overrides.
31
+ def force(name, **overrides)
32
+ Variant.force!(name, **overrides)
33
+ end
34
+
35
+ # Show variant-related environment variables.
36
+ def show
37
+ require 'console/logger'
38
+
39
+ environment = ENV.select{|key, _| key.include?(Variant::KEY)}
40
+
41
+ Console.logger.info("Environment", environment)
42
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ require_relative 'variant/version'
24
+ require_relative 'variant/environment'
25
+
26
+ module Variant
27
+ KEY = 'VARIANT'
28
+ SUFFIX = '_VARIANT'
29
+
30
+ # Force the process-level variant to be the specified value.
31
+ #
32
+ # @reentrant Parallel modifications to `ENV` are undefined.
33
+ #
34
+ # @example
35
+ # Variant.force!(:testing)
36
+ #
37
+ def self.force!(value, environment = ENV, **overrides)
38
+ # Clear any specific variants:
39
+ environment.delete_if{|key, value| key.end_with?(SUFFIX)}
40
+
41
+ # Set the specified variant:
42
+ environment[KEY] = value.to_s
43
+
44
+ overrides.each do |name, value|
45
+ key = name.upcase.to_s + SUFFIX
46
+
47
+ environment[key] = value.to_s
48
+ end
49
+
50
+ return environment
51
+ end
52
+
53
+ def self.default
54
+ Environment.instance.default_variant
55
+ end
56
+
57
+ def self.default= value
58
+ Environment.instance.default_variant= value
59
+ end
60
+
61
+ def self.for(*arguments)
62
+ Environment.instance.variant_for(*arguments)
63
+ end
64
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright, 2016, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ require 'thread/local'
24
+
25
+ module Variant
26
+ DEVELOPMENT = :development
27
+ PRODUCTION = :production
28
+ TESTING = :testing
29
+ STAGING = :staging
30
+
31
+ class Environment
32
+ extend Thread::Local
33
+
34
+ # It is not safe to modify ENV.
35
+ def initialize(overrides = {}, default: DEVELOPMENT)
36
+ @overrides = overrides
37
+ end
38
+
39
+ attr :overrides
40
+
41
+ def with(overrides)
42
+ old_overrides = @overrides
43
+ @overrides = overrides
44
+
45
+ yield self
46
+ ensure
47
+ @overrides = old_overrides
48
+ end
49
+
50
+ def to_hash
51
+ ENV.to_hash.update(@overrides)
52
+ end
53
+
54
+ def fetch(key, *arguments, &block)
55
+ @overrides.fetch(key) do
56
+ ENV.fetch(key, *arguments, &block)
57
+ end
58
+ end
59
+
60
+ def default_variant
61
+ self.fetch('VARIANT', DEVELOPMENT).to_sym
62
+ end
63
+
64
+ def default_variant= name
65
+ @overrides['VARIANT'] = name
66
+ end
67
+
68
+ def variant_for(name, default = nil)
69
+ self.fetch(variant_key(name)) do
70
+ self.fetch('VARIANT', default)
71
+ end&.to_sym
72
+ end
73
+
74
+ def override_variant(name, value)
75
+ @overrides[variant_key(name)] = value
76
+ end
77
+
78
+ def variant_key(name)
79
+ "#{name.upcase}_VARIANT"
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright, 2016, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ module Variant
24
+ VERSION = "0.1.0"
25
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright, 2020, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ require_relative 'lib/variant/version'
24
+
25
+ Gem::Specification.new do |spec|
26
+ spec.name = "variant"
27
+ spec.version = Variant::VERSION
28
+ spec.authors = ["Samuel Williams"]
29
+ spec.email = ["samuel.williams@oriontransfer.co.nz"]
30
+
31
+ spec.summary = "A policy gem for selecting different environments."
32
+ spec.homepage = "https://github.com/socketry/variant"
33
+ spec.license = "MIT"
34
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
35
+
36
+ # Specify which files should be added to the gem when it is released.
37
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
38
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
39
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
40
+ end
41
+
42
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
43
+ spec.require_paths = ["lib"]
44
+
45
+ spec.add_dependency "thread-local"
46
+
47
+ spec.add_development_dependency "covered"
48
+ spec.add_development_dependency "bundler"
49
+ spec.add_development_dependency "rspec"
50
+ spec.add_development_dependency "rake"
51
+ end
metadata ADDED
@@ -0,0 +1,124 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: variant
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Samuel Williams
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-02-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thread-local
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: covered
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description:
84
+ email:
85
+ - samuel.williams@oriontransfer.co.nz
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".github/workflows/development.yml"
91
+ - ".gitignore"
92
+ - ".rspec"
93
+ - Gemfile
94
+ - README.md
95
+ - Rakefile
96
+ - bake/variant.rb
97
+ - lib/variant.rb
98
+ - lib/variant/environment.rb
99
+ - lib/variant/version.rb
100
+ - variant.gemspec
101
+ homepage: https://github.com/socketry/variant
102
+ licenses:
103
+ - MIT
104
+ metadata: {}
105
+ post_install_message:
106
+ rdoc_options: []
107
+ require_paths:
108
+ - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: 2.3.0
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ requirements: []
120
+ rubygems_version: 3.1.2
121
+ signing_key:
122
+ specification_version: 4
123
+ summary: A policy gem for selecting different environments.
124
+ test_files: []