engine_of_war 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ .bin
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/.rbenv-version ADDED
@@ -0,0 +1 @@
1
+ 1.9.3-p0
data/.yardopts ADDED
@@ -0,0 +1,2 @@
1
+ --readme README.textile
2
+ --markup textile
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'http://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in engine_of_war.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/setup'
3
+
4
+ require "bundler/gem_tasks"
5
+ require 'rspec/core/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+
9
+ task :default => :spec
10
+
data/Readme.textile ADDED
File without changes
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/engine_of_war/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Thunderbolt Labs"]
6
+ gem.email = ["us@thunderboltlabs.com"]
7
+ gem.description = "Semi-static site engine."
8
+ gem.summary = "Semi-static site endine based on Padrino"
9
+ gem.homepage = "http://thunderboltlabs.com"
10
+
11
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
+ gem.files = `git ls-files`.split("\n")
13
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ gem.name = "engine_of_war"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = EngineOfWar::VERSION
17
+
18
+ gem.add_dependency 'sinatra'
19
+ gem.add_dependency "compass"
20
+ gem.add_dependency "padrino"
21
+ gem.add_dependency "active_support"
22
+ gem.add_dependency "builder"
23
+ gem.add_dependency 'haml'
24
+ gem.add_dependency 'sass', ">= 3.1.7"
25
+ gem.add_dependency "RedCloth"
26
+ gem.add_dependency "coffee-script"
27
+
28
+ gem.add_development_dependency "yard"
29
+ gem.add_development_dependency "RedCloth"
30
+ gem.add_development_dependency "rake"
31
+ gem.add_development_dependency "rspec"
32
+ gem.add_development_dependency "capybara"
33
+
34
+ end
@@ -0,0 +1,24 @@
1
+ require 'sinatra'
2
+ require 'compass'
3
+ require "builder"
4
+ require 'haml'
5
+ require 'sass'
6
+ require "RedCloth"
7
+ require "coffee-script"
8
+ require 'padrino-core/application/rendering'
9
+ require 'padrino-helpers'
10
+ require 'active_support/hash_with_indifferent_access'
11
+ require 'active_support/core_ext/object/blank'
12
+ require 'json'
13
+
14
+ module EngineOfWar; end
15
+
16
+ require 'engine_of_war/version'
17
+ require 'engine_of_war/extensions/string'
18
+ require 'engine_of_war/my_red_cloth_template'
19
+ require 'engine_of_war/layout'
20
+ require 'engine_of_war/page'
21
+ require 'engine_of_war/page_collection'
22
+ require 'engine_of_war/recommendation'
23
+ require 'engine_of_war/app'
24
+
@@ -0,0 +1,67 @@
1
+ class EngineOfWar::App < Sinatra::Base
2
+ register Padrino::Rendering
3
+ register Padrino::Helpers
4
+
5
+ Compass.configuration do |config|
6
+ config.project_path = File.dirname(__FILE__)
7
+ config.sass_dir = 'views/css'
8
+ end
9
+
10
+ set :haml, { :format => :html5 }
11
+ set :scss, Compass.sass_engine_options
12
+ # set :root, File.expand_path(File.dirname(__FILE__) + '/../')
13
+ set(:config) { File.expand_path(root + '/config/') }
14
+
15
+ def render_page_with_layout(page)
16
+ render_page(page, :layout => "layouts/#{page.layout}", :layout_engine => :haml)
17
+ end
18
+
19
+ get "/posts.atom" do
20
+ content_type :rss
21
+ builder do |xml|
22
+ xml.instruct! :xml, :version => '1.0'
23
+ xml.rss :version => "2.0" do
24
+ xml.channel do
25
+ xml.title "Thunderbolt Labs"
26
+ xml.link "http://#{request.host}"
27
+
28
+ collection("posts").each do |post|
29
+ xml.item do
30
+ xml.title post.meta[:title]
31
+ xml.link "http://#{request.host}#{post.url}"
32
+ xml.description render_page(post)
33
+ xml.pubDate post.meta[:date].rfc822
34
+ xml.guid "http://#{request.host}#{post.url}"
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ get %r{^/([^.]+)$} do |name|
43
+ render_page_with_layout(EngineOfWar::Page.new(name))
44
+ end
45
+
46
+ get "/" do
47
+ render_page_with_layout(EngineOfWar::Page.new(:index))
48
+ end
49
+
50
+ get "/*.*" do |name, ext|
51
+ content_type ext
52
+ render :"#{name}", :layout => false
53
+ end
54
+
55
+ helpers do
56
+ def render_page(page, opts = {})
57
+ opts[:locals] ||= {}
58
+ opts[:locals][:meta] = page.meta
59
+ opts[:locals][:page] = page
60
+ send(page.engine, page.source, opts)
61
+ end
62
+
63
+ def collection(dir)
64
+ EngineOfWar::PageCollection.new(dir)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,10 @@
1
+ class String
2
+ def unindent
3
+ gsub /^#{self[/\A\s*/]}/, ''
4
+ end
5
+
6
+ def uncomment(comment = "//")
7
+ gsub(%r{^#{comment}\s*}, '')
8
+ end
9
+ end
10
+
@@ -0,0 +1,29 @@
1
+ class Layout
2
+ attr_reader :page
3
+
4
+ def initialize(page)
5
+ @page = page
6
+ end
7
+
8
+ def name
9
+ potential_layouts.first + ".html"
10
+ end
11
+
12
+ def potential_layouts
13
+ [layout_from_directory, layout_from_meta, default_layout].reject(&:blank?).compact.select do |f|
14
+ File.exists?(File.join(page.views_root, "layouts", "#{f}.html.haml"))
15
+ end
16
+ end
17
+
18
+ def layout_from_directory
19
+ File.dirname(page.request_path).sub!(%r{^[/.]}, "")
20
+ end
21
+
22
+ def layout_from_meta
23
+ page.meta[:layout]
24
+ end
25
+
26
+ def default_layout
27
+ "application"
28
+ end
29
+ end
@@ -0,0 +1,78 @@
1
+ class EngineOfWar::RedClothTemplate < Tilt::RedClothTemplate
2
+ Tilt.register self, "textile"
3
+
4
+ BASE_IMAGE_URL = "/images"
5
+ include Padrino::Helpers::TagHelpers
6
+
7
+ def prepare
8
+ @engine = RedCloth.new(image_filter(code_filter(data)))
9
+ @output = nil
10
+ end
11
+
12
+ private
13
+
14
+ def code_filter(txt)
15
+ txt.gsub(/@@@ *(\w*)\r?\n? *(.+?)\r?\n?@@@/m) do
16
+ klass = $1.present? ? " class=\"#{$1.downcase}\"" : ""
17
+ "<pre><code#{klass}>#{$2}</code></pre>"
18
+ end
19
+ end
20
+
21
+ def image_filter(txt)
22
+ txt.gsub(/^%([<>]?)([0-9a-zA-Z_.-]+)([^%]*)%/) do
23
+ float = $1
24
+ image_id = $2
25
+ size = $3
26
+
27
+ float = :right if float == '>'
28
+ float = :left if float == '<'
29
+
30
+ uploaded_image_tag(image_id, :size => size, :float => float)
31
+ end
32
+ end
33
+
34
+ def uploaded_image_tag(image_name, opts = {})
35
+ opts.symbolize_keys
36
+
37
+ opts[:size] = "original" if opts[:size].blank?
38
+ opts[:size].strip!
39
+
40
+ basename, ext = image_name.split('.')
41
+ image_src = "#{BASE_IMAGE_URL}/#{basename}/#{opts[:size]}.#{ext}"
42
+ meta = meta_for_image(basename)
43
+
44
+ return "<div class='warning'>unknown image #{image_name}</div>" unless File.directory?(image_basedir(basename))
45
+
46
+ image_options = { :src => image_src }
47
+ image_options[:class] = "float-#{opts[:float]}" if opts[:float]
48
+ image_options[:alt] = meta[:description] if meta[:description]
49
+
50
+ href = meta[:source_url]
51
+
52
+ img_tag = content_tag :img, "", image_options
53
+ if href
54
+ return "<a href='#{href}'>#{img_tag}</a>"
55
+ else
56
+ return img_tag
57
+ end
58
+ end
59
+
60
+ def image_basedir(basename)
61
+ File.join(EngineOfWar::App.settings.public, BASE_IMAGE_URL, basename)
62
+ end
63
+
64
+ def meta_for_image(basename)
65
+ file = File.join(image_basedir(basename), "meta.yml")
66
+ if File.exist?(file)
67
+ YAML.load_file(file).delete_if {|k, v| v.blank? }
68
+ else
69
+ {}
70
+ end
71
+ end
72
+
73
+ # Required to confuse padrino
74
+ def block_is_template?(_)
75
+ false
76
+ end
77
+ end
78
+
@@ -0,0 +1,68 @@
1
+ class EngineOfWar::Page
2
+ YAML_REGEXP = /^(---\s*\n.*?\n?)^(---\s*$\n?)/m
3
+
4
+ attr_reader :request_path, :views_root, :meta, :source
5
+
6
+ def initialize(request_path)
7
+ @views_root = EngineOfWar::App.settings.views
8
+ @request_path = normalize_path(request_path)
9
+ @entire_source = File.read(template_path)
10
+ @meta, @source = split_body
11
+ end
12
+
13
+ def layout
14
+ Layout.new(self).name
15
+ end
16
+
17
+ def url
18
+ request_path
19
+ end
20
+
21
+ def engine
22
+ template_path.split(".").last.to_sym
23
+ end
24
+
25
+ def github_edit_url
26
+ relative_template_path = template_path.sub(views_root, "views")
27
+ "https://github.com/thunderboltlabs/thunderboltlabs/edit/master/#{relative_template_path}"
28
+ end
29
+
30
+ private
31
+
32
+ def normalize_path(path)
33
+ path = path.to_s
34
+ path.sub!(%r{/$}, "")
35
+ path.start_with?("/") ? path : "/#{path}"
36
+ end
37
+
38
+ def split_body
39
+ data = {}
40
+ body = @entire_source
41
+ if @entire_source =~ YAML_REGEXP
42
+ data = hash_from_yaml($1)
43
+ body = @entire_source.split(YAML_REGEXP).last
44
+ end
45
+
46
+ [HashWithIndifferentAccess.new(data), body]
47
+ end
48
+
49
+ def hash_from_yaml(yaml)
50
+ begin
51
+ return YAML.load(yaml)
52
+ rescue ArgumentError => e
53
+ raise e, "#{e.message}:\n#{yaml.inspect}"
54
+ end
55
+ end
56
+
57
+ def template_path
58
+ first_template_matching(request_path)
59
+ end
60
+
61
+ def first_template_matching(name)
62
+ pattern = File.join(views_root, "#{name}.html.*")
63
+ candidates = Dir[pattern]
64
+ raise Sinatra::NotFound, "Could find no files matching #{pattern}" if candidates.empty?
65
+ candidates.first
66
+ end
67
+ end
68
+
@@ -0,0 +1,47 @@
1
+ class EngineOfWar::PageCollection < Array
2
+ attr_accessor :collection_root
3
+
4
+ def initialize(collection_root)
5
+ super()
6
+ self.collection_root = collection_root
7
+ self.concat(pages)
8
+ end
9
+
10
+ private
11
+
12
+ def pages
13
+ unsorted_pages.sort_by do |page|
14
+ page.meta[:date]
15
+ end.reverse
16
+ end
17
+
18
+ def unsorted_pages
19
+ page_template_paths.map do |file_path|
20
+ EngineOfWar::Page.new(file_path)
21
+ end
22
+ end
23
+
24
+ def page_template_paths
25
+ page_files.map do |full_path|
26
+ template_path_for(full_path)
27
+ end
28
+ end
29
+
30
+ def template_path_for(full_path)
31
+ full_path[views_root] = ""
32
+ full_path[%r{\.[^/]*}] = ""
33
+ full_path
34
+ end
35
+
36
+ def page_files
37
+ Dir[File.join(pages_root, "**/*")]
38
+ end
39
+
40
+ def pages_root
41
+ File.join(views_root, collection_root)
42
+ end
43
+
44
+ def views_root
45
+ EngineOfWar::App.settings.views
46
+ end
47
+ end
@@ -0,0 +1,34 @@
1
+ class EngineOfWar::Recommendation
2
+ def self.random
3
+ new(recommendations_data.sample)
4
+ end
5
+
6
+ def initialize(values = {})
7
+ @values = HashWithIndifferentAccess.new(values)
8
+ end
9
+
10
+ def method_missing(*args, &block)
11
+ if key = args.first and @values.has_key?(key)
12
+ @values[key]
13
+ else
14
+ raise NoMethodError.new("#{key} not in #{@values.inspect}")
15
+ end
16
+ end
17
+
18
+ def inspect
19
+ "Recommendation: #{@values.inspect}"
20
+ end
21
+
22
+ def to_s; inspect; end
23
+
24
+ private
25
+
26
+ def self.recommendations_data
27
+ JSON.parse(File.read(json_file))
28
+ end
29
+
30
+ def self.json_file
31
+ File.join(EngineOfWar::App.settings.config, "recommendations.json")
32
+ end
33
+
34
+ end