contraption 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Code Climate](https://codeclimate.com/github/rampantmonkey/contraption.png)](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
|