remenv 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
+ 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