pax_global_header00006660000000000000000000000064124562715040014520gustar00rootroot0000000000000052 comment=beb9981708460056c182fcfb3d65b130fe43bb8c nenv-0.2.0/000077500000000000000000000000001245627150400124655ustar00rootroot00000000000000nenv-0.2.0/.gitignore000066400000000000000000000001661245627150400144600ustar00rootroot00000000000000/.bundle/ /.yardoc /Gemfile.lock /_yardoc/ /coverage/ /doc/ /pkg/ /spec/reports/ /tmp/ *.bundle *.so *.o *.a mkmf.log nenv-0.2.0/.rspec000066400000000000000000000000361245627150400136010ustar00rootroot00000000000000--color --require spec_helper nenv-0.2.0/.rubocop.yml000066400000000000000000000000401245627150400147310ustar00rootroot00000000000000inherit_from: .rubocop_todo.yml nenv-0.2.0/.rubocop_todo.yml000066400000000000000000000015401245627150400157640ustar00rootroot00000000000000# This configuration was generated by `rubocop --auto-gen-config` # on 2014-12-13 13:35:53 +0100 using RuboCop version 0.28.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. # Offense count: 1 Lint/HandleExceptions: Enabled: false # Offense count: 1 Metrics/AbcSize: Max: 16 # Offense count: 1 # Configuration parameters: AllowURI, URISchemes. Metrics/LineLength: Max: 112 # Offense count: 1 # Configuration parameters: CountComments. Metrics/MethodLength: Max: 11 # Offense count: 8 Style/Documentation: Enabled: false # Offense count: 1 # Configuration parameters: EnforcedStyle, SupportedStyles. Style/MethodName: Enabled: false nenv-0.2.0/.travis.yml000066400000000000000000000002601245627150400145740ustar00rootroot00000000000000language: ruby bundler_args: --without development rvm: - 1.9.3 - 2.0.0 - 2.1.5 - ruby-head - jruby - rbx matrix: allow_failures: - rvm: rbx - rvm: jruby nenv-0.2.0/Gemfile000066400000000000000000000004161245627150400137610ustar00rootroot00000000000000source 'https://rubygems.org' # Specify your gem's dependencies in nenv.gemspec gemspec development_group: :test gem 'coveralls', require: false group :development do gem 'guard-rspec', '~> 4.5', require: false gem 'guard-rubocop', require: false gem 'pry' end nenv-0.2.0/Guardfile000066400000000000000000000015031245627150400143110ustar00rootroot00000000000000# A sample Guardfile # More info at https://github.com/guard/guard#readme ## Uncomment and set this to only include directories you want to watch directories(%w(lib spec)) ## Uncomment to clear the screen before every task # clearing :on group :spec, halt_on_fail: true do guard :rspec, cmd: 'bundle exec rspec' do require 'guard/rspec/dsl' dsl = Guard::RSpec::Dsl.new(self) # Feel free to open issues for suggestions and improvements # RSpec files rspec = dsl.rspec watch(rspec.spec_helper) { rspec.spec_dir } watch(rspec.spec_support) { rspec.spec_dir } watch(rspec.spec_files) # Ruby files ruby = dsl.ruby dsl.watch_spec_files_for(ruby.lib_files) end guard :rubocop do watch(/.+\.rb$/) watch(/(?:.+\/)?\.rubocop(?:_todo)?\.yml$/) { |m| File.dirname(m[0]) } end end nenv-0.2.0/LICENSE.txt000066400000000000000000000020601245627150400143060ustar00rootroot00000000000000Copyright (c) 2014 Cezary Baginski MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. nenv-0.2.0/README.md000066400000000000000000000174161245627150400137550ustar00rootroot00000000000000[![Build Status](https://travis-ci.org/e2/nenv.png?branch=master)](https://travis-ci.org/e2/nenv) [![Gem Version](http://img.shields.io/gem/v/nenv.svg)](http://badge.fury.io/rb/nenv) [![Dependency Status](https://gemnasium.com/e2/nenv.svg)](https://gemnasium.com/e2/nenv) [![Code Climate](https://codeclimate.com/github/e2/nenv/badges/gpa.svg)](https://codeclimate.com/github/e2/nenv) [![Coverage Status](https://coveralls.io/repos/e2/nenv/badge.png)](https://coveralls.io/r/e2/nenv) # Nenv Using ENV in Ruby is like using raw SQL statements - it feels wrong, because it is. If you agree, this gem is for you. ## The benefits over using ENV directly: - much friendlier stubbing in tests - you no longer have to care whether false is "0" or "false" or whatever - NO MORE ALL CAPS EVERYWHERE! - keys become methods - namespaces which can be passed around as objects - you can subclass! - you can marshal/unmarshal your own types automatically! - strict mode saves you from doing validation yourself - and there's more to come... Other benefits (and compared to other solutions): - should still work with Ruby 1.8 (in case anyone is still stuck with it) - it's designed to be as lightweight and as fast as possible compared to ENV - designed to be both hackable and convenient ## Installation Add this line to your application's Gemfile: ```ruby gem 'nenv', '~> 0.1' ``` And then execute: $ bundle Or install it yourself as: $ gem install nenv ## Examples !!! ### Automatic booleans You no longer have to care whether the value is "0" or "false" or "no" or "FALSE" or ... whatever ```ruby # Without Nenv t.verbose = (ENV['CI'] == 'true') ok = ENV['RUBYGEMS_GEMDEPS'] == "1" || ENV.key?('BUNDLE_GEMFILE') ENV['DEBUG'] = "true" ``` now becomes: ```ruby t.verbose = Nenv.ci? gemdeps = Nenv.rubygems_gemdeps? || Nenv.bundle_gemfile? Nenv.debug = true ``` ### "Namespaces" ```ruby # Without Nenv puts ENV['GIT_BROWSER'] puts ENV['GIT_PAGER'] puts ENV['GIT_EDITOR'] ``` now becomes: ```ruby git = Nenv :git puts git.browser puts git.pager puts git.editor ``` Or in block form ```ruby Nenv :git do |git| puts git.browser puts git.pager puts git.editor end ``` ### Custom type handling ```ruby # Code without Nenv paths = [ENV['GEM_HOME`]] + ENV['GEM_PATH'].split(':') enable_logging if Integer(ENV['WEB_CONCURRENCY']) > 1 mydata = YAML.load(ENV['MY_DATA']) ENV['VERBOSE'] = debug ? "1" : nil ``` can become: ```ruby # setup gem = Nenv :gem gem.instance.create_method(:path) { |p| p.split(':') } web = Nenv :web web.instance.create_method(:concurrency) { |c| Integer(c) } my = Nenv :my my.instance.create_method(:data) { |d| YAML.load(d) } Nenv.instance.create_method(:verbose=) { |v| v ? 1 : nil } # and then you can simply do: paths = [gem.home] + gem.path enable_logging if web.concurrency > 1 mydata = my.data Nenv.verbose = debug ``` ### Automatic conversion to string ```ruby ENV['RUBYGEMS_GEMDEPS'] = 1 # TypeError: no implicit conversion of Fixnum (...) ``` Nenv automatically uses `to_s`: ```ruby Nenv.rubygems_gemdeps = 1 # no problem here ``` ### Custom assignment ```ruby data = YAML.load(ENV['MY_DATA']) data[:foo] = :bar ENV['MY_DATA'] = YAML.dump(data) ``` can now become: ```ruby my = Nenv :my my.instance.create_method(:data) { |d| YAML.load(d) } my.instance.create_method(:data=) { |d| YAML.dump(d) } data = my.data data[:foo] = :bar my.data = data ``` ### Strict mode ```ruby # Without Nenv fail 'home not allowed' if ENV['HOME'] = Dir.pwd # BUG! Assignment instead of comparing! puts ENV['HOME'] # Now contains clobbered value ``` Now, clobbering can be prevented: ```ruby env = Nenv::Environment.new env.create_method(:home) fail 'home not allowed' if env.home = Dir.pwd # Fails with NoMethodError puts env.home # works ``` ### Mashup mode You can first define all the load/dump logic globally in one place ```ruby Nenv.instance.create_method(:web_concurrency) { |d| Integer(d) } Nenv.instance.create_method(:web_concurrency=) Nenv.instance.create_method(:path) { |p| Pathname(p.split(File::PATH_SEPARATOR)) } Nenv.instance.create_method(:path=) { |array| array.map(&:to_s).join(File::PATH_SEPARATOR) } # And now, anywhere in your app: Nenv.web_concurrency += 3 Nenv.path += Pathname.pwd + "foo" ``` ### Your own class (recommended version for simpler unit tests) ```ruby MyEnv = Nenv::Builder.build do create_method(:foo?) end MyEnv.new('my').foo? # same as ENV['MY_FOO'][/^(?:false|no|n|0)/i,1].nil? ``` ### Your own class (dynamic version - not recommended because harder to test) ```ruby class MyEnv < Nenv::Environment def initialize super("my") create_method(:foo?) end end MyEnv.new.foo? # same as ENV['MY_FOO'][/^(?:false|no|n|0)/i,1].nil? ``` ## NOTES Still, avoid using environment variables if you can. At least, avoid actually setting them - especially in multithreaded apps. As for Nenv, while you can access the same variable with or without namespaces, filters are tied to instances, e.g.: ```ruby Nenv.instance.create_method(:foo_bar) { |d| Integer(d) } Nenv('foo').instance.create_method(:bar) { |d| Float(d) } env = Nenv::Environment.new(:foo).tap { |e| e.create_method(:bar) } ``` all work on the same variable, but each uses a different filter for reading the value. ## Documentation / SemVer / API Any behavior not mentioned here (in this README) is subject to change. This includes module names, class names, file names, method names, etc. If you are relying on behavior not documented here, please open a ticket. ## What's wrong with ENV? Well sure, having ENV act like a Hash is much better than calling "getenv". Unfortunately, the advantages of using ENV make no sense: - it's faster but ... environment variables are rarely used thousands of times in tight loops - it's already an object ... but there's not much you can do with it (try ENV.class) - it's globally available ... but you can't isolate it in tests (you need to reset it every time) - you can use it to set variables ... but it's named like a const - it allows you to use keys regardless of case ... but by convention lowercase shouldn't be used except for local variables (which are only really used by shell scripts) - it's supposed to look ugly to discourage use ... but often your app/gem is forced to use 3rd party environment variables anyway - it's a simple Hash-like class ... but either you encapsulate it in your own classes - or all the value mapping/validation happens everywhere you want the data (yuck!) But the BIGGEST disadvantage is in specs, e.g.: ```ruby allow(ENV).to receive(:[]).with('MY_VARIABLE').and_return("foo") allow(ENV).to receive(:[]=).with('MY_VARIABLE', "foo bar") # (and if you get the above wrong, you may be debugging for a long, long time...) ``` which could instead be completely isolated as (and without side effects): ```ruby allow(env).to receive(:variable).and_return("foo") expect(env).to receive(:variable=).with("foo bar") # (with verifying doubles it's hard to get it wrong and get stuck) ``` Here's a full example: ```ruby # In your implementation MyEnv = Nenv::Builder.build do create_method(:variable) create_method(:variable=) end class Foo def foo MyEnv.new(:my).variable += "bar" end end # Stubbing the class in your specs RSpec.describe Foo do let(:env) { instance_double(MyEnv) } before { allow(MyEnv).to receive(:new).with(:my).and_return(env) } describe "#foo" do before { allow(env).to receive(:variable).and_return("foo") } it "appends a value" do expect(env).to receive(:variable=).with("foo bar") subject.foo end end end ``` ## Contributing 1. Fork it ( https://github.com/[my-github-username]/nenv/fork ) 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create a new Pull Request nenv-0.2.0/Rakefile000066400000000000000000000005041245627150400141310ustar00rootroot00000000000000require 'bundler/gem_tasks' require 'nenv' default_tasks = [] require 'rspec/core/rake_task' default_tasks << RSpec::Core::RakeTask.new(:spec) do |t| t.verbose = Nenv.ci? end unless Nenv.ci? require 'rubocop/rake_task' default_tasks << RuboCop::RakeTask.new(:rubocop) end task default: default_tasks.map(&:name) nenv-0.2.0/lib/000077500000000000000000000000001245627150400132335ustar00rootroot00000000000000nenv-0.2.0/lib/nenv.rb000066400000000000000000000007621245627150400145330ustar00rootroot00000000000000require 'nenv/version' require 'nenv/autoenvironment' require 'nenv/builder' def Nenv(namespace = nil) Nenv::AutoEnvironment.new(namespace).tap do |env| yield env if block_given? end end module Nenv class << self def respond_to?(meth) instance.respond_to?(meth) end def method_missing(meth, *args) instance.send(meth, *args) end def reset @instance = nil end def instance @instance ||= Nenv::AutoEnvironment.new end end end nenv-0.2.0/lib/nenv/000077500000000000000000000000001245627150400142015ustar00rootroot00000000000000nenv-0.2.0/lib/nenv/autoenvironment.rb000066400000000000000000000003241245627150400177620ustar00rootroot00000000000000require 'nenv/environment' module Nenv class AutoEnvironment < Nenv::Environment def method_missing(meth, *args) create_method(meth) unless respond_to?(meth) send(meth, *args) end end end nenv-0.2.0/lib/nenv/builder.rb000066400000000000000000000002211245627150400161470ustar00rootroot00000000000000require 'nenv/environment' module Nenv module Builder def self.build(&block) Class.new(Nenv::Environment, &block) end end end nenv-0.2.0/lib/nenv/environment.rb000066400000000000000000000025241245627150400170750ustar00rootroot00000000000000require 'nenv/environment/dumper' require 'nenv/environment/loader' module Nenv class Environment class Error < ArgumentError end class MethodError < Error def initialize(meth) @meth = meth end end class AlreadyExistsError < MethodError def message format('Method %s already exists', @meth.inspect) end end def initialize(namespace = nil) @namespace = (namespace ? namespace.upcase : nil) end def self.create_method(meth, &block) _create_env_method(self, meth, &block) end def create_method(meth, &block) self.class._create_env_method(class << self; self; end, meth, &block) end private def _sanitize(meth) meth.to_s[/^([^=?]*)[=?]?$/, 1].upcase end def self._create_env_method(instance, meth, &block) _fail_if_exists(instance, meth) instance.send(:define_method, meth) do |*args| env_name = [@namespace, _sanitize(meth)].compact.join('_') if args.size == 1 raw_value = args.first ENV[env_name] = Dumper.new.dump(raw_value, &block) else Loader.new(meth).load(ENV[env_name], &block) end end end def self._fail_if_exists(instance, meth) fail(AlreadyExistsError, meth) if instance.instance_methods.include?(meth) end end end nenv-0.2.0/lib/nenv/environment/000077500000000000000000000000001245627150400165455ustar00rootroot00000000000000nenv-0.2.0/lib/nenv/environment/dumper.rb000066400000000000000000000003241245627150400203650ustar00rootroot00000000000000module Nenv class Environment class Dumper def dump(raw_value, &callback) return callback.call(raw_value) if callback raw_value.nil? ? nil : raw_value.to_s end end end end nenv-0.2.0/lib/nenv/environment/loader.rb000066400000000000000000000011241245627150400203360ustar00rootroot00000000000000module Nenv class Environment class Loader def initialize(meth) @bool = meth.to_s.end_with?('?') end def load(raw_value, &callback) return callback.call(raw_value) if callback @bool ? _to_bool(raw_value) : raw_value end private def _to_bool(raw_value) case raw_value when nil nil when '' fail ArgumentError, "Can't convert empty string into Bool" when '0', 'false', 'n', 'no', 'NO', 'FALSE' false else true end end end end end nenv-0.2.0/lib/nenv/version.rb000066400000000000000000000000441245627150400162110ustar00rootroot00000000000000module Nenv VERSION = '0.2.0' end nenv-0.2.0/nenv.gemspec000066400000000000000000000020331245627150400147760ustar00rootroot00000000000000# coding: utf-8 lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'nenv/version' Gem::Specification.new do |spec| spec.name = 'nenv' spec.version = Nenv::VERSION spec.authors = ['Cezary Baginski'] spec.email = ['cezary@chronomantic.net'] spec.summary = "Convenience wrapper for Ruby's ENV" spec.description = 'Using ENV is like using raw SQL statements in your code. We all know how that ends...' spec.homepage = 'https://github.com/e2/nenv' spec.license = 'MIT' spec.files = `git ls-files -z`.split("\x0").reject do |f| /^(?:\.rspec|\.rubocop.*\.yml|\.travis\.yml|Rakefile|Guardfile|Gemfile|spec\/.*)$/.match(f) end spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) } spec.test_files = [] spec.require_paths = ['lib'] spec.add_development_dependency 'bundler', '~> 1.7' spec.add_development_dependency 'rspec', '~> 3.1' spec.add_development_dependency 'rake', '~> 10.0' end nenv-0.2.0/spec/000077500000000000000000000000001245627150400134175ustar00rootroot00000000000000nenv-0.2.0/spec/lib/000077500000000000000000000000001245627150400141655ustar00rootroot00000000000000nenv-0.2.0/spec/lib/nenv/000077500000000000000000000000001245627150400151335ustar00rootroot00000000000000nenv-0.2.0/spec/lib/nenv/builder_spec.rb000066400000000000000000000011301245627150400201130ustar00rootroot00000000000000require 'nenv/builder' RSpec.describe Nenv::Builder do describe '#build' do before do allow(ENV).to receive(:[]).with('FOO') end it 'returns a class with the given methods' do FooEnv = Nenv::Builder.build do create_method(:foo?) end FooEnv.new.foo? end context 'with duplicate methods' do it 'fails' do expect do FooEnv = Nenv::Builder.build do create_method(:foo?) create_method(:foo?) end end.to raise_error(Nenv::Environment::AlreadyExistsError) end end end end nenv-0.2.0/spec/lib/nenv/environment/000077500000000000000000000000001245627150400174775ustar00rootroot00000000000000nenv-0.2.0/spec/lib/nenv/environment/dumper_spec.rb000066400000000000000000000012721245627150400223340ustar00rootroot00000000000000require 'yaml' require 'nenv/environment/dumper' RSpec.describe Nenv::Environment::Dumper do subject { described_class.new.dump(value) } context "with \"abc\"" do let(:value) { 'abc' } it { is_expected.to eq('abc') } end context 'with 123' do let(:value) { 123 } it { is_expected.to eq('123') } end context 'with nil' do let(:value) { nil } it { is_expected.to eq(nil) } end context 'with a block' do subject do described_class.new.dump(value) { |data| YAML.dump(data) } end context 'with a yaml string' do let(:value) { { foo: 3 } } let(:yaml) { "---\n:foo: 3\n" } it { is_expected.to eq(yaml) } end end end nenv-0.2.0/spec/lib/nenv/environment/loader_spec.rb000066400000000000000000000025701245627150400223100ustar00rootroot00000000000000require 'yaml' require 'nenv/environment/loader' RSpec.describe Nenv::Environment::Loader do context 'with no block' do subject { described_class.new(meth).load(value) } context 'with a normal method' do let(:meth) { :foo } context "with \"abc\"" do let(:value) { 'abc' } it { is_expected.to eq('abc') } end end context 'with a bool method' do let(:meth) { :foo? } %w(1 true y yes TRUE YES foobar).each do |data| context "with #{data.inspect}" do let(:value) { data } it { is_expected.to eq(true) } end end %w(0 false n no FALSE NO).each do |data| context "with #{data.inspect}" do let(:value) { data } it { is_expected.to eq(false) } end end context 'with nil' do let(:value) { nil } it { is_expected.to eq(nil) } end context 'when empty string' do let(:value) { '' } it do expect { subject }.to raise_error( ArgumentError, /Can't convert empty string into Bool/ ) end end end end context 'with a block' do subject do described_class.new(:foo).load(value) { |data| YAML.load(data) } end context 'with a yaml string' do let(:value) { "--- foo\n...\n" } it { is_expected.to eq('foo') } end end end nenv-0.2.0/spec/lib/nenv/environment_spec.rb000066400000000000000000000144771245627150400210530ustar00rootroot00000000000000require 'yaml' require 'nenv/environment' RSpec.describe Nenv::Environment do let(:env) { instance_double(Hash) } # a hash is close enough before(:each) { stub_const('ENV', env) } context 'without integration' do let(:dumper) { instance_double(described_class::Dumper) } let(:loader) { instance_double(described_class::Loader) } before do allow(described_class::Dumper).to receive(:new).and_return(dumper) allow(described_class::Loader).to receive(:new).and_return(loader) end context 'with no namespace' do let(:instance) { described_class.new } context 'with an existing method' do before do subject.create_method(:foo?) end it 'uses the name as full key' do expect(ENV).to receive(:[]).with('FOO').and_return('true') expect(loader).to receive(:load).with('true').and_return(true) expect(subject.foo?).to eq(true) end end end context 'with any namespace' do let(:namespace) { 'bar' } let(:instance) { described_class.new(namespace) } describe 'creating a method' do subject { instance } before do subject.create_method(:foo) end it { is_expected.to respond_to(:foo) } context 'when the method already exists' do let(:error) { described_class::AlreadyExistsError } let(:message) { 'Method :foo already exists' } specify do expect do subject.create_method(:foo) end.to raise_error(error, message) end end end describe 'calling' do subject { instance } context 'when method does not exist' do let(:error) { NoMethodError } let(:message) { /undefined method `foo' for/ } it { expect { subject.foo }.to raise_error(error, message) } end context 'with a reader method' do context 'with no block' do before { instance.create_method(meth) } context 'with a normal method' do let(:meth) { :foo } before do allow(loader).to receive(:load).with('123').and_return(123) end it 'returns unmarshalled stored value' do expect(ENV).to receive(:[]).with('BAR_FOO').and_return('123') expect(subject.foo).to eq 123 end end context 'with a bool method' do let(:meth) { :foo? } it 'references the proper ENV variable' do allow(loader).to receive(:load).with('false').and_return(false) expect(ENV).to receive(:[]).with('BAR_FOO').and_return('false') expect(subject.foo?).to eq false end end end context 'with a block' do before do instance.create_method(:foo) { |data| YAML.load(data) } end let(:value) { "---\n:foo: 5\n" } it 'unmarshals using the block' do allow(ENV).to receive(:[]).with('BAR_FOO') .and_return(value) allow(loader).to receive(:load).with(value) do |arg, &block| expect(block).to be block.call(arg) end expect(subject.foo).to eq(foo: 5) end end end context 'with a writer method' do before { instance.create_method(:foo=) } it 'set the environment variable' do expect(ENV).to receive(:[]=).with('BAR_FOO', '123') allow(dumper).to receive(:dump).with(123).and_return('123') subject.foo = 123 end it 'marshals and stores the value' do expect(ENV).to receive(:[]=).with('BAR_FOO', '123') allow(dumper).to receive(:dump).with(123).and_return('123') subject.foo = 123 end end context 'with a method containing underscores' do before { instance.create_method(:foo_baz) } it 'reads the correct variable' do expect(ENV).to receive(:[]).with('BAR_FOO_BAZ').and_return('123') allow(loader).to receive(:load).with('123').and_return(123) subject.foo_baz end end context 'with a block' do before do instance.create_method(:foo=) { |data| YAML.dump(data) } end let(:result) { "---\n:foo: 5\n" } it 'marshals using the block' do allow(ENV).to receive(:[]=).with('BAR_FOO', result) allow(dumper).to receive(:dump).with(foo: 5) do |arg, &block| expect(block).to be block.call(arg) end subject.foo = { foo: 5 } end end context 'with an unsanitized name' do pending end end end end describe 'with integration' do context 'with any namespace' do let(:namespace) { 'baz' } let(:instance) { described_class.new(namespace) } subject { instance } context 'with a reader method' do context 'with no block' do before { instance.create_method(:foo) } it 'returns the stored value' do allow(ENV).to receive(:[]).with('BAZ_FOO').and_return('123') expect(subject.foo).to eq '123' end end context 'with a block' do before do instance.create_method(:foo) { |data| YAML.load(data) } end it 'unmarshals the value' do expect(ENV).to receive(:[]).with('BAZ_FOO') .and_return("---\n:foo: 5\n") expect(subject.foo).to eq(foo: 5) end end end context 'with a writer method' do context 'with no block' do before { instance.create_method(:foo=) } it 'marshals and stores the value' do expect(ENV).to receive(:[]=).with('BAZ_FOO', '123') subject.foo = 123 end end context 'with a block' do before do instance.create_method(:foo=) { |data| YAML.dump(data) } end it 'nmarshals the value' do expect(ENV).to receive(:[]=).with('BAZ_FOO', "---\n:foo: 5\n") subject.foo = { foo: 5 } end end end end end end nenv-0.2.0/spec/lib/nenv_spec.rb000066400000000000000000000041601245627150400164730ustar00rootroot00000000000000require 'nenv' RSpec.describe Nenv do let(:env) { instance_double(Hash) } # Hash is close enough before { stub_const('ENV', env) } describe 'Nenv() helper method' do it 'reads from env' do expect(ENV).to receive(:[]).with('GIT_BROWSER').and_return('chrome') Nenv('git').browser end it 'return the value from env' do allow(ENV).to receive(:[]).with('GIT_BROWSER').and_return('firefox') expect(Nenv('git').browser).to eq('firefox') end end describe 'Nenv() helper method with block' do it 'reads from env' do expect(ENV).to receive(:[]).with('GIT_BROWSER').and_return('chrome') Nenv('git') do |git| git.browser end end it 'return the value from env' do allow(ENV).to receive(:[]).with('GIT_BROWSER').and_return('firefox') result = nil Nenv('git') do |git| result = git.browser end expect(result).to eq('firefox') end end describe 'Nenv module' do it 'reads from env' do expect(ENV).to receive(:[]).with('CI').and_return('true') Nenv.ci? end it 'return the value from env' do allow(ENV).to receive(:[]).with('CI').and_return('false') expect(Nenv.ci?).to be(false) end context 'with no method' do it 'automatically creates the method' do expect(ENV).to receive(:[]).with('FOO').and_return('true') Nenv.foo? end end context 'with existing method' do before do Nenv.instance.create_method(:foo?) end it 'reads from env' do expect(ENV).to receive(:[]).with('FOO').and_return('true') Nenv.foo? end it 'return the value from env' do expect(ENV).to receive(:[]).with('FOO').and_return('true') expect(Nenv.foo?).to be(true) end end end # Test added here to properly test if builder is required describe 'Nenv builder' do before do allow(ENV).to receive(:[]).with('FOO').and_return('false') end it 'is required and works' do FooEnv = Nenv::Builder.build do create_method(:foo?) end FooEnv.new.foo? end end end nenv-0.2.0/spec/spec_helper.rb000066400000000000000000000022371245627150400162410ustar00rootroot00000000000000require 'coveralls' Coveralls.wear! RSpec.configure do |config| config.expect_with :rspec do |expectations| expectations.include_chain_clauses_in_custom_matcher_descriptions = true end config.mock_with :rspec do |mocks| mocks.verify_partial_doubles = true end config.filter_run focus: ENV['CI'] != 'true' config.run_all_when_everything_filtered = true config.disable_monkey_patching! # config.warnings = true config.default_formatter = 'doc' if config.files_to_run.one? # config.profile_examples = 10 config.order = :random Kernel.srand config.seed config.before do allow(ENV).to receive(:[]) do |key| fail "stub me: ENV[#{key.inspect}]" end allow(ENV).to receive(:[]=) do |key, value| fail "stub me: ENV[#{key.inspect}] = #{value.inspect}" end allow(ENV).to receive(:[]).with('PRYRC').and_call_original allow(ENV).to receive(:[]).with('DISABLE_PRY').and_call_original allow(ENV).to receive(:[]).with('ANSICON').and_call_original allow(ENV).to receive(:[]).with('TERM').and_call_original end config.after do begin Nenv.method(:reset).call rescue NameError end end end