1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
|
require 'spec_helper'
Hashie::Hash.class_eval do
def self.inherited(klass)
klass.instance_variable_set('@inheritance_test', true)
end
end
class DashTest < Hashie::Dash
property :first_name, :required => true
property :email
property :count, :default => 0
end
class DashNoRequiredTest < Hashie::Dash
property :first_name
property :email
property :count, :default => 0
end
class Subclassed < DashTest
property :last_name, :required => true
end
class DashDefaultTest < Hashie::Dash
property :aliases, :default => ["Snake"]
end
class DeferredTest < Hashie::Dash
property :created_at, :default => Proc.new { Time.now }
end
describe DashTest do
subject { DashTest.new(:first_name => 'Bob', :email => 'bob@example.com') }
it('subclasses Hashie::Hash') { should respond_to(:to_mash) }
its(:to_s) { should == '#<DashTest count=0 email="bob@example.com" first_name="Bob">' }
it 'lists all set properties in inspect' do
subject.first_name = 'Bob'
subject.email = 'bob@example.com'
subject.inspect.should == '#<DashTest count=0 email="bob@example.com" first_name="Bob">'
end
its(:count) { should be_zero }
it { should respond_to(:first_name) }
it { should respond_to(:first_name=) }
it { should_not respond_to(:nonexistent) }
it 'errors out for a non-existent property' do
lambda { subject['nonexistent'] }.should raise_error(NoMethodError)
end
it 'errors out when attempting to set a required property to nil' do
lambda { subject.first_name = nil }.should raise_error(ArgumentError)
end
context 'writing to properties' do
it 'fails writing a required property to nil' do
lambda { subject.first_name = nil }.should raise_error(ArgumentError)
end
it 'fails writing a required property to nil using []=' do
lambda { subject['first_name'] = nil }.should raise_error(ArgumentError)
end
it 'fails writing to a non-existent property using []=' do
lambda { subject['nonexistent'] = 123 }.should raise_error(NoMethodError)
end
it 'works for an existing property using []=' do
subject['first_name'] = 'Bob'
subject['first_name'].should == 'Bob'
subject[:first_name].should == 'Bob'
end
it 'works for an existing property using a method call' do
subject.first_name = 'Franklin'
subject.first_name.should == 'Franklin'
end
end
context 'reading from properties' do
it 'fails reading from a non-existent property using []' do
lambda { subject['nonexistent'] }.should raise_error(NoMethodError)
end
it "should be able to retrieve properties through blocks" do
subject["first_name"] = "Aiden"
value = nil
subject.[]("first_name") { |v| value = v }
value.should == "Aiden"
end
it "should be able to retrieve properties through blocks with method calls" do
subject["first_name"] = "Frodo"
value = nil
subject.first_name { |v| value = v }
value.should == "Frodo"
end
end
context 'reading from deferred properties' do
it 'should evaluate proc after initial read' do
DeferredTest.new['created_at'].should be_instance_of(Time)
end
it "should not evalute proc after subsequent reads" do
deferred = DeferredTest.new
deferred['created_at'].object_id.should == deferred['created_at'].object_id
end
end
describe '.new' do
it 'fails with non-existent properties' do
lambda { described_class.new(:bork => '') }.should raise_error(NoMethodError)
end
it 'should set properties that it is able to' do
obj = described_class.new :first_name => 'Michael'
obj.first_name.should == 'Michael'
end
it 'accepts nil' do
lambda { DashNoRequiredTest.new(nil) }.should_not raise_error
end
it 'accepts block to define a global default' do
obj = described_class.new { |hash, key| key.to_s.upcase }
obj.first_name.should == 'FIRST_NAME'
obj.count.should be_zero
end
it "fails when required values are missing" do
expect { DashTest.new }.to raise_error(ArgumentError)
end
it "does not overwrite default values" do
obj1 = DashDefaultTest.new
obj1.aliases << "El Rey"
obj2 = DashDefaultTest.new
obj2.aliases.should_not include "El Rey"
end
end
describe 'properties' do
it 'lists defined properties' do
described_class.properties.should == Set.new([:first_name, :email, :count])
end
it 'checks if a property exists' do
described_class.property?('first_name').should be_true
described_class.property?(:first_name).should be_true
end
it 'checks if a property is required' do
described_class.required?('first_name').should be_true
described_class.required?(:first_name).should be_true
end
it 'doesnt include property from subclass' do
described_class.property?(:last_name).should be_false
end
it 'lists declared defaults' do
described_class.defaults.should == { :count => 0 }
end
end
describe '#replace' do
before { subject.replace(:first_name => "Cain") }
it 'return self' do
subject.replace(:email => "bar").to_hash.
should == {"email" => "bar", "count" => 0}
end
it 'sets all specified keys to their corresponding values' do
subject.first_name.should == "Cain"
end
it 'leaves only specified keys and keys with default values' do
subject.keys.sort.should == ['count', 'first_name']
subject.email.should be_nil
subject.count.should == 0
end
context 'when replacing keys with default values' do
before { subject.replace(:count => 3) }
it 'sets all specified keys to their corresponding values' do
subject.count.should == 3
end
end
end
end
describe Hashie::Dash, 'inheritance' do
before do
@top = Class.new(Hashie::Dash)
@middle = Class.new(@top)
@bottom = Class.new(@middle)
end
it 'reports empty properties when nothing defined' do
@top.properties.should be_empty
@top.defaults.should be_empty
end
it 'inherits properties downwards' do
@top.property :echo
@middle.properties.should include(:echo)
@bottom.properties.should include(:echo)
end
it 'doesnt inherit properties upwards' do
@middle.property :echo
@top.properties.should_not include(:echo)
@bottom.properties.should include(:echo)
end
it 'allows overriding a default on an existing property' do
@top.property :echo
@middle.property :echo, :default => 123
@bottom.properties.to_a.should == [:echo]
@bottom.new.echo.should == 123
end
it 'allows clearing an existing default' do
@top.property :echo
@middle.property :echo, :default => 123
@bottom.property :echo
@bottom.properties.to_a.should == [:echo]
@bottom.new.echo.should be_nil
end
it 'should allow nil defaults' do
@bottom.property :echo, :default => nil
@bottom.new.should have_key('echo')
end
end
describe Subclassed do
subject { Subclassed.new(:first_name => 'Bob', :last_name => 'McNob', :email => 'bob@example.com') }
its(:count) { should be_zero }
it { should respond_to(:first_name) }
it { should respond_to(:first_name=) }
it { should respond_to(:last_name) }
it { should respond_to(:last_name=) }
it 'has one additional property' do
described_class.property?(:last_name).should be_true
end
it "didn't override superclass inheritance logic" do
described_class.instance_variable_get('@inheritance_test').should be_true
end
end
|