alfa 0.0.5.pre → 0.0.6.pre

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 (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