actionframework 0.0.7 → 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/bin/afw +18 -16
- data/lib/actionframework/controller.rb +36 -0
- data/lib/actionframework/rackup.rb +2 -0
- data/lib/actionframework/routes.rb +53 -0
- data/lib/actionframework/settings.rb +12 -0
- data/lib/actionframework.rb +76 -321
- data/lib/actionframework_old.rb +373 -0
- metadata +31 -21
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: f2dfbfdbff057caaa49f475b6181cfe8a8c65a1c
|
|
4
|
+
data.tar.gz: a232de6f77636b5790bd31cb3f06887da70223a3
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 60ca2cf0c2938de702fa57cebaa58bcd4fd4d6e5c5522454337a55bea0ec1f3db7ce60308f674bccc7def60214980d97fe03d6cfd5e21725c7d2c4ebf0de90d3
|
|
7
|
+
data.tar.gz: 4167766a9254097c0b2f8aca143708a9dae10c9b3f01a109b7b955e590ed84f9a112972efc724a72bbeac3ca059cfe62babc1b35caeb41ee77e226ce72bb2b47
|
data/bin/afw
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
require 'optitron'
|
|
3
3
|
require 'fileutils'
|
|
4
|
-
require '
|
|
4
|
+
require 'actionframework'
|
|
5
5
|
require 'json'
|
|
6
6
|
|
|
7
|
-
class
|
|
7
|
+
class ActionFrameworkCLI < Optitron::CLI
|
|
8
8
|
desc "About ActionFramework"
|
|
9
9
|
def about
|
|
10
|
-
puts "ActionFramework (previously called
|
|
10
|
+
puts "ActionFramework (previously called ActionFramework) is a web application framework that tries to be as flexible as sinatra and at the same time have the structure of rails.Enjoy!"
|
|
11
11
|
end
|
|
12
12
|
desc "Create ActionFramework project"
|
|
13
13
|
def new projectname
|
|
@@ -20,30 +20,32 @@ class GorsCLI < Optitron::CLI
|
|
|
20
20
|
Dir.mkdir("#{projectname}/initializers")
|
|
21
21
|
FileUtils.touch("#{projectname}/views/layout.html.erb")
|
|
22
22
|
FileUtils.touch("#{projectname}/Gemfile")
|
|
23
|
-
File.write("#{projectname}/main.rb","# Example of basic configuration\
|
|
24
|
-
File.write("#{projectname}/controllers/default_controller.rb","class DefaultController <
|
|
25
|
-
\n def index\n \"<h1>Welcome to ActionFramework</h1><i>Great Opensource Ruby Server</i><p>
|
|
23
|
+
File.write("#{projectname}/main.rb","# Example of basic configuration\nActionFramework = ActionFramework::Server.new\n\nnActionFramework.autoimport\nActionFramework.start")
|
|
24
|
+
File.write("#{projectname}/controllers/default_controller.rb","class DefaultController < ActionFramework::Controller
|
|
25
|
+
\n def index\n \"<h1>Welcome to ActionFramework</h1><i>Great Opensource Ruby Server</i><p>ActionFramework is loading routes from routes.json but you should write your own main.rb<br/>This is just to gettings started</p>\"\n end\nend");
|
|
26
26
|
File.write("#{projectname}/routes.json","{\n \"get\": [{\n \"/\": \"DefaultController#index\"\n}]\n}")
|
|
27
|
-
File.write("#{projectname}/config/routes.rb","
|
|
28
|
-
File.write("#{projectname}/config/settings.rb","
|
|
27
|
+
File.write("#{projectname}/config/routes.rb","ActionFramework::Server.current.routes do\n\n get \"/\" => \"DefaultController#index\"\n\nend")
|
|
28
|
+
File.write("#{projectname}/config/settings.rb","ActionFramework::Server.current.settings do |s|\n\nend")
|
|
29
|
+
File.write("#{projectname}/Gemfile","source 'https://rubygems.org'\n\ngem 'actionframework'")
|
|
30
|
+
system("cd #{projectname} && bundle install")
|
|
29
31
|
puts "Done"
|
|
30
|
-
puts "
|
|
32
|
+
puts "Run \"afw s\" to run your app"
|
|
31
33
|
end
|
|
32
34
|
|
|
33
|
-
desc "Start
|
|
35
|
+
desc "Start ActionFramework server"
|
|
34
36
|
def s
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
$runningserver = ActionFramework::Server.new
|
|
38
|
+
ActionFramework::Server.current.start
|
|
37
39
|
end
|
|
38
40
|
|
|
39
|
-
desc "Start
|
|
41
|
+
desc "Start ActionFramework console"
|
|
40
42
|
def c
|
|
41
|
-
|
|
42
|
-
puts "Starting
|
|
43
|
+
$runningserver = ActionFramework::Server.new
|
|
44
|
+
puts "Starting ActionFramework IRB"
|
|
43
45
|
require 'irb'
|
|
44
46
|
ARGV.clear
|
|
45
47
|
IRB.start
|
|
46
48
|
end
|
|
47
49
|
end
|
|
48
50
|
|
|
49
|
-
|
|
51
|
+
ActionFrameworkCLI.dispatch
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#######################
|
|
2
|
+
# Licenced under MIT ##
|
|
3
|
+
### © BramVDB.com #####
|
|
4
|
+
#######################
|
|
5
|
+
|
|
6
|
+
module ActionFramework
|
|
7
|
+
class Controller
|
|
8
|
+
def initialize req,res,url
|
|
9
|
+
@req = req
|
|
10
|
+
@res = res
|
|
11
|
+
@url = url
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def request
|
|
15
|
+
@req
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def response
|
|
19
|
+
@res
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def params
|
|
23
|
+
@req.params
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def url
|
|
27
|
+
@url
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def erb template
|
|
31
|
+
renderer = Tilt::ERBTemplate.new("views/layout.html.erb")
|
|
32
|
+
output = renderer.render(self){ Tilt::ERBTemplate.new("views/"+template.to_s+".html.erb").render(self) }
|
|
33
|
+
return output
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#######################
|
|
2
|
+
# Licenced under MIT ##
|
|
3
|
+
### © BramVDB.com #####
|
|
4
|
+
#######################
|
|
5
|
+
|
|
6
|
+
module ActionFramework
|
|
7
|
+
class Routes
|
|
8
|
+
attr_accessor :routes
|
|
9
|
+
def initialize
|
|
10
|
+
@routes = {:get => {}, :post => {}, :update => {}, :delete => {}, :patch => {}}
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def build_regex string
|
|
14
|
+
string = string.gsub("{{","(?<")
|
|
15
|
+
string = string.gsub("}}",">(.*))")
|
|
16
|
+
string.insert(0,"^")
|
|
17
|
+
string = string+"$"
|
|
18
|
+
regex = Regexp.new (string)
|
|
19
|
+
regex
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def get hash
|
|
23
|
+
@routes[:get][build_regex(hash.keys.first.to_s)] = hash[hash.keys.first.to_s]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def post hash
|
|
27
|
+
@routes[:post][build_regex(hash.keys.first.to_s)] = hash[hash.keys.first.to_s]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def update hash
|
|
31
|
+
@routes[:update][build_regex(hash.keys.first.to_s)] = hash[hash.keys.first.to_s]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def delete hash
|
|
35
|
+
@routes[:delete][build_regex(hash.keys.first.to_s)] = hash[hash.keys.first.to_s]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def patch hash
|
|
39
|
+
@routes[:patch][build_regex(hash.keys.first.to_s)] = hash[hash.keys.first.to_s]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def route(path,method)
|
|
43
|
+
@routes[method.downcase.to_sym].each do |regex,controller|
|
|
44
|
+
puts regex
|
|
45
|
+
p regex
|
|
46
|
+
if(matched = path.match(regex))
|
|
47
|
+
return [controller,matched]
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
return nil
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
data/lib/actionframework.rb
CHANGED
|
@@ -1,329 +1,84 @@
|
|
|
1
1
|
require 'rack'
|
|
2
|
-
require 'erb'
|
|
3
2
|
require 'tilt'
|
|
4
3
|
require 'json'
|
|
5
|
-
require '
|
|
4
|
+
require 'erb'
|
|
5
|
+
|
|
6
|
+
require 'actionframework/routes'
|
|
7
|
+
require 'actionframework/controller'
|
|
8
|
+
require 'actionframework/settings'
|
|
6
9
|
|
|
7
10
|
$runningserver = nil
|
|
8
11
|
|
|
9
12
|
module ActionFramework
|
|
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
|
-
ctrl = Object.const_get(infoctrl[0]).new(request)
|
|
82
|
-
|
|
83
|
-
response = ctrl.send(infoctrl[1])
|
|
84
|
-
if(@settings.server != "thin")
|
|
85
|
-
response = [response]
|
|
86
|
-
end
|
|
87
|
-
[ctrl.info.response.status_code,ctrl.info.response.headers,response]
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def start
|
|
91
|
-
if(@settings.errorhandler != nil)
|
|
92
|
-
@errorhandler = Object.const_get(@settings.errorhandler).new
|
|
93
|
-
else
|
|
94
|
-
@errorhandler = ActionFramework::DefaultErrorHandler.new
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
if(@settings.daemon)
|
|
98
|
-
puts "Sending ActionFramework to background"
|
|
99
|
-
system("kill `cat running.pid`")
|
|
100
|
-
Process.daemon true
|
|
101
|
-
File.write("running.pid",Process.pid)
|
|
102
|
-
end
|
|
103
|
-
@logger.log @routesklass.inspect
|
|
104
|
-
Rack::Server.new({:app => self,:server => @settings.server, :Port => @settings.port}).start
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def routes &block
|
|
108
|
-
@routesklass.instance_eval &block
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def settings
|
|
112
|
-
yield(@settings)
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
def autoimport
|
|
116
|
-
Dir.glob("controllers/*").each do |file|
|
|
117
|
-
require './'+file
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
Dir.glob("models/*").each do |file|
|
|
121
|
-
require './'+file
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
require './config/routes'
|
|
125
|
-
require './config/settings'
|
|
126
|
-
|
|
127
|
-
Dir.glob("initializers/*").each do |file|
|
|
128
|
-
require './'+file
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
end
|
|
134
|
-
class Routes
|
|
135
|
-
NAME_PATTERN = /:(\S+)/
|
|
136
|
-
|
|
137
|
-
attr_accessor :routes
|
|
138
|
-
attr_accessor :models
|
|
139
|
-
attr_accessor :posts
|
|
140
|
-
|
|
141
|
-
def initialize logger
|
|
142
|
-
@routes = {}
|
|
143
|
-
@models = {}
|
|
144
|
-
@logger = logger
|
|
145
|
-
@routespost = {}
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def get hash
|
|
149
|
-
@routes[pattern_for(hash.keys.first.to_s)] = hash[hash.keys.first.to_s]
|
|
150
|
-
@logger.log "Adding route GET "+hash.keys.first.to_s
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
def json
|
|
154
|
-
# TODO zorg evoor dat routes ook van routes.json gehaald kunnen worden (structuur zie generator in de CLI)
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
def post hash
|
|
158
|
-
@routespost[hash.keys.first.to_s] = hash[hash.keys.first.to_s]
|
|
159
|
-
@logger.log "Adding route POST "+hash.keys.first.to_s
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
def post
|
|
163
|
-
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
def model hash
|
|
167
|
-
@routes["/api/"+hash.keys.first.to_s] = "ActionFramework::Model#call:"+hash[hash.keys.first.to_s];
|
|
168
|
-
puts "Adding model with path "+hash.keys.first.to_s
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
def routes(path)
|
|
172
|
-
hash = {}
|
|
173
|
-
controller = nil
|
|
174
|
-
@routes.each do |route,controller|
|
|
175
|
-
if(matched = route.match path)
|
|
176
|
-
matched.names.each do |name|
|
|
177
|
-
hash[name] = matched[name]
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
return [controller,hash]
|
|
181
|
-
end
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
# Logic from github.com/alisnic/nyny
|
|
185
|
-
def pattern_for signature
|
|
186
|
-
if(signature.class == Regexp)
|
|
187
|
-
return signature
|
|
188
|
-
end
|
|
189
|
-
build_regex(signature.start_with?('/') ? signature : "/#{signature}")
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
def build_regex signature
|
|
193
|
-
return %r(^#{signature}$) unless signature.include?(':')
|
|
194
|
-
|
|
195
|
-
groups = signature.split('/').map do |part|
|
|
196
|
-
next part if part.empty?
|
|
197
|
-
next part unless part.start_with? ':'
|
|
198
|
-
name = NAME_PATTERN.match(part)[1]
|
|
199
|
-
%Q{(?<#{name}>\\S+)}
|
|
200
|
-
end.select {|s| !s.empty? }.join('\/')
|
|
201
|
-
|
|
202
|
-
%r(^\/#{groups}$)
|
|
203
|
-
end
|
|
204
|
-
end
|
|
205
|
-
class Controller
|
|
206
|
-
attr_accessor :info
|
|
207
|
-
|
|
208
|
-
def initialize(context)
|
|
209
|
-
@info = context
|
|
210
|
-
if(self.respond_to? "before")
|
|
211
|
-
self.before
|
|
212
|
-
end
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
def erb template
|
|
216
|
-
renderer = Tilt::ERBTemplate.new("views/layout.html.erb")
|
|
217
|
-
output = renderer.render(self){ Tilt::ERBTemplate.new("views/"+template.to_s+".html.erb").render(self) }
|
|
218
|
-
return output
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
def params
|
|
222
|
-
@info.request.params
|
|
223
|
-
end
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
class Request
|
|
227
|
-
attr_accessor :response
|
|
228
|
-
attr_accessor :request
|
|
229
|
-
|
|
230
|
-
def initialize
|
|
231
|
-
@response = OpenStruct.new ({:headers => {}, :status_code => "200"})
|
|
232
|
-
@request = OpenStruct.new ({:ip => "",:user_agent => "",:headers => {},:params => {}})
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
-
def info
|
|
236
|
-
return @info
|
|
237
|
-
end
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
class Model
|
|
241
|
-
def initialize req
|
|
242
|
-
@req = req
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
def call modelname
|
|
246
|
-
case @req.request_method
|
|
247
|
-
when "GET"
|
|
248
|
-
if(Object.const_get(modelname.capitalize).respond_to? "append")
|
|
249
|
-
model = Object.const_get(modelname.capitalize).all.send(Object.const_get(modelname.capitalize).append)
|
|
250
|
-
else
|
|
251
|
-
model = Object.const_get(modelname.capitalize).all
|
|
252
|
-
end
|
|
253
|
-
model.to_json
|
|
254
|
-
when "POST"
|
|
255
|
-
if(Object.const_get(modelname.capitalize).respond_to? "append")
|
|
256
|
-
model = Object.const_get(modelname.capitalize).create(JSON.parse(@req.body.string))
|
|
257
|
-
else
|
|
258
|
-
model = Object.const_get(modelname.capitalize).create(JSON.parse(@req.body.string))
|
|
259
|
-
end
|
|
260
|
-
model.to_json
|
|
261
|
-
else
|
|
262
|
-
|
|
263
|
-
end
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
class Settings
|
|
269
|
-
attr_accessor :port
|
|
270
|
-
attr_accessor :server
|
|
271
|
-
attr_accessor :verbose
|
|
272
|
-
attr_accessor :daemon
|
|
273
|
-
attr_accessor :errorhandler
|
|
274
|
-
|
|
275
|
-
def initialize
|
|
276
|
-
@port = 8080
|
|
277
|
-
@server = "puma"
|
|
278
|
-
@verbose = true
|
|
279
|
-
@daemon = false
|
|
280
|
-
@errorhandler = nil
|
|
281
|
-
end
|
|
282
|
-
end
|
|
283
|
-
class Logger
|
|
284
|
-
|
|
285
|
-
def initialize(settings)
|
|
286
|
-
@settings = settings
|
|
287
|
-
end
|
|
288
|
-
|
|
289
|
-
def log msg
|
|
290
|
-
if(@settings.daemon)
|
|
291
|
-
return
|
|
292
|
-
end
|
|
293
|
-
if(@settings.verbose)
|
|
294
|
-
puts msg
|
|
295
|
-
end
|
|
296
|
-
end
|
|
297
|
-
|
|
298
|
-
end
|
|
299
|
-
|
|
300
|
-
class ErrorHelper
|
|
301
|
-
def call(errortype)
|
|
302
|
-
if(self.respond_to? "error_"+errortype)
|
|
303
|
-
[errortype, {},[self.send("error_"+errortype)]]
|
|
304
|
-
else
|
|
305
|
-
ActionFramework::DefaultErrorHandler.new.send("error_"+errortype)
|
|
306
|
-
end
|
|
307
|
-
end
|
|
308
|
-
end
|
|
309
|
-
|
|
310
|
-
class DefaultErrorHandler < ActionFramework::ErrorHelper
|
|
311
|
-
def error_404
|
|
312
|
-
"<h1>404 Not Found</h1>"
|
|
313
|
-
end
|
|
314
|
-
def error_500
|
|
315
|
-
"<h1>500 Internal server error</h1>"
|
|
316
|
-
end
|
|
317
|
-
def error_403
|
|
318
|
-
"<h1>403 Forbidden</h1>"
|
|
319
|
-
end
|
|
320
|
-
end
|
|
321
|
-
|
|
13
|
+
class Server
|
|
14
|
+
def initialize
|
|
15
|
+
require 'bundler'
|
|
16
|
+
Bundler.require(:default)
|
|
17
|
+
|
|
18
|
+
@routesklass = ActionFramework::Routes.new
|
|
19
|
+
@settings = ActionFramework::Settings.new
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.current
|
|
23
|
+
if($runningserver.nil?)
|
|
24
|
+
$runningserver = ActionFramework::Server.new
|
|
25
|
+
$runningserver.autoimport
|
|
26
|
+
$runningserver
|
|
27
|
+
else
|
|
28
|
+
$runningserver
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.current=(runningserver)
|
|
33
|
+
$runningserver = runningserver
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def autoimport
|
|
37
|
+
Dir.glob("controllers/*").each do |file|
|
|
38
|
+
require './'+file
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
Dir.glob("models/*").each do |file|
|
|
42
|
+
require './'+file
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
require './config/routes'
|
|
46
|
+
require './config/settings'
|
|
47
|
+
|
|
48
|
+
Dir.glob("initializers/*").each do |file|
|
|
49
|
+
require './'+file
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def call env
|
|
55
|
+
req = Rack::Request.new(env)
|
|
56
|
+
res = Rack::Response.new
|
|
57
|
+
|
|
58
|
+
controllerinfo = @routesklass.route(req.path,req.request_method)
|
|
59
|
+
if(controllerinfo == nil)
|
|
60
|
+
res.write "<h1>404 Not found</h1>"
|
|
61
|
+
return res.finish
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
controller = controllerinfo[0]
|
|
65
|
+
matcheddata = controllerinfo[1]
|
|
66
|
+
|
|
67
|
+
control = controller.split("#")
|
|
68
|
+
result = Object.const_get(control[0]).new(req,res,matcheddata).send(control[1])
|
|
69
|
+
res.body = [result]
|
|
70
|
+
res.finish
|
|
71
|
+
end
|
|
72
|
+
def routes &block
|
|
73
|
+
@routesklass.instance_eval &block
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def settings
|
|
77
|
+
yield @settings
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def start
|
|
81
|
+
Rack::Server.new({:app => self,:server => @settings.server, :Port => @settings.port}).start
|
|
82
|
+
end
|
|
83
|
+
end
|
|
322
84
|
end
|
|
323
|
-
|
|
324
|
-
at_exit do
|
|
325
|
-
puts "Exiting..."
|
|
326
|
-
if(File.exists? "running.pid")
|
|
327
|
-
File.delete("running.pid")
|
|
328
|
-
end
|
|
329
|
-
end
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
require 'rack.rb'
|
|
2
|
+
require 'erb'
|
|
3
|
+
require 'tilt'
|
|
4
|
+
require 'json'
|
|
5
|
+
require 'ostruct'
|
|
6
|
+
|
|
7
|
+
$runningserver = nil
|
|
8
|
+
|
|
9
|
+
module ActionFramework
|
|
10
|
+
class Server
|
|
11
|
+
def self.init
|
|
12
|
+
require 'bundler'
|
|
13
|
+
Bundler.require(:default)
|
|
14
|
+
ActionFramework::Server.current = ActionFramework::Server.new
|
|
15
|
+
ActionFramework::Server.current.autoimport
|
|
16
|
+
end
|
|
17
|
+
def initialize
|
|
18
|
+
@settings = Settings.new
|
|
19
|
+
@logger = Logger.new(@settings)
|
|
20
|
+
@routesklass = Routes.new(@logger)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.current
|
|
24
|
+
if($runningserver.nil?)
|
|
25
|
+
ActionFramework::Server.init
|
|
26
|
+
$runningserver
|
|
27
|
+
else
|
|
28
|
+
$runningserver
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.current=(runningserver)
|
|
33
|
+
$runningserver = runningserver
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def run
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def call env
|
|
41
|
+
if(@settings.errorhandler != nil)
|
|
42
|
+
@errorhandler = Object.const_get(@settings.errorhandler).new
|
|
43
|
+
else
|
|
44
|
+
@errorhandler = ActionFramework::DefaultErrorHandler.new
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
routesinfo = @routesklass.routes(env["REQUEST_PATH"],env["REQUEST_METHOD"].downcase)
|
|
48
|
+
controller = routesinfo[0]
|
|
49
|
+
@logger.log controller.inspect
|
|
50
|
+
matcheddata = routesinfo[1]
|
|
51
|
+
|
|
52
|
+
if(controller == nil)
|
|
53
|
+
if(@settings.server != "thin")
|
|
54
|
+
response = ["<h1>404 Not Found</h1>"]
|
|
55
|
+
else
|
|
56
|
+
response = "<h1>404 Not Found</h1>"
|
|
57
|
+
end
|
|
58
|
+
return @errorhandler.call "404"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Logic for models: in development
|
|
62
|
+
if(controller.include? "ActionFramework::")
|
|
63
|
+
ctrl = controller.split("#")
|
|
64
|
+
params = ctrl[1].split(":")
|
|
65
|
+
|
|
66
|
+
req = Rack::Request.new(env)
|
|
67
|
+
|
|
68
|
+
data = Model.new(req).call(params[1])
|
|
69
|
+
return ["200",{"Content-type" => "application/json"},[data]]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Call the Controller
|
|
73
|
+
request = Rack::Request.new(env)
|
|
74
|
+
request.request.params = Rack::Utils.parse_query(env["QUERY_STRING"])
|
|
75
|
+
Rack::Utils.parse_query(env["rack.input"].read).each do |key,value|
|
|
76
|
+
request.request.params[key] = value
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
if(matcheddata != nil)
|
|
80
|
+
request.request.params.merge! (matcheddata)
|
|
81
|
+
end
|
|
82
|
+
request.request.params.default = ""
|
|
83
|
+
|
|
84
|
+
infoctrl = controller.split("#")
|
|
85
|
+
ctrl = Object.const_get(infoctrl[0]).new(request)
|
|
86
|
+
|
|
87
|
+
response = ctrl.send(infoctrl[1])
|
|
88
|
+
if(@settings.server != "thin")
|
|
89
|
+
response = [response]
|
|
90
|
+
end
|
|
91
|
+
[ctrl.info.response.status_code,ctrl.info.response.headers,response]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def start
|
|
95
|
+
if(@settings.errorhandler != nil)
|
|
96
|
+
@errorhandler = Object.const_get(@settings.errorhandler).new
|
|
97
|
+
else
|
|
98
|
+
@errorhandler = ActionFramework::DefaultErrorHandler.new
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
if(@settings.daemon)
|
|
102
|
+
puts "Sending ActionFramework to background"
|
|
103
|
+
system("kill `cat running.pid`")
|
|
104
|
+
Process.daemon true
|
|
105
|
+
File.write("running.pid",Process.pid)
|
|
106
|
+
end
|
|
107
|
+
@logger.log @routesklass.inspect
|
|
108
|
+
Rack::Server.new({:app => self,:server => @settings.server, :Port => @settings.port}).start
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def routes &block
|
|
112
|
+
@routesklass.instance_eval &block
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def settings
|
|
116
|
+
yield(@settings)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def autoimport
|
|
120
|
+
Dir.glob("controllers/*").each do |file|
|
|
121
|
+
require './'+file
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
Dir.glob("models/*").each do |file|
|
|
125
|
+
require './'+file
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
require './config/routes'
|
|
129
|
+
require './config/settings'
|
|
130
|
+
|
|
131
|
+
Dir.glob("initializers/*").each do |file|
|
|
132
|
+
require './'+file
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
end
|
|
138
|
+
class Routes
|
|
139
|
+
NAME_PATTERN = /:(\S+)/
|
|
140
|
+
|
|
141
|
+
attr_accessor :routes
|
|
142
|
+
attr_accessor :models
|
|
143
|
+
attr_accessor :posts
|
|
144
|
+
|
|
145
|
+
def initialize logger
|
|
146
|
+
@routes = {:get => {}, :post => {},:update => {}, :delete => {},:patch => {}}
|
|
147
|
+
@models = {}
|
|
148
|
+
@logger = logger
|
|
149
|
+
@routespost = {}
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def get hash
|
|
153
|
+
@routes[:get][pattern_for(hash.keys.first.to_s)] = hash[hash.keys.first.to_s]
|
|
154
|
+
@logger.log "Adding route GET "+hash.keys.first.to_s
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def post hash
|
|
158
|
+
@routes[:post][hash.keys.first.to_s] = hash[hash.keys.first.to_s]
|
|
159
|
+
@logger.log "Adding route POST "+hash.keys.first.to_s
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def update hash
|
|
163
|
+
@routes[:update][hash.keys.first.to_s] = hash[hash.keys.first.to_s]
|
|
164
|
+
@logger.log "Adding route UPDATE "+hash.keys.first.to_s
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def delete hash
|
|
168
|
+
@routes[:delete][hash.keys.first.to_s] = hash[hash.keys.first.to_s]
|
|
169
|
+
@logger.log "Adding route DELETE "+hash.keys.first.to_s
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def patch hash
|
|
173
|
+
@routes[:patch][hash.keys.first.to_s] = hash[hash.keys.first.to_s]
|
|
174
|
+
@logger.log "Adding route PATCH "+hash.keys.first.to_s
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def model hash
|
|
178
|
+
# In development
|
|
179
|
+
@routes["/api/"+hash.keys.first.to_s] = "ActionFramework::Model#call:"+hash[hash.keys.first.to_s];
|
|
180
|
+
puts "Adding model with path "+hash.keys.first.to_s
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def routes(path,method)
|
|
184
|
+
hash = {}
|
|
185
|
+
controller = nil
|
|
186
|
+
@routes[method.to_sym].each do |route,controller|
|
|
187
|
+
if(matched = route.match path)
|
|
188
|
+
matched.names.each do |name|
|
|
189
|
+
hash[name] = matched[name]
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
return [controller,hash]
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
# Logic from github.com/alisnic/nyny
|
|
197
|
+
def pattern_for signature
|
|
198
|
+
if(signature.class == Regexp)
|
|
199
|
+
return signature
|
|
200
|
+
end
|
|
201
|
+
build_regex(signature.start_with?('/') ? signature : "/#{signature}")
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def build_regex signature
|
|
205
|
+
return %r(^#{signature}$) unless signature.include?(':')
|
|
206
|
+
|
|
207
|
+
groups = signature.split('/').map do |part|
|
|
208
|
+
next part if part.empty?
|
|
209
|
+
next part unless part.start_with? ':'
|
|
210
|
+
name = NAME_PATTERN.match(part)[1]
|
|
211
|
+
%Q{(?<#{name}>\\S+)}
|
|
212
|
+
end.select {|s| !s.empty? }.join('\/')
|
|
213
|
+
|
|
214
|
+
%r(^\/#{groups}$)
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
class Controller
|
|
218
|
+
attr_accessor :info
|
|
219
|
+
|
|
220
|
+
def initialize(context)
|
|
221
|
+
@info = context
|
|
222
|
+
if(self.respond_to? "before")
|
|
223
|
+
self.before
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def erb template
|
|
228
|
+
renderer = Tilt::ERBTemplate.new("views/layout.html.erb")
|
|
229
|
+
output = renderer.render(self){ Tilt::ERBTemplate.new("views/"+template.to_s+".html.erb").render(self) }
|
|
230
|
+
return output
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def params
|
|
234
|
+
@info.req.params
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def request
|
|
238
|
+
@info.req
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
class Request
|
|
244
|
+
attr_accessor :response
|
|
245
|
+
attr_accessor :request
|
|
246
|
+
attr_accessor :req
|
|
247
|
+
|
|
248
|
+
def initialize(env)
|
|
249
|
+
@response = OpenStruct.new ({:headers => {}, :status_code => "200"})
|
|
250
|
+
@request = OpenStruct.new ({:ip => "",:user_agent => "",:headers => {},:params => {}})
|
|
251
|
+
@req = Rack::Request.new(env)
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def info
|
|
255
|
+
return @info
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
class Model
|
|
260
|
+
def initialize req
|
|
261
|
+
@req = req
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def call modelname
|
|
265
|
+
case @req.request_method
|
|
266
|
+
when "GET"
|
|
267
|
+
if(Object.const_get(modelname.capitalize).respond_to? "append")
|
|
268
|
+
model = Object.const_get(modelname.capitalize).all.send(Object.const_get(modelname.capitalize).append)
|
|
269
|
+
else
|
|
270
|
+
model = Object.const_get(modelname.capitalize).all
|
|
271
|
+
end
|
|
272
|
+
model.to_json
|
|
273
|
+
when "POST"
|
|
274
|
+
if(Object.const_get(modelname.capitalize).respond_to? "append")
|
|
275
|
+
model = Object.const_get(modelname.capitalize).create(JSON.parse(@req.body.string))
|
|
276
|
+
else
|
|
277
|
+
model = Object.const_get(modelname.capitalize).create(JSON.parse(@req.body.string))
|
|
278
|
+
end
|
|
279
|
+
model.to_json
|
|
280
|
+
else
|
|
281
|
+
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
class Settings
|
|
288
|
+
attr_accessor :port
|
|
289
|
+
attr_accessor :server
|
|
290
|
+
attr_accessor :verbose
|
|
291
|
+
attr_accessor :daemon
|
|
292
|
+
attr_accessor :errorhandler
|
|
293
|
+
|
|
294
|
+
def initialize
|
|
295
|
+
@port = 8080
|
|
296
|
+
@server = "puma"
|
|
297
|
+
@verbose = true
|
|
298
|
+
@daemon = false
|
|
299
|
+
@errorhandler = nil
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
class Logger
|
|
303
|
+
|
|
304
|
+
def initialize(settings)
|
|
305
|
+
@settings = settings
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def log msg
|
|
309
|
+
if(@settings.daemon)
|
|
310
|
+
return
|
|
311
|
+
end
|
|
312
|
+
if(@settings.verbose)
|
|
313
|
+
puts msg
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
class ErrorHelper
|
|
320
|
+
def call(errortype)
|
|
321
|
+
if(self.respond_to? "error_"+errortype)
|
|
322
|
+
puts "Yes!!!!!"
|
|
323
|
+
[errortype, {},[self.send("error_"+errortype)]]
|
|
324
|
+
else
|
|
325
|
+
[errortype, {}, [ActionFramework::DefaultErrorHandler.new.send("error_"+errortype)]]
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
def erb template
|
|
330
|
+
renderer = Tilt::ERBTemplate.new("views/layout.html.erb")
|
|
331
|
+
output = renderer.render(self){ Tilt::ERBTemplate.new("views/"+template.to_s+".html.erb").render(self) }
|
|
332
|
+
return output
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
class DefaultErrorHandler < ActionFramework::ErrorHelper
|
|
338
|
+
def error_404
|
|
339
|
+
"<h1>404 Not Found</h1>"
|
|
340
|
+
end
|
|
341
|
+
def error_500
|
|
342
|
+
"<h1>500 Internal server error</h1>"
|
|
343
|
+
end
|
|
344
|
+
def error_403
|
|
345
|
+
"<h1>403 Forbidden</h1>"
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
at_exit do
|
|
351
|
+
puts "Exiting..."
|
|
352
|
+
if(File.exists? "running.pid")
|
|
353
|
+
File.delete("running.pid")
|
|
354
|
+
end
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
########## IMPORTANT LOGIC SOON TO BE INTEGRATED ######
|
|
359
|
+
string = "/{{appname}}/{{userid}}"
|
|
360
|
+
|
|
361
|
+
string = string.gsub("{{","(?<")
|
|
362
|
+
string = string.gsub("}}",">(.*))")
|
|
363
|
+
string.insert(0,"^")
|
|
364
|
+
string = string+"$"
|
|
365
|
+
puts string
|
|
366
|
+
regex = Regexp.new (string)
|
|
367
|
+
|
|
368
|
+
puts regex
|
|
369
|
+
|
|
370
|
+
if(matched = regex.match "/testapp/1")
|
|
371
|
+
puts "matched"
|
|
372
|
+
p matched
|
|
373
|
+
end
|
metadata
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: actionframework
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
5
|
-
prerelease:
|
|
4
|
+
version: 0.1.0
|
|
6
5
|
platform: ruby
|
|
7
6
|
authors:
|
|
8
7
|
- Bram Vandenbogaerde
|
|
@@ -14,49 +13,57 @@ dependencies:
|
|
|
14
13
|
- !ruby/object:Gem::Dependency
|
|
15
14
|
name: tilt
|
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
|
17
|
-
none: false
|
|
18
16
|
requirements:
|
|
19
|
-
- -
|
|
17
|
+
- - '>='
|
|
20
18
|
- !ruby/object:Gem::Version
|
|
21
19
|
version: '0'
|
|
22
20
|
type: :runtime
|
|
23
21
|
prerelease: false
|
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
-
none: false
|
|
26
23
|
requirements:
|
|
27
|
-
- -
|
|
24
|
+
- - '>='
|
|
28
25
|
- !ruby/object:Gem::Version
|
|
29
26
|
version: '0'
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
|
31
28
|
name: json
|
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
|
33
|
-
none: false
|
|
34
30
|
requirements:
|
|
35
|
-
- -
|
|
31
|
+
- - '>='
|
|
36
32
|
- !ruby/object:Gem::Version
|
|
37
33
|
version: '0'
|
|
38
34
|
type: :runtime
|
|
39
35
|
prerelease: false
|
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
41
|
-
none: false
|
|
42
37
|
requirements:
|
|
43
|
-
- -
|
|
38
|
+
- - '>='
|
|
44
39
|
- !ruby/object:Gem::Version
|
|
45
40
|
version: '0'
|
|
46
41
|
- !ruby/object:Gem::Dependency
|
|
47
42
|
name: rack
|
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
|
49
|
-
none: false
|
|
50
44
|
requirements:
|
|
51
|
-
- -
|
|
45
|
+
- - '>='
|
|
52
46
|
- !ruby/object:Gem::Version
|
|
53
47
|
version: '0'
|
|
54
48
|
type: :runtime
|
|
55
49
|
prerelease: false
|
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
-
none: false
|
|
58
51
|
requirements:
|
|
59
|
-
- -
|
|
52
|
+
- - '>='
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: optitron
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - '>='
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - '>='
|
|
60
67
|
- !ruby/object:Gem::Version
|
|
61
68
|
version: '0'
|
|
62
69
|
description: A web framework built on top of Rack, it has the simplicity of sinatra
|
|
@@ -67,32 +74,35 @@ executables:
|
|
|
67
74
|
extensions: []
|
|
68
75
|
extra_rdoc_files: []
|
|
69
76
|
files:
|
|
77
|
+
- lib/actionframework/controller.rb
|
|
78
|
+
- lib/actionframework/rackup.rb
|
|
79
|
+
- lib/actionframework/routes.rb
|
|
80
|
+
- lib/actionframework/settings.rb
|
|
70
81
|
- lib/actionframework.rb
|
|
82
|
+
- lib/actionframework_old.rb
|
|
71
83
|
- bin/afw
|
|
72
84
|
homepage: http://rubygems.org/gems/actionframework
|
|
73
85
|
licenses:
|
|
74
86
|
- MIT
|
|
87
|
+
metadata: {}
|
|
75
88
|
post_install_message:
|
|
76
89
|
rdoc_options: []
|
|
77
90
|
require_paths:
|
|
78
91
|
- lib
|
|
79
92
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
80
|
-
none: false
|
|
81
93
|
requirements:
|
|
82
|
-
- -
|
|
94
|
+
- - '>='
|
|
83
95
|
- !ruby/object:Gem::Version
|
|
84
96
|
version: '0'
|
|
85
97
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
86
|
-
none: false
|
|
87
98
|
requirements:
|
|
88
|
-
- -
|
|
99
|
+
- - '>='
|
|
89
100
|
- !ruby/object:Gem::Version
|
|
90
101
|
version: '0'
|
|
91
102
|
requirements: []
|
|
92
103
|
rubyforge_project:
|
|
93
|
-
rubygems_version:
|
|
104
|
+
rubygems_version: 2.0.3
|
|
94
105
|
signing_key:
|
|
95
|
-
specification_version:
|
|
106
|
+
specification_version: 4
|
|
96
107
|
summary: A web framework built on top of Rack
|
|
97
108
|
test_files: []
|
|
98
|
-
has_rdoc:
|