switzerland 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +7 -0
- data/README.md +180 -0
- data/bin/switz +127 -0
- data/features/1-publish-content.feature +45 -0
- data/features/2-manage-content.feature +17 -0
- data/features/3-format-content.feature +84 -0
- data/features/step_definitions/steps.rb +175 -0
- data/switzerland.gemspec +34 -0
- metadata +136 -0
data/LICENSE.txt
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright © 2012 Eric Lanehart
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
# ✚ Switzerland
|
2
|
+
|
3
|
+
- home to the Swiss Alps
|
4
|
+
- a great place to stash some cash
|
5
|
+
- eponymous graphic design: grids and Helvetica!
|
6
|
+
- the frickin’ birthplace of the world wide web
|
7
|
+
- famously ~ neutral ~
|
8
|
+
|
9
|
+
It’s also a static content generator written in Ruby. It’s like [Jekyll][jekyll] and [Middleman][middleman] in that it offers:
|
10
|
+
|
11
|
+
- Git-friendly file & folder-based content management
|
12
|
+
- [Markdown][markdown] formatting via [Kramdown][kramdown]
|
13
|
+
- [Fenced code blocks][code-blocks] with optional syntax highlighting
|
14
|
+
- YAML front matter
|
15
|
+
|
16
|
+
Missing is anything involving templates, pages, or assets. Switzerland’s output is primarily JSON, intended for consumption client or server-side. Any platform capable of making a GET request is `OK 200`. Publish content to GitHub or a Dropbox and access it from your app, website, or even a web browser.
|
17
|
+
|
18
|
+
|
19
|
+
Usage
|
20
|
+
--------------------------------------------------------------------------------
|
21
|
+
|
22
|
+
~~~
|
23
|
+
✚ gem install switzerland
|
24
|
+
✚ switz
|
25
|
+
~~~
|
26
|
+
|
27
|
+
If no arguments are provided Switzerland will inspect the local directory recursively and:
|
28
|
+
|
29
|
+
- Duplicate your content’s folder structure wherever the published content will live
|
30
|
+
- Pass any files ending in `.md` or `.markdown` through Kramdown
|
31
|
+
- Generate and save “published” HTML and JSON versions of each Markdown file
|
32
|
+
- Copy any image files alongside generated JSON/HTML
|
33
|
+
|
34
|
+
### Specify a Source
|
35
|
+
|
36
|
+
One or more source files and folders can be specified just like [cp][man-cp]. If source content is specified a publishing destination must also be provided.
|
37
|
+
|
38
|
+
~~~
|
39
|
+
✚ switz cheese overview.md published
|
40
|
+
~~~
|
41
|
+
|
42
|
+
The above command would create:
|
43
|
+
|
44
|
+
~~~
|
45
|
+
published/overview.html
|
46
|
+
published/overview.json
|
47
|
+
published/cheese/emmentaler.html
|
48
|
+
published/cheese/emmentaler.json
|
49
|
+
published/cheese/forked/jarlsberg.html
|
50
|
+
published/cheese/forked/jarlsberg.json
|
51
|
+
published/cheese/forked/leerdammer.html
|
52
|
+
published/cheese/forked/leerdammer.json
|
53
|
+
published/cheese/forked/maasdam.html
|
54
|
+
published/cheese/forked/maasdam.json
|
55
|
+
~~~
|
56
|
+
|
57
|
+
### Specify a Publishing Destination
|
58
|
+
|
59
|
+
If no arguments are provided then published content will be automatically saved into a relative directory named `published`. This may be overridden with an argument that either appears after specified source paths or by itself as the only argument.
|
60
|
+
|
61
|
+
~~~
|
62
|
+
✚ switz cheese.md public
|
63
|
+
~~~
|
64
|
+
|
65
|
+
···
|
66
|
+
|
67
|
+
~~~
|
68
|
+
public/cheese.html
|
69
|
+
public/cheese.json
|
70
|
+
~~~
|
71
|
+
|
72
|
+
|
73
|
+
Demo
|
74
|
+
--------------------------------------------------------------------------------
|
75
|
+
|
76
|
+
~~~
|
77
|
+
✚ echo "# Hallo" >> hallo.md
|
78
|
+
✚ switz hallo.md published
|
79
|
+
✚ ls -1 published
|
80
|
+
hallo.html
|
81
|
+
hallo.json
|
82
|
+
~~~
|
83
|
+
|
84
|
+
#### hallo.html
|
85
|
+
|
86
|
+
~~~ html
|
87
|
+
<h1>Hallo</h1>
|
88
|
+
~~~
|
89
|
+
|
90
|
+
#### hallo.json
|
91
|
+
|
92
|
+
~~~ javascript
|
93
|
+
{
|
94
|
+
"anchors": [{
|
95
|
+
"tag": "h1",
|
96
|
+
"text": "Hallo",
|
97
|
+
"anchor": "toc-hallo"
|
98
|
+
}],
|
99
|
+
"slug": "hallo",
|
100
|
+
"body": "<h1 id=\"toc-hallo\">Hallo</h1>"
|
101
|
+
}
|
102
|
+
~~~
|
103
|
+
|
104
|
+
|
105
|
+
Syntax Highlighting
|
106
|
+
--------------------------------------------------------------------------------
|
107
|
+
|
108
|
+
Use [fenced code blocks][code-blocks] to easily reference example code. The following format is also conveniently recognized by [GitHub Flavored Markdown][gfm]:
|
109
|
+
|
110
|
+
~~~ javascript
|
111
|
+
alert('hallo!');
|
112
|
+
~~~
|
113
|
+
|
114
|
+
Kramdown generates the following markup from the example above.
|
115
|
+
|
116
|
+
~~~~~~~ html
|
117
|
+
<pre>
|
118
|
+
<code class="language-javascript">
|
119
|
+
alert('hallo!');
|
120
|
+
</code>
|
121
|
+
</pre>
|
122
|
+
~~~~~~~
|
123
|
+
|
124
|
+
If a language is specified in the opening fence it is used to generate a class [as recommended][code-class]. This is useful when using client-slide libraries such as [google-code-prettify][prettify] and [Prism.js][prism].
|
125
|
+
|
126
|
+
#### Go automatic with CodeRay
|
127
|
+
|
128
|
+
If the [CodeRay][coderay] gem is installed the above example would be automatically converted into this markup, with classes to select & style:
|
129
|
+
|
130
|
+
~~~~~~~ html
|
131
|
+
<div>
|
132
|
+
alert(<span class="string"><span class="delimiter">'</span><span class="content">hallo!</span><span class="delimiter">'</span></span>);
|
133
|
+
</div>
|
134
|
+
~~~~~~~
|
135
|
+
|
136
|
+
|
137
|
+
YAML Front Matter
|
138
|
+
--------------------------------------------------------------------------------
|
139
|
+
|
140
|
+
Provide key/value pairs in front of your Markdown content like so and they will be mixed into the published JSON:
|
141
|
+
|
142
|
+
```
|
143
|
+
---
|
144
|
+
layout: three-column
|
145
|
+
title: Switzerland Ain’t a Static Site Generator
|
146
|
+
---
|
147
|
+
|
148
|
+
# SAASSG
|
149
|
+
```
|
150
|
+
|
151
|
+
···
|
152
|
+
|
153
|
+
~~~ javascript
|
154
|
+
{
|
155
|
+
"layout": "three-column",
|
156
|
+
"title": "Switzerland Ain’t a Static Site Generator"
|
157
|
+
"slug": "switzerland-aint-a-static-site-generator",
|
158
|
+
"body": "<h1 id=\"toc-saassg\">SAASSG</h1>"
|
159
|
+
}
|
160
|
+
~~~
|
161
|
+
|
162
|
+
#### The following keys are reserved:
|
163
|
+
|
164
|
+
- `anchors`
|
165
|
+
- `body`
|
166
|
+
- `slug`
|
167
|
+
|
168
|
+
|
169
|
+
[man-cp]: http://ss64.com/osx/cp.html
|
170
|
+
[kramdown]: http://kramdown.rubyforge.org
|
171
|
+
[coderay]: http://coderay.rubychan.de
|
172
|
+
[markdown]: http://daringfireball.net/projects/markdown
|
173
|
+
[jekyll]: http://jekyllrb.com
|
174
|
+
[middleman]: http://middlemanapp.com
|
175
|
+
[phpmarkdownextra]: http://michelf.ca/projects/php-markdown/extra
|
176
|
+
[gfm]: http://github.github.com/github-flavored-markdown
|
177
|
+
[code-blocks]: http://kramdown.rubyforge.org/syntax.html#code-blocks
|
178
|
+
[code-class]: http://www.whatwg.org/specs/web-apps/current-work/multipage/text-level-semantics.html#the-code-element
|
179
|
+
[prism]: http://prismjs.com
|
180
|
+
[prettify]: http://code.google.com/p/google-code-prettify
|
data/bin/switz
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
require 'kramdown'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'active_support/core_ext'
|
7
|
+
require 'yaml'
|
8
|
+
require 'nokogiri'
|
9
|
+
|
10
|
+
# From http://stackoverflow.com/questions/2070010
|
11
|
+
|
12
|
+
def colorize(text, color_code) "\e[#{color_code}m#{text}\e[0m" end
|
13
|
+
|
14
|
+
def grey(text); colorize(text, 37); end
|
15
|
+
def green(text); colorize(text, 42); end
|
16
|
+
def red(text); colorize(text, 41); end
|
17
|
+
|
18
|
+
# Process Markdown with Kramdown & Nokogiri, generate HTML + JSON
|
19
|
+
|
20
|
+
def publish_content(source_path, destination_path)
|
21
|
+
|
22
|
+
image_filetypes = ['.jpg','.png','.gif','.svg']
|
23
|
+
markdown_filetypes = ['.md','.markdown']
|
24
|
+
|
25
|
+
if image_filetypes.include? File.extname(source_path)
|
26
|
+
|
27
|
+
destination_path = File.join destination_path, File.dirname(source_path)
|
28
|
+
FileUtils.cp source_path, destination_path
|
29
|
+
|
30
|
+
elsif markdown_filetypes.include? File.extname(source_path)
|
31
|
+
|
32
|
+
destination_path = File.join destination_path, File.dirname(source_path)
|
33
|
+
|
34
|
+
markdown_filename = File.basename( source_path, File.extname(source_path) )
|
35
|
+
markdown_file = ''
|
36
|
+
|
37
|
+
File.open(source_path, 'r').each { |line| markdown_file << line }
|
38
|
+
|
39
|
+
yaml_content = YAML.load( markdown_file.match(/\A(---\s*\n.*?\n?)^(---\s*$\n?)/m).to_s ) # RegEx by Derek Worthen (Middleman implementation)
|
40
|
+
html_content = Nokogiri::HTML.parse( Kramdown::Document.new(markdown_file.lines.to_a[0..-1].join, :auto_id_prefix => "toc-", :coderay_css => :class, :coderay_line_numbers => nil, :coderay_wrap => nil).to_html )
|
41
|
+
|
42
|
+
anchors = []
|
43
|
+
|
44
|
+
html_content.css('h1, h2, h3, h4, h5, h6').each do |heading|
|
45
|
+
next unless heading.attribute('id')
|
46
|
+
anchors.push({ 'tag' => heading.name, 'text' => heading.text, 'anchor' => heading.attribute('id').value })
|
47
|
+
end
|
48
|
+
|
49
|
+
json_content = {
|
50
|
+
:body => html_content.css('body').inner_html,
|
51
|
+
:slug => markdown_filename,
|
52
|
+
:anchors => anchors
|
53
|
+
}
|
54
|
+
|
55
|
+
json_content.merge( yaml_content ) if yaml_content
|
56
|
+
|
57
|
+
File.open(destination_path + '/' + markdown_filename + '.html', 'w') do |file|
|
58
|
+
file.write html_content.css('body').inner_html
|
59
|
+
file.close
|
60
|
+
end
|
61
|
+
|
62
|
+
File.open(destination_path + '/' + markdown_filename + '.json', 'w') do |file|
|
63
|
+
file.write Hash[json_content.to_a.reverse].to_json
|
64
|
+
file.close
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Print help to terminal if no arguments are provided
|
71
|
+
|
72
|
+
if ARGV.empty?
|
73
|
+
puts red " ✚ hallo!"
|
74
|
+
puts " switzerland works like this:"
|
75
|
+
puts grey " switz source_file_or_directory [published_directory]"
|
76
|
+
puts grey " switz source_file1 source_directory2 [published_directory]"
|
77
|
+
end
|
78
|
+
|
79
|
+
# Traverse content, generate published version
|
80
|
+
|
81
|
+
base_path = Dir.pwd
|
82
|
+
destination_path = ARGV.last || 'published'
|
83
|
+
destination_path = File.expand_path destination_path
|
84
|
+
|
85
|
+
if ARGV.length > 1
|
86
|
+
source_paths = ARGV[0..-2]
|
87
|
+
else
|
88
|
+
source_paths = [base_path]
|
89
|
+
end
|
90
|
+
|
91
|
+
if File.exists? destination_path
|
92
|
+
FileUtils.chdir destination_path
|
93
|
+
FileUtils.rm_rf Dir['**/**']
|
94
|
+
FileUtils.chdir base_path
|
95
|
+
else
|
96
|
+
FileUtils.mkdir_p destination_path
|
97
|
+
end
|
98
|
+
|
99
|
+
source_paths.each do |source_path|
|
100
|
+
next if source_path === destination_path
|
101
|
+
|
102
|
+
if File.exists?(source_path) && File.directory?(source_path)
|
103
|
+
FileUtils.chdir source_path
|
104
|
+
|
105
|
+
Dir['**/**'].sort.each do |source_path|
|
106
|
+
if File.directory?(source_path)
|
107
|
+
FileUtils.mkdir_p File.join( destination_path, source_path )
|
108
|
+
elsif File.size(source_path) > 0
|
109
|
+
FileUtils.mkdir_p File.dirname( File.join( destination_path, source_path ) )
|
110
|
+
publish_content(source_path, destination_path)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
elsif File.exists?(source_path) && File.size(source_path) > 0
|
115
|
+
FileUtils.chdir base_path
|
116
|
+
FileUtils.mkdir_p File.dirname( File.join(destination_path, source_path) )
|
117
|
+
|
118
|
+
publish_content(source_path, destination_path)
|
119
|
+
elsif ARGV.length > 1
|
120
|
+
puts red " ✚ error "
|
121
|
+
puts grey " " + source_path + " not found"
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
puts green " ✚ published! "
|
127
|
+
puts grey " " + destination_path
|
@@ -0,0 +1,45 @@
|
|
1
|
+
Feature: Publishing Content
|
2
|
+
As a writer,
|
3
|
+
I want to publish my content
|
4
|
+
So I can access and present it
|
5
|
+
|
6
|
+
Scenario: Prepare destination
|
7
|
+
|
8
|
+
Given a tree of folders
|
9
|
+
When I publish content
|
10
|
+
Then the destination will be created if it does not exist
|
11
|
+
And any contents will be emptied
|
12
|
+
Then that tree will be published into the destination
|
13
|
+
|
14
|
+
Scenario: Specify content sources
|
15
|
+
|
16
|
+
Given a tree of folders
|
17
|
+
When I specify one or more sources of content and a destination
|
18
|
+
Then only those sources will be published into the destination
|
19
|
+
|
20
|
+
Scenario: Specify a different destination
|
21
|
+
|
22
|
+
Given a tree of folders
|
23
|
+
When I publish content with a specified destination
|
24
|
+
Then the destination will be created if it does not exist
|
25
|
+
Then that tree will be published into the destination
|
26
|
+
And the destination will match the specified destination
|
27
|
+
|
28
|
+
Scenario: Provide content as JSON
|
29
|
+
|
30
|
+
Given a folder containing Markdown files with content such as this:
|
31
|
+
"""
|
32
|
+
The overriding design goal for Markdown’s formatting syntax is to make it as readable as possible. The idea is that a Markdown-formatted document should be publishable as-is, as plain text, without looking like it’s been marked up with tags or formatting instructions. While Markdown’s syntax has been influenced by several existing text-to-HTML filters, the single biggest source of inspiration for Markdown’s syntax is the format of plain text email.
|
33
|
+
"""
|
34
|
+
When I publish content
|
35
|
+
Then the content will be published as JSON
|
36
|
+
|
37
|
+
Scenario: Empty stub files exist
|
38
|
+
|
39
|
+
Given a folder containing empty stub files
|
40
|
+
And a folder containing Markdown files with content such as this:
|
41
|
+
"""
|
42
|
+
# Not Empty
|
43
|
+
"""
|
44
|
+
When I publish content
|
45
|
+
Then the other content will be published as JSON
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Feature: Manage Content
|
2
|
+
|
3
|
+
As a writer,
|
4
|
+
I want to manage my content with files & folders
|
5
|
+
So that I can use my own software for writing
|
6
|
+
|
7
|
+
Scenario: Support image “attachments”
|
8
|
+
|
9
|
+
Given a folder containing image files
|
10
|
+
When I publish content
|
11
|
+
Then the images will be included
|
12
|
+
|
13
|
+
Scenario: Preserve folder structure
|
14
|
+
|
15
|
+
Given a tree of folders
|
16
|
+
When I publish content
|
17
|
+
Then that tree will be preserved
|
@@ -0,0 +1,84 @@
|
|
1
|
+
Feature: Content Formatting
|
2
|
+
As a writer,
|
3
|
+
I want to format my content using Markdown and YAML
|
4
|
+
So I can better focus on what I’m saying
|
5
|
+
|
6
|
+
Scenario: Markdown Formatting
|
7
|
+
|
8
|
+
Given a folder containing Markdown files with content such as this:
|
9
|
+
"""
|
10
|
+
A First Level Header
|
11
|
+
====================
|
12
|
+
|
13
|
+
A Second Level Header
|
14
|
+
---------------------
|
15
|
+
|
16
|
+
Now is the time for all good men to come to
|
17
|
+
the aid of their country. This is just a
|
18
|
+
regular paragraph.
|
19
|
+
|
20
|
+
The quick brown fox jumped over the lazy
|
21
|
+
dog’s back.
|
22
|
+
|
23
|
+
### Header 3
|
24
|
+
|
25
|
+
> This is a blockquote.
|
26
|
+
>
|
27
|
+
> This is the second paragraph in the blockquote.
|
28
|
+
>
|
29
|
+
> ## This is an H2 in a blockquote
|
30
|
+
"""
|
31
|
+
When I publish content
|
32
|
+
Then the Markdown will be converted into HTML
|
33
|
+
|
34
|
+
Scenario: YAML Front Matter
|
35
|
+
|
36
|
+
Given a folder containing files with Markdown and YAML content such as this:
|
37
|
+
"""
|
38
|
+
---
|
39
|
+
layout: three-column
|
40
|
+
title: This is an example
|
41
|
+
---
|
42
|
+
|
43
|
+
A Second Level Header
|
44
|
+
---------------------
|
45
|
+
|
46
|
+
Now is the time for all good men to come to
|
47
|
+
the aid of their country. This is just a
|
48
|
+
regular paragraph.
|
49
|
+
"""
|
50
|
+
When I publish content
|
51
|
+
Then the content will be published as JSON
|
52
|
+
|
53
|
+
Scenario: Table of Contents
|
54
|
+
|
55
|
+
Given Markdown containing headings such as this:
|
56
|
+
"""
|
57
|
+
A First Level Header
|
58
|
+
====================
|
59
|
+
|
60
|
+
A Second Level Header
|
61
|
+
---------------------
|
62
|
+
|
63
|
+
### Header 3
|
64
|
+
"""
|
65
|
+
When I publish content
|
66
|
+
Then the Markdown will be converted into HTML
|
67
|
+
And each heading will be assigned a unique anchor
|
68
|
+
And the anchors will be published as JSON
|
69
|
+
|
70
|
+
Scenario: GitHub-style Fenced Code Blocks
|
71
|
+
|
72
|
+
Given GitHub-flavored Markdown containing fenced code blocks such as this:
|
73
|
+
"""
|
74
|
+
### Example
|
75
|
+
|
76
|
+
~~~ ruby
|
77
|
+
def say_hallo
|
78
|
+
puts 'Hallo!'
|
79
|
+
end
|
80
|
+
~~~
|
81
|
+
"""
|
82
|
+
When I publish content
|
83
|
+
Then the code block will be converted into HTML
|
84
|
+
And the syntax will be highlighted using Coderay if installed
|
@@ -0,0 +1,175 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
ROOT = FileUtils.pwd
|
6
|
+
TMP_TEST_PATH = File.join ROOT, 'test'
|
7
|
+
|
8
|
+
destination = 'published'
|
9
|
+
|
10
|
+
Before do
|
11
|
+
FileUtils.mkdir TMP_TEST_PATH unless File.exists? TMP_TEST_PATH
|
12
|
+
Dir.chdir TMP_TEST_PATH
|
13
|
+
end
|
14
|
+
|
15
|
+
After do
|
16
|
+
FileUtils.rm_rf TMP_TEST_PATH
|
17
|
+
end
|
18
|
+
|
19
|
+
Given /^a folder containing empty stub files$/ do
|
20
|
+
`touch test.md`
|
21
|
+
end
|
22
|
+
|
23
|
+
Given /^a folder containing image files$/ do
|
24
|
+
`curl -o test.jpg -s http://farm5.staticflickr.com/4027/4711833381_b444090dcc.jpg`
|
25
|
+
end
|
26
|
+
|
27
|
+
Given /^.*a folder containing Markdown files.*$/ do |example_markdown|
|
28
|
+
File.open('example.md', 'w') do |file|
|
29
|
+
file.write example_markdown
|
30
|
+
file.close
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
Given /^.*a folder containing files with Markdown and YAML content.*$/ do |example_content|
|
35
|
+
File.open('example.md', 'w') do |file|
|
36
|
+
file.write example_content
|
37
|
+
file.close
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
Given /^.*Markdown containing headings.*$/ do |example_markdown|
|
42
|
+
File.open('example.md', 'w') do |file|
|
43
|
+
file.write example_markdown
|
44
|
+
file.close
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
Given /^.*Markdown containing fenced code blocks.*$/ do |example_markdown|
|
49
|
+
File.open('example.md', 'w') do |file|
|
50
|
+
file.write example_markdown
|
51
|
+
file.close
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
Given /^a tree of folders$/ do
|
56
|
+
FileUtils.mkdir_p 'cheese/cows/swiss'
|
57
|
+
File.open('cows.md', 'w') do |file|
|
58
|
+
file.write '# Cow Milk'
|
59
|
+
file.close
|
60
|
+
end
|
61
|
+
File.open('cheese/cows/swiss/emmentaler.md', 'w') do |file|
|
62
|
+
file.write '# The Real Swiss Cheese'
|
63
|
+
file.close
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
When /^I publish content$/ do
|
68
|
+
destination = 'published'
|
69
|
+
|
70
|
+
`switz`
|
71
|
+
raise('Script not found') unless $?.success?
|
72
|
+
end
|
73
|
+
|
74
|
+
When /^I publish content with a specified destination$/ do
|
75
|
+
destination = 'somewhere/else'
|
76
|
+
|
77
|
+
`switz #{destination}`
|
78
|
+
raise('Script not found') unless $?.success?
|
79
|
+
end
|
80
|
+
|
81
|
+
Then /^the destination will be created if it does not exist$/ do
|
82
|
+
File.exists?( File.join destination ).should === true
|
83
|
+
end
|
84
|
+
|
85
|
+
And /^any contents will be emptied$/ do
|
86
|
+
(Dir['#{destination}/**/**'].empty?).should === true
|
87
|
+
end
|
88
|
+
|
89
|
+
Then /^the images will be included$/ do
|
90
|
+
File.exists?( File.join destination, 'test.jpg' ).should === true
|
91
|
+
end
|
92
|
+
|
93
|
+
Then /^.*that tree will be.*$/ do
|
94
|
+
File.exists?( File.join destination, 'cheese', 'cows', 'swiss', 'emmentaler.html' ).should === true
|
95
|
+
end
|
96
|
+
|
97
|
+
When /^I specify one or more sources of content and a destination$/ do
|
98
|
+
sources = 'cows.md cheese/cows'
|
99
|
+
destination = 'somewhere/else'
|
100
|
+
|
101
|
+
`switz #{sources} #{destination}`
|
102
|
+
raise('Script not found') unless $?.success?
|
103
|
+
end
|
104
|
+
|
105
|
+
Then /^only those sources will be published into the destination$/ do
|
106
|
+
File.exists?( File.join destination, 'cows.html' ).should === true
|
107
|
+
File.exists?( File.join destination, 'swiss', 'emmentaler.html' ).should === true
|
108
|
+
end
|
109
|
+
|
110
|
+
Then /^the Markdown will be converted into HTML$/ do
|
111
|
+
example_markdown = File.join destination, 'example.html'
|
112
|
+
|
113
|
+
File.exists?(example_markdown).should === true
|
114
|
+
|
115
|
+
File.open(example_markdown, 'r') do |content|
|
116
|
+
Nokogiri::HTML.parse(content).css('h1').length.should > 0
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
Then /^the code block will be converted into HTML$/ do
|
121
|
+
example_markdown = File.join destination, 'example.html'
|
122
|
+
|
123
|
+
File.exists?(example_markdown).should === true
|
124
|
+
|
125
|
+
File.open(example_markdown, 'r') do |content|
|
126
|
+
if Gem::Specification.find_all_by_name('coderay').empty?
|
127
|
+
Nokogiri::HTML.parse(content).css('code.language-ruby').length.should > 0
|
128
|
+
else
|
129
|
+
Nokogiri::HTML.parse(content).css('span.function').length.should > 0
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
Then /^the syntax will be highlighted using Coderay if installed$/ do
|
135
|
+
unless Gem::Specification.find_all_by_name('coderay').empty?
|
136
|
+
example_markdown = File.join destination, 'example.html'
|
137
|
+
|
138
|
+
File.exists?(example_markdown).should === true
|
139
|
+
|
140
|
+
File.open(example_markdown, 'r') do |content|
|
141
|
+
Nokogiri::HTML.parse(content).css('span[class]').length.should === 7
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
And /^each heading will be assigned a unique anchor$/ do
|
147
|
+
example_markdown = File.join destination, 'example.html'
|
148
|
+
|
149
|
+
File.open(example_markdown, 'r') do |content|
|
150
|
+
Nokogiri::HTML.parse(content).css('h1[id], h2[id], h3[id]').length.should === 3
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
Then /^.*content will be published as JSON.*$/ do
|
155
|
+
example_json = File.join destination, 'example.json'
|
156
|
+
|
157
|
+
File.open(example_json, 'r') do |content|
|
158
|
+
JSON.parse(content.read)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
And /^the anchors will be published as JSON$/ do
|
163
|
+
example_json = File.join destination, 'example.json'
|
164
|
+
|
165
|
+
File.open(example_json, 'r') do |content|
|
166
|
+
anchors = JSON.parse(content.read)['anchors']
|
167
|
+
anchors[0]['tag'].should === 'h1'
|
168
|
+
anchors[1]['tag'].should === 'h2'
|
169
|
+
anchors[2]['tag'].should === 'h3'
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
And /^the destination will match the specified destination$/ do
|
174
|
+
File.exists?( File.join destination, 'cheese', 'cows', 'swiss', 'emmentaler.html' ).should === true
|
175
|
+
end
|
data/switzerland.gemspec
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
Gem::Specification.new do |spec|
|
2
|
+
spec.name = "switzerland"
|
3
|
+
spec.license = 'MIT'
|
4
|
+
spec.version = '0.0.1'
|
5
|
+
spec.date = '2012-10-28'
|
6
|
+
spec.authors = ["Eric Lanehart"]
|
7
|
+
spec.email = ["pushred@gmail.com"]
|
8
|
+
spec.homepage = "https://github.com/pushred/switzerland"
|
9
|
+
spec.summary = "A static content generator."
|
10
|
+
spec.description = "Write in Markdown, publish as JSON and HTML, present with any platform that can GET."
|
11
|
+
spec.executables = ["switz"]
|
12
|
+
|
13
|
+
spec.required_ruby_version = '>= 1.8.1'
|
14
|
+
|
15
|
+
spec.add_dependency 'activesupport', '>= 3.2.6'
|
16
|
+
spec.add_dependency 'kramdown', '>= 0.14.0'
|
17
|
+
spec.add_dependency 'nokogiri', '>= 1.5.5'
|
18
|
+
|
19
|
+
spec.add_development_dependency 'cucumber', '>= 1.2.1'
|
20
|
+
spec.add_development_dependency 'json', '>= 1.7.3'
|
21
|
+
|
22
|
+
# = MANIFEST =
|
23
|
+
spec.files = %w[
|
24
|
+
LICENSE.txt
|
25
|
+
README.md
|
26
|
+
bin/switz
|
27
|
+
features/1-publish-content.feature
|
28
|
+
features/2-manage-content.feature
|
29
|
+
features/3-format-content.feature
|
30
|
+
features/step_definitions/steps.rb
|
31
|
+
switzerland.gemspec
|
32
|
+
]
|
33
|
+
# = MANIFEST =
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: switzerland
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Eric Lanehart
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-10-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activesupport
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.2.6
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.2.6
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: kramdown
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 0.14.0
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.14.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: nokogiri
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.5.5
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.5.5
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: cucumber
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 1.2.1
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.2.1
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: json
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 1.7.3
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.7.3
|
94
|
+
description: Write in Markdown, publish as JSON and HTML, present with any platform
|
95
|
+
that can GET.
|
96
|
+
email:
|
97
|
+
- pushred@gmail.com
|
98
|
+
executables:
|
99
|
+
- switz
|
100
|
+
extensions: []
|
101
|
+
extra_rdoc_files: []
|
102
|
+
files:
|
103
|
+
- LICENSE.txt
|
104
|
+
- README.md
|
105
|
+
- bin/switz
|
106
|
+
- features/1-publish-content.feature
|
107
|
+
- features/2-manage-content.feature
|
108
|
+
- features/3-format-content.feature
|
109
|
+
- features/step_definitions/steps.rb
|
110
|
+
- switzerland.gemspec
|
111
|
+
homepage: https://github.com/pushred/switzerland
|
112
|
+
licenses:
|
113
|
+
- MIT
|
114
|
+
post_install_message:
|
115
|
+
rdoc_options: []
|
116
|
+
require_paths:
|
117
|
+
- lib
|
118
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
119
|
+
none: false
|
120
|
+
requirements:
|
121
|
+
- - ! '>='
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: 1.8.1
|
124
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
125
|
+
none: false
|
126
|
+
requirements:
|
127
|
+
- - ! '>='
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: '0'
|
130
|
+
requirements: []
|
131
|
+
rubyforge_project:
|
132
|
+
rubygems_version: 1.8.24
|
133
|
+
signing_key:
|
134
|
+
specification_version: 3
|
135
|
+
summary: A static content generator.
|
136
|
+
test_files: []
|