actionframework 0.0.7

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.
Files changed (3) hide show
  1. data/bin/afw +49 -0
  2. data/lib/actionframework.rb +329 -0
  3. metadata +98 -0
data/bin/afw ADDED
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optitron'
3
+ require 'fileutils'
4
+ require 'gors'
5
+ require 'json'
6
+
7
+ class GorsCLI < Optitron::CLI
8
+ desc "About ActionFramework"
9
+ def about
10
+ puts "ActionFramework (previously called GORS) 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
+ end
12
+ desc "Create ActionFramework project"
13
+ def new projectname
14
+ puts "Creating project directory and structure"
15
+ Dir.mkdir("#{projectname}")
16
+ Dir.mkdir("#{projectname}/controllers")
17
+ Dir.mkdir("#{projectname}/models")
18
+ Dir.mkdir("#{projectname}/views")
19
+ Dir.mkdir("#{projectname}/config")
20
+ Dir.mkdir("#{projectname}/initializers")
21
+ FileUtils.touch("#{projectname}/views/layout.html.erb")
22
+ FileUtils.touch("#{projectname}/Gemfile")
23
+ File.write("#{projectname}/main.rb","# Example of basic configuration\ngors = Gors::Server.new\n\nngors.autoimport\ngors.start")
24
+ File.write("#{projectname}/controllers/default_controller.rb","class DefaultController < Gors::Controller
25
+ \n def index\n \"<h1>Welcome to ActionFramework</h1><i>Great Opensource Ruby Server</i><p>Gors 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
+ File.write("#{projectname}/routes.json","{\n \"get\": [{\n \"/\": \"DefaultController#index\"\n}]\n}")
27
+ File.write("#{projectname}/config/routes.rb","Gors::Server.current.routes do\n\n get \"/\" => \"DefaultController#index\"\n\nend")
28
+ File.write("#{projectname}/config/settings.rb","Gors::Server.current.settings do |s|\n\nend")
29
+ puts "Done"
30
+ puts "Test ActionFramework by running \"gors s\""
31
+ end
32
+
33
+ desc "Start gors server"
34
+ def s
35
+ Gors::Server.init
36
+ Gors::Server.current.start
37
+ end
38
+
39
+ desc "Start gors console"
40
+ def c
41
+ Gors::Server.init
42
+ puts "Starting Gors IRB"
43
+ require 'irb'
44
+ ARGV.clear
45
+ IRB.start
46
+ end
47
+ end
48
+
49
+ GorsCLI.dispatch
@@ -0,0 +1,329 @@
1
+ require 'rack'
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"])
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
+ #
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 = Request.new
74
+ request.request.params = Rack::Utils.parse_query(env["QUERY_STRING"])
75
+ if(matcheddata != nil)
76
+ request.request.params.merge! (matcheddata)
77
+ end
78
+ request.request.params.default = ""
79
+
80
+ infoctrl = controller.split("#")
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
+
322
+ end
323
+
324
+ at_exit do
325
+ puts "Exiting..."
326
+ if(File.exists? "running.pid")
327
+ File.delete("running.pid")
328
+ end
329
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: actionframework
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.7
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Bram Vandenbogaerde
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-11-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: tilt
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: json
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rack
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: A web framework built on top of Rack, it has the simplicity of sinatra
63
+ and the structure of rails
64
+ email: bram.vandenbogaerde@gmail.com
65
+ executables:
66
+ - afw
67
+ extensions: []
68
+ extra_rdoc_files: []
69
+ files:
70
+ - lib/actionframework.rb
71
+ - bin/afw
72
+ homepage: http://rubygems.org/gems/actionframework
73
+ licenses:
74
+ - MIT
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubyforge_project:
93
+ rubygems_version: 1.8.23
94
+ signing_key:
95
+ specification_version: 3
96
+ summary: A web framework built on top of Rack
97
+ test_files: []
98
+ has_rdoc: