Skip to content

Commit

Permalink
Merge 667fbda into bd4c3b2
Browse files Browse the repository at this point in the history
  • Loading branch information
misfo committed Oct 5, 2013
2 parents bd4c3b2 + 667fbda commit 9bfabdb
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 82 deletions.
2 changes: 1 addition & 1 deletion config/reek.yml
Expand Up @@ -47,7 +47,7 @@ UncommunicativeModuleName:
NestedIterators:
ignore_iterators: []
exclude: [
'AbstractType::ClassMethods#create_abstract_singleton_method'
'AbstractType::AbstractMethodDeclarations#create_abstract_singleton_method'
]
enabled: true
max_allowed_nesting: 1
Expand Down
40 changes: 22 additions & 18 deletions lib/abstract_type.rb
Expand Up @@ -13,31 +13,35 @@ module AbstractType
# @api private
def self.included(descendant)
super
descendant.extend(ClassMethods)
create_new_method(descendant)
descendant.extend(AbstractMethodDeclarations)
end

private_class_method :included

module ClassMethods

# Instantiate a new object
#
# Ensures that the instance cannot be of the abstract type
# and must be a descendant.
#
# @example
# object = AbstractType.new
#
# @return [Object]
#
# @api public
def new(*)
if superclass.equal?(Object)
# Define the new method on the abstract type
#
# Ensures that the instance cannot be of the abstract type
# and must be a descendant.
#
# @param [Class] abstract_class
#
# @return [undefined]
#
# @api private
def self.create_new_method(abstract_class)
abstract_class.define_singleton_method(:new) do |*args, &block|
if equal?(abstract_class)
raise NotImplementedError, "#{inspect} is an abstract type"
else
super
super(*args, &block)
end
end
end

private_class_method :create_new_method

module AbstractMethodDeclarations

# Create abstract instance methods
#
Expand Down Expand Up @@ -109,5 +113,5 @@ def create_abstract_instance_method(name)
end
end

end # module ClassMethods
end # module AbstractMethodDeclarations
end # module AbstractType
20 changes: 20 additions & 0 deletions spec/shared/create_new_method_shared_spec.rb
@@ -0,0 +1,20 @@
# encoding: utf-8

shared_examples 'AbstractType.create_new_method' do
context 'called on a subclass' do
let(:object) { Class.new(abstract_type) }

it { should be_instance_of(object) }
end

context 'called on the class' do
let(:object) { abstract_type }

specify do
expect { subject }.to raise_error(
NotImplementedError,
"#{object} is an abstract type"
)
end
end
end
Expand Up @@ -2,7 +2,7 @@

require 'spec_helper'

describe AbstractType::ClassMethods, '#abstract_method' do
describe AbstractType::AbstractMethodDeclarations, '#abstract_method' do
subject { object.abstract_method(:some_method) }

let(:object) { Class.new { include AbstractType } }
Expand Down
Expand Up @@ -2,7 +2,8 @@

require 'spec_helper'

describe AbstractType::ClassMethods, '#abstract_singleton_method' do
describe AbstractType::AbstractMethodDeclarations,
'#abstract_singleton_method' do
subject { object.abstract_singleton_method(:some_method) }

let(:object) { Class.new { include AbstractType } }
Expand Down
Expand Up @@ -9,9 +9,17 @@
let(:klass) { Class.new }

it 'extends the klass' do
expect(klass.singleton_class).to_not include(described_class::ClassMethods)
expect(klass.singleton_class)
.to_not include(described_class::AbstractMethodDeclarations)
klass.send(:include, subject)
expect(klass.singleton_class).to include(described_class::ClassMethods)
expect(klass.singleton_class)
.to include(described_class::AbstractMethodDeclarations)
end

it 'overrides the new singleton method' do
expect(klass.method(:new).owner).to eq(Class)
klass.send(:include, subject)
expect(klass.method(:new).owner).to eq(klass.singleton_class)
end

it 'delegates to the ancestor' do
Expand Down
59 changes: 0 additions & 59 deletions spec/unit/abstract_type/class_methods/new_spec.rb

This file was deleted.

54 changes: 54 additions & 0 deletions spec/unit/abstract_type/module_methods/create_new_method_spec.rb
@@ -0,0 +1,54 @@
# encoding: utf-8

require 'spec_helper'

describe AbstractType, '.create_new_method' do
context 'with arguments' do
subject { object.new(:foo) }

let(:abstract_type) do
Class.new do
include AbstractType

def initialize(foo)
@foo = foo
end
end
end

it_behaves_like 'AbstractType.create_new_method'
end

context 'with a block' do
subject { object.new(:foo) { nil } }

let(:abstract_type) do
Class.new do
include AbstractType

def initialize(foo)
@foo = foo
yield
end
end
end

it_behaves_like 'AbstractType.create_new_method'
end

context 'without arguments' do
subject { object.new }

let(:abstract_type) { Class.new { include AbstractType } }

it_behaves_like 'AbstractType.create_new_method'
end

context 'on an class that doesn\'t have Object as its superclass' do
subject { object.new }

let(:abstract_type) { Class.new(RuntimeError) { include AbstractType } }

it_behaves_like 'AbstractType.create_new_method'
end
end

0 comments on commit 9bfabdb

Please sign in to comment.