groundskeeper 1.0.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/lib/groundskeeper.rb +8 -0
- data/lib/groundskeeper/middleware.rb +71 -0
- data/lib/groundskeeper/middleware/header.rb +25 -0
- data/lib/groundskeeper/middleware/parameter.rb +25 -0
- data/lib/groundskeeper/middleware/path.rb +29 -0
- data/lib/groundskeeper/middleware/subdomain.rb +43 -0
- data/lib/groundskeeper/version.rb +4 -0
- data/spec/lib/groundskeeper/middleware/path_spec.rb +28 -0
- data/spec/lib/groundskeeper/middleware/subdomain_spec.rb +21 -0
- data/spec/lib/groundskeeper/middleware_spec.rb +32 -0
- data/spec/lib/groundskeeper/version_spec.rb +7 -0
- data/spec/lib/groundskeeper_spec.rb +5 -0
- data/spec/spec_helper.rb +30 -0
- metadata +176 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c3975fada368881d791f29aff9a9d69ec1936601
|
4
|
+
data.tar.gz: e8ea24cf07c35ac745f2049ebe3f8bf89a1f120f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7eaad077b35bfc0fed048f25da2f5b899709d286e474ec33d89870e388aaeceb4ac5046d81f7c1b7e7df2f379f596fa5037879d752a263515b245a23ac7bb252
|
7
|
+
data.tar.gz: de45823a612d6f0bcbab713d6438078b6a6b349301dfbdcd755bbc094c986eca18ac3b559900e2dcc8725e4086c22613a8a2c5137743bc7774316ba8f14789fb
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Groundskeeper
|
2
|
+
class Middleware
|
3
|
+
NAMESPACE_KEY = "Groundskeeper-Namespace"
|
4
|
+
TENANT_KEY = "Groundskeeper-Tenant"
|
5
|
+
MODEL_KEY = :model
|
6
|
+
QUERY_KEY = :query
|
7
|
+
DEFAULT_KEY = :default
|
8
|
+
QUERY_DEFAULT = ->(model, slug) do
|
9
|
+
model.find_by_slug(slug)
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(app, options = {})
|
13
|
+
raise ArgumentError, "missing model" unless options.key?(model_key)
|
14
|
+
|
15
|
+
@options = options
|
16
|
+
@app = app
|
17
|
+
@env = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
def call(env)
|
21
|
+
@env = env
|
22
|
+
env[namespace_key] = namespace
|
23
|
+
env[tenant_key] = tenant
|
24
|
+
@app.call(env)
|
25
|
+
end
|
26
|
+
|
27
|
+
private def tenant
|
28
|
+
query.call(model, namespace) || default
|
29
|
+
end
|
30
|
+
|
31
|
+
private def model
|
32
|
+
if @options[model_key].is_a?(String)
|
33
|
+
Object.const_get(@options[model_key])
|
34
|
+
else
|
35
|
+
@options[model_key]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private def default
|
40
|
+
@options[default_key]
|
41
|
+
end
|
42
|
+
|
43
|
+
private def query
|
44
|
+
@options[query_key] || query_default
|
45
|
+
end
|
46
|
+
|
47
|
+
private def namespace_key
|
48
|
+
self.class.const_get("NAMESPACE_KEY")
|
49
|
+
end
|
50
|
+
|
51
|
+
private def tenant_key
|
52
|
+
self.class.const_get("TENANT_KEY")
|
53
|
+
end
|
54
|
+
|
55
|
+
private def model_key
|
56
|
+
self.class.const_get("MODEL_KEY")
|
57
|
+
end
|
58
|
+
|
59
|
+
private def default_key
|
60
|
+
self.class.const_get("DEFAULT_KEY")
|
61
|
+
end
|
62
|
+
|
63
|
+
private def query_key
|
64
|
+
self.class.const_get("QUERY_KEY")
|
65
|
+
end
|
66
|
+
|
67
|
+
private def query_default
|
68
|
+
self.class.const_get("QUERY_DEFAULT")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Groundskeeper
|
2
|
+
class Middleware
|
3
|
+
class Header < Middleware
|
4
|
+
PARSE_KEY = :parse
|
5
|
+
PARSE_DEFAULT = ->(headers) { headers[HEADER_DEFAULT_KEY] }
|
6
|
+
HEADER_DEFAULT_KEY = "Groundskeeper-Namespace"
|
7
|
+
|
8
|
+
private def namespace
|
9
|
+
# parse.call()
|
10
|
+
end
|
11
|
+
|
12
|
+
private def parse
|
13
|
+
@options[parse_key] || parse_default
|
14
|
+
end
|
15
|
+
|
16
|
+
private def parse_key
|
17
|
+
self.class.const_get("PARSE_KEY")
|
18
|
+
end
|
19
|
+
|
20
|
+
private def parse_default
|
21
|
+
self.class.const_get("PARSE_DEFAULT")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Groundskeeper
|
2
|
+
class Middleware
|
3
|
+
class Parameter < Middleware
|
4
|
+
PARSE_KEY = :parse
|
5
|
+
PARSE_DEFAULT = ->(params) { params[PARAM_DEFAULT_KEY] }
|
6
|
+
PARAM_DEFAULT_KEY = "tenant"
|
7
|
+
|
8
|
+
private def namespace
|
9
|
+
# parse.call()
|
10
|
+
end
|
11
|
+
|
12
|
+
private def parse
|
13
|
+
@options[parse_key] || parse_default
|
14
|
+
end
|
15
|
+
|
16
|
+
private def parse_key
|
17
|
+
self.class.const_get("PARSE_KEY")
|
18
|
+
end
|
19
|
+
|
20
|
+
private def parse_default
|
21
|
+
self.class.const_get("PARSE_DEFAULT")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Groundskeeper
|
2
|
+
class Middleware
|
3
|
+
class Path < Middleware
|
4
|
+
PARSE_KEY = :parse
|
5
|
+
PARSE_DEFAULT = ->(path) { path.split("/")[1] }
|
6
|
+
RACK_PATH_KEY = "PATH_INFO"
|
7
|
+
|
8
|
+
private def namespace
|
9
|
+
parse.call(@env[rack_path_key])
|
10
|
+
end
|
11
|
+
|
12
|
+
private def parse
|
13
|
+
@options[parse_key] || parse_default
|
14
|
+
end
|
15
|
+
|
16
|
+
private def parse_key
|
17
|
+
self.class.const_get("PARSE_KEY")
|
18
|
+
end
|
19
|
+
|
20
|
+
private def parse_default
|
21
|
+
self.class.const_get("PARSE_DEFAULT")
|
22
|
+
end
|
23
|
+
|
24
|
+
private def rack_path_key
|
25
|
+
self.class.const_get("RACK_PATH_KEY")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Groundskeeper
|
2
|
+
class Middleware
|
3
|
+
class Subdomain < Middleware
|
4
|
+
DEPTH_KEY = :depth
|
5
|
+
DEPTH_DEFAULT = -3
|
6
|
+
PARSE_KEY = :parse
|
7
|
+
PARSE_DEFAULT = ->(fqdn, depth) { fqdn.split(".")[depth] }
|
8
|
+
RACK_HOST_KEY = "HTTP_HOST"
|
9
|
+
|
10
|
+
private def namespace
|
11
|
+
parse.call(@env[rack_host_key], depth)
|
12
|
+
end
|
13
|
+
|
14
|
+
private def parse
|
15
|
+
@options[parse_key] || parse_default
|
16
|
+
end
|
17
|
+
|
18
|
+
private def parse_key
|
19
|
+
self.class.const_get("PARSE_KEY")
|
20
|
+
end
|
21
|
+
|
22
|
+
private def parse_default
|
23
|
+
self.class.const_get("PARSE_DEFAULT")
|
24
|
+
end
|
25
|
+
|
26
|
+
private def depth
|
27
|
+
@options[depth_key].to_i * -1 || depth_default
|
28
|
+
end
|
29
|
+
|
30
|
+
private def depth_key
|
31
|
+
self.class.const_get("DEPTH_KEY")
|
32
|
+
end
|
33
|
+
|
34
|
+
private def depth_default
|
35
|
+
self.class.const_get("DEPTH_DEFAULT")
|
36
|
+
end
|
37
|
+
|
38
|
+
private def rack_host_key
|
39
|
+
self.class.const_get("RACK_HOST_KEY")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "groundskeeper/middleware/path"
|
3
|
+
|
4
|
+
describe Groundskeeper::Middleware::Path do
|
5
|
+
include_context "rack setup"
|
6
|
+
let(:url) { "http://foo.example.com/admin/james/users" }
|
7
|
+
let(:namespace) { "admin" }
|
8
|
+
|
9
|
+
describe "#call" do
|
10
|
+
it "sets the namespace correctly" do
|
11
|
+
expect(request_namespace).to eq(namespace)
|
12
|
+
end
|
13
|
+
|
14
|
+
context "looking to namespace on second nested path resource" do
|
15
|
+
let(:options) do
|
16
|
+
{
|
17
|
+
model: model,
|
18
|
+
parse: ->(path) { path.split("/").compact[2] }
|
19
|
+
}
|
20
|
+
end
|
21
|
+
let(:namespace) { "james" }
|
22
|
+
|
23
|
+
it "sets the namespace correctly" do
|
24
|
+
expect(request_namespace).to eq(namespace)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "groundskeeper/middleware/subdomain"
|
3
|
+
|
4
|
+
describe Groundskeeper::Middleware::Subdomain do
|
5
|
+
include_context "rack setup"
|
6
|
+
|
7
|
+
describe "#call" do
|
8
|
+
it "sets the namespace correctly" do
|
9
|
+
expect(request_namespace).to eq(namespace)
|
10
|
+
end
|
11
|
+
|
12
|
+
context "looking to namespace on domain" do
|
13
|
+
let(:options) do { model: model, depth: 2 } end
|
14
|
+
let(:namespace) { "example" }
|
15
|
+
|
16
|
+
it "sets the namespace correctly" do
|
17
|
+
expect(request_namespace).to eq(namespace)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Groundskeeper::Middleware do
|
4
|
+
include_context "rack setup"
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
allow(middleware).to receive(:namespace).and_return(namespace)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#call" do
|
11
|
+
it "sets the namespace correctly" do
|
12
|
+
expect(request_namespace).to eq(namespace)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "sets the tenant correctly" do
|
16
|
+
expect(request_tenant).to eq(instance)
|
17
|
+
end
|
18
|
+
|
19
|
+
context "with a default" do
|
20
|
+
let(:default) { double("Default") }
|
21
|
+
let(:options) do { model: model, default: default } end
|
22
|
+
|
23
|
+
before(:each) do
|
24
|
+
allow(model).to receive(:find).and_return(nil)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "sets the default as the tenant" do
|
28
|
+
expect(request_tenant).to eq(default)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require "pry"
|
2
|
+
require "rspec"
|
3
|
+
require "groundskeeper"
|
4
|
+
|
5
|
+
shared_context "rack setup" do
|
6
|
+
let(:url) { "http://foo.example.com" }
|
7
|
+
let(:rack_env) do
|
8
|
+
{
|
9
|
+
"HTTP_HOST" => URI.parse(url).host,
|
10
|
+
"PATH_INFO" => URI.parse(url).path
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:namespace) { "foo" }
|
15
|
+
let(:model) { double("Model") }
|
16
|
+
let(:instance) { instance_double("Model") }
|
17
|
+
|
18
|
+
let(:app) { ->(env) { [200, rack_env, "app"] } }
|
19
|
+
let(:options) do { model: model } end
|
20
|
+
let(:middleware) { described_class.new(app, options) }
|
21
|
+
let(:request) { middleware.call(rack_env) }
|
22
|
+
let(:request_code) { request[0] }
|
23
|
+
let(:request_env) { request[1] }
|
24
|
+
let(:request_namespace) { request_env[Groundskeeper::Middleware::NAMESPACE_KEY] }
|
25
|
+
let(:request_tenant) { request_env[Groundskeeper::Middleware::TENANT_KEY] }
|
26
|
+
|
27
|
+
before(:each) do
|
28
|
+
allow(model).to receive(:find).and_return(instance)
|
29
|
+
end
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: groundskeeper
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kurtis Rainbolt-Greene
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-06-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rack
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
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.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.1'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: yard
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.8'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.8'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: kramdown
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.2'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.2'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: pry
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.9'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.9'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: pry-doc
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.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.6'
|
125
|
+
description: A simple multi-tenancy middleware with options
|
126
|
+
email:
|
127
|
+
- me@kurtisrainboltgreene.name
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- lib/groundskeeper.rb
|
133
|
+
- lib/groundskeeper/middleware.rb
|
134
|
+
- lib/groundskeeper/middleware/header.rb
|
135
|
+
- lib/groundskeeper/middleware/parameter.rb
|
136
|
+
- lib/groundskeeper/middleware/path.rb
|
137
|
+
- lib/groundskeeper/middleware/subdomain.rb
|
138
|
+
- lib/groundskeeper/version.rb
|
139
|
+
- spec/lib/groundskeeper/middleware/path_spec.rb
|
140
|
+
- spec/lib/groundskeeper/middleware/subdomain_spec.rb
|
141
|
+
- spec/lib/groundskeeper/middleware_spec.rb
|
142
|
+
- spec/lib/groundskeeper/version_spec.rb
|
143
|
+
- spec/lib/groundskeeper_spec.rb
|
144
|
+
- spec/spec_helper.rb
|
145
|
+
homepage: http://krainboltgreene.github.io/groundskeeper
|
146
|
+
licenses:
|
147
|
+
- MIT
|
148
|
+
metadata: {}
|
149
|
+
post_install_message:
|
150
|
+
rdoc_options: []
|
151
|
+
require_paths:
|
152
|
+
- lib
|
153
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - ">="
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
158
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
159
|
+
requirements:
|
160
|
+
- - ">="
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: '0'
|
163
|
+
requirements: []
|
164
|
+
rubyforge_project:
|
165
|
+
rubygems_version: 2.2.2
|
166
|
+
signing_key:
|
167
|
+
specification_version: 4
|
168
|
+
summary: A simple multi-tenancy middleware with options
|
169
|
+
test_files:
|
170
|
+
- spec/lib/groundskeeper/middleware/path_spec.rb
|
171
|
+
- spec/lib/groundskeeper/middleware/subdomain_spec.rb
|
172
|
+
- spec/lib/groundskeeper/middleware_spec.rb
|
173
|
+
- spec/lib/groundskeeper/version_spec.rb
|
174
|
+
- spec/lib/groundskeeper_spec.rb
|
175
|
+
- spec/spec_helper.rb
|
176
|
+
has_rdoc:
|