typedocs 0.0.1

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,28 @@
1
+ require 'typedocs/fallback/impl'
2
+
3
+ describe TypedocsFallback do
4
+ it { should_not be_enabled }
5
+ it('do_anything should success'){ subject.do_anything }
6
+ it('do_nothing should success'){ subject.do_nothing }
7
+ describe TypedocsFallback::DSL do
8
+ subject do
9
+ c = Class.new
10
+ c.instance_eval { include TypedocsFallback::DSL }
11
+ c
12
+ end
13
+ describe '#tdoc' do
14
+ it 'should accepts any arguments' do
15
+ subject.instance_eval do
16
+ tdoc
17
+ tdoc "String"
18
+ tdoc "1", "aaa"
19
+ end
20
+ end
21
+ it 'should return null object' do
22
+ subject.instance_eval do
23
+ tdoc('aaa').bbb().ccc(10, 20).ddd
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,4 @@
1
+ require 'typedocs/enable'
2
+ require 'typedocs'
3
+ require 'parslet/rig/rspec'
4
+
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Typedocs.typedef' do
4
+ before(:each) do
5
+ @ns = Module.new
6
+ ::TypedocsSpecSandbox = @ns
7
+ end
8
+ after(:each) do
9
+ Object.instance_eval { remove_const :TypedocsSpecSandbox }
10
+ Typedocs.initialize!
11
+ end
12
+ describe 'spec itself' do
13
+ it('Object::TypeDocsSpecSandBox exists') do
14
+ ::TypedocsSpecSandbox.should_not be_nil
15
+ ::TypedocsSpecSandbox.name.should == 'TypedocsSpecSandbox'
16
+ end
17
+ end
18
+
19
+ describe 'basic usage' do
20
+ before(:each) do
21
+ class @ns::A
22
+ include Typedocs::DSL
23
+ end
24
+ end
25
+ let(:klass) { @ns::A }
26
+ describe 'defining custom type @ConfigHash' do
27
+ before(:each) do
28
+ klass.class_eval do
29
+ tdoc.typedef :@ConfigHash, "{:hoge => Integer}"
30
+ end
31
+ end
32
+ it 'should referable from definede class' do
33
+ klass.class_eval {
34
+ tdoc "@ConfigHash"
35
+ def legal
36
+ {hoge: 10}
37
+ end
38
+ tdoc "@ConfigHash"
39
+ def illegal
40
+ {hoge: 'hoge'}
41
+ end
42
+ }
43
+ klass.new.legal.should == {hoge: 10}
44
+ expect { klass.new.illegal }.to raise_error Typedocs::RetValError
45
+ end
46
+ it 'should referable from inner type' do
47
+ expect {
48
+ class @ns::B
49
+ include Typedocs::DSL
50
+ tdoc "@ConfigHash"
51
+ def illegal; {}; end
52
+ end
53
+ Typedocs.context(@ns::B).defined_type!("@ConfigHash")
54
+ }.to raise_error Typedocs::NoSuchType
55
+ end
56
+ it 'should not referable from other type' do
57
+ class klass::InnerType
58
+ include Typedocs::DSL
59
+ tdoc "@ConfigHash"
60
+ def illegal; {}; end
61
+ end
62
+ expect { klass::InnerType.new.illegal }.to raise_error Typedocs::RetValError
63
+ end
64
+ it 'should not referable from inherited type' do
65
+ expect {
66
+ class @ns::C < klass
67
+ include Typedocs::DSL
68
+ tdoc "@ConfigHash"
69
+ def illegal; {}; end
70
+ end
71
+ Typedocs.context(@ns::C).defined_type!("@ConfigHash")
72
+ }.to raise_error Typedocs::NoSuchType
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe Typedocs::Parser::ASTBuilder do
4
+ def v_h(val)
5
+ {value: val}
6
+ end
7
+ def type_name_h(name)
8
+ {type_name: v_h(name) }
9
+ end
10
+ def named_type_h(type_name)
11
+ {type: type_name_h(type_name)}
12
+ end
13
+ describe 'type' do
14
+ subject { super().type }
15
+ it { should parse('TypeName').as(type_name_h('TypeName')) }
16
+ it { should parse('@DefinedTypeName').as(defined_type_name: {value: 'DefinedTypeName'}) }
17
+ it { should parse('_').as(any: '_') }
18
+ it { should parse('nil').as(nil_value: 'nil') }
19
+ it { should parse('void').as(void: 'void') }
20
+ it { should parse(':symbol_value').as(symbol_value: {value: 'symbol_value'}) }
21
+ it { should parse('"string_value"').as(string_value: {value: 'string_value'})}
22
+ it { should parse("'string'") }
23
+ it { should parse('[TupleType1, TupleType2]').as(tuple: {types: [named_type_h('TupleType1'), named_type_h('TupleType2')]}) }
24
+ it { should parse('[ArrayType...]').as(array: named_type_h('ArrayType')) }
25
+ it { should parse('{KeyType => ValueType}').as(hash_t: {key_t: named_type_h('KeyType'), val_t: named_type_h('ValueType')}) }
26
+ it { should parse('{:a => B}').as(hash_v: {entries: {key_v: {symbol_value: {value: 'a'}}, val_t: named_type_h('B')}, anymore: nil}) }
27
+ it { should parse('{:a => Integer, "b" => String}').as(hash_v: {entries: [{key_v: {symbol_value: {value: 'a'}}, val_t: named_type_h('Integer')}, {key_v: {string_value: {value: 'b'}}, val_t: named_type_h('String')}], anymore: nil}) }
28
+ it { should parse('{:a => Integer, ...}').as(hash_v: {entries: {key_v: {symbol_value: {value: 'a'}}, val_t: named_type_h('Integer')}, anymore: ', ...'}) }
29
+ it { should parse('Type1 | Type2').as([type_name_h('Type1'), type_name_h('Type2')])}
30
+ end
31
+
32
+ describe 'arg_spec' do
33
+ subject { super().arg_spec }
34
+ it { should parse('name').as(name: v_h('name'), type: nil, attr: nil) }
35
+ it { should parse('name:String').as(name: v_h('name'), type: type_name_h('String'), attr: nil) }
36
+ it { should parse('name:String|nil') }
37
+ it { should parse('data:{key:String => value:String}') }
38
+ it { should parse('Integer').as(type: type_name_h('Integer'), attr: nil) }
39
+ it { should parse('?String').as(type: type_name_h('String'), attr: '?') }
40
+ it { should parse('*a:String').as(type: type_name_h('String'), name: {value: 'a'}, attr: '*') }
41
+ it { should parse('*a').as(name: {value: 'a'}, type: nil, attr: '*') }
42
+ end
43
+
44
+ describe 'method_spec' do
45
+ subject { super().method_spec }
46
+ let(:empty_arg_spec) { {arg_specs: [], block_spec: nil, return_spec: nil} }
47
+ it { should parse('').as(method_spec: empty_arg_spec) }
48
+ it { should parse('Integer').as(method_spec: {arg_specs: [], block_spec: nil, return_spec: {type: {type_name: v_h('Integer')}}}) }
49
+ it { should parse('_ -> _') }
50
+ it { should parse('_ ->') }
51
+ it { should parse('& ->').as(method_spec: empty_arg_spec.merge(block_spec: {attr: nil, name: nil})) }
52
+ it { should parse('?&b ->').as(method_spec: empty_arg_spec.merge(block_spec: {attr: '?', name: v_h('b')})) }
53
+ it { should parse('a -> b -> & ->') }
54
+ it { should parse('a -> b -> ?& ->') }
55
+ it { should parse('a -> b -> &callback ->') }
56
+ it { should parse('_ -> Integer || Integer') }
57
+ it { should parse('_ -> _ || _ ->') }
58
+ it { should parse('||').as(method_spec: [empty_arg_spec, empty_arg_spec]) }
59
+ end
60
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe Typedocs::Parser::ObjectBuilder do
4
+ let(:klass) { Class.new }
5
+ let(:parser) { Typedocs::Parser::ASTBuilder.new }
6
+ let(:ts) { Typedocs::TypeSpec }
7
+ subject { Typedocs::Parser::ObjectBuilder.create_builder_for(klass) }
8
+
9
+ def t(parser_rule_name, src, expected_klass)
10
+ parser_rule = parser.public_send(parser_rule_name)
11
+ subject.apply(parser_rule.parse(src)).should be_kind_of(expected_klass)
12
+ end
13
+ def td(parser_rule_name, src, to_source)
14
+ parser_rule = parser.public_send(parser_rule_name)
15
+ obj = subject.apply(parser_rule.parse(src))
16
+ obj.should_not be_kind_of(Hash)
17
+ obj.to_source.should == to_source
18
+ end
19
+ describe 'transform types' do
20
+ it { t(:type, 'Integer', ts::TypeIsA) }
21
+ it { td(:type, '@X', '@X') }
22
+ it { t(:type, '_', ts::Any) }
23
+ it { t(:type, ':a', ts::Value) }
24
+ it { t(:type, '"str"', ts::Value) }
25
+ it { t(:type, '[A...]', ts::Array) }
26
+ it { t(:type, '[A, B]', ts::ArrayAsStruct) }
27
+ it { t(:type, '{A => B}', ts::HashType) }
28
+ describe 'hash_v' do
29
+ subject { super().apply(parser.type.parse('{:a => B}')) }
30
+ it { should be_kind_of(ts::HashValue) }
31
+ its(:to_source) { should == '{:a => B}' }
32
+ end
33
+ end
34
+
35
+ describe 'transform root' do
36
+ it { td(:root, 'A|B', 'A|B') }
37
+ it { td(:root, 'name:String', 'name:String') }
38
+ it { td(:root, 'a -> b', 'a:_ -> b:_') }
39
+ it { td(:root, 'x:A->ret:B || a:A -> b:B -> ret:C', 'x:A -> ret:B || a:A -> b:B -> ret:C') }
40
+ it { td(:root, 'x:X -> ?y -> *Z ->', 'x:X -> ?y:_ -> *Z -> void') }
41
+ it { td(:root, 'a -> ?&b ->', 'a:_ -> ?&b -> void') }
42
+ end
43
+ end
@@ -0,0 +1,598 @@
1
+ load File.join(File.dirname(__FILE__), 'spec_helper.rb')
2
+
3
+ describe Typedocs::Parser do
4
+ def parse(src)
5
+ Typedocs::Parser.new.parse(::Object, src)
6
+ end
7
+ describe 'parsing single validation' do
8
+ def spec_for(src)
9
+ parse(src).retval_spec
10
+ end
11
+ describe 'is-a' do
12
+ subject { spec_for 'Numeric' }
13
+ it { should be_valid(1) }
14
+ it { should_not be_valid('string') }
15
+ end
16
+ describe 'is-a(absolute name)' do
17
+ subject { spec_for '::Numeric' }
18
+ it { should be_valid(1) }
19
+ it { should_not be_valid('string') }
20
+ end
21
+ describe 'is-a(nested name)' do
22
+ subject { spec_for '::Object::Numeric' }
23
+ it { should be_valid(1) }
24
+ it { should_not be_valid('string') }
25
+ end
26
+ describe 'dont care(implicit)' do
27
+ subject { spec_for '' }
28
+ it { should be_valid(1) }
29
+ it { should be_valid(nil) }
30
+ end
31
+ describe 'dont carre(explicit)' do
32
+ subject { spec_for '--' }
33
+ it { should be_valid(1) }
34
+ it { should be_valid(nil) }
35
+ end
36
+ describe 'anything' do
37
+ subject { spec_for '_' }
38
+ it { should be_valid(1) }
39
+ it { should be_valid(nil) }
40
+ end
41
+ describe 'Array(as struct)' do
42
+ subject { spec_for '[String, Symbol]' }
43
+ it { should be_valid(['hoge', :foo]) }
44
+ it { should_not be_valid(['hoge', 'hoge']) }
45
+ it { should_not be_valid([nil, :foo]) }
46
+ it { should_not be_valid(['hoge', :foo, :bar]) }
47
+
48
+ describe 'when empty' do
49
+ subject { spec_for '[]' }
50
+ it { should be_valid([]) }
51
+ it { should_not be_valid([nil]) }
52
+ end
53
+ end
54
+ describe 'OR' do
55
+ subject { spec_for 'String | Symbol | Integer' }
56
+ it { should be_valid('s') }
57
+ it { should be_valid(:aaa) }
58
+ it { should be_valid(100) }
59
+ it { should_not be_valid(1.0) }
60
+ end
61
+ describe 'nil' do
62
+ subject { spec_for 'nil' }
63
+ it { should be_valid(nil) }
64
+ it { should_not be_valid(1) }
65
+ end
66
+ describe '[...]' do
67
+ subject { spec_for '[Integer...]' }
68
+ it { should be_valid([1,2,3]) }
69
+ it { should be_valid([]) }
70
+ it { should_not be_valid(['a']) }
71
+ end
72
+ describe 'Hash' do
73
+ describe 'hash_value' do
74
+ subject { spec_for '{:sym => Integer, "str" => String, \'str2\' => Symbol}' }
75
+ it { should be_valid({sym: 10, "str" => "string", "str2" => :a}) }
76
+ it { should_not be_valid({sym: 10, "str" => "string", "str2" => :a, a: 1}) }
77
+ it { should_not be_valid({sym: 10}) }
78
+ it { should_not be_valid(nil) }
79
+ end
80
+ shared_examples_for 'hash_type' do
81
+ it { should be_valid({}) }
82
+ it { should be_valid({'key' => 100}) }
83
+ it { should_not be_valid({'key' => 'value'}) }
84
+ it { should_not be_valid({:key => 100}) }
85
+ end
86
+ describe 'hash_type' do
87
+ subject { spec_for '{String => Integer}' }
88
+ it_should_behave_like 'hash_type'
89
+ end
90
+ describe 'named hash_type' do
91
+ subject { spec_for '{name:String => age:Integer}' }
92
+ it_should_behave_like 'hash_type'
93
+ end
94
+ # TODO: optional key
95
+ # TODO: error if key duplicated
96
+ end
97
+ # name:spec style
98
+ end
99
+ describe 'parsing method specification with block' do
100
+ describe 'Integer -> & -> String' do
101
+ subject { parse 'Integer -> & -> String' }
102
+ its(:block_spec) { should_not be_nil }
103
+ it { subject.block_spec.should_not be_valid(nil) }
104
+ it { subject.block_spec.should be_valid(lambda{}) }
105
+ end
106
+ describe 'Invalid syntax' do
107
+ it do
108
+ expect { parse 'Integer -> & -> Integer -> String' }.to raise_error
109
+ end
110
+ end
111
+ end
112
+ describe 'parsing complex arguments' do
113
+ def self.when_parsing(tdoc, &block)
114
+ describe "when parsing '#{tdoc}'" do
115
+ def self.its_arguments_should_accept(args)
116
+ it { method_spec.arguments_spec.should be_valid(args) }
117
+ end
118
+ def self.its_arguments_should_not_accept(args)
119
+ it { method_spec.arguments_spec.should_not be_valid(args) }
120
+ end
121
+ def self.its_arguments_should_accept_empty_only
122
+ its_arguments_should_accept []
123
+ its_arguments_should_not_accept [1]
124
+ end
125
+ def self.its_block_should_required
126
+ its(:block_spec) {
127
+ should be_valid(lambda{})
128
+ should_not be_valid(nil)
129
+ }
130
+ end
131
+ def self.its_block_should_optional
132
+ its(:block_spec) {
133
+ should be_valid(lambda{})
134
+ should be_valid(nil)
135
+ }
136
+ end
137
+ def self.its_block_should_none
138
+ its(:block_spec) {
139
+ should_not be_valid(lambda{})
140
+ should be_valid(nil)
141
+ }
142
+ end
143
+ def self.its_retval_should_accept(val)
144
+ its(:retval_spec) { should be_valid(val) }
145
+ end
146
+ def self.its_retval_should_not_accept(val)
147
+ its(:retval_spec) { should_not be_valid(val) }
148
+ end
149
+ def self.about_retval
150
+ describe 'retval' do
151
+ subject { method_spec.retval_spec }
152
+ def self.valid(val)
153
+ it { should be_valid(val) }
154
+ end
155
+ def self.invalid(val)
156
+ it { should_not be_valid(val) }
157
+ end
158
+ end
159
+ end
160
+ let(:method_spec) { parse(tdoc) }
161
+ subject { method_spec }
162
+ self.instance_eval &block
163
+ end
164
+ end
165
+ when_parsing 'Integer' do
166
+ its_arguments_should_accept_empty_only
167
+
168
+ its_block_should_none
169
+
170
+ its_retval_should_accept 1
171
+ its_retval_should_not_accept nil
172
+ end
173
+ when_parsing 'Integer -> Integer' do
174
+ its_arguments_should_accept [1]
175
+ its_arguments_should_not_accept []
176
+
177
+ its_block_should_none
178
+
179
+ its_retval_should_accept 1
180
+ its_retval_should_not_accept nil
181
+ end
182
+ when_parsing 'Integer|nil' do
183
+ its_arguments_should_accept_empty_only
184
+
185
+ its_block_should_none
186
+
187
+ its_retval_should_accept 1
188
+ its_retval_should_accept nil
189
+ its_retval_should_not_accept :a
190
+ end
191
+ when_parsing '& -> nil' do
192
+ its_arguments_should_accept_empty_only
193
+ its_block_should_required
194
+ its_retval_should_accept nil
195
+ end
196
+ when_parsing '?& -> nil' do
197
+ its_arguments_should_accept_empty_only
198
+ its_block_should_optional
199
+ its_retval_should_accept nil
200
+ end
201
+ when_parsing '*Integer -> nil' do
202
+ its_arguments_should_accept []
203
+ its_arguments_should_accept [1]
204
+ its_arguments_should_accept [1, 2]
205
+ its_arguments_should_not_accept [nil]
206
+
207
+ its_block_should_none
208
+ its_retval_should_accept nil
209
+ end
210
+ when_parsing '[Integer] -> nil' do
211
+ its_arguments_should_accept [[1]]
212
+ its_arguments_should_not_accept [[1, 2]]
213
+ end
214
+ when_parsing '[Integer, String] -> nil' do
215
+ its_arguments_should_accept [[1, 'foo']]
216
+ its_arguments_should_not_accept [[1, 2]]
217
+ end
218
+ when_parsing '[Integer...] -> nil' do
219
+ its_arguments_should_accept [[]]
220
+ its_arguments_should_accept [[1,2,3]]
221
+ its_arguments_should_not_accept [[nil]]
222
+ end
223
+ when_parsing '{ :i => Integer, ...} -> nil' do
224
+ its_arguments_should_accept [{i: 1}]
225
+ its_arguments_should_accept [{i: 1, j: 2}]
226
+ its_arguments_should_not_accept [{}]
227
+ end
228
+ end
229
+ end
230
+
231
+ describe Typedocs::MethodSpec do
232
+ def parse(src)
233
+ Typedocs::Parser.new.parse(::Object, src)
234
+ end
235
+ def ok(*args,&block)
236
+ case args.last
237
+ when Proc
238
+ subject.call_with_validate(block, *args[0..-2], &args.last)
239
+ else
240
+ subject.call_with_validate(block, *args)
241
+ end
242
+ # should not raise any exceptions
243
+ end
244
+ def ng_arg(*args, &block)
245
+ expect { ok(*args, &block) }.to raise_error Typedocs::ArgumentError
246
+ end
247
+ def ng_ret(*args, &block)
248
+ expect { ok(*args, &block) }.to raise_error Typedocs::RetValError
249
+ end
250
+ def ng_block(*args, &block)
251
+ expect { ok(*args, &block) }.to raise_error Typedocs::BlockError
252
+ end
253
+ describe 'validation' do
254
+ describe 'retval is Integer' do
255
+ subject { parse('Integer') }
256
+ it { ok { 1 } }
257
+ it { ng_ret { nil } }
258
+ it { ng_ret { '1' } }
259
+ end
260
+ describe 'retval is Integer or nil' do
261
+ subject { parse 'Integer|nil' }
262
+ it { ok { 1 } }
263
+ it { ok { nil } }
264
+ it { ng_ret { '1' } }
265
+ end
266
+ describe 'Integer -> Integer' do
267
+ subject { parse 'Integer -> Integer' }
268
+ it { ok(1) {|i| i} }
269
+ it { ng_arg(nil) { nil } }
270
+ it { ng_ret(1) { nil } }
271
+ end
272
+ describe 'Integer -> --(dont care)' do
273
+ subject { parse 'Integer -> --' }
274
+ it { ok(1) {1} }
275
+ it { ng_arg(nil) {1} }
276
+ end
277
+ describe 'Integer -> & -> String' do
278
+ subject { parse 'Integer -> & -> String' }
279
+ it { ok(1,lambda{|i|i.to_s}) {|&block| block.call 1} }
280
+ it { ng_block(1) {|&block| block.call 1} }
281
+ end
282
+ describe 'Integer -> ?& -> String' do
283
+ subject { parse 'Integer -> ?& -> String' }
284
+ it { ok(1,lambda{|i|i.to_s}) {|&block| block.call 'a'} }
285
+ it { ok(1) {|&block| 'a'} }
286
+ end
287
+ describe 'Integer -> Integer || String -> String' do
288
+ subject { parse 'Integer -> Integer || String -> String' }
289
+ it { ok(1) {|i| 2} }
290
+ it { ok('a') {|s| 'x'} }
291
+ end
292
+ end
293
+ end
294
+
295
+ describe Typedocs::TypeSpec::TypeIsA do
296
+ before do
297
+ ::Object.module_eval do
298
+ module A
299
+ module B
300
+ class C
301
+ end
302
+ end
303
+ end
304
+ end
305
+ end
306
+ after do
307
+ ::Object.module_eval { remove_const :A }
308
+ end
309
+ it do
310
+ Typedocs::TypeSpec::TypeIsA.new(A::B, 'C').should be_valid(A::B::C.new)
311
+ end
312
+ it do
313
+ Typedocs::TypeSpec::TypeIsA.new(A::B, '::A::B::C').should be_valid(A::B::C.new)
314
+ end
315
+ end
316
+
317
+ module TypeSpecSpecSandbox
318
+ end
319
+ describe Typedocs::TypeSpec do
320
+ let(:sandbox) { TypeSpecSpecSandbox }
321
+ let(:ns) { Typedocs::TypeSpec }
322
+ describe '::Any' do
323
+ subject { ns::Any.new }
324
+ it { should be_valid(nil) }
325
+ its(:to_source) { should == '_' }
326
+ it { expect { subject.error_message_for(nil) }.to raise_error }
327
+ end
328
+ describe '::Void' do
329
+ subject { ns::Void.new }
330
+ it { should be_valid(nil) }
331
+ its(:to_source) { should == 'void' }
332
+ it { expect { subject.error_message_for(nil) }.to raise_error }
333
+ end
334
+ describe '::TypeIsA' do
335
+ shared_examples_for 'Integer only' do
336
+ it { should be_valid(1) }
337
+ it { should_not be_valid('1') }
338
+ it { should_not be_valid(nil) }
339
+ end
340
+ describe 'with absolute name' do
341
+ subject { ns::TypeIsA.new sandbox, '::Integer' }
342
+ its(:to_source) { should == "::Integer" }
343
+ it_behaves_like 'Integer only'
344
+ end
345
+ describe 'with relative name' do
346
+ subject { ns::TypeIsA.new sandbox, 'Integer' }
347
+ its(:to_source) { should == "Integer" }
348
+ it_behaves_like 'Integer only'
349
+ end
350
+ end
351
+ describe '::Nil' do
352
+ subject { ns::Nil.new }
353
+ it { should be_valid(nil) }
354
+ it { should_not be_valid(1) }
355
+ its(:to_source) { should == 'nil' }
356
+ it { subject.error_message_for(1).should == "1 should == nil" }
357
+ end
358
+ describe '::ArrayAsStruct' do
359
+ subject { ns::ArrayAsStruct.new([ns::TypeIsA.new(Object,'Integer'), ns::Nil.new]) }
360
+ it { should be_valid([1, nil]) }
361
+ it { should_not be_valid(1) }
362
+ it { should_not be_valid([nil, nil]) }
363
+ it { should_not be_valid([]) }
364
+ it { should_not be_valid([1, nil, 1]) }
365
+ its(:to_source) { should == '[Integer, nil]' }
366
+ end
367
+ describe '::Array' do
368
+ subject { ns::Array.new(ns::TypeIsA.new(Object, 'Integer')) }
369
+ it { should be_valid([]) }
370
+ it { should be_valid([1]) }
371
+ it { should be_valid([1,2,3]) }
372
+ it { should_not be_valid(1) }
373
+ it { should_not be_valid([nil]) }
374
+ it { should_not be_valid([1,nil,2]) }
375
+ its(:to_source) { should == 'Integer...' }
376
+ end
377
+ describe '::HashValue' do
378
+ describe 'not accept others' do
379
+ subject { ns::HashValue.new([[:foo, ns::TypeIsA.new(Object, 'Integer')], ['bar', ns::Nil.new]], false) }
380
+ it { should be_valid({foo: 1, 'bar' => nil}) }
381
+ it { should_not be_valid({}) }
382
+ it { should_not be_valid({foo: 1}) }
383
+ it { should_not be_valid({foo: 1, 'bar' => nil, baz: 99}) }
384
+ its(:to_source) { should == '{:foo => Integer, "bar" => nil}' }
385
+ end
386
+ describe 'accept others' do
387
+ subject { ns::HashValue.new([[:foo, ns::TypeIsA.new(Object, 'Integer')], ['bar', ns::Nil.new]], true) }
388
+ it { should be_valid({foo: 1, 'bar' => nil}) }
389
+ it { should_not be_valid({}) }
390
+ it { should_not be_valid({foo: 1}) }
391
+ it { should be_valid({foo: 1, 'bar' => nil, baz: 99}) }
392
+ its(:to_source) { should == '{:foo => Integer, "bar" => nil, ...}' }
393
+ end
394
+ end
395
+ describe '::HashType' do
396
+ subject { ns::HashType.new(ns::TypeIsA.new(Object, 'Integer'), ns::TypeIsA.new(Object, 'String')) }
397
+ it { should be_valid({1 => "a"}) }
398
+ it { should be_valid({}) }
399
+ it { should_not be_valid({1 => 1}) }
400
+ it { should_not be_valid({1 => "a", 2 => 2}) }
401
+ its(:to_source) { should == '{Integer => String}' }
402
+ end
403
+ describe '::Or' do
404
+ describe 'when empty' do
405
+ it { expect { ns::Or.new([]) }.to raise_error ::ArgumentError }
406
+ end
407
+ describe 'Integer|nil' do
408
+ subject { ns::Or.new([ns::TypeIsA.new(Object, 'Integer'), ns::Nil.new]) }
409
+ it { should be_valid(nil) }
410
+ it { should be_valid(1) }
411
+ it { should_not be_valid("str") }
412
+ its(:to_source) { should == "Integer|nil" }
413
+ end
414
+ end
415
+ end
416
+
417
+ class ValueEquals < Typedocs::TypeSpec
418
+ def initialize(val)
419
+ @val = val
420
+ end
421
+ def valid?(val)
422
+ val == @val
423
+ end
424
+ def inspect
425
+ "(== #{@val.inspect})"
426
+ end
427
+ end
428
+ describe 'ensure ValueEquals helper works' do
429
+ subject { ValueEquals }
430
+ it { subject.new(1).should be_valid(1) }
431
+ it { subject.new(1).should_not be_valid(2) }
432
+ end
433
+ describe Typedocs::ArgumentsSpec do
434
+ def val(v)
435
+ ValueEquals.new(v)
436
+ end
437
+ subject { Typedocs::ArgumentsSpec.new }
438
+ describe 'with ()' do
439
+ it { should be_valid([]) }
440
+ it { should_not be_valid([:a]) }
441
+ end
442
+ describe 'with (a)' do
443
+ before do
444
+ subject.add_required(val :a)
445
+ end
446
+ it { should be_valid([:a]) }
447
+ it { should_not be_valid([]) }
448
+ it { should_not be_valid([:a,:b]) }
449
+ end
450
+ describe 'with (?a)' do
451
+ before do
452
+ subject.add_optional(val :a)
453
+ end
454
+ it { should be_valid([:a]) }
455
+ it { should be_valid([]) }
456
+ it { should_not be_valid([:a,:b]) }
457
+ end
458
+ describe 'with (a, ?b, ?c)' do
459
+ before do
460
+ subject.add_required(val :a)
461
+ subject.add_optional(val :b)
462
+ subject.add_optional(val :c)
463
+ end
464
+ it { should be_valid([:a]) }
465
+ it { should be_valid([:a,:b]) }
466
+ it { should be_valid([:a,:b,:c]) }
467
+ it { should_not be_valid([:a,:b,:c,:d]) }
468
+ it { should_not be_valid([]) }
469
+ end
470
+ describe 'with (*a)' do
471
+ before do
472
+ subject.add_rest(val :a)
473
+ end
474
+ it { should be_valid([]) }
475
+ it { should be_valid([:a]) }
476
+ it { should be_valid([:a,:a,:a]) }
477
+ it { should_not be_valid([:a,:b]) }
478
+ end
479
+ describe 'with (a, *b)' do
480
+ before do
481
+ subject.add_required(val :a)
482
+ subject.add_rest(val :b)
483
+ end
484
+ it { should be_valid([:a]) }
485
+ it { should be_valid([:a,:b,:b]) }
486
+ it { should_not be_valid([:a,:b,:c]) }
487
+ it { should_not be_valid([]) }
488
+ end
489
+ describe 'with (*a, b)' do
490
+ before do
491
+ subject.add_rest(val :a)
492
+ subject.add_required(val :b)
493
+ end
494
+ it { should be_valid([:b]) }
495
+ it { should be_valid([:a, :b]) }
496
+ it { should be_valid([:a, :a, :b]) }
497
+ it { should_not be_valid([:a, :b, :b]) }
498
+ it { should_not be_valid([]) }
499
+ it { should_not be_valid([:c]) }
500
+ end
501
+ describe 'with (a, *b, c)' do
502
+ before do
503
+ subject.add_required(val :a)
504
+ subject.add_rest(val :b)
505
+ subject.add_required(val :c)
506
+ end
507
+ it { should be_valid([:a, :c]) }
508
+ it { should be_valid([:a, :b, :c]) }
509
+ it { should be_valid([:a, :b, :b, :c]) }
510
+ it { should_not be_valid([:a, :b, :c, :c]) }
511
+ it { should_not be_valid([:a]) }
512
+ end
513
+ describe 'with (?a, *b, c)' do
514
+ before do
515
+ subject.add_optional(val :a)
516
+ subject.add_rest(val :b)
517
+ subject.add_required(val :c)
518
+ end
519
+ it { should be_valid([:c]) }
520
+ it { should be_valid([:a, :c]) }
521
+ it { should be_valid([:a, :b, :c]) }
522
+ it { should be_valid([:a, :b, :b, :c]) }
523
+ it { should_not be_valid([]) }
524
+ it { should_not be_valid([:a, :b, :c, :c]) }
525
+ end
526
+ describe 'with (a, ?b, c)' # error
527
+ describe 'with (a, *b, *c)' # error
528
+ describe 'with (a, *b, ?c)' # error
529
+ end
530
+
531
+ describe 'tdoc :inherit' do
532
+ before do
533
+ @ns = Class.new
534
+ end
535
+ describe 'A < B' do
536
+ before do
537
+ class @ns::A
538
+ include Typedocs::DSL
539
+ tdoc 'Integer'
540
+ def foo; '1'; end
541
+ end
542
+ class @ns::B < @ns::A
543
+ include Typedocs::DSL
544
+ tdoc :inherit
545
+ def foo; '2'; end
546
+ end
547
+ end
548
+ it 'inherit super method spec' do
549
+ expect { @ns::A.new.foo }.to raise_error Typedocs::RetValError
550
+ expect { @ns::B.new.foo }.to raise_error Typedocs::RetValError
551
+ end
552
+ end
553
+ describe 'deep nested class' do
554
+ before do
555
+ module @ns::Module
556
+ def foo; end
557
+ end
558
+ class @ns::A
559
+ include Typedocs::DSL
560
+ tdoc 'Integer'
561
+ def foo; end
562
+ end
563
+ class @ns::X < @ns::A
564
+ end
565
+ class @ns::B < @ns::X
566
+ include Typedocs::DSL
567
+ end
568
+ ns = @ns
569
+ @ns::B.class_eval { include(ns::Module) }
570
+ class @ns::B < @ns::X
571
+ def self.foo; end
572
+ tdoc :inherit
573
+ def foo; end
574
+ end
575
+ end
576
+ it 'inherit super method spec' do
577
+ expect { @ns::B.new.foo }.to raise_error Typedocs::RetValError
578
+ end
579
+ end
580
+ describe 'class method' do
581
+ before do
582
+ class @ns::A
583
+ include Typedocs::DSL
584
+ tdoc 'Integer'
585
+ def self.foo; end
586
+ end
587
+ end
588
+ it 'cant inherit' do
589
+ expect {
590
+ class @ns::B < @ns::A
591
+ include Typedocs::DSL
592
+ tdoc :inherit
593
+ def self.foo; end
594
+ end
595
+ }.to raise_error Typedocs::NoSuchMethod
596
+ end
597
+ end
598
+ end