siterest 0.1.0.pre1

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 (49) hide show
  1. data/Gemfile +9 -0
  2. data/Gemfile.lock +38 -0
  3. data/Rakefile +23 -0
  4. data/VERSION +1 -0
  5. data/bin/siterest +10 -0
  6. data/config.ru +6 -0
  7. data/lib/encoded_attachment/.gitignore +7 -0
  8. data/lib/encoded_attachment/Gemfile +11 -0
  9. data/lib/encoded_attachment/LICENSE +20 -0
  10. data/lib/encoded_attachment/README.md +107 -0
  11. data/lib/encoded_attachment/Rakefile +41 -0
  12. data/lib/encoded_attachment/encoded_attachment.gemspec +23 -0
  13. data/lib/encoded_attachment/lib/activerecord/base.rb +63 -0
  14. data/lib/encoded_attachment/lib/activeresource/base.rb +121 -0
  15. data/lib/encoded_attachment/lib/activeresource/connection.rb +7 -0
  16. data/lib/encoded_attachment/lib/encoded_attachment/version.rb +3 -0
  17. data/lib/encoded_attachment/lib/encoded_attachment.rb +47 -0
  18. data/lib/encoded_attachment/test/active_record_test.rb +136 -0
  19. data/lib/encoded_attachment/test/active_resource_test.rb +276 -0
  20. data/lib/encoded_attachment/test/avatars/.gitignore +0 -0
  21. data/lib/encoded_attachment/test/config/database.yml +19 -0
  22. data/lib/encoded_attachment/test/config/schema.rb +17 -0
  23. data/lib/encoded_attachment/test/fixtures/kitten.jpg +0 -0
  24. data/lib/encoded_attachment/test/fixtures/tapir.jpg +0 -0
  25. data/lib/encoded_attachment/test/test_helper.rb +73 -0
  26. data/lib/siterest/asset.rb +27 -0
  27. data/lib/siterest/client.rb +149 -0
  28. data/lib/siterest/command.rb +105 -0
  29. data/lib/siterest/server.rb +58 -0
  30. data/lib/siterest/site.rb +6 -0
  31. data/lib/siterest/template/filters/core_filters.rb +57 -0
  32. data/lib/siterest/template/filters/datetime_filters.rb +8 -0
  33. data/lib/siterest/template/filters/url_filters.rb +82 -0
  34. data/lib/siterest/template/objects/article.rb +35 -0
  35. data/lib/siterest/template/objects/page.rb +71 -0
  36. data/lib/siterest/template/objects/site.rb +51 -0
  37. data/lib/siterest/template.rb +6 -0
  38. data/lib/siterest/user.rb +6 -0
  39. data/lib/siterest.rb +56 -0
  40. data/lib/upfile.rb +51 -0
  41. data/readme.md +86 -0
  42. data/site/data/articles/2008-04-24-my-first-blog-post.md +12 -0
  43. data/site/data/pages/about-us/something.md +0 -0
  44. data/site/data/pages/about-us.md +12 -0
  45. data/site/data/pages/contact.md +12 -0
  46. data/site/data/pages/home.md +14 -0
  47. data/site/data/site.yaml +2 -0
  48. data/siterest.gemspec +101 -0
  49. metadata +203 -0
@@ -0,0 +1,149 @@
1
+ require 'fileutils'
2
+ require 'stringio'
3
+ require 'pp'
4
+
5
+ module Siterest
6
+ class Client
7
+ def pull_templates(site)
8
+ reset_path(templates_path)
9
+
10
+ results = []
11
+ page = 1
12
+
13
+ while page == 1 || results.size > 0
14
+ results = Template.all(:params => {:subdomain => site, :page => page}).each do |template|
15
+ filename = templates_path + template.name
16
+
17
+ File.open(filename, 'w') do |f|
18
+ f.write(template.source)
19
+ end
20
+
21
+ puts "Downloaded #{filename}"
22
+ end
23
+
24
+ page += 1
25
+ end
26
+
27
+
28
+ end
29
+
30
+ def pull_assets(site)
31
+ reset_path(
32
+ [assets_path + 'images', assets_path + 'javascripts', assets_path + 'stylesheets']
33
+ )
34
+
35
+ results = []
36
+ page = 1
37
+
38
+ while page == 1 || results.size > 0
39
+ results = Asset.all(:params => {:subdomain => site, :page => page}).each do |asset|
40
+ file = asset.to_file
41
+ if file.size > 0
42
+ mode = asset.binary? ? 'wb' : 'w'
43
+ filename = assets_path + asset.path.split('/').slice(2..-1).join('/')
44
+
45
+ File.open(filename, mode) do |f|
46
+ f.write(file.read)
47
+ end
48
+ end
49
+
50
+ puts "Downloaded #{asset.id} #{filename}"
51
+ end
52
+
53
+ page += 1
54
+ end
55
+
56
+ end
57
+
58
+ def push_templates(site)
59
+
60
+ Dir.glob("templates/*").each do |filename|
61
+ basename = File.basename(filename)
62
+ source = File.read(filename)
63
+
64
+ existing = Template.first(:params => {
65
+ :subdomain => site,
66
+ :search => {:name_eq => basename}
67
+ })
68
+
69
+ if existing
70
+ existing.update_attributes(:source => source, :subdomain => site)
71
+ else
72
+ Template.create(
73
+ :subdomain => site,
74
+ :name => basename,
75
+ :source => source
76
+ )
77
+ end
78
+
79
+ puts "#{existing ? 'Updated' : 'Created'} #{filename}"
80
+ end
81
+ end
82
+
83
+
84
+ def push_assets(site)
85
+ require 'siterest/asset'
86
+
87
+ Dir.glob("assets/*/*").each do |filename|
88
+ file = open(filename)
89
+ # puts file
90
+ #
91
+ # io = StringIO.new(open(file).read)
92
+ # io.original_filename = File.basename(file)
93
+ #
94
+ existing = Asset.first(:params => {
95
+ :subdomain => site, :search => {:data_file_name_eq => File.basename(filename)}
96
+ })
97
+
98
+ if existing
99
+ existing.data = file
100
+ existing.save
101
+ else
102
+ Asset.create(:data => file, :subdomain => site, :layout => true)
103
+ end
104
+
105
+ puts "#{existing ? 'Updated' : 'Created'} #{filename}"
106
+ end
107
+ #
108
+ # asset = Asset.new(:subdomain => site)
109
+ # new_path = asset.send(:new_element_path).to_s
110
+ # collection_path = asset.send(:collection_path).to_s
111
+ #
112
+ # puts Siterest.url.to_s
113
+ #
114
+ #
115
+ # resource = RestClient::Resource.new(Siterest.url.gsub('//', "//#{Siterest.token}:x@"))
116
+ #
117
+ # resource[collection_path].post :content_type => 'application/xml', :asset => {:data => open('assets/images/bg.png'), :layout => true}
118
+
119
+ # RestClient.post 'http://localhost:3000/foo', fields_hash.merge(:file => File.new('/path/to/file'))
120
+
121
+ #
122
+ # Dir.glob("site/assets/*/*").each do |file|
123
+ # Asset.create(
124
+ # :data => open(file)
125
+ # :subdomain => site
126
+ # )
127
+ # end
128
+ end
129
+
130
+ def request_path
131
+
132
+ end
133
+
134
+ private
135
+ def templates_path
136
+ Pathname.new(Dir.pwd) + 'templates'
137
+ end
138
+
139
+ def assets_path
140
+ Pathname.new(Dir.pwd) + 'assets'
141
+ end
142
+
143
+ def reset_path(path)
144
+ FileUtils.rm_rf(path)
145
+ FileUtils.mkdir_p(path)
146
+ end
147
+
148
+ end
149
+ end
@@ -0,0 +1,105 @@
1
+ module Siterest
2
+ class Command
3
+ attr_accessor :input, :output, :command, :args
4
+
5
+ def initialize(input=STDIN, output=STDOUT, *args)
6
+ @input = input
7
+ @output = output
8
+ self.command, *self.args = args
9
+
10
+ self.command ||= 'render'
11
+
12
+
13
+ end
14
+
15
+ def put(string, newline=true)
16
+ @output.print(newline ? string + "\n" : string)
17
+ end
18
+
19
+ def run!
20
+ puts Dir.pwd
21
+ puts "#{self.command} Command"
22
+
23
+ unless File.exist?(config_file)
24
+ config
25
+ else
26
+ self.send(command)
27
+ end
28
+ end
29
+
30
+ def render
31
+ Thread.new { Launchy.open("http://localhost:8888") }
32
+ Server.run! :host => 'localhost', :port => 8888
33
+ end
34
+
35
+ def config
36
+ put "Let's setup your SiteRest, visit follow url if you don't have a account"
37
+ put "http://www.siterest.com"
38
+
39
+ put "API token: ", false
40
+ token = input.gets.chomp
41
+
42
+ put "Server (default: http://api.siterest.com): ", false
43
+ server = input.gets.chomp
44
+
45
+ server = server == '' ? 'http://api.siterest.com' : server
46
+
47
+ save_config(:api_token => token, :server_url => server)
48
+ end
49
+
50
+ def setup
51
+ FileUtils.cp_r(File.dirname(__FILE__) + '/../../site/data', 'data')
52
+ end
53
+
54
+ def pull
55
+ site = self.args.shift
56
+
57
+ client.pull_templates(site)
58
+ client.pull_assets(site)
59
+ end
60
+
61
+ def push
62
+ site = self.args.shift
63
+
64
+ put "Are you sure you want to overwrite your site design(type in yes)"
65
+
66
+ put "[yes|no]: ", false
67
+ answer = input.gets.chomp
68
+
69
+ if answer == 'yes'
70
+ put "Pushing templates..."
71
+
72
+ client.push_templates(site)
73
+
74
+ put "Pushing site assets..."
75
+
76
+ client.push_assets(site)
77
+ else
78
+ put 'May be next time'
79
+ end
80
+ end
81
+
82
+
83
+ def client
84
+ Client.new
85
+ end
86
+
87
+ def home_directory
88
+ ENV['HOME']
89
+ end
90
+
91
+ def config_file
92
+ "#{ENV['HOME']}/.siterest/config.yml"
93
+ end
94
+
95
+ def save_config(config)
96
+ File.open(config_file, "w") do|file|
97
+ file.puts(config.to_yaml)
98
+ end
99
+ end
100
+
101
+ def load_config
102
+ YAML.load_file(config_file)
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,58 @@
1
+ require 'rubygems'
2
+ require 'sinatra/base'
3
+ require 'cgi'
4
+
5
+ # require 'h2o'
6
+ # require 'yaml'
7
+ # require 'rdiscount'
8
+ # require 'ostruct'
9
+
10
+ module Siterest
11
+ class Server < Sinatra::Base
12
+ set :public, 'assets'
13
+
14
+ get '/' do
15
+ render_h2o 'home.html', :page => Page.find('home')
16
+ end
17
+
18
+ get %r{/(news|blog)} do
19
+ render_h2o 'list.html', :collection => Article.all
20
+ end
21
+
22
+ get %r{^/(\d{4})(?:/(\d{2}))$} do
23
+ year, month = params[:captures]
24
+
25
+ results = Article.all.find_all do |a|
26
+ puts a.published_at
27
+
28
+ a.published_at.year == year.to_i && a.published_at.month == month.to_i
29
+ end
30
+
31
+ render_h2o 'list.html', :collection => results
32
+ end
33
+
34
+ get '/tags/:tag' do
35
+ results = Article.all.find_all do |a|
36
+ a.tags.include?(params[:tag])
37
+ end
38
+
39
+ render_h2o 'list.html', :collection => results
40
+ end
41
+
42
+ get '/:year/:month/:permalink' do
43
+ render_h2o 'article.html', :page => Article.find(request.path_info[1..-1])
44
+ end
45
+
46
+ get '/:permalink' do
47
+ render_h2o 'page.html', :page => Page.find(params[:permalink])
48
+ end
49
+ end
50
+ end
51
+
52
+ def render_h2o(template, context = {})
53
+ global = {
54
+ :site => Site.new(YAML.load_file('data/site.yaml'))
55
+ }
56
+ template = H2o::Template.new("templates/#{template}")
57
+ template.render global.merge(context)
58
+ end
@@ -0,0 +1,6 @@
1
+ module Siterest
2
+ class Site < ActiveResource::Base
3
+ self.site = Siterest.url
4
+ self.user = Siterest.token
5
+ end
6
+ end
@@ -0,0 +1,57 @@
1
+ module CoreFilters
2
+
3
+ # String filters
4
+ def upper string
5
+ string.to_s.upcase
6
+ end
7
+
8
+ def lower string
9
+ string.to_s.downcase
10
+ end
11
+
12
+ def capitalize string
13
+ string.to_s.capitalize
14
+ end
15
+
16
+ def escape string, attribute=false
17
+ string = string.dup.to_s
18
+
19
+ {
20
+ '&' => '&amp;',
21
+ '>' => '&gt;',
22
+ '<' => '&lt;'
23
+ }.each do |v, k|
24
+ string.tr!(v, k)
25
+ end
26
+
27
+ string.gsub!(/"/, '&quot;') if attribute
28
+
29
+ string
30
+ end
31
+
32
+ # Array Filters
33
+ def join(list, delimiter=', ')
34
+ list.join(delimiter)
35
+ end
36
+
37
+ def first(list)
38
+ list.first
39
+ end
40
+
41
+ def last(list)
42
+ list.last
43
+ end
44
+
45
+ #String Filters
46
+ # def raw(stringish)
47
+ # stringish.to_s.html_safe
48
+ # end
49
+
50
+ #sliding Filters
51
+ # def sliding_it(content)
52
+ # content.split(/<h2>/).delete_if(&:blank?).map{|a| "<h2>" + a}
53
+ # end
54
+
55
+
56
+ H2o::Filters << self
57
+ end
@@ -0,0 +1,8 @@
1
+ module DateTimeFilters
2
+
3
+ def date(input, format = '%B %d, %Y @ %I:%M %p')
4
+ input.strftime(format) unless input.nil?
5
+ end
6
+
7
+ H2o::Filters << self
8
+ end
@@ -0,0 +1,82 @@
1
+ module UrlFilters
2
+
3
+ def base_url(path = '')
4
+ asset_url(path)
5
+ end
6
+
7
+ def asset_url(path = '')
8
+ assets_path + path
9
+ end
10
+
11
+ def css_tag(stylesheet, attributes = {})
12
+ attributes = {
13
+ 'media' => "screen", 'rel' => "stylesheet", 'type' => "text/css"
14
+ }.merge(attributes)
15
+ source = <<-css
16
+ <link href="#{asset_url + stylesheet}" #{html_attr_for(attributes)} />
17
+ css
18
+
19
+ source.lstrip
20
+ end
21
+
22
+ def script_tag(script)
23
+ source = <<-src
24
+ <script src="#{asset_url + script}" type="text/javascript"></script>
25
+ src
26
+
27
+ source.lstrip
28
+ end
29
+
30
+ def image_tag(image, attributes = {})
31
+ source = <<-img
32
+ <img src="#{asset_url + image}" #{html_attr_for(attributes)}/>
33
+ img
34
+
35
+ source.lstrip
36
+ end
37
+
38
+ def links_to(anchor, object, attributes = {})
39
+ if object.is_a? String
40
+ url = object
41
+ elsif object.respond_to?(:url)
42
+ url = object.url
43
+ end
44
+
45
+ attributes.merge!(:href => url)
46
+
47
+ "<a #{html_attr_for(attributes)}>#{anchor}</a>"
48
+ end
49
+
50
+ # Paginate collection
51
+ # * <tt>:previous_label</tt> -- default: "« Previous" (this parameter is called <tt>:prev_label</tt> in versions <b>2.3.2</b> and older!)
52
+ # * <tt>:next_label</tt> -- default: "Next »"
53
+ # * <tt>:page_links</tt> -- when false, only previous/next links are rendered (default: true)
54
+ # * <tt>:inner_window</tt> -- how many links are shown around the current page (default: 4)
55
+ # * <tt>:outer_window</tt> -- how many links are around the first and the last page (default: 1)
56
+ # * <tt>:separator</tt> -- string separator for page HTML elements (default: single space)
57
+ #
58
+ def paginate(collection, options = {})
59
+ options[:request_uri] = @context.resolve(:request_uri)
60
+ Paginator.new.will_paginate(collection, options)
61
+ end
62
+
63
+ private
64
+ def html_attr_for(attributes = {})
65
+ attrs = attributes.inject([]) do |attr, (key, value)|
66
+ attr << "#{key}=\"#{value}\""
67
+ end
68
+
69
+ attrs.join(' ')
70
+ end
71
+
72
+ def assets_path
73
+ '/'
74
+ end
75
+
76
+ H2o::Filters << self
77
+ end
78
+ #
79
+ # class Paginator
80
+ # include ActionView::Helpers::TagHelper
81
+ # include WillPaginate::H2oCompatible::ViewHelpers
82
+ # end
@@ -0,0 +1,35 @@
1
+
2
+ class Article < OpenStruct
3
+ h2o_expose :title, :body, :excerpt, :author_name, :url, :permalink, :created_at, :published_at
4
+
5
+ def self.all
6
+ Dir.glob("data/articles/*.md").map do |path|
7
+ build(path)
8
+ end
9
+ end
10
+
11
+ def self.find(url)
12
+ year, month, permalink = url.split('/')
13
+ pattern = "data/articles/#{year}-#{month}-*-#{permalink}.md"
14
+
15
+ path = Dir.glob(pattern).first or raise "Article not found"
16
+
17
+ return build(path)
18
+ end
19
+
20
+ def self.build(path)
21
+ if path =~ %r(data/articles/(\d{4})-(\d{2})-(\d{2})-(.+).md)
22
+ year, month, day, permalink = $1, $2, $3, $4
23
+ end
24
+
25
+ attributes = Page.build_content(path).merge(
26
+ 'published_at' => Time.local(year, month, day),
27
+ 'url' => "/" + [year, month, permalink].join('/'),
28
+ 'permalink' => permalink
29
+ )
30
+
31
+ self.new attributes
32
+ end
33
+ end
34
+
35
+
@@ -0,0 +1,71 @@
1
+ class Page < OpenStruct
2
+ h2o_expose :title, :body, :url, :permalink, :created_at, :published_at, :children
3
+
4
+ def self.all
5
+ cache = {}
6
+ pages = recursive_build('data/pages', cache).uniq
7
+
8
+ homepage = pages.find{|p| p.permalink == 'home'}
9
+
10
+ subpages = pages - [homepage]
11
+ homepage.children = subpages
12
+
13
+ pages
14
+ end
15
+
16
+ def self.recursive_build(start_path, cache)
17
+ Dir.glob("#{start_path}/*").map do |path|
18
+ if File.directory?(path)
19
+ page = cache[path + '.md'] = build(path + '.md')
20
+ page.children = recursive_build(path, cache)
21
+ elsif !cache[path]
22
+ page = cache[path] = build(path)
23
+ else
24
+ page = cache[path]
25
+ end
26
+ page
27
+ end
28
+ end
29
+
30
+ def self.build(path)
31
+ attributes = build_content(path)
32
+ url = path.gsub(%r(data/pages/(.+).md)){|m| $1 }
33
+ permalink = url.split('/').last
34
+
35
+ self.new attributes.merge(:url => url, :permalink => permalink)
36
+ end
37
+
38
+ def self.find(permalink)
39
+ path = Dir.glob("data/pages/#{permalink}.md").first or raise "Page not found"
40
+
41
+ attributes = build_content(path)
42
+ url = path.gsub(%r(data/pages/(.+).md)){|m| $1 }
43
+ permalink = url.split('/').last
44
+
45
+ if permalink == 'home'
46
+ permalink = nil
47
+ url = ''
48
+ end
49
+
50
+ url = "/" + url
51
+
52
+ self.new attributes.merge(:url => url, :permalink => permalink)
53
+ end
54
+
55
+ def self.build_content(filename)
56
+ source = File.read(filename)
57
+ meta, content = source.split(/---\n(.+?)---/sm)[1,2]
58
+
59
+ if meta
60
+ attributes = YAML.load(meta)
61
+ else
62
+ attributes = {}
63
+ end
64
+
65
+ attributes.merge(
66
+ 'body' => content && RDiscount.new(content).to_html,
67
+ 'published_at' => attributes['published_at'] || File.mtime(filename)
68
+ )
69
+ end
70
+ end
71
+
@@ -0,0 +1,51 @@
1
+ class Site < OpenStruct
2
+ h2o_expose :title, :subdomain, :url, :about, :created_at, :homepage,
3
+ :articles, :latest_articles, :archives, :tag_cloud
4
+
5
+ def homepage
6
+ @homepage ||= self.pages.find{|p| p.permalink == 'home'}
7
+ end
8
+
9
+ def articles
10
+ @articles ||= Article.all
11
+ end
12
+ alias latest_articles articles
13
+
14
+ def pages
15
+ @pages ||= Page.all
16
+ end
17
+
18
+ def archives
19
+ Dir.glob("data/articles/*.md").map do |path|
20
+
21
+ if path =~ %r(data/articles/(\d{4})-(\d{2})-(\d{2})-(.+).md)
22
+ year, month, day, permalink = $1.to_i, $2.to_i, $3.to_i, $4
23
+ end
24
+
25
+ date = Date.new(year, month, day)
26
+
27
+ {
28
+ :date => date,
29
+ :url => "/#{date.strftime('%Y/%m')}"
30
+ }
31
+ end
32
+ end
33
+
34
+ def tag_cloud
35
+ tags = {}
36
+ self.articles.map(&:tags).flatten.map do |t|
37
+ tags[t] ||= 0
38
+ tags[t] += 1
39
+ end
40
+
41
+ tags.map do |key, value|
42
+ {
43
+ :name => key,
44
+ :count => value,
45
+ :url => "/tags/#{CGI.escape(key)}"
46
+ }
47
+ end
48
+ end
49
+ end
50
+
51
+
@@ -0,0 +1,6 @@
1
+ module Siterest
2
+ class Template < ActiveResource::Base
3
+ self.site = Siterest.site_resource_url
4
+ self.user = Siterest.token
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Siterest
2
+ class User < ActiveResource::Base
3
+ self.site = Siterest.site_resource_url
4
+ self.user = Siterest.token
5
+ end
6
+ end
data/lib/siterest.rb ADDED
@@ -0,0 +1,56 @@
1
+ require "rubygems"
2
+
3
+ require "bundler"
4
+ Bundler.setup
5
+
6
+ require 'yaml'
7
+ require 'h2o'
8
+ require 'launchy'
9
+ require 'active_resource'
10
+ require 'rest_client'
11
+ require 'yaml'
12
+ require 'rdiscount'
13
+ require 'ostruct'
14
+
15
+ module Siterest
16
+
17
+ autoload :Server, 'siterest/server'
18
+ autoload :Client, 'siterest/client'
19
+ autoload :Command, 'siterest/command'
20
+
21
+ autoload :Template, 'siterest/template'
22
+ autoload :Asset, 'siterest/asset'
23
+ autoload :User, 'siterest/user'
24
+ autoload :Site, 'siterest/site'
25
+
26
+ # load template api
27
+ require 'siterest/template/objects/site'
28
+ require 'siterest/template/objects/page'
29
+ require 'siterest/template/objects/article'
30
+
31
+ # load filters
32
+ require 'siterest/template/filters/core_filters'
33
+ require 'siterest/template/filters/datetime_filters'
34
+ require 'siterest/template/filters/url_filters'
35
+
36
+ def self.config
37
+ YAML.load_file("#{ENV['HOME']}/.siterest/config.yml")
38
+ rescue
39
+ raise "You need to setup API key, run siterest setup"
40
+ end
41
+
42
+ def self.token
43
+ @token ||= config[:api_token]
44
+ rescue
45
+ raise "You need to setup API key, run siterest setup"
46
+ end
47
+
48
+ def self.url
49
+ @token ||= config[:server_url]
50
+ end
51
+
52
+ def self.site_resource_url
53
+ "#{self.url}/sites/:subdomain"
54
+ end
55
+
56
+ end