lib/lotus/utils/kernel.rb in lotus-utils-0.1.1 vs lib/lotus/utils/kernel.rb in lotus-utils-0.2.0

- old
+ new

@@ -1,8 +1,9 @@ require 'set' require 'date' require 'time' +require 'pathname' module Lotus module Utils # Kernel utilities # @since 0.1.1 @@ -18,24 +19,22 @@ # # @param arg [Object] the input # # @return [Array] the result of the coercion # - # @raise [NoMethodError] if arg doesn't implement #nil? - # # @since 0.1.1 # - # @see http://www.ruby-doc.org/core-2.1.1/Kernel.html#method-i-Array + # @see http://www.ruby-doc.org/core-2.1.2/Kernel.html#method-i-Array # - # @see http://www.ruby-doc.org/core-2.1.1/Array.html#method-i-flatten - # @see http://www.ruby-doc.org/core-2.1.1/Array.html#method-i-compact - # @see http://www.ruby-doc.org/core-2.1.1/Array.html#method-i-uniq + # @see http://www.ruby-doc.org/core-2.1.2/Array.html#method-i-flatten + # @see http://www.ruby-doc.org/core-2.1.2/Array.html#method-i-compact + # @see http://www.ruby-doc.org/core-2.1.2/Array.html#method-i-uniq # # @example Basic Usage # require 'lotus/utils/kernel' # - # Lotus::Utils::Kernel.Array(nil) # => nil + # Lotus::Utils::Kernel.Array(nil) # => [] # Lotus::Utils::Kernel.Array(true) # => [true] # Lotus::Utils::Kernel.Array(false) # => [false] # Lotus::Utils::Kernel.Array(1) # => [1] # Lotus::Utils::Kernel.Array([1]) # => [1] # Lotus::Utils::Kernel.Array([1, [2]]) # => [1,2] @@ -61,27 +60,27 @@ # Lotus::Utils::Kernel.Array(set) # => [1,2,3] # # response = Response.new(200, {}, 'hello') # Lotus::Utils::Kernel.Array(response) # => [200, {}, "hello"] def self.Array(arg) - super(arg).flatten.compact.uniq unless arg.nil? + super(arg).flatten.compact.uniq end # Coerces the argument to be a set. # # @param arg [Object] the input # # @return [Set] the result of the coercion # - # @raise [NoMethodError] if arg doesn't implement #respond_to? + # @raise [TypeError] if arg doesn't implement #respond_to? # # @since 0.1.1 # # @example Basic Usage # require 'lotus/utils/kernel' # - # Lotus::Utils::Kernel.Set(nil) # => nil + # Lotus::Utils::Kernel.Set(nil) # => #<Set: {}> # Lotus::Utils::Kernel.Set(true) # => #<Set: {true}> # Lotus::Utils::Kernel.Set(false) # => #<Set: {false}> # Lotus::Utils::Kernel.Set(1) # => #<Set: {1}> # Lotus::Utils::Kernel.Set([1]) # => #<Set: {1}> # Lotus::Utils::Kernel.Set([1, 1]) # => #<Set: {1}> @@ -110,37 +109,37 @@ # # => #<Set: {"daa798b4-630c-4e11-b29d-92f0b1c7d075"}> # # @example Unchecked Exceptions # require 'lotus/utils/kernel' # - # Lotus::Utils::Kernel.Set(BasicObject.new) # => NoMethodError + # Lotus::Utils::Kernel.Set(BasicObject.new) # => TypeError def self.Set(arg) if arg.respond_to?(:to_set) arg.to_set else Set.new(::Kernel.Array(arg)) - end unless arg.nil? + end + rescue NoMethodError + raise TypeError.new("can't convert into Set") end # Coerces the argument to be an hash. # # @param arg [Object] the input # - # @return [Hash, nil] the result of the coercion + # @return [Hash] the result of the coercion # - # @raise [NoMethodError] if arg doesn't implement #nil? - # @raise [NoMethodError] if arg doesn't implement #respond_to? # @raise [TypeError] if arg can't be coerced # # @since 0.1.1 # - # @see http://www.ruby-doc.org/core-2.1.1/Kernel.html#method-i-Hash + # @see http://www.ruby-doc.org/core-2.1.2/Kernel.html#method-i-Hash # # @example Basic Usage # require 'lotus/utils/kernel' # - # Lotus::Utils::Kernel.Hash(nil) # => nil + # Lotus::Utils::Kernel.Hash(nil) # => {} # Lotus::Utils::Kernel.Hash({a: 1}) # => { :a => 1 } # Lotus::Utils::Kernel.Hash([[:a, 1]]) # => { :a => 1 } # Lotus::Utils::Kernel.Hash(Set.new([[:a, 1]])) # => { :a => 1 } # # @example Hash Interface @@ -174,51 +173,49 @@ # # @example Unchecked Exceptions # require 'lotus/utils/kernel' # # input = BasicObject.new - # Lotus::Utils::Kernel.Hash(input) # => NoMethodError + # Lotus::Utils::Kernel.Hash(input) # => TypeError if RUBY_VERSION >= '2.1' def self.Hash(arg) if arg.respond_to?(:to_h) arg.to_h else super(arg) - end unless arg.nil? + end + rescue NoMethodError + raise TypeError.new "can't convert into Hash" end else def self.Hash(arg) case arg - when NilClass then nil when ::Hash then arg when ::Array, ::Set then Hash[*self.Array(arg)] when ->(a) { a.respond_to?(:to_h) } then arg.to_h else super(arg) end - rescue ArgumentError - raise TypeError + rescue ArgumentError, NoMethodError + raise TypeError.new "can't convert into Hash" end end # Coerces the argument to be an integer. # # It's similar to Ruby's Kernel.Integer, but it doesn't stop at the first - # error and tries to be less "whiny". + # error and raise an exception only when the argument can't be coerced. # # @param arg [Object] the argument # - # @return [Fixnum,nil] the result of the coercion + # @return [Fixnum] the result of the coercion # # @raise [TypeError] if the argument can't be coerced - # @raise [NoMethodError] if the argument doesn't implenent #nil? - # @raise [TypeError,FloatDomainError,RangeError] if the argument it's too - # big. # # @since 0.1.1 # - # @see http://www.ruby-doc.org/core-2.1.1/Kernel.html#method-i-Integer + # @see http://www.ruby-doc.org/core-2.1.2/Kernel.html#method-i-Integer # # @example Basic Usage # require 'bigdecimal' # require 'lotus/utils/kernel' # @@ -250,22 +247,22 @@ # @example Error Handling # require 'lotus/utils/kernel' # # # nil # Kernel.Integer(nil) # => TypeError - # Lotus::Utils::Kernel.Integer(nil) # => nil + # Lotus::Utils::Kernel.Integer(nil) # => 0 # # # float represented as a string - # Kernel.Integer("23.4") # => ArgumentError + # Kernel.Integer("23.4") # => TypeError # Lotus::Utils::Kernel.Integer("23.4") # => 23 # # # rational represented as a string - # Kernel.Integer("2/3") # => ArgumentError + # Kernel.Integer("2/3") # => TypeError # Lotus::Utils::Kernel.Integer("2/3") # => 2 # # # complex represented as a string - # Kernel.Integer("2.5/1") # => ArgumentError + # Kernel.Integer("2.5/1") # => TypeError # Lotus::Utils::Kernel.Integer("2.5/1") # => 2 # # @example Unchecked Exceptions # require 'date' # require 'bigdecimal' @@ -289,52 +286,55 @@ # # # When DateTime # input = DateTime.now # Lotus::Utils::Kernel.Integer(input) # => TypeError # - # # Missing #nil? - # input = BasicObject.new - # Lotus::Utils::Kernel.Integer(input) # => NoMethodError - # # # bigdecimal infinity # input = BigDecimal.new("Infinity") - # Lotus::Utils::Kernel.Integer(input) # => FloatDomainError + # Lotus::Utils::Kernel.Integer(input) # => TypeError # # # bigdecimal NaN # input = BigDecimal.new("NaN") - # Lotus::Utils::Kernel.Integer(input) # => FloatDomainError + # Lotus::Utils::Kernel.Integer(input) # => TypeError # # # big rational # input = Rational(-8) ** Rational(1, 3) - # Lotus::Utils::Kernel.Integer(input) # => RangeError + # Lotus::Utils::Kernel.Integer(input) # => TypeError # # # big complex represented as a string # input = Complex(2, 3) - # Lotus::Utils::Kernel.Integer(input) # => RangeError + # Lotus::Utils::Kernel.Integer(input) # => TypeError def self.Integer(arg) - super(arg) unless arg.nil? - rescue ArgumentError - arg.to_i + super(arg) + rescue ArgumentError, TypeError + begin + if arg.respond_to?(:to_i) + arg.to_i + else + raise TypeError.new "can't convert into Integer" + end + rescue NoMethodError + raise TypeError.new "can't convert into Integer" + end + rescue RangeError + raise TypeError.new "can't convert into Integer" end # Coerces the argument to be a float. # # It's similar to Ruby's Kernel.Float, but it doesn't stop at the first - # error and tries to be less "whiny". + # error and raise an exception only when the argument can't be coerced. # # @param arg [Object] the argument # - # @return [Float,nil] the result of the coercion + # @return [Float] the result of the coercion # # @raise [TypeError] if the argument can't be coerced - # @raise [NoMethodError] if the argument doesn't implenent #nil? - # @raise [TypeError,FloatDomainError,RangeError] if the argument it's too - # big. # # @since 0.1.1 # - # @see http://www.ruby-doc.org/core-2.1.1/Kernel.html#method-i-Float + # @see http://www.ruby-doc.org/core-2.1.2/Kernel.html#method-i-Float # # @example Basic Usage # require 'bigdecimal' # require 'lotus/utils/kernel' # @@ -367,22 +367,22 @@ # require 'bigdecimal' # require 'lotus/utils/kernel' # # # nil # Kernel.Float(nil) # => TypeError - # Lotus::Utils::Kernel.Float(nil) # => nil + # Lotus::Utils::Kernel.Float(nil) # => 0.0 # # # float represented as a string - # Kernel.Float("23.4") # => ArgumentError + # Kernel.Float("23.4") # => TypeError # Lotus::Utils::Kernel.Float("23.4") # => 23.4 # # # rational represented as a string - # Kernel.Float("2/3") # => ArgumentError + # Kernel.Float("2/3") # => TypeError # Lotus::Utils::Kernel.Float("2/3") # => 2.0 # # # complex represented as a string - # Kernel.Float("2.5/1") # => ArgumentError + # Kernel.Float("2.5/1") # => TypeError # Lotus::Utils::Kernel.Float("2.5/1") # => 2.5 # # # bigdecimal infinity # input = BigDecimal.new("Infinity") # Lotus::Utils::Kernel.Float(input) # => Infinity @@ -416,39 +416,49 @@ # input = DateTime.now # Lotus::Utils::Kernel.Float(input) # => TypeError # # # Missing #nil? # input = BasicObject.new - # Lotus::Utils::Kernel.Float(input) # => NoMethodError + # Lotus::Utils::Kernel.Float(input) # => TypeError # # # big rational # input = Rational(-8) ** Rational(1, 3) - # Lotus::Utils::Kernel.Float(input) # => RangeError + # Lotus::Utils::Kernel.Float(input) # => TypeError # # # big complex represented as a string # input = Complex(2, 3) - # Lotus::Utils::Kernel.Float(input) # => RangeError + # Lotus::Utils::Kernel.Float(input) # => TypeError def self.Float(arg) - super(arg) unless arg.nil? - rescue ArgumentError - arg.to_f + super(arg) + rescue ArgumentError, TypeError + begin + if arg.respond_to?(:to_f) + arg.to_f + else + raise TypeError.new "can't convert into Float" + end + rescue NoMethodError + raise TypeError.new "can't convert into Float" + end + rescue RangeError + raise TypeError.new "can't convert into Float" end # Coerces the argument to be a string. # - # It's similar to Ruby's Kernel.String, but it's less "whiny". + # Identical behavior of Ruby's Kernel.Array, still here because we want + # to keep the interface consistent # # @param arg [Object] the argument # - # @return [String,nil] the result of the coercion + # @return [String] the result of the coercion # # @raise [TypeError] if the argument can't be coerced - # @raise [NoMethodError] if the argument doesn't implement #nil? # # @since 0.1.1 # - # @see http://www.ruby-doc.org/core-2.1.1/Kernel.html#method-i-String + # @see http://www.ruby-doc.org/core-2.1.2/Kernel.html#method-i-String # # @example Basic Usage # require 'date' # require 'bigdecimal' # require 'lotus/utils/kernel' @@ -488,14 +498,10 @@ # # @example String interface # require 'lotus/utils/kernel' # # SimpleObject = Class.new(BasicObject) do - # def nil? - # false - # end - # # def to_s # 'simple object' # end # end # @@ -509,53 +515,40 @@ # isbn = Isbn.new(123) # # Lotus::Utils::Kernel.String(simple) # => "simple object" # Lotus::Utils::Kernel.String(isbn) # => "123" # - # @example Error Handling + # @example Comparison with Ruby # require 'lotus/utils/kernel' # # # nil # Kernel.String(nil) # => "" - # Lotus::Utils::Kernel.String(nil) # => nil + # Lotus::Utils::Kernel.String(nil) # => "" # # @example Unchecked Exceptions # require 'lotus/utils/kernel' # - # BaseObject = Class.new(BasicObject) do - # def nil? - # false - # end - # end - # - # # Missing #nil? - # input = BasicObject.new - # Lotus::Utils::Kernel.String(input) # => NoMethodError - # # # Missing #to_s or #to_str # input = BaseObject.new # Lotus::Utils::Kernel.Integer(input) # => TypeError def self.String(arg) - super(arg) unless arg.nil? + super(arg) end # Coerces the argument to be a Date. # # @param arg [Object] the argument # - # @return [Date,nil] the result of the coercion + # @return [Date] the result of the coercion # - # @raise [NoMethodError] if the argument doesn't implement #respond_to? or #to_s - # @raise [ArgumentError] if the argument can't be coerced + # @raise [TypeError] if the argument can't be coerced # # @since 0.1.1 # # @example Basic Usage # require 'lotus/utils/kernel' # - # Lotus::Utils::Kernel.Date(nil) # => nil - # # Lotus::Utils::Kernel.Date(Date.today) # # => #<Date: 2014-04-17 ((2456765j,0s,0n),+0s,2299161j)> # # Lotus::Utils::Kernel.Date(DateTime.now) # # => #<Date: 2014-04-17 ((2456765j,0s,0n),+0s,2299161j)> @@ -582,37 +575,44 @@ # # => #<Date: 2014-12-25 ((2457017j,0s,0n),+0s,2299161j)> # # @example Unchecked Exceptions # require 'lotus/utils/kernel' # - # # Missing #nil? + # # nil + # input = nil + # Lotus::Utils::Kernel.Date(input) # => TypeError + # + # # Missing #respond_to? # input = BasicObject.new - # Lotus::Utils::Kernel.Date(input) # => NoMethodError + # Lotus::Utils::Kernel.Date(input) # => TypeError + # + # # Missing #to_s? + # input = BasicObject.new + # Lotus::Utils::Kernel.Date(input) # => TypeError def self.Date(arg) if arg.respond_to?(:to_date) arg.to_date else Date.parse(arg.to_s) - end unless arg.nil? + end + rescue ArgumentError, NoMethodError + raise TypeError.new "can't convert into Date" end # Coerces the argument to be a DateTime. # # @param arg [Object] the argument # - # @return [DateTime,nil] the result of the coercion + # @return [DateTime] the result of the coercion # - # @raise [NoMethodError] if the argument doesn't implement #respond_to? or #to_s - # @raise [ArgumentError] if the argument can't be coerced + # @raise [TypeError] if the argument can't be coerced # # @since 0.1.1 # # @example Basic Usage # require 'lotus/utils/kernel' # - # Lotus::Utils::Kernel.DateTime(nil) # => nil - # # Lotus::Utils::Kernel.DateTime(3483943) # # => Time.at(3483943).to_datetime #<DateTime: 1970-02-10T08:45:43+01:00 ((2440628j,27943s,0n),+3600s,2299161j)> # # Lotus::Utils::Kernel.DateTime(DateTime.now) # # => #<DateTime: 2014-04-18T09:33:49+02:00 ((2456766j,27229s,690849000n),+7200s,2299161j)> @@ -642,39 +642,45 @@ # # => #<DateTime: 2014-01-01T00:00:00+00:00 ((2456659j,0s,0n),+0s,2299161j)> # # @example Unchecked Exceptions # require 'lotus/utils/kernel' # - # # Missing #nil? + # # When nil + # input = nil + # Lotus::Utils::Kernel.DateTime(input) # => TypeError + # + # # Missing #respond_to? # input = BasicObject.new - # Lotus::Utils::Kernel.DateTime(input) # => NoMethodError + # Lotus::Utils::Kernel.DateTime(input) # => TypeError + # + # # Missing #to_s? + # input = BasicObject.new + # Lotus::Utils::Kernel.DateTime(input) # => TypeError def self.DateTime(arg) case arg when ->(a) { a.respond_to?(:to_datetime) } then arg.to_datetime when Numeric then DateTime(Time.at(arg)) - when NilClass then nil else DateTime.parse(arg.to_s) end + rescue ArgumentError, NoMethodError + raise TypeError.new "can't convert into DateTime" end # Coerces the argument to be a Time. # # @param arg [Object] the argument # - # @return [Time,nil] the result of the coercion + # @return [Time] the result of the coercion # - # @raise [NoMethodError] if the argument doesn't implement #respond_to? or #to_s - # @raise [ArgumentError] if the argument can't be coerced + # @raise [TypeError] if the argument can't be coerced # # @since 0.1.1 # # @example Basic Usage # require 'lotus/utils/kernel' # - # Lotus::Utils::Kernel.Time(nil) # => nil - # # Lotus::Utils::Kernel.Time(Time.now) # # => 2014-04-18 15:56:39 +0200 # # Lotus::Utils::Kernel.Time(DateTime.now) # # => 2014-04-18 15:56:39 +0200 @@ -701,37 +707,46 @@ # # => 1970-01-01 01:00:00 +0100 # # @example Unchecked Exceptions # require 'lotus/utils/kernel' # - # # Missing #nil? + # # When nil + # input = nil + # Lotus::Utils::Kernel.Time(input) # => TypeError + # + # # Missing #respond_to? # input = BasicObject.new - # Lotus::Utils::Kernel.Time(input) # => NoMethodError + # Lotus::Utils::Kernel.Time(input) # => TypeError + # + # # Missing #to_s? + # input = BasicObject.new + # Lotus::Utils::Kernel.Time(input) # => TypeError def self.Time(arg) case arg when ->(a) { a.respond_to?(:to_time) } then arg.to_time when Numeric then Time.at(arg) - when NilClass then nil else Time.parse(arg.to_s) end + rescue ArgumentError, NoMethodError + raise TypeError.new "can't convert into Time" end # Coerces the argument to be a boolean. # # @param arg [Object] the argument # - # @return [true,false,nil] the result of the coercion + # @return [true,false] the result of the coercion # - # @raise [NoMethodError] if the argument doesn't implenent #respond_to? + # @raise [TypeError] if the argument can't be coerced # # @since 0.1.1 # # @example Basic Usage # require 'lotus/utils/kernel' # - # Lotus::Utils::Kernel.Boolean(nil) # => nil + # Lotus::Utils::Kernel.Boolean(nil) # => false # Lotus::Utils::Kernel.Boolean(0) # => false # Lotus::Utils::Kernel.Boolean(1) # => true # Lotus::Utils::Kernel.Boolean('0') # => false # Lotus::Utils::Kernel.Boolean('1') # => true # Lotus::Utils::Kernel.Boolean(Object.new) # => true @@ -754,19 +769,130 @@ # @example Unchecked Exceptions # require 'lotus/utils/kernel' # # # Missing #respond_to? # input = BasicObject.new - # Lotus::Utils::Kernel.Boolean(input) # => NoMethodError + # Lotus::Utils::Kernel.Boolean(input) # => TypeError def self.Boolean(arg) case arg when Numeric then arg > 0 && arg <= 1 when String, '0' then Boolean(arg.to_i) - when NilClass then nil when ->(a) { a.respond_to?(:to_bool) } then arg.to_bool else !!arg end + rescue NoMethodError + raise TypeError.new "can't convert into Boolean" + end + + # Coerces the argument to be a Pathname. + # + # @param arg [#to_pathname,#to_str] the argument + # + # @return [Pathname] the result of the coercion + # + # @raise [TypeError] if the argument can't be coerced + # + # @since 0.1.2 + # + # @example Basic Usage + # require 'lotus/utils/kernel' + # + # Lotus::Utils::Kernel.Pathname(Pathname.new('/path/to')) # => #<Pathname:/path/to> + # Lotus::Utils::Kernel.Pathname('/path/to') # => #<Pathname:/path/to> + # + # @example Pathname Interface + # require 'lotus/utils/kernel' + # + # class HomePath + # def to_pathname + # Pathname.new Dir.home + # end + # end + # + # Lotus::Utils::Kernel.Pathname(HomePath.new) # => #<Pathname:/Users/luca> + # + # @example String Interface + # require 'lotus/utils/kernel' + # + # class RootPath + # def to_str + # '/' + # end + # end + # + # Lotus::Utils::Kernel.Pathname(RootPath.new) # => #<Pathname:/> + # + # @example Unchecked Exceptions + # require 'lotus/utils/kernel' + # + # # When nil + # input = nil + # Lotus::Utils::Kernel.Pathname(input) # => TypeError + # + # # Missing #respond_to? + # input = BasicObject.new + # Lotus::Utils::Kernel.Pathname(input) # => TypeError + def self.Pathname(arg) + case arg + when ->(a) { a.respond_to?(:to_pathname) } then arg.to_pathname + else + super + end + rescue NoMethodError + raise TypeError.new "can't convert into Pathname" + end + + # Coerces the argument to be a String. + # + # @param arg [#to_sym] the argument + # + # @return [Symbol] the result of the coercion + # + # @raise [TypeError] if the argument can't be coerced + # + # @since 0.2.0 + # + # @example Basic Usage + # require 'lotus/utils/kernel' + # + # Lotus::Utils::Kernel.Symbol(:hello) # => :hello + # Lotus::Utils::Kernel.Symbol('hello') # => :hello + # + # @example Symbol Interface + # require 'lotus/utils/kernel' + # + # class StatusSymbol + # def to_sym + # :success + # end + # end + # + # Lotus::Utils::Kernel.Symbol(StatusSymbol.new) # => :success + # + # @example Unchecked Exceptions + # require 'lotus/utils/kernel' + # + # # When nil + # input = nil + # Lotus::Utils::Kernel.Symbol(input) # => TypeError + # + # # When empty string + # input = '' + # Lotus::Utils::Kernel.Symbol(input) # => TypeError + # + # # Missing #respond_to? + # input = BasicObject.new + # Lotus::Utils::Kernel.Symbol(input) # => TypeError + def self.Symbol(arg) + case arg + when '' then raise TypeError.new "can't convert into Symbol" + when ->(a) { a.respond_to?(:to_sym) } then arg.to_sym + else + raise TypeError.new "can't convert into Symbol" + end + rescue NoMethodError + raise TypeError.new "can't convert into Symbol" end end end end