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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9c85a3bddfc3872bab4b7d4203197f45bc85e14d
4
- data.tar.gz: 50a67c2c30eadbbde07ac7a96424394ffc5255d2
3
+ metadata.gz: 42b04d75d9c3ed910907e1c46163b85226939122
4
+ data.tar.gz: ffbf8a3228d0271f6c8a631ad3f626484c7ec4ba
5
5
  SHA512:
6
- metadata.gz: 627b62bacbbb4983841a977c990deea9155c6da7d47bfdbb6a086ec6953d26b73ce943fc898f37e02e1ef0f248af0463b4c0e717007e97fa61f1c4321d312425
7
- data.tar.gz: b797cfc9ff3ad128893df8a84e812a0bf559e442f04feede620235ceaa41785e1738d0d8ee167bd0abaf7242821bbee1b5c5aa2f10ffa5b6af45f3b71142da3f
6
+ metadata.gz: 0625ca1aba2e5eb757cbd0d613fa4b2712c4c6c130093cf39c43e9b9c21fd8948bfaca6f6a8bbe2d3cc8876dbf8d637afc61f29835eeed22d3bcf309d5737f0f
7
+ data.tar.gz: e4195b642f031804e08eca399335b95b48604d7a98d0c64eca640c322f4eb3bf3fada7e3a36a3d81c438bf928a932c077c3413b7e1a6ebe6e58b7cb5de6332cb
@@ -0,0 +1,16 @@
1
+ # See http://help.github.com/ignore-files/ for more about ignoring files.
2
+
3
+ /.bundle/
4
+ /tmp/
5
+ /log/*.log
6
+ /public/~assets/
7
+
8
+ # IDE settings (Eclipse)
9
+ /.project
10
+ /.classpath
11
+
12
+ # IDE settings (JetBrains RubyMine)
13
+ *.iml
14
+ *.ipr
15
+ *.iws
16
+ /.idea/
@@ -0,0 +1 @@
1
+ 2.1.1
File without changes
@@ -2,5 +2,10 @@ source 'https://rubygems.org'
2
2
 
3
3
  gem 'alfa', '#{ALFA_VERSION}'
4
4
 
5
- # Using mysql2 as database adapter
6
- gem 'mysql2', '~> 0.3' # 0.3.11
5
+ # Use mysql2 as database adapter
6
+ gem 'mysql2', '~> 0.3', '>= 0.3.15'
7
+
8
+ # Uncomment following gems if necessary:
9
+ #
10
+ # gem 'thin'
11
+ # gem 'redcarpet'
File without changes
@@ -0,0 +1,10 @@
1
+ !!! 5
2
+ %html
3
+ %head
4
+ %meta{charset: 'utf-8'}
5
+ %title<
6
+ = block(:title)
7
+ != styles
8
+ %body
9
+ != block(:body)
10
+ != scripts
@@ -0,0 +1,7 @@
1
+ - extends './base.haml'
2
+
3
+ - block(:title) do
4
+ #{PROJECT_NAME} admin
5
+
6
+ - block(:body) do
7
+ != @body
@@ -0,0 +1 @@
1
+ apps/admin/default#index
@@ -0,0 +1,10 @@
1
+ !!! 5
2
+ %html
3
+ %head
4
+ %meta{charset: 'utf-8'}
5
+ %title<
6
+ = block(:title)
7
+ != styles
8
+ %body
9
+ != block(:body)
10
+ != scripts
@@ -0,0 +1,7 @@
1
+ - extends './base.haml'
2
+
3
+ - block(:title) do
4
+ #{PROJECT_NAME}
5
+
6
+ - block(:body) do
7
+ != @body
@@ -1,6 +1,19 @@
1
1
  require 'alfa/database'
2
2
  require 'yaml'
3
3
 
4
+ # Read more about the timestamps plugin:
5
+ # http://sequel.jeremyevans.net/rdoc-plugins/classes/Sequel/Plugins/Timestamps.html
6
+ Sequel::Model.plugin :timestamps, update_on_create: true
7
+
8
+ # Read more about prepared statements and the plugin:
9
+ # http://sequel.jeremyevans.net/rdoc/files/doc/prepared_statements_rdoc.html
10
+ # http://sequel.jeremyevans.net/rdoc-plugins/classes/Sequel/Plugins/PreparedStatements.html
11
+ # Sequel::Model.plugin :prepared_statements
12
+
13
+ # Read more about available plugins:
14
+ # http://sequel.jeremyevans.net/rdoc-plugins/classes/Sequel/Plugins.html
15
+
16
+
4
17
  # Main database for application private use
5
18
  module DB
6
19
  Main = Sequel.connect(YAML.load(File.open(File.expand_path('../passwords/db-main.yml', __FILE__))).symbolize_keys[:dsn], :encoding=>'utf8')
@@ -9,3 +22,5 @@ end
9
22
  Dir[File.join(PROJECT_ROOT, 'db/main/models/*.rb')].each do |f|
10
23
  require f
11
24
  end
25
+
26
+ Sequel.extension :blank
@@ -0,0 +1,3 @@
1
+ *
2
+ !.gitignore
3
+ !*.sample.yml
@@ -0,0 +1,8 @@
1
+ ---
2
+ # dns format ([...] can be omitted):
3
+ # adapter://user:[password]@host[:port]/database
4
+ dsn: "mysql2://user:password@localhost:3306/#{PROJECT_NAME}"
5
+ host: "localhost"
6
+ user: "user"
7
+ password: "password"
8
+ dbname: "#{PROJECT_NAME}"
@@ -0,0 +1,2 @@
1
+ ---
2
+ session_secret: "YOUR_SECRET_STRING"
@@ -0,0 +1,2 @@
1
+ ---
2
+ session_secret: "#{SESSION_SECRET}"
@@ -9,6 +9,7 @@ module Project
9
9
  config[:run_mode] = :development # :development or :production or :test
10
10
  config[:log][:file] = File.join(PROJECT_ROOT, 'log/web.log')
11
11
  config[:serve_static] = true
12
+ config[:session][:secret] = YAML.load(File.open(File.expand_path('../passwords/secrets.yml', __FILE__))).symbolize_keys[:session_secret]
12
13
  end
13
14
 
14
15
  WebApplication.init!
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,13 @@
1
+ Options -Indexes
2
+
3
+ <IfModule mod_expires.c>
4
+ ExpiresActive on
5
+ ExpiresByType image/gif A604800
6
+ ExpiresByType image/png A604800
7
+ ExpiresByType image/jpg A604800
8
+ ExpiresByType image/jpeg A604800
9
+ ExpiresByType image/x-icon A604800
10
+ ExpiresByType image/vnd.microsoft.icon A604800
11
+ ExpiresByType text/css A604800
12
+ ExpiresByType application/javascript A604800
13
+ </IfModule>
File without changes
File without changes
@@ -1,6 +1,7 @@
1
1
  require 'alfa/logger'
2
2
  require 'alfa/config'
3
3
  require 'alfa/exceptions'
4
+ require 'alfa/user'
4
5
 
5
6
  Encoding.default_external = 'utf-8'
6
7
  Encoding.default_internal = 'utf-8'
@@ -36,7 +37,7 @@ module Alfa
36
37
  @logger.info " DOCUMENT_ROOT: #{@config[:document_root]}\n"
37
38
  @log_file.flush
38
39
  ObjectSpace.define_finalizer(@logger, Proc.new {@logger.info "Application (pid=#{$$}) stopped at #{DateTime.now}\n\n"})
39
- @config[:db].each_value { |db| db[:instance].loggers = [@logger] }
40
+ @config[:db].each_value { |db| db[:instance].logger = @logger }
40
41
  else
41
42
  @logger = Alfa::NullLogger.new
42
43
  end
@@ -47,11 +48,30 @@ module Alfa
47
48
  def self.load_tasks
48
49
  VARS[:rakeapp_instance] = self
49
50
  require 'alfa/tasks'
51
+ Dir[File.join(@config[:project_root], 'tasks', '*.rake')].each do |f|
52
+ Kernel.load f
53
+ end
50
54
  end
51
55
 
52
56
 
53
57
  def self.verify_config
54
58
  raise Exceptions::E001.new('config[:project_root] should be defined') unless @config[:project_root]
55
59
  end
60
+
61
+
62
+ def self.try_register(login, password)
63
+ @config[:db][:main][:instance].transaction do
64
+ unless User.first(:login=>login)
65
+ @logger.portion do |l|
66
+ salt = SecureRandom.hex(5)
67
+ passhash = Digest::MD5.hexdigest("#{salt}#{password}")
68
+ User.create(:login=>login, :salt=>salt, :passhash=>passhash)
69
+ l.info("created new user login=#{login}, password=***, salt=#{salt}, passhash=#{passhash}")
70
+ end
71
+ return true, "Registration done"
72
+ end
73
+ return false, "User with login #{login} already exists"
74
+ end
75
+ end
56
76
  end
57
77
  end
@@ -1,12 +1,15 @@
1
1
  require File.expand_path('../../../../version', __FILE__)
2
2
  require 'fileutils'
3
3
  require 'alfa/support'
4
+ require 'securerandom'
4
5
 
5
6
  PROJECT_NAME = $*[1]
7
+ SESSION_SECRET = SecureRandom.base64(24)
6
8
 
7
9
  sr = {
8
10
  '#{ALFA_VERSION}' => ALFA_VERSION,
9
11
  '#{PROJECT_NAME}' => PROJECT_NAME,
12
+ '#{SESSION_SECRET}' => SESSION_SECRET
10
13
  }
11
14
 
12
15
  target_dir = File.join(Dir.pwd, PROJECT_NAME)
@@ -38,12 +41,14 @@ ensure
38
41
  puts ""
39
42
  end
40
43
 
41
- begin
42
- print "Bundle install... "
43
- FileUtils.cd PROJECT_NAME
44
- `bundle install`
45
- print "done"
46
- ensure
47
- FileUtils.cd '..'
48
- puts ""
49
- end
44
+ puts "Run 'cd #{PROJECT_NAME} && bundle install' manually"
45
+
46
+ # begin
47
+ # print "Bundle install... "
48
+ # FileUtils.cd PROJECT_NAME
49
+ # `bundle install`
50
+ # print "done"
51
+ # ensure
52
+ # FileUtils.cd '..'
53
+ # puts ""
54
+ # end
data/lib/alfa/config.rb CHANGED
@@ -4,17 +4,18 @@ module Alfa
4
4
  def initialize
5
5
  self[:db] = {}
6
6
  self[:log] = {}
7
+ self[:session] = {key: 'session', secret: nil}
7
8
  end
8
9
 
9
10
  def []=(key, value)
10
- if [:db, :log].include? key
11
+ if [:db, :log, :session].include? key
11
12
  raise "key :#{key} should include Enumerable" unless value.class.included_modules.include? Enumerable
12
13
  end
13
14
  super
14
15
  end
15
16
 
16
17
  def store(key, value)
17
- if [:db, :log].include? key
18
+ if [:db, :log, :session].include? key
18
19
  raise "key :#{key} should include Enumerable" unless value.class.included_modules.include? Enumerable
19
20
  end
20
21
  super
@@ -1,124 +1,39 @@
1
- require 'alfa/support'
2
- require 'alfa/exceptions'
1
+ require 'alfa/wrapper'
3
2
 
4
3
  module Alfa
5
4
  class Controller
6
- attr_accessor :application, :request, :config, :app_sym, :c_sym
5
+ include Alfa::WrapperMethods
7
6
 
8
- def _instance_variables_hash
9
- Hash[instance_variables.map { |name| [name.to_sym, instance_variable_get(name)] } ]
10
- end
11
-
12
- def _clear_instance_variables
13
- instance_variables.each {|name| remove_instance_variable(name)}
14
- end
15
-
16
- def href(*o)
17
- kwargs = _extract_href_params(*o)
18
- @application.routes.href(kwargs)
19
- end
20
-
21
- alias :href_to :href
22
-
23
- def _extract_href_params(*o)
24
- args, kwargs = Support.args_kwargs(*o)
25
- if args.any?
26
- if args.first.is_a?(Symbol)
27
- kwargs[:action] = args.first
28
- else
29
- kwargs.merge! _string_to_aca(args.first.to_s)
30
- end
31
- end
32
- kwargs = {:app=>@app_sym}.merge kwargs
33
- kwargs = {:controller=>@c_sym}.merge kwargs if kwargs[:action]
34
- kwargs
35
- end
36
-
37
- # Convert string to App-Controller-Action hash
38
- # 'app*controller#action'
39
- def _string_to_aca(str)
40
- res = {}
41
- s1 = str.split('@')
42
- raise Exceptions::E004.new("E004: Bad href argument #{str}: it should contain at most one @ symbol") if s1.length > 2
43
- res[:app] = s1.last.to_sym if s1.length > 1
44
- s2 = s1.first.split('#')
45
- raise Exceptions::E004.new("E004: Bad href argument #{str}: it should contain at most one # symbol") if s2.length > 2
46
- res[:controller] = s2.first.to_sym if s2.length > 1
47
- res[:action] = s2.last.to_sym if s2.length > 0
48
- res
49
- end
7
+ attr_accessor :application, :request, :config, :app_sym, :c_sym, :params, :resourcer, :route
50
8
 
51
-
52
- def session
53
- @request.session
9
+ def initialize(route: nil)
10
+ @route = route
54
11
  end
55
12
 
56
- # Return current user
57
- def user
58
- @user ||= (
59
- if @request.session[:user_id] && (u = @application.config[:db][:main][:instance][:users].first(id: @request.session[:user_id]))
60
- User.new(u)
61
- else
62
- GuestUser
63
- end
64
- )
13
+ def self.__options
14
+ @__options ||= {}
65
15
  end
66
16
 
67
-
68
- def grant?(grant)
69
- user.grant?(grant)
70
- end
71
-
72
-
73
- [300, 301, 302, 303].each do |code|
74
- define_method ("redirect_#{code}".to_sym) do |url|
75
- @application.redirect(url, code)
76
- end
17
+ def render(type)
18
+ self.class.options(caller_locations(1, 1)[0].label.to_sym, {render: type})
77
19
  end
78
20
 
79
- alias :redirect :redirect_302
80
-
81
-
82
- def try_login(username, password)
83
- u = @application.config[:db][:main][:instance][:users].first(login: username)
84
- raise "No such login: #{username}" unless u
85
- if u[:passhash] == Digest::MD5.hexdigest("#{u[:salt]}#{password}")
86
- # success
87
- session[:user_id] = u[:id]
88
- return true
89
- else
90
- # fail
91
- session[:user_id] = nil
92
- raise 'login fail'
93
- return false
94
- end
21
+ def self.options(method, opts)
22
+ __options[method.to_sym] = __options[method.to_sym] ? __options[method.to_sym].merge(opts) : opts
95
23
  end
96
24
 
97
-
98
- def try_register(username, password)
99
- @config[:db][:main][:instance].transaction do
100
- unless @config[:db][:main][:instance][:users].first(:login=>username)
101
- @logger.portion do |l|
102
- salt = SecureRandom.hex(5)
103
- passhash = Digest::MD5.hexdigest("#{salt}#{password}")
104
- @config[:db][:main][:instance][:users].insert(:login=>username, :salt=>salt, :passhash=>passhash)
105
- l.info("create new user login=#{username}, password=#{password}, salt=#{salt}, passhash=#{passhash}")
106
- end
107
- return true, "Registration done"
108
- end
109
- return false, "User with login #{username} already exists"
110
- end
25
+ def set_options(opts = {})
26
+ self.class.options(caller_locations(1, 1)[0].label.to_sym, opts)
111
27
  end
112
28
 
113
-
114
- def try_logout
115
- session[:user_id] = nil
116
- @user = GuestUser
29
+ def self.get_content_type(method)
30
+ o = __options[method]
31
+ o.is_a?(Hash) ? o[:content_type] : nil
117
32
  end
118
33
 
119
- # Store flash message to session
120
- def flash(message)
121
-
34
+ def self.get_render(method)
35
+ o = __options[method]
36
+ o.is_a?(Hash) ? o[:render] : nil
122
37
  end
123
38
  end
124
39
  end
data/lib/alfa/database.rb CHANGED
@@ -1,2 +1,3 @@
1
- #require 'alfa/database/mysql'
2
1
  require 'sequel'
2
+
3
+ Sequel.default_timezone = :utc
@@ -3,6 +3,8 @@ module Alfa
3
3
  # Route not found
4
4
  class Route404 < StandardError; end
5
5
 
6
+ class Route403 < StandardError; end
7
+
6
8
  class HttpRedirect < StandardError
7
9
  attr_reader :url, :code
8
10
  def initialize(url, code)
@@ -10,6 +12,9 @@ module Alfa
10
12
  end
11
13
  end
12
14
 
15
+
16
+ class NoSuchController < StandardError; end
17
+
13
18
  # Application's config.project_root required
14
19
  class E001 < StandardError; end
15
20
 
data/lib/alfa/logger.rb CHANGED
@@ -5,7 +5,7 @@ require 'alfa/support'
5
5
  module Alfa
6
6
  class NullLogger
7
7
  def portion(*args, &block)
8
- l = WeakRef.new(self.class.new)
8
+ l = self.class.new
9
9
  yield(l)
10
10
  end
11
11
 
@@ -22,8 +22,8 @@ module Alfa
22
22
 
23
23
  class Logger < ::Logger
24
24
 
25
- def initialize(logdev, shift_age = 0, shift_size = 1048576)
26
- super
25
+ def initialize(logdev)
26
+ super(nil)
27
27
  @logdev = logdev
28
28
  @formatter = Formatter.new
29
29
  end
@@ -32,6 +32,7 @@ module Alfa
32
32
  io = VirtualIO.new
33
33
  l = Logger.new(io)
34
34
  l.formatter = @formatter
35
+ l.level = @level
35
36
  yield(l)
36
37
  self << io.join
37
38
  flush if kwargs[:sync]
@@ -0,0 +1,29 @@
1
+ module Alfa
2
+ class Resourcer
3
+ def initialize
4
+ @resources = {
5
+ action: {styles: [], scripts:[], added_scripts: []},
6
+ layout: {styles: [], scripts:[], added_scripts: []},
7
+ snippet: {styles: [], scripts:[], added_scripts: []},
8
+ }
9
+ end
10
+
11
+ def [](name)
12
+ @resources[@cursor][name]
13
+ end
14
+
15
+ # @param l Symbol
16
+ def level=(l)
17
+ raise "level should be on of #{@resources.keys}" unless @resources.keys.include?(l)
18
+ @cursor = l
19
+ end
20
+
21
+ def styles
22
+ @resources[:layout][:styles].concat(@resources[:action][:styles]).concat(@resources[:snippet][:styles])
23
+ end
24
+
25
+ def scripts
26
+ @resources[:layout][:scripts].concat(@resources[:action][:scripts]).concat(@resources[:snippet][:scripts])
27
+ end
28
+ end
29
+ end
data/lib/alfa/router.rb CHANGED
@@ -6,6 +6,8 @@ module Alfa
6
6
 
7
7
  class << self
8
8
  attr_accessor :apps_dir
9
+ attr_reader :apps
10
+ attr_reader :mounts
9
11
  end
10
12
 
11
13
  # initialize class variables
@@ -36,6 +38,9 @@ module Alfa
36
38
 
37
39
  def self.reset
38
40
  @routes.clear
41
+ @cursor = @routes
42
+ @cursors_stack = []
43
+ @mounts.clear
39
44
  @apps_dir = nil
40
45
  end
41
46
 
@@ -70,6 +75,7 @@ module Alfa
70
75
  path, a = path.first.to_a
71
76
  app = a.to_sym
72
77
  end
78
+ path = "#{path}/" unless path[-1] == '/'
73
79
  @mounts << {:path => path, :app => app, :options => options}
74
80
  if @apps_dir
75
81
  self.context :app => app do
@@ -122,9 +128,19 @@ module Alfa
122
128
  fail_flag = false
123
129
  rule_segments.zip(url_segments).each do |rule_segment, url_segment|
124
130
  skip_flag = true if rule_segment == '**'
125
- if rule_segment =~ /^:[a-z]+\w*$/i && url_segment =~ /^[a-z0-9_]+$/
126
- pares[rule_segment[1..-1].to_sym] = url_segment.to_sym
127
- elsif (rule_segment == url_segment) || (rule_segment == '*' && url_segment =~ /^[a-z0-9_]+$/) || (rule_segment == nil && skip_flag) || rule_segment == '**'
131
+ if rule_segment =~ /\A:[a-z]+\w*\z/i && url_segment =~ /\A[a-z0-9_]+\z/
132
+ key = rule_segment[1..-1].to_sym
133
+ url_segment = url_segment.to_sym if [:controller, :action].include?(key)
134
+ pares[key] = url_segment
135
+ elsif rule_segment.to_s[-1..-1] == '?'
136
+ key = rule_segment[1..-2].to_sym
137
+ if [:action].include?(key)
138
+ url_segment = url_segment.nil? ? :index : url_segment.to_sym
139
+ else
140
+ url_segment = nil
141
+ end
142
+ pares[key] = url_segment
143
+ elsif (rule_segment == url_segment) || (rule_segment == '*' && url_segment =~ /\A[a-z0-9_]+\z/) || (rule_segment == nil && skip_flag) || rule_segment == '**'
128
144
  else
129
145
  fail_flag = true
130
146
  break
@@ -147,15 +163,17 @@ module Alfa
147
163
  # @return route, params
148
164
  # route is route that given in routes.rb
149
165
  # params is detected params
150
- def self.find_route url
166
+ def self.find_route(url, exclude: [])
151
167
  @routes.each do |route|
152
168
  if route[:context].is_a? Hash # container
153
169
  if self.app_match?(route[:context][:app][:path], url)
154
170
  url = url[(route[:context][:app][:path].length-1)..-1]
155
171
  route[:routes].each do |r|
156
- is_success, params = self.route_match?(r[:rule], url)
157
- r[:options][:app] = route[:context][:app][:app]
158
- return r, params if is_success
172
+ unless exclude.include?(r[:rule])
173
+ is_success, params = self.route_match?(r[:rule], url)
174
+ r[:options][:app] = route[:context][:app][:app]
175
+ return r, params if is_success
176
+ end
159
177
  end
160
178
  raise Alfa::Exceptions::Route404
161
179
  end
@@ -176,13 +194,15 @@ module Alfa
176
194
  if route[:context].is_a?(Hash) # container
177
195
  if route[:context][:app][:app] == kwargs[:app]
178
196
  route[:routes].each do |r|
179
- r[:placeholders] = r[:rule].scan(/:([a-z_][a-z0-9_]*)/).map{|m| m[0].to_sym}.sort unless r[:placeholders]
180
- if (r[:placeholders] - kwargs.keys).empty? &&
181
- (kwargs.keys & r[:options].keys).all?{|key| kwargs[key] == r[:options][key]} &&
182
- (kwargs.keys - [:app] - r[:placeholders] - r[:options].keys).empty?
183
- result = File.join(route[:context][:app][:path], r[:rule].strtr(kwargs.map{|key, value| [":#{key}", value.to_s]}))
184
- result += "?#{::Rack::Utils.build_query(params)}" if params.any?
185
- return result
197
+ unless r[:rule].is_a?(Fixnum)
198
+ r[:placeholders] = r[:rule].scan(/:([a-z_][a-z0-9_]*)/).map{|m| m[0].to_sym}.sort unless r[:placeholders]
199
+ if (r[:placeholders] - kwargs.keys).empty? &&
200
+ (kwargs.keys & r[:options].keys).all?{|key| kwargs[key] == r[:options][key]} &&
201
+ (kwargs.keys - [:app] - r[:placeholders] - r[:options].keys).empty?
202
+ result = File.join(route[:context][:app][:path], r[:rule].strtr(kwargs.map{|key, value| [":#{key}", value.to_s]}))
203
+ result += "?#{::Rack::Utils.build_query(params)}" if params.any?
204
+ return result
205
+ end
186
206
  end
187
207
  end
188
208
  end
@@ -0,0 +1,42 @@
1
+ module Alfa
2
+ class Snippeter
3
+ @snippets = {}
4
+ @config = {}
5
+ @cursor = nil
6
+
7
+ class << self
8
+ attr_accessor :config
9
+ attr_writer :mounts
10
+ end
11
+
12
+ # @param Symbol app
13
+ def self.load
14
+ @mounts.each do |m|
15
+ app = m[:app]
16
+ path = File.join(@config[:project_root], 'apps', app.to_s, 'snippets.rb')
17
+ @cursor = app
18
+ @snippets[@cursor] ||= {}
19
+ if File.exist?(path)
20
+ load_in_instance_context path
21
+ end
22
+ end
23
+ end
24
+
25
+ # @param Symbol name
26
+ # @param Proc &block
27
+ def self.snippet(name, &block)
28
+ raise 'Snippet name should be a Symbol' unless name.is_a?(Symbol)
29
+ raise 'Snippets requires scope' unless @cursor
30
+ @snippets[@cursor][name] = block
31
+ end
32
+
33
+
34
+ def self.[](name)
35
+ if @config[:run_mode] == :development
36
+ @snippets.clear
37
+ self.load
38
+ end
39
+ @snippets[name]
40
+ end
41
+ end
42
+ end