grippy-doozer 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.
- data/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +57 -0
- data/Rakefile +59 -0
- data/VERSION +1 -0
- data/bin/doozer +8 -0
- data/doozer.gemspec +114 -0
- data/lib/doozer/README.rb +40 -0
- data/lib/doozer/active_support/array.rb +14 -0
- data/lib/doozer/active_support/class.rb +221 -0
- data/lib/doozer/active_support/date_time.rb +23 -0
- data/lib/doozer/active_support/object.rb +43 -0
- data/lib/doozer/active_support/time.rb +32 -0
- data/lib/doozer/app.rb +265 -0
- data/lib/doozer/configs.rb +131 -0
- data/lib/doozer/controller.rb +335 -0
- data/lib/doozer/extend.rb +10 -0
- data/lib/doozer/initializer.rb +95 -0
- data/lib/doozer/lib.rb +32 -0
- data/lib/doozer/logger.rb +11 -0
- data/lib/doozer/orm/active_record.rb +19 -0
- data/lib/doozer/orm/data_mapper.rb +19 -0
- data/lib/doozer/orm/sequel.rb +18 -0
- data/lib/doozer/partial.rb +99 -0
- data/lib/doozer/plugins/paginate/init.rb +2 -0
- data/lib/doozer/plugins/paginate/lib/paginate/collection.rb +60 -0
- data/lib/doozer/plugins/paginate/lib/paginate/finder.rb +116 -0
- data/lib/doozer/plugins/paginate/lib/paginate/view_helpers.rb +37 -0
- data/lib/doozer/plugins/paginate/lib/paginate.rb +32 -0
- data/lib/doozer/rackup/server.ru +37 -0
- data/lib/doozer/rackup/test.rb +19 -0
- data/lib/doozer/redirect.rb +12 -0
- data/lib/doozer/route.rb +264 -0
- data/lib/doozer/scripts/cluster.rb +132 -0
- data/lib/doozer/scripts/migrate.rb +108 -0
- data/lib/doozer/scripts/task.rb +60 -0
- data/lib/doozer/scripts/test.rb +23 -0
- data/lib/doozer/version.rb +8 -0
- data/lib/doozer/view_helpers.rb +163 -0
- data/lib/doozer/watcher.rb +375 -0
- data/lib/doozer.rb +30 -0
- data/lib/generator/generator.rb +547 -0
- data/templates/skeleton/Rakefile +3 -0
- data/templates/skeleton/app/controllers/application_controller.rb +2 -0
- data/templates/skeleton/app/controllers/index_controller.rb +7 -0
- data/templates/skeleton/app/helpers/application_helper.rb +17 -0
- data/templates/skeleton/app/views/global/_header.html.erb +7 -0
- data/templates/skeleton/app/views/global/_navigation.html.erb +6 -0
- data/templates/skeleton/app/views/index/index.html.erb +108 -0
- data/templates/skeleton/app/views/layouts/default.html.erb +23 -0
- data/templates/skeleton/config/app.yml +31 -0
- data/templates/skeleton/config/database.yml +25 -0
- data/templates/skeleton/config/environment.rb +13 -0
- data/templates/skeleton/config/rack.rb +30 -0
- data/templates/skeleton/config/routes.rb +69 -0
- data/templates/skeleton/script/cluster +5 -0
- data/templates/skeleton/script/migrate +5 -0
- data/templates/skeleton/script/task +5 -0
- data/templates/skeleton/script/test +4 -0
- data/templates/skeleton/static/404.html +16 -0
- data/templates/skeleton/static/500.html +16 -0
- data/templates/skeleton/static/css/style.css +32 -0
- data/templates/skeleton/static/favicon.ico +0 -0
- data/templates/skeleton/static/js/application.js +1 -0
- data/templates/skeleton/static/js/jquery-1.3.min.js +19 -0
- data/templates/skeleton/static/robots.txt +5 -0
- data/templates/skeleton/test/fixtures/setup.rb +6 -0
- data/templates/skeleton/test/setup.rb +33 -0
- data/test/doozer_test.rb +7 -0
- data/test/test_helper.rb +10 -0
- metadata +126 -0
data/lib/doozer/app.rb
ADDED
@@ -0,0 +1,265 @@
|
|
1
|
+
module Doozer
|
2
|
+
class App
|
3
|
+
APP_PATH = Dir.pwd
|
4
|
+
include Doozer::Util::Logger
|
5
|
+
attr_accessor :options
|
6
|
+
|
7
|
+
def initialize(args={})
|
8
|
+
@options=args
|
9
|
+
|
10
|
+
# load routes
|
11
|
+
load_routes
|
12
|
+
|
13
|
+
# load the application coontrollers, views, and helpers
|
14
|
+
load_files
|
15
|
+
|
16
|
+
# load models
|
17
|
+
load_models
|
18
|
+
|
19
|
+
# attach the file watcher for the mvc/lib/etc in development mode
|
20
|
+
require 'doozer/watcher'; load_watcher if Doozer::Configs.rack_env != :deployment
|
21
|
+
|
22
|
+
p "Doozer racked up..."
|
23
|
+
end
|
24
|
+
|
25
|
+
# This method is called along the rackup chain and maps the request path to the route, controller, and view for the format type.
|
26
|
+
def call(env)
|
27
|
+
# p env.inspect
|
28
|
+
# [200, {"Content-Type" => "text/html"}, "DOH!!!"]
|
29
|
+
path = env["PATH_INFO"]
|
30
|
+
# match env.path_info against the route compile
|
31
|
+
#p env.inspect
|
32
|
+
route = Doozer::Routing::Routes::match(path)
|
33
|
+
# p "path: #{path}"
|
34
|
+
# p "route: #{route.inspect}"
|
35
|
+
if not route.nil?
|
36
|
+
if route.app.nil?
|
37
|
+
extra_params = route.extra_params(path)
|
38
|
+
controller_klass = handler(route.controller.to_sym)
|
39
|
+
controller = controller_klass.new({:env=>env, :route=>route, :extra_params=>extra_params, :port=>@options[:Port]})
|
40
|
+
|
41
|
+
# call after_initialize test for excludes
|
42
|
+
#execution_time('controller.after_initialize',:start)
|
43
|
+
controller.after_initialize if not controller_klass.after_initialize_exclude.include?(route.action.to_sym)
|
44
|
+
#execution_time(nil, :end)
|
45
|
+
|
46
|
+
begin
|
47
|
+
|
48
|
+
# call before_filter test for excludes
|
49
|
+
#execution_time('controller.before_filter',:start)
|
50
|
+
controller.before_filter if not controller_klass.before_filter_exclude.include?(route.action.to_sym)
|
51
|
+
#execution_time(nil,:end)
|
52
|
+
|
53
|
+
# call the action method
|
54
|
+
#execution_time('controller.method(route.action).call',:start)
|
55
|
+
controller.method(route.action).call()
|
56
|
+
#execution_time(nil,:end)
|
57
|
+
|
58
|
+
# call after_filter test for excludes
|
59
|
+
#execution_time('controller.after_filter',:start)
|
60
|
+
controller.after_filter if not controller_klass.after_filter_exclude.include?(route.action.to_sym)
|
61
|
+
#execution_time(nil, :end)
|
62
|
+
|
63
|
+
# render controller...
|
64
|
+
#execution_time('controller.render_result',:start)
|
65
|
+
# r = Rack::Response.new(controller.render_controller(view, layout), route.status, {"Content-Type" => route.content_type})
|
66
|
+
r = Rack::Response.new(controller.render_result, route.status, {"Content-Type" => route.content_type})
|
67
|
+
#execution_time(nil,:end)
|
68
|
+
r.set_cookie('flash',{:value=>nil, :path=>'/'})
|
69
|
+
r.set_cookie('session',{:value=>controller.session_to_cookie(), :path=>'/'})
|
70
|
+
controller = nil
|
71
|
+
return r.to_a
|
72
|
+
|
73
|
+
rescue Doozer::Redirect => redirect
|
74
|
+
# set the status to the one defined in the route which type of redirect do we need to handle?
|
75
|
+
status = (route.status==301) ? 301 : 302
|
76
|
+
# check to make sure the status wasn't manually changed in the controller
|
77
|
+
status = redirect.status if not redirect.status.nil?
|
78
|
+
|
79
|
+
r = Rack::Response.new("redirect...", status, {"Content-Type" => "text/html", "Location"=>redirect.url})
|
80
|
+
# if we get a redirect we need to do something with the flash messages...
|
81
|
+
r.set_cookie('flash',{:value=>controller.flash_to_cookie(), :path=>'/'}) # might need to set the domain from config app_name value
|
82
|
+
r.set_cookie('session',{:value=>controller.session_to_cookie(), :path=>'/'})
|
83
|
+
return r.to_a
|
84
|
+
rescue => e
|
85
|
+
if Doozer::Configs.rack_env == :deployment
|
86
|
+
logger.error("RuntimeError: #{e.to_s}")
|
87
|
+
for line in e.backtrace
|
88
|
+
logger.error(" #{line}")
|
89
|
+
end
|
90
|
+
logger.error("Printing env variables:")
|
91
|
+
logger.error(env.inspect)
|
92
|
+
return [500, {"Content-Type" => "text/html"}, @@errors[500]]
|
93
|
+
else
|
94
|
+
raise e
|
95
|
+
end
|
96
|
+
end
|
97
|
+
else
|
98
|
+
return route.app.call(env)
|
99
|
+
end
|
100
|
+
else
|
101
|
+
return [404, {"Content-Type" => "text/html"}, @@errors[404]]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def execution_time(name = nil, point = :start)
|
106
|
+
if Doozer::Configs.rack_env == :development
|
107
|
+
@execution_time_name = name if name
|
108
|
+
@execution_time_start = Time.now().to_f if point == :start
|
109
|
+
@execution_time_end = Time.now().to_f if point == :end
|
110
|
+
logger.info("Excecution Time: #{@execution_time_name}: #{("%0.2f" % ( (@execution_time_end - @execution_time_start) * 1000).to_f)}ms") if point == :end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def load_files
|
115
|
+
p "Caching files..."
|
116
|
+
@@controllers = {}
|
117
|
+
@@layouts={}
|
118
|
+
@@views={}
|
119
|
+
@@errors={}
|
120
|
+
|
121
|
+
# require helper files and include into Doozer::Partial
|
122
|
+
helper_files = Dir.glob(File.join(APP_PATH,'/app/helpers/*_helper.rb'))
|
123
|
+
helper_files.each {|f|
|
124
|
+
require f
|
125
|
+
key = f.split("helpers/")[1].gsub(/.rb/,'')
|
126
|
+
Doozer::Partial.include_view_helper(key)
|
127
|
+
}
|
128
|
+
|
129
|
+
# cache contoller classes
|
130
|
+
controller_files = Dir.glob(File.join(APP_PATH,'/app/controllers/*_controller.rb'))
|
131
|
+
# we need to load the application_controller first since this might not be the first in the list...
|
132
|
+
if controller_files.length > 0
|
133
|
+
i=0
|
134
|
+
for f in controller_files
|
135
|
+
break if i==0 and f.index('application_controller.rb')
|
136
|
+
if f.index('application_controller.rb')
|
137
|
+
controller_files.insert(0, controller_files.delete(f))
|
138
|
+
break
|
139
|
+
end
|
140
|
+
i+=1
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
controller_files.each { |f|
|
145
|
+
require f
|
146
|
+
key = f.split("controllers/")[1].split("_controller.rb")[0]
|
147
|
+
if key.index("_")
|
148
|
+
value = key.split('_').each{ | k | k.capitalize! }.join('')
|
149
|
+
else
|
150
|
+
value = key.capitalize
|
151
|
+
end
|
152
|
+
klass_name = "#{value}Controller"
|
153
|
+
@@controllers[key.to_sym] = klass_name
|
154
|
+
# p "cache controller: #{key.to_sym}"
|
155
|
+
|
156
|
+
# importing view helpers into controller
|
157
|
+
controller_klass = Object.const_get(klass_name)
|
158
|
+
# automatically ads the application helper to the class
|
159
|
+
controller_klass.include_view_helper('application_helper')
|
160
|
+
controller_klass.include_view_helpers
|
161
|
+
}
|
162
|
+
|
163
|
+
# cache layout erb's
|
164
|
+
layout_files = Dir.glob(File.join(APP_PATH,'/app/views/layouts/*.erb'))
|
165
|
+
layout_files.each {|f|
|
166
|
+
key = f.split("layouts/")[1].split(".html.erb")[0].gsub(/.xml.erb/, '_xml').gsub(/.json.erb/, '_json')
|
167
|
+
results = []
|
168
|
+
File.new(f, "r").each { |line| results << line }
|
169
|
+
@@layouts[key.to_sym] = ERB.new(results.join(""))
|
170
|
+
}
|
171
|
+
|
172
|
+
#lood 404 and 500 pages if they exist
|
173
|
+
pnf = Doozer::Configs.page_not_found_url
|
174
|
+
if pnf
|
175
|
+
file = File.join(APP_PATH,"/#{pnf}")
|
176
|
+
results = []
|
177
|
+
File.new(file, "r").each { |line| results << line }
|
178
|
+
@@errors[404] = results.join("")
|
179
|
+
else
|
180
|
+
@@errors[404] = "<html><body>Sorry, this page can't be found.</body></html>"
|
181
|
+
end
|
182
|
+
ise = Doozer::Configs.internal_server_error_url
|
183
|
+
if ise
|
184
|
+
file = File.join(APP_PATH,"/#{ise}")
|
185
|
+
results = []
|
186
|
+
File.new(file, "r").each { |line| results << line }
|
187
|
+
@@errors[500] = results.join("")
|
188
|
+
else
|
189
|
+
@@errors[500] = "<html><body>There was an internal server error which borked this request.</body></html>"
|
190
|
+
end
|
191
|
+
|
192
|
+
@@controllers.each_key { | key |
|
193
|
+
# p key.inspect
|
194
|
+
files = Dir.glob(File.join(APP_PATH,"/app/views/#{key.to_s}/*.erb"))
|
195
|
+
files.each { | f |
|
196
|
+
#!!!don't cache partials here!!!
|
197
|
+
view = f.split("#{key.to_s}/")[1].split(".erb")[0].gsub(/\./,'_')
|
198
|
+
# p "check view: #{view}"
|
199
|
+
if not /^_/.match( view )
|
200
|
+
# p "cache view: #{view}"
|
201
|
+
results = []
|
202
|
+
File.new(f, "r").each { |line| results << line }
|
203
|
+
@@views[key] = {} if @@views[key].nil?
|
204
|
+
@@views[key][view.to_sym] = ERB.new(results.join(""))
|
205
|
+
end
|
206
|
+
}
|
207
|
+
}
|
208
|
+
end
|
209
|
+
|
210
|
+
def load_routes
|
211
|
+
require File.join(APP_PATH, 'config/routes')
|
212
|
+
end
|
213
|
+
|
214
|
+
def load_models
|
215
|
+
Dir.glob(File.join(APP_PATH,'/app/models/*.rb')).each { | model | require model }
|
216
|
+
end
|
217
|
+
|
218
|
+
def load_watcher
|
219
|
+
p "All along the watchtower..."
|
220
|
+
watcher = FileSystemWatcher.new()
|
221
|
+
# watcher.addDirectory(File.join(File.dirname(__FILE__),'../doozer/'), "*.rb")
|
222
|
+
watcher.addDirectory(File.join(APP_PATH,'/app/'), "**/*")
|
223
|
+
watcher.addDirectory(File.join(APP_PATH,'/app/'), "**/**/*")
|
224
|
+
watcher.addDirectory(File.join(APP_PATH,'/config/'), "*.*")
|
225
|
+
watcher.addDirectory(File.join(APP_PATH,'/lib/'), "*.*")
|
226
|
+
watcher.addDirectory(File.join(APP_PATH,'/static/'), "*.*")
|
227
|
+
watcher.addDirectory(File.join(APP_PATH,'/static/'), "**/**/*")
|
228
|
+
|
229
|
+
watcher.sleepTime = 1
|
230
|
+
watcher.start { |status,file|
|
231
|
+
if(status == FileSystemWatcher::CREATED) then
|
232
|
+
puts "created: #{file}"
|
233
|
+
load_files
|
234
|
+
Doozer::Partial.clear_loaded_partials
|
235
|
+
elsif(status == FileSystemWatcher::MODIFIED) then
|
236
|
+
puts "modified: #{file}"
|
237
|
+
load_files
|
238
|
+
Doozer::Partial.clear_loaded_partials
|
239
|
+
elsif(status == FileSystemWatcher::DELETED) then
|
240
|
+
puts "deleted: #{file}"
|
241
|
+
load_files
|
242
|
+
Doozer::Partial.clear_loaded_partials
|
243
|
+
end
|
244
|
+
}
|
245
|
+
#don't join the thread it messes up rackup threading watcher.join()
|
246
|
+
end
|
247
|
+
|
248
|
+
def handler(key)
|
249
|
+
return Object.const_get(@@controllers[key])
|
250
|
+
end
|
251
|
+
|
252
|
+
def self.controllers
|
253
|
+
@@controllers
|
254
|
+
end
|
255
|
+
|
256
|
+
def self.layouts
|
257
|
+
@@layouts
|
258
|
+
end
|
259
|
+
|
260
|
+
def self.views
|
261
|
+
@@views
|
262
|
+
end
|
263
|
+
|
264
|
+
end #App
|
265
|
+
end #Doozer
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
module Doozer
|
5
|
+
|
6
|
+
# This is the main Configs class which loads root/config/app.yml and root/config/database.yml
|
7
|
+
#
|
8
|
+
# It also provides a few helper methods like logger, env_path, base_url and app_name
|
9
|
+
class Configs
|
10
|
+
APP_PATH = Dir.pwd
|
11
|
+
@@possible_orm = [:active_record, :data_mapper, :sequel]
|
12
|
+
|
13
|
+
# Rack refers to production as deployment.
|
14
|
+
def self.load(rack_env)
|
15
|
+
p "APP_ROOT: #{APP_PATH}"
|
16
|
+
p "Loading configs for #{rack_env}"
|
17
|
+
|
18
|
+
# TODO: remove this and replace with APP_PATH
|
19
|
+
@@env_path = Dir.pwd
|
20
|
+
@@config = Config::CONFIG
|
21
|
+
rack_env = (rack_env.kind_of? String) ? rack_env.to_sym : rack_env
|
22
|
+
case rack_env
|
23
|
+
when :development
|
24
|
+
when :deployment
|
25
|
+
rack_env = :deployment
|
26
|
+
when :test, :none
|
27
|
+
rack_env = :test
|
28
|
+
else
|
29
|
+
raise ":development, :deployment, or :test are only environments allowed"
|
30
|
+
end
|
31
|
+
|
32
|
+
# set logging for environment
|
33
|
+
if [:development, :test].include?(rack_env)
|
34
|
+
@@logger = Logger.new(STDOUT)
|
35
|
+
else
|
36
|
+
@@logger = Logger.new("#{APP_PATH}/log/#{rack_env}.log")
|
37
|
+
end
|
38
|
+
|
39
|
+
@@config[:rack_env] = rack_env
|
40
|
+
# p ":rack_env set to #{@@config[:rack_env]}"
|
41
|
+
|
42
|
+
begin
|
43
|
+
@@config[:database] = Configs.symbolize_keys( YAML.load(File.read(File.join(APP_PATH,'config/database.yml'))) )
|
44
|
+
rescue
|
45
|
+
p "Failed to load config/database.yml"
|
46
|
+
end
|
47
|
+
|
48
|
+
begin
|
49
|
+
@@config[:app] = Configs.symbolize_keys( YAML.load(File.read(File.join(APP_PATH,'config/app.yml'))) )
|
50
|
+
rescue
|
51
|
+
p "Failed to load config/app.yml"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# We initialize the application logger in this Configs. This is then extended through to the ActiveRecord and is also available in ViewHelpers.
|
56
|
+
def self.logger
|
57
|
+
@@logger
|
58
|
+
end
|
59
|
+
|
60
|
+
# This is the file path the app was loaded under. Dir.pwd moves to root in daemon mode so we cache this.
|
61
|
+
def self.env_path
|
62
|
+
@@env_path
|
63
|
+
end
|
64
|
+
|
65
|
+
# Take a hash and turn all the keys into symbols
|
66
|
+
def self.symbolize_keys(hash=nil)
|
67
|
+
out = {}; hash.each { | k, val | out[k.to_sym] = val}
|
68
|
+
return out
|
69
|
+
end
|
70
|
+
|
71
|
+
# Return the rack environment this application was loaded with.
|
72
|
+
def self.rack_env
|
73
|
+
return @@config[:rack_env] if not @@config[:rack_env].nil?
|
74
|
+
end
|
75
|
+
|
76
|
+
# Input a symbol and return the config for this sym
|
77
|
+
def self.get(sym=nil)
|
78
|
+
@@config[sym]
|
79
|
+
end
|
80
|
+
|
81
|
+
# Return the orm mapping gem name to load
|
82
|
+
def self.orm
|
83
|
+
begin
|
84
|
+
return @@config[:database][:orm]
|
85
|
+
rescue
|
86
|
+
end
|
87
|
+
return nil
|
88
|
+
end
|
89
|
+
|
90
|
+
# Return the database configuration setting for the loaded environment
|
91
|
+
def self.db
|
92
|
+
return @@config[:database][@@config[:rack_env]] if not @@config[:database].nil?
|
93
|
+
end
|
94
|
+
|
95
|
+
# Only used for Sequel ORM for getting the db connection after connecting
|
96
|
+
def self.db_conn
|
97
|
+
@@db_conn
|
98
|
+
end
|
99
|
+
|
100
|
+
# Only used for Sequel ORM to set the db connection
|
101
|
+
def self.db_conn=(conn)
|
102
|
+
@@db_conn = conn
|
103
|
+
end
|
104
|
+
|
105
|
+
# Return the app configuration setting for the loaded environment
|
106
|
+
def self.app
|
107
|
+
return @@config[:app][@@config[:rack_env]]
|
108
|
+
end
|
109
|
+
|
110
|
+
# Return the app base url
|
111
|
+
def self.base_url
|
112
|
+
self.app["base_url"] || ""
|
113
|
+
end
|
114
|
+
|
115
|
+
# Return the app name
|
116
|
+
def self.app_name
|
117
|
+
self.app["name"] || ""
|
118
|
+
end
|
119
|
+
|
120
|
+
# Return the app 404 url
|
121
|
+
def self.page_not_found_url
|
122
|
+
self.app[404] || nil
|
123
|
+
end
|
124
|
+
|
125
|
+
# Return the app 404 url
|
126
|
+
def self.internal_server_error_url
|
127
|
+
self.app[500] || nil
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
end
|