My clever co-worker Shane Harvie just blogged about making Ruby constructors protected in a nice way.
Shane, here’s something slightly more terse which might be the new content of your make_constructor_protect.rb file:
class Class def protect_constructor class_eval(%Q[ class < < self protected :new def inherited(klass) klass.class_eval do def self.new(*args); super; end end end end ]) end end
Seems to pass all the tests. So, your party.rb might look like this now (I’ve left the other stuff commented out, and added access to annual_cost just to be sure).
With a little more effort messing around with the Module.protected, I reckon you could make “protected :new” work as a more natural idiomatic approach – the way you originally hoped it might.
Update: not really as some kernel behaviour appears to be suppressed. See comments.
require 'make_constructor_protected'
require 'test/unit'
class Party
# include MakeConstructorProtected
attr_reader :name
protect_constructor
def initialize(name)
@name = name
end
end
class Employee < Party
attr_reader :annual_cost
def initialize(name, id, annual_cost)
super(name)
@id, @annual_cost = id, annual_cost
end
end
class Department < Party
def initialize(name)
super
end
end
class PartyTest < Test::Unit::TestCase
def test_new_raises_no_method_error
assert_raise(NoMethodError) { Party.new("some name") }
end
def test_department_initialize
d = Department.new("name")
assert_equal "name", d.name
end
def test_employee_initialize
e = Employee.new("name", 5, 12)
assert_equal "name", e.name
assert_equal 12, e.annual_cost
end
end