dzl 1.0.0.beta0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +9 -0
- data/README.md +44 -0
- data/Rakefile +15 -0
- data/config.ru +41 -0
- data/dzl.gemspec +21 -0
- data/lib/dzl/doc/endpoint_doc.rb +70 -0
- data/lib/dzl/doc/router_doc.rb +26 -0
- data/lib/dzl/doc/task.rb +5 -0
- data/lib/dzl/doc/templates/endpoint.erb +55 -0
- data/lib/dzl/doc/templates/home.erb +8 -0
- data/lib/dzl/doc.rb +58 -0
- data/lib/dzl/dsl_proxies/defaults.rb +10 -0
- data/lib/dzl/dsl_proxies/endpoint.rb +30 -0
- data/lib/dzl/dsl_proxies/parameter.rb +75 -0
- data/lib/dzl/dsl_proxies/parameter_block.rb +61 -0
- data/lib/dzl/dsl_proxies/protection.rb +6 -0
- data/lib/dzl/dsl_proxies/router.rb +62 -0
- data/lib/dzl/dsl_proxy.rb +8 -0
- data/lib/dzl/dsl_subject.rb +15 -0
- data/lib/dzl/dsl_subjects/defaults.rb +12 -0
- data/lib/dzl/dsl_subjects/endpoint.rb +79 -0
- data/lib/dzl/dsl_subjects/parameter/allowed_values.rb +60 -0
- data/lib/dzl/dsl_subjects/parameter/type_conversion.rb +59 -0
- data/lib/dzl/dsl_subjects/parameter.rb +100 -0
- data/lib/dzl/dsl_subjects/parameter_block.rb +64 -0
- data/lib/dzl/dsl_subjects/protection.rb +31 -0
- data/lib/dzl/dsl_subjects/router.rb +87 -0
- data/lib/dzl/errors.rb +33 -0
- data/lib/dzl/examples/base.rb +9 -0
- data/lib/dzl/examples/fun_with_handlers.rb +33 -0
- data/lib/dzl/examples/fun_with_hooks.rb +65 -0
- data/lib/dzl/examples/fun_with_params.rb +71 -0
- data/lib/dzl/examples/fun_with_requests.rb +47 -0
- data/lib/dzl/examples/route_profile.rb +158 -0
- data/lib/dzl/examples/trey.rb +97 -0
- data/lib/dzl/logger.rb +65 -0
- data/lib/dzl/rack_interface.rb +95 -0
- data/lib/dzl/request.rb +54 -0
- data/lib/dzl/response_context/request_helpers.rb +11 -0
- data/lib/dzl/response_context.rb +47 -0
- data/lib/dzl/validator.rb +10 -0
- data/lib/dzl/validators/size.rb +32 -0
- data/lib/dzl/validators/value.rb +30 -0
- data/lib/dzl/value_or_error.rb +32 -0
- data/lib/dzl/version.rb +3 -0
- data/lib/dzl.rb +96 -0
- data/spec/dsl_subject_spec.rb +14 -0
- data/spec/endpoint_doc_spec.rb +25 -0
- data/spec/fun_with_handlers_spec.rb +37 -0
- data/spec/fun_with_hooks_spec.rb +61 -0
- data/spec/fun_with_params_spec.rb +197 -0
- data/spec/fun_with_requests_spec.rb +101 -0
- data/spec/logger_spec.rb +48 -0
- data/spec/route_params_spec.rb +13 -0
- data/spec/router_doc_spec.rb +32 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/trey_spec.rb +135 -0
- data/spec/value_or_error_spec.rb +44 -0
- metadata +142 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'dzl/examples/base'
|
2
|
+
|
3
|
+
class Dzl::Examples::FunWithRequests < Dzl::Examples::Base
|
4
|
+
endpoint '/foo' do
|
5
|
+
handle do
|
6
|
+
'get'
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
endpoint '/post_op', :post do
|
11
|
+
handle do
|
12
|
+
'post'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
endpoint '/multi_op', :post, :put do
|
17
|
+
handle do
|
18
|
+
request.request_method.downcase
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
get '/get_only'
|
23
|
+
delete '/delete_only'
|
24
|
+
get '/get_and_post', :post
|
25
|
+
|
26
|
+
get '/validated_header' do
|
27
|
+
required_header :key do
|
28
|
+
validate_with { |k| k == 'hello' }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
get '/ambiguous' do
|
33
|
+
required :foo
|
34
|
+
|
35
|
+
handle do
|
36
|
+
params[:foo]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
get '/ambiguous' do
|
41
|
+
required :bar
|
42
|
+
|
43
|
+
handle do
|
44
|
+
params[:bar]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'dzl/examples/base'
|
2
|
+
|
3
|
+
class Dzl::Examples::RouteProfile < Dzl::Examples::base
|
4
|
+
global_pblock do end
|
5
|
+
|
6
|
+
#150 routes
|
7
|
+
endpoint '/Lorem' do end
|
8
|
+
endpoint '/ipsum' do end
|
9
|
+
endpoint '/dolor' do end
|
10
|
+
endpoint '/sit' do end
|
11
|
+
endpoint '/amet' do end
|
12
|
+
endpoint '/consectetur' do end
|
13
|
+
endpoint '/adipiscing' do end
|
14
|
+
endpoint '/elit' do end
|
15
|
+
endpoint '/Aenean' do end
|
16
|
+
endpoint '/pulvinar' do end
|
17
|
+
endpoint '/ante' do end
|
18
|
+
endpoint '/id' do end
|
19
|
+
endpoint '/venenatis' do end
|
20
|
+
endpoint '/eleifend' do end
|
21
|
+
endpoint '/Vivamus' do end
|
22
|
+
endpoint '/mattis' do end
|
23
|
+
endpoint '/tempor' do end
|
24
|
+
endpoint '/bibendum' do end
|
25
|
+
endpoint '/nulla' do end
|
26
|
+
endpoint '/lobortis' do end
|
27
|
+
endpoint '/vitae' do end
|
28
|
+
endpoint '/Vestibulum' do end
|
29
|
+
endpoint '/primis' do end
|
30
|
+
endpoint '/in' do end
|
31
|
+
endpoint '/faucibus' do end
|
32
|
+
endpoint '/orci' do end
|
33
|
+
endpoint '/luctus' do end
|
34
|
+
endpoint '/et' do end
|
35
|
+
endpoint '/ultrices' do end
|
36
|
+
endpoint '/posuere' do end
|
37
|
+
endpoint '/cubilia' do end
|
38
|
+
endpoint '/Curae;' do end
|
39
|
+
endpoint '/Proin' do end
|
40
|
+
endpoint '/nisi' do end
|
41
|
+
endpoint '/malesuada' do end
|
42
|
+
endpoint '/eu' do end
|
43
|
+
endpoint '/scelerisque' do end
|
44
|
+
endpoint '/ut' do end
|
45
|
+
endpoint '/eget' do end
|
46
|
+
endpoint '/augue' do end
|
47
|
+
endpoint '/Aliquam' do end
|
48
|
+
endpoint '/erat' do end
|
49
|
+
endpoint '/volutpat' do end
|
50
|
+
endpoint '/Praesent' do end
|
51
|
+
endpoint '/leo' do end
|
52
|
+
endpoint '/commodo' do end
|
53
|
+
endpoint '/ac' do end
|
54
|
+
endpoint '/suscipit' do end
|
55
|
+
endpoint '/sed' do end
|
56
|
+
endpoint '/magna' do end
|
57
|
+
endpoint '/Fusce' do end
|
58
|
+
endpoint '/lacinia' do end
|
59
|
+
endpoint '/lorem' do end
|
60
|
+
endpoint '/felis' do end
|
61
|
+
endpoint '/fermentum' do end
|
62
|
+
endpoint '/non' do end
|
63
|
+
endpoint '/molestie' do end
|
64
|
+
endpoint '/ligula' do end
|
65
|
+
endpoint '/sollicitudin' do end
|
66
|
+
endpoint '/Cras' do end
|
67
|
+
endpoint '/auctor' do end
|
68
|
+
endpoint '/mi' do end
|
69
|
+
endpoint '/eros' do end
|
70
|
+
endpoint '/quis' do end
|
71
|
+
endpoint '/velit' do end
|
72
|
+
endpoint '/facilisis' do end
|
73
|
+
endpoint '/a' do end
|
74
|
+
endpoint '/metus' do end
|
75
|
+
endpoint '/Ut' do end
|
76
|
+
endpoint '/enim' do end
|
77
|
+
endpoint '/aliquam' do end
|
78
|
+
endpoint '/cursus' do end
|
79
|
+
endpoint '/Etiam' do end
|
80
|
+
endpoint '/imperdiet' do end
|
81
|
+
endpoint '/rhoncus' do end
|
82
|
+
endpoint '/nibh' do end
|
83
|
+
endpoint '/tincidunt' do end
|
84
|
+
endpoint '/ullamcorper' do end
|
85
|
+
endpoint '/Nulla' do end
|
86
|
+
endpoint '/dapibus' do end
|
87
|
+
endpoint '/nunc' do end
|
88
|
+
endpoint '/at' do end
|
89
|
+
endpoint '/vestibulum' do end
|
90
|
+
endpoint '/tortor' do end
|
91
|
+
endpoint '/pharetra' do end
|
92
|
+
endpoint '/vulputate' do end
|
93
|
+
endpoint '/accumsan' do end
|
94
|
+
endpoint '/Pellentesque' do end
|
95
|
+
endpoint '/Nam' do end
|
96
|
+
endpoint '/elementum' do end
|
97
|
+
endpoint '/ultricies' do end
|
98
|
+
endpoint '/Morbi' do end
|
99
|
+
endpoint '/varius' do end
|
100
|
+
endpoint '/lacus' do end
|
101
|
+
endpoint '/mollis' do end
|
102
|
+
endpoint '/Quisque' do end
|
103
|
+
endpoint '/porttitor' do end
|
104
|
+
endpoint '/arcu' do end
|
105
|
+
endpoint '/mauris' do end
|
106
|
+
endpoint '/hendrerit' do end
|
107
|
+
endpoint '/pretium' do end
|
108
|
+
endpoint '/placerat' do end
|
109
|
+
endpoint '/quam' do end
|
110
|
+
endpoint '/feugiat' do end
|
111
|
+
endpoint '/diam' do end
|
112
|
+
endpoint '/aliquet' do end
|
113
|
+
endpoint '/convallis' do end
|
114
|
+
endpoint '/Donec' do end
|
115
|
+
endpoint '/dignissim' do end
|
116
|
+
endpoint '/lectus' do end
|
117
|
+
endpoint '/rutrum' do end
|
118
|
+
endpoint '/nisl' do end
|
119
|
+
endpoint '/ornare' do end
|
120
|
+
endpoint '/tristique' do end
|
121
|
+
endpoint '/sapien' do end
|
122
|
+
endpoint '/euismod' do end
|
123
|
+
endpoint '/vel' do end
|
124
|
+
endpoint '/massa' do end
|
125
|
+
endpoint '/porta' do end
|
126
|
+
endpoint '/nec' do end
|
127
|
+
endpoint '/habitant' do end
|
128
|
+
endpoint '/morbi' do end
|
129
|
+
endpoint '/senectus' do end
|
130
|
+
endpoint '/netus' do end
|
131
|
+
endpoint '/fames' do end
|
132
|
+
endpoint '/turpis' do end
|
133
|
+
endpoint '/egestas' do end
|
134
|
+
endpoint '/Curabitur' do end
|
135
|
+
endpoint '/pellentesque' do end
|
136
|
+
endpoint '/libero' do end
|
137
|
+
endpoint '/Duis' do end
|
138
|
+
endpoint '/congue' do end
|
139
|
+
endpoint '/iaculis' do end
|
140
|
+
endpoint '/In' do end
|
141
|
+
endpoint '/Nunc' do end
|
142
|
+
endpoint '/Sed' do end
|
143
|
+
endpoint '/blandit' do end
|
144
|
+
endpoint '/tempus' do end
|
145
|
+
endpoint '/tellus' do end
|
146
|
+
endpoint '/condimentum' do end
|
147
|
+
endpoint '/interdum' do end
|
148
|
+
endpoint '/fringilla' do end
|
149
|
+
endpoint '/viverra' do end
|
150
|
+
endpoint '/justo' do end
|
151
|
+
endpoint '/consequat' do end
|
152
|
+
endpoint '/gravida' do end
|
153
|
+
endpoint '/risus' do end
|
154
|
+
endpoint '/urna' do end
|
155
|
+
endpoint '/semper' do end
|
156
|
+
endpoint '/dui' do end
|
157
|
+
|
158
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'dzl/examples/base'
|
2
|
+
|
3
|
+
class Dzl::Examples::Trey < Dzl::Examples::Base
|
4
|
+
METRIC_NAMES_OR_WHATEVER ||= %w{m1 m2 m3 m4 m5 m6}
|
5
|
+
|
6
|
+
# this could be handy
|
7
|
+
# defaults do
|
8
|
+
# type Array do
|
9
|
+
# unique
|
10
|
+
# separator ' '
|
11
|
+
# end
|
12
|
+
# end
|
13
|
+
|
14
|
+
# global parameter block applies to all routes
|
15
|
+
# each route gets it's own copy, so, they can
|
16
|
+
# mess with the predefined parameters as much as
|
17
|
+
# they'd like
|
18
|
+
global_pblock do
|
19
|
+
# required_header :api_key do
|
20
|
+
# validate_with { |key| key == 'open sesame' }
|
21
|
+
# end
|
22
|
+
|
23
|
+
param :page_ids do
|
24
|
+
type Array
|
25
|
+
size <= 5
|
26
|
+
end
|
27
|
+
|
28
|
+
param :post_ids do
|
29
|
+
type Array
|
30
|
+
size <= 100
|
31
|
+
end
|
32
|
+
|
33
|
+
param :metrics do
|
34
|
+
type Array
|
35
|
+
allowed_values METRIC_NAMES_OR_WHATEVER
|
36
|
+
end
|
37
|
+
|
38
|
+
param :since, :until do
|
39
|
+
type Date
|
40
|
+
end
|
41
|
+
|
42
|
+
param :interval do
|
43
|
+
allowed_values %w{day week month}
|
44
|
+
default 'day'
|
45
|
+
end
|
46
|
+
|
47
|
+
param :limit do
|
48
|
+
type Fixnum
|
49
|
+
allowed_values 1..250
|
50
|
+
default 250
|
51
|
+
end
|
52
|
+
|
53
|
+
param :sort do
|
54
|
+
default 'created_time'
|
55
|
+
end
|
56
|
+
|
57
|
+
param :order do
|
58
|
+
prevalidate_transform do |input|
|
59
|
+
input.downcase
|
60
|
+
end
|
61
|
+
allowed_values ['asc', 'desc', 'ascending', 'descending']
|
62
|
+
default :desc
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
endpoint '/page_insights' do
|
67
|
+
required :page_ids, :metrics, :since, :until
|
68
|
+
optional :interval
|
69
|
+
forbid :post_ids, :limit, :sort, :order
|
70
|
+
end
|
71
|
+
|
72
|
+
endpoint '/post_insights' do
|
73
|
+
required :post_ids, :metrics
|
74
|
+
forbid :page_ids, :since, :until, :interval, :limit, :sort, :order
|
75
|
+
end
|
76
|
+
|
77
|
+
# endpoint '/post_insights' do
|
78
|
+
# required :page_ids do
|
79
|
+
# size <= 5
|
80
|
+
# end
|
81
|
+
|
82
|
+
# required :metrics, :since, :until
|
83
|
+
# forbid :post_ids, :interval, :limit, :sort, :order
|
84
|
+
# end
|
85
|
+
|
86
|
+
endpoint '/posts' do
|
87
|
+
required :page_ids, :metrics
|
88
|
+
optional :since, :until, :limit, :sort, :order
|
89
|
+
forbid :post_ids
|
90
|
+
end
|
91
|
+
|
92
|
+
# endpoint '/posts' do
|
93
|
+
# required :post_ids, :metrics
|
94
|
+
# optional :since, :until, :limit, :sort, :order
|
95
|
+
# forbid :page_ids
|
96
|
+
# end
|
97
|
+
end
|
data/lib/dzl/logger.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
class ActiveSupport::BufferedLogger
|
2
|
+
def self.timestamp
|
3
|
+
DateTime.now.strftime("[%Y-%m-%d %H:%M:%S] - ")
|
4
|
+
end
|
5
|
+
|
6
|
+
alias_method :orig_add, :add
|
7
|
+
def add(severity, message = nil, progname = nil, &block)
|
8
|
+
message = "#{ActiveSupport::BufferedLogger.timestamp}#{message}"
|
9
|
+
orig_add(severity, message, progname, &block)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module Dzl
|
14
|
+
class Logger
|
15
|
+
LOG_METHODS = [:debug, :info, :warn, :error, :fatal]
|
16
|
+
def initialize(app_root)
|
17
|
+
@app_root = app_root
|
18
|
+
@loggers = {
|
19
|
+
default: create_logger # log/[environment].log
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
# Get the standard logger methods defined
|
24
|
+
LOG_METHODS.each do |severity|
|
25
|
+
define_method(severity) do |msg|
|
26
|
+
log(severity, msg)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
############
|
31
|
+
# Receives all the default log methods on AppClass.logger
|
32
|
+
# and forwards to the default logger
|
33
|
+
############
|
34
|
+
def log(severity, msg)
|
35
|
+
@loggers[:default].send(severity, msg)
|
36
|
+
end
|
37
|
+
|
38
|
+
############
|
39
|
+
# The idea here is that you can call
|
40
|
+
# AppClass.logger.tidy.debug("Something")
|
41
|
+
# and we'll write your log message to tidy.environment.log
|
42
|
+
############
|
43
|
+
def method_missing(m, *args, &block)
|
44
|
+
if @loggers[:default].respond_to?(m)
|
45
|
+
# Don't create things like flush.development.log (-:
|
46
|
+
@loggers[:default].send(m, *args, &block)
|
47
|
+
else
|
48
|
+
@loggers[m] ||= create_logger(m.to_s)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
def create_logger(name = nil)
|
54
|
+
logfile = name ? "#{name}.#{Dzl.env}.log" : "#{Dzl.env}.log"
|
55
|
+
ActiveSupport::BufferedLogger.new(
|
56
|
+
File.join(@app_root, 'log', logfile),
|
57
|
+
%w{ staging production }.include?(Dzl.env) ? ::Logger::INFO : ::Logger::DEBUG
|
58
|
+
)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.logger
|
63
|
+
@@logger ||= Logger.new
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'dzl/request'
|
3
|
+
|
4
|
+
module Dzl::RackInterface
|
5
|
+
PROFILE_REQUESTS = false
|
6
|
+
|
7
|
+
def call(env)
|
8
|
+
response = nil
|
9
|
+
request = nil
|
10
|
+
start_time = Time.now
|
11
|
+
start_profile if PROFILE_REQUESTS
|
12
|
+
response = begin
|
13
|
+
request = Dzl::Request.new(env)
|
14
|
+
__router.handle_request(request)
|
15
|
+
rescue Dzl::RespondWithHTTPBasicChallenge
|
16
|
+
respond_with_http_basic_challenge
|
17
|
+
rescue Dzl::Error => e
|
18
|
+
respond_with_dzl_error_handler(e)
|
19
|
+
rescue StandardError => e
|
20
|
+
respond_with_standard_error_handler(e)
|
21
|
+
end
|
22
|
+
|
23
|
+
if response[0] < 100
|
24
|
+
response = respond_with_standard_error_handler(StandardError.new('Application did not respond'))
|
25
|
+
end
|
26
|
+
|
27
|
+
stop_profiling_and_print if PROFILE_REQUESTS
|
28
|
+
log_request(request, response, (Time.now - start_time)) unless request.silent?
|
29
|
+
|
30
|
+
if Dzl.production? || Dzl.staging?
|
31
|
+
(response[0] < 500) ? response : [response[0], [], [response[0].to_s]]
|
32
|
+
else
|
33
|
+
response
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def respond_with_http_basic_challenge
|
38
|
+
response = Rack::Response.new
|
39
|
+
response['WWW-Authenticate'] = %(Basic realm="Dzl HTTP Basic")
|
40
|
+
response.status = 401
|
41
|
+
response.headers['Content-Type'] = 'text/html'
|
42
|
+
response.write("Not Authorized\n")
|
43
|
+
response.finish
|
44
|
+
end
|
45
|
+
|
46
|
+
def respond_with_standard_error_handler(e)
|
47
|
+
response = Rack::Response.new
|
48
|
+
response.headers['Content-Type'] = 'application/json'
|
49
|
+
response.status = 500
|
50
|
+
|
51
|
+
response.write({
|
52
|
+
status: 500,
|
53
|
+
error_class: e.class.to_s,
|
54
|
+
errors: e.to_s,
|
55
|
+
trace: e.backtrace
|
56
|
+
}.to_json)
|
57
|
+
|
58
|
+
response.finish
|
59
|
+
end
|
60
|
+
|
61
|
+
def respond_with_dzl_error_handler(e)
|
62
|
+
response = Rack::Response.new
|
63
|
+
response.headers['Content-Type'] = 'application/json'
|
64
|
+
|
65
|
+
if e.is_a?(Dzl::RequestError)
|
66
|
+
response.status = e.status
|
67
|
+
response.write(e.to_json)
|
68
|
+
else
|
69
|
+
response.status = e.status
|
70
|
+
response.write(e.to_json)
|
71
|
+
end
|
72
|
+
|
73
|
+
response.finish
|
74
|
+
end
|
75
|
+
|
76
|
+
def start_profile
|
77
|
+
require 'ruby-prof'
|
78
|
+
RubyProf.start
|
79
|
+
end
|
80
|
+
|
81
|
+
def stop_profiling_and_print
|
82
|
+
result = RubyProf.stop
|
83
|
+
printer = RubyProf::GraphHtmlPrinter.new(result)
|
84
|
+
printer.print(
|
85
|
+
File.open('/Projects/dzl/profile.html', 'w'),
|
86
|
+
min_percent: 5
|
87
|
+
)
|
88
|
+
end
|
89
|
+
|
90
|
+
def log_request(request, response, seconds)
|
91
|
+
logger.info "#{request.request_method} #{request.path}"
|
92
|
+
logger.info "PARAMS: #{request.params}"
|
93
|
+
logger.info "#{response[0]} in #{seconds * 1000}ms"
|
94
|
+
end
|
95
|
+
end
|
data/lib/dzl/request.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
class Dzl::Request < Rack::Request
|
2
|
+
attr_accessor :silent
|
3
|
+
|
4
|
+
def initialize(env)
|
5
|
+
super(env)
|
6
|
+
|
7
|
+
@endpoints = Hash.new({})
|
8
|
+
end
|
9
|
+
|
10
|
+
def headers
|
11
|
+
@headers ||= begin
|
12
|
+
env.each_with_object({}) do |env_pair, headers|
|
13
|
+
k, v = env_pair
|
14
|
+
if header = (/HTTP_(.+)/.match(k.upcase.gsub('-', '_'))[1]) rescue nil
|
15
|
+
headers[header.downcase] = v
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def params
|
22
|
+
@params ||= super
|
23
|
+
end
|
24
|
+
|
25
|
+
def overwrite_headers(new_headers)
|
26
|
+
@headers = new_headers
|
27
|
+
end
|
28
|
+
|
29
|
+
def overwrite_params(new_params)
|
30
|
+
@params = new_params
|
31
|
+
end
|
32
|
+
|
33
|
+
def handle_with_endpoint(endpoint)
|
34
|
+
overwrite_params(@endpoints[endpoint][:params])
|
35
|
+
overwrite_headers(@endpoints[endpoint][:headers])
|
36
|
+
endpoint.handle(self).finish
|
37
|
+
end
|
38
|
+
|
39
|
+
def params_and_headers_for_endpoint(endpoint, params_and_headers = nil)
|
40
|
+
if params_and_headers
|
41
|
+
raise ArgumentError unless params_and_headers.is_a?(Hash) &&
|
42
|
+
params_and_headers.has_key?(:params) &&
|
43
|
+
params_and_headers.has_key?(:headers)
|
44
|
+
|
45
|
+
@endpoints[endpoint].merge!(params_and_headers)
|
46
|
+
else
|
47
|
+
@endpoints[endpoint].slice(:params, :headers)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def silent?
|
52
|
+
@silent == true
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'dzl/response_context/request_helpers'
|
2
|
+
|
3
|
+
class Dzl::ResponseContext
|
4
|
+
include RequestHelpers
|
5
|
+
attr_reader :request, :response, :endpoint
|
6
|
+
|
7
|
+
@@default_handler = Proc.new do
|
8
|
+
response['Content-Type'] = 'application/json'
|
9
|
+
{
|
10
|
+
headers: headers,
|
11
|
+
params: params
|
12
|
+
}.to_json
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(endpoint, request, handler = nil)
|
16
|
+
@request = request
|
17
|
+
@endpoint = endpoint
|
18
|
+
@handler = handler
|
19
|
+
__build_response_with_defaults__
|
20
|
+
end
|
21
|
+
|
22
|
+
def logger
|
23
|
+
@logger ||= @endpoint.router.app.logger
|
24
|
+
end
|
25
|
+
|
26
|
+
def __respond__
|
27
|
+
@endpoint.hooks[:after_validate].each do |proc|
|
28
|
+
self.instance_exec(&proc)
|
29
|
+
end
|
30
|
+
|
31
|
+
value = @handler ? self.instance_exec(&@handler) : self.instance_exec(&@@default_handler)
|
32
|
+
|
33
|
+
unless @response.body.present?
|
34
|
+
@response.write(value)
|
35
|
+
end
|
36
|
+
|
37
|
+
@response
|
38
|
+
end
|
39
|
+
|
40
|
+
def __build_response_with_defaults__
|
41
|
+
@response = Rack::Response.new
|
42
|
+
|
43
|
+
if ct = @endpoint.router.defaults[:content_type]
|
44
|
+
@response['Content-Type'] = ct
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Dzl::Validators
|
2
|
+
class Size < Dzl::Validator
|
3
|
+
attr_reader :conditions
|
4
|
+
def initialize
|
5
|
+
@conditions = []
|
6
|
+
end
|
7
|
+
|
8
|
+
def validate(input)
|
9
|
+
unless input.respond_to?(:size)
|
10
|
+
return Dzl::ValueOrError.new(
|
11
|
+
e: :cannot_validate_size
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
valid = @conditions.all? do |op, n|
|
16
|
+
input.size.send(op, n)
|
17
|
+
end
|
18
|
+
|
19
|
+
if valid
|
20
|
+
Dzl::ValueOrError.new(v: input)
|
21
|
+
else
|
22
|
+
Dzl::ValueOrError.new(e: :size_validation_failed)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
[:==, :<=, :>=, :<, :>].each do |op|
|
27
|
+
define_method(op) do |n|
|
28
|
+
@conditions << [op, n]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Dzl::Validators
|
2
|
+
class Value < Dzl::Validator
|
3
|
+
attr_reader :conditions
|
4
|
+
def initialize
|
5
|
+
@conditions = []
|
6
|
+
end
|
7
|
+
|
8
|
+
def validate(input)
|
9
|
+
valid = @conditions.all? do |op, n|
|
10
|
+
return Dzl::ValueOrError.new(
|
11
|
+
e: :value_validation_failed
|
12
|
+
) unless input.respond_to?(op)
|
13
|
+
|
14
|
+
input.send(op, n)
|
15
|
+
end
|
16
|
+
|
17
|
+
if valid
|
18
|
+
Dzl::ValueOrError.new(v: input)
|
19
|
+
else
|
20
|
+
Dzl::ValueOrError.new(e: :value_validation_failed)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
[:==, :<=, :>=, :<, :>].each do |op|
|
25
|
+
define_method(op) do |n|
|
26
|
+
@conditions << [op, n]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class Dzl::ValueOrError
|
2
|
+
attr_reader :error, :value
|
3
|
+
|
4
|
+
def initialize(opts = {})
|
5
|
+
@error = opts[:error] || opts[:e]
|
6
|
+
@value = opts[:value] || opts[:v]
|
7
|
+
|
8
|
+
if @error && @value
|
9
|
+
raise ArgumentError, "it's ValueOrError, not ValueAndError"
|
10
|
+
end
|
11
|
+
|
12
|
+
unless @error || opts.has_key?(:v) || opts.has_key?(:value)
|
13
|
+
raise ArgumentError, "Must provide :value key, even if nil"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def error?
|
18
|
+
@error.present?
|
19
|
+
end
|
20
|
+
|
21
|
+
def value?
|
22
|
+
!error?
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
if error?
|
27
|
+
"e: #{@error.inspect}"
|
28
|
+
else
|
29
|
+
"v: #{@value.inspect}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/dzl/version.rb
ADDED