penthouse 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +3 -0
- data/README.md +42 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/penthouse/app.rb +37 -0
- data/lib/penthouse/configuration.rb +21 -0
- data/lib/penthouse/routers/base_router.rb +24 -0
- data/lib/penthouse/routers/subdomain_router.rb +18 -0
- data/lib/penthouse/runners/base_runner.rb +33 -0
- data/lib/penthouse/runners/schema_runner.rb +20 -0
- data/lib/penthouse/sidekiq/middleware/client.rb +8 -0
- data/lib/penthouse/sidekiq/middleware/server.rb +9 -0
- data/lib/penthouse/sidekiq/railtie.rb +7 -0
- data/lib/penthouse/sidekiq.rb +30 -0
- data/lib/penthouse/tenants/base_tenant.rb +29 -0
- data/lib/penthouse/tenants/octopus_schema_tenant.rb +28 -0
- data/lib/penthouse/tenants/octopus_shard_tenant.rb +36 -0
- data/lib/penthouse/tenants/schema_tenant.rb +45 -0
- data/lib/penthouse/version.rb +3 -0
- data/lib/penthouse.rb +61 -0
- data/penthouse.gemspec +34 -0
- metadata +210 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 89e508c4ecb8d4e9aaebf054202f87e0ef171578
|
4
|
+
data.tar.gz: d89449c14673b9a0764c82a4711018dc8db85fce
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3c6cebc9a8e4d0d12331d4d801cbe87866c998c52695c17d5400b8102217f98c117b89bd52dff1eb23be7f09ef8e23827e38f56af4051f28904680d8500e3be0
|
7
|
+
data.tar.gz: 09bacbedcbbe99b6af2165e6501661267a0e6b7735a3234f9ef3c8c00b92385749c2b2ba9971dbe5a0e7a0c2460f46e4890c3352ff22f8fce0a743d6d9e59ee0
|
data/.gitignore
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ryantownsend-penthouse-rubygem
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.3.0
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
Penthouse is an alternative to the excellent [Apartment gem](https://github.com/influitive/apartment) – however Penthouse is more of a framework for multi-tenancy than a library, in that it provides less out-of-the-box functionality, but should make for easier customisation.
|
2
|
+
|
3
|
+
## Installation
|
4
|
+
|
5
|
+
Add this line to your application's Gemfile:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
gem 'penthouse'
|
9
|
+
```
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
If you're using Rails, you just need to configure an initializer at `config/initializers/penthouse.rb`
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
require 'penthouse'
|
17
|
+
# include the standard Rack app
|
18
|
+
require 'penthouse/app'
|
19
|
+
# include the automated Sidekiq integration, should you be using it
|
20
|
+
require 'penthouse/sidekiq' if defined?(Sidekiq)
|
21
|
+
# require the relevant router/runner you wish to use
|
22
|
+
require 'penthouse/routers/subdomain_router'
|
23
|
+
require 'penthouse/runners/schema_runner'
|
24
|
+
|
25
|
+
Penthouse.configure do |config|
|
26
|
+
config.router = Penthouse::Routers::SubdomainRouter
|
27
|
+
config.runner = Penthouse::Runners::SchemaRunner
|
28
|
+
end
|
29
|
+
|
30
|
+
Rails.application.config.middleware.use Penthouse::App
|
31
|
+
```
|
32
|
+
|
33
|
+
It's advised that if you want to customise these classes, you do so by sub-classing `Penthouse::App`, `Penthouse::Routers::BaseRouter` and/or `Penthouse::Runners::BaseRunner` within this initializer.
|
34
|
+
|
35
|
+
## Dictionary
|
36
|
+
|
37
|
+
* **Router** – this class receives a Rack request object and returns an identifier (just a string or symbol) for the tenant.
|
38
|
+
* **Runner** – this class receives the identifier (either from the router or manually switching), then looks up the tenant instance and runs the code within it.
|
39
|
+
|
40
|
+
## Contributing
|
41
|
+
|
42
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/ryantownsend/penthouse.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "penthouse"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
#
|
2
|
+
# The Penthouse::App class defines a Rack middleware to be included into your
|
3
|
+
# stack before your main application is called.
|
4
|
+
#
|
5
|
+
# @example Typically in Rails you'd use:
|
6
|
+
# Rails.application.config.middleware.use Penthouse::App, router: Penthouse::Routers::BaseRouter
|
7
|
+
#
|
8
|
+
# This app uses the router to determine the tenant instance, then calls the
|
9
|
+
# application within that tenant.
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'rack/request'
|
13
|
+
|
14
|
+
module Penthouse
|
15
|
+
class App
|
16
|
+
attr_accessor :app, :router, :runner
|
17
|
+
private :app=, :router=, :runner=
|
18
|
+
|
19
|
+
# @param app the Rack application
|
20
|
+
# @param router [#call] the class/proc to use as the router
|
21
|
+
# @param runner [#call] the class/proc to use as the runner
|
22
|
+
def initialize(app, router: Penthouse.configuration.router, runner: Penthouse.configuration.runner)
|
23
|
+
self.app = app
|
24
|
+
self.router = router
|
25
|
+
self.runner = runner
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param env [Hash] the environment passed from Rack
|
29
|
+
# @raise [Penthouse::TenantNotFound] if the tenant cannot be found/switched to
|
30
|
+
def call(env)
|
31
|
+
request = Rack::Request.new(env)
|
32
|
+
runner.call(router.call(request)) do
|
33
|
+
app.call(env)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#
|
2
|
+
# The Penthouse::Configuration class contains all configuration options for
|
3
|
+
# Penthouse, such as which router to use.
|
4
|
+
#
|
5
|
+
# @example
|
6
|
+
# Penthouse.configure do |config|
|
7
|
+
# config.router = Penthouse::Routers::BaseRouter
|
8
|
+
# config.runner = Penthouse::Runners::BaseRunner
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
|
12
|
+
module Penthouse
|
13
|
+
class Configuration
|
14
|
+
attr_accessor :router, :runner
|
15
|
+
|
16
|
+
def initialize(router: nil, runner: nil)
|
17
|
+
self.router = router
|
18
|
+
self.runner = runner
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#
|
2
|
+
# This class provides an abstract for the router interface. Whilst any Proc
|
3
|
+
# could be used, it's safest for people to sub-class to ensure that any future
|
4
|
+
# interface changes are catered for.
|
5
|
+
#
|
6
|
+
# A router class's responsibility in Penthouse is to receive a Rack::Request
|
7
|
+
# object from the App instance and return an identifier for that tenant
|
8
|
+
#
|
9
|
+
|
10
|
+
module Penthouse
|
11
|
+
module Routers
|
12
|
+
class BaseRouter
|
13
|
+
|
14
|
+
# Typically used by the App to return a tenant that can be switched to
|
15
|
+
# @param request [Rack::Request] The request from the Rack app, used to determine the tenant
|
16
|
+
# @return [String, Symbol] A tenant identifier
|
17
|
+
# @raise [Penthouse::TenantNotFound] if the tenant cannot be found/switched to
|
18
|
+
def self.call(request)
|
19
|
+
raise NotImplementedError
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#
|
2
|
+
# This router will load the tenant name based on a request's sub-domain
|
3
|
+
#
|
4
|
+
|
5
|
+
module Penthouse
|
6
|
+
module Routers
|
7
|
+
class SubdomainRouter < BaseRouter
|
8
|
+
|
9
|
+
# Determines the tenant identifier based on the sub-domain of the request
|
10
|
+
# @param request [Rack::Request] The request from the Rack app, used to determine the tenant
|
11
|
+
# @return [String, Symbol] A tenant identifier
|
12
|
+
def self.call(request)
|
13
|
+
request.host.split(".").first
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#
|
2
|
+
# This class provides an abstract for the runner interface. Whilst any Proc
|
3
|
+
# could be used, it's easiest to sub-class then overwrite the #load_tenant
|
4
|
+
# method.
|
5
|
+
#
|
6
|
+
# A runner class's responsibility in Penthouse is to receive an identifier for
|
7
|
+
# a tenant and a block, and to execute that block within the tenant
|
8
|
+
#
|
9
|
+
|
10
|
+
module Penthouse
|
11
|
+
module Runners
|
12
|
+
class BaseRunner
|
13
|
+
|
14
|
+
# @param tenant_identifier [String, Symbol] The identifier for the tenant
|
15
|
+
# @param block [Block] The code to execute within the tenant
|
16
|
+
# @raise [Penthouse::TenantNotFound] if the tenant cannot be switched to
|
17
|
+
def self.call(tenant_identifier, &block)
|
18
|
+
load_tenant(tenant_identifier).call do |tenant|
|
19
|
+
Penthouse.with_tenant(tenant.identifier) do
|
20
|
+
block.yield(tenant)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# @param tenant_identifier [String, Symbol] The identifier for the tenant
|
26
|
+
# @return [Penthouse::Tenants::BaseTenant] An instance of a tenant
|
27
|
+
# @raise [Penthouse::TenantNotFound] if the tenant cannot be switched to
|
28
|
+
def self.load_tenant(tenant_identifier)
|
29
|
+
raise NotImplementedError
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#
|
2
|
+
# This runner will simply use the SchemaTenant
|
3
|
+
#
|
4
|
+
|
5
|
+
require_relative './base_runner'
|
6
|
+
require_relative '../tenants/schema_tenant'
|
7
|
+
|
8
|
+
module Penthouse
|
9
|
+
module Runners
|
10
|
+
class SchemaRunner < BaseRunner
|
11
|
+
|
12
|
+
# @param tenant_identifier [String, Symbol] The identifier for the tenant
|
13
|
+
# @return [Penthouse::Tenants::BaseTenant] An instance of a tenant
|
14
|
+
def self.load_tenant(tenant_identifier)
|
15
|
+
Tenants::SchemaTenant.new(tenant_identifier, tenant_schema: tenant_identifier)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'sidekiq'
|
2
|
+
require 'penthouse/sidekiq/middleware/client'
|
3
|
+
require 'penthouse/sidekiq/middleware/server'
|
4
|
+
|
5
|
+
module Penthouse
|
6
|
+
module Sidekiq
|
7
|
+
module Middleware
|
8
|
+
|
9
|
+
def self.run
|
10
|
+
::Sidekiq.configure_client do |config|
|
11
|
+
config.client_middleware do |chain|
|
12
|
+
chain.add Penthouse::Sidekiq::Middleware::Client
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
::Sidekiq.configure_server do |config|
|
17
|
+
config.client_middleware do |chain|
|
18
|
+
chain.add Penthouse::Sidekiq::Middleware::Client
|
19
|
+
end
|
20
|
+
|
21
|
+
config.server_middleware do |chain|
|
22
|
+
chain.insert_before ::Sidekiq::Middleware::Server::RetryJobs, Penthouse::Sidekiq::Middleware::Server
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
require 'penthouse/sidekiq/railtie' if defined?(Rails)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#
|
2
|
+
# This class provides an abstract for the tenant interface. Whilst any Proc
|
3
|
+
# could be used, it's safest for people to sub-class to ensure that any future
|
4
|
+
# interface changes are catered for.
|
5
|
+
#
|
6
|
+
# A tenant class's responsibility is to receive a block, around which it should
|
7
|
+
# handle switching to the given tenant's configuration, ensuring that if an
|
8
|
+
# exception occurs, the configuration is reset back to the global configuration.
|
9
|
+
#
|
10
|
+
module Penthouse
|
11
|
+
module Tenants
|
12
|
+
class BaseTenant
|
13
|
+
attr_accessor :identifier
|
14
|
+
private :identifier=
|
15
|
+
|
16
|
+
# @param identifier [String, Symbol] An identifier for the tenant
|
17
|
+
def initialize(identifier)
|
18
|
+
self.identifier = identifier
|
19
|
+
end
|
20
|
+
|
21
|
+
# placeholder for the relevant tenant-switching code
|
22
|
+
# @param block [Block] The code to execute within the tenant
|
23
|
+
# @yield [BaseTenant] The current tenant instance
|
24
|
+
def call(&block)
|
25
|
+
raise NotImplementedError
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#
|
2
|
+
# The OctopusSchemaTenant class relies upon Octopus [1], it uses the master
|
3
|
+
# database and simply switches the schema search path to allow for isolated
|
4
|
+
# data, but low overheads in terms of costs. Note: this means tenants will be
|
5
|
+
# sharing a single Postgres instance and therefore performance is shared.
|
6
|
+
#
|
7
|
+
# [1]: (https://github.com/thiagopradi/octopus)
|
8
|
+
#
|
9
|
+
|
10
|
+
require_relative './schema_tenant'
|
11
|
+
require 'octopus'
|
12
|
+
|
13
|
+
module Penthouse
|
14
|
+
module Tenants
|
15
|
+
class OctopusSchemaTenant < SchemaTenant
|
16
|
+
|
17
|
+
# ensures we're on the master Octopus shard, just updates the schema name
|
18
|
+
# with the tenant name
|
19
|
+
# @param block [Block] The code to execute within the schema
|
20
|
+
# @yield [SchemaTenant] The current tenant instance
|
21
|
+
def call(&block)
|
22
|
+
Octopus.using(:master) do
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#
|
2
|
+
# The ShardTenant class relies upon Octopus [1], it switches to a different
|
3
|
+
# shard per tenant, allowing for each tenant to have their own database, 100%
|
4
|
+
# isolated from other tenants in terms of data and performance.
|
5
|
+
#
|
6
|
+
# [1]: (https://github.com/thiagopradi/octopus)
|
7
|
+
#
|
8
|
+
|
9
|
+
require_relative './base_tenant'
|
10
|
+
require 'octopus'
|
11
|
+
|
12
|
+
module Penthouse
|
13
|
+
module Tenants
|
14
|
+
class OctopusShardTenant < BaseTenant
|
15
|
+
attr_accessor :shard
|
16
|
+
private :shard=
|
17
|
+
|
18
|
+
# @param identifier [String, Symbol] An identifier for the tenant
|
19
|
+
# @param shard [String, Symbol] the configured Octopus shard to use for this tenant
|
20
|
+
def initialize(identifer, shard:)
|
21
|
+
super(identifier)
|
22
|
+
self.shard = shard
|
23
|
+
freeze
|
24
|
+
end
|
25
|
+
|
26
|
+
# switches to the relevant Octopus shard, and processes the block
|
27
|
+
# @param block [Block] The code to execute within the connection to the shard
|
28
|
+
# @yield [ShardTenant] The current tenant instance
|
29
|
+
def call(&block)
|
30
|
+
Octopus.using(shard) do
|
31
|
+
block.yield(self)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
#
|
2
|
+
# The SchemaTenant class simply switches the schema search path to allow for
|
3
|
+
# isolated data, but low overheads in terms of costs. Note: this means tenants
|
4
|
+
# will be sharing a single Postgres instance and therefore performance is
|
5
|
+
# shared.
|
6
|
+
#
|
7
|
+
|
8
|
+
require_relative './base_tenant'
|
9
|
+
|
10
|
+
module Penthouse
|
11
|
+
module Tenants
|
12
|
+
class SchemaTenant < BaseTenant
|
13
|
+
attr_accessor :tenant_schema, :persistent_schemas, :default_schema
|
14
|
+
private :tenant_schema=, :persistent_schemas=, :default_schema=
|
15
|
+
|
16
|
+
# @param identifier [String, Symbol] An identifier for the tenant
|
17
|
+
# @param tenant_schema [String] your tenant's schema name in Postgres
|
18
|
+
# @param tenant_schema [String] your tenant's schema name in Postgres
|
19
|
+
# @param persistent_schemas [Array<String>] The schemas you always want in the search path
|
20
|
+
# @param default_schema [String] The global schema name, usually 'public'
|
21
|
+
def initialize(identifier, tenant_schema:, persistent_schemas: ["shared_extensions"], default_schema: "public")
|
22
|
+
super(identifier)
|
23
|
+
self.tenant_schema = tenant_schema
|
24
|
+
self.persistent_schemas = Array(persistent_schemas).flatten
|
25
|
+
self.default_schema = default_schema
|
26
|
+
freeze
|
27
|
+
end
|
28
|
+
|
29
|
+
# ensures we're on the master Octopus shard, just updates the schema name
|
30
|
+
# with the tenant name
|
31
|
+
# @param block [Block] The code to execute within the schema
|
32
|
+
# @yield [SchemaTenant] The current tenant instance
|
33
|
+
def call(&block)
|
34
|
+
begin
|
35
|
+
# set the search path to include the tenant
|
36
|
+
ActiveRecord::Base.connection.schema_search_path = persistent_schemas.unshift(tenant_schema).join(", ")
|
37
|
+
block.yield(self)
|
38
|
+
ensure
|
39
|
+
# reset the search path back to the default
|
40
|
+
ActiveRecord::Base.connection.schema_search_path = persistent_schemas.unshift(default_schema).join(", ")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/penthouse.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require "penthouse/version"
|
2
|
+
require "penthouse/configuration"
|
3
|
+
require "penthouse/routers/base_router"
|
4
|
+
require "penthouse/runners/base_runner"
|
5
|
+
|
6
|
+
module Penthouse
|
7
|
+
class TenantNotFound < RuntimeError; end
|
8
|
+
|
9
|
+
class << self
|
10
|
+
# Retrieves the currently active tenant identifier
|
11
|
+
# @return [String, Symbol] the current tenant name
|
12
|
+
def tenant
|
13
|
+
Thread.current[:tenant]
|
14
|
+
end
|
15
|
+
|
16
|
+
# Sets the currently active tenant identifier
|
17
|
+
# @param tenant_identifier [String, Symbol] the identifier for the tenant
|
18
|
+
def tenant=(tenant_identifier)
|
19
|
+
Thread.current[:tenant] = tenant_identifier
|
20
|
+
end
|
21
|
+
|
22
|
+
# Similar to Penthouse.tenant=, except this will switch back after the given
|
23
|
+
# block has finished executing
|
24
|
+
# @param tenant_identifier [String, Symbol] the identifier for the tenant
|
25
|
+
# @param default_tenant [String, Symbol] the identifier for the tenant to return to
|
26
|
+
# @param block [Block] the code to execute
|
27
|
+
# @yield [String, Symbol] the identifier for the tenant
|
28
|
+
def with_tenant(tenant_identifier, default_tenant: tenant, &block)
|
29
|
+
self.tenant = tenant_identifier
|
30
|
+
block.yield(tenant_identifier)
|
31
|
+
ensure
|
32
|
+
self.tenant = default_tenant
|
33
|
+
end
|
34
|
+
|
35
|
+
# Executes the given block of code within a given tenant
|
36
|
+
# @param tenant_identifier [String, Symbol] the identifier for the tenant
|
37
|
+
# @param runner [Penthouse::Runners::BaseRunner] an optional runner to use, defaults to the one configured
|
38
|
+
# @param block [Block] the code to execute
|
39
|
+
def switch(tenant_identifier, runner: configuration.runner, &block)
|
40
|
+
runner.call(tenant_identifier, &block)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Allows you to configure the router of Penthouse
|
44
|
+
# @yield [Penthouse::Configuration]
|
45
|
+
def configure(&block)
|
46
|
+
# allow the configuration by the block
|
47
|
+
block.yield(self.configuration)
|
48
|
+
# prevent modification of configuration once set
|
49
|
+
self.configuration.freeze
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns the current configuration of Penthouse
|
53
|
+
# @return [Penthouse::Configuration]
|
54
|
+
def configuration
|
55
|
+
@configuration ||= Configuration.new(
|
56
|
+
router: Routers::BaseRouter,
|
57
|
+
runner: Runners::BaseRunner
|
58
|
+
)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/penthouse.gemspec
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'penthouse/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'penthouse'
|
8
|
+
spec.version = Penthouse::VERSION
|
9
|
+
spec.authors = ['Ryan Townsend']
|
10
|
+
spec.email = ['ryan@ryantownsend.co.uk']
|
11
|
+
|
12
|
+
spec.summary = %q{Multi-tenancy framework. Out of the box, supports Postgres schemas and per-tenant databases}
|
13
|
+
spec.homepage = 'https://github.com/ryantownsend/penthouse'
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
16
|
+
spec.bindir = 'exe'
|
17
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
|
20
|
+
spec.add_dependency 'bundler', '~> 1.11'
|
21
|
+
|
22
|
+
spec.add_development_dependency 'bundler', '~> 1.11'
|
23
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
24
|
+
spec.add_development_dependency 'yard', '~> 0.8.7.6'
|
25
|
+
# testing
|
26
|
+
spec.add_development_dependency 'rspec', '~> 3.4.0'
|
27
|
+
spec.add_development_dependency 'simplecov', '~> 0.11.2'
|
28
|
+
# web
|
29
|
+
spec.add_development_dependency 'rack', '~> 1.6.4'
|
30
|
+
# db
|
31
|
+
spec.add_development_dependency 'ar-octopus', '~> 0.8.6'
|
32
|
+
spec.add_development_dependency 'activerecord', '~> 4.2.6'
|
33
|
+
spec.add_development_dependency 'pg'
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,210 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: penthouse
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ryan Townsend
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-03-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.11'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.11'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.11'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.11'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: yard
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.8.7.6
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.8.7.6
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 3.4.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 3.4.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.11.2
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.11.2
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rack
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 1.6.4
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 1.6.4
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: ar-octopus
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.8.6
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.8.6
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: activerecord
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 4.2.6
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 4.2.6
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: pg
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
description:
|
154
|
+
email:
|
155
|
+
- ryan@ryantownsend.co.uk
|
156
|
+
executables: []
|
157
|
+
extensions: []
|
158
|
+
extra_rdoc_files: []
|
159
|
+
files:
|
160
|
+
- ".gitignore"
|
161
|
+
- ".ruby-gemset"
|
162
|
+
- ".ruby-version"
|
163
|
+
- Gemfile
|
164
|
+
- README.md
|
165
|
+
- Rakefile
|
166
|
+
- bin/console
|
167
|
+
- bin/setup
|
168
|
+
- lib/penthouse.rb
|
169
|
+
- lib/penthouse/app.rb
|
170
|
+
- lib/penthouse/configuration.rb
|
171
|
+
- lib/penthouse/routers/base_router.rb
|
172
|
+
- lib/penthouse/routers/subdomain_router.rb
|
173
|
+
- lib/penthouse/runners/base_runner.rb
|
174
|
+
- lib/penthouse/runners/schema_runner.rb
|
175
|
+
- lib/penthouse/sidekiq.rb
|
176
|
+
- lib/penthouse/sidekiq/middleware/client.rb
|
177
|
+
- lib/penthouse/sidekiq/middleware/server.rb
|
178
|
+
- lib/penthouse/sidekiq/railtie.rb
|
179
|
+
- lib/penthouse/tenants/base_tenant.rb
|
180
|
+
- lib/penthouse/tenants/octopus_schema_tenant.rb
|
181
|
+
- lib/penthouse/tenants/octopus_shard_tenant.rb
|
182
|
+
- lib/penthouse/tenants/schema_tenant.rb
|
183
|
+
- lib/penthouse/version.rb
|
184
|
+
- penthouse.gemspec
|
185
|
+
homepage: https://github.com/ryantownsend/penthouse
|
186
|
+
licenses: []
|
187
|
+
metadata: {}
|
188
|
+
post_install_message:
|
189
|
+
rdoc_options: []
|
190
|
+
require_paths:
|
191
|
+
- lib
|
192
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
193
|
+
requirements:
|
194
|
+
- - ">="
|
195
|
+
- !ruby/object:Gem::Version
|
196
|
+
version: '0'
|
197
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
requirements: []
|
203
|
+
rubyforge_project:
|
204
|
+
rubygems_version: 2.5.1
|
205
|
+
signing_key:
|
206
|
+
specification_version: 4
|
207
|
+
summary: Multi-tenancy framework. Out of the box, supports Postgres schemas and per-tenant
|
208
|
+
databases
|
209
|
+
test_files: []
|
210
|
+
has_rdoc:
|