contraption 0.2.0 → 0.3.0
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.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/README.md +21 -9
- data/Rakefile +4 -0
- data/benchmark.rb +8 -0
- data/bin/contraption +3 -5
- data/data/formats/landing_page.erb +22 -0
- data/data/formats/page.erb +22 -0
- data/data/formats/tag_cloud.erb +2 -0
- data/doc/classes.dot +118 -0
- data/doc/classes.png +0 -0
- data/features/{author_generates_site.feature → author_builds_site.feature} +0 -0
- data/features/repository_is_generated.feature +12 -0
- data/features/step_definitions/repository_generation_steps.rb +22 -0
- data/features/support/hooks.rb +1 -1
- data/lib/contraption.rb +2 -0
- data/lib/contraption/catalog.rb +3 -4
- data/lib/contraption/command_selector.rb +27 -0
- data/lib/contraption/diagnoser.rb +12 -0
- data/lib/contraption/generator.rb +35 -0
- data/lib/contraption/header.rb +1 -0
- data/lib/contraption/location.rb +12 -0
- data/lib/contraption/options.rb +4 -0
- data/lib/contraption/orchestrator.rb +54 -0
- data/lib/contraption/previewer.rb +28 -0
- data/lib/contraption/repository.rb +23 -2
- data/lib/contraption/runner.rb +5 -38
- data/lib/contraption/s3_uploader.rb +5 -3
- data/lib/contraption/site.rb +13 -0
- data/lib/contraption/tag_cloud.rb +1 -1
- data/lib/contraption/version.rb +1 -1
- data/spec/contraption/lib/catalog_spec.rb +0 -29
- metadata +19 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: db47cc8b0f80c9b56c5ce15af3e3d02201d2a3d2
|
4
|
+
data.tar.gz: 04dd17291329b373f04780fb7dccebde4abb1064
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5da3efa5065cd2a501f2d67f40af417db884f49549a3acd4319f9fd5fe27903a73debd3507b7e76a0fd753d1155d3ebe92d53a006c2798c493c1a6ad3252253a
|
7
|
+
data.tar.gz: 63e2c8eee732f05dc0d6b1a73f87a2495cc6a9085f8fe79dc6f02c6685582b3e80fdb987d5e6b9f6719d9d6bac84c47a3f7785015e721c0b4db21e093fdadaf0
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,24 +1,31 @@
|
|
1
1
|
# Contraption
|
2
2
|
|
3
|
-
|
3
|
+
__Contraption__ - *Informal, often facetious or derogatory, a device or contrivance, esp one considered strange, unnecessarily intricate, or improvised*
|
4
|
+
|
5
|
+
Contraption is a engine for managing static web content specifically targeted at blogging.
|
4
6
|
|
5
7
|
## Installation
|
6
8
|
|
7
|
-
|
9
|
+
$ gem install contraption
|
8
10
|
|
9
|
-
|
11
|
+
## Usage
|
10
12
|
|
11
|
-
|
13
|
+
__Step 1__: Generate new content directory.
|
12
14
|
|
13
|
-
|
15
|
+
bin/contraption generate -d my_content
|
14
16
|
|
15
|
-
|
17
|
+
__Step 2__: Write a new draft.
|
16
18
|
|
17
|
-
|
19
|
+
vim drafts/why_contraption_is_awesome.md
|
18
20
|
|
19
|
-
|
21
|
+
__Step 3__: Preview site.
|
22
|
+
|
23
|
+
bin/contraption preview -s my_content
|
24
|
+
|
25
|
+
__Step 4__: Build website.
|
26
|
+
|
27
|
+
bin/contraption -s my_content -d public_html
|
20
28
|
|
21
|
-
TODO: Write usage instructions here
|
22
29
|
|
23
30
|
## Development
|
24
31
|
[](https://codeclimate.com/github/rampantmonkey/contraption)
|
@@ -31,3 +38,8 @@ TODO: Write usage instructions here
|
|
31
38
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
32
39
|
4. Push to the branch (`git push origin my-new-feature`)
|
33
40
|
5. Create new Pull Request
|
41
|
+
|
42
|
+
If you are looking for ideas check out the [issue tracker](https://github.com/rampantmonkey/contraption/issues).
|
43
|
+
|
44
|
+
## License
|
45
|
+
Contraption is licensed under [The MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
CHANGED
data/benchmark.rb
ADDED
data/bin/contraption
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
3
|
+
require 'contraption/command_selector'
|
2
4
|
|
3
|
-
|
4
|
-
require 'contraption/runner'
|
5
|
-
|
6
|
-
options = Contraption::Options.new ARGV
|
7
|
-
Contraption::Runner.new(options).run!
|
5
|
+
Contraption::CommandSelector.go ARGV
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<!-- This is an example generated by Contraption
|
3
|
+
'landing_page.erb' represents the first page visitors will see when visiting your website.
|
4
|
+
Currently this is just a copy of 'page.rb', but it provides an opportunity for customization.
|
5
|
+
-->
|
6
|
+
|
7
|
+
<body>
|
8
|
+
<nav>
|
9
|
+
<ul>
|
10
|
+
<li><a href="">Home</a></li>
|
11
|
+
<li><a href="recent.html">Posts</a></li>
|
12
|
+
<li><a href="about.html">About Me</a></li>
|
13
|
+
</ul>
|
14
|
+
</nav>
|
15
|
+
<div class="content">
|
16
|
+
<!-- the 'context' tag below is the outlet which tells contraption to "insert text here". -->
|
17
|
+
<%= context %>
|
18
|
+
</div>
|
19
|
+
<footer>
|
20
|
+
<p>© Your Name Goes Here <%= Time.new.year %></p>
|
21
|
+
</footer>
|
22
|
+
</body>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<!-- This is an example generated by Contraption
|
3
|
+
'page.erb' represents the outermost layer of every page in the website.
|
4
|
+
You should put the structure of your page along with common elements (navagation, stylesheets, footer, etc.)
|
5
|
+
-->
|
6
|
+
|
7
|
+
<body>
|
8
|
+
<nav>
|
9
|
+
<ul>
|
10
|
+
<li><a href="">Home</a></li>
|
11
|
+
<li><a href="recent.html">Posts</a></li>
|
12
|
+
<li><a href="about.html">About Me</a></li>
|
13
|
+
</ul>
|
14
|
+
</nav>
|
15
|
+
<div class="content">
|
16
|
+
<!-- the 'context' tag below is the outlet which tells contraption to "insert text here". -->
|
17
|
+
<%= context %>
|
18
|
+
</div>
|
19
|
+
<footer>
|
20
|
+
<p>© Your Name Goes Here <%= Time.new.year %></p>
|
21
|
+
</footer>
|
22
|
+
</body>
|
data/doc/classes.dot
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
digraph G {
|
2
|
+
rankdir = "BT"
|
3
|
+
fontname = "Menlo-Regular"
|
4
|
+
fontsize = 8
|
5
|
+
|
6
|
+
node [
|
7
|
+
fontname = "Menlo-Regular"
|
8
|
+
fontsize = 8
|
9
|
+
shape = "record"
|
10
|
+
]
|
11
|
+
|
12
|
+
edge [
|
13
|
+
fontname = "Menlo-Regular"
|
14
|
+
fontsize = 8
|
15
|
+
]
|
16
|
+
|
17
|
+
// Classes
|
18
|
+
AwsS3 [ label="AWS::S3" ]
|
19
|
+
Catalog [ label = "{Catalog|+ initialize(items)\l+ \<\<(new_item)\l+ by_year()\l+ by_month()\l+ by_day()\l+ by_tag()\l+ each()\l+ most_recent(n=1)}" ]
|
20
|
+
CommandSelector [ label="{CommandSelector|+ go(args)}" ]
|
21
|
+
Day [ label="{Day}" ]
|
22
|
+
Diagnoser [ label="Diagnoser}" ]
|
23
|
+
Enumerable [ label = "{«module»\nEnumerable}" ]
|
24
|
+
Erb [ label = "{ERB}" ]
|
25
|
+
Formatter [ label = "{Formatter|+ initialize(location)\l+ formats()\l+ format(context,method=nil)}" ]
|
26
|
+
Generator [ label="{Generator}" ]
|
27
|
+
Header [ label = "{Header|+ from(string)|+ initialize(opts=\{\})\l+ filename(ext)\l+ new?\l+ update(new_opts=\{\})}" ]
|
28
|
+
HttpHandler [ label="{HttpHandler}" ]
|
29
|
+
Location [ label="{Location|+ initialize(path='.')\l+ list(ext=/.*/)\l+ path()\l+ cd(dir)\l+ create!()\l+ remove(file_name)\l+ ==(other)\l+ exist?\l+ executable?\l+ readable?\l+ read(file_name)\l+ writable?\l+ write(file_name, content)}" ]
|
30
|
+
Month [ label="{Month}" ]
|
31
|
+
Options [ label="{Options|+ initialize(args)}" ]
|
32
|
+
Optparse [ label="{OptionParser}" ]
|
33
|
+
Orchestrator [ label="{Orchestrator}" ]
|
34
|
+
Post [ label="{Post|+ build(data='')\l+ translate_markdown content|+ body()\l+ metadata\l+ publish(handlers=[])}" ]
|
35
|
+
Previewer [ label="{Previewer}" ]
|
36
|
+
RedcarpetMarkdown [ label="{Redcarpet::Markdown}" ]
|
37
|
+
RedcarpetRender [ label="{Redcarpet::Render}" ]
|
38
|
+
Repository [ label="{Repository|+ initialize(path)\l+ formatter()\l+ validate()\l+ valid_layout?\l+ construct_locations()\l+ drafts()\l+ posts()\l+ static_files()\l+ completed_drafts()\l+ finalize_completed_drafts(link_handlers=[])}" ]
|
39
|
+
RssBuilder [ label="{RSSBuilder|+ to_rss()\l+ initialize(posts)}" ]
|
40
|
+
RssMaker [ label="{RSS::Maker}" ]
|
41
|
+
Runner [ label="{Runner}" ]
|
42
|
+
S3Uploader [ label="{S3Uploader|+ initialize(connection_args=\{\},\r target_bucket,\r path)}" ]
|
43
|
+
Site [ label="{Site|+ initialize(location, posts, formats)\l+ build_all_individuals()\+ build_individual(i)\l+ build_month_pages()\l+ build_year_pages()\l+ build_tag_pages()\l+ build_recent()\l+ build_landing()\l+ build_tag_cloud()\l+ build_rss()\l+ root()}" ]
|
44
|
+
Tag [ label="{Tag|+ initialize(text)\l+ to_s()\l+ to_url()\l+ to_sym()}" ]
|
45
|
+
TagCloud [ label="{TagCloud|+ initialize(posts)\l+ to_s()}" ]
|
46
|
+
Yaml [ label="{YAML}" ]
|
47
|
+
Year [ label="{Year}" ]
|
48
|
+
|
49
|
+
// Protocols
|
50
|
+
edge [
|
51
|
+
arrowhead = "onormal"
|
52
|
+
style = "dashed"
|
53
|
+
]
|
54
|
+
|
55
|
+
ControlProtocol [ label="{«protocol»|+ run!\l+ initialize(options)}" ]
|
56
|
+
|
57
|
+
OptionProtocol [ label="{«protocol»|+ source\l+ destination}" ]
|
58
|
+
Options -> OptionProtocol
|
59
|
+
|
60
|
+
LinkHandler [ label="{«protocol»\nLinkHandler|+ protocol\l+ handle(link)}" ]
|
61
|
+
HttpHandler -> LinkHandler
|
62
|
+
S3Uploader -> LinkHandler
|
63
|
+
|
64
|
+
S3Credentials [ label="{«protocol»\nS3Credentials|+ s3_target_bucket\l+ s3_access_key_id\l+ s3_secret_access_key}" ]
|
65
|
+
Options -> S3Credentials
|
66
|
+
|
67
|
+
// Dependencies
|
68
|
+
edge [
|
69
|
+
arrowhead = "vee"
|
70
|
+
style = "dashed"
|
71
|
+
]
|
72
|
+
|
73
|
+
Catalog -> Day
|
74
|
+
Catalog -> Month
|
75
|
+
Catalog -> Year
|
76
|
+
CommandSelector -> Diagnoser
|
77
|
+
CommandSelector -> Generator
|
78
|
+
CommandSelector -> Options
|
79
|
+
CommandSelector -> Previewer
|
80
|
+
CommandSelector -> Runner
|
81
|
+
Formatter -> Erb
|
82
|
+
Options -> Location
|
83
|
+
Options -> Optparse
|
84
|
+
Options -> Yaml
|
85
|
+
Orchestrator -> HttpHandler
|
86
|
+
Orchestrator -> OptionProtocol
|
87
|
+
Orchestrator -> Repository
|
88
|
+
Orchestrator -> Site
|
89
|
+
Post -> Header
|
90
|
+
Post -> LinkHandler
|
91
|
+
Post -> RedcarpetMarkdown
|
92
|
+
Post -> RedcarpetRender
|
93
|
+
Repository -> Catalog
|
94
|
+
Repository -> Formatter
|
95
|
+
Repository -> Post
|
96
|
+
RssBuilder -> RssMaker
|
97
|
+
Runner -> S3Credentials
|
98
|
+
Runner -> S3Uploader
|
99
|
+
S3Uploader -> AwsS3
|
100
|
+
S3Uploader -> S3Credentials
|
101
|
+
Site -> RssBuilder
|
102
|
+
Site -> Tag
|
103
|
+
Site -> TagCloud
|
104
|
+
TagCloud -> Tag
|
105
|
+
|
106
|
+
// Inheritance
|
107
|
+
edge [
|
108
|
+
arrowhead = "onormal"
|
109
|
+
style = "solid"
|
110
|
+
]
|
111
|
+
|
112
|
+
Catalog -> Enumerable
|
113
|
+
Diagnoser -> ControlProtocol
|
114
|
+
Generator -> ControlProtocol
|
115
|
+
Orchestrator -> ControlProtocol
|
116
|
+
Previewer -> Orchestrator
|
117
|
+
Runner -> Orchestrator
|
118
|
+
}
|
data/doc/classes.png
ADDED
Binary file
|
File without changes
|
@@ -0,0 +1,12 @@
|
|
1
|
+
Feature: Repository is generated
|
2
|
+
|
3
|
+
As a new user
|
4
|
+
I want to create a valid directory structure
|
5
|
+
That will serve as input to Contraption
|
6
|
+
And include example template to help get started
|
7
|
+
|
8
|
+
Scenario: generate repository
|
9
|
+
Given I have a writeable directory
|
10
|
+
When I run contraption generate
|
11
|
+
Then I should have a valid project
|
12
|
+
And contraption should accept the generated repository as input
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative '../../lib/contraption/location'
|
2
|
+
require_relative '../../lib/contraption/repository'
|
3
|
+
require_relative '../../lib/contraption/command_selector'
|
4
|
+
|
5
|
+
Given(/^I have a writeable directory$/) do
|
6
|
+
@target_dir = 'new_repository'
|
7
|
+
FileUtils.rm_r @target_dir if File.exist? @target_dir
|
8
|
+
expect(Dir.mkdir(@target_dir)).to eq 0
|
9
|
+
end
|
10
|
+
|
11
|
+
When(/^I run contraption generate$/) do
|
12
|
+
Contraption::CommandSelector.go ['generate', '-d', @target_dir]
|
13
|
+
end
|
14
|
+
|
15
|
+
Then(/^I should have a valid project$/) do
|
16
|
+
path = Contraption::Location.new @target_dir
|
17
|
+
expect{Contraption::Repository.new path}.not_to raise_error
|
18
|
+
end
|
19
|
+
|
20
|
+
Then(/^contraption should accept the generated repository as input$/) do
|
21
|
+
expect{Contraption::CommandSelector.go ['-s', @target_dir, '-d', @target_dir + 'output']}.not_to raise_error
|
22
|
+
end
|
data/features/support/hooks.rb
CHANGED
data/lib/contraption.rb
CHANGED
@@ -3,6 +3,8 @@ require "contraption/post"
|
|
3
3
|
require "contraption/header"
|
4
4
|
require "contraption/catalog"
|
5
5
|
require "contraption/location"
|
6
|
+
require "contraption/orchestrator"
|
7
|
+
require "contraption/previewer"
|
6
8
|
require "contraption/runner"
|
7
9
|
require "contraption/tag"
|
8
10
|
require "contraption/tag_cloud"
|
data/lib/contraption/catalog.rb
CHANGED
@@ -27,10 +27,9 @@ module Contraption
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def by_tag
|
30
|
-
all(:tags).
|
31
|
-
|
32
|
-
|
33
|
-
end
|
30
|
+
tags = all(:tags).uniq{|t| t.to_url}
|
31
|
+
items.each_with_object(Hash.new {|h,k| h[k] = []}) do |item, result|
|
32
|
+
item.tags.each{|t| result[t.to_url] << item}
|
34
33
|
end
|
35
34
|
end
|
36
35
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative 'diagnoser'
|
2
|
+
require_relative 'generator'
|
3
|
+
require_relative 'options'
|
4
|
+
require_relative 'runner'
|
5
|
+
require_relative 'previewer'
|
6
|
+
|
7
|
+
module Contraption
|
8
|
+
class CommandSelector
|
9
|
+
class << self
|
10
|
+
def go args
|
11
|
+
case args.first
|
12
|
+
when 'diagnose'
|
13
|
+
args.shift
|
14
|
+
Diagnoser
|
15
|
+
when 'generate'
|
16
|
+
args.shift
|
17
|
+
Generator
|
18
|
+
when 'preview'
|
19
|
+
args.shift
|
20
|
+
Previewer
|
21
|
+
else
|
22
|
+
Runner
|
23
|
+
end.send("new", Options.new(args)).run!
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Contraption
|
2
|
+
class Generator
|
3
|
+
def initialize args
|
4
|
+
@options = args
|
5
|
+
end
|
6
|
+
|
7
|
+
def run!
|
8
|
+
directories = ['drafts', 'posts']
|
9
|
+
directories.each do |d|
|
10
|
+
destination.cd d
|
11
|
+
end
|
12
|
+
|
13
|
+
init_git
|
14
|
+
copy_example_files
|
15
|
+
make_initial_commit
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def destination
|
20
|
+
@options.destination
|
21
|
+
end
|
22
|
+
|
23
|
+
def init_git
|
24
|
+
`git init #{destination.path}`
|
25
|
+
end
|
26
|
+
|
27
|
+
def copy_example_files
|
28
|
+
`cp -r data/* #{destination.path}`
|
29
|
+
end
|
30
|
+
|
31
|
+
def make_initial_commit
|
32
|
+
`cd #{destination.path}; git add --all .; git commit -m 'Generated input for Contraption static site generator'`
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/contraption/header.rb
CHANGED
data/lib/contraption/location.rb
CHANGED
@@ -16,10 +16,18 @@ module Contraption
|
|
16
16
|
.map{ |f| f.basename.to_s }
|
17
17
|
end
|
18
18
|
|
19
|
+
def entries
|
20
|
+
pn.entries.map{|e| e.expand_path(pn) }
|
21
|
+
end
|
22
|
+
|
19
23
|
def path
|
20
24
|
pn.to_s
|
21
25
|
end
|
22
26
|
|
27
|
+
def to_s
|
28
|
+
pn.expand_path.to_s
|
29
|
+
end
|
30
|
+
|
23
31
|
def read file_name
|
24
32
|
complete_name = pn+file_name
|
25
33
|
return :file_does_not_exist unless complete_name.exist?
|
@@ -29,6 +37,10 @@ module Contraption
|
|
29
37
|
complete_name.open("r") { |f| yield f }
|
30
38
|
end
|
31
39
|
|
40
|
+
def destroy
|
41
|
+
FileUtils.rm_rf pn.expand_path
|
42
|
+
end
|
43
|
+
|
32
44
|
def cd directory
|
33
45
|
l = Location.new(pn+directory)
|
34
46
|
l.create! unless l.pn.directory?
|
data/lib/contraption/options.rb
CHANGED
@@ -36,6 +36,10 @@ module Contraption
|
|
36
36
|
opts.on("-d", "--destination path", "Path to destination") do |path|
|
37
37
|
@values[:destination] = Location.new path
|
38
38
|
end
|
39
|
+
opts.on("-h", "--help") do
|
40
|
+
puts opts
|
41
|
+
exit
|
42
|
+
end
|
39
43
|
opts.on("-s", "--source path", "Path to source") do |path|
|
40
44
|
@values[:source] = Location.new path
|
41
45
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require_relative 'repository'
|
2
|
+
require_relative 'site'
|
3
|
+
require_relative 'http_handler'
|
4
|
+
|
5
|
+
module Contraption
|
6
|
+
class Orchestrator
|
7
|
+
def initialize options
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def run!
|
12
|
+
source.finalize_completed_drafts handlers
|
13
|
+
site.build_all_individuals
|
14
|
+
site.build_month_pages
|
15
|
+
site.build_year_pages
|
16
|
+
site.build_tag_pages
|
17
|
+
site.build_tag_cloud
|
18
|
+
site.build_recent
|
19
|
+
site.build_landing
|
20
|
+
site.build_rss
|
21
|
+
site.build_archive_navigation
|
22
|
+
copy_static_files
|
23
|
+
|
24
|
+
post_run
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def site
|
29
|
+
@site ||= Site.new @options.destination, posts, formatter
|
30
|
+
end
|
31
|
+
|
32
|
+
def source
|
33
|
+
raise "Not implemented"
|
34
|
+
end
|
35
|
+
|
36
|
+
def post_run; end
|
37
|
+
|
38
|
+
def formatter
|
39
|
+
@formatter ||= source.formatter
|
40
|
+
end
|
41
|
+
|
42
|
+
def posts
|
43
|
+
@posts ||= source.posts
|
44
|
+
end
|
45
|
+
|
46
|
+
def copy_static_files
|
47
|
+
`cp -r #{source.static_file_path}/* #{site.root}` unless (Dir[source.static_file_path.to_s + "/*"]).length == 0
|
48
|
+
end
|
49
|
+
|
50
|
+
def handlers
|
51
|
+
[ HttpHandler.new ]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative 'orchestrator'
|
2
|
+
|
3
|
+
module Contraption
|
4
|
+
class Previewer < Orchestrator
|
5
|
+
PORT = 9009
|
6
|
+
|
7
|
+
def post_run
|
8
|
+
trap("INT") { cleanup }
|
9
|
+
spawn_server
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
def source
|
14
|
+
@source ||= Repository.new(@options.source).clone
|
15
|
+
end
|
16
|
+
|
17
|
+
def cleanup
|
18
|
+
puts "\nremoving temporary files and shutting down server"
|
19
|
+
source.destroy
|
20
|
+
site.location.destroy
|
21
|
+
end
|
22
|
+
|
23
|
+
def spawn_server
|
24
|
+
puts "Previewing site on http://localhost:#{PORT}"
|
25
|
+
`ruby -run -e httpd #{site.root} -p #{PORT} &> /dev/null`
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -13,6 +13,16 @@ module Contraption
|
|
13
13
|
@formatter = Formatter.new @formats_source
|
14
14
|
end
|
15
15
|
|
16
|
+
def clone
|
17
|
+
new_path = @path.cd "../.tmp_#{Time.now.to_i}"
|
18
|
+
`cp -r #{@path.path}/* #{new_path.path}`
|
19
|
+
Repository.new new_path
|
20
|
+
end
|
21
|
+
|
22
|
+
def destroy
|
23
|
+
@path.destroy
|
24
|
+
end
|
25
|
+
|
16
26
|
def validate
|
17
27
|
raise "Invalid source directory structure in #{@path}" unless valid_layout?
|
18
28
|
end
|
@@ -26,13 +36,24 @@ module Contraption
|
|
26
36
|
end
|
27
37
|
|
28
38
|
def posts
|
29
|
-
Catalog.new( @posts_source.list.map
|
39
|
+
Catalog.new( @posts_source.list.map do |p|
|
40
|
+
begin
|
41
|
+
Post.build(@posts_source.read p)
|
42
|
+
rescue ArgumentError => e
|
43
|
+
STDERR.puts "Invalid post #{p}"
|
44
|
+
end
|
45
|
+
end.select{|p| p.title != ''}
|
46
|
+
)
|
30
47
|
end
|
31
48
|
|
32
|
-
def
|
49
|
+
def static_file_path
|
33
50
|
@static_source.path
|
34
51
|
end
|
35
52
|
|
53
|
+
def static_files
|
54
|
+
@static_source.entries
|
55
|
+
end
|
56
|
+
|
36
57
|
def completed_drafts
|
37
58
|
drafts.map{|draft| [draft, @drafts_source.read(draft)]}
|
38
59
|
.each_with_object([]) do |draft, result|
|
data/lib/contraption/runner.rb
CHANGED
@@ -1,60 +1,27 @@
|
|
1
|
-
require_relative '
|
2
|
-
require_relative 'site'
|
1
|
+
require_relative 'orchestrator'
|
3
2
|
require_relative 's3_uploader'
|
4
|
-
require_relative 'http_handler'
|
5
3
|
|
6
4
|
module Contraption
|
7
|
-
class Runner
|
5
|
+
class Runner < Orchestrator
|
8
6
|
def initialize options
|
9
7
|
@options = options
|
10
8
|
end
|
11
9
|
|
12
|
-
def run!
|
13
|
-
source.finalize_completed_drafts handlers
|
14
|
-
site.build_all_individuals
|
15
|
-
site.build_month_pages
|
16
|
-
site.build_year_pages
|
17
|
-
site.build_tag_pages
|
18
|
-
site.build_tag_cloud
|
19
|
-
site.build_recent
|
20
|
-
site.build_landing
|
21
|
-
site.build_rss
|
22
|
-
copy_static_files
|
23
|
-
end
|
24
|
-
|
25
10
|
private
|
26
|
-
def formatter
|
27
|
-
@formatter ||= source.formatter
|
28
|
-
end
|
29
|
-
|
30
|
-
def posts
|
31
|
-
@posts ||= source.posts
|
32
|
-
end
|
33
|
-
|
34
|
-
def site
|
35
|
-
@site ||= Site.new @options.destination, posts, formatter
|
36
|
-
end
|
37
|
-
|
38
11
|
def source
|
39
12
|
@source ||= Repository.new @options.source
|
40
13
|
end
|
41
14
|
|
42
|
-
def copy_static_files
|
43
|
-
`cp -r #{source.static_files}/* #{site.root}` unless (Dir[source.static_files.to_s + "/*"]).length == 0
|
44
|
-
end
|
45
|
-
|
46
15
|
def handlers
|
16
|
+
h = super
|
47
17
|
if @options.s3_access_key_id
|
48
|
-
|
49
|
-
HttpHandler.new,
|
18
|
+
h <<
|
50
19
|
S3Uploader.new({access_key_id: @options.s3_access_key_id,
|
51
20
|
secret_access_key: @options.s3_secret_access_key},
|
52
21
|
@options.s3_target_bucket,
|
53
22
|
@options.source)
|
54
|
-
]
|
55
|
-
else
|
56
|
-
[ HttpHandler.new]
|
57
23
|
end
|
24
|
+
h
|
58
25
|
end
|
59
26
|
end
|
60
27
|
end
|
@@ -16,14 +16,16 @@ module Contraption
|
|
16
16
|
def handle request
|
17
17
|
local_path = Pathname.new(@path.path) + request.last
|
18
18
|
if local_path.exist?
|
19
|
-
|
20
|
-
|
19
|
+
remote_path = "#{Time.now.year}" + "/#{"%02d" % Time.now.mon}/" + request.last.split('/').last
|
20
|
+
upload local_path, remote_path
|
21
|
+
["http:", "#{@target_bucket}/#{remote_path}"]
|
21
22
|
else
|
22
|
-
raise "#{
|
23
|
+
raise "#{local_path.expand_path} does not exist"
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
26
27
|
def upload local_path, remote_path
|
28
|
+
puts "Uploading #{local_path} to #{remote_path}"
|
27
29
|
AWS::S3::S3Object.store(remote_path, open(local_path), @target_bucket, :access => :public_read, 'Cache-Control' => 'max-age=3136000')
|
28
30
|
end
|
29
31
|
end
|
data/lib/contraption/site.rb
CHANGED
@@ -55,10 +55,23 @@ module Contraption
|
|
55
55
|
@location.write 'rss', feed
|
56
56
|
end
|
57
57
|
|
58
|
+
def build_archive_navigation
|
59
|
+
content = @posts.by_month
|
60
|
+
.keys
|
61
|
+
.sort_by{|m| m.year*12 + m.month}
|
62
|
+
.map{|m| %Q{<a class="indivisible" href="#{m.year}/#{"%02d" % m.month}">#{Date::ABBR_MONTHNAMES[m.month]} #{m.year}</a>}}
|
63
|
+
.join("\n")
|
64
|
+
write_as_page content, @location, 'archive.html'
|
65
|
+
end
|
66
|
+
|
58
67
|
def root
|
59
68
|
@location.path
|
60
69
|
end
|
61
70
|
|
71
|
+
def location
|
72
|
+
@location
|
73
|
+
end
|
74
|
+
|
62
75
|
private
|
63
76
|
def build collection
|
64
77
|
Array(collection).map {|p| @formats.format p}.join
|
data/lib/contraption/version.rb
CHANGED
@@ -69,35 +69,6 @@ module Contraption
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
-
context "tag grouping" do
|
73
|
-
let(:item_1) { stub(tags: %w[a b c]) }
|
74
|
-
let(:item_2) { stub(tags: [])}
|
75
|
-
let(:item_3) { stub(tags: %w[a d]) }
|
76
|
-
let(:item_4) { stub(tags: %w[b c d]) }
|
77
|
-
let(:item_5) { stub(tags: %w[c e]) }
|
78
|
-
let(:catalog) { Catalog.new [item_1, item_2, item_3, item_4, item_5] }
|
79
|
-
|
80
|
-
it "groups all items tagged with 'a'" do
|
81
|
-
catalog.by_tag[:a].should eq [item_1, item_3]
|
82
|
-
end
|
83
|
-
|
84
|
-
it "groups all items tagged with 'b'" do
|
85
|
-
catalog.by_tag[:b].should eq [item_1, item_4]
|
86
|
-
end
|
87
|
-
|
88
|
-
it "groups all items tagged with 'c'" do
|
89
|
-
catalog.by_tag[:c].should eq [item_1, item_4, item_5]
|
90
|
-
end
|
91
|
-
|
92
|
-
it "groups all items tagged with 'd'" do
|
93
|
-
catalog.by_tag[:d].should eq [item_3, item_4]
|
94
|
-
end
|
95
|
-
|
96
|
-
it "groups all items tagged with 'e'" do
|
97
|
-
catalog.by_tag[:e].should eq [item_5]
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
72
|
it "includes enumerable" do
|
102
73
|
Catalog.included_modules.should include Enumerable
|
103
74
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: contraption
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Casey Robinson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-02-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -122,22 +122,35 @@ files:
|
|
122
122
|
- LICENSE.txt
|
123
123
|
- README.md
|
124
124
|
- Rakefile
|
125
|
+
- benchmark.rb
|
125
126
|
- bin/contraption
|
126
127
|
- contraption.gemspec
|
128
|
+
- data/formats/landing_page.erb
|
129
|
+
- data/formats/page.erb
|
130
|
+
- data/formats/tag_cloud.erb
|
131
|
+
- doc/classes.dot
|
132
|
+
- doc/classes.png
|
133
|
+
- features/author_builds_site.feature
|
127
134
|
- features/author_finalizes_draft.feature
|
128
|
-
- features/
|
135
|
+
- features/repository_is_generated.feature
|
129
136
|
- features/step_definitions/author_steps.rb
|
137
|
+
- features/step_definitions/repository_generation_steps.rb
|
130
138
|
- features/support/env.rb
|
131
139
|
- features/support/example_inputs.rb
|
132
140
|
- features/support/hooks.rb
|
133
141
|
- lib/contraption.rb
|
134
142
|
- lib/contraption/catalog.rb
|
143
|
+
- lib/contraption/command_selector.rb
|
144
|
+
- lib/contraption/diagnoser.rb
|
135
145
|
- lib/contraption/formatter.rb
|
146
|
+
- lib/contraption/generator.rb
|
136
147
|
- lib/contraption/header.rb
|
137
148
|
- lib/contraption/http_handler.rb
|
138
149
|
- lib/contraption/location.rb
|
139
150
|
- lib/contraption/options.rb
|
151
|
+
- lib/contraption/orchestrator.rb
|
140
152
|
- lib/contraption/post.rb
|
153
|
+
- lib/contraption/previewer.rb
|
141
154
|
- lib/contraption/repository.rb
|
142
155
|
- lib/contraption/rss_builder.rb
|
143
156
|
- lib/contraption/runner.rb
|
@@ -182,9 +195,11 @@ signing_key:
|
|
182
195
|
specification_version: 4
|
183
196
|
summary: Static site generator
|
184
197
|
test_files:
|
198
|
+
- features/author_builds_site.feature
|
185
199
|
- features/author_finalizes_draft.feature
|
186
|
-
- features/
|
200
|
+
- features/repository_is_generated.feature
|
187
201
|
- features/step_definitions/author_steps.rb
|
202
|
+
- features/step_definitions/repository_generation_steps.rb
|
188
203
|
- features/support/env.rb
|
189
204
|
- features/support/example_inputs.rb
|
190
205
|
- features/support/hooks.rb
|