diff --git a/README.md b/README.md index 0345acc..a310ff5 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,6 @@ Loads `.env` file. ## Installation - Add this to your application's `shard.yml`: ```yaml @@ -15,10 +14,10 @@ dependencies: github: gdotdesign/cr-dotenv ``` - ## Usage Your `.env` file: + ``` # Comments can be included for context # @@ -30,6 +29,7 @@ ANOTHER_VAR=awesome-value ``` In your application: + ```crystal require "dotenv" @@ -42,12 +42,17 @@ Dotenv.load ".env-other" # If you load env variable from file and # you want to raise execption in case of # missing dotenv file, to make this error -# immediately obvious then use the bang +# immediately obvious then use the bang # verion of the load method: Dotenv.load! # or Dotenv.load! ".env-other" +# Loading multiple files in order, +# and sets the last loaded value for a varibale +Dotenv.load! %w(.env .env.test) + + # From IO Dotenv.load MemoryIO.new("VAR=test") @@ -72,6 +77,7 @@ puts ENV["MY_VARIABLE"] # my-value ## Contributors - [[gdotdesign]](https://github.com/[gdotdesign]) Gusztáv Szikszai - creator, maintainer -- [[bonyiii]](https://github.com/[bonyiii]) +- [[bonyiii]](https://github.com/[bonyiii]) - [[kriskova]](https://github.com/kriskova) - [[neovintage]](https://github.com/[neovintage]) Rimas Silkaitis +- [[rodrigopinto]](https://github.com/[rodrigopinto]) Rodrigo Pinto diff --git a/shard.yml b/shard.yml index 4429ef4..37f2899 100644 --- a/shard.yml +++ b/shard.yml @@ -1,5 +1,5 @@ name: dotenv -version: 0.1.0 +version: 0.2.0 authors: - Gusztáv Szikszai diff --git a/spec/dotenv_spec.cr b/spec/dotenv_spec.cr index 745a7cd..9369d3b 100644 --- a/spec/dotenv_spec.cr +++ b/spec/dotenv_spec.cr @@ -3,82 +3,102 @@ require "./spec_helper" Dotenv.verbose = false describe Dotenv do - context "Non exsisting file." do - it "should print warning" do - Dotenv.load ".some-non-existent-env-file" + describe "#load" do + context "Non existing file." do + it "should print warning" do + Dotenv.load ".some-non-existent-env-file" + end end - end - context "Exsisting file" do - File.write ".test-env", "VAR=Hello" + context "Existing file" do + File.write ".test-env", "VAR=Hello" - it "should load env" do - Dotenv.load ".test-env" - ENV["VAR"].should eq "Hello" - end + it "should load env" do + Dotenv.load ".test-env" + ENV["VAR"].should eq "Hello" + end + + it "should return hash" do + hash = Dotenv.load ".test-env" + hash["VAR"].should eq "Hello" + end - it "should return hash" do - hash = Dotenv.load ".test-env" - hash["VAR"].should eq "Hello" + File.delete ".test-env" end - File.delete ".test-env" - end + context "Multiple existing file" do + File.write ".test-env", "VAR=Hello" + File.write ".local-env", "VAR=HelloLocal" + + it "should load env" do + Dotenv.load %w(.test-env .local-env) + ENV["VAR"].should eq "HelloLocal" + end - context "Comment Lines and Empty Lines" do - File.write ".test-env", "# This is a comment\nVAR=Dude\n\n" + it "should return hash" do + hash = Dotenv.load %w(.test-env .local-env) + hash["VAR"].should eq "HelloLocal" + end - it "should ignore" do - hash = Dotenv.load ".test-env" - hash.should eq({"VAR" => "Dude"}) + File.delete ".test-env" + File.delete ".local-env" end - File.delete ".test-env" - end + context "Comment Lines and Empty Lines" do + File.write ".test-env", "# This is a comment\nVAR=Dude\n\n" - context "Values with special characters" do - File.write ".test-env", "VAR=postgres://foo@localhost:5432/bar?max_pool_size=10" + it "should ignore" do + hash = Dotenv.load ".test-env" + hash.should eq({"VAR" => "Dude"}) + end - it "should allow `=` in values" do - hash = Dotenv.load ".test-env" - hash.should eq({"VAR" => "postgres://foo@localhost:5432/bar?max_pool_size=10"}) + File.delete ".test-env" end - File.delete ".test-env" - end + context "Values with special characters" do + File.write ".test-env", "VAR=postgres://foo@localhost:5432/bar?max_pool_size=10" - context "From IO" do - it "should load env" do - io = IO::Memory.new "VAR2=test\nVAR3=other" - hash = Dotenv.load io - hash["VAR2"].should eq "test" - hash["VAR3"].should eq "other" - ENV["VAR2"].should eq "test" - ENV["VAR3"].should eq "other" + it "should allow `=` in values" do + hash = Dotenv.load ".test-env" + hash.should eq({"VAR" => "postgres://foo@localhost:5432/bar?max_pool_size=10"}) + end + + File.delete ".test-env" + end + + context "From IO" do + it "should load env" do + io = IO::Memory.new "VAR2=test\nVAR3=other" + hash = Dotenv.load io + hash["VAR2"].should eq "test" + hash["VAR3"].should eq "other" + ENV["VAR2"].should eq "test" + ENV["VAR3"].should eq "other" + end end - end - context "From Hash" do - it "should load env" do - hash = Dotenv.load({"test" => "test"}) - hash["test"].should eq "test" - ENV["test"].should eq "test" + context "From Hash" do + it "should load env" do + hash = Dotenv.load({"test" => "test"}) + hash["test"].should eq "test" + ENV["test"].should eq "test" + end end - end - context "Invalid file" do - File.write ".test-env", "VAR1=Hello\nHELLO:asd" + context "Invalid file" do + File.write ".test-env", "VAR1=Hello\nHELLO:asd" - it "should read valid lines only" do - Dotenv.load ".test-env" - ENV["VAR1"].should eq "Hello" + it "should read valid lines only" do + Dotenv.load ".test-env" + ENV["VAR1"].should eq "Hello" - expect_raises do - ENV["HELLO"] + expect_raises(KeyError) do + ENV["HELLO"] + end end - end - File.delete ".test-env" + File.delete ".test-env" + end end describe "#load!" do @@ -88,9 +108,15 @@ describe Dotenv do Dotenv.load! ".test-env" end end + + it "should raise FileMissing error" do + expect_raises(Dotenv::FileMissing) do + Dotenv.load! %w(.test-env .local-env) + end + end end - context "Exsisting file" do + context "Existing file" do File.write ".test-env", "VAR=Hello" it "should load env" do @@ -106,6 +132,24 @@ describe Dotenv do File.delete ".test-env" end + context "Multiple existing file" do + File.write ".test-env", "VAR=Hello" + File.write ".local-env", "VAR=HelloLocal" + + it "should load env" do + Dotenv.load! %w(.test-env .local-env) + ENV["VAR"].should eq "HelloLocal" + end + + it "should return hash" do + hash = Dotenv.load! %w(.test-env .local-env) + hash["VAR"].should eq "HelloLocal" + end + + File.delete ".test-env" + File.delete ".local-env" + end + context "From IO" do it "should load env" do io = IO::Memory.new "VAR2=test\nVAR3=other" diff --git a/src/dotenv.cr b/src/dotenv.cr index c2eb5d8..0524913 100644 --- a/src/dotenv.cr +++ b/src/dotenv.cr @@ -12,13 +12,19 @@ module Dotenv @@verbose = value end - def load(path = ".env") : Hash(String, String) - load File.open(File.expand_path(path)) + def load(filename = ".env") : Hash(String, String) + load open(filename) rescue ex - log "DOTENV - Could not open file: #{path}" + log "DOTENV - Could not open file: #{filename}" {} of String => String end + def load(filenames : Array(String)) : Hash(String, String) + filenames.each_with_object({} of String => String) do |filename, hash| + hash.merge!(load(filename)) + end + end + def load(io : IO) : Hash(String, String) hash = {} of String => String io.each_line do |line| @@ -35,12 +41,18 @@ module Dotenv ENV end - def load!(path = ".env") : Hash(String, String) - load File.open(File.expand_path(path)) + def load!(filename = ".env") : Hash(String, String) + load open(filename) rescue ex raise FileMissing.new("Missing file!") end + def load!(filenames : Array(String)) : Hash(String, String) + filenames.each_with_object({} of String => String) do |filename, hash| + hash.merge!(load!(filename)) + end + end + def load!(io : IO) : Hash(String, String) load(io) end @@ -61,4 +73,8 @@ module Dotenv private def log(message : String) puts message if @@verbose end + + private def open(filename : String) : File + File.open(File.expand_path(filename)) + end end diff --git a/src/dotenv/version.cr b/src/dotenv/version.cr index 999b1ff..b0c4568 100644 --- a/src/dotenv/version.cr +++ b/src/dotenv/version.cr @@ -1,3 +1,3 @@ module Dotenv - VERSION = "0.1.0" + VERSION = "0.2.0" end