octiron 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ # Always start SimpleCov
2
+ require 'simplecov'
3
+ SimpleCov.start do
4
+ add_filter 'spec'
5
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ require_relative '../lib/octiron/support/camel_case'
3
+
4
+ class Tester
5
+ include ::Octiron::Support::CamelCase
6
+ end
7
+
8
+ describe ::Octiron::Support::CamelCase do
9
+ before do
10
+ @tester = Tester.new
11
+ end
12
+
13
+ it "capitalizes a single word" do
14
+ expect(@tester.camel_case('foo')).to eql 'Foo'
15
+ end
16
+
17
+ it "capitalizes letters in underscore separated words" do
18
+ expect(@tester.camel_case('foo_bar')).to eql 'FooBar'
19
+ end
20
+
21
+ it "handles symbols" do
22
+ expect(@tester.camel_case(:foo_bar)).to eql 'FooBar'
23
+ end
24
+ end
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+ require_relative '../lib/octiron/support/constantize'
3
+
4
+ class Tester
5
+ include ::Octiron::Support::Constantize
6
+ end
7
+
8
+ class Test
9
+ end
10
+
11
+ module TestModule
12
+ class InnerTest
13
+ end
14
+ end
15
+
16
+ class A
17
+ class A
18
+ end
19
+ end
20
+
21
+ class B < A
22
+ class B
23
+ end
24
+ end
25
+
26
+ describe ::Octiron::Support::Constantize do
27
+ before do
28
+ @tester = Tester.new
29
+ end
30
+
31
+ it "throws with an empty path (i.e. '::')" do
32
+ expect do
33
+ @tester.constantize('::')
34
+ end.to raise_error(NameError)
35
+ end
36
+
37
+ it "resolves a constant in the global namespace" do
38
+ expect(@tester.constantize('Test')).to eql Test
39
+ end
40
+
41
+ it "accepts absolute paths (i.e. starting with '::')" do
42
+ expect(@tester.constantize('::Test')).to eql Test
43
+ end
44
+
45
+ it "accepts nested names" do
46
+ expect(@tester.constantize('TestModule::InnerTest')).to \
47
+ eql TestModule::InnerTest
48
+ end
49
+
50
+ it "performs lookup in ancestors" do
51
+ expect(@tester.constantize('A::A')).to eql A::A
52
+
53
+ expect do
54
+ @tester.constantize('A::does_not_exist')
55
+ end.to raise_error(NameError)
56
+
57
+ expect(@tester.constantize('B::B')).to eql B::B
58
+ expect(@tester.constantize('B::A')).to eql A::A
59
+
60
+ expect do
61
+ @tester.constantize('B::does_not_exist')
62
+ end.to raise_error(NameError)
63
+ end
64
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+ require_relative '../lib/octiron/support/identifiers'
3
+
4
+ class Tester
5
+ include ::Octiron::Support::Identifiers
6
+
7
+ def initialize(*_)
8
+ @default_namespace = 'Octiron::Support'
9
+ end
10
+ end
11
+
12
+ class Test
13
+ end
14
+
15
+ module TestModule
16
+ class InnerTest
17
+ end
18
+ end
19
+
20
+ class A
21
+ class A
22
+ end
23
+ end
24
+
25
+ class B < A
26
+ class B
27
+ end
28
+ end
29
+
30
+ describe ::Octiron::Support::Identifiers do
31
+ before do
32
+ @tester = Tester.new
33
+ end
34
+
35
+ it "throws with an empty path (i.e. '::')" do
36
+ expect do
37
+ @tester.identify('::')
38
+ end.to raise_error(NameError)
39
+
40
+ expect do
41
+ @tester.identify('')
42
+ end.to raise_error(NameError)
43
+
44
+ expect do
45
+ @tester.identify(nil)
46
+ end.to raise_error(NameError)
47
+ end
48
+
49
+ it "returns the name of a Class" do
50
+ expect(@tester.identify(Test)).to eql 'Test'
51
+ expect(@tester.identify(A)).to eql 'A'
52
+ expect(@tester.identify(B)).to eql 'B'
53
+ end
54
+
55
+ it "returns Hashes untouched" do
56
+ test_hash = {}
57
+ expect(@tester.identify(test_hash)).to eql test_hash
58
+ expect(@tester.identify(test_hash).object_id).to eql test_hash.object_id
59
+ end
60
+
61
+ it "resolves strings to constant names" do
62
+ expect(@tester.identify('Octiron::Support::Identifiers')).to eql \
63
+ 'Octiron::Support::Identifiers'
64
+ end
65
+
66
+ it "attempts to resolve anything else as constants in the default namespace" do
67
+ expect(@tester.identify(:identifiers)).to eql \
68
+ 'Octiron::Support::Identifiers'
69
+ end
70
+ end
@@ -0,0 +1,311 @@
1
+ require 'spec_helper'
2
+ require_relative '../lib/octiron/transmogrifiers/registry'
3
+
4
+ class Test1
5
+ end
6
+
7
+ class Test2
8
+ end
9
+
10
+ class Test3
11
+ end
12
+
13
+ class Transmogrifier
14
+ attr_reader :invoked
15
+ def initialize
16
+ @invoked = 0
17
+ end
18
+
19
+ def call(_)
20
+ @invoked += 1
21
+ end
22
+ end
23
+
24
+ class HashTransmogrifier < Transmogrifier
25
+ def initialize(bad = false)
26
+ super()
27
+ @bad = bad
28
+ end
29
+
30
+ def call(from)
31
+ super
32
+
33
+ if @bad
34
+ return {}
35
+ end
36
+
37
+ return {
38
+ a: from[:a],
39
+ b_c: from[:b][:c],
40
+ }
41
+ end
42
+ end
43
+
44
+ class Test1To2Transmogrifier < Transmogrifier
45
+ def call(from)
46
+ super
47
+ return Test2.new
48
+ end
49
+ end
50
+
51
+ class Test2To3Transmogrifier < Transmogrifier
52
+ def call(from)
53
+ super
54
+ return Test3.new
55
+ end
56
+ end
57
+
58
+ class Test1To3Transmogrifier < Transmogrifier
59
+ def call(from)
60
+ super
61
+ return Test3.new
62
+ end
63
+ end
64
+
65
+ describe Octiron::Transmogrifiers::Registry do
66
+ describe "construction" do
67
+ it "can be constructed without a default namespace" do
68
+ reg = nil
69
+ expect do
70
+ reg = ::Octiron::Transmogrifiers::Registry.new
71
+ end.not_to raise_error
72
+
73
+ expect(reg.default_namespace).to eql 'Octiron::Transmogrifiers'
74
+ end
75
+
76
+ it "can be constructed with a namespace" do
77
+ reg = nil
78
+ expect do
79
+ reg = ::Octiron::Transmogrifiers::Registry.new(::Octiron::Transmogrifiers)
80
+ end.not_to raise_error
81
+
82
+ expect(reg.default_namespace).to eql 'Octiron::Transmogrifiers'
83
+ end
84
+ end
85
+
86
+ describe "registration" do
87
+ before :each do
88
+ @reg = ::Octiron::Transmogrifiers::Registry.new
89
+ end
90
+
91
+ it "can register a transmogrifier object" do
92
+ expect do
93
+ @reg.register(Test1, Test2, false, Transmogrifier.new)
94
+ end.not_to raise_error
95
+ end
96
+
97
+ it "throws when registering a transmogrifier for the same pair twice" do
98
+ expect do
99
+ @reg.register(Test1, Test2, false, Transmogrifier.new)
100
+ end.not_to raise_error
101
+
102
+ expect do
103
+ @reg.register(Test1, Test2, false, Transmogrifier.new)
104
+ end.to raise_error(ArgumentError)
105
+ end
106
+
107
+ it "can overwrite transmogrifiers" do
108
+ expect do
109
+ @reg.register(Test1, Test2, false, Transmogrifier.new)
110
+ end.not_to raise_error
111
+
112
+ expect do
113
+ @reg.register(Test1, Test2, true, Transmogrifier.new)
114
+ end.not_to raise_error
115
+ end
116
+
117
+ it "can register transmogrifier procs" do
118
+ expect do
119
+ @reg.register(Test1, Test2) do |_|
120
+ end
121
+ end.not_to raise_error
122
+ end
123
+
124
+ it "raises if no transmogrifier is given" do
125
+ expect do
126
+ @reg.register(Test1, Test2)
127
+ end.to raise_error(ArgumentError)
128
+
129
+ expect do
130
+ @reg.register(Test1, Test2, false)
131
+ end.to raise_error(ArgumentError)
132
+ end
133
+
134
+ it "can deregister a transmogrifier" do
135
+ expect do
136
+ @reg.register(Test1, Test2) do |_|
137
+ end
138
+ end.not_to raise_error
139
+
140
+ # First time, there is a transmogrifier
141
+ expect do
142
+ @reg.deregister(Test1, Test2)
143
+ end.not_to raise_error
144
+
145
+ # Second time, there is none - it still shouldn't fail
146
+ expect do
147
+ @reg.deregister(Test1, Test2)
148
+ end.not_to raise_error
149
+ end
150
+ end
151
+
152
+ describe "register argument validation" do
153
+ before :each do
154
+ @reg = ::Octiron::Transmogrifiers::Registry.new
155
+ end
156
+
157
+ it "accepts string names" do
158
+ expect do
159
+ @reg.register('Test1', 'Test2', false, Transmogrifier.new)
160
+ end.not_to raise_error
161
+ end
162
+
163
+ it "accepts symbol names" do
164
+ expect do
165
+ @reg.register(:test1, :test2, false, Transmogrifier.new)
166
+ end.not_to raise_error
167
+ end
168
+
169
+ it "accepts hash prototypes" do
170
+ proto1 = {
171
+ a: nil,
172
+ b: {
173
+ c: 42,
174
+ },
175
+ }
176
+ proto2 = {
177
+ a: nil,
178
+ b_c: nil,
179
+ }
180
+
181
+ expect do
182
+ @reg.register(proto1, proto2, false, Transmogrifier.new)
183
+ end.not_to raise_error
184
+ end
185
+ end
186
+
187
+ describe "transmogrification" do
188
+ before :each do
189
+ @reg = ::Octiron::Transmogrifiers::Registry.new
190
+ @trans1to2 = Test1To2Transmogrifier.new
191
+ @trans2to3 = Test2To3Transmogrifier.new
192
+ @reg.register(Test1, Test2, false, @trans1to2)
193
+ @reg.register(Test2, Test3, false, @trans2to3)
194
+ end
195
+
196
+ it "can transmogrify with a directly registered transmogrifier" do
197
+ result = nil
198
+
199
+ expect do
200
+ result = @reg.transmogrify(Test1.new, Test2)
201
+ end.not_to raise_error
202
+
203
+ expect(result.class).to eql Test2
204
+
205
+ expect(@trans1to2.invoked).to eql 1
206
+ expect(@trans2to3.invoked).to eql 0
207
+ end
208
+
209
+ it "can transmogrify with indirectly registered transmogrifiers" do
210
+ result = nil
211
+
212
+ expect do
213
+ result = @reg.transmogrify(Test1.new, Test3)
214
+ end.not_to raise_error
215
+
216
+ expect(result.class).to eql Test3
217
+
218
+ expect(@trans1to2.invoked).to eql 1
219
+ expect(@trans2to3.invoked).to eql 1
220
+ end
221
+
222
+ it "chooses the shortest transmogrification path" do
223
+ result = nil
224
+
225
+ direct = Test1To3Transmogrifier.new
226
+ @reg.register(Test1, Test3, false, direct)
227
+
228
+ expect do
229
+ result = @reg.transmogrify(Test1.new, Test3)
230
+ end.not_to raise_error
231
+
232
+ expect(result.class).to eql Test3
233
+
234
+ expect(@trans1to2.invoked).to eql 0
235
+ expect(@trans2to3.invoked).to eql 0
236
+ expect(direct.invoked).to eql 1
237
+ end
238
+
239
+ it "fails if no transmogrifier is found" do
240
+ expect do
241
+ @reg.transmogrify(Test1.new, Hash)
242
+ end.to raise_error(ArgumentError)
243
+ end
244
+
245
+ it "fails if a transmogrifier misbehaves" do
246
+ # Register the wrong 'direct' transmogrifier that will then be chosen
247
+ direct = Test1To2Transmogrifier.new
248
+ @reg.register(Test1, Test3, false, direct)
249
+
250
+ expect do
251
+ @reg.transmogrify(Test1.new, Test3)
252
+ end.to raise_error(RuntimeError)
253
+ end
254
+
255
+ it "transmogrifies hashes" do
256
+ proto1 = {
257
+ a: nil,
258
+ b: {
259
+ c: 42,
260
+ },
261
+ }
262
+ proto2 = {
263
+ a: nil,
264
+ b_c: nil,
265
+ }
266
+
267
+ @reg.register(proto1, proto2, false, HashTransmogrifier.new)
268
+
269
+ from = {
270
+ a: 'foo',
271
+ b: {
272
+ c: 42,
273
+ },
274
+ }
275
+
276
+ result = nil
277
+ expect do
278
+ result = @reg.transmogrify(from, proto2)
279
+ end.not_to raise_error
280
+
281
+ expect(result[:a]).to eql 'foo'
282
+ expect(result[:b_c]).to eql 42
283
+ end
284
+
285
+ it "throws if a hash transmogrifier produces bad results" do
286
+ proto1 = {
287
+ a: nil,
288
+ b: {
289
+ c: 42,
290
+ },
291
+ }
292
+ proto2 = {
293
+ a: nil,
294
+ b_c: nil,
295
+ }
296
+
297
+ @reg.register(proto1, proto2, false, HashTransmogrifier.new(true))
298
+
299
+ from = {
300
+ a: 'foo',
301
+ b: {
302
+ c: 42,
303
+ },
304
+ }
305
+
306
+ expect do
307
+ @reg.transmogrify(from, proto2)
308
+ end.to raise_error(RuntimeError)
309
+ end
310
+ end
311
+ end