retter 0.2.2 → 0.2.3
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.
- data/.travis.yml +1 -1
- data/ChangeLog.md +10 -0
- data/README.md +1 -3
- data/bin/retter +8 -4
- data/lib/retter/binder.rb +50 -0
- data/lib/retter/command.rb +42 -39
- data/lib/retter/config.rb +24 -23
- data/lib/retter/entries.rb +14 -18
- data/lib/retter/entry.rb +52 -29
- data/lib/retter/generator/base.rb +6 -7
- data/lib/retter/generator/skel/Gemfile +1 -2
- data/lib/retter/generator/skel/Retterfile +2 -2
- data/lib/retter/generator/skel/layouts/article.html.haml +3 -2
- data/lib/retter/generator/skel/layouts/entry.html.haml +3 -2
- data/lib/retter/generator/skel/layouts/index.html.haml +4 -2
- data/lib/retter/generator.rb +0 -1
- data/lib/retter/{renderers.rb → markdown.rb} +22 -1
- data/lib/retter/page/article.rb +54 -0
- data/lib/retter/page/base.rb +97 -0
- data/lib/retter/page/entries.rb +17 -0
- data/lib/retter/page/entry.rb +46 -0
- data/lib/retter/page/feed.rb +63 -0
- data/lib/retter/page/index.rb +17 -0
- data/lib/retter/page/profile.rb +17 -0
- data/lib/retter/page/view_helper.rb +9 -1
- data/lib/retter/page.rb +22 -74
- data/lib/retter/preprint.rb +19 -10
- data/lib/retter/version.rb +1 -1
- data/lib/retter.rb +41 -29
- data/retter.gemspec +44 -53
- data/spec/command/callback_spec.rb +16 -6
- data/spec/command/clean_spec.rb +20 -0
- data/spec/command/commit_spec.rb +11 -12
- data/spec/command/edit_spec.rb +28 -38
- data/spec/command/list_spec.rb +4 -4
- data/spec/command/open_spec.rb +2 -2
- data/spec/command/preview_spec.rb +7 -12
- data/spec/command/rebind_spec.rb +143 -66
- data/spec/spec_helper.rb +10 -3
- data/spec/support/example_group_helper.rb +55 -15
- data/spec/support/matchers.rb +0 -1
- metadata +195 -78
- data/lib/retter/generator/updator.rb +0 -7
- data/lib/retter/pages/article.rb +0 -41
- data/lib/retter/pages/entries.rb +0 -15
- data/lib/retter/pages/entry.rb +0 -35
- data/lib/retter/pages/feed.rb +0 -51
- data/lib/retter/pages/index.rb +0 -15
- data/lib/retter/pages/profile.rb +0 -15
- data/lib/retter/pages.rb +0 -77
- data/spec/command/invoke_after_spec.rb +0 -29
- data/spec/fixtures/sample.md +0 -295
data/spec/command/rebind_spec.rb
CHANGED
@@ -4,11 +4,8 @@ require 'spec_helper'
|
|
4
4
|
|
5
5
|
describe 'Retter::Command#rebind', clean: :all do
|
6
6
|
context 'first post' do
|
7
|
-
let(:date_str)
|
8
|
-
let(:
|
9
|
-
let(:date_file) { Retter.entries.retter_file(date) }
|
10
|
-
let(:date_html) { Retter::Pages.entry_file(date) }
|
11
|
-
let(:article) { <<-EOM }
|
7
|
+
let(:date_str) { '2011/01/01' }
|
8
|
+
let(:article) { <<-EOM }
|
12
9
|
# 朝11時
|
13
10
|
|
14
11
|
おはようございます
|
@@ -19,13 +16,14 @@ describe 'Retter::Command#rebind', clean: :all do
|
|
19
16
|
EOM
|
20
17
|
|
21
18
|
before do
|
22
|
-
|
19
|
+
time_travel_to date_str
|
23
20
|
|
24
|
-
|
21
|
+
write_to_wip_file article
|
25
22
|
|
26
|
-
command.should_receive(:
|
27
|
-
command.should_receive(:
|
28
|
-
|
23
|
+
command.should_receive(:after_callback).with(:bind)
|
24
|
+
command.should_receive(:after_callback).with(:rebind)
|
25
|
+
|
26
|
+
invoke_command :rebind
|
29
27
|
end
|
30
28
|
|
31
29
|
describe 'wip file' do
|
@@ -35,80 +33,80 @@ describe 'Retter::Command#rebind', clean: :all do
|
|
35
33
|
end
|
36
34
|
|
37
35
|
describe 'index.html' do
|
38
|
-
let(:index_html) {
|
36
|
+
let(:index_html) { generated_file('index.html').read }
|
39
37
|
|
40
|
-
it { texts_of(index_html, 'article p').should
|
38
|
+
it { texts_of(index_html, 'article p').should include 'おはようございます' }
|
41
39
|
it { texts_of(index_html, 'article h1.date').should == %w(2011-01-01) }
|
42
|
-
it { texts_of(index_html, 'article h1').should
|
40
|
+
it { texts_of(index_html, 'article h1').should == %w(2011-01-01 朝11時 夜1時) }
|
43
41
|
end
|
44
42
|
|
45
43
|
describe 'entries.html' do
|
46
|
-
let(:entries_html) {
|
44
|
+
let(:entries_html) { generated_file('entries.html').read }
|
47
45
|
|
48
46
|
it { texts_of(entries_html, 'a.entry').first.should == '01/01' }
|
49
|
-
it { texts_of(entries_html, 'a.article').should
|
47
|
+
it { texts_of(entries_html, 'a.article').should == %w(朝11時 夜1時) }
|
50
48
|
end
|
51
49
|
|
52
50
|
describe 'entry.html' do
|
53
|
-
let(:entry_html) {
|
51
|
+
let(:entry_html) { entry_html_file(date_str).read }
|
54
52
|
|
55
|
-
it { texts_of(entry_html, 'article p').should
|
53
|
+
it { texts_of(entry_html, 'article p').should == %w(おはようございます おやすみなさい) }
|
56
54
|
it { texts_of(entry_html, 'article h1.date').should == %w(2011-01-01) }
|
57
|
-
it { texts_of(entry_html, 'article h1').should
|
55
|
+
it { texts_of(entry_html, 'article h1').should == %w(2011-01-01 朝11時 夜1時) }
|
58
56
|
end
|
59
57
|
|
60
|
-
describe '
|
61
|
-
let(:
|
58
|
+
describe 'article (first)' do
|
59
|
+
let(:article_html) { article_html_file(date_str, 'a0').read }
|
62
60
|
|
63
61
|
describe 'body' do
|
64
|
-
subject { texts_of(
|
62
|
+
subject { texts_of(article_html, 'article p') }
|
65
63
|
|
66
|
-
it { should
|
67
|
-
it { should_not include
|
64
|
+
it { should include 'おはようございます' }
|
65
|
+
it { should_not include 'おやすみなさい' }
|
68
66
|
end
|
69
67
|
|
70
68
|
describe 'date' do
|
71
|
-
subject { texts_of(
|
69
|
+
subject { texts_of(article_html, 'article h1.date') }
|
72
70
|
|
73
71
|
it { should == %w(2011-01-01) }
|
74
72
|
end
|
75
73
|
|
76
74
|
describe 'headings' do
|
77
|
-
subject { texts_of(
|
75
|
+
subject { texts_of(article_html, 'article h1') }
|
78
76
|
|
79
|
-
it { should
|
80
|
-
it { should_not include
|
77
|
+
it { should include '朝11時' }
|
78
|
+
it { should_not include '夜1時' }
|
81
79
|
end
|
82
80
|
end
|
83
81
|
|
84
|
-
describe '
|
85
|
-
let(:
|
82
|
+
describe 'article (last)' do
|
83
|
+
let(:article_html) { article_html_file(date_str, 'a1').read }
|
86
84
|
|
87
85
|
describe 'body' do
|
88
|
-
subject { texts_of(
|
86
|
+
subject { texts_of(article_html, 'article p') }
|
89
87
|
|
90
|
-
it { should
|
91
|
-
it { should_not include
|
88
|
+
it { should include 'おやすみなさい' }
|
89
|
+
it { should_not include 'おはようございます' }
|
92
90
|
end
|
93
91
|
|
94
92
|
describe 'date' do
|
95
|
-
subject { texts_of(
|
93
|
+
subject { texts_of(article_html, 'article h1.date') }
|
96
94
|
|
97
95
|
it { should == %w(2011-01-01) }
|
98
96
|
end
|
99
97
|
|
100
98
|
describe 'headings' do
|
101
|
-
subject { texts_of(
|
99
|
+
subject { texts_of(article_html, 'article h1') }
|
102
100
|
|
103
|
-
it { should
|
104
|
-
it { should_not include
|
101
|
+
it { should include '夜1時' }
|
102
|
+
it { should_not include '朝11時' }
|
105
103
|
end
|
106
104
|
end
|
107
105
|
end
|
108
106
|
|
109
|
-
context 'includes code block' do
|
110
|
-
let(:index_html) {
|
111
|
-
let(:article)
|
107
|
+
context 'article includes code block' do
|
108
|
+
let(:index_html) { generated_file('index.html').read }
|
109
|
+
let(:article) { <<-EOM }
|
112
110
|
# コードを書きました
|
113
111
|
|
114
112
|
```ruby
|
@@ -117,13 +115,14 @@ sleep 1000
|
|
117
115
|
EOM
|
118
116
|
|
119
117
|
before do
|
120
|
-
|
118
|
+
write_to_wip_file article
|
121
119
|
end
|
122
120
|
|
123
121
|
context 'use Pygments' do
|
124
122
|
before do
|
125
|
-
Retter.config.renderer Retter::
|
126
|
-
|
123
|
+
Retter::Site.config.renderer Retter::Markdown::PygmentsRenderer
|
124
|
+
|
125
|
+
invoke_command :rebind
|
127
126
|
end
|
128
127
|
|
129
128
|
specify 'code should be highlighted' do
|
@@ -133,8 +132,9 @@ sleep 1000
|
|
133
132
|
|
134
133
|
context 'use CodeRay' do
|
135
134
|
before do
|
136
|
-
Retter.config.renderer Retter::
|
137
|
-
|
135
|
+
Retter::Site.config.renderer Retter::Markdown::CodeRayRenderer
|
136
|
+
|
137
|
+
invoke_command :rebind
|
138
138
|
end
|
139
139
|
|
140
140
|
specify 'code should be highlighted' do
|
@@ -143,57 +143,134 @@ sleep 1000
|
|
143
143
|
end
|
144
144
|
end
|
145
145
|
|
146
|
-
context '
|
146
|
+
context 'use custom markup' do
|
147
|
+
let(:index_html) { generated_file('index.html').read }
|
148
|
+
let(:custom_markup) { Object.new.tap {|o| o.define_singleton_method(:render, &:upcase) } }
|
149
|
+
|
147
150
|
before do
|
148
|
-
|
151
|
+
Retter::Site.config.markup custom_markup
|
152
|
+
|
153
|
+
write_to_wip_file 'hi'
|
154
|
+
|
155
|
+
invoke_command :rebind
|
156
|
+
end
|
157
|
+
|
158
|
+
after do
|
159
|
+
Retter::Entries.instance_variable_set :@markup, nil
|
160
|
+
end
|
161
|
+
|
162
|
+
subject { texts_of(index_html, 'article p') }
|
163
|
+
|
164
|
+
it { should include 'HI' }
|
165
|
+
end
|
149
166
|
|
150
|
-
|
167
|
+
context 'with silent option' do
|
168
|
+
before do
|
169
|
+
write_to_wip_file 'article'
|
151
170
|
end
|
152
171
|
|
153
172
|
specify 'rebind callback should not invoked' do
|
154
|
-
command.should_not_receive(:
|
173
|
+
command.should_not_receive(:after_callback)
|
155
174
|
|
156
|
-
|
175
|
+
invoke_command :rebind, silent: true
|
157
176
|
end
|
158
177
|
end
|
159
178
|
|
160
179
|
context 'skipping some singleton pages binding' do
|
161
|
-
let(:
|
162
|
-
let(:
|
163
|
-
let(:
|
164
|
-
let(:
|
165
|
-
let(:feed_file) { retter_home.join('feed.rss') }
|
180
|
+
let(:index_html) { generated_file('index.html') }
|
181
|
+
let(:profile_html) { generated_file('profile.html') }
|
182
|
+
let(:entries_html) { generated_file('entries.html') }
|
183
|
+
let(:feed_file) { generated_file('feed.rss') }
|
166
184
|
|
167
185
|
before do
|
168
186
|
index_html.unlink
|
169
187
|
|
170
|
-
|
188
|
+
invoke_command :edit
|
171
189
|
end
|
172
190
|
|
173
191
|
context 'skipping all' do
|
174
192
|
before do
|
175
|
-
|
176
|
-
|
177
|
-
|
193
|
+
invoke_command :rebind do |config|
|
194
|
+
config.allow_binding :none
|
195
|
+
end
|
178
196
|
end
|
179
197
|
|
180
198
|
it { profile_html.should_not be_exist }
|
181
199
|
it { entries_html.should_not be_exist }
|
182
|
-
it { feed_file.should_not
|
183
|
-
it { index_html.should
|
200
|
+
it { feed_file.should_not be_exist }
|
201
|
+
it { index_html.should be_exist }
|
184
202
|
end
|
185
203
|
|
186
204
|
context 'skipping only :feed' do
|
187
205
|
before do
|
188
|
-
|
189
|
-
|
190
|
-
|
206
|
+
invoke_command :rebind do |config|
|
207
|
+
config.allow_binding [:profile, :entries]
|
208
|
+
end
|
191
209
|
end
|
192
210
|
|
193
|
-
it { profile_html.should
|
194
|
-
it { entries_html.should
|
211
|
+
it { profile_html.should be_exist }
|
212
|
+
it { entries_html.should be_exist }
|
195
213
|
it { feed_file.should_not be_exist }
|
196
|
-
it { index_html.should
|
214
|
+
it { index_html.should be_exist }
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
context 'with link or image' do
|
219
|
+
let(:index_html) { generated_file('index.html').read }
|
220
|
+
let(:elements) { nokogiri(index_html) }
|
221
|
+
|
222
|
+
before do
|
223
|
+
write_to_wip_file article
|
224
|
+
|
225
|
+
invoke_command :rebind
|
226
|
+
end
|
227
|
+
|
228
|
+
describe 'a href="//example.com/foo/bar"' do
|
229
|
+
let(:article) { '[title](//example.com/foo/bar)' }
|
230
|
+
|
231
|
+
it { elements.search("a[href='//example.com/foo/bar']").should_not be_empty }
|
232
|
+
end
|
233
|
+
|
234
|
+
describe 'img src="//example.com/foo/bar.png"' do
|
235
|
+
let(:article) { '' }
|
236
|
+
|
237
|
+
it { elements.search("img[src='//example.com/foo/bar.png']").should_not be_empty }
|
238
|
+
end
|
239
|
+
|
240
|
+
describe 'a href="/foo/bar"' do
|
241
|
+
let(:article) { '[title](/foo/bar)' }
|
242
|
+
|
243
|
+
it { elements.search("a[href='./foo/bar']").should_not be_empty }
|
244
|
+
end
|
245
|
+
|
246
|
+
describe 'img src="/foo/bar.png"' do
|
247
|
+
let(:article) { '' }
|
248
|
+
|
249
|
+
it { elements.search("img[src='./foo/bar.png']").should_not be_empty }
|
250
|
+
end
|
251
|
+
|
252
|
+
describe 'a href="./foo/bar"' do
|
253
|
+
let(:article) { '[title](./foo/bar)' }
|
254
|
+
|
255
|
+
it { elements.search("a[href='./foo/bar']").should_not be_empty }
|
256
|
+
end
|
257
|
+
|
258
|
+
describe 'img src="./foo/bar.png"' do
|
259
|
+
let(:article) { '' }
|
260
|
+
|
261
|
+
it { elements.search("img[src='./foo/bar.png']").should_not be_empty }
|
262
|
+
end
|
263
|
+
|
264
|
+
describe 'a href="../foo/bar"' do
|
265
|
+
let(:article) { '[title](../foo/bar)' }
|
266
|
+
|
267
|
+
it { elements.search("a[href='../foo/bar']").should_not be_empty }
|
268
|
+
end
|
269
|
+
|
270
|
+
describe 'img src="../foo/bar.png"' do
|
271
|
+
let(:article) { '' }
|
272
|
+
|
273
|
+
it { elements.search("img[src='../foo/bar.png']").should_not be_empty }
|
197
274
|
end
|
198
275
|
end
|
199
276
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
3
|
require 'tapp'
|
4
|
+
require 'delorean'
|
4
5
|
|
5
6
|
if ENV['COVERAGE']
|
6
7
|
require 'simplecov'
|
@@ -26,13 +27,19 @@ RSpec.configure do |config|
|
|
26
27
|
|
27
28
|
config.after :each, clean: :all do
|
28
29
|
FileUtils.rm_rf retter_home
|
29
|
-
|
30
|
+
|
31
|
+
Retter::Site.reset!
|
30
32
|
end
|
31
33
|
|
32
|
-
config.before do
|
34
|
+
config.before :each do
|
33
35
|
env = {'EDITOR' => fake_editor.to_path, 'RETTER_HOME' => RETTER_ROOT.join('tmp', 'test').to_s}
|
34
36
|
|
35
|
-
Retter.load env
|
37
|
+
Retter::Site.load env
|
38
|
+
end
|
39
|
+
|
40
|
+
config.include Delorean
|
41
|
+
config.after :each do
|
42
|
+
back_to_the_present
|
36
43
|
end
|
37
44
|
|
38
45
|
config.include ExampleGroupHelper
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
require 'time'
|
4
3
|
require 'nokogiri'
|
4
|
+
require 'stringio'
|
5
5
|
|
6
6
|
module ExampleGroupHelper
|
7
7
|
module RetterShortcuts
|
@@ -9,8 +9,58 @@ module ExampleGroupHelper
|
|
9
9
|
@command ||= Retter::Command.new
|
10
10
|
end
|
11
11
|
|
12
|
+
def invoke_command(command_name, *args)
|
13
|
+
@command ||= Retter::Command.new
|
14
|
+
|
15
|
+
yield Retter::Site.config if block_given?
|
16
|
+
|
17
|
+
if args.last.is_a?(Hash)
|
18
|
+
options = args.pop
|
19
|
+
|
20
|
+
@command.stub!(:options) { options }
|
21
|
+
end
|
22
|
+
|
23
|
+
@command.__send__ command_name, *args
|
24
|
+
end
|
25
|
+
|
12
26
|
def wip_file
|
13
|
-
Retter.entries.wip_file
|
27
|
+
Retter::Site.entries.wip_file
|
28
|
+
end
|
29
|
+
|
30
|
+
def write_to_wip_file(body)
|
31
|
+
wip_file.open('w') {|f| f.write body }
|
32
|
+
end
|
33
|
+
|
34
|
+
def generated_file(path)
|
35
|
+
Retter::Site.config.retter_home.join(path)
|
36
|
+
end
|
37
|
+
|
38
|
+
def markdown_file(date)
|
39
|
+
date = date_wrap(date)
|
40
|
+
|
41
|
+
Retter::Site.entries.retter_file(date)
|
42
|
+
end
|
43
|
+
|
44
|
+
def find_entry_by_string(str)
|
45
|
+
Retter::Site.entries.detect_by_string(str)
|
46
|
+
end
|
47
|
+
|
48
|
+
def entry_html_file(date)
|
49
|
+
date = date_wrap(date)
|
50
|
+
|
51
|
+
Retter::Page.entry_file(date)
|
52
|
+
end
|
53
|
+
|
54
|
+
def article_html_file(date, id)
|
55
|
+
date = date_wrap(date)
|
56
|
+
|
57
|
+
Retter::Page.entry_dir(date).join("#{id}.html")
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def date_wrap(str)
|
63
|
+
Date.parse(str.to_s)
|
14
64
|
end
|
15
65
|
end
|
16
66
|
|
@@ -29,30 +79,20 @@ module ExampleGroupHelper
|
|
29
79
|
module Stream
|
30
80
|
def capture(stream)
|
31
81
|
begin
|
32
|
-
stream = stream.to_s
|
33
82
|
eval "$#{stream} = StringIO.new"
|
83
|
+
|
34
84
|
yield
|
85
|
+
|
35
86
|
result = eval("$#{stream}").string
|
36
87
|
ensure
|
37
|
-
eval(
|
88
|
+
eval %($#{stream} = #{stream.upcase})
|
38
89
|
end
|
39
90
|
|
40
91
|
result
|
41
92
|
end
|
42
93
|
end
|
43
94
|
|
44
|
-
module StubTime
|
45
|
-
def stub_time(time_str)
|
46
|
-
date = Date.parse(time_str)
|
47
|
-
time = Time.parse(time_str)
|
48
|
-
|
49
|
-
Date.stub!(:today).and_return(date)
|
50
|
-
Time.stub!(:now).and_return(time)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
95
|
include RetterShortcuts
|
55
96
|
include HTML
|
56
97
|
include Stream
|
57
|
-
include StubTime
|
58
98
|
end
|
data/spec/support/matchers.rb
CHANGED