summaryrefslogtreecommitdiff
path: root/spec/hashie/extensions/coercion_spec.rb
blob: 3781b23458c74af2951771fd4d9a583e92eeac48 (plain)
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
require 'spec_helper'

describe Hashie::Extensions::Coercion do
  class Initializable
    attr_reader :coerced, :value

    def initialize(obj, coerced = false)
      @coerced = coerced
      @value = obj.class.to_s
    end

    def coerced?
      !!@coerced
    end
  end

  class Coercable < Initializable
    def self.coerce(obj)
      new(obj, true)
    end
  end

  before(:each) do
    class ExampleCoercableHash < Hash
      include Hashie::Extensions::Coercion
      include Hashie::Extensions::MergeInitializer
    end
  end

  subject { ExampleCoercableHash }

  let(:instance) { subject.new }

  describe '#coerce_key' do
    it { subject.should be_respond_to(:coerce_key) }

    it 'runs through coerce on a specified key' do
      subject.coerce_key :foo, Coercable

      instance[:foo] = 'bar'
      instance[:foo].should be_coerced
    end

    it 'supports an array of keys' do
      subject.coerce_keys :foo, :bar, Coercable

      instance[:foo] = 'bar'
      instance[:bar] = 'bax'
      instance[:foo].should be_coerced
      instance[:bar].should be_coerced
    end

    it 'calls #new if no coerce method is available' do
      subject.coerce_key :foo, Initializable

      instance[:foo] = 'bar'
      instance[:foo].value.should eq 'String'
      instance[:foo].should_not be_coerced
    end

    it 'coerces when the merge initializer is used' do
      subject.coerce_key :foo, Coercable
      instance = subject.new(foo: 'bar')

      instance[:foo].should be_coerced
    end

    context 'when #replace is used' do
      before { subject.coerce_key :foo, :bar, Coercable }

      let(:instance) do
        subject.new(foo: 'bar').replace(foo: 'foz', bar: 'baz', hi: 'bye')
      end

      it 'coerces relevant keys' do
        instance[:foo].should be_coerced
        instance[:bar].should be_coerced
        instance[:hi].should_not respond_to(:coerced?)
      end

      it 'sets correct values' do
        instance[:hi].should eq 'bye'
      end
    end

    context 'when used with a Mash' do
      class UserMash < Hashie::Mash
      end
      class TweetMash < Hashie::Mash
        include Hashie::Extensions::Coercion
        coerce_key :user, UserMash
      end

      it 'coerces with instance initialization' do
        tweet = TweetMash.new(user: { email: 'foo@bar.com' })
        tweet[:user].should be_a(UserMash)
      end

      it 'coerces when setting with attribute style' do
        tweet = TweetMash.new
        tweet.user = { email: 'foo@bar.com' }
        tweet[:user].should be_a(UserMash)
      end

      it 'coerces when setting with string index' do
        tweet = TweetMash.new
        tweet['user'] = { email: 'foo@bar.com' }
        tweet[:user].should be_a(UserMash)
      end

      it 'coerces when setting with symbol index' do
        tweet = TweetMash.new
        tweet[:user] = { email: 'foo@bar.com' }
        tweet[:user].should be_a(UserMash)
      end
    end
  end

  describe '#coerce_value' do
    context 'with strict: true' do
      it 'coerces any value of the exact right class' do
        subject.coerce_value String, Coercable

        instance[:foo] = 'bar'
        instance[:bar] = 'bax'
        instance[:hi]  = :bye
        instance[:foo].should be_coerced
        instance[:bar].should be_coerced
        instance[:hi].should_not respond_to(:coerced?)
      end

      it 'coerces values from a #replace call' do
        subject.coerce_value String, Coercable

        instance[:foo] = :bar
        instance.replace(foo: 'bar', bar: 'bax')
        instance[:foo].should be_coerced
        instance[:bar].should be_coerced
      end

      it 'does not coerce superclasses' do
        klass = Class.new(String)
        subject.coerce_value klass, Coercable

        instance[:foo] = 'bar'
        instance[:foo].should_not be_kind_of(Coercable)
        instance[:foo] = klass.new
        instance[:foo].should be_kind_of(Coercable)
      end
    end
  end

  after(:each) do
    Object.send(:remove_const, :ExampleCoercableHash)
  end
end