forked from rkh/sinatra-namespace
/
namespace.rb
115 lines (98 loc) · 3.4 KB
/
namespace.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
require 'sinatra/base'
module Sinatra
module Namespace
module NestedMethods
attr_reader :prefix, :options, :base
def get(name = nil, options = {}, &block) prefixed(:get, name, options, &block) end
def put(name = nil, options = {}, &block) prefixed(:put, name, options, &block) end
def post(name = nil, options = {}, &block) prefixed(:post, name, options, &block) end
def delete(name = nil, options = {}, &block) prefixed(:delete, name, options, &block) end
def head(name = nil, options = {}, &block) prefixed(:head, name, options, &block) end
def before(name = nil, &block) prefixed(:before, name, &block) end
def after(name = nil, &block) prefixed(:after, name, &block) end
def helpers(*list, &block)
include(*list) unless list.empty?
class_eval(&block) if block
end
private
def app
return base if base.is_a? Class
base.app
end
def prefixed_path(name)
if prefix.is_a? Regexp or name.is_a? Regexp
path = /#{prefix}#{name}/
path = /^#{path}$/ if base.is_a? Class
path
else
prefix.to_s + name.to_s
end
end
def prefixed(method, name, *args, &block)
if name.respond_to? :key?
args.unshift name
name = nil
end
options.each { |o, a| app.send(o, *a ) }
base.send(method, prefixed_path(name), *args, &block)
end
end
module ClassMethods
def namespace(prefix = nil, options = {}, &block)
Namespace.setup(self, prefix, options, Module.new, &block)
end
def make_namespace(mod, options = {})
options[:base] ||= self
Namespace.make_namespace(mod, options)
end
def make_namespace?(klass, meth)
true
end
end
module ModularMethods
def setup(base, prefix = nil, options = {}, mixin = nil, &block)
prefix, options = nil, prefix if options.empty? and prefix.respond_to? :key?
prefix ||= "/*"
mixin ||= self
mixin.class_eval { @prefix, @options, @base = prefix, options, base }
mixin.extend ClassMethods, NestedMethods
mixin.before { extend mixin }
mixin.class_eval(&block) if block
mixin
end
end
extend ModularMethods
def self.make_namespace(mod, options = {})
from = caller[0] =~ /make_namespace/ ? caller[1] : caller[0]
base = options.delete(:base) || options.delete(:for)
options[:prefix] ||= '/' << mod.name.gsub(/^#{base.name}::/, '').
gsub(/::/, '/').gsub(/([a-z\d]+)([A-Z][a-z])/,'\1_\2').downcase
setup base, options.delete(:prefix), options, mod
end
def self.included(klass)
klass.extend ModularMethods
super
end
def self.registered(klass)
klass.extend ClassMethods
end
end
module NamespaceDetector
Module.send(:include, self)
def method_missing(meth, *args, &block)
return super if is_a? Class or !name
base = Object
detected = name.split('::').any? do |name|
base = base.const_get(name)
base < Sinatra::Base
end
if detected and base.make_namespace?(self, meth)
Sinatra::Namespace.make_namespace self, :base => base
send(meth, *args, &block)
else
super
end
end
end
register Namespace
end