siteleaf 0.8.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.
data/.DS_Store ADDED
Binary file
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in siteleaf.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Oak Studios LLC
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,114 @@
1
+ Siteleaf
2
+ ==========
3
+
4
+ Installation
5
+ ------------
6
+
7
+ Build gem from source:
8
+
9
+ gem build siteleaf.gemspec
10
+
11
+ Then install with:
12
+
13
+ gem install siteleaf
14
+
15
+ To use this gem in your application, add the following to your Gemfile:
16
+
17
+ gem 'siteleaf', :git => 'git://github.com/siteleaf/siteleaf-gem.git'
18
+
19
+
20
+ Testing sites locally
21
+ ---------------------
22
+
23
+ The Siteleaf gem allows you to test and develop your sites locally.
24
+
25
+ Set up a new site locally:
26
+
27
+ siteleaf new yoursite.com
28
+
29
+ Configure an existing site:
30
+
31
+ siteleaf config yoursite.com
32
+
33
+ If using [Pow](http://pow.cx), your local website will be automatically set up and can be accessed at `http://yoursite.dev`.
34
+
35
+ Local sites can also be manually run:
36
+
37
+ siteleaf server
38
+
39
+ In this case, your local site can be accessed at `http://localhost:9292`.
40
+
41
+
42
+ Using the API
43
+ -------------
44
+
45
+ This gem also allows you to interact with the Siteleaf API.
46
+
47
+ ```ruby
48
+ require 'siteleaf'
49
+
50
+ # authentication
51
+ Siteleaf.api_key = 'KEY'
52
+ Siteleaf.api_secret = 'SECRET'
53
+
54
+ # get authenticated user
55
+ me = Siteleaf::Users.find('me')
56
+
57
+ # get all sites
58
+ sites = Siteleaf::Site.all
59
+
60
+ # create new site
61
+ site = Siteleaf::Site.create({
62
+ :title => 'My Website',
63
+ :domain => 'mywebsite.com'
64
+ })
65
+
66
+ # get site by id
67
+ site = Siteleaf::Site.find('5196f137cc8591956b000001')
68
+
69
+ # update site
70
+ site.title = 'New Title'
71
+ site.save
72
+
73
+ # delete site
74
+ site.delete
75
+
76
+ # delete site by id
77
+ Siteleaf::Site.delete('5196f137cc8591956b000001')
78
+
79
+ # get all pages in site
80
+ pages = site.pages
81
+
82
+ # create new page in site
83
+ page = Siteleaf::Page.create({
84
+ :title => 'My Page',
85
+ :slug => 'my-page', # optional
86
+ :body => 'This is my first page.'
87
+ })
88
+
89
+ # get page by id
90
+ page = Siteleaf::Page.find('519719ddcc85910626000001')
91
+
92
+ # update page, add metadata
93
+ page.title = 'New Title'
94
+ page.meta = [{"key" => "foo", "value" => "bar"}]
95
+ page.save
96
+
97
+ # delete page
98
+ page.delete
99
+
100
+ # delete page by id
101
+ Siteleaf::Page.delete('519719ddcc85910626000001')
102
+ ```
103
+
104
+
105
+ Contributing
106
+ ------------
107
+
108
+ Help us improve this gem:
109
+
110
+ 1. Fork it
111
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
112
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
113
+ 4. Push to the branch (`git push origin my-new-feature`)
114
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/siteleaf ADDED
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'siteleaf'
4
+
5
+ def help
6
+ 'See https://github.com/siteleaf/siteleaf-gem for documentation.'
7
+ end
8
+
9
+ def auth(re_auth = false)
10
+ Siteleaf.load_settings if !re_auth
11
+
12
+ if re_auth or !Siteleaf.api_key
13
+ print 'Enter your Siteleaf e-mail: '
14
+ email = $stdin.gets.chomp
15
+
16
+ print 'Enter your Siteleaf password: '
17
+ system 'stty -echo'
18
+ password = $stdin.gets.chomp
19
+ system 'stty echo'
20
+
21
+ print "\nAuthorizing...\n"
22
+
23
+ if auth = Siteleaf::Client.auth(email, password) and auth.has_key?('api_key')
24
+ File.open(Siteleaf.settings_file,'w') do|file|
25
+ Marshal.dump({:api_key => auth['api_key'], :api_secret => auth['api_secret']}, file)
26
+ end
27
+ print "=> Gem authorized.\n" if re_auth
28
+ else
29
+ print "Could not authorize, check your e-mail or password.\n"
30
+ end
31
+ end
32
+ end
33
+
34
+ def config(site)
35
+ File.open('config.ru', 'w') { |file| file.write "# Intended for development purposes only, do not upload or use in production.
36
+ # See https://github.com/siteleaf/siteleaf-gem for documentation.
37
+
38
+ require 'siteleaf'
39
+ run Siteleaf::Server.new(site_id:'#{site.id}')" }
40
+
41
+ pow_path = "#{Etc.getpwuid.dir}/.pow"
42
+ if Dir.exists?(pow_path)
43
+ site_no_tld = site.domain.gsub(/\.[a-z]{0,4}$/i,'')
44
+ site_symlink = "#{pow_path}/#{site_no_tld}"
45
+ FileUtils.rm(site_symlink) if File.symlink?(site_symlink)
46
+ FileUtils.symlink(File.absolute_path("."), site_symlink)
47
+ puts "=> Site configured with Pow, open `http://#{site_no_tld}.dev` to test site locally.\n"
48
+ else
49
+ puts "=> Site configured, run `siteleaf server` to test site locally.\n"
50
+ end
51
+ end
52
+
53
+ case ARGV[0]
54
+ when '-v', '--version'
55
+ puts Siteleaf::VERSION
56
+ when '-h', '--help'
57
+ puts help
58
+ when 's', 'server'
59
+ if File.exists?('config.ru')
60
+ `rackup config.ru`
61
+ else
62
+ puts "No config found, run `siteleaf config yoursite.com`.\n"
63
+ end
64
+ when 'auth'
65
+ auth true
66
+ when 'c', 'config', 'setup'
67
+ auth
68
+ if site = Siteleaf::Site.find_by_domain(ARGV[1])
69
+ config site
70
+ else
71
+ puts "No site found for `#{ARGV[1]}`, run `siteleaf new #{ARGV[1]}` to create it.\n"
72
+ end
73
+ when 'n', 'new'
74
+ auth
75
+ if site = Siteleaf::Site.create(:title => ARGV[1], :domain => ARGV[1])
76
+ dir = ARGV.size >= 3 ? ARGV[2] : ARGV[1]
77
+ Dir.mkdir(dir) unless Dir.exists?(dir)
78
+ Dir.chdir(dir)
79
+ config site
80
+ else
81
+ puts "Could not create site `#{ARGV[1]}`.\n"
82
+ end
83
+ else
84
+ puts "`#{ARGV[0]}` command not found.\n"
85
+ puts help
86
+ end
data/lib/siteleaf.rb ADDED
@@ -0,0 +1,40 @@
1
+ libdir = File.dirname(__FILE__)
2
+ $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
3
+
4
+ require 'siteleaf/version'
5
+ require 'siteleaf/client'
6
+ require 'siteleaf/server'
7
+ require 'siteleaf/entity'
8
+ require 'siteleaf/site'
9
+ require 'siteleaf/page'
10
+ require 'siteleaf/post'
11
+ require 'siteleaf/meta'
12
+ require 'siteleaf/user'
13
+
14
+ module Siteleaf
15
+
16
+ @api_base = 'https://api.siteleaf.com/v1'
17
+
18
+ class << self
19
+ attr_accessor :api_key, :api_secret, :api_base
20
+ end
21
+
22
+ def self.api_url(url='')
23
+ "#{@api_base}/#{url}"
24
+ end
25
+
26
+ def self.settings_file
27
+ "#{Etc.getpwuid.dir}/.siteleaf"
28
+ end
29
+
30
+ def self.load_settings
31
+ if File.exists?(self.settings_file)
32
+ config = File.open(self.settings_file) do|file|
33
+ Marshal.load(file)
34
+ end
35
+ self.api_key = config[:api_key] if config.has_key?(:api_key)
36
+ self.api_secret = config[:api_secret] if config.has_key?(:api_secret)
37
+ end
38
+ end
39
+
40
+ end
Binary file
@@ -0,0 +1,47 @@
1
+ require 'rest-client'
2
+ require 'json'
3
+
4
+ module Siteleaf
5
+ class Client
6
+ def self.auth(email, password)
7
+ request = RestClient::Request.new(:url => Siteleaf.api_url('auth'), :method => :post, :user => email, :password => password)
8
+ begin
9
+ response = request.execute
10
+ return JSON.parse(response) # parse JSON
11
+ rescue => e
12
+ return e.inspect # error
13
+ end
14
+ end
15
+
16
+ def self.get(path, params = nil)
17
+ self.execute(:get, path, nil, params)
18
+ end
19
+
20
+ def self.post(path, params)
21
+ self.execute(:post, path, params)
22
+ end
23
+
24
+ def self.put(path, params)
25
+ self.execute(:put, path, params)
26
+ end
27
+
28
+ def self.delete(path)
29
+ self.execute(:delete, path)
30
+ end
31
+
32
+ def self.execute(method, path, payload = nil, params = nil)
33
+ Siteleaf.load_settings if !Siteleaf.api_key
34
+ request = RestClient::Request.new(:url => Siteleaf.api_url(path), :method => method, :payload => payload, :headers => { :params => params }, :user => Siteleaf.api_key, :password => Siteleaf.api_secret)
35
+ begin
36
+ response = request.execute
37
+ if response.headers[:content_type].to_s.include?('json')
38
+ return JSON.parse(response) # parse JSON
39
+ else
40
+ return response # raw
41
+ end
42
+ rescue => e
43
+ return e.inspect # error
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,63 @@
1
+ module Siteleaf
2
+ class Entity
3
+
4
+ def initialize(attributes = {})
5
+ self.attributes = attributes
6
+ end
7
+
8
+ def self.all
9
+ result = Client.get "#{self.endpoint}"
10
+ result.map { |r| self.new(r) } if result
11
+ end
12
+
13
+ def self.find(id)
14
+ result = Client.get "#{self.endpoint}/#{id}"
15
+ self.new(result) if result
16
+ end
17
+
18
+ def self.create(attributes = {})
19
+ self.new(attributes).save
20
+ end
21
+
22
+ def save
23
+ if self.id
24
+ result = Client.put "#{self.class.endpoint}/#{self.id}", self.attributes
25
+ else
26
+ result = Client.post "#{self.create_endpoint}", self.attributes
27
+ end
28
+ if result
29
+ self.attributes = result
30
+ return self
31
+ end
32
+ end
33
+
34
+ def self.delete(id)
35
+ Client.delete "#{self.endpoint}/#{id}"
36
+ end
37
+
38
+ def delete
39
+ Client.delete "#{self.class.endpoint}/#{self.id}"
40
+ end
41
+
42
+ def attributes
43
+ Hash[self.instance_variables.map { |name| [name[1..-1], self.instance_variable_get(name)] }]
44
+ end
45
+
46
+ def attributes=(attributes = {})
47
+ attributes.each_pair { |k, v| k != "attributes" and respond_to?(name = "#{k}=") and send(name, v) }
48
+ end
49
+
50
+ def self.class_name
51
+ self.name.split('::')[-1]
52
+ end
53
+
54
+ def self.endpoint
55
+ "#{self.class_name.downcase}s"
56
+ end
57
+
58
+ def create_endpoint
59
+ self.class.endpoint
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,24 @@
1
+ module Siteleaf
2
+ class Meta < Entity
3
+
4
+ attr_accessor :id, :key, :value, :page_id, :post_id
5
+ protected :id=
6
+
7
+ def create_endpoint
8
+ if self.page_id
9
+ "pages/#{self.page_id}/meta"
10
+ elsif self.post_id
11
+ "posts/#{self.post_id}/meta"
12
+ end
13
+ end
14
+
15
+ def post
16
+ Post.find(self.post_id) if self.post_id
17
+ end
18
+
19
+ def page
20
+ Page.find(self.page_id) if self.page_id
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,30 @@
1
+ module Siteleaf
2
+ class Page < Entity
3
+
4
+ attr_accessor :id, :title, :body, :slug, :url, :parent_id, :site_id, :published_at, :created_at, :updated_at, :meta
5
+ protected :id=, :created_at=, :updated_at=
6
+
7
+ def create_endpoint
8
+ "sites/#{self.site_id}/pages"
9
+ end
10
+
11
+ def site
12
+ Site.find(self.site_id) if self.site_id
13
+ end
14
+
15
+ def posts
16
+ result = Client.get "pages/#{self.id}/posts"
17
+ result.map { |r| Post.new(r) } if result
18
+ end
19
+
20
+ def pages
21
+ result = Client.get "pages/#{self.id}/pages"
22
+ result.map { |r| self.new(r) } if result
23
+ end
24
+
25
+ def page
26
+ Page.find(self.parent_id) if self.parent_id
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,15 @@
1
+ module Siteleaf
2
+ class Post < Page
3
+
4
+ attr_accessor :taxonomy
5
+
6
+ def create_endpoint
7
+ "pages/#{self.parent_id}/posts"
8
+ end
9
+
10
+ def parent
11
+ Page.find(self.parent_id)
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,67 @@
1
+ module Siteleaf
2
+ class Server
3
+ attr_accessor :site_id
4
+
5
+ def initialize(attributes = {})
6
+ self.site_id = attributes[:site_id]
7
+ end
8
+
9
+ def resolve_template(url = "/")
10
+ path = url.gsub(/\/\z|\A\//, '') #strip beginning and trailing slashes
11
+ paths = path.split("/")
12
+ templates = []
13
+
14
+ if path == ""
15
+ templates.push("index.html")
16
+ else
17
+ templates.push("#{paths.join('/')}.html")
18
+ templates.push("#{paths.join('/')}/index.html")
19
+ templates.push("#{paths.join('/')}/default.html")
20
+ while paths.size > 0
21
+ paths.pop
22
+ templates.push("#{paths.join('/')}/default.html") if paths.size > 0
23
+ end
24
+ end
25
+ templates.push("default.html")
26
+
27
+ templates.each do |t|
28
+ return File.read(t) if File.exists?(t)
29
+ end
30
+
31
+ return nil
32
+ end
33
+
34
+ def call(env)
35
+ site = Siteleaf::Site.new({:id => self.site_id})
36
+
37
+ url = env['PATH_INFO']
38
+ path = url.gsub(/\/\z|\A\//, '') #strip beginning and trailing slashes
39
+
40
+ if !File.directory?(path) and File.exists?(path)
41
+ Rack::File.new(Dir.pwd).call(env)
42
+ else
43
+ template_data = nil
44
+ is_asset = /(^assets|\.)/.match(path)
45
+
46
+ if is_asset
47
+ if asset = site.resolve(url) and asset_url = asset['file']['url']
48
+ require 'open-uri'
49
+ output = open(asset_url)
50
+ [200, {'Content-Type' => output.content_type}, [output.read]]
51
+ end
52
+ else
53
+ if template_data = resolve_template(url)
54
+ # compile liquid includes into a single page
55
+ include_tags = /\{\%\s+include\s+['"]([A-Za-z0-9_\-\/]+)['"]\s+\%\}/
56
+ while include_tags.match(template_data)
57
+ template_data = template_data.gsub(include_tags) { |i| File.read("_#{$1}.html") }
58
+ end
59
+ end
60
+
61
+ output = site.preview(url, template_data)
62
+ [200, {'Content-Type' => output.headers[:content_type]}, [output]]
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,26 @@
1
+ module Siteleaf
2
+ class Site < Entity
3
+
4
+ attr_accessor :id, :title, :domain, :timezone, :user_id, :created_at, :updated_at
5
+ protected :id=, :user_id=, :created_at=, :updated_at=
6
+
7
+ def self.find_by_domain(domain)
8
+ result = Client.get "sites", {"domain" => domain}
9
+ self.new(result.first) if result and result.size >= 1
10
+ end
11
+
12
+ def pages
13
+ result = Client.get "sites/#{self.id}/pages"
14
+ result.map { |r| Page.new(r) } if result
15
+ end
16
+
17
+ def resolve(url = '/')
18
+ Client.get "sites/#{self.id}/resolve", {"url" => url}
19
+ end
20
+
21
+ def preview(url = '/', template = nil)
22
+ Client.post "sites/#{self.id}/preview.html", {"url" => url, "template" => template}
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,8 @@
1
+ module Siteleaf
2
+ class User < Entity
3
+
4
+ attr_accessor :id, :email, :firstname, :lastname, :created_at, :updated_at
5
+ protected :id=, :created_at=, :updated_at=
6
+
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ module Siteleaf
2
+ VERSION = "0.8.0"
3
+ end
data/siteleaf.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'siteleaf/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "siteleaf"
8
+ gem.version = Siteleaf::VERSION
9
+ gem.authors = ["Siteleaf"]
10
+ gem.email = ["api@siteleaf.com"]
11
+ gem.description = %q{A Ruby interface to the Siteleaf API.}
12
+ gem.summary = gem.description
13
+ gem.homepage = "http://siteleaf.com"
14
+
15
+ # gem.required_ruby_version = '>= 1.9.2'
16
+
17
+ gem.add_dependency 'rest-client'
18
+ gem.add_dependency 'json'
19
+ # gem.add_dependency 'liquid'
20
+
21
+ gem.files = `git ls-files`.split($/)
22
+ gem.files += Dir.glob("lib/**/*.rb")
23
+ gem.executables = ["siteleaf"]
24
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
25
+ gem.require_paths = ["lib"]
26
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: siteleaf
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.8.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Siteleaf
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rest-client
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: json
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: A Ruby interface to the Siteleaf API.
47
+ email:
48
+ - api@siteleaf.com
49
+ executables:
50
+ - siteleaf
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - .DS_Store
55
+ - .gitignore
56
+ - Gemfile
57
+ - LICENSE.txt
58
+ - README.md
59
+ - Rakefile
60
+ - bin/siteleaf
61
+ - lib/siteleaf.rb
62
+ - lib/siteleaf/.DS_Store
63
+ - lib/siteleaf/client.rb
64
+ - lib/siteleaf/entity.rb
65
+ - lib/siteleaf/meta.rb
66
+ - lib/siteleaf/page.rb
67
+ - lib/siteleaf/post.rb
68
+ - lib/siteleaf/server.rb
69
+ - lib/siteleaf/site.rb
70
+ - lib/siteleaf/user.rb
71
+ - lib/siteleaf/version.rb
72
+ - siteleaf.gemspec
73
+ homepage: http://siteleaf.com
74
+ licenses: []
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubyforge_project:
93
+ rubygems_version: 1.8.23
94
+ signing_key:
95
+ specification_version: 3
96
+ summary: A Ruby interface to the Siteleaf API.
97
+ test_files: []