2018-03-04 10:09:32 -05:00
|
|
|
require_relative '../../spec_helper'
|
|
|
|
require_relative 'fixtures/classes'
|
2017-05-07 08:04:49 -04:00
|
|
|
|
|
|
|
describe "Struct.new" do
|
|
|
|
it "creates a constant in Struct namespace with string as first argument" do
|
|
|
|
struct = Struct.new('Animal', :name, :legs, :eyeballs)
|
|
|
|
struct.should == Struct::Animal
|
|
|
|
struct.name.should == "Struct::Animal"
|
|
|
|
end
|
|
|
|
|
|
|
|
it "overwrites previously defined constants with string as first argument" do
|
|
|
|
first = Struct.new('Person', :height, :weight)
|
|
|
|
first.should == Struct::Person
|
|
|
|
|
|
|
|
second = nil
|
2019-07-27 06:40:09 -04:00
|
|
|
-> {
|
2017-05-07 08:04:49 -04:00
|
|
|
second = Struct.new('Person', :hair, :sex)
|
2020-02-28 13:07:17 -05:00
|
|
|
}.should complain(/constant/)
|
2017-05-07 08:04:49 -04:00
|
|
|
second.should == Struct::Person
|
|
|
|
|
|
|
|
first.members.should_not == second.members
|
|
|
|
end
|
|
|
|
|
|
|
|
it "calls to_str on its first argument (constant name)" do
|
|
|
|
obj = mock('Foo')
|
|
|
|
def obj.to_str() "Foo" end
|
|
|
|
struct = Struct.new(obj)
|
|
|
|
struct.should == Struct::Foo
|
|
|
|
struct.name.should == "Struct::Foo"
|
|
|
|
end
|
|
|
|
|
|
|
|
it "creates a new anonymous class with nil first argument" do
|
|
|
|
struct = Struct.new(nil, :foo)
|
|
|
|
struct.new("bar").foo.should == "bar"
|
|
|
|
struct.should be_kind_of(Class)
|
|
|
|
struct.name.should be_nil
|
|
|
|
end
|
|
|
|
|
|
|
|
it "creates a new anonymous class with symbol arguments" do
|
|
|
|
struct = Struct.new(:make, :model)
|
|
|
|
struct.should be_kind_of(Class)
|
|
|
|
struct.name.should == nil
|
|
|
|
end
|
|
|
|
|
|
|
|
it "does not create a constant with symbol as first argument" do
|
|
|
|
Struct.new(:Animal2, :name, :legs, :eyeballs)
|
|
|
|
Struct.const_defined?("Animal2").should be_false
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
it "fails with invalid constant name as first argument" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { Struct.new('animal', :name, :legs, :eyeballs) }.should raise_error(NameError)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "raises a TypeError if object doesn't respond to to_sym" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { Struct.new(:animal, mock('giraffe')) }.should raise_error(TypeError)
|
|
|
|
-> { Struct.new(:animal, 1.0) }.should raise_error(TypeError)
|
|
|
|
-> { Struct.new(:animal, Time.now) }.should raise_error(TypeError)
|
|
|
|
-> { Struct.new(:animal, Class) }.should raise_error(TypeError)
|
|
|
|
-> { Struct.new(:animal, nil) }.should raise_error(TypeError)
|
|
|
|
-> { Struct.new(:animal, true) }.should raise_error(TypeError)
|
|
|
|
-> { Struct.new(:animal, ['chris', 'evan']) }.should raise_error(TypeError)
|
2017-12-15 12:44:37 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
ruby_version_is ""..."2.5" do
|
|
|
|
it "raises a TypeError if an argument is a Hash" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { Struct.new(:animal, { name: 'chris' }) }.should raise_error(TypeError)
|
2017-12-15 12:44:37 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
ruby_version_is "2.5" do
|
|
|
|
it "raises a ArgumentError if passed a Hash with an unknown key" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { Struct.new(:animal, { name: 'chris' }) }.should raise_error(ArgumentError)
|
2017-12-15 12:44:37 -05:00
|
|
|
end
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
2019-11-30 15:26:52 -05:00
|
|
|
it "raises ArgumentError when there is a duplicate member" do
|
|
|
|
-> { Struct.new(:foo, :foo) }.should raise_error(ArgumentError, "duplicate member: foo")
|
|
|
|
end
|
|
|
|
|
2017-05-07 08:04:49 -04:00
|
|
|
it "raises a TypeError if object is not a Symbol" do
|
|
|
|
obj = mock(':ruby')
|
|
|
|
def obj.to_sym() :ruby end
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { Struct.new(:animal, obj) }.should raise_error(TypeError)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "processes passed block with instance_eval" do
|
|
|
|
klass = Struct.new(:something) { @something_else = 'something else entirely!' }
|
|
|
|
klass.instance_variables.should include(:@something_else)
|
|
|
|
end
|
|
|
|
|
|
|
|
context "with a block" do
|
|
|
|
it "allows class to be modified via the block" do
|
|
|
|
klass = Struct.new(:version) do
|
|
|
|
def platform
|
|
|
|
:ruby
|
|
|
|
end
|
|
|
|
end
|
|
|
|
instance = klass.new('2.2')
|
|
|
|
|
|
|
|
instance.version.should == '2.2'
|
|
|
|
instance.platform.should == :ruby
|
|
|
|
end
|
|
|
|
|
|
|
|
it "passes same struct class to the block" do
|
|
|
|
given = nil
|
|
|
|
klass = Struct.new(:attr) do |block_parameter|
|
|
|
|
given = block_parameter
|
|
|
|
end
|
|
|
|
klass.should equal(given)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "on subclasses" do
|
|
|
|
it "creates a constant in subclass' namespace" do
|
|
|
|
struct = StructClasses::Apple.new('Computer', :size)
|
|
|
|
struct.should == StructClasses::Apple::Computer
|
|
|
|
end
|
|
|
|
|
|
|
|
it "creates an instance" do
|
|
|
|
StructClasses::Ruby.new.kind_of?(StructClasses::Ruby).should == true
|
|
|
|
end
|
|
|
|
|
|
|
|
it "creates reader methods" do
|
|
|
|
StructClasses::Ruby.new.should have_method(:version)
|
|
|
|
StructClasses::Ruby.new.should have_method(:platform)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "creates writer methods" do
|
|
|
|
StructClasses::Ruby.new.should have_method(:version=)
|
|
|
|
StructClasses::Ruby.new.should have_method(:platform=)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "fails with too many arguments" do
|
2019-07-27 06:40:09 -04:00
|
|
|
-> { StructClasses::Ruby.new('2.0', 'i686', true) }.should raise_error(ArgumentError)
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
2018-11-27 15:38:57 -05:00
|
|
|
|
|
|
|
it "passes a hash as a normal argument" do
|
|
|
|
type = Struct.new(:args)
|
|
|
|
|
|
|
|
obj = type.new(keyword: :arg)
|
|
|
|
obj2 = type.new(*[{keyword: :arg}])
|
|
|
|
|
|
|
|
obj.should == obj2
|
|
|
|
obj.args.should == {keyword: :arg}
|
|
|
|
obj2.args.should == {keyword: :arg}
|
|
|
|
end
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|
2017-12-27 11:12:47 -05:00
|
|
|
|
|
|
|
ruby_version_is "2.5" do
|
|
|
|
context "keyword_init: true option" do
|
|
|
|
before :all do
|
|
|
|
@struct_with_kwa = Struct.new(:name, :legs, keyword_init: true)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "creates a class that accepts keyword arguments to initialize" do
|
|
|
|
obj = @struct_with_kwa.new(name: "elefant", legs: 4)
|
|
|
|
obj.name.should == "elefant"
|
|
|
|
obj.legs.should == 4
|
|
|
|
end
|
|
|
|
|
2019-11-30 15:26:52 -05:00
|
|
|
it "raises when there is a duplicate member" do
|
|
|
|
-> { Struct.new(:foo, :foo, keyword_init: true) }.should raise_error(ArgumentError, "duplicate member: foo")
|
|
|
|
end
|
|
|
|
|
2017-12-27 11:12:47 -05:00
|
|
|
describe "new class instantiation" do
|
|
|
|
it "accepts arguments as hash as well" do
|
|
|
|
obj = @struct_with_kwa.new({name: "elefant", legs: 4})
|
|
|
|
obj.name.should == "elefant"
|
|
|
|
obj.legs.should == 4
|
|
|
|
end
|
|
|
|
|
2019-11-30 15:26:52 -05:00
|
|
|
it "allows missing arguments" do
|
|
|
|
obj = @struct_with_kwa.new(name: "elefant")
|
|
|
|
obj.name.should == "elefant"
|
|
|
|
obj.legs.should be_nil
|
|
|
|
end
|
|
|
|
|
|
|
|
it "allows no arguments" do
|
|
|
|
obj = @struct_with_kwa.new
|
|
|
|
obj.name.should be_nil
|
|
|
|
obj.legs.should be_nil
|
|
|
|
end
|
|
|
|
|
2017-12-27 11:12:47 -05:00
|
|
|
it "raises ArgumentError when passed not declared keyword argument" do
|
|
|
|
-> {
|
|
|
|
@struct_with_kwa.new(name: "elefant", legs: 4, foo: "bar")
|
|
|
|
}.should raise_error(ArgumentError, /unknown keywords: foo/)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "raises ArgumentError when passed a list of arguments" do
|
|
|
|
-> {
|
|
|
|
@struct_with_kwa.new("elefant", 4)
|
|
|
|
}.should raise_error(ArgumentError, /wrong number of arguments/)
|
|
|
|
end
|
2018-11-27 15:38:57 -05:00
|
|
|
|
|
|
|
it "raises ArgumentError when passed a single non-hash argument" do
|
|
|
|
-> {
|
|
|
|
@struct_with_kwa.new("elefant")
|
|
|
|
}.should raise_error(ArgumentError, /wrong number of arguments/)
|
|
|
|
end
|
2017-12-27 11:12:47 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "keyword_init: false option" do
|
2019-11-30 15:26:52 -05:00
|
|
|
before :all do
|
|
|
|
@struct_without_kwa = Struct.new(:name, :legs, keyword_init: false)
|
|
|
|
end
|
|
|
|
|
2017-12-27 11:12:47 -05:00
|
|
|
it "behaves like it does without :keyword_init option" do
|
|
|
|
obj = @struct_without_kwa.new("elefant", 4)
|
|
|
|
obj.name.should == "elefant"
|
|
|
|
obj.legs.should == 4
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2017-05-07 08:04:49 -04:00
|
|
|
end
|