hightouch 0.1.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.
Files changed (42) hide show
  1. data/Gemfile +12 -0
  2. data/Gemfile.lock +121 -0
  3. data/README.md +10 -0
  4. data/bin/hightouch +6 -0
  5. data/bin/ht +6 -0
  6. data/config.rb +26 -0
  7. data/lib/hightouch.rb +89 -0
  8. data/lib/hightouch/app_generator.rb +25 -0
  9. data/lib/hightouch/archive.rb +30 -0
  10. data/lib/hightouch/archive_page_generator.rb +10 -0
  11. data/lib/hightouch/blog.rb +40 -0
  12. data/lib/hightouch/blog_posting.rb +95 -0
  13. data/lib/hightouch/category.rb +7 -0
  14. data/lib/hightouch/cli.rb +10 -0
  15. data/lib/hightouch/tag.rb +7 -0
  16. data/lib/hightouch/version.rb +3 -0
  17. data/rvmrc.example +1 -0
  18. data/source/blog/2012/02/02/setup-your-rails-dev-env-with-rda.html.markdown +150 -0
  19. data/source/blog/2012/03/01/example.html.markdown +11 -0
  20. data/source/images/adventure/background.jpg +0 -0
  21. data/source/images/adventure/bars.png +0 -0
  22. data/source/images/adventure/blacktrans.png +0 -0
  23. data/source/images/adventure/blog_posting_bg.png +0 -0
  24. data/source/index.html.haml +2 -0
  25. data/source/javascripts/all.js +1 -0
  26. data/source/layouts/blog_postings.html.haml +31 -0
  27. data/source/layouts/layout.html.haml +31 -0
  28. data/source/partials/_blog_posting.html.haml +14 -0
  29. data/source/partials/_blog_posting_summary.html.haml +16 -0
  30. data/source/partials/_bottombar.html.haml +9 -0
  31. data/source/partials/_sidebar.html.haml +17 -0
  32. data/source/partials/_tags.html.haml +6 -0
  33. data/source/stylesheets/adventure.css.scss +198 -0
  34. data/source/stylesheets/coderay.css +136 -0
  35. data/source/stylesheets/default.css.scss +3 -0
  36. data/source/stylesheets/pygments-github.css +70 -0
  37. data/source/stylesheets/pygments.css +62 -0
  38. data/source/templates/archive.html.haml +4 -0
  39. data/source/templates/category.html.haml +5 -0
  40. data/source/templates/tag.html.haml +4 -0
  41. data/spec/spec_helper.rb +12 -0
  42. metadata +145 -0
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'middleman', git: 'https://github.com/middleman/middleman.git'
4
+ gem 'rygments'
5
+ gem 'rack-codehighlighter'
6
+ gem 'redcarpet'
7
+ gem 'virtus'
8
+
9
+ # Development dependencies
10
+ gem 'pry'
11
+ gem 'rspec'
12
+ gem 'factory_girl'
data/Gemfile.lock ADDED
@@ -0,0 +1,121 @@
1
+ GIT
2
+ remote: https://github.com/middleman/middleman.git
3
+ revision: 3c78d9f171e44806165bf2a5c710b376a23bcd7b
4
+ specs:
5
+ middleman (3.0.0.beta.2)
6
+ middleman-core (= 3.0.0.beta.2)
7
+ middleman-more (= 3.0.0.beta.2)
8
+ middleman-core (3.0.0.beta.2)
9
+ activesupport (~> 3.2.0)
10
+ i18n (~> 0.6.0)
11
+ listen (~> 0.3.3)
12
+ rack (~> 1.4.0)
13
+ rack-test (~> 0.6.1)
14
+ thin (~> 1.3.1)
15
+ thor (~> 0.14.0)
16
+ tilt (~> 1.3.1)
17
+ middleman-more (3.0.0.beta.2)
18
+ coffee-script (~> 2.2.0)
19
+ compass (~> 0.12.0)
20
+ execjs (~> 1.2)
21
+ haml (~> 3.1.0)
22
+ middleman-core (= 3.0.0.beta.2)
23
+ redcarpet (~> 2.1.0)
24
+ sass (>= 3.1.7)
25
+ sprockets (~> 2.1)
26
+ sprockets-sass (~> 0.7.0)
27
+ uglifier (~> 1.2.0)
28
+
29
+ GEM
30
+ remote: http://rubygems.org/
31
+ specs:
32
+ activesupport (3.2.2)
33
+ i18n (~> 0.6)
34
+ multi_json (~> 1.0)
35
+ chunky_png (1.2.5)
36
+ coderay (1.0.5)
37
+ coffee-script (2.2.0)
38
+ coffee-script-source
39
+ execjs
40
+ coffee-script-source (1.2.0)
41
+ compass (0.12.0)
42
+ chunky_png (~> 1.2)
43
+ fssm (>= 0.2.7)
44
+ sass (~> 3.1)
45
+ daemons (1.1.8)
46
+ diff-lcs (1.1.3)
47
+ eventmachine (0.12.10)
48
+ execjs (1.3.0)
49
+ multi_json (~> 1.0)
50
+ factory_girl (2.6.3)
51
+ activesupport (>= 2.3.9)
52
+ ffi (1.0.11)
53
+ fssm (0.2.8.1)
54
+ haml (3.1.4)
55
+ hike (1.2.1)
56
+ i18n (0.6.0)
57
+ listen (0.3.3)
58
+ rb-fchange (~> 0.0.5)
59
+ rb-fsevent (~> 0.9.0)
60
+ rb-inotify (~> 0.8.8)
61
+ method_source (0.7.1)
62
+ multi_json (1.1.0)
63
+ nokogiri (1.5.2)
64
+ pry (0.9.8.4)
65
+ coderay (~> 1.0.5)
66
+ method_source (~> 0.7.1)
67
+ slop (>= 2.4.4, < 3)
68
+ rack (1.4.1)
69
+ rack-codehighlighter (0.5.0)
70
+ nokogiri (>= 1.4.1)
71
+ rack (>= 1.0.0)
72
+ rack-test (0.6.1)
73
+ rack (>= 1.0)
74
+ rb-fchange (0.0.5)
75
+ ffi
76
+ rb-fsevent (0.9.0)
77
+ rb-inotify (0.8.8)
78
+ ffi (>= 0.5.0)
79
+ redcarpet (2.1.0)
80
+ rspec (2.8.0)
81
+ rspec-core (~> 2.8.0)
82
+ rspec-expectations (~> 2.8.0)
83
+ rspec-mocks (~> 2.8.0)
84
+ rspec-core (2.8.0)
85
+ rspec-expectations (2.8.0)
86
+ diff-lcs (~> 1.1.2)
87
+ rspec-mocks (2.8.0)
88
+ rygments (0.2.0)
89
+ sass (3.1.15)
90
+ slop (2.4.4)
91
+ sprockets (2.3.1)
92
+ hike (~> 1.2)
93
+ multi_json (~> 1.0)
94
+ rack (~> 1.0)
95
+ tilt (~> 1.1, != 1.3.0)
96
+ sprockets-sass (0.7.0)
97
+ sprockets (~> 2.0)
98
+ tilt (~> 1.1)
99
+ thin (1.3.1)
100
+ daemons (>= 1.0.9)
101
+ eventmachine (>= 0.12.6)
102
+ rack (>= 1.0.0)
103
+ thor (0.14.6)
104
+ tilt (1.3.3)
105
+ uglifier (1.2.3)
106
+ execjs (>= 0.3.0)
107
+ multi_json (>= 1.0.2)
108
+ virtus (0.3.0)
109
+
110
+ PLATFORMS
111
+ ruby
112
+
113
+ DEPENDENCIES
114
+ factory_girl
115
+ middleman!
116
+ pry
117
+ rack-codehighlighter
118
+ redcarpet
119
+ rspec
120
+ rygments
121
+ virtus
data/README.md ADDED
@@ -0,0 +1,10 @@
1
+ # Intro
2
+
3
+ hightouch (HT) is a static website generator based on
4
+ [middleman](https://github.com/middleman/middleman) and
5
+ inspired by
6
+ [middleman-blog](https://github.com/middleman/middleman-blog).
7
+
8
+ ### Start to write a blog posting
9
+
10
+
data/bin/hightouch ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path('../lib/hightouch.rb', File.dirname(__FILE__))
4
+
5
+ Hightouch::CLI.start
6
+
data/bin/ht ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path('../lib/hightouch.rb', File.dirname(__FILE__))
4
+
5
+ Hightouch::CLI.start
6
+
data/config.rb ADDED
@@ -0,0 +1,26 @@
1
+ Bundler.require
2
+ require 'i18n'
3
+ require 'hightouch'
4
+
5
+ activate :hightouch
6
+
7
+ Encoding.default_external = 'utf-8'
8
+
9
+ require "redcarpet"
10
+ set :markdown_engine, :redcarpet
11
+
12
+ require 'rygments'
13
+ require 'rack/codehighlighter'
14
+ page "/blog/*", layout: :blog_postings
15
+
16
+ use Rack::Codehighlighter,
17
+ :pygments,
18
+ element: 'code',
19
+ markdown: true,
20
+ pattern: /\A:::([-_+\w]+)\s*\n/
21
+
22
+ configure :build do; end
23
+
24
+ ready do
25
+ generate_archive_pages
26
+ end
data/lib/hightouch.rb ADDED
@@ -0,0 +1,89 @@
1
+ $LOAD_PATH << File.join(File.dirname(__FILE__))
2
+
3
+ require 'middleman'
4
+ require 'virtus'
5
+ require 'thor/group'
6
+
7
+ require 'hightouch/app_generator'
8
+ require 'hightouch/cli'
9
+ require 'hightouch/archive_page_generator'
10
+
11
+ module Hightouch
12
+ autoload :BlogPosting, 'hightouch/blog_posting'
13
+ autoload :Archive, 'hightouch/archive'
14
+ autoload :Category, 'hightouch/category'
15
+ autoload :Tag, 'hightouch/tag'
16
+ autoload :Blog, 'hightouch/blog'
17
+
18
+ class << self
19
+ def registered(app)
20
+ app.helpers HelperMethods
21
+ app.helpers ActiveSupport::Inflector
22
+
23
+ app.after_configuration do
24
+ frontmatter_changed /blog\/(\d{4})\/(\d{2})\/(\d{2})\/(.*)\.html/ do |file|
25
+ blog.touch_blog_posting(self.sitemap.page(self.sitemap.file_to_path(file)))
26
+ end
27
+ end
28
+ end
29
+
30
+ alias :included :registered
31
+ end
32
+
33
+ module HelperMethods
34
+ include ArchivePageGenerator
35
+
36
+ def blog
37
+ @blog ||= Blog.new(self)
38
+ end
39
+
40
+ def generate_archive_pages
41
+ [:categories, :tags, :archives].each do |i|
42
+ blog.send(i).each { |k, v| generate_archive_page(v) }
43
+ end
44
+ end
45
+
46
+ def font_size_for_tag(tag, opts = {})
47
+ max_font_size = opts[:max_font_size] || 36
48
+ min_font_size = opts[:min_font_size] || 11
49
+
50
+ max_count = max_tag.count
51
+ min_count = min_tag.count
52
+
53
+ size = begin
54
+ if max_count == min_count
55
+ min_font_size
56
+ else
57
+ min_font_size + (max_count - (max_count - (tag.count - min_count))) * (max_font_size - min_font_size).to_f/(max_count - min_count).to_f
58
+ end
59
+ end
60
+ end
61
+
62
+ private
63
+ def generate_category_page(category)
64
+ name = category.is_a?(String) ? category : category.name
65
+ page "/blog/#{name}.html", proxy: "/templates/category.html", ignore: true do
66
+ @category_name = name
67
+ end
68
+ end
69
+
70
+ def generate_tag_page(tag)
71
+ name = tag.is_a?(String) ? tag : tag.name
72
+ page "/blog/tags/#{name}.html", proxy: "/templates/tag.html", ignore: true do
73
+ @tag_name = name
74
+ end
75
+ end
76
+
77
+ def max_tag
78
+ blog.tags.values.max { |x, y| x.count <=> y.count }
79
+ end
80
+
81
+ def min_tag
82
+ blog.tags.values.min { |x, y| x.count <=> y.count }
83
+ end
84
+
85
+
86
+ end
87
+ end
88
+
89
+ Middleman::Extensions.register(:hightouch) { Hightouch }
@@ -0,0 +1,25 @@
1
+ module Hightouch
2
+ class AppGenerator < ::Thor::Group
3
+ include ::Thor::Actions
4
+
5
+ argument :path
6
+
7
+ def self.source_root
8
+ File.join(File.dirname(__FILE__), '../../')
9
+ end
10
+
11
+ def create_app_dir
12
+ empty_directory(path)
13
+ end
14
+
15
+ def create_files
16
+ directory 'source', "#{path}/source"
17
+
18
+ copy_file 'config.rb', "#{path}/config.rb"
19
+ copy_file 'Gemfile', "#{path}/Gemfile"
20
+ copy_file 'Gemfile.lock', "#{path}/Gemfile.lock"
21
+ copy_file 'README.md', "#{path}/README.md"
22
+ copy_file 'rvmrc.example', "#{path}/rvmrc.example"
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,30 @@
1
+ module Hightouch
2
+ class Archive
3
+ include Virtus
4
+
5
+ attribute :name, String
6
+ attribute :blog, Blog
7
+ attribute :blog_postings, Hash, default: {}
8
+
9
+ def add_blog_posting(blog_posting)
10
+ blog_postings[blog_posting.name] = blog_posting
11
+ end
12
+
13
+ def remove_blog_posting(blog_posting)
14
+ blog_postings.delete(blog_posting.name)
15
+ blog.remove_archive(self) if empty?
16
+ end
17
+
18
+ def empty?
19
+ blog_postings.empty?
20
+ end
21
+
22
+ def count
23
+ blog_postings.size
24
+ end
25
+
26
+ def path
27
+ "/blog/#{name}/index.html"
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,10 @@
1
+ module Hightouch
2
+ module ArchivePageGenerator
3
+ def generate_archive_page(archive)
4
+ page archive.path, proxy: "/templates/archive.html", ignore: true do
5
+ @collection = archive.class.name.split(/::/).last.downcase.pluralize.to_sym
6
+ @archive_name = archive.name
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,40 @@
1
+ module Hightouch
2
+ class Blog
3
+ include Virtus
4
+
5
+ attribute :archives, Hash, default: {}
6
+ attribute :categories, Hash, default: {}
7
+ attribute :tags, Hash, default: {}
8
+ attribute :blog_postings, Hash, default: {}
9
+
10
+ attr_reader :app
11
+
12
+ def initialize(app = nil)
13
+ @app = app
14
+ end
15
+
16
+ def create_archive(type, attrs)
17
+ send(type.name.split(/::/).last.downcase.pluralize.to_sym)[attrs[:name]] = type.new(attrs)
18
+ end
19
+
20
+ def remove_archive(archive)
21
+ key = archive.name
22
+ send(archive.class.name.split(/::/).last.downcase.pluralize.to_sym).delete(key)
23
+ end
24
+
25
+ def touch_blog_posting(page)
26
+ key = page.data.title
27
+ blog_posting = blog_postings[key]
28
+
29
+ if blog_posting
30
+ blog_posting.update
31
+ else
32
+ blog_postings[key] = BlogPosting.new(page, self)
33
+ end
34
+ end
35
+
36
+ def blog_posting(path)
37
+ blog_postings.values.select { |v| v.url == path }.first
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,95 @@
1
+ module Hightouch
2
+ class BlogPosting
3
+ include Virtus
4
+
5
+ DESC_SEPARATOR = /READMORE/
6
+
7
+ attribute :blog, Blog
8
+
9
+ attribute :name, String
10
+ attribute :url, String
11
+ attribute :description, String
12
+ attribute :author, String
13
+ attribute :date_created, Date
14
+ attribute :tags, Hash, default: {}
15
+ attribute :categories, Hash, default: {}
16
+ attribute :archive, Archive
17
+
18
+ attr_reader :raw, :page
19
+
20
+ def initialize(page, blog)
21
+ @blog = blog
22
+ @page = page
23
+
24
+ update
25
+ end
26
+
27
+ def update
28
+ app = page.store.app
29
+ path = page.source_file.sub(app.source_dir, '')
30
+
31
+ @name = page.data.title
32
+
33
+ @date_created = Date.strptime(page.data.date_created, '%Y/%m/%d') if page.data.date_created
34
+ @author = page.data.author
35
+ @url = '/' + page.path
36
+ @raw = app.frontmatter(path).last
37
+
38
+ update_association(Category, page.data.categories) if page.data.categories
39
+ update_association(Tag, page.data.tags) if page.data.tags
40
+ update_archive(@date_created)
41
+
42
+ @description = nil
43
+ @article_body = nil
44
+ end
45
+
46
+ def article_body
47
+ @article_body ||= begin
48
+ body = page.render(layout: false)
49
+ body.sub!(DESC_SEPARATOR, '')
50
+ end
51
+ end
52
+
53
+ def description
54
+ @description ||= begin
55
+ desc = if raw =~ DESC_SEPARATOR
56
+ raw.split(DESC_SEPARATOR).first
57
+ else
58
+ raw.match(/(.{1,200}.*?)(\n|\Z)/m).to_s
59
+ end
60
+ engine = ::Tilt[page.source_file].new { desc }
61
+ engine.render
62
+ end
63
+
64
+ end
65
+
66
+ private
67
+ def update_association(type, updated)
68
+ association_name = type.name.split(/::/).last.downcase.pluralize.to_sym
69
+ association = send(association_name)
70
+ association.each do |k, v|
71
+ unless updated.include? k
72
+ association.delete(k).remove_blog_posting(self)
73
+ end
74
+ end
75
+
76
+ updated.each do |u|
77
+ a = association[u]
78
+ next if a
79
+
80
+ a = blog.send(association_name)[u] || blog.send(:create_archive, type, name: u, blog: blog)
81
+
82
+ a.add_blog_posting(self)
83
+ association[u] = a
84
+ end
85
+ end
86
+
87
+ def update_archive(date_created)
88
+ name = date_created.strftime('%Y/%m')
89
+ return if archive && archive.name == name
90
+
91
+ archive = blog.archives[name] || blog.create_archive(Archive, name: name, blog: blog)
92
+ archive.add_blog_posting(self)
93
+ end
94
+ end
95
+ end