jetra 1.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5b6d7a10300cb071943c84db41627c7dbc051e4c
4
+ data.tar.gz: f4c8b2ce7efaa9d93ccbe301eb70ee51b44b155f
5
+ SHA512:
6
+ metadata.gz: 000a5c59fc536a6d0f95ffef0c50bee342da2843da07f2cc288f9c1d7245eb6fe0ee40712f96ccfdf8b7abe1e1d7036705c6f70fc210aaf7311fd6eb907555f6
7
+ data.tar.gz: d7c93df3cba8b1f6e734c01f6499c50457a02a4b2dbd1c87330fc6cb2585bb7d97fc618ede00926b1c62ad4f061cd19a13c8510f3421859c43e330da2825ab7b
@@ -0,0 +1,2 @@
1
+
2
+ require "jetra/base"
@@ -0,0 +1,66 @@
1
+
2
+ require "set"
3
+ require 'json'
4
+
5
+ module Jetra
6
+
7
+ class RackAdapter
8
+
9
+ include Rack::Utils
10
+
11
+ def initialize(app)
12
+ @app = app
13
+
14
+ @routes = Set.new
15
+ @app.routes.each_key do |route|
16
+ @routes << route
17
+ end
18
+
19
+ end
20
+
21
+ def call(env)
22
+
23
+ request = Rack::Request.new(env)
24
+
25
+ route = request.path_info
26
+ route.chop! if (char=route[-1]) and char=='/' # ignore last '/' char
27
+ route[0] = '' if route[0]=="/" #remove first '/' char
28
+
29
+ sym_route = route.to_sym
30
+
31
+ if @routes.include?(sym_route)
32
+ params = indifferent_params(request.params)
33
+ res = @app.call(sym_route, params)
34
+ else
35
+ res = @app.call(:not_found, {route: route})
36
+ end
37
+
38
+ result = {}
39
+ result[:status] = res.status
40
+ result[:body] = res.body
41
+
42
+ ['200', {'Content-Type' => 'application/json;charset=utf-8'}, [result.to_json]]
43
+ end
44
+
45
+ # Enable string or symbol key access to the nested params hash.
46
+ def indifferent_params(object)
47
+ case object
48
+ when Hash
49
+ new_hash = indifferent_hash
50
+ object.each { |key, value| new_hash[key] = indifferent_params(value) }
51
+ new_hash
52
+ when Array
53
+ object.map { |item| indifferent_params(item) }
54
+ else
55
+ object
56
+ end
57
+ end
58
+
59
+ # Creates a Hash with indifferent access.
60
+ def indifferent_hash
61
+ Hash.new {|hash,key| hash[key.to_s] if Symbol === key }
62
+ end
63
+
64
+ end
65
+
66
+ end
@@ -0,0 +1,10 @@
1
+ module Jetra
2
+
3
+ class Application
4
+
5
+ def initialize(app)
6
+ @app = app
7
+ end
8
+
9
+ end
10
+ end
@@ -0,0 +1,323 @@
1
+ require "jetra/application"
2
+
3
+ module Jetra
4
+
5
+ class NotFoundException < Exception ; end
6
+
7
+ class Halt ; end
8
+
9
+ class Request
10
+
11
+ attr_accessor :route, :params
12
+
13
+ def initialize(route, params)
14
+ @route = route || ""
15
+ @params = params || {}
16
+ end
17
+ end
18
+
19
+ class Response
20
+
21
+ attr_accessor :status, :body
22
+
23
+ def initialize(status=0, body=nil)
24
+ @status = status.to_i
25
+ @body = body
26
+ end
27
+
28
+ def finish
29
+ self.freeze
30
+ end
31
+ end
32
+
33
+ class Base
34
+
35
+ attr_accessor :request, :response, :params
36
+
37
+ def call(route, params)
38
+ dup.call!(route, params)
39
+ end
40
+
41
+ def call!(route, params)
42
+
43
+ @request = Request.new(route, params)
44
+ @response = Response.new
45
+
46
+ @params = indifferentParams(@request.params)
47
+
48
+ invoke { dispatch! }
49
+
50
+ @response.finish
51
+ end
52
+
53
+ def currentClass
54
+ self.class
55
+ end
56
+
57
+ def indifferentParams(object)
58
+ case object
59
+ when Hash
60
+ newHash = indifferentHash
61
+ object.each { |key, value| newHash[key] = indifferentParams(value) }
62
+ newHash
63
+ when Array
64
+ object.map { |item| indifferentParams(item) }
65
+ else
66
+ object
67
+ end
68
+ end
69
+
70
+ def indifferentHash
71
+ Hash.new {|hash,key| hash[key.to_s] if Symbol === key }
72
+ end
73
+
74
+ def invoke
75
+ res = catch(Halt) { yield }
76
+
77
+ if Array === res
78
+ res = res.dup
79
+
80
+ if status = res.shift
81
+ response.status = status
82
+ end
83
+
84
+ if body = res.shift
85
+ response.body = body
86
+ end
87
+ else
88
+ if res
89
+ response.body = res
90
+ end
91
+ end
92
+ nil
93
+ end
94
+
95
+ def dispatch!
96
+ filter! :before
97
+ route!
98
+ rescue ::Exception => boom
99
+ gotError = true
100
+ handleException!(boom)
101
+ ensure
102
+ begin
103
+ filter! :after
104
+ rescue ::Exception => boom
105
+ handleException!(boom) unless gotError
106
+ end
107
+ end
108
+
109
+ def handleException!(boom)
110
+
111
+ response.status = 0
112
+
113
+ errorBlock!(boom.class, boom)
114
+
115
+ raise boom
116
+ end
117
+
118
+ def halt(*response)
119
+ response = response.first if response.length == 1
120
+ throw Halt, response
121
+ end
122
+
123
+ def filter!(type)
124
+ currentClass.filters[type].each do |args|
125
+ processRoute(*args)
126
+ end
127
+ end
128
+
129
+ def route!
130
+
131
+ if block = currentClass.routes[@request.route.to_sym]
132
+ processRoute do |*args|
133
+ routeEval { block[*args] }
134
+ end
135
+ end
136
+
137
+ routeMissing
138
+ end
139
+
140
+ def errorBlock!(errorClass, *blockParams)
141
+
142
+ if errorBlocks = currentClass.errors[errorClass]
143
+ errorBlocks.reverse_each do |errorBlock|
144
+ args = [errorBlock]
145
+ args += [blockParams]
146
+ resp = processRoute(*args)
147
+ end
148
+ end
149
+
150
+ if errorClass.respond_to? :superclass and errorClass.superclass <= Exception
151
+ errorBlock!(errorClass.superclass, *blockParams)
152
+ end
153
+ end
154
+
155
+ def routeEval
156
+ throw Halt, yield
157
+ end
158
+
159
+ def processRoute(block=nil,values=[])
160
+ block ? block[self,values] : yield(self,values)
161
+ end
162
+
163
+ def routeMissing
164
+ raise NotFoundException.new("route not found")
165
+ end
166
+
167
+ def successResponse(body, args = {status: 1})
168
+ status = args[:status]
169
+ raise "status code must >= 1 when using success" if status < 1
170
+
171
+ if body.class == String
172
+ body = {msg: body}
173
+ end
174
+
175
+ response.body = body
176
+ response.status = status
177
+ nil
178
+ end
179
+
180
+ def failureResponse(body, args = {status: -1})
181
+ status = args[:status]
182
+ raise "status code must <= -1 when using failure" if status > -1
183
+
184
+ if body.class == String
185
+ body = {msg: body}
186
+ end
187
+
188
+ response.body = body
189
+ response.status = status
190
+ nil
191
+ end
192
+
193
+ def haltSuccess(body, args = {status: 1})
194
+ halt successResponse(body, args)
195
+ end
196
+
197
+ def haltFailure(body, args ={status: -1})
198
+ halt failureResponse(body, args)
199
+ end
200
+
201
+ class << self
202
+
203
+ attr_accessor :routes, :filters, :errors
204
+
205
+ def prototype
206
+ @prototype ||= new
207
+ end
208
+
209
+ def call(route, params={})
210
+ prototype.call(route, params)
211
+ end
212
+
213
+ def before(&block)
214
+ addFilter(:before, &block)
215
+ end
216
+
217
+ def after(&block)
218
+ addFilter(:after, &block)
219
+ end
220
+
221
+ def addFilter(type, &block)
222
+ @filters[type] << compile!(&block)
223
+ end
224
+
225
+ def route(symbol, &block)
226
+ block ||= Proc.new { method(symbol).call }
227
+ @routes[symbol] = compile!(&block)
228
+ end
229
+
230
+ def error(*codes, &block)
231
+ codes = codes.map { |c| Array(c) }.flatten
232
+ codes << Exception if codes.empty?
233
+ codes.each { |c| (@errors[c] ||= []) << compile!(&block) }
234
+ end
235
+
236
+ def generateUnboundMethod(&block)
237
+ methodName = :id #any symbol is ok.
238
+ define_method(methodName, &block)
239
+ method = instance_method methodName
240
+ remove_method methodName
241
+ method
242
+ end
243
+
244
+ def compile!(&block)
245
+
246
+ unboundMethod = generateUnboundMethod(&block)
247
+
248
+ block.arity != 0 ?
249
+ proc { |a,p| unboundMethod.bind(a).call(*p) } :
250
+ proc { |a,p| unboundMethod.bind(a).call }
251
+ end
252
+
253
+ def inherited(subclass)
254
+
255
+ subclass.routes = copyRoutes
256
+ subclass.filters = copyFilters
257
+ subclass.errors = copyErrors
258
+
259
+ super
260
+ end
261
+
262
+ def copyRoutes
263
+ newRoutes = {}
264
+ @routes.each do |key, value|
265
+ newRoutes[key] = value
266
+ end
267
+ newRoutes
268
+ end
269
+
270
+ def copyFilters
271
+ newFilters = {}
272
+ @filters.each do |key, values|
273
+ newValues = []
274
+ values.each do |value|
275
+ newValues << value
276
+ end
277
+ newFilters[key] = newValues
278
+ end
279
+ newFilters
280
+ end
281
+
282
+ def copyErrors
283
+ newErrors = {}
284
+ @errors.each do |key, values|
285
+ newValues = []
286
+ values.each do |value|
287
+ newValues << value
288
+ end
289
+ newErrors[key] = newValues
290
+ end
291
+ newErrors
292
+ end
293
+
294
+ def to_app
295
+
296
+ newApp = Jetra::Application.new(self)
297
+ @routes.each_key do |route|
298
+ eval("newApp.define_singleton_method(route) do |params={}| ; @app.call(route, params) ; end ")
299
+ end
300
+
301
+ eval("newApp.define_singleton_method(:method_missing) do |methodName, params={}| ; @app.call(methodName, params) ; end ")
302
+
303
+ newApp
304
+ end
305
+
306
+ end
307
+
308
+ @routes = {}
309
+ @filters = {:before => [], :after => []}
310
+ @errors = {}
311
+
312
+ error do |boom|
313
+ if boom.class == Jetra::NotFoundException
314
+ trace = []
315
+ else
316
+ trace = boom.backtrace
317
+ end
318
+ response.body = {msg: "#{boom.class} - #{boom.message}", class: boom.class.to_s, route: request.route, params: params, trace: trace}
319
+ halt
320
+ end
321
+
322
+ end
323
+ end
@@ -0,0 +1,51 @@
1
+ require "jetra/application"
2
+
3
+ module Jetra
4
+
5
+ class Builder
6
+
7
+ def initialize(&block)
8
+ @use = []
9
+ instance_eval(&block) if block_given?
10
+
11
+ @app = build_app
12
+ end
13
+
14
+ def call(route, params={})
15
+ @app.call(route, params)
16
+ end
17
+
18
+ def routes
19
+ @run.routes
20
+ end
21
+
22
+ def to_app
23
+
24
+ newApp = Jetra::Application.new(self)
25
+ routes.each_key do |route|
26
+ eval("newApp.define_singleton_method(route) do |params={}| ; @app.call(route, params) ; end ")
27
+ end
28
+
29
+ eval("newApp.define_singleton_method(:method_missing) do |methodName, params={}| ; @app.call(methodName, params) ; end ")
30
+
31
+ newApp
32
+ end
33
+
34
+ private
35
+
36
+ def use(middleware)
37
+ @use << proc { |app| middleware.new(app) }
38
+ end
39
+
40
+ def run(app)
41
+ @run = app
42
+ end
43
+
44
+ def build_app
45
+ app = @run
46
+ fail "missing run statement" unless app
47
+ app = @use.reverse.inject(app) { |a,e| e[a] }
48
+ app
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,53 @@
1
+ require "jetra/application"
2
+
3
+ module Jetra
4
+
5
+ class Combiner
6
+
7
+ def initialize(&block)
8
+
9
+ @leader = nil
10
+ @routes = {}
11
+
12
+ instance_eval(&block) if block_given?
13
+
14
+ fail "missing mount statement" unless @leader
15
+ end
16
+
17
+ def call(route, params={})
18
+ if app = @routes[route]
19
+ app.call(route, params)
20
+ else
21
+ @leader.call(route, params)
22
+ end
23
+ end
24
+
25
+ def routes
26
+ @routes
27
+ end
28
+
29
+ def to_app
30
+
31
+ newApp = Jetra::Application.new(self)
32
+ routes.each_key do |route|
33
+ eval("newApp.define_singleton_method(route) do |params={}| ; @app.call(route, params) ; end ")
34
+ end
35
+
36
+ eval("newApp.define_singleton_method(:method_missing) do |method_name, params={}| ; @app.call(method_name, params) ; end ")
37
+
38
+ newApp
39
+ end
40
+
41
+ private
42
+
43
+ def mount(app)
44
+
45
+ app.routes.each_key do |route|
46
+ @routes[route] ||= app
47
+ end
48
+
49
+ @leader ||= app
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,30 @@
1
+ module Jetra
2
+
3
+ module Middleware
4
+
5
+ #简单的中间件示例
6
+ class Sample
7
+
8
+ def initialize(app)
9
+ @app = app
10
+ end
11
+
12
+ def call(route, params)
13
+
14
+ #you can do something you like before call
15
+
16
+ #puts "sample middleware call start.."
17
+
18
+ response = @app.call(route, params)
19
+
20
+ #puts "sample middleware call finish.."
21
+
22
+ #you can do something you like after call
23
+
24
+ response
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,37 @@
1
+ module Jetra
2
+
3
+ module Middleware
4
+
5
+ #验证参数和返回值的基本类型
6
+ class Validater
7
+
8
+ def initialize(app)
9
+ @app = app
10
+ end
11
+
12
+ def call(route, params)
13
+
14
+ if !params.kind_of?(Hash)
15
+ response = Jetra::Response.new
16
+ response.status = 0
17
+ response.body = {msg: "Jetra::Middleware::Validater: params type miss match. excepted Hash, got #{params.class.to_s}"}
18
+ else
19
+ response = @app.call(route, params)
20
+ if !response.status.kind_of?(Integer)
21
+ response.status = 0
22
+ response.body = {msg: "Jetra::Middleware::Validater: response.status type miss match. excepted Integer, got #{response.status.class.to_s}"}
23
+ else
24
+ if !response.body.kind_of?(Hash)
25
+ response.status = 0
26
+ response.body = {msg: "Jetra::Middleware::Validater: response.body type miss match. excepted Hash, got #{response.body.class.to_s}"}
27
+ end
28
+ end
29
+ end
30
+
31
+ response
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,5 @@
1
+ module Jetra
2
+
3
+ Version = "1.0.1"
4
+
5
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jetra
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jeffrey
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-04-20 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: micro DSL
14
+ email:
15
+ - jeffrey6052@163.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/jetra.rb
21
+ - lib/jetra/adapter/rack.rb
22
+ - lib/jetra/application.rb
23
+ - lib/jetra/base.rb
24
+ - lib/jetra/builder.rb
25
+ - lib/jetra/combiner.rb
26
+ - lib/jetra/middleware/sample.rb
27
+ - lib/jetra/middleware/validater.rb
28
+ - lib/jetra/version.rb
29
+ homepage:
30
+ licenses:
31
+ - MIT
32
+ metadata: {}
33
+ post_install_message:
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ requirements: []
48
+ rubyforge_project:
49
+ rubygems_version: 2.6.8
50
+ signing_key:
51
+ specification_version: 4
52
+ summary: make it easy to write micro service
53
+ test_files: []