envied 0.9.1 → 0.9.2.rc1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 1eae6e996d1e0a70624b7c24167eccd631a5d9a0
4
- data.tar.gz: d9df438b52137f7a22592b468a44895f7cd5a99d
2
+ SHA256:
3
+ metadata.gz: 13dbc94c996f024f24f78d106973b051c90c83231a79a5f78e190f17c31c431b
4
+ data.tar.gz: '0836c6bb61eb65228beaa6ee0100d9229f7557b52d663a68914b641528d37d6f'
5
5
  SHA512:
6
- metadata.gz: 6e770306eb9e9fb37130e5a3fb69be59d3c25443bbd1c36ab09303a9575ad884f0f4569755827f7e0f1362e05621d0c7ac6455d2eb438b620b2bd48e4f6ac3fb
7
- data.tar.gz: 6a49f0e90abb416a73e3199961df26b4cdef5e83fa8c0b60e9053f46f4ed18cec7608faddb9b82fdaa726a9329922981135eb05c6a85043ae4052ca34ddff7bb
6
+ metadata.gz: 85fc118a868a8b78e22c9e1160fe842e2a4a173f86c39f740cdaa8f26cc3ba2d383f4ab2c6606ee422a60e914b30a8b6f5db109532051831430be52b8e1f030c
7
+ data.tar.gz: 96f37d724c1d660e1530360782c01d704562ded183c4f19fc3e9821c2a8ac6bab319434210d15c9e7f40d8e80c686bbdd61f73df20c66af549b109ec3a31f9f3
data/.gitignore CHANGED
@@ -1,18 +1,14 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- .config
5
- .yardoc
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /tmp/
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
13
+
6
14
  Gemfile.lock
7
- InstalledFiles
8
- _yardoc
9
- coverage
10
- doc/
11
- lib/bundler/man
12
- pkg
13
- rdoc
14
- spec/reports
15
- test/tmp
16
- test/version_tmp
17
- tmp
18
- bin
data/.rspec CHANGED
@@ -1,3 +1,2 @@
1
- --warnings
2
- --format progress
3
1
  --color
2
+ --require spec_helper
@@ -1,16 +1,15 @@
1
1
  language: ruby
2
2
 
3
3
  before_install:
4
+ - "echo 'gem: --no-document' > ~/.gemrc"
4
5
  - gem update --system
5
6
  - gem install bundler
6
7
 
7
8
  rvm:
8
- - 2.1.10
9
- - 2.2.7
10
- - 2.3.4
11
- - 2.4.1
12
- - jruby-9.1.12.0
13
- - jruby-head
9
+ - 2.4.5
10
+ - 2.5.5
11
+ - 2.6.2
12
+ - jruby-9.2.6.0
14
13
 
15
14
  cache: bundler
16
15
  sudo: false
@@ -1,3 +1,8 @@
1
+ ## master / unreleased
2
+
3
+ * Now requiring Ruby 2.4+ [#48], [#51]
4
+ * Removed `coercible` dependency as now all coercion functionality is implemented locally. This is a backwards compatible change. [#49]
5
+
1
6
  ## 0.9.1 / 2017-07-06
2
7
 
3
8
  * Updates `envied check:heroku` to support multiline ENV variables [#42](../../pull/42)
data/Gemfile CHANGED
@@ -2,6 +2,3 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in envied.gemspec
4
4
  gemspec
5
-
6
- gem 'pry'
7
- gem 'benchmark-ips'
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # ENVied [![Build Status](https://travis-ci.org/eval/envied.svg?branch=master)](https://travis-ci.org/eval/envied)
1
+ # ENVied [![Build Status](https://travis-ci.org/eval/envied.svg?branch=master)](https://travis-ci.org/eval/envied) [![project chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://envied-rb.zulipchat.com/)
2
2
 
3
3
  ### TL;DR ensure presence and type of your app's ENV-variables.
4
4
 
@@ -19,7 +19,6 @@ For the rationale behind this project, see this [blogpost](http://www.gertgoet.c
19
19
  * [Groups](#groups)
20
20
  * [Defaults](#defaults)
21
21
  * [More examples](#more-examples)
22
- * [Rails](#rails--spring)
23
22
  * [Command-line interface](#command-line-interface)
24
23
  * [How do I...?](#how-do-i)
25
24
  * [Testing](#testing)
@@ -91,11 +90,11 @@ The following types are supported:
91
90
  * `:time` (e.g. '14:00')
92
91
  * `:hash` (e.g. 'a=1&b=2' becomes `{'a' => '1', 'b' => '2'}`)
93
92
  * `:array` (e.g. 'tag1,tag2' becomes `['tag1', 'tag2']`)
94
- * `:uri` (e.g. 'http://www.google.com' becomes `URI.parse('http://www.google.com')`
93
+ * `:uri` (e.g. 'http://www.google.com' becomes result of `URI.parse('http://www.google.com')`)
95
94
 
96
95
  ### Groups
97
96
 
98
- Groups give you more flexibility to define when variables are needed.
97
+ Groups give you more flexibility to define when variables are needed.
99
98
  It's similar to groups in a Gemfile:
100
99
 
101
100
  ```ruby
@@ -147,7 +146,7 @@ variable :FORCE_SSL, :boolean, default: 'false'
147
146
  variable :PORT, :integer, default: proc {|envied| envied.FORCE_SSL ? 443 : 80 }
148
147
  ```
149
148
 
150
- Please remember that ENVied only **reads** from ENV; it doesn't mutate ENV.
149
+ Please remember that ENVied only **reads** from ENV; it doesn't mutate ENV.
151
150
  Don't let setting a default for, say `RAILS_ENV`, give you the impression that `ENV['RAILS_ENV']` is set.
152
151
  As a rule of thumb you should only use defaults:
153
152
  * for local development
@@ -220,7 +219,7 @@ bundle exec rspec
220
219
  ## Developing
221
220
 
222
221
  ```bash
223
- bundle exec pry --gem
222
+ bin/console
224
223
  ```
225
224
 
226
225
  ## Contributing
data/Rakefile CHANGED
@@ -1,10 +1,6 @@
1
1
  require "bundler/gem_tasks"
2
- require 'rspec/core/rake_task'
2
+ require "rspec/core/rake_task"
3
3
 
4
- RSpec::Core::RakeTask.new(:spec) do |s|
5
- s.ruby_opts = %w(-w)
6
- s.rspec_opts = '--format progress'
7
- end
4
+ RSpec::Core::RakeTask.new(:spec)
8
5
 
9
- desc "Run the specs"
10
6
  task default: :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "envied"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require 'envied'
3
+
4
+ ENVied::Cli.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -18,10 +18,11 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.required_ruby_version = ">= 2.1.9"
22
- spec.add_dependency "coercible", "~> 1.0"
21
+ spec.required_ruby_version = ">= 2.4"
22
+
23
23
  spec.add_dependency "thor", "~> 0.15"
24
- spec.add_development_dependency "bundler", "~> 1.5"
25
- spec.add_development_dependency "rake"
24
+
25
+ spec.add_development_dependency "bundler", "~> 2.0"
26
+ spec.add_development_dependency "rake", "~> 12.0"
26
27
  spec.add_development_dependency "rspec", "~> 3.0"
27
28
  end
@@ -12,8 +12,7 @@ class ENVied
12
12
  alias_method :required?, :env
13
13
  end
14
14
 
15
- def self.require(*args)
16
- options = args.last.is_a?(Hash) ? args.pop : {}
15
+ def self.require(*args, **options)
17
16
  requested_groups = (args && !args.empty?) ? args : ENV['ENVIED_GROUPS']
18
17
  env!(requested_groups, options)
19
18
  error_on_missing_variables!(options)
@@ -22,26 +21,23 @@ class ENVied
22
21
  ensure_spring_after_fork_require(args, options)
23
22
  end
24
23
 
25
- def self.env!(requested_groups, options = {})
26
- @env = begin
27
- @config = options.fetch(:config) { Configuration.load }
28
- groups = required_groups(*requested_groups)
29
- EnvProxy.new(@config, groups: groups)
30
- end
24
+ def self.env!(requested_groups, **options)
25
+ @config = options.fetch(:config) { Configuration.load }
26
+ @env = EnvProxy.new(@config, groups: required_groups(*requested_groups))
31
27
  end
32
28
 
33
- def self.error_on_missing_variables!(options = {})
29
+ def self.error_on_missing_variables!(**options)
34
30
  names = env.missing_variables.map(&:name)
35
31
  if names.any?
36
- msg = "The following environment variables should be set: #{names * ', '}."
32
+ msg = "The following environment variables should be set: #{names.join(', ')}."
37
33
  msg << "\nPlease make sure to stop Spring before retrying." if spring_enabled? && !options[:via_spring]
38
34
  raise msg
39
35
  end
40
36
  end
41
37
 
42
- def self.error_on_uncoercible_variables!(options = {})
38
+ def self.error_on_uncoercible_variables!(**options)
43
39
  errors = env.uncoercible_variables.map do |v|
44
- "%{name} ('%{value}' can't be coerced to %{type})" % {name: v.name, value: env.value_to_coerce(v), type: v.type }
40
+ format("%{name} with %{value} (%{type})", name: v.name, value: env.value_to_coerce(v).inspect, type: v.type)
45
41
  end
46
42
  if errors.any?
47
43
  msg = "The following environment variables are not coercible: #{errors.join(", ")}."
@@ -56,17 +52,18 @@ class ENVied
56
52
  result.any? ? result.map(&:to_sym) : [:default]
57
53
  end
58
54
 
59
- def self.ensure_spring_after_fork_require(args, options = {})
55
+ def self.ensure_spring_after_fork_require(args, **options)
60
56
  if spring_enabled? && !options[:via_spring]
61
- Spring.after_fork { ENVied.require(args, options.merge(:via_spring => true)) }
57
+ Spring.after_fork { ENVied.require(args, options.merge(via_spring: true)) }
62
58
  end
63
59
  end
64
60
 
65
61
  def self.springify(&block)
66
62
  if defined?(ActiveSupport::Deprecation.warn) && !required?
67
- ActiveSupport::Deprecation.warn(<<-MSG)
68
- It's no longer recommended to `ENVied.require` within ENVied.springify's block. Please re-run `envied init:rails` to upgrade.
69
- MSG
63
+ ActiveSupport::Deprecation.warn(<<~MSG)
64
+ It's no longer recommended to `ENVied.require` within ENVied.springify's
65
+ block. Please re-run `envied init:rails` to upgrade.
66
+ MSG
70
67
  end
71
68
  if spring_enabled?
72
69
  Spring.after_fork(&block)
@@ -43,10 +43,8 @@ class ENVied
43
43
  puts "Writing Envfile to #{File.expand_path('Envfile')}"
44
44
  template("Envfile.tt")
45
45
 
46
- puts <<-INIT
47
- Add the following snippet (or similar) to your app's initialization:
48
- ENVied.require(*ENV['ENVIED_GROUPS'] || [:default, ENV['RACK_ENV']])
49
- INIT
46
+ puts "Add the following snippet (or similar) to your app's initialization:"
47
+ puts "ENVied.require(*ENV['ENVIED_GROUPS'] || [:default, ENV['RACK_ENV']])"
50
48
  end
51
49
 
52
50
  desc "init:rails", "Generate all files needed for a Rails project"
@@ -79,7 +77,6 @@ INIT
79
77
  end
80
78
 
81
79
  desc "check:heroku", "Checks whether a Heroku config contains required variables"
82
-
83
80
  long_desc <<-LONG
84
81
  Checks the config of your Heroku app against the local Envfile.
85
82
 
@@ -96,14 +93,11 @@ INIT
96
93
  option :quiet, type: :boolean, desc: 'Communicate success of the check only via the exit status.'
97
94
  define_method "check:heroku" do
98
95
  if STDIN.tty?
99
- error <<-ERR
100
- Please pipe the contents of `heroku config --json` to this task.
101
- I.e. `heroku config --json | bundle exec envied check:heroku`"
102
- ERR
96
+ error "Please pipe to this task i.e. `heroku config --json | bundle exec envied check:heroku`"
103
97
  exit 1
104
98
  end
105
99
  heroku_env = JSON.parse(STDIN.read)
106
- ENV.replace({}).update(heroku_env)
100
+ ENV.replace(heroku_env)
107
101
 
108
102
  requested_groups = ENV['ENVIED_GROUPS'] || options[:groups]
109
103
  ENVied.require(*requested_groups)
@@ -117,7 +111,6 @@ ERR
117
111
  Generates a shell script to check the Heroku config against the local Envfile.
118
112
 
119
113
  The same as the check:heroku-task, but all in one script (no need to pipe `heroku config --json` to it etc.).
120
-
121
114
  LONG
122
115
  option :dest, banner: "where to put the script", desc: "Default: bin/<app>-env-check or bin/heroku-env-check"
123
116
  option :app, banner: "name of Heroku app", desc: "uses ENV['HEROKU_APP'] as default if present", default: ENV['HEROKU_APP']
@@ -1,7 +1,8 @@
1
- require 'coercible'
2
-
3
1
  # Responsible for all string to type coercions.
4
2
  class ENVied::Coercer
3
+
4
+ UnsupportedCoercion = Class.new(StandardError)
5
+
5
6
  # Coerce strings to specific type.
6
7
  #
7
8
  # @param string [String] the string to be coerced
@@ -14,14 +15,9 @@ class ENVied::Coercer
14
15
  # @return [type] the coerced string.
15
16
  def coerce(string, type)
16
17
  unless supported_type?(type)
17
- raise ArgumentError, "#{type.inspect} is not supported type"
18
+ raise ArgumentError, "The type `#{type.inspect}` is not supported."
18
19
  end
19
- coerce_method_for(type.to_sym)[string]
20
- end
21
-
22
- def coerce_method_for(type)
23
- return nil unless supported_type?(type)
24
- coercer.method("to_#{type.downcase}")
20
+ coercer.public_send("to_#{type.downcase}", string)
25
21
  end
26
22
 
27
23
  def self.supported_types
@@ -52,7 +48,7 @@ class ENVied::Coercer
52
48
  end
53
49
 
54
50
  def coercer
55
- @coercer ||= Coercible::Coercer.new[ENViedString]
51
+ @coercer ||= ENViedString.new
56
52
  end
57
53
 
58
54
  def coerced?(value)
@@ -63,7 +59,7 @@ class ENVied::Coercer
63
59
  return false unless supported_type?(type)
64
60
  coerce(string, type)
65
61
  true
66
- rescue Coercible::UnsupportedCoercion
62
+ rescue UnsupportedCoercion
67
63
  false
68
64
  end
69
65
  end
@@ -1,15 +1,55 @@
1
- require 'coercible'
1
+ class ENVied::Coercer::ENViedString
2
+ TRUE_VALUES = %w[1 on t true y yes].freeze
3
+ FALSE_VALUES = %w[0 off f false n no].freeze
4
+ BOOLEAN_MAP = (TRUE_VALUES.product([ true ]) + FALSE_VALUES.product([ false ])).to_h.freeze
2
5
 
3
- class ENVied::Coercer::ENViedString < Coercible::Coercer::String
4
6
  def to_array(str)
5
7
  str.split(/(?<!\\),/).map{|i| i.gsub(/\\,/,',') }
6
8
  end
7
9
 
10
+ def to_boolean(str)
11
+ BOOLEAN_MAP.fetch(str&.downcase) do
12
+ raise_unsupported_coercion(str, __method__)
13
+ end
14
+ end
15
+
16
+ def to_date(str)
17
+ require 'date'
18
+ ::Date.parse(str)
19
+ rescue ArgumentError
20
+ raise_unsupported_coercion(str, __method__)
21
+ end
22
+
23
+ def to_float(str)
24
+ Float(str)
25
+ rescue ArgumentError
26
+ raise_unsupported_coercion(str, __method__)
27
+ end
28
+
8
29
  def to_hash(str)
9
30
  require 'cgi'
10
31
  ::CGI.parse(str).map { |key, values| [key, values[0]] }.to_h
11
32
  end
12
33
 
34
+ def to_string(str)
35
+ if str.respond_to?(:to_str)
36
+ str.public_send(:to_str)
37
+ else
38
+ raise_unsupported_coercion(str, __method__)
39
+ end
40
+ end
41
+
42
+ def to_symbol(str)
43
+ str.to_sym
44
+ end
45
+
46
+ def to_time(str)
47
+ require 'time'
48
+ ::Time.parse(str)
49
+ rescue ArgumentError
50
+ raise_unsupported_coercion(str, __method__)
51
+ end
52
+
13
53
  def to_uri(str)
14
54
  require 'uri'
15
55
  ::URI.parse(str)
@@ -20,4 +60,13 @@ class ENVied::Coercer::ENViedString < Coercible::Coercer::String
20
60
  rescue ArgumentError
21
61
  raise_unsupported_coercion(str, __method__)
22
62
  end
63
+
64
+ private
65
+
66
+ def raise_unsupported_coercion(value, method)
67
+ raise(
68
+ ENVied::Coercer::UnsupportedCoercion,
69
+ "#{self.class}##{method} doesn't know how to coerce #{value.inspect}"
70
+ )
71
+ end
23
72
  end
@@ -2,21 +2,13 @@ class ENVied
2
2
  class Configuration
3
3
  attr_reader :current_group, :defaults_enabled, :coercer
4
4
 
5
- def initialize(options = {}, &block)
5
+ def initialize(**options, &block)
6
6
  @coercer = options.fetch(:coercer, Coercer.new)
7
7
  @defaults_enabled = options.fetch(:enable_defaults, defaults_enabled_default)
8
8
  instance_eval(&block) if block_given?
9
9
  end
10
10
 
11
- def defaults_enabled_default
12
- if ENV['ENVIED_ENABLE_DEFAULTS'].nil?
13
- false
14
- else
15
- @coercer.coerce(ENV['ENVIED_ENABLE_DEFAULTS'], :boolean)
16
- end
17
- end
18
-
19
- def self.load(options = {})
11
+ def self.load(**options)
20
12
  envfile = File.expand_path('Envfile')
21
13
  new(options).tap do |v|
22
14
  v.instance_eval(File.read(envfile), envfile)
@@ -33,13 +25,9 @@ class ENVied
33
25
  @defaults_enabled
34
26
  end
35
27
 
36
- def variable(name, *args)
37
- options = args.last.is_a?(Hash) ? args.pop : {}
38
- type = args.first || :string
39
-
28
+ def variable(name, type = :string, **options)
40
29
  unless coercer.supported_type?(type)
41
- raise ArgumentError,
42
- "Variable type (of #{name}) should be one of #{coercer.supported_types}"
30
+ raise ArgumentError, "#{type.inspect} is not a supported type. Should be one of #{coercer.supported_types}"
43
31
  end
44
32
  options[:group] = current_group if current_group
45
33
  variables << ENVied::Variable.new(name, type, options)
@@ -57,6 +45,15 @@ class ENVied
57
45
  def variables
58
46
  @variables ||= []
59
47
  end
60
- end
61
48
 
49
+ private
50
+
51
+ def defaults_enabled_default
52
+ if ENV['ENVIED_ENABLE_DEFAULTS'].nil?
53
+ false
54
+ else
55
+ @coercer.coerce(ENV['ENVIED_ENABLE_DEFAULTS'], :boolean)
56
+ end
57
+ end
58
+ end
62
59
  end