tetrahedron 0.0.0.1
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.
- checksums.yaml +7 -0
 - data/.gitignore +6 -0
 - data/AUTHORS +0 -0
 - data/Gemfile +3 -0
 - data/Gemfile.lock +65 -0
 - data/LICENSE +0 -0
 - data/README.md +4 -0
 - data/Rakefile +2 -0
 - data/bin/tetrahedron +4 -0
 - data/config/app.ru +21 -0
 - data/config/application.rb +8 -0
 - data/config/environment.rb +18 -0
 - data/config/puma.rb +29 -0
 - data/lib/tetrahedron.rb +59 -0
 - data/lib/tetrahedron/app.rb +16 -0
 - data/lib/tetrahedron/assets.rb +43 -0
 - data/lib/tetrahedron/base.rb +34 -0
 - data/lib/tetrahedron/bootfile.rb +43 -0
 - data/lib/tetrahedron/bundler.rb +10 -0
 - data/lib/tetrahedron/configuration.rb +44 -0
 - data/lib/tetrahedron/controller.rb +17 -0
 - data/lib/tetrahedron/database.rb +113 -0
 - data/lib/tetrahedron/endpoint.rb +4 -0
 - data/lib/tetrahedron/environment.rb +28 -0
 - data/lib/tetrahedron/error.rb +4 -0
 - data/lib/tetrahedron/errors.rb +7 -0
 - data/lib/tetrahedron/gem.rb +58 -0
 - data/lib/tetrahedron/model.rb +32 -0
 - data/lib/tetrahedron/rake.rb +16 -0
 - data/lib/tetrahedron/redis.rb +4 -0
 - data/lib/tetrahedron/sessions.rb +28 -0
 - data/lib/tetrahedron/tasks/tet.rake +5 -0
 - data/tetrahedron.gemspec +34 -0
 - metadata +174 -0
 
    
        checksums.yaml
    ADDED
    
    | 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ---
         
     | 
| 
      
 2 
     | 
    
         
            +
            SHA1:
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: f11bb282f14b3b5c27899cdb70fef27f4154dc20
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: a04eafc6d60df291569009131ee564c5fc404b44
         
     | 
| 
      
 5 
     | 
    
         
            +
            SHA512:
         
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: acb35b1fe3d7a07905a753ff2d8422db1478a097f22d18840230085cf14b8c108e0257a5c71ebc10e5969c7bd8eb3ef565638ed343f883ae8512b4195c47dce6
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 1c7365409ba0e9bf0d686a849df7d4a445730a23685af903c50bb2193e702960224be195dc8cc0e0265a5d0f33fd39ed3057443cb7f7f834456ef9b97794a2ab
         
     | 
    
        data/.gitignore
    ADDED
    
    
    
        data/AUTHORS
    ADDED
    
    | 
         
            File without changes
         
     | 
    
        data/Gemfile
    ADDED
    
    
    
        data/Gemfile.lock
    ADDED
    
    | 
         @@ -0,0 +1,65 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            PATH
         
     | 
| 
      
 2 
     | 
    
         
            +
              remote: .
         
     | 
| 
      
 3 
     | 
    
         
            +
              specs:
         
     | 
| 
      
 4 
     | 
    
         
            +
                tetrahedron (0.0.0.1)
         
     | 
| 
      
 5 
     | 
    
         
            +
                  activesupport
         
     | 
| 
      
 6 
     | 
    
         
            +
                  sequel
         
     | 
| 
      
 7 
     | 
    
         
            +
                  sinatra
         
     | 
| 
      
 8 
     | 
    
         
            +
                  sinatra-contrib
         
     | 
| 
      
 9 
     | 
    
         
            +
                  thor
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            GEM
         
     | 
| 
      
 12 
     | 
    
         
            +
              remote: https://rubygems.org/
         
     | 
| 
      
 13 
     | 
    
         
            +
              specs:
         
     | 
| 
      
 14 
     | 
    
         
            +
                activesupport (4.2.5)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  i18n (~> 0.7)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  json (~> 1.7, >= 1.7.7)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  minitest (~> 5.1)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  thread_safe (~> 0.3, >= 0.3.4)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  tzinfo (~> 1.1)
         
     | 
| 
      
 20 
     | 
    
         
            +
                backports (3.6.7)
         
     | 
| 
      
 21 
     | 
    
         
            +
                coderay (1.1.0)
         
     | 
| 
      
 22 
     | 
    
         
            +
                i18n (0.7.0)
         
     | 
| 
      
 23 
     | 
    
         
            +
                json (1.8.3)
         
     | 
| 
      
 24 
     | 
    
         
            +
                method_source (0.8.2)
         
     | 
| 
      
 25 
     | 
    
         
            +
                minitest (5.8.3)
         
     | 
| 
      
 26 
     | 
    
         
            +
                multi_json (1.11.2)
         
     | 
| 
      
 27 
     | 
    
         
            +
                pry (0.10.3)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  coderay (~> 1.1.0)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  method_source (~> 0.8.1)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  slop (~> 3.4)
         
     | 
| 
      
 31 
     | 
    
         
            +
                rack (1.6.4)
         
     | 
| 
      
 32 
     | 
    
         
            +
                rack-protection (1.5.3)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  rack
         
     | 
| 
      
 34 
     | 
    
         
            +
                rack-test (0.6.3)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  rack (>= 1.0)
         
     | 
| 
      
 36 
     | 
    
         
            +
                rake (10.4.2)
         
     | 
| 
      
 37 
     | 
    
         
            +
                sequel (4.28.0)
         
     | 
| 
      
 38 
     | 
    
         
            +
                sinatra (1.4.6)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  rack (~> 1.4)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  rack-protection (~> 1.4)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  tilt (>= 1.3, < 3)
         
     | 
| 
      
 42 
     | 
    
         
            +
                sinatra-contrib (1.4.6)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  backports (>= 2.0)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  multi_json
         
     | 
| 
      
 45 
     | 
    
         
            +
                  rack-protection
         
     | 
| 
      
 46 
     | 
    
         
            +
                  rack-test
         
     | 
| 
      
 47 
     | 
    
         
            +
                  sinatra (~> 1.4.0)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  tilt (>= 1.3, < 3)
         
     | 
| 
      
 49 
     | 
    
         
            +
                slop (3.6.0)
         
     | 
| 
      
 50 
     | 
    
         
            +
                thor (0.19.1)
         
     | 
| 
      
 51 
     | 
    
         
            +
                thread_safe (0.3.5)
         
     | 
| 
      
 52 
     | 
    
         
            +
                tilt (2.0.1)
         
     | 
| 
      
 53 
     | 
    
         
            +
                tzinfo (1.2.2)
         
     | 
| 
      
 54 
     | 
    
         
            +
                  thread_safe (~> 0.1)
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
            PLATFORMS
         
     | 
| 
      
 57 
     | 
    
         
            +
              ruby
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
            DEPENDENCIES
         
     | 
| 
      
 60 
     | 
    
         
            +
              pry
         
     | 
| 
      
 61 
     | 
    
         
            +
              rake
         
     | 
| 
      
 62 
     | 
    
         
            +
              tetrahedron!
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
            BUNDLED WITH
         
     | 
| 
      
 65 
     | 
    
         
            +
               1.10.6
         
     | 
    
        data/LICENSE
    ADDED
    
    | 
         
            File without changes
         
     | 
    
        data/README.md
    ADDED
    
    
    
        data/Rakefile
    ADDED
    
    
    
        data/bin/tetrahedron
    ADDED
    
    
    
        data/config/app.ru
    ADDED
    
    | 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env rackup
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative 'application'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require_relative 'environment'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            # TODO(mtwilliams): Request tracking (make Heroku compatiable).
         
     | 
| 
      
 7 
     | 
    
         
            +
            # TODO(mtwilliams): Performance monitoring (make Heroku compatiable).
         
     | 
| 
      
 8 
     | 
    
         
            +
            # TODO(mtwilliams): Error handling.
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            if Tetrahedron::Sessions.configured?
         
     | 
| 
      
 11 
     | 
    
         
            +
              use Rack::Session::Cookie, :key => Tetrahedron::Sessions.config.cookie,
         
     | 
| 
      
 12 
     | 
    
         
            +
                                         :domain => Tetrahedron::Sessions.config.domain,
         
     | 
| 
      
 13 
     | 
    
         
            +
                                         :expire_after => Tetrahedron::Sessions.config.lifetime,
         
     | 
| 
      
 14 
     | 
    
         
            +
                                         :secret => Tetrahedron::Sessions.config.secret
         
     | 
| 
      
 15 
     | 
    
         
            +
            else
         
     | 
| 
      
 16 
     | 
    
         
            +
              # TODO(mtwilliams): Use a logger.
         
     | 
| 
      
 17 
     | 
    
         
            +
              $stderr.puts "Sessions not configured!\n => Use Tetrahedron::Sessions.configure in config/environment.rb!"
         
     | 
| 
      
 18 
     | 
    
         
            +
            end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            # TODO(mtwilliams): Remove cylcical dependency so we can use a constantized version.
         
     | 
| 
      
 21 
     | 
    
         
            +
            run Tetrahedron.config.app.constantize
         
     | 
| 
         @@ -0,0 +1,18 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require_relative 'application'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Tetrahedron::Environment.load
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            if Tetrahedron.env.development?
         
     | 
| 
      
 6 
     | 
    
         
            +
              # Synchronize STDOUT and STDERR to make debugging easier.
         
     | 
| 
      
 7 
     | 
    
         
            +
              STDOUT.sync = STDERR.sync = true
         
     | 
| 
      
 8 
     | 
    
         
            +
            end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            require File.join(Tetrahedron.config.root, "config", "environment")
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            unless Tetrahedron::Database.configured?
         
     | 
| 
      
 13 
     | 
    
         
            +
              $stderr.puts "Database not configured!\n => Use Tetrahedron::Database.configure in config/environment.rb!"
         
     | 
| 
      
 14 
     | 
    
         
            +
            end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            # unless Tetrahedron::Redis.configured?
         
     | 
| 
      
 17 
     | 
    
         
            +
            #   $stderr.puts "Redis not configured!\n => Use Tetrahedron::Redis.configure in config/environment.rb!"
         
     | 
| 
      
 18 
     | 
    
         
            +
            # end
         
     | 
    
        data/config/puma.rb
    ADDED
    
    | 
         @@ -0,0 +1,29 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require_relative 'application'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require_relative 'environment'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            rackup      File.join(Tetrahedron.root, 'config', 'app.ru')
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            environment Tetrahedron.env.to_s
         
     | 
| 
      
 7 
     | 
    
         
            +
            bind        "tcp://#{ENV['HOST'] || '0.0.0.0'}:#{ENV['PORT'] || 80}"
         
     | 
| 
      
 8 
     | 
    
         
            +
            port        (ENV['PORT'] || 80).to_i
         
     | 
| 
      
 9 
     | 
    
         
            +
            workers     (ENV['PUMA_WORKERS'] || 1).to_i
         
     | 
| 
      
 10 
     | 
    
         
            +
            threads     (ENV['PUMA_MIN_THREADS'] || 1).to_i,
         
     | 
| 
      
 11 
     | 
    
         
            +
                        (ENV['PUMA_MAX_THREADS'] || 1).to_i
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            preload_app!
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            before_fork do
         
     | 
| 
      
 16 
     | 
    
         
            +
              if Tetrahedron.env.production?
         
     | 
| 
      
 17 
     | 
    
         
            +
                # TODO(mtwilliams): Precompile assets.
         
     | 
| 
      
 18 
     | 
    
         
            +
                Tetrahedron::Assets.precompile
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
            end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            on_worker_boot do
         
     | 
| 
      
 23 
     | 
    
         
            +
              Tetrahedron.bootfile.up.call() if Tetrahedron.bootfile.up
         
     | 
| 
      
 24 
     | 
    
         
            +
            end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            # TODO(mtwilliams): Report low-level errors in production.
         
     | 
| 
      
 27 
     | 
    
         
            +
             # lowlevel_error_handler do |e|
         
     | 
| 
      
 28 
     | 
    
         
            +
             #   ...
         
     | 
| 
      
 29 
     | 
    
         
            +
             # end
         
     | 
    
        data/lib/tetrahedron.rb
    ADDED
    
    | 
         @@ -0,0 +1,59 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'bundler'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            Bundler.require(:default)
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            # Some things aren't nicely cut gems, unforunately.
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'base64'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'erb'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'net/http'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'ostruct'
         
     | 
| 
      
 11 
     | 
    
         
            +
            require 'securerandom'
         
     | 
| 
      
 12 
     | 
    
         
            +
            require 'socket'
         
     | 
| 
      
 13 
     | 
    
         
            +
            require 'time'
         
     | 
| 
      
 14 
     | 
    
         
            +
            require 'uri'
         
     | 
| 
      
 15 
     | 
    
         
            +
            require 'yaml'
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            # Smells like Rails...
         
     | 
| 
      
 18 
     | 
    
         
            +
            require 'active_support'
         
     | 
| 
      
 19 
     | 
    
         
            +
            require 'active_support/core_ext'
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            module Tetrahedron
         
     | 
| 
      
 22 
     | 
    
         
            +
              def self.root
         
     | 
| 
      
 23 
     | 
    
         
            +
                @root ||= File.expand_path(File.join(File.dirname(__FILE__), '..'))
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
            end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            require 'tetrahedron/gem'
         
     | 
| 
      
 28 
     | 
    
         
            +
            require 'tetrahedron/bundler'
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            require 'tetrahedron/error'
         
     | 
| 
      
 31 
     | 
    
         
            +
            require 'tetrahedron/errors'
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            require 'tetrahedron/configuration'
         
     | 
| 
      
 34 
     | 
    
         
            +
            require 'tetrahedron/environment'
         
     | 
| 
      
 35 
     | 
    
         
            +
            require 'tetrahedron/bootfile'
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            Tetrahedron::Bundler.require
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            require 'sinatra/base'
         
     | 
| 
      
 40 
     | 
    
         
            +
            require 'sinatra/contrib'
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            require 'sequel'
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            Sequel.extension :migration
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            Sequel::Model.plugin :timestamps
         
     | 
| 
      
 47 
     | 
    
         
            +
            Sequel::Model.plugin :subclasses
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            require 'tetrahedron/base'
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
            require 'tetrahedron/assets'
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
            require 'tetrahedron/database'
         
     | 
| 
      
 54 
     | 
    
         
            +
            require 'tetrahedron/sessions'
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
            require 'tetrahedron/app'
         
     | 
| 
      
 57 
     | 
    
         
            +
            require 'tetrahedron/model'
         
     | 
| 
      
 58 
     | 
    
         
            +
            require 'tetrahedron/controller'
         
     | 
| 
      
 59 
     | 
    
         
            +
            require 'tetrahedron/endpoint'
         
     | 
| 
         @@ -0,0 +1,16 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Tetrahedron
         
     | 
| 
      
 2 
     | 
    
         
            +
              class App < Tetrahedron::Base
         
     | 
| 
      
 3 
     | 
    
         
            +
                configure do
         
     | 
| 
      
 4 
     | 
    
         
            +
                  environment = Tetrahedron::Assets::Environment.new
         
     | 
| 
      
 5 
     | 
    
         
            +
                  set :assets, environment: environment
         
     | 
| 
      
 6 
     | 
    
         
            +
                  sprockets_based_server = Tetrahedron::Assets::Server.new(settings.assets[:environment])
         
     | 
| 
      
 7 
     | 
    
         
            +
                  set :assets, server: sprockets_based_server
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                get %r{^/assets/*} do
         
     | 
| 
      
 11 
     | 
    
         
            +
                  # Assets are handled by Sprockets.
         
     | 
| 
      
 12 
     | 
    
         
            +
                  env['PATH_INFO'].sub('/assets', '')
         
     | 
| 
      
 13 
     | 
    
         
            +
                  settings.assets[:server].call!(env)
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,43 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Tetrahedron
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Assets
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Environment < Sprockets::Environment
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def initialize
         
     | 
| 
      
 5 
     | 
    
         
            +
                    super(Tetrahedron.config.root)
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                    self.append_path('vendor/assets/styles')
         
     | 
| 
      
 8 
     | 
    
         
            +
                    self.append_path('vendor/assets/scripts')
         
     | 
| 
      
 9 
     | 
    
         
            +
                    self.append_path('vendor/assets/fonts')
         
     | 
| 
      
 10 
     | 
    
         
            +
                    self.append_path('vendor/assets/images')
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                    self.append_path('assets/styles')
         
     | 
| 
      
 13 
     | 
    
         
            +
                    self.append_path('assets/scripts')
         
     | 
| 
      
 14 
     | 
    
         
            +
                    self.append_path('assets/fonts')
         
     | 
| 
      
 15 
     | 
    
         
            +
                    self.append_path('assets/images')
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                    if Tetrahedron.env.production?
         
     | 
| 
      
 18 
     | 
    
         
            +
                      self.css_compressor = CSSminify.new
         
     | 
| 
      
 19 
     | 
    
         
            +
                      self.js_compressor = Uglifier.new
         
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                class Server
         
     | 
| 
      
 25 
     | 
    
         
            +
                  def initialize(environment)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    @environment = environment
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  def call(env)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    @environment.call(env)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                class Precompiler
         
     | 
| 
      
 35 
     | 
    
         
            +
                  # Precompile.
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                def self.precompile
         
     | 
| 
      
 39 
     | 
    
         
            +
                  # TODO(mtwilliams): Implement asset precompilation.
         
     | 
| 
      
 40 
     | 
    
         
            +
                  $stderr.puts "Asset precompilation is not implemented yet!"
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,34 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Tetrahedron
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Base < Sinatra::Base
         
     | 
| 
      
 3 
     | 
    
         
            +
                set :environment, Tetrahedron.env.to_sym
         
     | 
| 
      
 4 
     | 
    
         
            +
                set :root, Tetrahedron.config.root
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                # Don't use the built-in web-server.
         
     | 
| 
      
 7 
     | 
    
         
            +
                set :run, false
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                # Errors are bubbled so they can be handled by middleware.
         
     | 
| 
      
 10 
     | 
    
         
            +
                set :dump_errors, false
         
     | 
| 
      
 11 
     | 
    
         
            +
                set :raise_errors, true
         
     | 
| 
      
 12 
     | 
    
         
            +
                set :show_exceptions, false
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                # Fuck you, IE9.
         
     | 
| 
      
 15 
     | 
    
         
            +
                disable :method_override
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                configure :development do
         
     | 
| 
      
 18 
     | 
    
         
            +
                  # King of iteration, baby.
         
     | 
| 
      
 19 
     | 
    
         
            +
                  register Sinatra::Reloader
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                configure do
         
     | 
| 
      
 23 
     | 
    
         
            +
                  disable :static
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                get '/*' do
         
     | 
| 
      
 27 
     | 
    
         
            +
                  # Try to serve statically first.
         
     | 
| 
      
 28 
     | 
    
         
            +
                  server = Rack::Static.new(proc {[404, {}, []]}, root: File.join(Tetrahedron.config.root, '/public'))
         
     | 
| 
      
 29 
     | 
    
         
            +
                  status, headers, response = server.call(env)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  pass if status == 404
         
     | 
| 
      
 31 
     | 
    
         
            +
                  [status, headers, response]
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,43 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Tetrahedron
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Bootfile
         
     | 
| 
      
 3 
     | 
    
         
            +
                DEFAULT = "config/boot.rb"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                attr_reader :up
         
     | 
| 
      
 6 
     | 
    
         
            +
                attr_reader :down
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def initialize()
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # TODO(mtwilliams): Provide reasonable defaults.
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def self.load(filename=Tetrahedron::Bootfile::DEFAULT)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  bootfile = Tetrahedron::Bootfile.new
         
     | 
| 
      
 14 
     | 
    
         
            +
                  require File.join(Tetrahedron.root, "config", "application")
         
     | 
| 
      
 15 
     | 
    
         
            +
                  DomainSpecificLanguage.for(bootfile).instance_eval(File.read(filename), filename)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  bootfile
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                class DomainSpecificLanguage
         
     | 
| 
      
 20 
     | 
    
         
            +
                  def initialize(bootfile)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    @bootfile = bootfile
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  def up(&block)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    @bootfile.instance_variable_set(:@up, block)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  def down(&block)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    @bootfile.instance_variable_set(:@down, block)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  def self.for(bootfile)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    DomainSpecificLanguage.new(bootfile)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
              def self.bootfile(path=Tetrahedron::Bootfile::DEFAULT)
         
     | 
| 
      
 39 
     | 
    
         
            +
                @bootfile ||= begin
         
     | 
| 
      
 40 
     | 
    
         
            +
                  Bootfile.load(path)
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,44 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Tetrahedron
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Configuration
         
     | 
| 
      
 3 
     | 
    
         
            +
                DEFAULT = "config/tetrahedron.rb"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                attr_reader :app
         
     | 
| 
      
 6 
     | 
    
         
            +
                attr_reader :root
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def initialize()
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # TODO(mtwilliams): Best guess @app and @root.
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def self.load(filename=Tetrahedron::Configuration::DEFAULT)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  configuration = Tetrahedron::Configuration.new
         
     | 
| 
      
 14 
     | 
    
         
            +
                  DomainSpecificLanguage.for(configuration).instance_eval(File.read(filename), filename)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  configuration
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                class DomainSpecificLanguage
         
     | 
| 
      
 19 
     | 
    
         
            +
                  def initialize(configuration)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    @configuration = configuration
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  def app(name)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    @configuration.instance_variable_set(:@app, name)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  def root(directory)
         
     | 
| 
      
 28 
     | 
    
         
            +
                    raise Tetrahedron::MisconfiguredError.new(:root, 'the path given does not exist') unless File.exist?(directory)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    raise Tetrahedron::MisconfiguredError.new(:root, 'the path given is not a directory') unless File.directory?(directory)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    @configuration.instance_variable_set(:@root, directory)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  def self.for(configuration)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    DomainSpecificLanguage.new(configuration)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              def self.config(path=Tetrahedron::Configuration::DEFAULT)
         
     | 
| 
      
 40 
     | 
    
         
            +
                @configuration ||= begin
         
     | 
| 
      
 41 
     | 
    
         
            +
                  Configuration.load(path)
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Tetrahedron
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Controller < Tetrahedron::Base
         
     | 
| 
      
 3 
     | 
    
         
            +
                set :views, File.join(Tetrahedron.config.root, 'app', Tetrahedron.config.app.underscore, 'views')
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                # Use app/<app>/views/_layouts/default as the default layout.
         
     | 
| 
      
 6 
     | 
    
         
            +
                set :erb, :layout => :'_layouts/default'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                # Recognize *.html.erb as Erubis templates.
         
     | 
| 
      
 9 
     | 
    
         
            +
                Tilt.register Tilt::ErubisTemplate, 'html.erb'
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                # Don't recognize *.erb templates.
         
     | 
| 
      
 12 
     | 
    
         
            +
                def erb(template, options={}, locals={})
         
     | 
| 
      
 13 
     | 
    
         
            +
                  options[:layout] = settings.erb[:layout] if options[:layout].nil?
         
     | 
| 
      
 14 
     | 
    
         
            +
                  render 'html.erb', template, options, locals
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,113 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Tetrahedron
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Database
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Configuration
         
     | 
| 
      
 4 
     | 
    
         
            +
                  Options = %i{adapter user password host port database pool}
         
     | 
| 
      
 5 
     | 
    
         
            +
                  attr_reader *Options
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                  def initialize(configuration={})
         
     | 
| 
      
 8 
     | 
    
         
            +
                    Options.each do |opt|
         
     | 
| 
      
 9 
     | 
    
         
            +
                      self.instance_variable_set(:"@#{opt}", configuration[opt])
         
     | 
| 
      
 10 
     | 
    
         
            +
                    end
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  def override(overrides={})
         
     | 
| 
      
 14 
     | 
    
         
            +
                    configuration = self.dup
         
     | 
| 
      
 15 
     | 
    
         
            +
                    Options.each do |opt|
         
     | 
| 
      
 16 
     | 
    
         
            +
                      configuration.instance_variable_set(:"@#{opt}", overrides[opt]) if overrides.include? opt
         
     | 
| 
      
 17 
     | 
    
         
            +
                    end
         
     | 
| 
      
 18 
     | 
    
         
            +
                    configuration
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                def self.configured?
         
     | 
| 
      
 23 
     | 
    
         
            +
                  !@configuration.nil?
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                def self.configure(configuration)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  # TODO(mtwilliams): Validate |configuration|.
         
     | 
| 
      
 28 
     | 
    
         
            +
                  configuration[:database] ||= Terahedron.config.app.to_s.underscore.gsub(/::/,'_')
         
     | 
| 
      
 29 
     | 
    
         
            +
                  configuration[:pool] ||= 1
         
     | 
| 
      
 30 
     | 
    
         
            +
                  @configuration = Configuration.new(configuration)
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                # TODO(mtwilliams): Refactor into Terahedron::Service.wait_until_reachable
         
     | 
| 
      
 34 
     | 
    
         
            +
                def self.wait_until_reachable(overrides={})
         
     | 
| 
      
 35 
     | 
    
         
            +
                  # By default, we wait up to 15 seconds.
         
     | 
| 
      
 36 
     | 
    
         
            +
                  overrides[:timeout] ||= 15
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  configuration   = @configuration.override(overrides) if configured?
         
     | 
| 
      
 39 
     | 
    
         
            +
                  configuration ||= Configuration.new(overrides)
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  # TODO(mtwilliams): Don't assume TCP.
         
     | 
| 
      
 42 
     | 
    
         
            +
                   # Look at |configuration.adapter|.
         
     | 
| 
      
 43 
     | 
    
         
            +
                  Timeout::timeout(overrides[:timeout]) do
         
     | 
| 
      
 44 
     | 
    
         
            +
                    while true
         
     | 
| 
      
 45 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 46 
     | 
    
         
            +
                        TCPSocket.new(configuration.host, configuration.port).close
         
     | 
| 
      
 47 
     | 
    
         
            +
                        return true
         
     | 
| 
      
 48 
     | 
    
         
            +
                      rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, SocketError
         
     | 
| 
      
 49 
     | 
    
         
            +
                        # We're all good citizens, right?
         
     | 
| 
      
 50 
     | 
    
         
            +
                        Kernel.sleep(1)
         
     | 
| 
      
 51 
     | 
    
         
            +
                      end
         
     | 
| 
      
 52 
     | 
    
         
            +
                    end
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
                rescue Timeout::Error
         
     | 
| 
      
 55 
     | 
    
         
            +
                  false
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                def self.wait_until_reachable!(overrides={})
         
     | 
| 
      
 59 
     | 
    
         
            +
                  # TODO(mtwilliams): Raise a custom exception type.
         
     | 
| 
      
 60 
     | 
    
         
            +
                  raise "Database is unreachable!" unless wait_until_reachable
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                def self.connect(overrides={})
         
     | 
| 
      
 64 
     | 
    
         
            +
                  # Wait some amount of time before assuming the database is down.
         
     | 
| 
      
 65 
     | 
    
         
            +
                  Tetrahedron::Database.wait_until_reachable!(overrides)
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                  configuration   = @configuration.override(overrides) if configured?
         
     | 
| 
      
 68 
     | 
    
         
            +
                  configuration ||= Configuration.new(overrides)
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                  @connection = Sequel.connect(:adapter => configuration.adapter,
         
     | 
| 
      
 71 
     | 
    
         
            +
                                               :user => configuration.user,
         
     | 
| 
      
 72 
     | 
    
         
            +
                                               :password => configuration.password,
         
     | 
| 
      
 73 
     | 
    
         
            +
                                               :host => configuration.host,
         
     | 
| 
      
 74 
     | 
    
         
            +
                                               :port => configuration.port,
         
     | 
| 
      
 75 
     | 
    
         
            +
                                               :database => configuration.database,
         
     | 
| 
      
 76 
     | 
    
         
            +
                                               :test => true,
         
     | 
| 
      
 77 
     | 
    
         
            +
                                               :sslmode => :prefer,
         
     | 
| 
      
 78 
     | 
    
         
            +
                                               :max_connections => configuration.pool)
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                  # Reback our models with the new connection pool.
         
     | 
| 
      
 81 
     | 
    
         
            +
                  Tetrahedron::Model.db = @connection
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                  true
         
     | 
| 
      
 84 
     | 
    
         
            +
                end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                def self.disconnect
         
     | 
| 
      
 87 
     | 
    
         
            +
                  connection = @connection
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                  # TODO(mtwilliams): Ensure this is thread safe.
         
     | 
| 
      
 90 
     | 
    
         
            +
                  # Make sure no one tries to use the disconnected connection pool.
         
     | 
| 
      
 91 
     | 
    
         
            +
                  Tetrahedron::Model.db = Sequel.mock
         
     | 
| 
      
 92 
     | 
    
         
            +
                  @connection = nil
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                  connection.disconnect unless connection.nil?
         
     | 
| 
      
 95 
     | 
    
         
            +
                end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                def self.connection
         
     | 
| 
      
 98 
     | 
    
         
            +
                  @connection
         
     | 
| 
      
 99 
     | 
    
         
            +
                end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                def self.reset
         
     | 
| 
      
 102 
     | 
    
         
            +
                  # TODO(mtwilliams): Drop and recreate database.
         
     | 
| 
      
 103 
     | 
    
         
            +
                end
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                def self.migrate
         
     | 
| 
      
 106 
     | 
    
         
            +
                  Sequel::IntegerMigrator.run(connection, File.join(Tetrahedron.config.root, 'db', 'migrations'))
         
     | 
| 
      
 107 
     | 
    
         
            +
                end
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
                def self.seed
         
     | 
| 
      
 110 
     | 
    
         
            +
                  Kernel.load(File.join(Tetrahedron.config.root, 'db', 'seed.rb'))
         
     | 
| 
      
 111 
     | 
    
         
            +
                end
         
     | 
| 
      
 112 
     | 
    
         
            +
              end
         
     | 
| 
      
 113 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,28 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Tetrahedron
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Environment
         
     | 
| 
      
 3 
     | 
    
         
            +
                # Loads `ENV` from `.env` if available.
         
     | 
| 
      
 4 
     | 
    
         
            +
                def self.load
         
     | 
| 
      
 5 
     | 
    
         
            +
                  # TODO(mtwilliams): Use a proper logger.
         
     | 
| 
      
 6 
     | 
    
         
            +
                  $stdout.puts "Loading environment from `.env` if available..."
         
     | 
| 
      
 7 
     | 
    
         
            +
                  require 'dotenv'
         
     | 
| 
      
 8 
     | 
    
         
            +
                  Dotenv.load! File.join(Tetrahedron.config.root, '.env')
         
     | 
| 
      
 9 
     | 
    
         
            +
                  $stdout.puts " => Loaded from `.env`."
         
     | 
| 
      
 10 
     | 
    
         
            +
                rescue LoadError => _
         
     | 
| 
      
 11 
     | 
    
         
            +
                  $stderr.puts " => The 'dotenv' Gem is not available on this system."
         
     | 
| 
      
 12 
     | 
    
         
            +
                  false
         
     | 
| 
      
 13 
     | 
    
         
            +
                rescue Errno::ENOENT
         
     | 
| 
      
 14 
     | 
    
         
            +
                  $stderr.puts " => No `.env' file."
         
     | 
| 
      
 15 
     | 
    
         
            +
                  false
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              def self.env
         
     | 
| 
      
 20 
     | 
    
         
            +
                env = ENV["#{Tetrahedron.config.app.upcase.gsub(/::/,'_')}_ENV"] || ENV['TETRAHEDRON_ENV'] || ENV['RACK_ENV']
         
     | 
| 
      
 21 
     | 
    
         
            +
                @env ||= ::ActiveSupport::StringInquirer.new(env)
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              def self.env=(new_environment)
         
     | 
| 
      
 25 
     | 
    
         
            +
                ENV["#{Tetrahedron.config.app.upcase.gsub(/::/,'_')}_ENV"] = ENV['TETRAHEDRON_ENV'] = new_environment
         
     | 
| 
      
 26 
     | 
    
         
            +
                @env = ::ActiveSupport::StringInquirer.new(new_environment)
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,58 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'ostruct'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Tetrahedron
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Gem
         
     | 
| 
      
 5 
     | 
    
         
            +
                # The name of this Gem.
         
     | 
| 
      
 6 
     | 
    
         
            +
                def self.name
         
     | 
| 
      
 7 
     | 
    
         
            +
                  "tetrahedron"
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                # The name and email address of the primary author.
         
     | 
| 
      
 11 
     | 
    
         
            +
                def self.author
         
     | 
| 
      
 12 
     | 
    
         
            +
                  self.authors.first
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                # The name and email addresses of all authors.
         
     | 
| 
      
 16 
     | 
    
         
            +
                def self.authors
         
     | 
| 
      
 17 
     | 
    
         
            +
                  [["Michael Williams", "m.t.williams@live.com"]].map do |author|
         
     | 
| 
      
 18 
     | 
    
         
            +
                    name, email = author
         
     | 
| 
      
 19 
     | 
    
         
            +
                    OpenStruct.new(name: name, email: email)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                # This Gem's homepage URL.
         
     | 
| 
      
 24 
     | 
    
         
            +
                def self.homepage
         
     | 
| 
      
 25 
     | 
    
         
            +
                  "http://github.com/mtwilliams/tetrahedron"
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                # This Gem's URL.
         
     | 
| 
      
 29 
     | 
    
         
            +
                def self.url
         
     | 
| 
      
 30 
     | 
    
         
            +
                  "https://rubygems.org/gems/#{self.name}"
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                # A short summary of this Gem.
         
     | 
| 
      
 34 
     | 
    
         
            +
                def self.summary
         
     | 
| 
      
 35 
     | 
    
         
            +
                  "Opinionated Sinatra."
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                # A full description of this Gem.
         
     | 
| 
      
 39 
     | 
    
         
            +
                def self.description
         
     | 
| 
      
 40 
     | 
    
         
            +
                  "Tetrahedron is an opinionated web development framework."
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                module VERSION #:nodoc:
         
     | 
| 
      
 44 
     | 
    
         
            +
                  MAJOR, MINOR, PATCH, PRE = [0, 0, 0, 1]
         
     | 
| 
      
 45 
     | 
    
         
            +
                  STRING = [MAJOR, MINOR, PATCH, PRE].compact.join('.')
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                # The semantic version of the this Gem.
         
     | 
| 
      
 49 
     | 
    
         
            +
                def self.version
         
     | 
| 
      
 50 
     | 
    
         
            +
                  Gem::VERSION::STRING
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                # The license covering Tetrahedron.
         
     | 
| 
      
 54 
     | 
    
         
            +
                def self.license
         
     | 
| 
      
 55 
     | 
    
         
            +
                  "Public Domain"
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
              end
         
     | 
| 
      
 58 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,32 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Tetrahedron
         
     | 
| 
      
 2 
     | 
    
         
            +
              Model = Class.new(Sequel::Model)
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
              # Stop Sequel from bitching if it's subclassed before the first database
         
     | 
| 
      
 5 
     | 
    
         
            +
              # connection is established.
         
     | 
| 
      
 6 
     | 
    
         
            +
              Model.db = Sequel.mock if Sequel::DATABASES.empty?
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              class Model
         
     | 
| 
      
 9 
     | 
    
         
            +
                def self::db=(db)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  super(db)
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  # All the way down, boys.
         
     | 
| 
      
 13 
     | 
    
         
            +
                  self.descendents.each do |subclass|
         
     | 
| 
      
 14 
     | 
    
         
            +
                    subclass.db = db
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              def self::Model(source)
         
     | 
| 
      
 20 
     | 
    
         
            +
                unless Sequel::Model::ANONYMOUS_MODEL_CLASSES.key?(source)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  anonymous_model_class = nil
         
     | 
| 
      
 22 
     | 
    
         
            +
                  if source.is_a?(Sequel::Database)
         
     | 
| 
      
 23 
     | 
    
         
            +
                    anonymous_model_class = Class.new(Tetrahedron::Model)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    anonymous_model_class.db = source
         
     | 
| 
      
 25 
     | 
    
         
            +
                  else
         
     | 
| 
      
 26 
     | 
    
         
            +
                    anonymous_model_class = Class.new(Tetrahedron::Model).set_dataset(source)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
                  Sequel::Model::ANONYMOUS_MODEL_CLASSES[source] = anonymous_model_class
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
                return Sequel::Model::ANONYMOUS_MODEL_CLASSES[source]
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,16 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Tetrahedron
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Rake
         
     | 
| 
      
 3 
     | 
    
         
            +
                def self.install
         
     | 
| 
      
 4 
     | 
    
         
            +
                  root = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
         
     | 
| 
      
 5 
     | 
    
         
            +
                  require_relative 'configuration'
         
     | 
| 
      
 6 
     | 
    
         
            +
                  Tetrahedron::Configuration.load
         
     | 
| 
      
 7 
     | 
    
         
            +
                  require_relative 'environment'
         
     | 
| 
      
 8 
     | 
    
         
            +
                  Tetrahedron::Environment.load
         
     | 
| 
      
 9 
     | 
    
         
            +
                  require File.join(root, 'config', 'application')
         
     | 
| 
      
 10 
     | 
    
         
            +
                  require File.join(root, 'config', 'environment')
         
     | 
| 
      
 11 
     | 
    
         
            +
                  Dir.glob(File.join(root, 'lib', 'tetrahedron', 'tasks', '**.rake')).each do |path|
         
     | 
| 
      
 12 
     | 
    
         
            +
                    Kernel.load(path)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,28 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Tetrahedron
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Sessions
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Configuration
         
     | 
| 
      
 4 
     | 
    
         
            +
                  Options = %i{cookie domain lifetime secret}
         
     | 
| 
      
 5 
     | 
    
         
            +
                  attr_reader *Options
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                  def initialize(configuration={})
         
     | 
| 
      
 8 
     | 
    
         
            +
                    Options.each do |opt|
         
     | 
| 
      
 9 
     | 
    
         
            +
                      self.instance_variable_set(:"@#{opt}", configuration[opt])
         
     | 
| 
      
 10 
     | 
    
         
            +
                    end
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def self.config
         
     | 
| 
      
 15 
     | 
    
         
            +
                  @configuration
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                def self.configured?
         
     | 
| 
      
 19 
     | 
    
         
            +
                  !@configuration.nil?
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                def self.configure(configuration)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  # TODO(mtwilliams): Validate |configuration|.
         
     | 
| 
      
 24 
     | 
    
         
            +
                  configuration[:cookie] ||= "#{Tetrahedron.config.app.to_s.downcase.gsub(/::/,'.')}.session"
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @configuration = Sessions::Configuration.new(configuration)
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
            end
         
     | 
    
        data/tetrahedron.gemspec
    ADDED
    
    | 
         @@ -0,0 +1,34 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            $:.push File.expand_path(File.join(File.dirname(__FILE__), 'lib'))
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'tetrahedron/gem'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            Gem::Specification.new do |s|
         
     | 
| 
      
 5 
     | 
    
         
            +
              s.name              = Tetrahedron::Gem.name
         
     | 
| 
      
 6 
     | 
    
         
            +
              s.version           = Tetrahedron::Gem.version
         
     | 
| 
      
 7 
     | 
    
         
            +
              s.platform          = Gem::Platform::RUBY
         
     | 
| 
      
 8 
     | 
    
         
            +
              s.author            = Tetrahedron::Gem.author.name
         
     | 
| 
      
 9 
     | 
    
         
            +
              s.email             = Tetrahedron::Gem.author.email
         
     | 
| 
      
 10 
     | 
    
         
            +
              s.homepage          = Tetrahedron::Gem.homepage
         
     | 
| 
      
 11 
     | 
    
         
            +
              s.summary           = Tetrahedron::Gem.summary
         
     | 
| 
      
 12 
     | 
    
         
            +
              s.description       = Tetrahedron::Gem.description
         
     | 
| 
      
 13 
     | 
    
         
            +
              s.license           = Tetrahedron::Gem.license
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              s.required_ruby_version = '>= 2.2.3'
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              s.files         = `git ls-files`.split("\n")
         
     | 
| 
      
 18 
     | 
    
         
            +
              s.test_files    = `git ls-files -- {test,spec,features}/*`.split("\n")
         
     | 
| 
      
 19 
     | 
    
         
            +
              s.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              s.require_paths = %w(lib)
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              s.add_development_dependency("rake")
         
     | 
| 
      
 24 
     | 
    
         
            +
              s.add_development_dependency("pry")
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              s.add_dependency("activesupport")
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
              s.add_dependency("sinatra")
         
     | 
| 
      
 29 
     | 
    
         
            +
              s.add_dependency("sinatra-contrib")
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              s.add_dependency("sequel")
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
              s.add_dependency("thor")
         
     | 
| 
      
 34 
     | 
    
         
            +
            end
         
     | 
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,174 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: tetrahedron
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.0.0.1
         
     | 
| 
      
 5 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 6 
     | 
    
         
            +
            authors:
         
     | 
| 
      
 7 
     | 
    
         
            +
            - Michael Williams
         
     | 
| 
      
 8 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 9 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 10 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2015-11-27 00:00:00.000000000 Z
         
     | 
| 
      
 12 
     | 
    
         
            +
            dependencies:
         
     | 
| 
      
 13 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 14 
     | 
    
         
            +
              name: rake
         
     | 
| 
      
 15 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 16 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 17 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 18 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 19 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 20 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 21 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 22 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 23 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 24 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 25 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 26 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 27 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 28 
     | 
    
         
            +
              name: pry
         
     | 
| 
      
 29 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 30 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 31 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 32 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 33 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 34 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 35 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 36 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 37 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 38 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 39 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 40 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 41 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 42 
     | 
    
         
            +
              name: activesupport
         
     | 
| 
      
 43 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 44 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 45 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 46 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 47 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 48 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 49 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 50 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 51 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 52 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 53 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 54 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 55 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 56 
     | 
    
         
            +
              name: sinatra
         
     | 
| 
      
 57 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 58 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 59 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 60 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 61 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 62 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 63 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 64 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 65 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 66 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 67 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 68 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 69 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 70 
     | 
    
         
            +
              name: sinatra-contrib
         
     | 
| 
      
 71 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 72 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 73 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 74 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 75 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 76 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 77 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 78 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 79 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 80 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 81 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 82 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 83 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 84 
     | 
    
         
            +
              name: sequel
         
     | 
| 
      
 85 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 86 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 87 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 88 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 89 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 90 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 91 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 92 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 93 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 94 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 95 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 96 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 97 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 98 
     | 
    
         
            +
              name: thor
         
     | 
| 
      
 99 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 100 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 101 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 102 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 103 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 104 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 105 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 106 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 107 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 108 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 109 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 110 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 111 
     | 
    
         
            +
            description: Tetrahedron is an opinionated web development framework.
         
     | 
| 
      
 112 
     | 
    
         
            +
            email: m.t.williams@live.com
         
     | 
| 
      
 113 
     | 
    
         
            +
            executables:
         
     | 
| 
      
 114 
     | 
    
         
            +
            - tetrahedron
         
     | 
| 
      
 115 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 116 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 117 
     | 
    
         
            +
            files:
         
     | 
| 
      
 118 
     | 
    
         
            +
            - ".gitignore"
         
     | 
| 
      
 119 
     | 
    
         
            +
            - AUTHORS
         
     | 
| 
      
 120 
     | 
    
         
            +
            - Gemfile
         
     | 
| 
      
 121 
     | 
    
         
            +
            - Gemfile.lock
         
     | 
| 
      
 122 
     | 
    
         
            +
            - LICENSE
         
     | 
| 
      
 123 
     | 
    
         
            +
            - README.md
         
     | 
| 
      
 124 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
      
 125 
     | 
    
         
            +
            - bin/tetrahedron
         
     | 
| 
      
 126 
     | 
    
         
            +
            - config/app.ru
         
     | 
| 
      
 127 
     | 
    
         
            +
            - config/application.rb
         
     | 
| 
      
 128 
     | 
    
         
            +
            - config/environment.rb
         
     | 
| 
      
 129 
     | 
    
         
            +
            - config/puma.rb
         
     | 
| 
      
 130 
     | 
    
         
            +
            - lib/tetrahedron.rb
         
     | 
| 
      
 131 
     | 
    
         
            +
            - lib/tetrahedron/app.rb
         
     | 
| 
      
 132 
     | 
    
         
            +
            - lib/tetrahedron/assets.rb
         
     | 
| 
      
 133 
     | 
    
         
            +
            - lib/tetrahedron/base.rb
         
     | 
| 
      
 134 
     | 
    
         
            +
            - lib/tetrahedron/bootfile.rb
         
     | 
| 
      
 135 
     | 
    
         
            +
            - lib/tetrahedron/bundler.rb
         
     | 
| 
      
 136 
     | 
    
         
            +
            - lib/tetrahedron/configuration.rb
         
     | 
| 
      
 137 
     | 
    
         
            +
            - lib/tetrahedron/controller.rb
         
     | 
| 
      
 138 
     | 
    
         
            +
            - lib/tetrahedron/database.rb
         
     | 
| 
      
 139 
     | 
    
         
            +
            - lib/tetrahedron/endpoint.rb
         
     | 
| 
      
 140 
     | 
    
         
            +
            - lib/tetrahedron/environment.rb
         
     | 
| 
      
 141 
     | 
    
         
            +
            - lib/tetrahedron/error.rb
         
     | 
| 
      
 142 
     | 
    
         
            +
            - lib/tetrahedron/errors.rb
         
     | 
| 
      
 143 
     | 
    
         
            +
            - lib/tetrahedron/gem.rb
         
     | 
| 
      
 144 
     | 
    
         
            +
            - lib/tetrahedron/model.rb
         
     | 
| 
      
 145 
     | 
    
         
            +
            - lib/tetrahedron/rake.rb
         
     | 
| 
      
 146 
     | 
    
         
            +
            - lib/tetrahedron/redis.rb
         
     | 
| 
      
 147 
     | 
    
         
            +
            - lib/tetrahedron/sessions.rb
         
     | 
| 
      
 148 
     | 
    
         
            +
            - lib/tetrahedron/tasks/tet.rake
         
     | 
| 
      
 149 
     | 
    
         
            +
            - tetrahedron.gemspec
         
     | 
| 
      
 150 
     | 
    
         
            +
            homepage: http://github.com/mtwilliams/tetrahedron
         
     | 
| 
      
 151 
     | 
    
         
            +
            licenses:
         
     | 
| 
      
 152 
     | 
    
         
            +
            - Public Domain
         
     | 
| 
      
 153 
     | 
    
         
            +
            metadata: {}
         
     | 
| 
      
 154 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 155 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 156 
     | 
    
         
            +
            require_paths:
         
     | 
| 
      
 157 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 158 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 159 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 160 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 161 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 162 
     | 
    
         
            +
                  version: 2.2.3
         
     | 
| 
      
 163 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 164 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 165 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 166 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 167 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 168 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 169 
     | 
    
         
            +
            rubyforge_project: 
         
     | 
| 
      
 170 
     | 
    
         
            +
            rubygems_version: 2.4.5.1
         
     | 
| 
      
 171 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 172 
     | 
    
         
            +
            specification_version: 4
         
     | 
| 
      
 173 
     | 
    
         
            +
            summary: Opinionated Sinatra.
         
     | 
| 
      
 174 
     | 
    
         
            +
            test_files: []
         
     |