tetrahedron 0.0.0.1 → 0.0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +15 -1
- data/README.md +1 -2
- data/lib/tetrahedron/application/base.rb +16 -0
- data/lib/tetrahedron/application/controller.rb +16 -0
- data/lib/tetrahedron/application/endpoint.rb +7 -0
- data/lib/tetrahedron/application.rb +31 -0
- data/lib/tetrahedron/base.rb +9 -20
- data/lib/tetrahedron/database.rb +66 -90
- data/lib/tetrahedron/databases/postgres.rb +48 -0
- data/lib/tetrahedron/databases/sqlite3.rb +30 -0
- data/lib/tetrahedron/gem.rb +2 -2
- data/lib/tetrahedron/middleware.rb +25 -0
- data/lib/tetrahedron/service.rb +61 -0
- data/lib/tetrahedron/sessions.rb +26 -17
- data/lib/tetrahedron.rb +26 -54
- data/tetrahedron.gemspec +7 -2
- metadata +82 -21
- data/config/app.ru +0 -21
- data/config/application.rb +0 -8
- data/config/environment.rb +0 -18
- data/config/puma.rb +0 -29
- data/lib/tetrahedron/app.rb +0 -16
- data/lib/tetrahedron/assets.rb +0 -43
- data/lib/tetrahedron/bootfile.rb +0 -43
- data/lib/tetrahedron/bundler.rb +0 -10
- data/lib/tetrahedron/configuration.rb +0 -44
- data/lib/tetrahedron/controller.rb +0 -17
- data/lib/tetrahedron/endpoint.rb +0 -4
- data/lib/tetrahedron/environment.rb +0 -28
- data/lib/tetrahedron/errors.rb +0 -7
- data/lib/tetrahedron/model.rb +0 -32
- data/lib/tetrahedron/rake.rb +0 -16
- data/lib/tetrahedron/redis.rb +0 -4
- data/lib/tetrahedron/tasks/tet.rake +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5b9d0311bd16dd7fb7b8c35d19fcce8ae77a2036
|
4
|
+
data.tar.gz: 9ee81f6f029ba59b260b1e56f49db1dbb0233e87
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c2ac0f186880b502265c894461fba56c33e30b931069e614df647627c5fdb8981a65529a3a849a584d9aae7b7dba456f14d48a0a74c5e86a72f826212897b1b
|
7
|
+
data.tar.gz: 1a3cb3c6184c50a59bc0b76eff23b72af0717d4b96283646ee90b58286609cccef8386c7587a7cccf0afdc4e52c2e1e30479a8d1646fb01f17b5164d1d69b150
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
tetrahedron (0.0.0
|
4
|
+
tetrahedron (0.0.1.0)
|
5
5
|
activesupport
|
6
|
+
erubis
|
7
|
+
mail
|
8
|
+
rack
|
9
|
+
rack-contrib
|
10
|
+
redis
|
6
11
|
sequel
|
7
12
|
sinatra
|
8
13
|
sinatra-contrib
|
@@ -19,9 +24,14 @@ GEM
|
|
19
24
|
tzinfo (~> 1.1)
|
20
25
|
backports (3.6.7)
|
21
26
|
coderay (1.1.0)
|
27
|
+
erubis (2.7.0)
|
28
|
+
git-version-bump (0.15.1)
|
22
29
|
i18n (0.7.0)
|
23
30
|
json (1.8.3)
|
31
|
+
mail (2.6.3)
|
32
|
+
mime-types (>= 1.16, < 3)
|
24
33
|
method_source (0.8.2)
|
34
|
+
mime-types (2.99)
|
25
35
|
minitest (5.8.3)
|
26
36
|
multi_json (1.11.2)
|
27
37
|
pry (0.10.3)
|
@@ -29,11 +39,15 @@ GEM
|
|
29
39
|
method_source (~> 0.8.1)
|
30
40
|
slop (~> 3.4)
|
31
41
|
rack (1.6.4)
|
42
|
+
rack-contrib (1.4.0)
|
43
|
+
git-version-bump (~> 0.15)
|
44
|
+
rack (~> 1.4)
|
32
45
|
rack-protection (1.5.3)
|
33
46
|
rack
|
34
47
|
rack-test (0.6.3)
|
35
48
|
rack (>= 1.0)
|
36
49
|
rake (10.4.2)
|
50
|
+
redis (3.2.2)
|
37
51
|
sequel (4.28.0)
|
38
52
|
sinatra (1.4.6)
|
39
53
|
rack (~> 1.4)
|
data/README.md
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
Tetrahedron
|
2
|
-
===========
|
1
|
+
# Tetrahedron [![Gem Version](https://img.shields.io/gem/v/tetrahedron.svg)](https://rubygems.org/gems/tetrahedron) [![Build Status](https://img.shields.io/travis/mtwilliams/tetrahedron/master.svg)](https://travis-ci.org/mtwilliams/tetrahedron) [![Code Climate](https://img.shields.io/codeclimate/github/mtwilliams/tetrahedron.svg)](https://codeclimate.com/github/mtwilliams/tetrahedron) [![Dependency Status](https://img.shields.io/gemnasium/mtwilliams/tetrahedron.svg)](https://gemnasium.com/mtwilliams/tetrahedron)
|
3
2
|
|
4
3
|
[Welcome to the Tet.](https://www.youtube.com/watch?v=lt-udg9zQSE)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Tetrahedron
|
2
|
+
class Application
|
3
|
+
class Base < Tetrahedron::Base
|
4
|
+
def self.inherited(base)
|
5
|
+
super(base)
|
6
|
+
base.send :define_singleton_method, :inherited do |basee|
|
7
|
+
super(basee)
|
8
|
+
basee.set :application, Proc.new { basee.to_s.split('::')[0..-2].join('::').constantize }
|
9
|
+
basee.set :environment, Proc.new { application.environment.to_sym }
|
10
|
+
basee.set :root, Proc.new { application.root }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Tetrahedron
|
2
|
+
class Application
|
3
|
+
class Controller < Tetrahedron::Application::Base
|
4
|
+
set :views, Proc.new { "#{root}/app/broadsheet/views" }
|
5
|
+
|
6
|
+
# Recognize *.html.erb as Erubis templates.
|
7
|
+
Tilt.register Tilt::ErubisTemplate, 'html.erb'
|
8
|
+
|
9
|
+
# Don't recognize *.erb templates.
|
10
|
+
def erb(template, options={}, locals={})
|
11
|
+
options[:layout] = settings.erb[:layout] if options[:layout].nil?
|
12
|
+
render 'html.erb', template, options, locals
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'sinatra/contrib/all'
|
3
|
+
|
4
|
+
module Tetrahedron
|
5
|
+
class Application < Tetrahedron::Base
|
6
|
+
def self.env
|
7
|
+
components = self.to_s.upcase.split('::')
|
8
|
+
possibilities = (components.size.downto(1).map{|n| components.first(n).join('_')+'_ENV'})
|
9
|
+
environments = (possibilities+['RACK_ENV']).map{|possibility| ENV[possibility]}
|
10
|
+
@env ||= ::ActiveSupport::StringInquirer.new(environments.reject(&:nil?).first)
|
11
|
+
end
|
12
|
+
|
13
|
+
set :environment, Proc.new { self.env.to_sym }
|
14
|
+
set :root, Dir.pwd
|
15
|
+
|
16
|
+
# Don't use the built-in web-server.
|
17
|
+
set :run, false
|
18
|
+
|
19
|
+
def self.inherited(application)
|
20
|
+
super(application)
|
21
|
+
|
22
|
+
Tetrahedron::Middleware.install(application)
|
23
|
+
Tetrahedron::Sessions.install(application)
|
24
|
+
|
25
|
+
application.const_set('Controller', Class.new(Controller))
|
26
|
+
application.const_set('Endpoint', Class.new(Endpoint))
|
27
|
+
|
28
|
+
Tetrahedron::Database.install(application)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/tetrahedron/base.rb
CHANGED
@@ -1,11 +1,8 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'sinatra/contrib/all'
|
3
|
+
|
1
4
|
module Tetrahedron
|
2
5
|
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
6
|
# Errors are bubbled so they can be handled by middleware.
|
10
7
|
set :dump_errors, false
|
11
8
|
set :raise_errors, true
|
@@ -14,21 +11,13 @@ module Tetrahedron
|
|
14
11
|
# Fuck you, IE9.
|
15
12
|
disable :method_override
|
16
13
|
|
17
|
-
|
18
|
-
|
19
|
-
register Sinatra::Reloader
|
20
|
-
end
|
14
|
+
# TODO(mtwilliams): Re-enable basic protections, like traversal.
|
15
|
+
disable :protection
|
21
16
|
|
22
|
-
|
23
|
-
|
24
|
-
end
|
17
|
+
# Let users handle serving static files.
|
18
|
+
disable :static
|
25
19
|
|
26
|
-
|
27
|
-
|
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
|
20
|
+
# Hot-reload in development.
|
21
|
+
register Sinatra::Reloader
|
33
22
|
end
|
34
23
|
end
|
data/lib/tetrahedron/database.rb
CHANGED
@@ -1,113 +1,89 @@
|
|
1
|
-
|
2
|
-
module Database
|
3
|
-
class Configuration
|
4
|
-
Options = %i{adapter user password host port database pool}
|
5
|
-
attr_reader *Options
|
1
|
+
require 'sequel'
|
6
2
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
11
|
-
end
|
3
|
+
# Everyone needs these.
|
4
|
+
Sequel.extension :migration
|
5
|
+
Sequel::Model.plugin :timestamps
|
12
6
|
|
13
|
-
|
14
|
-
|
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
|
7
|
+
# The Tet needs this for the magic performed in `Model.db=`.
|
8
|
+
Sequel::Model.plugin :subclasses
|
21
9
|
|
22
|
-
|
23
|
-
|
10
|
+
module Tetrahedron
|
11
|
+
class Database < Service
|
12
|
+
class Configuration < Service::Configuration
|
24
13
|
end
|
25
14
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
@configuration = Configuration.new(configuration)
|
15
|
+
class Provider < Service::Provider
|
16
|
+
def connection; end
|
17
|
+
def connect; raise NotImplementedError; end
|
18
|
+
def disconnect; raise NotImplementedError; end
|
31
19
|
end
|
32
20
|
|
33
|
-
|
34
|
-
|
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
|
21
|
+
def self.connected?
|
22
|
+
!self.connection.nil?
|
56
23
|
end
|
57
24
|
|
58
|
-
def self.
|
59
|
-
|
60
|
-
|
25
|
+
def self.connection
|
26
|
+
configured!
|
27
|
+
self.class_variable_get(:@@provider).connection
|
61
28
|
end
|
62
29
|
|
63
|
-
def self.connect
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
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
|
30
|
+
def self.connect
|
31
|
+
configured!
|
32
|
+
connected = self.class_variable_get(:@@provider).connect
|
33
|
+
# Back our models with the new connection.
|
34
|
+
model = self.class_variable_get(:@@application).const_get("Model")
|
35
|
+
model.db = self.connection if connected
|
36
|
+
connected
|
84
37
|
end
|
85
38
|
|
86
39
|
def self.disconnect
|
87
|
-
|
40
|
+
configured!
|
41
|
+
# TODO(mtwilliams): Verify that this is thread-safe.
|
42
|
+
model = self.class_variable_get(:@@application).const_get("Model")
|
43
|
+
model.db = Sequel.mock
|
44
|
+
self.class_variable_get(:@@provider).disconnect
|
45
|
+
end
|
88
46
|
|
89
|
-
|
90
|
-
|
91
|
-
Tetrahedron::Model.db = Sequel.mock
|
92
|
-
@connection = nil
|
47
|
+
def self.install(application)
|
48
|
+
super(application)
|
93
49
|
|
94
|
-
|
95
|
-
end
|
50
|
+
# TODO(mtwilliams): Refactor out this horrid mess.
|
96
51
|
|
97
|
-
|
98
|
-
|
99
|
-
|
52
|
+
# We can't build an inheritence heirarchy.
|
53
|
+
# See https://groups.google.com/d/msg/sequel-talk/OG5ti9JAJIE/p1iqO57cwqwJ.
|
54
|
+
application.class_eval("Model = Class.new(Sequel::Model);")
|
55
|
+
model = application.const_get("Model")
|
100
56
|
|
101
|
-
|
102
|
-
#
|
103
|
-
|
57
|
+
# Stop Sequel from bitching when we users subclass models before the
|
58
|
+
# database connection is established.
|
59
|
+
model.db = Sequel.mock
|
104
60
|
|
105
|
-
|
106
|
-
|
107
|
-
|
61
|
+
# Back descendents.
|
62
|
+
model.send :define_singleton_method, :db= do |db|
|
63
|
+
super(db)
|
64
|
+
# All the way down, boys.
|
65
|
+
self.descendents.each do |descendent|
|
66
|
+
descendent.db = db
|
67
|
+
end
|
68
|
+
end
|
108
69
|
|
109
|
-
|
110
|
-
|
70
|
+
# Custom names are cool, m'kay.
|
71
|
+
application.send :define_singleton_method, :Model do |source|
|
72
|
+
anonymous_model_class = model::ANONYMOUS_MODEL_CLASSES_MUTEX.synchronize do
|
73
|
+
model::ANONYMOUS_MODEL_CLASSES[source]
|
74
|
+
end
|
75
|
+
unless anonymous_model_class
|
76
|
+
anonymous_model_class = if source.is_a?(Sequel::Database)
|
77
|
+
Class.new(model).db = source
|
78
|
+
else
|
79
|
+
Class.new(model).set_dataset(source)
|
80
|
+
end
|
81
|
+
model::ANONYMOUS_MODEL_CLASSES_MUTEX.synchronize do
|
82
|
+
model::ANONYMOUS_MODEL_CLASSES[source] = anonymous_model_class
|
83
|
+
end
|
84
|
+
end
|
85
|
+
anonymous_model_class
|
86
|
+
end
|
111
87
|
end
|
112
88
|
end
|
113
89
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Tetrahedron
|
2
|
+
module Databases
|
3
|
+
class Postgres < Database::Provider
|
4
|
+
class Configuration < Database::Configuration
|
5
|
+
attr_accessor :host,
|
6
|
+
:port,
|
7
|
+
:user,
|
8
|
+
:password,
|
9
|
+
:database,
|
10
|
+
:pool
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@configuration = Configuration.new
|
15
|
+
yield @configuration if block_given?
|
16
|
+
end
|
17
|
+
|
18
|
+
def connection
|
19
|
+
@connection
|
20
|
+
end
|
21
|
+
|
22
|
+
def connect
|
23
|
+
# Wait some amount of time before assuming the database is down.
|
24
|
+
Service.wait_until_reachable!(:protocol => :tcp,
|
25
|
+
:host => @configuration.host,
|
26
|
+
:port => @configuration.port,
|
27
|
+
:timeout => 15)
|
28
|
+
|
29
|
+
@connection = Sequel.postgres(:host => @configuration.host,
|
30
|
+
:port => @configuration.port,
|
31
|
+
:user => @configuration.user,
|
32
|
+
:password => @configuration.password,
|
33
|
+
:database => @configuration.database,
|
34
|
+
:test => true,
|
35
|
+
:sslmode => :prefer,
|
36
|
+
:max_connections => @configuration.pool)
|
37
|
+
|
38
|
+
true
|
39
|
+
end
|
40
|
+
|
41
|
+
def disconnect
|
42
|
+
@connection.disconnect if @connection
|
43
|
+
@connection = nil
|
44
|
+
true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Tetrahedron
|
2
|
+
module Databases
|
3
|
+
class SQLite3 < Database::Provider
|
4
|
+
class Configuration < Database::Configuration
|
5
|
+
attr_accessor :path
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@configuration = Configuration.new
|
10
|
+
yield @configuration if block_given?
|
11
|
+
end
|
12
|
+
|
13
|
+
def connection
|
14
|
+
@connection
|
15
|
+
end
|
16
|
+
|
17
|
+
def connect
|
18
|
+
# If no path was specified, default to a transient in-memory database.
|
19
|
+
@connection = Sequel.sqlite(:database => (@configuration.path || ':memory:'))
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
def disconnect
|
24
|
+
@connection.disconnect if @connection
|
25
|
+
@connection = nil
|
26
|
+
true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/tetrahedron/gem.rb
CHANGED
@@ -32,7 +32,7 @@ module Tetrahedron
|
|
32
32
|
|
33
33
|
# A short summary of this Gem.
|
34
34
|
def self.summary
|
35
|
-
"
|
35
|
+
"Welcome to the Tet."
|
36
36
|
end
|
37
37
|
|
38
38
|
# A full description of this Gem.
|
@@ -41,7 +41,7 @@ module Tetrahedron
|
|
41
41
|
end
|
42
42
|
|
43
43
|
module VERSION #:nodoc:
|
44
|
-
MAJOR, MINOR, PATCH, PRE = [0, 0,
|
44
|
+
MAJOR, MINOR, PATCH, PRE = [0, 0, 1, 0]
|
45
45
|
STRING = [MAJOR, MINOR, PATCH, PRE].compact.join('.')
|
46
46
|
end
|
47
47
|
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Tetrahedron
|
2
|
+
class Middleware
|
3
|
+
def self.use(middleware, *args, &block)
|
4
|
+
stack = self.class_variable_get(:@@stack)
|
5
|
+
stack << proc { |app| middleware.new(app, *args, &block) }
|
6
|
+
self.class_variable_set(:@@stack, stack)
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(app)
|
10
|
+
@app = app
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
middlewares = self.class.class_variable_get(:@@stack).reverse
|
15
|
+
wrapped = middlewares.inject(@app) {|_, middleware| middleware[_]}
|
16
|
+
wrapped.call(env)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.install(application)
|
20
|
+
middleware = Class.new(self)
|
21
|
+
application.const_set('Middleware', middleware)
|
22
|
+
middleware.class_variable_set(:@@stack, [])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Tetrahedron
|
2
|
+
class Service
|
3
|
+
def self.install(application)
|
4
|
+
service = Class.new(self)
|
5
|
+
service.class_variable_set(:@@application, application)
|
6
|
+
application.const_set(self.to_s.split('::').last, service)
|
7
|
+
end
|
8
|
+
|
9
|
+
Unconfigured = Class.new(Tetrahedron::Error)
|
10
|
+
Misconfigured = Class.new(Tetrahedron::Error)
|
11
|
+
AlreadyConfigured = Class.new(Tetrahedron::Error)
|
12
|
+
|
13
|
+
class Configuration
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.configured?
|
17
|
+
self.class_variable_defined?(:@@provider)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.configured!
|
21
|
+
raise Unconfigured unless self.configured?
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.configure(&configurator)
|
25
|
+
raise AlreadyConfigured if self.configured?
|
26
|
+
provider = configurator.call()
|
27
|
+
raise Misconfigured unless provider.is_a? Provider
|
28
|
+
self.class_variable_set(:@@provider, provider)
|
29
|
+
end
|
30
|
+
|
31
|
+
Unreachable = Class.new(Tetrahedron::Error)
|
32
|
+
|
33
|
+
class Provider
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.wait_until_reachable(opts={})
|
37
|
+
Timeout::timeout(opts.fetch(:timeout, 15)) do
|
38
|
+
while true
|
39
|
+
begin
|
40
|
+
case opts[:protocol]
|
41
|
+
when :tcp
|
42
|
+
TCPSocket.new(opts[:host], opts[:port]).close
|
43
|
+
return true
|
44
|
+
when :udp
|
45
|
+
raise "This makes no sense!"
|
46
|
+
end
|
47
|
+
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, SocketError
|
48
|
+
# We're all good citizens, right?
|
49
|
+
Kernel.sleep(1)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
rescue Timeout::Error
|
54
|
+
false
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.wait_until_reachable!(opts={})
|
58
|
+
raise Unreachable unless self.wait_until_reachable(opts)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/tetrahedron/sessions.rb
CHANGED
@@ -1,28 +1,37 @@
|
|
1
1
|
module Tetrahedron
|
2
|
-
|
2
|
+
class Sessions
|
3
3
|
class Configuration
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
OPTIONS = [:key, :domain, :path, :expires, :secret]
|
5
|
+
attr_accessor *OPTIONS
|
6
|
+
def dsl(&block)
|
7
|
+
config = self
|
8
|
+
dsl = Class.new
|
9
|
+
OPTIONS.each do |option|
|
10
|
+
dsl.send :define_method, option.to_sym do |value|
|
11
|
+
config.instance_variable_set(:"@#{option}", value)
|
12
|
+
end
|
10
13
|
end
|
14
|
+
dsl.new.instance_eval(&block)
|
11
15
|
end
|
12
16
|
end
|
13
17
|
|
14
|
-
def self.
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
def self.configure(&configurator)
|
19
|
+
application = self.class_variable_get(:@@application)
|
20
|
+
configuration = Configuration.new
|
21
|
+
configuration.key = (application.to_s.underscore.split('::')+['session']).join('.')
|
22
|
+
configuration.dsl(&configurator)
|
23
|
+
middleware = application.const_get('Middleware')
|
24
|
+
middleware.use(Rack::Session::Cookie, :key => configuration.key,
|
25
|
+
:domain => configuration.domain,
|
26
|
+
:path => configuration.path,
|
27
|
+
:expire_after => configuration.expires,
|
28
|
+
:secret => configuration.secret)
|
20
29
|
end
|
21
30
|
|
22
|
-
def self.
|
23
|
-
|
24
|
-
|
25
|
-
|
31
|
+
def self.install(application)
|
32
|
+
sessions = Class.new(self)
|
33
|
+
application.const_set('Sessions', sessions)
|
34
|
+
sessions.class_variable_set(:@@application, application)
|
26
35
|
end
|
27
36
|
end
|
28
37
|
end
|
data/lib/tetrahedron.rb
CHANGED
@@ -1,59 +1,31 @@
|
|
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
1
|
require 'active_support'
|
19
2
|
require 'active_support/core_ext'
|
20
3
|
|
21
4
|
module Tetrahedron
|
22
|
-
|
23
|
-
|
24
|
-
|
5
|
+
require 'tetrahedron/gem'
|
6
|
+
require 'tetrahedron/error'
|
7
|
+
|
8
|
+
require 'tetrahedron/middleware'
|
9
|
+
require 'tetrahedron/sessions'
|
10
|
+
|
11
|
+
require 'tetrahedron/base'
|
12
|
+
require 'tetrahedron/application'
|
13
|
+
require 'tetrahedron/application/base'
|
14
|
+
require 'tetrahedron/application/controller'
|
15
|
+
require 'tetrahedron/application/endpoint'
|
16
|
+
|
17
|
+
require 'tetrahedron/service'
|
18
|
+
require 'tetrahedron/database'
|
19
|
+
require 'tetrahedron/databases/sqlite3'
|
20
|
+
require 'tetrahedron/databases/postgres'
|
21
|
+
|
22
|
+
# require 'tetrahedron/cache'
|
23
|
+
# require 'tetrahedron/caches/null' #=> ActiveSupport::Cache::NullStore
|
24
|
+
# require 'tetrahedron/caches/memory' #=> ActiveSupport::Cache::MemoryStore
|
25
|
+
# require 'tetrahedron/caches/memcache' #=> Dalli
|
26
|
+
# require 'tetrahedron/caches/redis' #=> Hiredis
|
27
|
+
# require 'tetrahedron/queue'
|
28
|
+
# require 'tetrahedron/queues/null' #=> .*~~~ The Abyss ~~~*.
|
29
|
+
# require 'tetrahedron/queues/spawn' #=> Thread.new
|
30
|
+
# require 'tetrahedron/queues/sidekiq' #=> Sidekiq (from Redis, with Love)
|
25
31
|
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'
|
data/tetrahedron.gemspec
CHANGED
@@ -23,12 +23,17 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.add_development_dependency("rake")
|
24
24
|
s.add_development_dependency("pry")
|
25
25
|
|
26
|
+
s.add_dependency("thor")
|
27
|
+
|
26
28
|
s.add_dependency("activesupport")
|
27
29
|
|
30
|
+
s.add_dependency("rack")
|
31
|
+
s.add_dependency("rack-contrib")
|
28
32
|
s.add_dependency("sinatra")
|
29
33
|
s.add_dependency("sinatra-contrib")
|
34
|
+
s.add_dependency("erubis")
|
30
35
|
|
31
36
|
s.add_dependency("sequel")
|
32
|
-
|
33
|
-
s.add_dependency("
|
37
|
+
s.add_dependency("redis")
|
38
|
+
s.add_dependency("mail")
|
34
39
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tetrahedron
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.0
|
4
|
+
version: 0.0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-11-
|
11
|
+
date: 2015-11-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: thor
|
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'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: activesupport
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,6 +66,34 @@ dependencies:
|
|
52
66
|
- - ">="
|
53
67
|
- !ruby/object:Gem::Version
|
54
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rack
|
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: rack-contrib
|
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'
|
55
97
|
- !ruby/object:Gem::Dependency
|
56
98
|
name: sinatra
|
57
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +122,20 @@ dependencies:
|
|
80
122
|
- - ">="
|
81
123
|
- !ruby/object:Gem::Version
|
82
124
|
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: erubis
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
83
139
|
- !ruby/object:Gem::Dependency
|
84
140
|
name: sequel
|
85
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -95,7 +151,21 @@ dependencies:
|
|
95
151
|
- !ruby/object:Gem::Version
|
96
152
|
version: '0'
|
97
153
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
154
|
+
name: redis
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :runtime
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: mail
|
99
169
|
requirement: !ruby/object:Gem::Requirement
|
100
170
|
requirements:
|
101
171
|
- - ">="
|
@@ -123,29 +193,20 @@ files:
|
|
123
193
|
- README.md
|
124
194
|
- Rakefile
|
125
195
|
- bin/tetrahedron
|
126
|
-
- config/app.ru
|
127
|
-
- config/application.rb
|
128
|
-
- config/environment.rb
|
129
|
-
- config/puma.rb
|
130
196
|
- lib/tetrahedron.rb
|
131
|
-
- lib/tetrahedron/
|
132
|
-
- lib/tetrahedron/
|
197
|
+
- lib/tetrahedron/application.rb
|
198
|
+
- lib/tetrahedron/application/base.rb
|
199
|
+
- lib/tetrahedron/application/controller.rb
|
200
|
+
- lib/tetrahedron/application/endpoint.rb
|
133
201
|
- 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
202
|
- lib/tetrahedron/database.rb
|
139
|
-
- lib/tetrahedron/
|
140
|
-
- lib/tetrahedron/
|
203
|
+
- lib/tetrahedron/databases/postgres.rb
|
204
|
+
- lib/tetrahedron/databases/sqlite3.rb
|
141
205
|
- lib/tetrahedron/error.rb
|
142
|
-
- lib/tetrahedron/errors.rb
|
143
206
|
- lib/tetrahedron/gem.rb
|
144
|
-
- lib/tetrahedron/
|
145
|
-
- lib/tetrahedron/
|
146
|
-
- lib/tetrahedron/redis.rb
|
207
|
+
- lib/tetrahedron/middleware.rb
|
208
|
+
- lib/tetrahedron/service.rb
|
147
209
|
- lib/tetrahedron/sessions.rb
|
148
|
-
- lib/tetrahedron/tasks/tet.rake
|
149
210
|
- tetrahedron.gemspec
|
150
211
|
homepage: http://github.com/mtwilliams/tetrahedron
|
151
212
|
licenses:
|
@@ -170,5 +231,5 @@ rubyforge_project:
|
|
170
231
|
rubygems_version: 2.4.5.1
|
171
232
|
signing_key:
|
172
233
|
specification_version: 4
|
173
|
-
summary:
|
234
|
+
summary: Welcome to the Tet.
|
174
235
|
test_files: []
|
data/config/app.ru
DELETED
@@ -1,21 +0,0 @@
|
|
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
|
data/config/application.rb
DELETED
data/config/environment.rb
DELETED
@@ -1,18 +0,0 @@
|
|
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
DELETED
@@ -1,29 +0,0 @@
|
|
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/app.rb
DELETED
@@ -1,16 +0,0 @@
|
|
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
|
data/lib/tetrahedron/assets.rb
DELETED
@@ -1,43 +0,0 @@
|
|
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
|
data/lib/tetrahedron/bootfile.rb
DELETED
@@ -1,43 +0,0 @@
|
|
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
|
data/lib/tetrahedron/bundler.rb
DELETED
@@ -1,44 +0,0 @@
|
|
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
|
@@ -1,17 +0,0 @@
|
|
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
|
data/lib/tetrahedron/endpoint.rb
DELETED
@@ -1,28 +0,0 @@
|
|
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
|
data/lib/tetrahedron/errors.rb
DELETED
data/lib/tetrahedron/model.rb
DELETED
@@ -1,32 +0,0 @@
|
|
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
|
data/lib/tetrahedron/rake.rb
DELETED
@@ -1,16 +0,0 @@
|
|
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
|
data/lib/tetrahedron/redis.rb
DELETED