remenv 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5a6fba380b02fbbac878a4d9d213a6fc2e79aa16
4
+ data.tar.gz: d6b942a1a0e4b9307823cb06f9f4bc34ea48744a
5
+ SHA512:
6
+ metadata.gz: d20f07b922da837876ba08bfdd6b5d218ba43d97af224878c184ee8a68ebe3d48f61413c0b5489950afdb0dbffd67ace5d74f660b71133597479d09026bec2c5
7
+ data.tar.gz: 8487cf51d4e4d596aaadee6dbc4fe284f47d380910a75beba59436a355bd522d925f5fe689946d9796f74e80531508c88d02f1bc7424dc3f276ffb52791d82cf
@@ -0,0 +1,10 @@
1
+ *.gem
2
+ .bundle
3
+ .config
4
+ Gemfile.lock
5
+ doc/
6
+ pkg
7
+ rdoc
8
+ tmp
9
+ bin/rspec
10
+ TODO.md
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --warnings
3
+ --require spec_helper
@@ -0,0 +1,3 @@
1
+ ## 0.1.0 (2014-08-18)
2
+
3
+ * Initial release!
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in remenv.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Dscout, Inc
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,118 @@
1
+ # Remenv
2
+
3
+ Remote environment management. Heroku style environment configuration brought to
4
+ any production environment that has a key/value store.
5
+
6
+ ## Why Remenv?
7
+
8
+ Managing your system's configuration with environment variables is effective,
9
+ convenient, safe, and flexibile. It lets an application use the same code across
10
+ all environments and be configured entirely by variables in the environment.
11
+ The problem comes in when you have multiple production systems that need to have
12
+ the same environment. Problems are compounded when there are multiple developers
13
+ deploying to the same environment but with differing local copies of production
14
+ environment variables. Of course, ideally nobody would be in that kind of
15
+ distributed race conundrum, but in reality people make mistakes and the
16
+ production flow isn't as coordinated as we may like.
17
+
18
+ The goal of remenv is to provide a very simple (very Heroku inspired) set of
19
+ tools for managing an applications environment across any number of systems. It
20
+ approaches the problem by applying a thin layer of sugar over maniupating a
21
+ centralized key value store—namely Redis.
22
+
23
+ ## Installation
24
+
25
+ Add this line to your application's Gemfile.
26
+
27
+ ```ruby
28
+ gem 'remenv'
29
+ ```
30
+
31
+ You'll probably want to binstub it so you can avoid typing `bundle exec` all of
32
+ the time:
33
+
34
+ ```bash
35
+ bundle binstub remenv
36
+ ```
37
+
38
+ ## Command Line Usage
39
+
40
+ Running `remenv` from the command line will print out a (hopefully) helpful bit
41
+ of documentation about each command. That is certainly the best place to start:
42
+
43
+ ```
44
+ $ remenv
45
+
46
+ Commands:
47
+ remenv clear # Clear all stored key/value pairs
48
+ remenv dump FILENAME # Dump all stored key/value pairs to FILENAME
49
+ remenv help [COMMAND] # Describe available commands or one specific command
50
+ remenv load FILENAME # Load all key/value pairs from FILENAME
51
+ remenv set KEY=VALUE # Store VALUE for KEY
52
+ remenv show [KEY] # Show value for KEY or all stored key/value pairs
53
+ remenv unset KEY # Remove values for KEY
54
+
55
+ Options:
56
+ [--adapter=ADAPTER] # Default: redis
57
+ [--stage=STAGE] # Default: development
58
+ [--namespace=NAMESPACE] # Default: remenv
59
+ [--url=URL]
60
+ ```
61
+
62
+ ## Configuration
63
+
64
+ Settings should be persisted by writing configuration as YAML to `.remenv.yml`
65
+ for the current directory. Multiple stages (development, production, etc) can be
66
+ specified within the same configuration if desired. The default stage is assumed
67
+ to be development.
68
+
69
+ ```yaml
70
+ test:
71
+ adapter: memory
72
+ namespace: remenv-test
73
+ development:
74
+ adapter: redis
75
+ namespace: remenv
76
+ url: redis://localhost:6379/15
77
+ production:
78
+ adapter: redis
79
+ namespace: remenv-production
80
+ url: redis://server.com:6379/0
81
+ ```
82
+
83
+ ## Workflow
84
+
85
+ 1. Import your existing `.env` configuration for development or production:
86
+
87
+ ```bash
88
+ $ remenv load .env
89
+ ```
90
+
91
+ 2. Update any vars that may be missing or incorrect:
92
+
93
+ ```bash
94
+ $ remenv show
95
+
96
+ LOG_LEVEL DEBUG
97
+ RACK_ENV production
98
+ RAILS_ENV production
99
+
100
+ $ remenv set LOG_LEVEL=INFO
101
+
102
+ OK!
103
+ LOG_LEVEL INFO
104
+ ```
105
+
106
+ 3. Sync the configuration to a remote server using Capistrano:
107
+
108
+ ```bash
109
+ $ cap production remenv:sync
110
+ ```
111
+
112
+ ## Contributing
113
+
114
+ 1. Fork it ( http://github.com/dscout/remenv/fork )
115
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
116
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
117
+ 4. Push to the branch (`git push origin my-new-feature`)
118
+ 5. Create new Pull Request
@@ -0,0 +1,15 @@
1
+ require 'bundler/setup'
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new :spec
6
+
7
+ task :console do
8
+ require 'irb'
9
+ require 'irb/completion'
10
+ require 'remenv'
11
+ ARGV.clear
12
+ IRB.start
13
+ end
14
+
15
+ task default: :spec
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'remenv'
5
+ require 'remenv/cli'
6
+ Remenv::CLI.start(ARGV)
@@ -0,0 +1,30 @@
1
+ require 'forwardable'
2
+ require 'remenv/adapter/memory'
3
+ require 'remenv/config'
4
+ require 'remenv/io'
5
+ require 'remenv/version'
6
+ require 'remenv/formatter'
7
+
8
+ module Remenv
9
+ extend Forwardable
10
+ extend self
11
+
12
+ def_delegators :adapter, :show, :clear!, :set, :get, :unset
13
+ def_delegators :io, :dump, :load
14
+
15
+ def configure
16
+ yield self
17
+ end
18
+
19
+ def adapter=(adapter)
20
+ @adapter = adapter
21
+ end
22
+
23
+ def adapter
24
+ @adapter ||= Adapter::Memory.new
25
+ end
26
+
27
+ def io
28
+ Remenv::IO.new(adapter)
29
+ end
30
+ end
@@ -0,0 +1,33 @@
1
+ module Remenv
2
+ module Adapter
3
+ class Memory
4
+ attr_reader :store
5
+
6
+ def initialize
7
+ clear!
8
+ end
9
+
10
+ def show
11
+ store
12
+ end
13
+
14
+ def clear!
15
+ @store = {}
16
+ end
17
+
18
+ def set(pairs)
19
+ pairs.each do |key, value|
20
+ store[key.to_s] = value.to_s
21
+ end
22
+ end
23
+
24
+ def get(key)
25
+ store[key.to_s]
26
+ end
27
+
28
+ def unset(*keys)
29
+ keys.each { |key| store.delete(key) }
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,36 @@
1
+ require 'redis'
2
+
3
+ module Remenv
4
+ module Adapter
5
+ class Redis
6
+ attr_reader :store, :namespace
7
+
8
+ def initialize(url: , namespace: 'remenv')
9
+ @store = ::Redis.new(url: url)
10
+ @namespace = namespace
11
+ end
12
+
13
+ def show
14
+ store.hgetall(namespace)
15
+ end
16
+
17
+ def clear!
18
+ store.del(namespace)
19
+ end
20
+
21
+ def set(pairs)
22
+ pairs.each do |field, value|
23
+ store.hset(namespace, field, value)
24
+ end
25
+ end
26
+
27
+ def get(key)
28
+ store.hget(namespace, key)
29
+ end
30
+
31
+ def unset(*keys)
32
+ store.hdel(namespace, keys)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,106 @@
1
+ require 'thor'
2
+
3
+ module Remenv
4
+ class CLI < Thor
5
+ class_option :adapter, default: 'redis'
6
+ class_option :stage, default: 'development'
7
+ class_option :namespace, default: 'remenv'
8
+ class_option :url
9
+
10
+ no_commands do
11
+ def merged_settings
12
+ defaults = Remenv::Config.load(stage: options[:stage])
13
+ symbolized = defaults.each_with_object({}) do |(key, val), hash|
14
+ hash[key.to_sym] = val
15
+ end
16
+
17
+ symbolized.merge!(options)
18
+ end
19
+
20
+ def configure!
21
+ settings = merged_settings
22
+
23
+ if settings['adapter'] == 'redis'
24
+ require 'remenv/adapter/redis'
25
+
26
+ Remenv.adapter = Remenv::Adapter::Redis.new(
27
+ url: settings['url'],
28
+ namespace: settings['namespace']
29
+ )
30
+ end
31
+ end
32
+
33
+ def with_configuration
34
+ configure!
35
+ yield
36
+ end
37
+ end
38
+
39
+ desc 'show [KEY]', 'Show value for KEY or all stored key/value pairs'
40
+ def show(key = nil)
41
+ with_configuration do
42
+ pairs = key.nil? ? Remenv.show : Remenv.get(key)
43
+
44
+ puts Remenv::Formatter.pretty(pairs)
45
+ end
46
+ end
47
+
48
+ desc 'clear', 'Clear all stored key/value pairs'
49
+ def clear
50
+ with_configuration do
51
+ Remenv.clear!
52
+
53
+ if yes?('Are you sure? (y/n)')
54
+ say 'OK! Cleared', :green
55
+ else
56
+ say 'Aborted', :red
57
+ end
58
+ end
59
+ end
60
+
61
+ desc 'set KEY=VALUE', 'Store VALUE for KEY'
62
+ def set(*pairs)
63
+ with_configuration do
64
+ hash = pairs.each_with_object({}) do |pair, memo|
65
+ key, value = pair.split('=')
66
+ memo[key] = value
67
+ end
68
+
69
+ Remenv.set(hash)
70
+
71
+ say 'OK!', :green
72
+ puts Remenv::Formatter.pretty(hash)
73
+ end
74
+ end
75
+
76
+ desc 'unset KEY', 'Remove values for KEY'
77
+ def unset(*keys)
78
+ with_configuration do
79
+ Remenv.unset(*keys)
80
+
81
+ say 'OK!', :green
82
+ end
83
+ end
84
+
85
+ desc 'dump FILENAME', 'Dump all stored key/value pairs to FILENAME'
86
+ def dump(filename)
87
+ with_configuration do
88
+ Remenv.dump(filename)
89
+
90
+ say "OK! Dumped to #{filename}", :green
91
+ end
92
+ end
93
+
94
+ desc 'load FILENAME', 'Load all key/value pairs from FILENAME'
95
+ def load(filename)
96
+ with_configuration do
97
+ if yes?('This will clear all existing variables: (y/n)')
98
+ Remenv.load(filename)
99
+ say 'OK! Loaded', :green
100
+ else
101
+ say 'Aborted', :red
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,16 @@
1
+ require 'psych'
2
+
3
+ module Remenv
4
+ module Config
5
+ extend self
6
+
7
+ def load(filename: '.remenv.yml', stage: :development)
8
+ if File.exist?(filename)
9
+ loaded = Psych.load_file(filename)
10
+ loaded[stage] || loaded[stage.to_s]
11
+ else
12
+ {}
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ module Remenv
2
+ module Formatter
3
+ extend self
4
+
5
+ def pretty(hash)
6
+ hash ||= {}
7
+ max_len = hash.keys.map(&:size).max
8
+ sorted = hash.sort_by { |key, _| key }
9
+
10
+ sorted.inject('') do |buff, (key, val)|
11
+ buff << "#{key.to_s.ljust(max_len)} #{val}\n"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,46 @@
1
+ module Remenv
2
+ class IO
3
+ attr_reader :adapter
4
+
5
+ def initialize(adapter)
6
+ @adapter = adapter
7
+ end
8
+
9
+ def dump(filename)
10
+ write(File.open(filename, 'w+'))
11
+ end
12
+
13
+ def load(filename)
14
+ adapter.clear!
15
+
16
+ File.open(filename, 'r') do |file|
17
+ read(file)
18
+ end
19
+ end
20
+
21
+ def read(handle)
22
+ pairs = handle.each_with_object({}) do |line, hash|
23
+ raw_key, raw_val = line.split(/\s*=\s*/)
24
+
25
+ next if raw_key.nil? || raw_val.nil?
26
+
27
+ key = raw_key.sub(/^export /i, '')
28
+ val = raw_val.strip.gsub(/'|"/, '')
29
+
30
+ hash[key] = val
31
+ end
32
+
33
+ adapter.set(pairs)
34
+ end
35
+
36
+ def write(handle, leader: 'export')
37
+ handle.tap do |io|
38
+ adapter.show.each do |key, value|
39
+ io << %(#{leader} #{key}="#{value}"\n)
40
+ end
41
+
42
+ io.rewind
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,16 @@
1
+ namespace :remenv do
2
+ set :remenv_file, -> { "#{shared_path}/.env" }
3
+
4
+ desc "Upload the current environment as a file"
5
+ task :sync do
6
+ on roles(:app), in: :parallel do
7
+ envfile = fetch(:remenv_file)
8
+ envio = Remenv::IO.write(stringio)
9
+
10
+ upload!(envio, envfile)
11
+ end
12
+ end
13
+
14
+ desc "Sync and restart apps"
15
+ task sync_with_restart: ['remenv:sync', 'deploy:restart']
16
+ end
@@ -0,0 +1,3 @@
1
+ module Remenv
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'remenv/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'remenv'
8
+ spec.version = Remenv::VERSION
9
+ spec.authors = ['Parker Selbert']
10
+ spec.email = ['parker@sorentwo.com']
11
+ spec.homepage = 'https://github.com/dscout/remenv'
12
+ spec.license = 'MIT'
13
+ spec.summary = %q{Database backed environment management}
14
+ spec.description = %q{Database backed environment management}
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = 'remenv'
18
+ spec.test_files = spec.files.grep(%r{^spec/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'thor'
22
+
23
+ spec.add_development_dependency 'bundler'
24
+ spec.add_development_dependency 'capistrano'
25
+ spec.add_development_dependency 'rake'
26
+ spec.add_development_dependency 'rspec', '3.0.0'
27
+ spec.add_development_dependency 'redis'
28
+ end
@@ -0,0 +1,12 @@
1
+ require 'remenv/adapter/memory'
2
+
3
+ describe Remenv::Adapter::Memory do
4
+ it 'converts all keys and to strings' do
5
+ adapter = Remenv::Adapter::Memory.new
6
+
7
+ adapter.set(port: 3000)
8
+
9
+ expect(adapter.show).to have_key('port')
10
+ expect(adapter.get('port')).to eq('3000')
11
+ end
12
+ end
@@ -0,0 +1,42 @@
1
+ require 'remenv/adapter/redis'
2
+
3
+ describe Remenv::Adapter::Redis do
4
+ let(:adapter) do
5
+ Remenv::Adapter::Redis.new(url: 'redis://localhost:6379/15')
6
+ end
7
+
8
+ after do
9
+ adapter.clear!
10
+ end
11
+
12
+ describe '#show' do
13
+ it 'is an empty hash without anything stored' do
14
+ expect(adapter.show).to eq({})
15
+ end
16
+ end
17
+
18
+ describe '#set' do
19
+ it 'stores the key and value' do
20
+ adapter.set(PORT: 3000)
21
+
22
+ expect(adapter.show).to eq('PORT' => '3000')
23
+ end
24
+ end
25
+
26
+ describe '#get' do
27
+ it 'retrieves the value at the provided key' do
28
+ adapter.set(PORT: 3000)
29
+
30
+ expect(adapter.get('PORT')).to eq('3000')
31
+ end
32
+ end
33
+
34
+ describe '#unset' do
35
+ it 'clears the provided keys' do
36
+ adapter.set(KEY1: 1, KEY2: 2, KEY3: 3)
37
+ adapter.unset(:KEY1, :KEY3)
38
+
39
+ expect(adapter.show).to eq('KEY2' => '2')
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,32 @@
1
+ require 'remenv/config'
2
+ require 'fileutils'
3
+
4
+ describe Remenv::Config do
5
+ after do
6
+ FileUtils.rm('.remenv.yml', force: true)
7
+ end
8
+
9
+ it 'loads default settings from the current directory' do
10
+ hash = { url: 'cache.com:6329/0', namespace: 'cache-env' }
11
+
12
+ File.open('.remenv.yml', 'w') do |file|
13
+ Psych.dump({ 'development' => hash }, file)
14
+ end
15
+
16
+ expect(Remenv::Config.load).to eq(hash)
17
+ end
18
+
19
+ it 'loads environment specific settings when provided' do
20
+ staging = { url: 'cache.com:6329/0', namespace: 'cache-env' }
21
+
22
+ File.open('.remenv.yml', 'w') do |file|
23
+ Psych.dump({ staging: staging }, file)
24
+ end
25
+
26
+ expect(Remenv::Config.load(stage: :staging)).to eq(staging)
27
+ end
28
+
29
+ it 'falls back to an empty hash without a config' do
30
+ expect(Remenv::Config.load).to eq({})
31
+ end
32
+ end
@@ -0,0 +1,27 @@
1
+ require 'remenv/formatter'
2
+
3
+ describe Remenv::Formatter do
4
+ describe '.pretty' do
5
+ it 'prettifies the supplied hash' do
6
+ formatted = Remenv::Formatter.pretty(
7
+ PORT: 3000,
8
+ URL: '/api',
9
+ LOG_LEVEL: 'info'
10
+ )
11
+
12
+ expected = <<-EOF.gsub(/^\s+/, '')
13
+ LOG_LEVEL info
14
+ PORT 3000
15
+ URL /api
16
+ EOF
17
+
18
+ expect(formatted).to eq(expected)
19
+ end
20
+
21
+ it 'does not format nil input' do
22
+ formatted = Remenv::Formatter.pretty(nil)
23
+
24
+ expect(formatted).to eq('')
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,70 @@
1
+ require 'remenv/io'
2
+ require 'fileutils'
3
+
4
+ describe Remenv::IO do
5
+ let(:adapter) { Remenv::Adapter::Memory.new }
6
+
7
+ describe '#write' do
8
+ it 'writes the current configuration to an io object' do
9
+ handle = StringIO.new
10
+ io = Remenv::IO.new(adapter)
11
+
12
+ adapter.set(key1: 'a', key2: 'b')
13
+ io.write(handle, leader: 'export')
14
+
15
+ expected = <<-DATA.gsub(/^\s+/, '')
16
+ export key1="a"
17
+ export key2="b"
18
+ DATA
19
+
20
+ expect(handle.read).to eq(expected)
21
+ end
22
+ end
23
+
24
+ describe '#read' do
25
+ it 'reads configuration from an io object' do
26
+ handle = StringIO.new("key1=a\nkey2=b\n")
27
+
28
+ io = Remenv::IO.new(adapter)
29
+ io.read(handle)
30
+
31
+ expect(adapter.show).to eq(
32
+ 'key1' => 'a',
33
+ 'key2' => 'b'
34
+ )
35
+ end
36
+
37
+ it 'ignores export statements and whitespace' do
38
+ handle = StringIO.new(%(export key1 = a\n\n# comment\nEXPORT key2 = 'b'\nexport key3="c"))
39
+
40
+ io = Remenv::IO.new(adapter)
41
+ io.read(handle)
42
+
43
+ expect(adapter.show).to eq(
44
+ 'key1' => 'a',
45
+ 'key2' => 'b',
46
+ 'key3' => 'c'
47
+ )
48
+ end
49
+ end
50
+
51
+ describe '#load' do
52
+ let(:filename) { 'vars.env' }
53
+
54
+ after do
55
+ FileUtils.rm(filename, force: true)
56
+ end
57
+
58
+ it 'clears any existing stored configuration' do
59
+ File.open(filename, 'w') do |file|
60
+ file << 'export key2="b"'
61
+ end
62
+
63
+ adapter.set(key1: 'a')
64
+ io = Remenv::IO.new(adapter)
65
+ io.load(filename)
66
+
67
+ expect(adapter.show).to eq('key2' => 'b')
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,61 @@
1
+ require 'fileutils'
2
+
3
+ describe Remenv do
4
+ after do
5
+ Remenv.adapter = nil
6
+ Remenv.clear!
7
+ end
8
+
9
+ describe '.adapter' do
10
+ it 'defaults to an in-memory adapter' do
11
+ expect(Remenv.adapter).to be_instance_of(Remenv::Adapter::Memory)
12
+ end
13
+
14
+ it 'can be overridden to use a custom adapter' do
15
+ adapter = double(:adapter)
16
+
17
+ Remenv.adapter = adapter
18
+
19
+ expect(Remenv.adapter).to be(adapter)
20
+ end
21
+ end
22
+
23
+ describe '.configure' do
24
+ it 'allows interaction with the module' do
25
+ adapter = double(:adapter)
26
+
27
+ Remenv.configure do |remenv|
28
+ remenv.adapter = adapter
29
+ end
30
+
31
+ expect(Remenv.adapter).to be(adapter)
32
+ end
33
+ end
34
+
35
+ describe '.set' do
36
+ it 'stores each key and value' do
37
+ pairs = { 'RACK_ENV' => 'production', 'PORT' => '3000' }
38
+
39
+ Remenv.set(pairs)
40
+
41
+ expect(Remenv.show).to eq(pairs)
42
+ end
43
+ end
44
+
45
+ describe '.unset' do
46
+ it 'clears the provided keys' do
47
+ Remenv.set(KEY1: 1, KEY2: 2, KEY3: 3)
48
+ Remenv.unset('KEY1', 'KEY3')
49
+
50
+ expect(Remenv.show).to eq('KEY2' => '2')
51
+ end
52
+ end
53
+
54
+ describe '.get' do
55
+ it 'retrieves the value at the provided key' do
56
+ Remenv.set('PORT' => '3000')
57
+
58
+ expect(Remenv.get('PORT')).to eq('3000')
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,22 @@
1
+ require 'remenv'
2
+
3
+ RSpec.configure do |config|
4
+ config.filter_run :focus
5
+ config.run_all_when_everything_filtered = true
6
+
7
+ if config.files_to_run.one?
8
+ config.formatter = 'doc' if config.formatters.none?
9
+ end
10
+
11
+ config.order = :random
12
+ Kernel.srand config.seed
13
+
14
+ config.expect_with :rspec do |expectations|
15
+ expectations.syntax = :expect
16
+ end
17
+
18
+ config.mock_with :rspec do |mocks|
19
+ mocks.syntax = :expect
20
+ mocks.verify_partial_doubles = true
21
+ end
22
+ end
metadata ADDED
@@ -0,0 +1,161 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: remenv
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Parker Selbert
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-08-19 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'
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: bundler
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: capistrano
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: rake
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: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '='
74
+ - !ruby/object:Gem::Version
75
+ version: 3.0.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '='
81
+ - !ruby/object:Gem::Version
82
+ version: 3.0.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: redis
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Database backed environment management
98
+ email:
99
+ - parker@sorentwo.com
100
+ executables:
101
+ - remenv
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - ".rspec"
107
+ - CHANGELOG.md
108
+ - Gemfile
109
+ - LICENSE.txt
110
+ - README.md
111
+ - Rakefile
112
+ - bin/remenv
113
+ - lib/remenv.rb
114
+ - lib/remenv/adapter/memory.rb
115
+ - lib/remenv/adapter/redis.rb
116
+ - lib/remenv/cli.rb
117
+ - lib/remenv/config.rb
118
+ - lib/remenv/formatter.rb
119
+ - lib/remenv/io.rb
120
+ - lib/remenv/tasks/remenv.cap
121
+ - lib/remenv/version.rb
122
+ - remenv.gemspec
123
+ - spec/adapter/memory_spec.rb
124
+ - spec/adapter/redis_spec.rb
125
+ - spec/remenv/config_spec.rb
126
+ - spec/remenv/formatter_spec.rb
127
+ - spec/remenv/io_spec.rb
128
+ - spec/remenv_spec.rb
129
+ - spec/spec_helper.rb
130
+ homepage: https://github.com/dscout/remenv
131
+ licenses:
132
+ - MIT
133
+ metadata: {}
134
+ post_install_message:
135
+ rdoc_options: []
136
+ require_paths:
137
+ - lib
138
+ required_ruby_version: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ required_rubygems_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ requirements: []
149
+ rubyforge_project:
150
+ rubygems_version: 2.3.0
151
+ signing_key:
152
+ specification_version: 4
153
+ summary: Database backed environment management
154
+ test_files:
155
+ - spec/adapter/memory_spec.rb
156
+ - spec/adapter/redis_spec.rb
157
+ - spec/remenv/config_spec.rb
158
+ - spec/remenv/formatter_spec.rb
159
+ - spec/remenv/io_spec.rb
160
+ - spec/remenv_spec.rb
161
+ - spec/spec_helper.rb