wikilink-converter 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,43 @@
1
+ RSpec::Matchers.define :convert do |*from|
2
+ from_description = from
3
+ from_description = nil if from.empty?
4
+ from_description = from.first if from.size == 1
5
+
6
+ diffable
7
+
8
+ define_method :actual do
9
+ @real_actual ||= @actual.call(*from)
10
+ end
11
+
12
+ def expected
13
+ [@to]
14
+ end
15
+
16
+ match do |method|
17
+ actual == @to
18
+ end
19
+
20
+ description do
21
+ "convert #{from_description.inspect} to #{@to.inspect}"
22
+ end
23
+
24
+ failure_message_for_should do |method|
25
+ <<MESSAGE
26
+ expected #{from_description.inspect}
27
+ to #{@to.inspect}
28
+ got #{actual.inspect}
29
+ MESSAGE
30
+ end
31
+
32
+ failure_message_for_should_not do |method|
33
+ <<MESSAGE
34
+ expected #{from_description.inspect}
35
+ not to #{@to.inspect}
36
+ got #{actual.inspect}
37
+ MESSAGE
38
+ end
39
+
40
+ chain :to do |to|
41
+ @to = to
42
+ end
43
+ end
@@ -0,0 +1,113 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+
3
+ shared_examples 'converter that can forward to given block' do |klass|
4
+ klass ||= describes
5
+
6
+ context 'given block through #config' do
7
+ let(:converter) { klass.new.config { 'it works' } }
8
+
9
+ describe '#run' do
10
+ subject { converter.method(:run) }
11
+ it 'forwards to the block' do
12
+ subject.should convert(':', 'Home', 'Home', '/').to('it works')
13
+ end
14
+ end
15
+ end
16
+
17
+ context 'given block accessing options in constructor through #config' do
18
+ let(:converter) {
19
+ klass.new(fake_result: 'fake').config { options[:fake_result] }
20
+ }
21
+
22
+ describe '#run' do
23
+ subject { converter.method(:run) }
24
+ it 'forwards to the block and allows options access' do
25
+ subject.should convert(':', 'Home', 'Home', '/').to('fake')
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ describe Wikilink::Converter::Namespace do
32
+ let(:converter) { Wikilink::Converter::Namespace.new }
33
+ describe '#run' do
34
+ subject { converter.method(:run) }
35
+ it 'does nothing' do
36
+ subject.should convert(':', 'Home', 'Home', '/').to(nil)
37
+ end
38
+ end
39
+
40
+ it_behaves_like 'converter that can forward to given block'
41
+ end
42
+
43
+ describe Wikilink::Converter::Namespace::Default do
44
+ shared_examples 'converter that keeps query fragment only path untouched' do
45
+ it { should convert(':', '#toc-1', 'Header 1', '/').
46
+ to('<a href="#toc-1">Header 1</a>')
47
+ }
48
+ it { should convert(':', '?q=keyword', 'Search keyword', '/').
49
+ to('<a href="?q=keyword">Search keyword</a>')
50
+ }
51
+ it { should convert(':', '?q=keyword#page-10', 'Search keyword (page 10)', '/').
52
+ to('<a href="?q=keyword#page-10">Search keyword (page 10)</a>')
53
+ }
54
+ end
55
+
56
+ let(:converter) { self.class.describes.new }
57
+ describe '#run' do
58
+ subject { converter.method(:run) }
59
+ it { should convert(':', 'Home', 'Name', '/').
60
+ to('<a href="Home">Name</a>')
61
+ }
62
+ it_behaves_like 'converter that keeps query fragment only path untouched'
63
+ end
64
+
65
+ context 'given option :prefix "/wiki/"' do
66
+ let(:converter) { self.class.describes.new prefix: '/wiki/' }
67
+ describe '#run' do
68
+ subject { converter.method(:run) }
69
+ it_behaves_like 'converter that keeps query fragment only path untouched'
70
+ end
71
+ end
72
+
73
+ context 'given option :suffix "/index.html"' do
74
+ let(:converter) { self.class.describes.new suffix: '/index.html' }
75
+ describe '#run' do
76
+ subject { converter.method(:run) }
77
+ it { should convert(':', 'Home', 'Name', '/').
78
+ to('<a href="Home/index.html">Name</a>')
79
+ }
80
+ it_behaves_like 'converter that keeps query fragment only path untouched'
81
+ end
82
+ end
83
+
84
+ context 'given option :external true' do
85
+ let(:converter) { self.class.describes.new external: true }
86
+ describe '#run' do
87
+ subject { converter.method(:run) }
88
+ it { should convert(':', 'Home', 'Name', '/').
89
+ to('<a class="external" href="Home">Name</a>')
90
+ }
91
+ end
92
+ end
93
+ context 'given option :class "fancy"' do
94
+ let(:converter) { self.class.describes.new class: 'fancy' }
95
+ describe '#run' do
96
+ subject { converter.method(:run) }
97
+ it { should convert(':', 'Home', 'Name', '/').
98
+ to('<a class="fancy" href="Home">Name</a>')
99
+ }
100
+ end
101
+ end
102
+ context 'given option :external true and :class "fancy"' do
103
+ let(:converter) { self.class.describes.new external: true, class: 'fancy' }
104
+ describe '#run' do
105
+ subject { converter.method(:run) }
106
+ it { should convert(':', 'Home', 'Name', '/').
107
+ to('<a class="fancy external" href="Home">Name</a>')
108
+ }
109
+ end
110
+ end
111
+
112
+ it_behaves_like 'converter that can forward to given block'
113
+ end
@@ -0,0 +1,334 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+
3
+ describe Wikilink::Converter::Site do
4
+ DEFAULT_NAMESPACE = Wikilink::Converter::Site::DEFAULT_NAMESPACE
5
+ CURRENT_SITE_NAME = Wikilink::Converter::Site::CURRENT_SITE_NAME
6
+
7
+ # { subject.foo }.should forward(:bar).to(handler).with(any_args)
8
+ RSpec::Matchers.define :forward do |message|
9
+ match do |block|
10
+ block.call
11
+ @handler.received_message?(message, *@arguments)
12
+ end
13
+
14
+ description do
15
+ "forward to message #{message} to #{@handler.inspect}"
16
+ end
17
+
18
+ failure_message_for_should do |block|
19
+ <<MESSAGE
20
+ expected forward #{message}
21
+ to #{block}
22
+ with #{@arguments.inspect}
23
+ MESSAGE
24
+ end
25
+
26
+ failure_message_for_should_not do |block|
27
+ <<MESSAGE
28
+ expected not forward #{message}
29
+ to #{block}
30
+ with #{@arguments.inspect}
31
+ MESSAGE
32
+ end
33
+
34
+ chain :with do |*arguments|
35
+ @arguments = arguments
36
+ end
37
+
38
+ chain :to do |handler|
39
+ @handler = handler
40
+ end
41
+ end
42
+
43
+ shared_examples 'configuring a new instance of class as namespace handler' do |namespace|
44
+ # require setting converter to an instance of Site
45
+ context 'with converter class' do
46
+ class SpecNamespace; end
47
+ define_method :call do |*args|
48
+ if namespace.to_s.empty?
49
+ converter.on_namespace SpecNamespace, *args
50
+ else
51
+ converter.on_namespace namespace, SpecNamespace, *args
52
+ end
53
+ end
54
+ let(:namespace_converter) { double(:namespace_converter) }
55
+
56
+ it 'creates a new instance of the specified class' do
57
+ SpecNamespace.should_receive(:new).once
58
+ call
59
+ end
60
+
61
+ it 'uses the instance of the class as new namespace converter' do
62
+ SpecNamespace.should_receive(:new).once.and_return(namespace_converter)
63
+ call
64
+ namespace_converter.should_receive(:run).and_return('it works')
65
+ converter.run(':', namespace, 'Home', 'Name', '/').should eq('it works')
66
+ end
67
+
68
+ context 'and options' do
69
+ let(:options) { { foo: :bar} }
70
+ it 'creates a new instance of the specified class and options' do
71
+ SpecNamespace.should_receive(:new).once
72
+ call options
73
+ end
74
+
75
+ it 'initializes the new instance of the specified class with options' do
76
+ SpecNamespace.should_receive(:new).with(hash_including(foo: :bar)).once
77
+ call options
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ let(:default_namespace) { double(:default_namespace).as_null_object }
84
+ let(:namespace) { double(:namespace).as_null_object }
85
+ before { Wikilink::Converter::Namespace::Default.stub(:new) { default_namespace } }
86
+
87
+ shared_examples ''
88
+
89
+ context 'current site' do
90
+ let(:site_name) { CURRENT_SITE_NAME }
91
+ let(:converter) { Wikilink::Converter::Site.new name: site_name }
92
+
93
+ describe '#initialize' do
94
+ def initialize_site(&block)
95
+ Wikilink::Converter::Site.new name: site_name, &block
96
+ end
97
+
98
+ it 'sets option :prefix to "/"' do
99
+ converter.options[:prefix].should eq('/')
100
+ end
101
+ it 'sets option :external to false' do
102
+ converter.options[:external].should be_false
103
+ end
104
+ it 'sets up default namespace with option :site_name' do
105
+ klass = Wikilink::Converter::Namespace::Default
106
+ klass.should_receive(:new).with(hash_including(site_name: site_name))
107
+ initialize_site
108
+ end
109
+ it 'sets up default namespace with option :name' do
110
+ klass = Wikilink::Converter::Namespace::Default
111
+ klass.should_receive(:new).with(hash_including(name: DEFAULT_NAMESPACE))
112
+ initialize_site
113
+ end
114
+ it 'yields self' do
115
+ initialize_site do |arg|
116
+ arg.should be_a_kind_of(Wikilink::Converter::Site)
117
+ end
118
+ end
119
+
120
+ context 'with option :external true' do
121
+ let(:converter) { Wikilink::Converter::Site.new name: site_name, external: true }
122
+ it 'leaves option :external as true' do
123
+ converter.options[:external].should be_true
124
+ end
125
+ end
126
+ context 'with option :prefix "/wiki/"' do
127
+ let(:converter) { Wikilink::Converter::Site.new name: site_name, prefix: '/wiki/' }
128
+ it 'leaves option :prefix as "/wiki/"' do
129
+ converter.options[:prefix].should eq('/wiki/')
130
+ end
131
+ end
132
+ end
133
+
134
+ describe '#run' do
135
+ it 'delegates default namespace to Namespace::Default instance' do
136
+ ->{ converter.run(':', DEFAULT_NAMESPACE, 'Home', 'Name', '/') }.
137
+ should forward(:run).to(default_namespace).with(':', 'Home', 'Name', '/')
138
+ end
139
+ end
140
+
141
+ describe '#on_default_namespace' do
142
+ it 'is a shortcut of #on_namespace' do
143
+ converter.should_receive(:on_namespace).with(DEFAULT_NAMESPACE, 'arg')
144
+ converter.on_default_namespace 'arg'
145
+ end
146
+ end
147
+
148
+ describe '#on_namespace' do
149
+ context 'without any arguments nor block' do
150
+ let(:default_namespace) { double(:default_namespace) }
151
+
152
+ it 'does not change the default namespace handler' do
153
+ Wikilink::Converter::Namespace::Default.should_receive(:new).
154
+ once.and_return(default_namespace)
155
+ converter.on_namespace
156
+ end
157
+ end
158
+
159
+ context 'with block' do
160
+ it 'configures default namespace with the block' do
161
+ yielded = double('yielded')
162
+ yielded.should_receive(:poke)
163
+ default_namespace.should_receive(:config).and_yield
164
+ converter.on_namespace do
165
+ yielded.poke
166
+ end
167
+ end
168
+ end
169
+
170
+ context 'with options' do
171
+ let(:default_namespace) { double(:default_namespace) }
172
+
173
+ it 'does not change the default namespace handler' do
174
+ Wikilink::Converter::Namespace::Default.should_receive(:new).
175
+ once.and_return(default_namespace)
176
+ converter.on_namespace foo: :bar
177
+ end
178
+ end
179
+
180
+ context 'with default namespace name' do
181
+ let(:default_namespace) { double(:default_namespace) }
182
+
183
+ it 'does not change the default namespace handler' do
184
+ Wikilink::Converter::Namespace::Default.should_receive(:new).
185
+ once.and_return(default_namespace)
186
+ converter.on_namespace(DEFAULT_NAMESPACE)
187
+ end
188
+ end
189
+ context 'with other namespace name' do
190
+ let(:name) { 'topics' }
191
+ let(:klass) { Wikilink::Converter::Namespace }
192
+
193
+ it 'creates a new Wikilink::Converter::Namespace instance' do
194
+ klass.should_receive(:new)
195
+ converter.on_namespace name
196
+ end
197
+ it 'initializes Wikilink::Converter::Namespace instance with option :site_name' do
198
+ klass.should_receive(:new).with(hash_including(site_name: site_name))
199
+ converter.on_namespace name
200
+ end
201
+ it 'initializes Wikilink::Converter::Namespace instance with option :name' do
202
+ klass.should_receive(:new).with(hash_including(name: name))
203
+ converter.on_namespace name
204
+ end
205
+ it 'uses the instance of Wikilink::Converter::Namespace as new namespace converter' do
206
+ klass.should_receive(:new).and_return(namespace)
207
+ converter.on_namespace name
208
+ namespace.should_receive(:run).and_return('it works')
209
+ converter.run(':', name, 'Home', 'Name', '/').should eq('it works')
210
+ end
211
+
212
+ context 'with object' do
213
+ it 'uses that object as new namespace converter' do
214
+ converter.on_namespace name, namespace
215
+ namespace.should_receive(:run).and_return('it works')
216
+ converter.run(':', name, 'Home', 'Name', '/').should eq('it works')
217
+ end
218
+ end
219
+
220
+ it_behaves_like 'configuring a new instance of class as namespace handler', 'topics'
221
+ end
222
+
223
+ it_behaves_like 'configuring a new instance of class as namespace handler'
224
+
225
+ context 'with object' do
226
+ it 'uses that object as new namespace converter' do
227
+ converter.on_namespace namespace
228
+ namespace.should_receive(:run).and_return('it works')
229
+ converter.run(':', DEFAULT_NAMESPACE, 'Home', 'Name', '/').should eq('it works')
230
+ end
231
+ end
232
+
233
+ context 'with namespace, classname and options' do
234
+ end
235
+ end
236
+ end
237
+
238
+ context 'external site' do
239
+ let(:name) { 'wikipedia' }
240
+ let(:converter) { Wikilink::Converter::Site.new name: name }
241
+
242
+ describe '#initialize' do
243
+ alias_method :initialize_site, :converter
244
+
245
+ it 'does not set option :prefix' do
246
+ converter.options[:prefix].should be_nil
247
+ end
248
+ it 'sets option :external to true' do
249
+ converter.options[:external].should be_true
250
+ end
251
+
252
+ it 'sets up default namespace with option :site_name' do
253
+ klass = Wikilink::Converter::Namespace::Default
254
+ klass.should_receive(:new).with(hash_including(site_name: name))
255
+ initialize_site
256
+ end
257
+ it 'sets up default namespace with option :name' do
258
+ klass = Wikilink::Converter::Namespace::Default
259
+ klass.should_receive(:new).with(hash_including(name: DEFAULT_NAMESPACE))
260
+ initialize_site
261
+ end
262
+
263
+ context 'with option :external false' do
264
+ let(:converter) { Wikilink::Converter::Site.new name: name, external: false }
265
+ it 'leaves option :external as false' do
266
+ converter.options[:external].should be_false
267
+ end
268
+ end
269
+ context 'with option :prefix "/wiki/"' do
270
+ let(:converter) { Wikilink::Converter::Site.new name: name, prefix: '/wiki/' }
271
+ it 'leaves option :prefix as "/wiki/"' do
272
+ converter.options[:prefix].should eq('/wiki/')
273
+ end
274
+ end
275
+ end
276
+
277
+ describe '#run' do
278
+ it 'delegates default namespace to Namespace::Default instance' do
279
+ ->{ converter.run(':', DEFAULT_NAMESPACE, 'Home', 'Name', '/') }.
280
+ should forward(:run).to(default_namespace).with(':', 'Home', 'Name', '/')
281
+ end
282
+
283
+ context 'with method #on_namespace_topics defined' do
284
+ before { Wikilink::Converter::Namespace::Default.unstub(:new) }
285
+ class SpecSite < Wikilink::Converter::Site
286
+ def on_namespace_topics(colon, path, name, current_page)
287
+ 'it works'
288
+ end
289
+ end
290
+ let(:converter) { SpecSite.new }
291
+ it 'invokes #on_namespace_topics to handle namespace topics' do
292
+ converter.run(':', 'topics', 'Home', 'Name', '/').should eq('it works')
293
+ end
294
+
295
+ context 'but user has override it' do
296
+ before {
297
+ converter.namespace('topics') do
298
+ 'use this version'
299
+ end
300
+ }
301
+
302
+ it 'uses user version' do
303
+ converter.run(':', 'topics', 'Home', 'Name', '/').should eq('use this version')
304
+ end
305
+ end
306
+ end
307
+
308
+ context 'with method #on_namespace_ defined' do
309
+ before { Wikilink::Converter::Namespace::Default.unstub(:new) }
310
+ class SpecSite < Wikilink::Converter::Site
311
+ def on_namespace_(colon, path, name, current_page)
312
+ 'it works'
313
+ end
314
+ end
315
+ let(:converter) { SpecSite.new }
316
+ it 'invokes #on_namespace_ to handle default namespace' do
317
+ converter.run(':', DEFAULT_NAMESPACE, 'Home', 'Name', '/').should eq('it works')
318
+ end
319
+
320
+ context 'but user has override it' do
321
+ before {
322
+ converter.namespace do
323
+ 'use this version'
324
+ end
325
+ }
326
+
327
+ it 'uses user version' do
328
+ converter.run(':', DEFAULT_NAMESPACE, 'Home', 'Name', '/').should eq('use this version')
329
+ end
330
+ end
331
+ end
332
+ end
333
+ end
334
+ end
@@ -0,0 +1,31 @@
1
+ # -*- coding: utf-8 -*-
2
+ require File.expand_path('../../../../spec_helper', __FILE__)
3
+ require 'wikilink/converter/sites/ruby_china'
4
+
5
+ describe Wikilink::Converter::Sites::RubyChina do
6
+ subject { converter.method(:run) }
7
+
8
+ context 'ruby-china.org' do
9
+ let(:rubychina) { Wikilink::Converter::Sites::RubyChina }
10
+ let(:converter) {
11
+ Wikilink::Converter.new { |on| on.current_site(rubychina) }
12
+ }
13
+
14
+ it { should convert('[[Ruby]]').to('<a href="/wiki/Ruby">Ruby</a>') }
15
+ it { should convert('[[topic:1]]').to('<a href="/topics/1">topic:1</a>') }
16
+ it { should convert('[[node:1]]').to('<a href="/topics/node1">node:1</a>') }
17
+ end
18
+
19
+ context 'external ruby-taiwan.org' do
20
+ let(:rubytaiwan) { Wikilink::Converter::Sites::RubyTaiwan }
21
+ let(:converter) {
22
+ Wikilink::Converter.new { |on|
23
+ on.site('rubytaiwan', rubytaiwan)
24
+ }
25
+ }
26
+
27
+ it { should convert('[[rubytaiwan:Ruby]]').to('<a class="external" href="http://ruby-taiwan.org/wiki/Ruby">rubytaiwan:Ruby</a>') }
28
+ it { should convert('[[rubytaiwan:topic:1]]').to('<a class="external" href="http://ruby-taiwan.org/topics/1">rubytaiwan:topic:1</a>') }
29
+ it { should convert('[[rubytaiwan:node:1]]').to('<a class="external" href="http://ruby-taiwan.org/topics/node1">rubytaiwan:node:1</a>') }
30
+ end
31
+ end
@@ -0,0 +1,25 @@
1
+ # -*- coding: utf-8 -*-
2
+ require File.expand_path('../../../../spec_helper', __FILE__)
3
+ require 'wikilink/converter/sites/wikipedia'
4
+
5
+ describe Wikilink::Converter::Sites::Wikipedia do
6
+ subject { converter.method(:run) }
7
+
8
+ context 'en current site' do
9
+ let(:wikipedia) { Wikilink::Converter::Sites::Wikipedia }
10
+ let(:converter) {
11
+ Wikilink::Converter.new { |on| on.current_site(wikipedia) }
12
+ }
13
+ it { should convert('[[Ruby]]').to('<a href="/wiki/Ruby">Ruby</a>')}
14
+ end
15
+
16
+ context 'zh external site' do
17
+ let(:wikipedia) { Wikilink::Converter::Sites::Wikipedia }
18
+ let(:converter) {
19
+ Wikilink::Converter.new(lang: 'zh') do |on|
20
+ on.site('wiki', wikipedia)
21
+ end
22
+ }
23
+ it { should convert('[[wiki:红宝石]]').to('<a class="external" href="http://zh.wikipedia.org/wiki/红宝石">wiki:红宝石</a>')}
24
+ end
25
+ end