alfa 0.0.5.pre → 0.0.6.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/dummy/project/.gitignore +16 -0
  3. data/dummy/project/.ruby-version +1 -0
  4. data/dummy/project/CHANGELOG +0 -0
  5. data/dummy/project/Gemfile.source +7 -2
  6. data/dummy/project/README +0 -0
  7. data/dummy/project/apps/admin/layouts/base.haml +10 -0
  8. data/dummy/project/apps/admin/layouts/index.haml.source +7 -0
  9. data/dummy/project/apps/admin/templates/default/index.haml +1 -0
  10. data/dummy/project/apps/frontend/layouts/base.haml +10 -0
  11. data/dummy/project/apps/frontend/layouts/index.haml.source +7 -0
  12. data/dummy/project/apps/frontend/templates/default/{index.tpl → index.haml} +0 -0
  13. data/dummy/project/config/db.rb +15 -0
  14. data/dummy/project/config/passwords/.gitignore.source +3 -0
  15. data/dummy/project/config/passwords/db-main.yml.source +8 -0
  16. data/dummy/project/config/passwords/secrets.sample.yml +2 -0
  17. data/dummy/project/config/passwords/secrets.yml.source +2 -0
  18. data/dummy/project/config/web_application.rb +1 -0
  19. data/dummy/project/db/main/migrations/.keep +0 -0
  20. data/dummy/project/db/main/models/.keep +0 -0
  21. data/dummy/project/db/main/schema/.keep +0 -0
  22. data/dummy/project/db/main/seed.rb +0 -0
  23. data/dummy/project/log/.keep +0 -0
  24. data/dummy/project/public/.htaccess +13 -0
  25. data/dummy/project/tasks/.keep +0 -0
  26. data/dummy/project/test/.keep +0 -0
  27. data/lib/alfa/application.rb +21 -1
  28. data/lib/alfa/commands/new.rb +14 -9
  29. data/lib/alfa/config.rb +3 -2
  30. data/lib/alfa/controller.rb +19 -104
  31. data/lib/alfa/database.rb +2 -1
  32. data/lib/alfa/exceptions.rb +5 -0
  33. data/lib/alfa/logger.rb +4 -3
  34. data/lib/alfa/resourcer.rb +29 -0
  35. data/lib/alfa/router.rb +34 -14
  36. data/lib/alfa/snippeter.rb +42 -0
  37. data/lib/alfa/support/common.rb +195 -0
  38. data/lib/alfa/support/nil_operations.rb +207 -0
  39. data/lib/alfa/support/time.rb +5 -0
  40. data/lib/alfa/support.rb +3 -135
  41. data/lib/alfa/tasks/assets.rake +16 -0
  42. data/lib/alfa/tasks/db.rake +169 -0
  43. data/lib/alfa/tasks/generators.rake +80 -0
  44. data/lib/alfa/tasks.rb +4 -0
  45. data/lib/alfa/tfile.rb +1 -1
  46. data/lib/alfa/user.rb +41 -6
  47. data/lib/alfa/web_application.rb +96 -31
  48. data/lib/alfa/wrapper.rb +155 -0
  49. data/lib/alfa.rb +0 -2
  50. data/lib/rack/file_alfa.rb +2 -1
  51. data/lib/sequel/extensions/igrep.rb +19 -0
  52. data/lib/sequel/extensions/with_pks.rb +15 -0
  53. data/lib/template-inheritance/alfa_helpers.rb +106 -25
  54. data/lib/tilt/alfa_patch.rb +1 -1
  55. data/test/data/test_router/1/apps/frontend/routes.rb +1 -0
  56. data/test/data/test_router/2/apps/frontend/routes.rb +1 -0
  57. data/test/data/test_web_application/apps/admin/controllers/second.rb +5 -0
  58. data/test/data/test_web_application/apps/admin/layouts/default.haml +1 -0
  59. data/test/data/test_web_application/apps/admin/layouts/default.tpl +1 -0
  60. data/test/data/test_web_application/apps/admin/routes.rb +1 -0
  61. data/test/data/test_web_application/apps/admin/templates/default/test_04.haml +1 -0
  62. data/test/data/test_web_application/apps/admin/templates/default/test_04.tpl +1 -0
  63. data/test/data/test_web_application/apps/admin/templates/default/test_08.haml +2 -0
  64. data/test/data/test_web_application/apps/admin/templates/default/test_08a.haml +1 -0
  65. data/test/data/test_web_application/apps/admin/templates/second/index.haml +1 -0
  66. data/test/data/test_web_application/apps/frontend/controllers/second.rb +5 -0
  67. data/test/data/test_web_application/apps/frontend/layouts/default.haml +1 -0
  68. data/test/data/test_web_application/apps/frontend/layouts/default.tpl +1 -0
  69. data/test/data/test_web_application/apps/frontend/routes.rb +1 -0
  70. data/test/data/test_web_application/apps/frontend/templates/default/bar.haml +0 -0
  71. data/test/data/test_web_application/apps/frontend/templates/default/bar.tpl +0 -0
  72. data/test/data/test_web_application/apps/frontend/templates/default/frontend_only.haml +0 -0
  73. data/test/data/test_web_application/apps/frontend/templates/default/frontend_only.tpl +0 -0
  74. data/test/data/test_web_application/apps/frontend/templates/default/index.haml +0 -0
  75. data/test/data/test_web_application/apps/frontend/templates/default/index.tpl +0 -0
  76. data/test/data/test_web_application/apps/frontend/templates/default/test_04.haml +1 -0
  77. data/test/data/test_web_application/apps/frontend/templates/default/test_04.tpl +1 -0
  78. data/test/data/test_web_application/apps/frontend/templates/default/test_08.haml +2 -0
  79. data/test/data/test_web_application/apps/frontend/templates/default/test_08a.haml +1 -0
  80. data/test/data/test_web_application/apps/frontend/templates/second/index.haml +1 -0
  81. data/test/test_config.rb +2 -2
  82. data/test/test_controller.rb +13 -3
  83. data/test/test_router.rb +13 -6
  84. data/test/test_ruby_core.rb +32 -0
  85. data/test/test_support.rb +152 -11
  86. data/test/test_web_application.rb +7 -0
  87. data/version.rb +1 -1
  88. metadata +100 -16
  89. data/lib/alfa/database/mysql.rb +0 -107
  90. data/lib/alfa/models/base.rb +0 -7
  91. data/lib/alfa/models/base_sql.rb +0 -9
  92. data/lib/alfa/models/dummy.rb +0 -7
  93. data/lib/alfa/models/mysql.rb +0 -62
  94. data/lib/alfa/models.rb +0 -2
@@ -0,0 +1,169 @@
1
+ require 'sequel/extensions/migration'
2
+ require 'alfa/logger'
3
+
4
+ # All maintainable databases
5
+ def dbs
6
+ Alfa::VARS[:rakeapp_instance].instance_eval do
7
+ config[:db].select{|name, db| db[:maintain]}
8
+ end
9
+ end
10
+
11
+ namespace :db do
12
+ # Auxiliary task
13
+ # Check is database name given, if not given - exit with error message
14
+ task :require_db do
15
+ unless ENV['db']
16
+ puts "Please specify database such as: db=database"
17
+ puts "Known maintainable databases: " << dbs.map{|name, db| name}.join(', ')
18
+ exit
19
+ end
20
+ @db_name = ENV['db'].to_sym
21
+ @db = dbs[@db_name]
22
+ unless @db
23
+ puts "Unknown database \"#{ENV['db']}\". Known maintainable databases: " << dbs.map{|name, db| name}.join(', ')
24
+ exit
25
+ end
26
+ end
27
+
28
+ # Auxiliary task
29
+ # Set @db if database name given
30
+ task :optional_db do
31
+ @db = nil
32
+ @db_name = nil
33
+ if ENV['db']
34
+ @db_name = ENV['db'].to_sym
35
+ @db = dbs[@db_name]
36
+ unless @db
37
+ puts "Unknown database. Known maintainable databases: " << dbs.map{|name, db| name}.join(', ')
38
+ exit
39
+ end
40
+ end
41
+ end
42
+
43
+ # Auxiliary task
44
+ # Set logger($stdout) for all databases
45
+ task :stdout_logger do
46
+ @stdout_logger ||= Alfa::Logger.new($stdout)
47
+ dbs.each_value do |db|
48
+ db[:instance].loggers << @stdout_logger
49
+ end
50
+ end
51
+
52
+ desc "Drop all tables in schema"
53
+ task :drop => [:require_db, :stdout_logger] do
54
+ @db[:instance].tables.each do |table|
55
+ @db[:instance].foreign_key_list(table).each do |key|
56
+ @db[:instance].alter_table table do
57
+ drop_foreign_key(key[:columns])
58
+ end
59
+ end
60
+ end
61
+ @db[:instance].drop_table(*@db[:instance].tables)
62
+ end
63
+
64
+ desc "Create dumb migration for certain database and puts them into PROJECT_ROOT/db/%database%/migration"
65
+ task :'new-migration' => [:require_db, :stdout_logger] do
66
+ unless @db[:path]
67
+ puts "Error: not specified path for database #{@db_name}"
68
+ exit
69
+ end
70
+ ts = Time.now.utc.strftime('%Y%m%d%H%M%S')
71
+ pattern = <<EOL
72
+ # Migration #{ts}
73
+ # Don't rename this file after implement migration
74
+
75
+ Sequel.migration do
76
+ up do
77
+ # Put up migration code here
78
+ # Use Sequel migration syntax (http://sequel.jeremyevans.net/rdoc/files/doc/schema_modification_rdoc.html) or native SQL (run "SQL command")
79
+ end
80
+
81
+ down do
82
+ # Put down migration code here
83
+ end
84
+ end
85
+ EOL
86
+ filename = "#{ts}_m.rb"
87
+ migration_file = File.join(@db[:path], 'migrations', filename)
88
+ if File.exist?(migration_file)
89
+ puts "Error: file #{migration_file} already exists, exiting"
90
+ exit
91
+ end
92
+
93
+ File.open(migration_file, 'w') do |f|
94
+ f.write pattern
95
+ puts "Create migration #{migration_file}"
96
+ end
97
+ end
98
+
99
+ desc "Migrate database(s)"
100
+ task :migrate => [:optional_db, :stdout_logger] do
101
+ if @db
102
+ Sequel::Migrator.run(@db[:instance], File.join(@db[:path], 'migrations'))
103
+ else
104
+ dbs.each do |name, db|
105
+ Sequel::Migrator.run(db[:instance], File.join(db[:path], 'migrations'))
106
+ end
107
+ end
108
+ end
109
+
110
+ namespace :migrate do
111
+ desc "Migrate database 1 step up"
112
+ task :up => [:require_db, :stdout_logger] do
113
+ migrator = Sequel::TimestampMigrator.new(@db[:instance], File.join(@db[:path], 'migrations'))
114
+ if migrator.migration_tuples
115
+ m = migrator.migration_tuples.first
116
+ if m[2] == :up
117
+ target = m[1].split('_').first.to_i
118
+ Sequel::Migrator.run(@db[:instance], File.join(@db[:path], 'migrations'), :target=>target)
119
+ end
120
+ end
121
+ end
122
+
123
+ desc "Migrate database 1 step down"
124
+ task :down => [:require_db, :stdout_logger] do
125
+ migrator = Sequel::TimestampMigrator.new(@db[:instance], File.join(@db[:path], 'migrations'))
126
+ to_rollback = migrator.applied_migrations.last
127
+ if to_rollback
128
+ target = migrator.applied_migrations[0..-2].last # last but one applied migration
129
+ if target
130
+ target = target.split('_').first.to_i
131
+ else
132
+ target = 0
133
+ end
134
+ Sequel::Migrator.run(@db[:instance], File.join(@db[:path], 'migrations'), :target=>target)
135
+ else
136
+ puts "Nothing to rollback"
137
+ end
138
+ end
139
+ end
140
+
141
+ desc "Test databases connection parameters"
142
+ task :test do
143
+ errors = 0
144
+ dbs.each do |name, db|
145
+ begin
146
+ db[:instance].test_connection
147
+ rescue Sequel::DatabaseConnectionError => e
148
+ errors = errors + 1
149
+ puts e.message
150
+ end
151
+ end
152
+ if errors > 0
153
+ puts "Some DSN problems found. Check config/passwords/db-*.yml"
154
+ else
155
+ puts "All DSNs are ok!"
156
+ end
157
+ end
158
+
159
+ desc 'Seed chosen Database'
160
+ task :seed => [:optional_db, :stdout_logger] do
161
+ if @db
162
+ Kernel.load File.join(@db[:path], 'seed.rb')
163
+ else
164
+ dbs.each do |name, db|
165
+ Kernel.load File.join(db[:path], 'seed.rb')
166
+ end
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,80 @@
1
+ namespace :+ do
2
+
3
+ task :require_model => [:'db:require_db'] do
4
+ unless ENV['model']
5
+ puts "Please specify model in single form such as: model=images"
6
+ exit
7
+ end
8
+ @model_name = ENV['model'].to_sym
9
+ if File.exist?(File.join(PROJECT_ROOT, 'db', @db_name.to_s, 'models', "#{@model_name.to_s}.rb"))
10
+ puts "Model #{@model_name} for db #{@db_name} already exists"
11
+ exit
12
+ end
13
+ end
14
+
15
+ desc 'Create model'
16
+ task :model => [:'db:require_db', :require_model] do
17
+ model_filename = Alfa::Support.underscore_name(@model_name)
18
+ model_classname = Alfa::Support.camelcase_name(@model_name)
19
+ db_classname = Alfa::Support.camelcase_name(@db_name)
20
+ ts = Time.now.utc.strftime('%Y%m%d%H%M%S')
21
+ pattern = <<EOL
22
+ # Migration #{ts} for model #{model_classname}
23
+ # Don't rename this file after implement migration
24
+
25
+ Sequel.migration do
26
+ up do
27
+ # Use Sequel migration syntax (http://sequel.jeremyevans.net/rdoc/files/doc/schema_modification_rdoc.html) or native SQL (run "SQL command")
28
+ create_table :#{model_filename}s do
29
+ primary_key :id
30
+ # ...
31
+ column :created_at, DateTime
32
+ column :updated_at, DateTime
33
+ end
34
+ end
35
+
36
+ down do
37
+ drop_table :#{model_filename}s
38
+ end
39
+ end
40
+ EOL
41
+ filename = "#{ts}_#{model_filename}s.rb"
42
+ migration_file = File.join(@db[:path], 'migrations', filename)
43
+ if File.exist?(migration_file)
44
+ puts "Error: file #{migration_file} already exists, exiting"
45
+ exit
46
+ end
47
+ File.open(migration_file, 'w') do |f|
48
+ f.write pattern
49
+ puts "Create migration #{migration_file}"
50
+ end
51
+
52
+ pattern = <<EOL
53
+ class #{model_classname} < Sequel::Model(DB::#{db_classname}[:#{model_filename}s])
54
+ # Uncomment following plugins if necessary:
55
+ # plugin :timestamps, update_on_create: true
56
+ # plugin :prepared_statements
57
+ # plugin :serialization, %method%, %field%
58
+ # Read more about available plugins: http://sequel.jeremyevans.net/rdoc-plugins/classes/Sequel/Plugins.html
59
+
60
+ # Use associations:
61
+ # one_to_one :association_name, class: :OtherModel, key: :key_name
62
+ # one_to_many ...
63
+ # many_to_one ...
64
+ # many_to_many ...
65
+ # one_through_one ...
66
+ # Read more about association basics: http://sequel.jeremyevans.net/rdoc/files/doc/association_basics_rdoc.html
67
+ end
68
+ EOL
69
+ filename = "#{model_filename}.rb"
70
+ model_file = File.join(@db[:path], 'models', filename)
71
+ if File.exist?(model_file)
72
+ puts "Error: file #{model_file} already exists, exiting"
73
+ exit
74
+ end
75
+ File.open(model_file, 'w') do |f|
76
+ f.write pattern
77
+ puts "Create migration #{model_file}"
78
+ end
79
+ end
80
+ end
data/lib/alfa/tasks.rb CHANGED
@@ -1,2 +1,6 @@
1
1
  load 'alfa/tasks/assets.rake'
2
2
  load 'alfa/tasks/db.rake'
3
+ load 'alfa/tasks/generators.rake'
4
+
5
+ require 'rake/testtask'
6
+ Rake::TestTask.new
data/lib/alfa/tfile.rb CHANGED
@@ -56,7 +56,7 @@ module Alfa
56
56
  end
57
57
 
58
58
  def extname= arg
59
- arg = '.' + arg unless arg =~ /^\./
59
+ arg = '.' + arg unless arg =~ /\A\./
60
60
  self.basename= self.filename + arg
61
61
  end
62
62
 
data/lib/alfa/user.rb CHANGED
@@ -1,3 +1,6 @@
1
+ require 'digest/md5'
2
+ require 'securerandom'
3
+
1
4
  module Alfa
2
5
  class << self
3
6
  attr_accessor :GROUPS
@@ -27,16 +30,20 @@ module Alfa
27
30
  def [](key)
28
31
  nil
29
32
  end
33
+
34
+ def method_missing(*o)
35
+ nil
36
+ end
30
37
  end
31
38
 
39
+
32
40
  class User
33
- def initialize(properties)
34
- @properties = properties
41
+ def initialize(object)
42
+ @object = object
35
43
  end
36
44
 
37
45
  def grants
38
- @groups_p ||= groups + [:public]
39
- @groups_p.map{|g| Alfa.GROUPS[g] || []}.flatten
46
+ (groups + [:public]).map{|g| Alfa.GROUPS[g] || []}.flatten
40
47
  end
41
48
 
42
49
  def grant?(name)
@@ -45,7 +52,7 @@ module Alfa
45
52
 
46
53
  # @return Array
47
54
  def groups
48
- @groups ||= @properties[:groups].to_s.split(',').map{|s| s.strip.to_sym}
55
+ @object.groups.map{|s| s.to_s.strip.to_sym}
49
56
  end
50
57
 
51
58
  def group?(name)
@@ -57,7 +64,35 @@ module Alfa
57
64
  end
58
65
 
59
66
  def [](key)
60
- @properties[key]
67
+ @object[key]
68
+ end
69
+
70
+ def method_missing(*o)
71
+ @object.send(*o)
72
+ end
73
+
74
+ def self.method_missing(*o)
75
+ @object.class.send(*o)
76
+ end
77
+ end
78
+
79
+ # Prepend this module in User model in your Project
80
+ # Example:
81
+ # class User < Sequel::Model(DB::Main[:users])
82
+ # prepend Alfa::UserModule
83
+ # end
84
+ module UserModule
85
+ def password=(p)
86
+ self.salt = SecureRandom.hex(5)
87
+ self.passhash = Digest::MD5.hexdigest("#{self.salt}#{p}")
88
+ end
89
+
90
+ def password_valid?(p)
91
+ self.passhash == Digest::MD5.hexdigest("#{self.salt}#{p}")
92
+ end
93
+
94
+ def groups=(g)
95
+ super(Array(g))
61
96
  end
62
97
  end
63
98
  end
@@ -5,16 +5,17 @@ require 'alfa/tfile'
5
5
  require 'alfa/controller'
6
6
  require 'alfa/router'
7
7
  require 'alfa/ruty'
8
- require 'alfa/user'
8
+ require 'alfa/snippeter'
9
+ require 'alfa/wrapper'
10
+ require 'alfa/resourcer'
9
11
  require 'rack/utils'
10
12
  require 'rack/request'
11
13
  require 'rack/file_alfa'
12
- require 'digest/md5'
13
- require 'securerandom'
14
14
  require 'haml'
15
15
  require 'alfa/template-inheritance'
16
16
  require 'tilt/alfa_patch'
17
17
  require 'haml/alfa_patch'
18
+ require 'json'
18
19
 
19
20
  module Alfa
20
21
  class WebApplication < Alfa::Application
@@ -32,6 +33,7 @@ module Alfa
32
33
  end
33
34
  end
34
35
 
36
+ # noinspection RubyResolve
35
37
  def self.init!
36
38
  super
37
39
  Alfa::Router.reset
@@ -39,6 +41,9 @@ module Alfa
39
41
  load File.join(@config[:project_root], 'config/routes.rb')
40
42
  TemplateInheritance.logger = @logger
41
43
  Alfa.GROUPS = @config[:groups]
44
+ Alfa::Snippeter.config = @config
45
+ Alfa::Snippeter.mounts = Alfa::Router.mounts
46
+ Alfa::Snippeter.load
42
47
  end
43
48
 
44
49
  # main Rack routine
@@ -77,37 +82,60 @@ module Alfa
77
82
  headers['Expires'] = (Time.now + 2592000).httpdate
78
83
  else
79
84
  request = Rack::Request.new(env) # weakref?
80
- app_sym = route[:options].has_key?(:app) ? route[:options][:app] : params[:app]
81
- c_sym = route[:options].has_key?(:controller) ? route[:options][:controller] : params[:controller]
82
- a_sym = route[:options].has_key?(:action) ? route[:options][:action] : params[:action]
83
- l_sym = route[:options].has_key?(:layout) ? route[:options][:layout] : :default
84
- controller = self.invoke_controller(app_sym, c_sym)
85
+ app_sym, c_sym, a_sym, l_sym = route_to_symbols(route, params)
86
+ controller = self.invoke_controller(app_sym, c_sym, route)
87
+ unless controller.class.instance_methods(false).include?(a_sym)
88
+ if route[:rule] =~ /\A\/:(controller|action)\/?\z/
89
+ route, params = self.routes.find_route(Rack::Utils.unescape(env['PATH_INFO']), exclude: [route[:rule]])
90
+ app_sym, c_sym, a_sym, l_sym = route_to_symbols(route, params)
91
+ controller = self.invoke_controller(app_sym, c_sym, route)
92
+ raise Exceptions::Route404 unless controller
93
+ end
94
+ end
85
95
  raise Exceptions::Route404 unless controller.class.instance_methods(false).include?(a_sym)
86
96
  controller._clear_instance_variables # cleanup
87
97
  controller.application = self
88
98
  controller.request = request
89
99
  controller.app_sym = app_sym
90
100
  controller.c_sym = c_sym
91
- controller.__send__(a_sym)
92
- data = controller._instance_variables_hash
93
- Ruty::Tags::RequireStyle.clean_cache # cleanup
94
- Ruty::Tags::RequireScript.clean_cache # cleanup
95
- content = self.render_template(app_sym, c_sym, a_sym, controller, data, &block)
96
- body = self.render_layout(app_sym.to_s, l_sym.to_s, data.merge({:@body => content}))
97
- headers["Content-Type"] = 'text/html; charset=utf-8'
101
+ controller.params = params
102
+ data = controller.__send__(a_sym)
103
+ case controller.class.get_content_type(a_sym)
104
+ when :json
105
+ headers['Content-Type'] = 'application/json; charset=utf-8'
106
+ body = JSON.generate(data, quirks_mode: true)
107
+ else
108
+ data = controller._instance_variables_hash
109
+ resourcer = Alfa::Resourcer.new
110
+ wrapper = Alfa::Wrapper.new(application: self, request: request, app_sym: app_sym, c_sym: c_sym, resourcer: resourcer, params: params, route: route)
111
+ Ruty::Tags::RequireStyle.clean_cache # cleanup
112
+ Ruty::Tags::RequireScript.clean_cache # cleanup
113
+ content = self.render_template(app_sym, c_sym, a_sym, controller, wrapper, data, &block)
114
+ if controller.class.get_render(a_sym) == :partial
115
+ body = content
116
+ else
117
+ body = self.render_layout(app_sym.to_s, l_sym.to_s, controller, wrapper, data.merge({:@body => content}))
118
+ end
119
+ headers['Content-Type'] = 'text/html; charset=utf-8'
120
+ end
98
121
  end
99
122
  rescue Alfa::Exceptions::Route404 => e
100
123
  response_code = 404
101
- body = 'Url not found<br>urls map:<br>'
124
+ body = "Url not found (#{e.message}) <br>urls map:<br>"
102
125
  body += self.routes.instance_variable_get(:@routes).inspect
103
126
  l.info "404: Url not found (#{e.message})"
127
+ rescue Alfa::Exceptions::Route403 => e
128
+ response_code = 403
129
+ body = "Error 403: Forbidden (#{e.message})"
130
+ l.info "403: Forbidden"
104
131
  rescue Exceptions::HttpRedirect => e
105
132
  response_code = e.code
106
133
  headers['Location'] = e.url.to_s
107
- body = ''
134
+ body = "You was redirected to #{e.url}"
108
135
  rescue Exception => e
109
136
  response_code = 500
110
- body = "Error occured: #{e.message} at #{e.backtrace.first}<br>Full backtrace:<br>\n#{e.backtrace.join("<br>\n")}"
137
+ body = "Error occured: #{CGI.escape_html(e.message)} at #{e.backtrace.first}<br>Full backtrace:<br>\n#{e.backtrace.join("<br>\n")}"
138
+ l.error "ERROR: #{e.message} at #{e.backtrace.first}"
111
139
  end
112
140
  if t_sym == :default
113
141
  #debug_info = '<hr>Queries:<br>' + @logger.logs.map { |log|
@@ -124,17 +152,44 @@ module Alfa
124
152
  return [response_code, headers, [body, @bputs.join('<br>')]]
125
153
  end
126
154
 
155
+
156
+ def self.route_to_symbols(route, params)
157
+ app_sym = route[:options].has_key?(:app) ? route[:options][:app] : params[:app]
158
+ c_sym = route[:options].has_key?(:controller) ? route[:options][:controller] : params[:controller]
159
+ a_sym = route[:options].has_key?(:action) ? route[:options][:action] : params[:action]
160
+ l_sym = route[:options].has_key?(:layout) ? route[:options][:layout] : :default
161
+ return app_sym, c_sym, a_sym, l_sym
162
+ end
163
+
127
164
  # router
128
165
  def self.routes
129
166
  @router ||= Alfa::Router
130
167
  end
131
168
 
132
169
 
170
+ def self.snippets
171
+ @snippeter ||= Alfa::Snippeter
172
+ end
173
+
174
+ # Evaluate snippet with given name
175
+ # @param Symbol name
176
+ # @param Alfa::Controller controller
177
+ # return String
178
+ def self.snippet(name, wrapper)
179
+ block = snippets[wrapper.app_sym][name]
180
+ raise "Not found snippet #{name} for app #{wrapper.app_sym}" unless block
181
+ wrapper.instance_eval(&block)
182
+ data = wrapper._instance_variables_hash
183
+ render_snippet(wrapper.app_sym, name, wrapper, data)
184
+ end
185
+
186
+
133
187
  def self.rackup(builder)
134
- builder.use Rack::Session::Cookie
188
+ builder.use Rack::Lock
189
+ builder.use Rack::Session::Cookie, key: @config[:session][:key], secret: @config[:session][:secret]
135
190
  if @config[:serve_static]
136
191
  builder.run Rack::Cascade.new([
137
- Rack::FileAlfa.new(@config[:document_root]),
192
+ Rack::FileAlfa.new(@config[:document_root], {'Cache-Control'=>'max-age=2592000'}),
138
193
  self,
139
194
  ])
140
195
  else
@@ -152,6 +207,7 @@ module Alfa
152
207
  raise Exceptions::HttpRedirect.new(url, code)
153
208
  end
154
209
 
210
+
155
211
  # private section
156
212
 
157
213
  def self.verify_config
@@ -162,30 +218,39 @@ module Alfa
162
218
  @config[:groups][:public] = [] unless @config[:groups][:public]
163
219
  end
164
220
 
165
- def self.invoke_controller(a_sym, c_sym)
166
- load File.join(@config[:project_root], 'apps', a_sym.to_s, 'controllers', c_sym.to_s + '.rb')
221
+ def self.invoke_controller(a_sym, c_sym, route)
222
+ f = File.join(@config[:project_root], 'apps', a_sym.to_s, 'controllers', c_sym.to_s + '.rb')
223
+ return nil unless File.exists?(f)
224
+ load f
167
225
  klass_name = Alfa::Support.camelcase_name(c_sym)+'Controller'
168
226
  klass = Kernel.const_get(klass_name) # weakref?
169
- instance = klass.new
227
+ instance = klass.new(route: route)
170
228
  Object.module_eval{remove_const(klass_name)}
171
229
  return instance
172
230
  end
173
231
 
174
- def self.render_template(app_sym, c_sym, a_sym, controller, data = {}, &block)
175
- render(file: File.join(@config[:project_root], 'apps', app_sym.to_s, 'templates', c_sym.to_s, a_sym.to_s), controller: controller, data: data, &block)
232
+ def self.render_template(app_sym, c_sym, a_sym, controller, wrapper, data = {}, &block)
233
+ wrapper.resourcer.level = :action
234
+ render(file: File.join(@config[:project_root], 'apps', app_sym.to_s, 'templates', c_sym.to_s, a_sym.to_s), controller: controller, data: data, wrapper: wrapper, &block)
235
+ end
236
+
237
+ def self.render_layout(app, layout, controller, wrapper, data = {})
238
+ wrapper.resourcer.level = :layout
239
+ render(file: File.join(@config[:project_root], 'apps', app, 'layouts', layout.to_s), controller: controller, wrapper: wrapper, data: data)
176
240
  end
177
241
 
178
- def self.render_layout(app, layout, data = {})
179
- render(file: File.join(@config[:project_root], 'apps', app, 'layouts', layout.to_s), data: data)
242
+ def self.render_snippet(app_sym, snip_sym, wrapper, data = {})
243
+ wrapper.resourcer.level = :snippet
244
+ render(file: File.join(@config[:project_root], 'apps', app_sym.to_s, 'templates/_snippets', snip_sym.to_s), wrapper: wrapper, data: data)
180
245
  end
181
246
 
182
- def self.render(file: nil, controller: nil, data: {})
247
+ def self.render(file: nil, controller: nil, wrapper: nil, data: {})
183
248
  @config[:templates_priority].each do |ext|
184
249
  f = "#{file}.#{ext}"
185
250
  if File.exist?(f)
186
251
  case ext
187
252
  when :haml
188
- template = self.haml_template(f, controller)
253
+ template = self.haml_template(f, controller, wrapper)
189
254
  yield(controller, template) if block_given? # required only for thread isolation test
190
255
  return template.render data
191
256
  when :tpl
@@ -205,9 +270,9 @@ module Alfa
205
270
  @ruty_loader ||= Ruty::Loaders::Filesystem.new(:dirname => File.join(@config[:project_root], 'apps'))
206
271
  end
207
272
 
208
- def self.haml_template(file, controller)
273
+ def self.haml_template(file, controller, wrapper)
209
274
  # @haml_templates[file.to_sym] ||= TemplateInheritance::Template.new(file)
210
- scope = TemplateInheritance::RenderScope.new(controller)
275
+ scope = TemplateInheritance::RenderScope.new(controller, wrapper, wrapper.resourcer)
211
276
  TemplateInheritance::Template.new(file, scope)
212
277
  end
213
278