utopia 1.8.3 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/documentation/.bowerrc +4 -0
  4. data/documentation/.rspec +4 -0
  5. data/documentation/Gemfile +27 -0
  6. data/documentation/Rakefile +5 -0
  7. data/documentation/config.ru +50 -0
  8. data/documentation/config/README.md +7 -0
  9. data/documentation/config/environment.rb +10 -0
  10. data/documentation/lib/readme.txt +1 -0
  11. data/documentation/pages/_heading.xnode +2 -0
  12. data/documentation/pages/_page.xnode +28 -0
  13. data/documentation/pages/errors/exception.xnode +5 -0
  14. data/documentation/pages/errors/file-not-found.xnode +5 -0
  15. data/documentation/pages/links.yaml +2 -0
  16. data/documentation/pages/welcome/index.xnode +41 -0
  17. data/documentation/pages/wiki/content.md +7 -0
  18. data/{setup/examples → documentation/pages}/wiki/controller.rb +8 -6
  19. data/documentation/pages/wiki/development-environment-setup/content.md +14 -0
  20. data/{setup/examples → documentation/pages}/wiki/edit.xnode +1 -1
  21. data/documentation/pages/wiki/server-setup/content.md +40 -0
  22. data/documentation/pages/wiki/show.xnode +12 -0
  23. data/documentation/pages/wiki/your-first-page/content.md +31 -0
  24. data/documentation/public +1 -0
  25. data/documentation/spec/website_context.rb +11 -0
  26. data/documentation/spec/website_spec.rb +15 -0
  27. data/documentation/tasks/test.rake +10 -0
  28. data/documentation/tasks/utopia.rake +38 -0
  29. data/lib/utopia/content.rb +2 -2
  30. data/lib/utopia/content/link.rb +5 -1
  31. data/lib/utopia/content/markup.rb +86 -66
  32. data/lib/utopia/content/tag.rb +28 -45
  33. data/lib/utopia/content/transaction.rb +31 -25
  34. data/lib/utopia/controller/actions.rb +1 -0
  35. data/lib/utopia/redirection.rb +4 -4
  36. data/lib/utopia/version.rb +1 -1
  37. data/setup/site/public/_static/site.css +20 -8
  38. data/spec/utopia/content/markup_spec.rb +10 -10
  39. data/spec/utopia/content/tag_spec.rb +36 -0
  40. data/spec/utopia/controller/middleware_spec.ru +4 -1
  41. data/spec/utopia/controller/middleware_spec/controller/controller.rb +2 -0
  42. data/spec/utopia/controller/middleware_spec/controller/nested/controller.rb +2 -0
  43. data/spec/utopia/controller/middleware_spec/redirect/controller.rb +2 -0
  44. data/spec/utopia/controller/middleware_spec/redirect/test/controller.rb +2 -0
  45. data/spec/utopia/controller/respond_spec.ru +5 -2
  46. data/spec/utopia/exceptions/handler_spec.ru +3 -1
  47. data/spec/utopia/exceptions/handler_spec/controller.rb +2 -0
  48. data/spec/utopia/exceptions/mailer_spec.ru +6 -2
  49. data/spec/utopia/localization_spec.rb +2 -2
  50. data/spec/utopia/localization_spec.ru +2 -1
  51. data/spec/utopia/localization_spec/controller.rb +2 -0
  52. data/spec/utopia/performance_spec/config.ru +1 -0
  53. data/spec/utopia/performance_spec/pages/api/controller.rb +1 -1
  54. data/utopia.gemspec +3 -3
  55. metadata +36 -14
  56. data/ext/utopia/xnode/fast_scanner/extconf.rb +0 -6
  57. data/ext/utopia/xnode/fast_scanner/parser.c +0 -289
  58. data/setup/examples/wiki/index.xnode +0 -10
  59. data/setup/examples/wiki/welcome/content.md +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5095d35222a513f2daa3c4b93e1a03490fa89654
4
- data.tar.gz: 6d71788ce9d2d1cd24e65ccb1314946e3d2c692f
3
+ metadata.gz: 92b8e6466b0a5eea4cb1e6009734e9cea5c76160
4
+ data.tar.gz: 9854cb98bf4f4ac5794fe19370c3af2e28aec456
5
5
  SHA512:
6
- metadata.gz: 6ba7fadd9730016d29fdefb2ff26ca2911867daa811290bd40a76f7cd640af4ea534e3ab8f040f97fc75b1f445bb81cf133295a77d9bf4a5c519014c077299a4
7
- data.tar.gz: cc97dcf681d73a609e2adfd1d6422403340a2708e0763f1229ec34d4bc7ddd67e1491932da42c9df801f719ada966432068092a5437a8c0a51eca122847dcd4b
6
+ metadata.gz: fdc050063c8b3b7ece0d94ee388fec013f52adc0cc2f63f92a7e4bb94eb849a8ecbfb41664a183047475adc88f5959b019077edc5cdbb9061eb8b8a8057a2a60
7
+ data.tar.gz: 781fe07c015abd3d777f2b4cd0340d43deee4846ca05ec2171c882569bd56add14604cc54ae5276b414dc778be77d2be7c86e90835a4793abb1df52b462b4117
data/Gemfile CHANGED
@@ -7,6 +7,8 @@ group :development do
7
7
  gem 'pry'
8
8
  gem 'pry-coolline'
9
9
 
10
+ gem 'kramdown'
11
+
10
12
  gem 'json'
11
13
  end
12
14
 
@@ -0,0 +1,4 @@
1
+ {
2
+ "directory" : "public/_static/components"
3
+ }
4
+
@@ -0,0 +1,4 @@
1
+ --color
2
+ --format documentation
3
+ --backtrace
4
+ --warnings
@@ -0,0 +1,27 @@
1
+
2
+ source "https://rubygems.org"
3
+
4
+ gem "utopia", path: File.expand_path("../", __dir__)
5
+
6
+ gem "rake"
7
+ gem "bundler"
8
+
9
+ gem "kramdown"
10
+
11
+ group :development do
12
+ # For `rake server`:
13
+ gem "puma"
14
+
15
+ # For `rake console`:
16
+ gem "pry"
17
+ gem "rack-test"
18
+
19
+ # For `rspec` testing:
20
+ gem "rspec"
21
+ gem "simplecov"
22
+ end
23
+
24
+ group :production do
25
+ # Used for passenger-config to restart server after deployment:
26
+ gem "passenger"
27
+ end
@@ -0,0 +1,5 @@
1
+
2
+ # Load all rake tasks:
3
+ import(*Dir.glob('tasks/*.rake'))
4
+
5
+ task :default => :server
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env rackup
2
+
3
+ require_relative 'config/environment'
4
+
5
+ if RACK_ENV == :production
6
+ # Handle exceptions in production with a error page and send an email notification:
7
+ use Utopia::Exceptions::Handler
8
+ use Utopia::Exceptions::Mailer
9
+ else
10
+ # We want to propate exceptions up when running tests:
11
+ use Rack::ShowExceptions unless RACK_ENV == :test
12
+
13
+ # Serve the public directory in a similar way to the web server:
14
+ use Utopia::Static, root: 'public'
15
+ end
16
+
17
+ use Rack::Sendfile
18
+
19
+ use Utopia::ContentLength
20
+
21
+ use Utopia::Redirection::Rewrite,
22
+ '/' => '/welcome/index'
23
+
24
+ use Utopia::Redirection::DirectoryIndex
25
+
26
+ use Utopia::Redirection::Errors,
27
+ 404 => '/errors/file-not-found'
28
+
29
+ use Utopia::Localization,
30
+ :default_locale => 'en',
31
+ :locales => ['en', 'de', 'ja', 'zh'],
32
+ :nonlocalized => ['/_static/', '/_cache/']
33
+
34
+ use Utopia::Controller,
35
+ cache_controllers: (RACK_ENV == :production),
36
+ base: Utopia::Controller::Base
37
+
38
+ use Utopia::Static
39
+
40
+ # Serve dynamic content
41
+ use Utopia::Content,
42
+ cache_templates: (RACK_ENV == :production),
43
+ tags: {
44
+ 'deferred' => Utopia::Tags::Deferred,
45
+ 'override' => Utopia::Tags::Override,
46
+ 'node' => Utopia::Tags::Node,
47
+ 'environment' => Utopia::Tags::Environment.for(RACK_ENV)
48
+ }
49
+
50
+ run lambda { |env| [404, {}, []] }
@@ -0,0 +1,7 @@
1
+ # Utopia Config
2
+
3
+ This directory contains `environment.rb` which is used to initialize the running environment for tasks and servers.
4
+
5
+ ## Setting Environment Variables
6
+
7
+ If you wish to set environment variables on a per-deployment basis, you can do so by creating an `config/environment.yaml` and populating it with key-value pairs.
@@ -0,0 +1,10 @@
1
+
2
+ require 'bundler/setup'
3
+ Bundler.setup
4
+
5
+ require 'utopia/setup'
6
+ Utopia.setup
7
+
8
+ RACK_ENV = ENV.fetch('RACK_ENV', :development).to_sym unless defined? RACK_ENV
9
+
10
+ require 'kramdown'
@@ -0,0 +1 @@
1
+ You can add additional code for your application in this directory, and require it directly from the config.ru.
@@ -0,0 +1,2 @@
1
+ <?r transaction.attributes[:title] ||= content ?>
2
+ <h1><content/></h1>
@@ -0,0 +1,28 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <?r response.content_type = "text/html; charset=utf-8" ?>
5
+ <?r response.cache! ?>
6
+
7
+ <?r if title = self[:title] ?>
8
+ <title>#{title.gsub(/<.*?>/, "")} - Utopia</title>
9
+ <?r else ?>
10
+ <title>Utopia</title>
11
+ <?r end ?>
12
+
13
+ <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous" />
14
+
15
+ <link rel="icon" type="image/png" href="/_static/icon.png" />
16
+ <link rel="stylesheet" href="/_static/site.css" type="text/css" media="screen" />
17
+ </head>
18
+
19
+ <body class="#{attributes[:class]}">
20
+ <header>
21
+ <img src="/_static/utopia.svg" />
22
+ </header>
23
+
24
+ <div id="page">
25
+ <content />
26
+ </div>
27
+ </body>
28
+ </html>
@@ -0,0 +1,5 @@
1
+ <page>
2
+ <heading>Exception</heading>
3
+
4
+ <p>It seems like something didn't quite work out as expected!</p>
5
+ </page>
@@ -0,0 +1,5 @@
1
+ <page>
2
+ <heading>File Not Found</heading>
3
+
4
+ <p>The file you requested is unfortunately not available at this time!</p>
5
+ </page>
@@ -0,0 +1,2 @@
1
+ errors:
2
+ display: false
@@ -0,0 +1,41 @@
1
+ <page class="front">
2
+ <heading>Welcome to Utopia...</heading>
3
+
4
+ <section class="features">
5
+ <div>
6
+ <i class="fa fa-bolt"></i>
7
+ <h2>Low latency and high throughput</h2>
8
+ <p>Utopia has been carefully tuned for low-latency and algorithmic efficiency. During development, requests reload the entire stack, while in production everything is cached using <a href="http://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Map.html">thread-safe data-structures</a>. Serve thousands of requests per second with ease.</p>
9
+ </div>
10
+
11
+ <div>
12
+ <i class="fa fa-cubes"></i>
13
+ <h2>Modular code and structure</h2>
14
+ <p>Utopia provides independently useful <a href="https://github.com/rack/rack">Rack</a> middleware and has been designed with simplicify in mind. Several fully-featured webapps and a ton of commercial websites have guided the development of the Utopia stack. It is capable of handling a diverse range of requirements.</p>
15
+ </div>
16
+
17
+ <div>
18
+ <i class="fa fa-code"></i>
19
+ <h2>Well tested and maintained</h2>
20
+ <p>Utopia comprises a <a href="https://github.com/ioquatix/utopia">core gem</a> and several supporting libraries, the main ones being <a href="https://github.com/ioquatix/trenni">trenni</a> for templates and parsing, and <a href="https://github.com/ioquatix/http-accept">http-accept</a> for HTTP header processing. Together, these gems have over 90% test coverage.</p>
21
+ </div>
22
+
23
+ <div>
24
+ <i class="fa fa-server"></i>
25
+ <h2>Batteries included</h2>
26
+ <p>Utopia includes both a recommended development model and a server deployment model out of the box. This is exposed via the <code>utopia</code> command. We recommend use of <a href="https://www.nginx.com">Nginx</a> and <a href="https://www.phusionpassenger.com">Passenger</a> for server side deployment.</p>
27
+ </div>
28
+
29
+ <div>
30
+ <i class="fa fa-globe"></i>
31
+ <h2>Standards compliant localization</h2>
32
+ <p>Utopia supports the <code>Accept-Language</code> header and transparently selects the correct view to render. Build multi-lingual websites and webapps easily: translate content incrementally as required, or not at all.</p>
33
+ </div>
34
+ </section>
35
+
36
+ <section>
37
+ <h2>Documentation</h2>
38
+
39
+ <p>For up-to-date documentation, please browse the included <a href="/wiki/">wiki</a>. Feel free to improve it and submit a PR :)</p>
40
+ </section>
41
+ </page>
@@ -0,0 +1,7 @@
1
+ # Welcome to Utopia
2
+
3
+ This wiki includes documentation and examples showing how to use Utopia.
4
+
5
+ - [Development Environment Setup](development-environment-setup/)
6
+ - [Server Setup](server-setup/)
7
+ - [Your first page](your-first-page/)
@@ -4,18 +4,20 @@ prepend Actions
4
4
  on '**' do |request, path|
5
5
  @page_path = path.components[0..-2]
6
6
 
7
- if @page_path.empty?
8
- goto! "welcome/index"
9
- end
10
-
11
7
  @page_file = File.join(BASE_PATH, @page_path, "content.md")
12
- @page_title = Trenni::Strings::to_title @page_path.last
8
+
9
+ if last_path_component = @page_path.last
10
+ @page_title = Trenni::Strings::to_title(last_path_component)
11
+ else
12
+ @page_title = "Wiki"
13
+ end
13
14
  end
14
15
 
15
16
  def read_contents
16
17
  if File.exist? @page_file
17
18
  File.read(@page_file)
18
19
  else
20
+ "\# #{@page_title}\n\n" +
19
21
  "This page is empty."
20
22
  end
21
23
  end
@@ -37,5 +39,5 @@ end
37
39
  on '**/index' do |request, path|
38
40
  @content = read_contents
39
41
 
40
- path.components = ["index"]
42
+ path.components = ["show"]
41
43
  end
@@ -0,0 +1,14 @@
1
+ # Development Environment Setup
2
+
3
+ Utopia is built on Ruby and Rack. Therefore, Ruby (suggested 2.0+) should be installed and working. Then, simply run:
4
+
5
+ $ gem install utopia
6
+
7
+ To install all required dependencies.
8
+
9
+ Utopia and it's dependencies are built on Linux and Mac by default, and therefore compatibility with Windows is not guaranteed.
10
+
11
+ ## Atom Integration
12
+
13
+ Utopia uses [Trenni](https://github.com/ioquatix/trenni) for templates and it has a syntax slightly different from ERB. However, there is a [package for Atom](https://atom.io/packages/language-trenni) which provides accurate syntax highlighting.
14
+
@@ -5,7 +5,7 @@
5
5
  <form action="#" method="post">
6
6
  <fieldset>
7
7
  <legend>Page Content</legend>
8
- <textarea name="content">#{Strings::to_html self[:content]}</textarea>
8
+ <textarea name="content">#{self[:content]}</textarea>
9
9
  </fieldset>
10
10
 
11
11
  <fieldset class="footer">
@@ -0,0 +1,40 @@
1
+ # Server Setup
2
+
3
+ The best deployment platform for Utopia is Linux. Specifically, [Arch Linux](https://www.archlinux.org/) with the following packages:
4
+
5
+ - [nginx-mainline-passenger](https://aur.archlinux.org/packages/nginx-mainline-passenger/)
6
+ - [passenger-nginx-module](https://aur.archlinux.org/packages/passenger-nginx-module/)
7
+
8
+ There have been issues with the official packages and thus these packages were developed and tested with Utopia deployment in mind.
9
+
10
+ ## Sample Nginx Configuration
11
+
12
+ Create a configuration file for your site, e.g. `/etc/nginx/sites/www.example.com`:
13
+
14
+ server {
15
+ listen 80;
16
+ server_name www.example.com;
17
+ root /srv/http/www.example.com/public;
18
+ passenger_enabled on;
19
+ }
20
+
21
+ server {
22
+ listen 80;
23
+ server_name example.com;
24
+ rewrite ^ http://www.example.com$uri permanent;
25
+ }
26
+
27
+ ## Deployment via Git
28
+
29
+ The preferred method of deployment to a production server is via git. The `utopia` command assists with setup of a remote git repository on the server. It will setup a `git` `post-update` hook which will deploy the site correctly and restart passenger for that site.
30
+
31
+ To setup a server for deployment:
32
+
33
+ $ mkdir /srv/http/www.example.com
34
+ $ cd /srv/http/www.example.com
35
+ $ sudo -u http utopia server create
36
+
37
+ On your development machine, you should setup the git remote:
38
+
39
+ $ git remote add production ssh://remote/srv/http/www.example.com
40
+ $ git push --set-upstream production master
@@ -0,0 +1,12 @@
1
+ <page>
2
+ <?r
3
+ transaction.attributes[:title] ||= @page_title
4
+ ?>
5
+
6
+ #{MarkupString.raw Kramdown::Document.new(self[:content]).to_html}
7
+
8
+ <footer>
9
+ Last Modified: #{File.mtime(self[:page_file]) rescue "N/A"} &mdash;
10
+ <a href="edit">Edit</a>
11
+ </footer>
12
+ </page>
@@ -0,0 +1,31 @@
1
+ # Your First Page
2
+
3
+ To setup the default site, simply create a directory and use the `utopia` command:
4
+
5
+ $ mkdir www.example.com
6
+ $ cd www.example.com
7
+ $ utopia site create
8
+ $ rake server
9
+
10
+ You will now have a basic template site running on http://localhost:9292.
11
+
12
+ ## Welcome Page
13
+
14
+ Utopia includes a redirection middleware to redirect all root-level requests to a given URI. The default being `/welcome/index`:
15
+
16
+ use Utopia::Redirection::Rewrite,
17
+ '/' => '/welcome/index'
18
+
19
+ This page includes a basic overview of Utopia. Most of it's standard HTML, except for the outer `<page>` tag. Utopia uses the name `page` to lookup the file-system hierarchy. First, it looks for `/welcome/_page.xnode`, and then it looks for `/_page.xnode` which it finds. This page template includes a tag `<content/>` which is replaced with the inner body of the `<page>` tag. This recursive lookup is the heart of Utopia.
20
+
21
+ ## Links
22
+
23
+ Utopia is a content-centric web application platform. It leverages the file-system to provide a mapping between logical resources and files on disk. The primary mode of mapping incoming requests to specific nodes (content) is done using the `links.yaml` file.
24
+
25
+ The links file associates metadata with node names for a given directory. This can include things like redirects, titles, descriptions, etc. You can add any metadata you like, to support your specific use-case. The primary use of the links files is to provide site structure, e.g. menus. In addition, they can function as a rudimentary data-store for static information, e.g. a list of applications (each with it's own page), a list of features, etc.
26
+
27
+ You'll notice that there is a file `/links.yaml`. This file contains important metadata relating to the `errors` subdirectory. As we don't want these nodes showing up in a top level menu, we mark them as `display: false`
28
+
29
+ errors:
30
+ display: false
31
+
@@ -0,0 +1 @@
1
+ ../setup/site/public
@@ -0,0 +1,11 @@
1
+
2
+ require 'rack/test'
3
+
4
+ RSpec.shared_context "website" do
5
+ include Rack::Test::Methods
6
+
7
+ let(:rackup_path) {File.expand_path('../config.ru', __dir__)}
8
+ let(:rackup_directory) {File.dirname(rackup_path)}
9
+
10
+ let(:app) {Rack::Builder.parse_file(rackup_path).first}
11
+ end
@@ -0,0 +1,15 @@
1
+
2
+ require_relative 'website_context'
3
+
4
+ # Learn about best practice specs from http://betterspecs.org
5
+ RSpec.describe "my website" do
6
+ include_context "website"
7
+
8
+ it "should have an accessible front page" do
9
+ get "/"
10
+
11
+ follow_redirect!
12
+
13
+ expect(last_response.status).to be == 200
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:test) do |task|
5
+ task.rspec_opts = %w{--require simplecov} if ENV['COVERAGE']
6
+ end
7
+
8
+ task :coverage do
9
+ ENV['COVERAGE'] = 'y'
10
+ end