serif 0.5.2 → 0.6

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.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +58 -21
  4. data/LICENSE +1 -1
  5. data/README.md +11 -13
  6. data/lib/serif.rb +3 -2
  7. data/lib/serif/admin_server.rb +10 -10
  8. data/lib/serif/commands.rb +2 -2
  9. data/lib/serif/config.rb +1 -1
  10. data/lib/serif/content_file.rb +9 -9
  11. data/lib/serif/draft.rb +1 -1
  12. data/lib/serif/errors.rb +1 -1
  13. data/lib/serif/markup_renderer.rb +28 -17
  14. data/lib/serif/post.rb +1 -1
  15. data/lib/serif/server.rb +1 -1
  16. data/lib/serif/site.rb +5 -29
  17. data/rakefile +3 -6
  18. data/serif.gemspec +9 -3
  19. data/statics/assets/js/attachment.js +3 -3
  20. data/statics/skeleton/_config.yml +1 -1
  21. data/statics/skeleton/_layouts/default.html +1 -1
  22. data/statics/skeleton/_templates/archive_page.html +1 -1
  23. data/statics/skeleton/_templates/post.html +1 -1
  24. data/statics/skeleton/archive.html +1 -1
  25. data/statics/skeleton/index.html +1 -1
  26. data/statics/templates/admin/bookmarks.liquid +1 -1
  27. data/statics/templates/admin/edit_draft.liquid +1 -1
  28. data/statics/templates/admin/index.liquid +1 -1
  29. data/statics/templates/admin/layout.liquid +6 -4
  30. data/statics/templates/admin/new_draft.liquid +1 -1
  31. metadata +123 -127
  32. data/test/commands_spec.rb +0 -77
  33. data/test/config_spec.rb +0 -55
  34. data/test/content_file_spec.rb +0 -113
  35. data/test/draft_spec.rb +0 -275
  36. data/test/file_digest_tag_spec.rb +0 -38
  37. data/test/filters_spec.rb +0 -90
  38. data/test/liquid_filter_date_extension_spec.rb +0 -15
  39. data/test/markup_renderer_spec.rb +0 -47
  40. data/test/post_spec.rb +0 -139
  41. data/test/site_dir/_config.yml +0 -18
  42. data/test/site_dir/_drafts/another-sample-draft +0 -3
  43. data/test/site_dir/_drafts/sample-draft +0 -3
  44. data/test/site_dir/_layouts/alt-layout.html +0 -3
  45. data/test/site_dir/_layouts/default.html +0 -8
  46. data/test/site_dir/_posts/2012-01-05-sample-post +0 -4
  47. data/test/site_dir/_posts/2013-01-01-second-post +0 -4
  48. data/test/site_dir/_posts/2013-03-07-post-with-custom-layout +0 -5
  49. data/test/site_dir/_posts/2399-01-01-penultimate-post +0 -4
  50. data/test/site_dir/_posts/2400-01-01-final-post +0 -4
  51. data/test/site_dir/_templates/archive_page.html +0 -9
  52. data/test/site_dir/_templates/post.html +0 -10
  53. data/test/site_dir/archive.html +0 -7
  54. data/test/site_dir/file-digest-test.html +0 -4
  55. data/test/site_dir/index.html +0 -9
  56. data/test/site_dir/page-alt-layout.html +0 -3
  57. data/test/site_dir/page-header-but-no-layout.html +0 -3
  58. data/test/site_dir/test-smarty-filter.html +0 -3
  59. data/test/site_dir/test-stylesheet.css +0 -3
  60. data/test/site_generation_spec.rb +0 -204
  61. data/test/site_spec.rb +0 -189
  62. data/test/test_helper.rb +0 -61
@@ -1,9 +0,0 @@
1
- <h2>Posts</h2>
2
-
3
- <p>There are {{ site.posts.size }} posts:</p>
4
-
5
- <ul>
6
- {% for post in site.posts %}
7
- <li><a href="{{ post.url | escape }}">{{ post.title | escape }}</a> (posted {{ post.created | xmlschema }})</li>
8
- {% endfor %}
9
- </ul>
@@ -1,3 +0,0 @@
1
- layout: alt-layout
2
-
3
- page alt layout
@@ -1,3 +0,0 @@
1
- foo: bar
2
-
3
- file containing headers but no layout option, to test that it still uses the default
@@ -1,3 +0,0 @@
1
- Some content
2
-
3
- {{ "testing's for a " | append: '"' | append: "heading's" | append: '"' | append: " `with code` in it..." | smarty }}
@@ -1,3 +0,0 @@
1
- #foo {
2
- bar: baz;
3
- }
@@ -1,204 +0,0 @@
1
- require "test_helper"
2
-
3
- describe Serif::Site do
4
- subject do
5
- Serif::Site.new(testing_dir)
6
- end
7
-
8
- before(:each) do
9
- FileUtils.rm_rf(testing_dir("_site"))
10
- end
11
-
12
- describe "site generation" do
13
- it "raises PostConflictError if there are conflicts" do
14
- # not nil, the value is unimportant
15
- subject.stub(:conflicts) { [] }
16
- expect { capture_stdout { subject.generate } }.to raise_error(Serif::PostConflictError)
17
- end
18
-
19
- it "uses the permalinks in the config file for site generation" do
20
- capture_stdout { subject.generate }
21
- File.exist?(testing_dir("_site/test-blog/sample-post.html")).should be_true
22
- end
23
-
24
- it "reads the layout header for a non-post file and uses the appropriate layout file" do
25
- capture_stdout { subject.generate }
26
-
27
- # check it actually got generated
28
- File.exist?(testing_dir("_site/page-alt-layout.html")).should be_true
29
- File.read("_site/page-alt-layout.html").lines.first.should =~ /<h1.+?>Alternate layout<\/h1>/
30
- end
31
-
32
- it "reads the layout header for a post file and uses the appropriate layout file" do
33
- capture_stdout { subject.generate }
34
-
35
- # check it actually got generated
36
- File.exist?(testing_dir("_site/test-blog/post-with-custom-layout.html")).should be_true
37
- File.read("_site/test-blog/post-with-custom-layout.html").lines.first.should =~ /<h1.+?>Alternate layout<\/h1>/
38
- end
39
-
40
- it "supports a smarty filter" do
41
- capture_stdout { subject.generate }
42
- File.read("_site/test-smarty-filter.html").should =~ /testing&rsquo;s for a &ldquo;heading&rsquo;s&rdquo; `with code` in it&hellip;/
43
- end
44
-
45
- it "correctly handles file_digest calls" do
46
- capture_stdout { subject.generate }
47
-
48
- File.read("_site/file-digest-test.html").strip.should == "f8390232f0c354a871f9ba0ed306163c\n.f8390232f0c354a871f9ba0ed306163c"
49
- end
50
-
51
- it "makes the previous and next posts available" do
52
- capture_stdout { subject.generate }
53
-
54
- contents = File.read("_site/test-blog/sample-post.html")
55
- previous_title = contents[/^Previous post: .+?$/]
56
- next_title = contents[/^Next post: .+?$/]
57
-
58
- previous_title.should be_nil
59
- next_title.should_not be_nil
60
- next_title[/(?<=: ).+/].should == "Second post"
61
-
62
- contents = File.read("_site/test-blog/final-post.html")
63
- previous_title = contents[/Previous post: .+?$/]
64
- next_title = contents[/Next post: .+?$/]
65
-
66
- previous_title.should_not be_nil
67
- next_title.should be_nil
68
- previous_title[/(?<=: ).+/].should == "Penultimate post"
69
- end
70
-
71
- it "sets a draft_preview flag for preview urls" do
72
- preview_flag_pattern = /draftpreviewflagexists/
73
-
74
- capture_stdout { subject.generate }
75
-
76
- d = Serif::Draft.from_slug(subject, "sample-draft")
77
- preview_contents = File.read(testing_dir("_site/#{subject.private_url(d)}.html"))
78
- (preview_contents =~ preview_flag_pattern).should be_true
79
-
80
- # does not exist on live published pages
81
- (File.read(testing_dir("_site/test-blog/second-post.html")) =~ preview_flag_pattern).should be_false
82
- end
83
-
84
- it "sets a post_page flag for regular posts" do
85
- capture_stdout { subject.generate }
86
- d = Serif::Post.from_basename(subject, "2013-01-01-second-post")
87
- d.should_not be_nil
88
- contents = File.read(testing_dir("_site#{d.url}.html"))
89
-
90
- # available to the post layout file
91
- (contents =~ /post_page flag set for template/).should be_true
92
-
93
- # available in the layout file itself
94
- (contents =~ /post_page flag set for layout/).should be_true
95
-
96
- # not set for regular pages
97
- (File.read(testing_dir("_site/index.html")) =~ /post_page flag set for template/).should be_false
98
- (File.read(testing_dir("_site/index.html")) =~ /post_page flag set for layout/).should be_false
99
-
100
- # not set for drafts
101
- d = Serif::Draft.from_slug(subject, "sample-draft")
102
- preview_contents = File.read(testing_dir("_site/#{subject.private_url(d)}.html"))
103
- (preview_contents =~ /post_page flag set for template/).should be_false
104
- (preview_contents =~ /post_page flag set for layout/).should be_false
105
- end
106
-
107
- it "creates draft preview files" do
108
- capture_stdout { subject.generate }
109
-
110
- Dir.exist?(testing_dir("_site/drafts")).should be_true
111
- Dir[File.join(testing_dir("_site/drafts/*"))].size.should == subject.drafts.size
112
-
113
- Dir.exist?(testing_dir("_site/drafts/sample-draft")).should be_true
114
- Dir[File.join(testing_dir("_site/drafts/sample-draft"), "*.html")].size.should == 1
115
-
116
- d = Serif::Draft.from_slug(subject, "sample-draft")
117
- subject.private_url(d).should_not be_nil
118
-
119
- # absolute paths
120
- (subject.private_url(d) =~ /\A\/drafts\/#{d.slug}\/.*\z/).should be_true
121
-
122
- # 60 characters long (30 bytes as hex chars)
123
- (subject.private_url(d) =~ /\A\/drafts\/#{d.slug}\/[a-z0-9]{60}\z/).should be_true
124
-
125
- # does not create more than one
126
- capture_stdout { subject.generate }
127
- Dir[File.join(testing_dir("_site/drafts/sample-draft"), "*.html")].size.should == 1
128
- end
129
-
130
- context "for posts with an update: now header" do
131
- around :each do |example|
132
- begin
133
- d = Serif::Draft.new(subject)
134
- d.slug = "post-to-be-auto-updated"
135
- d.title = "Testing title"
136
- d.save("# some content")
137
- d.publish!
138
-
139
- @temporary_post = Serif::Post.new(subject, d.path)
140
- @temporary_post.autoupdate = true
141
- @temporary_post.save
142
-
143
- example.run
144
- ensure
145
- FileUtils.rm(@temporary_post.path)
146
- end
147
- end
148
-
149
- it "sets the updated header to the current time" do
150
- t = Time.now + 30
151
- Timecop.freeze(t) do
152
- capture_stdout { subject.generate }
153
- Serif::Post.from_basename(subject, @temporary_post.basename).updated.to_i.should == t.to_i
154
- end
155
- end
156
- end
157
-
158
- context "for drafts with a publish: now header" do
159
- before :each do
160
- @time = Time.utc(2012, 12, 21, 15, 30, 00)
161
-
162
- draft = Serif::Draft.new(subject)
163
- draft.slug = "post-to-be-published-on-generate"
164
- draft.title = "Some draft title"
165
- draft.autopublish = true
166
- draft.save("some content")
167
-
168
- @post = Serif::Draft.from_slug(subject, draft.slug)
169
- @post.should_not be_nil
170
-
171
- # verifies that the header has actually been written to the file, since
172
- # we round-trip the save and load.
173
- @post.autopublish?.should be_true
174
-
175
- # Site#generate creates a backup of the site directory in /tmp
176
- # and uses a timestamp, which is now fixed across all tests,
177
- # so we have to remove it first.
178
- FileUtils.rm_rf("/tmp/_site.2012-12-21-15-30-00")
179
-
180
- Timecop.freeze(@time)
181
- end
182
-
183
- after :each do
184
- Timecop.return
185
-
186
- # the generate processes creates its own set of instances, and we're
187
- # publishing a draft marked as autopublish, so our @post instance
188
- # has a #path value which is for the draft, not for the newly published
189
- # post. thus, we need to clobber.
190
- FileUtils.rm(*Dir[testing_dir("_posts/*-#{@post.slug}")])
191
- end
192
-
193
- it "places the file in the published posts folder" do
194
- capture_stdout { subject.generate }
195
- File.exist?(testing_dir("_site/test-blog/#{@post.slug}.html")).should be_true
196
- end
197
-
198
- it "marks the creation time as the current time" do
199
- capture_stdout { subject.generate }
200
- subject.posts.find { |p| p.slug == @post.slug }.created.to_i.should == @time.to_i
201
- end
202
- end
203
- end
204
- end
@@ -1,189 +0,0 @@
1
- require "test_helper"
2
-
3
- describe Serif::Site do
4
- subject do
5
- Serif::Site.new(testing_dir)
6
- end
7
-
8
- describe "#conflicts" do
9
- context "with no arguments" do
10
- it "is nil if there are no conflicts" do
11
- subject.conflicts.should be_nil
12
- end
13
-
14
- it "is a map of url => conflicts_array if there are conflicts" do
15
- d = Serif::Draft.new(subject)
16
- conflicting_post = subject.posts.first
17
- d.slug = conflicting_post.slug
18
- d.title = "Anything you like"
19
- d.save("# Some content")
20
-
21
- # need this to be true
22
- d.url.should == conflicting_post.url
23
-
24
- begin
25
- conflicts = subject.conflicts
26
- conflicts.should_not be_nil
27
- conflicts.class.should == Hash
28
- conflicts.size.should == 1
29
- conflicts.keys.should == [conflicting_post.url]
30
- conflicts[conflicting_post.url].size.should == 2
31
- ensure
32
- FileUtils.rm(d.path)
33
- end
34
- end
35
- end
36
-
37
- context "with an argument given" do
38
- it "is nil if there are no conflicts" do
39
- subject.conflicts(subject.drafts.sample).should be_nil
40
- subject.conflicts(subject.posts.sample).should be_nil
41
-
42
- d = Serif::Draft.new(subject)
43
- subject.conflicts(d).should be_nil
44
- end
45
-
46
- it "is an array of conflicting content if there are conflicts" do
47
- d = Serif::Draft.new(subject)
48
- conflicting_post = subject.posts.first
49
- d.slug = conflicting_post.slug
50
- d.title = "Anything you like"
51
- d.save("# Some content")
52
-
53
- # need this to be true
54
- d.url.should == conflicting_post.url
55
-
56
- begin
57
- conflicts = subject.conflicts(d)
58
- conflicts.should_not be_nil
59
- conflicts.class.should == Array
60
- conflicts.size.should == 2
61
- conflicts.each do |e|
62
- e.url.should == conflicting_post.url
63
- end
64
- ensure
65
- FileUtils.rm(d.path)
66
- end
67
- end
68
- end
69
- end
70
-
71
- describe "#source_directory" do
72
- it "should be sane" do
73
- subject.directory.should == File.join(File.dirname(__FILE__), "site_dir")
74
- end
75
- end
76
-
77
- describe "#posts" do
78
- it "is the number of posts in the site" do
79
- subject.posts.length.should == 5
80
- end
81
- end
82
-
83
- describe "#drafts" do
84
- it "is the number of drafts in the site" do
85
- subject.drafts.length.should == 2
86
- end
87
- end
88
-
89
- describe "#private_url" do
90
- it "returns nil for a draft without an existing file" do
91
- d = double("")
92
- d.stub(:slug) { "foo" }
93
- subject.private_url(d).should be_nil
94
- end
95
- end
96
-
97
- describe "#latest_update_time" do
98
- it "is the latest time that a post was updated" do
99
- subject.latest_update_time.should == Serif::Post.all(subject).max_by { |p| p.updated }.updated
100
- end
101
- end
102
-
103
- describe "#site_path" do
104
- it "should be relative, not absolute" do
105
- p = Pathname.new(subject.site_path("foo"))
106
- p.relative?.should be_true
107
- p.absolute?.should be_false
108
- end
109
-
110
- it "takes a string and prepends _site to that path" do
111
- %w[a b c d e f].each do |e|
112
- subject.site_path(e).should == "_site/#{e}"
113
- end
114
- end
115
- end
116
-
117
- describe "#config" do
118
- it "is a Serif::Config instance" do
119
- subject.config.class.should == Serif::Config
120
- end
121
-
122
- it "should have the permalink format available" do
123
- subject.config.permalink.should_not be_nil
124
- end
125
- end
126
-
127
- describe "#archives" do
128
- it "contains posts given in reverse chronological order" do
129
- archives = subject.archives
130
- archives[:posts].each_cons(2) do |a, b|
131
- (a.created >= b.created).should be_true
132
- end
133
-
134
- archives[:years].each do |year|
135
- year[:posts].each_cons(2) do |a, b|
136
- (a.created >= b.created).should be_true
137
- end
138
-
139
- year[:months].each do |month|
140
- month[:posts].each_cons(2) do |a, b|
141
- (a.created >= b.created).should be_true
142
- end
143
- end
144
- end
145
- end
146
- end
147
-
148
- describe "#to_liquid" do
149
- it "uses the value of #archives without modification" do
150
- subject.should_receive(:archives).once
151
- subject.to_liquid
152
- end
153
- end
154
-
155
- describe "#archive_url_for_date" do
156
- it "uses the archive URL format from the config to construct an archive URL string" do
157
- date = Date.parse("2012-01-02")
158
- subject.archive_url_for_date(date).should == "/test-archive/2012/01"
159
- end
160
- end
161
-
162
- describe "#bypass?" do
163
- it "is false if the filename has a .html extension" do
164
- subject.bypass?("foo.html").should be_false
165
- end
166
-
167
- it "is false if the filename has an .xml extension" do
168
- subject.bypass?("foo.xml").should be_false
169
- end
170
-
171
- it "is true if the filename is neither xml nor html by extension" do
172
- subject.bypass?("foo.css").should be_true
173
- end
174
- end
175
-
176
- describe "#tmp_path" do
177
- it "takes a string and prepends tmp/_site to that path" do
178
- %w[a b c d].each do |e|
179
- subject.tmp_path(e).should == "tmp/_site/#{e}"
180
- end
181
- end
182
-
183
- it "should be relative, not absolute" do
184
- p = Pathname.new(subject.tmp_path("foo"))
185
- p.absolute?.should be_false
186
- p.relative?.should be_true
187
- end
188
- end
189
- end
@@ -1,61 +0,0 @@
1
- require "simplecov"
2
-
3
- # if we're running on Travis, use Coveralls, otherwise
4
- # let us generate SimpleCov output as normal.
5
- if ENV["CI"]
6
- require "coveralls"
7
- SimpleCov.formatter = Coveralls::SimpleCov::Formatter
8
- end
9
-
10
- SimpleCov.start do
11
- add_filter "/test/"
12
- end
13
-
14
- # run tests in production mode so that file digests are enabled
15
- ENV["ENV"] = "production"
16
-
17
- # workaround checking. here before loading our application to ensure
18
- # we aren't testing against our own monkeypatches.
19
-
20
- describe "date 'now' patch" do
21
- # if this test fails, the monkey match on StandardFilters#date can be removed
22
- it "is necessary" do
23
- liquid_filter = Object.new
24
- liquid_filter.extend(Liquid::StandardFilters)
25
- (liquid_filter.date_orig("now", "%Y") rescue "").should_not == Time.now.year.to_s
26
- end
27
- end
28
-
29
- describe "curly quote patch" do
30
- # if this test fails, the workaround for the "markdown" filter can be removed
31
- it "is necessary" do
32
- renderer = Redcarpet::Markdown.new(Serif::MarkupRenderer)
33
- renderer.render("something's here").should_not include("something&rsquo;s here")
34
- end
35
- end
36
-
37
- require "serif"
38
- require "serif/commands"
39
- require "fileutils"
40
- require "pathname"
41
- require "time"
42
- require "date"
43
- require "timecop"
44
-
45
- def testing_dir(path = nil)
46
- full_path = File.join(File.dirname(__FILE__), "site_dir")
47
-
48
- path ? File.join(full_path, path) : full_path
49
- end
50
-
51
- def capture_stdout
52
- begin
53
- $orig_stdout = $stdout
54
- $stdout = StringIO.new
55
- yield
56
- $stdout.rewind
57
- return $stdout.string
58
- ensure
59
- $stdout = $orig_stdout
60
- end
61
- end