Skip to content

Commit

Permalink
Merge branch 'master' into 0.3.x
Browse files Browse the repository at this point in the history
  • Loading branch information
jodosha committed Nov 14, 2014
2 parents 07698e3 + 3ae03b8 commit 47e517a
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 26 deletions.
53 changes: 46 additions & 7 deletions lib/lotus/utils/class.rb
@@ -1,22 +1,61 @@
require 'lotus/utils/string'
require 'lotus/utils/deprecation'

module Lotus
module Utils
# Class utilities
# @since 0.1.0
class Class
# Loads a class for the given string or pattern.
#
# @param name [String] the specific class name or pattern for the class that we want to load
# Loads a class for the given name.
#
# @param name [String] the specific class name
# @param namespace [Class, Module] the Ruby namespace where we want to perform the lookup.
#
# @return [Class, Module] the found Ruby constant.
#
# @raise [NameError] if no constant can be found.
#
# @since 0.1.0
#
# @example
# require 'lotus/utils/class'
#
# module App
# module Service
# class Endpoint
# end
# end
#
# class ServiceEndpoint
# end
# end
#
# # basic usage
# Lotus::Utils::Class.load!('App::Service') # => App::Service
#
# # with explicit namespace
# Lotus::Utils::Class.load!('Service', App) # => App::Service
#
# # with missing constant
# Lotus::Utils::Class.load!('Unknown') # => raises NameError
def self.load!(name, namespace = Object)
if name.match(/\|/)
Utils::Deprecation.new("Using Lotus::Utils::Class.load! with a pattern is deprecated, please use Lotus::Utils::Class.load_from_pattern!: #{ name }, #{ namespace }")
return load_from_pattern!(name, namespace)
end

namespace.const_get(name)
end

# Loads a class from the given pattern name and namespace
#
# @param pattern [String] the class name pattern
# @param namespace [Class, Module] the Ruby namespace where we want to perform the lookup.
# @return [Class, Module] the found Ruby constant.
#
# @raise [NameError] if no constant can be found.
#
# @since x.x.x
#
# @see Lotus::Utils::String#tokenize
#
# @example
Expand Down Expand Up @@ -44,15 +83,15 @@ class Class
#
# # with missing constant
# Lotus::Utils::Class.load!('Unknown') # => raises NameError
def self.load!(name, namespace = Object)
String.new(name).tokenize do |token|
def self.load_from_pattern!(pattern, namespace = Object)
String.new(pattern).tokenize do |token|
begin
return namespace.const_get(token)
rescue NameError
end
end

full_name = [ (namespace == Object ? nil : namespace), name ].compact.join('::')
full_name = [ (namespace == Object ? nil : namespace), pattern ].compact.join('::')
raise NameError.new("uninitialized constant #{ full_name }")
end
end
Expand Down
56 changes: 37 additions & 19 deletions test/class_test.rb
Expand Up @@ -2,62 +2,80 @@
require 'lotus/utils/class'

describe Lotus::Utils::Class do
describe '.load!' do
before do
module App
module Layer
class Step
end
before do
module App
module Layer
class Step
end
end

module Service
class Point
end
module Service
class Point
end
end

class ServicePoint
end
class ServicePoint
end
end
end

describe '.load!' do
it 'loads the class from the given static string' do
Lotus::Utils::Class.load!('App::Layer::Step').must_equal(App::Layer::Step)
end

it 'raises an error in case of missing class' do
-> { Lotus::Utils::Class.load!('Missing') }.must_raise(NameError)
end

it 'prints a deprecation warning if used with a pattern' do
_, err = capture_io do
Lotus::Utils::Class.load!('(Layer|Layer::)Step', App).must_equal(App::Layer::Step)
end

err.must_include "Using Lotus::Utils::Class.load! with a pattern is deprecated, please use Lotus::Utils::Class.load_from_pattern!: (Layer|Layer::)Step, App"
end
end

describe '.load_from_pattern!' do
it 'loads the class from the given static string' do
Lotus::Utils::Class.load_from_pattern!('App::Layer::Step').must_equal(App::Layer::Step)
end

it 'raises error for missing constant' do
error = -> { Lotus::Utils::Class.load!('MissingConstant') }.must_raise(NameError)
error = -> { Lotus::Utils::Class.load_from_pattern!('MissingConstant') }.must_raise(NameError)
error.message.must_equal "uninitialized constant MissingConstant"
end

it 'raises error for missing constant with multiple alternatives' do
error = -> { Lotus::Utils::Class.load!('Missing(Constant|Class)') }.must_raise(NameError)
error = -> { Lotus::Utils::Class.load_from_pattern!('Missing(Constant|Class)') }.must_raise(NameError)
error.message.must_equal "uninitialized constant Missing(Constant|Class)"
end

it 'raises error with full constant name' do
error = -> { Lotus::Utils::Class.load!('Step', App) }.must_raise(NameError)
error = -> { Lotus::Utils::Class.load_from_pattern!('Step', App) }.must_raise(NameError)
error.message.must_equal "uninitialized constant App::Step"
end

it 'raises error with full constant name and multiple alternatives' do
error = -> { Lotus::Utils::Class.load!('(Step|Point)', App) }.must_raise(NameError)
error = -> { Lotus::Utils::Class.load_from_pattern!('(Step|Point)', App) }.must_raise(NameError)
error.message.must_equal "uninitialized constant App::(Step|Point)"
end

it 'loads the class from given string, by interpolating tokens' do
Lotus::Utils::Class.load!('App::Service(::Point|Point)').must_equal(App::Service::Point)
Lotus::Utils::Class.load_from_pattern!('App::Service(::Point|Point)').must_equal(App::Service::Point)
end

it 'loads the class from given string, by interpolating string tokens and respecting their order' do
Lotus::Utils::Class.load!('App::Service(Point|::Point)').must_equal(App::ServicePoint)
Lotus::Utils::Class.load_from_pattern!('App::Service(Point|::Point)').must_equal(App::ServicePoint)
end

it 'loads the class from given string, by interpolating tokens and not stopping after first fail' do
Lotus::Utils::Class.load!('App::(Layer|Layer::)Step').must_equal(App::Layer::Step)
Lotus::Utils::Class.load_from_pattern!('App::(Layer|Layer::)Step').must_equal(App::Layer::Step)
end

it 'loads class from given string and namespace' do
Lotus::Utils::Class.load!('(Layer|Layer::)Step', App).must_equal(App::Layer::Step)
Lotus::Utils::Class.load_from_pattern!('(Layer|Layer::)Step', App).must_equal(App::Layer::Step)
end
end
end

0 comments on commit 47e517a

Please sign in to comment.