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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d1c34da43377fb2b0cec9e0c8cf821867a18a85b
4
- data.tar.gz: 8623c83b4113c1878756257ea4f43f02d8fa8ab4
3
+ metadata.gz: db47cc8b0f80c9b56c5ce15af3e3d02201d2a3d2
4
+ data.tar.gz: 04dd17291329b373f04780fb7dccebde4abb1064
5
5
  SHA512:
6
- metadata.gz: 873f12c0aa72c64145879a0b09564419aef292d60fd3eee8d00553c9639279ec353b21a0c5bc77e3558ad6dc8ab7223f34b186b98263daff0c847aa1c20e4d4a
7
- data.tar.gz: 78c1b4f321c8327e687f542dfc508a0f4bf8df61ed8e71a4f463fd1a5e2bdced4b9b5bf82987d5e642c5bd5f7b721e38612a2b6f2c248eceb18e7e001f195fb9
6
+ metadata.gz: 5da3efa5065cd2a501f2d67f40af417db884f49549a3acd4319f9fd5fe27903a73debd3507b7e76a0fd753d1155d3ebe92d53a006c2798c493c1a6ad3252253a
7
+ data.tar.gz: 63e2c8eee732f05dc0d6b1a73f87a2495cc6a9085f8fe79dc6f02c6685582b3e80fdb987d5e6b9f6719d9d6bac84c47a3f7785015e721c0b4db21e093fdadaf0
data/.gitignore CHANGED
@@ -7,7 +7,6 @@ Gemfile.lock
7
7
  InstalledFiles
8
8
  _yardoc
9
9
  coverage
10
- doc/
11
10
  lib/bundler/man
12
11
  pkg
13
12
  rdoc
data/README.md CHANGED
@@ -1,24 +1,31 @@
1
1
  # Contraption
2
2
 
3
- TODO: Write a gem description
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
- Add this line to your application's Gemfile:
9
+ $ gem install contraption
8
10
 
9
- gem 'contraption'
11
+ ## Usage
10
12
 
11
- And then execute:
13
+ __Step 1__: Generate new content directory.
12
14
 
13
- $ bundle
15
+ bin/contraption generate -d my_content
14
16
 
15
- Or install it yourself as:
17
+ __Step 2__: Write a new draft.
16
18
 
17
- $ gem install contraption
19
+ vim drafts/why_contraption_is_awesome.md
18
20
 
19
- ## Usage
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
@@ -8,5 +8,9 @@ Cucumber::Rake::Task.new(:features) do |t|
8
8
  t.cucumber_opts = "features --format pretty"
9
9
  end
10
10
 
11
+ task :doc do
12
+ `dot -Tpng -o doc/classes.png doc/classes.dot`
13
+ end
14
+
11
15
  task :default => [:spec, :features]
12
16
 
@@ -0,0 +1,8 @@
1
+ require 'benchmark'
2
+ require_relative 'lib/contraption/command_selector'
3
+
4
+ elapsed_time = Benchmark.realtime do
5
+ Contraption::CommandSelector.go ARGV
6
+ end
7
+
8
+ puts "Time: #{elapsed_time}s"
@@ -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
- require 'contraption/options'
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>&copy; 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>&copy; Your Name Goes Here <%= Time.new.year %></p>
21
+ </footer>
22
+ </body>
@@ -0,0 +1,2 @@
1
+ <h1>Tag Cloud</h1>
2
+ <%= context[:content] %>
@@ -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
+ }
Binary file
@@ -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
@@ -1,3 +1,3 @@
1
1
  After do
2
- `rm -rf tmp`
2
+ `rm -rf tmp #{@target_dir} #{@target_dir ? @target_dir+'output' : ''}`
3
3
  end
@@ -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"
@@ -27,10 +27,9 @@ module Contraption
27
27
  end
28
28
 
29
29
  def by_tag
30
- all(:tags).each_with_object(Hash.new {|h,k| h[k] = []}) do |tag, result|
31
- items.each do |item|
32
- result[tag.to_sym] << item if item.tags.include? tag
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,12 @@
1
+ module Contraption
2
+ class Diagnoser
3
+ def initialize args
4
+ @options = args.values
5
+ end
6
+
7
+ def run!
8
+ key_width = @options.keys.map(&:length).max + 1
9
+ @options.each_pair{|k,v| puts "#{(k.to_s << ':').ljust key_width} #{v}"}
10
+ end
11
+ end
12
+ 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
@@ -51,6 +51,7 @@ module Contraption
51
51
 
52
52
  def initialize opts={}
53
53
  @defaults = { title: "",
54
+ external: nil,
54
55
  publication_date: "",
55
56
  summary: "",
56
57
  type: "",
@@ -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?
@@ -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{|p| Post.build(@posts_source.read p)} )
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 static_files
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|
@@ -1,60 +1,27 @@
1
- require_relative 'repository'
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
- upload local_path, request.last
20
- ["http:", "#{@target_bucket}/#{request.last}"]
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 "#{request.last} does not exist"
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
@@ -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
@@ -15,7 +15,7 @@ module Contraption
15
15
  private
16
16
  def tag_link tag
17
17
  tag = Tag.new tag
18
- %Q{<a href="tags/#{tag.to_url}/index.html">#{tag.to_s}</a>}
18
+ %Q{<a class="indivisible" href="tags/#{tag.to_url}/index.html">#{tag.to_s}</a>}
19
19
  end
20
20
 
21
21
  def scale element
@@ -1,3 +1,3 @@
1
1
  module Contraption
2
- VERSION = "0.2.0"
2
+ VERSION = '0.3.0'
3
3
  end
@@ -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.2.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: 2013-11-03 00:00:00.000000000 Z
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/author_generates_site.feature
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/author_generates_site.feature
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