sharpie 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,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 sharpie.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Alan deLevie
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,104 @@
1
+ # Sharpie
2
+
3
+ Quick and easy static site generation with a familiar API.
4
+
5
+ ## Usage
6
+
7
+ ```ruby
8
+ class App < Sharpie::Base
9
+
10
+ get "/" do
11
+ "Hello, world."
12
+ end
13
+
14
+ # get posts from ActiveRecord or elsewhere
15
+ def self.posts
16
+ Post.all
17
+ end
18
+
19
+ posts.each do |post|
20
+ get "/posts/#{post.id}" do
21
+ erb :post
22
+ end
23
+
24
+ get "/posts/#{post.id}.json" do
25
+ post.to_json
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+
32
+ App.build!("_site")
33
+ ```
34
+
35
+ Or use with an existing Sinatra application:
36
+
37
+ ```ruby
38
+ class App < Sinatra::Base
39
+ register Sinatra::AdvancedRoutes # this is required
40
+
41
+ def self.posts
42
+ Post.all
43
+ end
44
+
45
+ posts.each do |post|
46
+ get "/posts/#{post['id']}.json" do
47
+ post.to_json
48
+ end
49
+ end
50
+
51
+ get "/" do
52
+ erb :index
53
+ end
54
+ end
55
+
56
+ builder = Sharpie::Builder.new(App)
57
+ builder.build!("_site")
58
+ ```
59
+
60
+ `Sharpie::Base` subclasses from `Sinatra::Base`.
61
+
62
+ ## Installation
63
+
64
+ Add this line to your application's Gemfile:
65
+
66
+ ```ruby
67
+ gem 'sharpie'
68
+ ```
69
+
70
+ And then execute:
71
+
72
+ ```sh
73
+ $ bundle
74
+ ```
75
+
76
+ Or install it yourself as:
77
+
78
+ ```sh
79
+ $ gem install sharpie
80
+ ```
81
+
82
+ ## Contributing
83
+
84
+ 1. Fork it
85
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
86
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
87
+ 4. Push to the branch (`git push origin my-new-feature`)
88
+ 5. Create new Pull Request
89
+
90
+ ## Why
91
+
92
+ Sinatra routes make web app and API creation dead-simple. The syntax is straightforward and allows for your site to feel more like Ruby and less like a bloated framework. And there's also no reason why this powerful API should be limited to dynamic web applications. Sinatra routes simply describe a path and a response. Whether the response is evaluated ahead of time or on fly should not matter.
93
+
94
+ ### Why not Jekyll?
95
+
96
+ Jekyll is great for blogs and other types of sites where content is "hand created." That is, a human creates a file in a folder and writes some Markdown. Sharpie is more geared towards use-cases where the original content is already in a machine-readable format. For example, if you have a set of 1000s of JSON files that you want to expose via REST API. With Sharpie, you can write such an API with very few (yet straightfoward) lines of code.
97
+
98
+ ### Fork
99
+
100
+ This software is mostly a fork of the [sinatra-static](https://github.com/paulasmuth/sinatra-static) gem by [Paul Asmuth](https://twitter.com/paulasmuth). Paul's code is very well-written. I'd rather copy and attribute it than re-invent a well-made wheel, and instead focus on building an interface that suits my needs. More specifically, I want Sharpie to be part of a toolchain for rapidly developing static file-backed REST APIs.
101
+
102
+ # License
103
+
104
+ This software, which is a fork of MIT-licensed software, is also MIT-licensed. See `LICENSE.txt`.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require "rake/testtask"
4
+ Rake::TestTask.new(:test) do |test|
5
+ test.libs << "lib" << "test"
6
+ test.pattern = "test/**/test_*.rb"
7
+ test.verbose = true
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,86 @@
1
+ class SinatraStatic
2
+
3
+ @@file_extensions = %w(css js xml json html csv)
4
+
5
+ attr_accessor :app
6
+
7
+ include Rack::Test::Methods
8
+
9
+ require 'term/ansicolor'
10
+ class ColorString < String
11
+ include Term::ANSIColor
12
+ end
13
+
14
+ def initialize(app)
15
+ @app = app
16
+ end
17
+
18
+ def build!(dir)
19
+ handle_error_no_each_route! unless @app.respond_to?(:each_route)
20
+ handle_error_dir_not_found!(dir) unless dir_exists?(dir)
21
+ build_routes(dir)
22
+ end
23
+
24
+ private
25
+
26
+ def build_routes(dir)
27
+ @app.each_route do |route|
28
+ next unless route.verb == 'GET'
29
+ build_path(route.path, dir)
30
+ end
31
+ end
32
+
33
+ def build_path(path, dir)
34
+ ::FileUtils.mkdir_p(dir_for_path(path, dir))
35
+ ::File.open(file_for_path(path, dir), 'w+') do |f|
36
+ f.write(get_path(path).body)
37
+ end
38
+ end
39
+
40
+ def get_path(path)
41
+ self.get(path).tap do |resp|
42
+ handle_error_non_200!(path) unless resp.status == 200
43
+ end
44
+ end
45
+
46
+ def file_for_path(path, dir)
47
+ if path.match(/[^\/\.]+.(#{file_extensions.join("|")})$/)
48
+ ::File.join(dir, path)
49
+ else
50
+ ::File.join(dir, path, 'index.html')
51
+ end
52
+ end
53
+
54
+ def dir_exists?(dir)
55
+ ::File.exists?(dir) && ::File.directory?(dir)
56
+ end
57
+
58
+ def dir_for_path(path, dir)
59
+ file_for_path(path, dir).match(/(.*)\/[^\/]+$/)[1]
60
+ end
61
+
62
+ def file_extensions
63
+ @@file_extensions
64
+ end
65
+
66
+ def env
67
+ ENV['RACK_ENV']
68
+ end
69
+
70
+ def handle_error_no_each_route!
71
+ handle_error!("can't call app.each_route, did you include sinatra-advanced-routes?")
72
+ end
73
+
74
+ def handle_error_dir_not_found!(dir)
75
+ handle_error!("can't find output directory: #{dir}")
76
+ end
77
+
78
+ def handle_error_non_200!(path)
79
+ handle_error!("GET #{path} returned non-200 status code...")
80
+ end
81
+
82
+ def handle_error!(desc)
83
+ puts ColorString.new("failed: #{desc}").red; exit!
84
+ end
85
+
86
+ end
@@ -0,0 +1,3 @@
1
+ module Sharpie
2
+ VERSION = "0.0.1"
3
+ end
data/lib/sharpie.rb ADDED
@@ -0,0 +1,96 @@
1
+ require "sharpie/version"
2
+ require "bundler/setup"
3
+ require "sinatra"
4
+ require "sinatra/advanced_routes"
5
+ require "rack/test"
6
+
7
+ module Sharpie
8
+
9
+ class Base < Sinatra::Base
10
+ register Sinatra::AdvancedRoutes
11
+
12
+ def self.build!(path)
13
+ builder = Sharpie::Builder.new(self)
14
+ builder.build!(path)
15
+ end
16
+ end
17
+
18
+ class ColorString < String
19
+ include Term::ANSIColor
20
+ end
21
+
22
+ class Builder
23
+ attr_accessor :app
24
+ include Rack::Test::Methods
25
+
26
+ @@file_extensions = %w(css js xml json html csv)
27
+
28
+ def initialize(sinatra_application)
29
+ @app = sinatra_application
30
+ end
31
+
32
+ def build!(dir)
33
+ handle_error_no_each_route! unless @app.respond_to?(:each_route)
34
+ #handle_error_dir_not_found!(dir) unless dir_exists?(dir)
35
+ build_routes(dir)
36
+ end
37
+
38
+ private
39
+
40
+ def build_routes(dir)
41
+ @app.each_route do |route|
42
+ next unless route.verb == "GET"
43
+ build_path(route.path, dir)
44
+ end
45
+ end
46
+
47
+ def build_path(path, dir)
48
+ FileUtils.mkdir_p(dir_for_path(path, dir))
49
+ File.open(file_for_path(path, dir), "w+") do |f|
50
+ f.write(get_path(path).body)
51
+ end
52
+ end
53
+
54
+ def get_path(path)
55
+ self.get(path).tap do |resp|
56
+ unless resp.status == 200
57
+ binding.pry
58
+ handle_error_non_200!(path)
59
+ end
60
+ end
61
+ end
62
+
63
+ def file_extensions
64
+ @@file_extensions
65
+ end
66
+
67
+ def file_for_path(path, dir)
68
+ if path.match(/[^\/\.]+.(#{file_extensions.join("|")})$/)
69
+ File.join(dir, path)
70
+ else
71
+ File.join(dir, path, "index.html")
72
+ end
73
+ end
74
+
75
+ def dir_for_path(path, dir)
76
+ file_for_path(path, dir).match(/(.*)\/[^\/]+$/)[1]
77
+ end
78
+
79
+ def dir_exists?(dir)
80
+ File.exists?(dir) && ::File.directory?(dir)
81
+ end
82
+
83
+ def handle_error_non_200!(path)
84
+ handle_error!("GET #{path} returned non-200 status code...")
85
+ end
86
+
87
+ def handle_error_no_each_route!
88
+ handle_error!("can't call app.each_route, did you include sinatra-advanced-routes?")
89
+ end
90
+
91
+ def handle_error!(desc)
92
+ raise "Sharpie error: #{desc}"
93
+ end
94
+ end
95
+
96
+ end
data/sharpie.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sharpie/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "sharpie"
8
+ spec.version = Sharpie::VERSION
9
+ spec.authors = ["Alan deLevie"]
10
+ spec.email = ["adelevie@gmail.com"]
11
+ spec.description = %q{Static site generation with a familiar API.}
12
+ spec.summary = %q{Converts Sinatra apps into static sites.}
13
+ spec.homepage = "http://github.com/adelevie/sharpie"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "sinatra"
22
+ spec.add_dependency "sinatra-advanced-routes"
23
+ spec.add_dependency "rack-test"
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.3"
26
+ spec.add_development_dependency "rake"
27
+ spec.add_development_dependency "pry-rescue"
28
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,7 @@
1
+ require "minitest/autorun"
2
+ require "pry-rescue/minitest"
3
+ require "sharpie"
4
+ require "fileutils"
5
+ require "json"
6
+ require_relative "test_app"
7
+ require_relative "test_sharpie_app"
data/test/test_app.rb ADDED
@@ -0,0 +1,33 @@
1
+ require "bundler/setup"
2
+ require "sinatra/base"
3
+ require "sinatra/advanced_routes"
4
+ require "json"
5
+
6
+ class TestApp < Sinatra::Base
7
+ register Sinatra::AdvancedRoutes
8
+
9
+ def self.posts
10
+ [
11
+ {
12
+ "id" => 1,
13
+ "title" => "Hello, world",
14
+ "body" => "Sinatra routes + static html = win"
15
+ },
16
+ {
17
+ "id" => 2,
18
+ "title" => "Second Post",
19
+ "body" => "Why not?"
20
+ }
21
+ ]
22
+ end
23
+
24
+ posts.each do |post|
25
+ get "/posts/#{post['id']}.json" do
26
+ post.to_json
27
+ end
28
+ end
29
+
30
+ get "/" do
31
+ erb :index
32
+ end
33
+ end
@@ -0,0 +1,56 @@
1
+ require "helper"
2
+
3
+ class TestBuild < MiniTest::Unit::TestCase
4
+
5
+ def setup
6
+ FileUtils.rm_rf("test/sites/test_app")
7
+ FileUtils.rm_rf("test/sites/test_sharpie_app")
8
+ end
9
+
10
+ def teardown
11
+ FileUtils.rm_rf("test/sites/test_app")
12
+ FileUtils.rm_rf("test/sites/test_sharpie_app")
13
+ end
14
+
15
+ def test_build
16
+ path = "test/sites/test_app"
17
+ sharpie = Sharpie::Builder.new(TestApp)
18
+ sharpie.build!(path)
19
+
20
+ contents = []
21
+ Dir.foreach(path) do |item|
22
+ next if item == "." or item == ".."
23
+ contents << item
24
+ end
25
+
26
+ assert_equal true, contents.include?("posts")
27
+ assert_equal true, contents.include?("index.html")
28
+
29
+ first_post = File.open("#{path}/posts/1.json").read
30
+ assert_equal String, first_post.class
31
+
32
+ parsed_first_post = JSON.parse(first_post)
33
+ assert_equal String, parsed_first_post["title"].class
34
+ assert_equal String, parsed_first_post["body"].class
35
+ end
36
+
37
+ def test_build_sharpie_app
38
+ path = "test/sites/test_sharpie_app"
39
+ TestSharpieApp.build!(path)
40
+
41
+ contents = []
42
+ Dir.foreach(path) do |item|
43
+ next if item == "." or item == ".."
44
+ contents << item
45
+ end
46
+
47
+ assert_equal true, contents.include?("numbers")
48
+ assert_equal true, contents.include?("index.html")
49
+
50
+ 10.times do |i|
51
+ parsed_page = JSON.parse(File.open("#{path}/numbers/#{i}.json").read)
52
+ assert_equal i, parsed_page["number"]
53
+ end
54
+ end
55
+
56
+ end
@@ -0,0 +1,17 @@
1
+ require "bundler/setup"
2
+ require "sharpie"
3
+ require "json"
4
+
5
+ class TestSharpieApp < Sharpie::Base
6
+ get "/" do
7
+ "<html><body><p>Welcome to the index.</p></body></html>"
8
+ end
9
+
10
+ 10.times do |i|
11
+ get "/numbers/#{i}.json" do
12
+ {
13
+ "number" => i
14
+ }.to_json
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,6 @@
1
+ <html>
2
+ <title>Home</title>
3
+ <body>
4
+ <p>Welcome to the index.</p>
5
+ </body>
6
+ </html>
metadata ADDED
@@ -0,0 +1,167 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sharpie
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Alan deLevie
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-07-27 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: sinatra
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: sinatra-advanced-routes
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
+ - !ruby/object:Gem::Dependency
47
+ name: rack-test
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: bundler
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '1.3'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '1.3'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rake
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: pry-rescue
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: Static site generation with a familiar API.
111
+ email:
112
+ - adelevie@gmail.com
113
+ executables: []
114
+ extensions: []
115
+ extra_rdoc_files: []
116
+ files:
117
+ - .gitignore
118
+ - Gemfile
119
+ - LICENSE.txt
120
+ - README.md
121
+ - Rakefile
122
+ - lib/sharpie.rb
123
+ - lib/sharpie/sinatra_static.rb
124
+ - lib/sharpie/version.rb
125
+ - sharpie.gemspec
126
+ - test/helper.rb
127
+ - test/test_app.rb
128
+ - test/test_build.rb
129
+ - test/test_sharpie_app.rb
130
+ - test/views/index.erb
131
+ homepage: http://github.com/adelevie/sharpie
132
+ licenses:
133
+ - MIT
134
+ post_install_message:
135
+ rdoc_options: []
136
+ require_paths:
137
+ - lib
138
+ required_ruby_version: !ruby/object:Gem::Requirement
139
+ none: false
140
+ requirements:
141
+ - - ! '>='
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ segments:
145
+ - 0
146
+ hash: 642336815966126004
147
+ required_rubygems_version: !ruby/object:Gem::Requirement
148
+ none: false
149
+ requirements:
150
+ - - ! '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ segments:
154
+ - 0
155
+ hash: 642336815966126004
156
+ requirements: []
157
+ rubyforge_project:
158
+ rubygems_version: 1.8.24
159
+ signing_key:
160
+ specification_version: 3
161
+ summary: Converts Sinatra apps into static sites.
162
+ test_files:
163
+ - test/helper.rb
164
+ - test/test_app.rb
165
+ - test/test_build.rb
166
+ - test/test_sharpie_app.rb
167
+ - test/views/index.erb