ramaze 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (193) hide show
  1. data/Rakefile +14 -259
  2. data/bin/ramaze +52 -25
  3. data/doc/AUTHORS +6 -0
  4. data/doc/CHANGELOG +1363 -42
  5. data/doc/INSTALL +1 -1
  6. data/doc/README +48 -35
  7. data/doc/README.html +637 -0
  8. data/doc/TODO +7 -16
  9. data/doc/allison/allison.css +6 -7
  10. data/doc/allison/allison.gif +0 -0
  11. data/doc/allison/cache/STYLE +1 -2
  12. data/doc/changes.txt +3375 -0
  13. data/doc/changes.xml +3378 -0
  14. data/doc/meta/announcement.txt +47 -0
  15. data/doc/meta/configuration.txt +179 -0
  16. data/doc/meta/internals.txt +111 -0
  17. data/doc/readme_chunks/features.txt +8 -16
  18. data/doc/readme_chunks/installing.txt +7 -1
  19. data/doc/tutorial/todolist.txt +2 -3
  20. data/examples/blog/main.rb +9 -8
  21. data/examples/blog/public/styles/blog.css +132 -0
  22. data/examples/blog/src/controller.rb +14 -41
  23. data/examples/blog/src/model.rb +12 -13
  24. data/examples/blog/src/view.rb +16 -0
  25. data/examples/blog/template/edit.xhtml +19 -8
  26. data/examples/blog/template/index.xhtml +14 -22
  27. data/examples/blog/template/new.xhtml +18 -5
  28. data/examples/caching.rb +5 -8
  29. data/examples/element.rb +3 -3
  30. data/examples/hello.rb +3 -5
  31. data/examples/simple.rb +4 -7
  32. data/examples/templates/template/external.haml +8 -7
  33. data/examples/templates/template/external.mab +11 -8
  34. data/examples/templates/template_amrita2.rb +4 -4
  35. data/examples/templates/template_erubis.rb +3 -3
  36. data/examples/templates/template_ezamar.rb +1 -2
  37. data/examples/templates/template_haml.rb +24 -23
  38. data/examples/templates/template_liquid.rb +3 -1
  39. data/examples/templates/template_markaby.rb +15 -9
  40. data/examples/todolist/src/element/page.rb +1 -1
  41. data/lib/proto/conf/benchmark.yaml +6 -20
  42. data/lib/proto/conf/debug.yaml +6 -19
  43. data/lib/proto/conf/live.yaml +7 -19
  44. data/lib/proto/conf/silent.yaml +6 -16
  45. data/lib/proto/conf/stage.yaml +6 -18
  46. data/lib/proto/public/error.zmr +2 -2
  47. data/lib/ramaze.rb +34 -72
  48. data/lib/ramaze/adapter.rb +21 -18
  49. data/lib/ramaze/adapter/mongrel.rb +0 -3
  50. data/lib/ramaze/adapter/webrick.rb +6 -6
  51. data/lib/ramaze/cache/memcached.rb +3 -0
  52. data/lib/ramaze/controller.rb +227 -183
  53. data/lib/ramaze/dispatcher.rb +34 -129
  54. data/lib/ramaze/dispatcher/action.rb +28 -0
  55. data/lib/ramaze/dispatcher/error.rb +43 -0
  56. data/lib/ramaze/dispatcher/file.rb +34 -0
  57. data/lib/ramaze/global.rb +89 -48
  58. data/lib/ramaze/helper/aspect.rb +8 -6
  59. data/lib/ramaze/helper/auth.rb +3 -3
  60. data/lib/ramaze/helper/cache.rb +2 -2
  61. data/lib/ramaze/helper/file.rb +14 -0
  62. data/lib/ramaze/helper/inform.rb +36 -0
  63. data/lib/ramaze/helper/link.rb +7 -3
  64. data/lib/ramaze/helper/markaby.rb +30 -0
  65. data/lib/ramaze/helper/redirect.rb +2 -0
  66. data/lib/ramaze/inform.rb +8 -182
  67. data/lib/ramaze/inform/analogger.rb +19 -0
  68. data/lib/ramaze/inform/growl.rb +28 -0
  69. data/lib/ramaze/inform/hub.rb +26 -0
  70. data/lib/ramaze/inform/informer.rb +92 -0
  71. data/lib/ramaze/inform/informing.rb +44 -0
  72. data/lib/ramaze/inform/syslog.rb +27 -0
  73. data/lib/ramaze/inform/xosd.rb +42 -0
  74. data/lib/ramaze/snippets.rb +6 -2
  75. data/lib/ramaze/snippets/object/traits.rb +13 -1
  76. data/lib/ramaze/snippets/ramaze/autoreload.rb +58 -2
  77. data/lib/ramaze/snippets/string/color.rb +27 -0
  78. data/lib/ramaze/snippets/string/each.rb +6 -0
  79. data/lib/ramaze/snippets/struct/fill.rb +15 -0
  80. data/lib/ramaze/template/ezamar.rb +13 -22
  81. data/lib/ramaze/template/ezamar/element.rb +12 -12
  82. data/lib/ramaze/template/liquid.rb +19 -18
  83. data/lib/ramaze/template/markaby.rb +37 -58
  84. data/lib/ramaze/tool/localize.rb +128 -0
  85. data/lib/ramaze/tool/tidy.rb +51 -21
  86. data/lib/ramaze/trinity.rb +3 -3
  87. data/lib/ramaze/trinity/request.rb +41 -23
  88. data/lib/ramaze/trinity/response.rb +10 -5
  89. data/lib/ramaze/trinity/session.rb +17 -3
  90. data/lib/ramaze/version.rb +2 -2
  91. data/rake_tasks/conf.rake +56 -0
  92. data/rake_tasks/gem.rake +44 -0
  93. data/rake_tasks/maintaince.rake +187 -0
  94. data/spec/all.rb +32 -0
  95. data/spec/examples/caching.rb +19 -0
  96. data/spec/examples/element.rb +15 -0
  97. data/spec/examples/hello.rb +11 -0
  98. data/spec/examples/simple.rb +51 -0
  99. data/spec/examples/templates/template_amrita2.rb +14 -0
  100. data/spec/examples/templates/template_erubis.rb +21 -0
  101. data/spec/examples/templates/template_ezamar.rb +22 -0
  102. data/spec/examples/templates/template_haml.rb +23 -0
  103. data/spec/examples/templates/template_liquid.rb +24 -0
  104. data/spec/examples/templates/template_markaby.rb +21 -0
  105. data/spec/helper.rb +81 -0
  106. data/spec/{spec_helper_context.rb → helper/context.rb} +1 -1
  107. data/spec/helper/layout.rb +55 -0
  108. data/spec/helper/mock_http.rb +66 -0
  109. data/spec/{spec_helper_requester.rb → helper/requester.rb} +0 -6
  110. data/spec/{spec_helper_simple_http.rb → helper/simple_http.rb} +57 -57
  111. data/spec/helper/wrap.rb +193 -0
  112. data/spec/{adapter_spec.rb → ramaze/adapter.rb} +7 -5
  113. data/spec/{tc_adapter_mongrel.rb → ramaze/adapter/mongrel.rb} +2 -2
  114. data/spec/{tc_adapter_webrick.rb → ramaze/adapter/webrick.rb} +2 -2
  115. data/spec/{tc_cache.rb → ramaze/cache.rb} +16 -16
  116. data/spec/ramaze/conf/locale_de.yaml +6 -0
  117. data/spec/ramaze/conf/locale_en.yaml +6 -0
  118. data/spec/ramaze/controller.rb +184 -0
  119. data/spec/ramaze/controller/template/greet.xhtml +1 -0
  120. data/spec/ramaze/controller/template_resolving.rb +54 -0
  121. data/spec/ramaze/dependencies.rb +16 -0
  122. data/spec/{tc_element.rb → ramaze/element.rb} +21 -19
  123. data/spec/ramaze/error.rb +64 -0
  124. data/spec/{tc_gestalt.rb → ramaze/gestalt.rb} +10 -10
  125. data/spec/{tc_global.rb → ramaze/global.rb} +7 -7
  126. data/spec/{tc_helper_aspect.rb → ramaze/helper/aspect.rb} +22 -14
  127. data/spec/{tc_helper_auth.rb → ramaze/helper/auth.rb} +9 -7
  128. data/spec/{tc_helper_cache.rb → ramaze/helper/cache.rb} +14 -24
  129. data/spec/{tc_helper_feed.rb → ramaze/helper/feed.rb} +12 -12
  130. data/spec/ramaze/helper/file.rb +17 -0
  131. data/spec/{tc_helper_flash.rb → ramaze/helper/flash.rb} +16 -17
  132. data/spec/{tc_helper_form.rb → ramaze/helper/form.rb} +25 -26
  133. data/spec/{tc_helper_link.rb → ramaze/helper/link.rb} +9 -9
  134. data/spec/{tc_helper_redirect.rb → ramaze/helper/redirect.rb} +11 -10
  135. data/spec/{tc_helper_stack.rb → ramaze/helper/stack.rb} +10 -11
  136. data/spec/ramaze/inform/informer.rb +40 -0
  137. data/spec/ramaze/inform/syslog.rb +10 -0
  138. data/spec/ramaze/localize.rb +40 -0
  139. data/spec/ramaze/morpher.rb +82 -0
  140. data/spec/ramaze/params.rb +124 -0
  141. data/spec/{public → ramaze/public}/error404.xhtml +0 -0
  142. data/spec/{public → ramaze/public}/favicon.ico +0 -0
  143. data/spec/{public → ramaze/public}/ramaze.png +0 -0
  144. data/spec/{public → ramaze/public}/test_download.css +0 -0
  145. data/spec/ramaze/request.rb +129 -0
  146. data/spec/{tc_request_mongrel.rb → ramaze/request/mongrel.rb} +2 -2
  147. data/spec/{tc_request_webrick.rb → ramaze/request/webrick.rb} +1 -1
  148. data/spec/{tc_session.rb → ramaze/session.rb} +18 -18
  149. data/spec/{tc_store.rb → ramaze/store/default.rb} +10 -10
  150. data/spec/{tc_store_yaml.rb → ramaze/store/yaml.rb} +9 -9
  151. data/spec/ramaze/template.rb +86 -0
  152. data/spec/{tc_template_amrita2.rb → ramaze/template/amrita2.rb} +5 -5
  153. data/spec/{template → ramaze/template}/amrita2/data.amrita +0 -0
  154. data/spec/{template → ramaze/template}/amrita2/index.amrita +0 -0
  155. data/spec/{template → ramaze/template}/amrita2/sum.amrita +0 -0
  156. data/spec/{tc_template_erubis.rb → ramaze/template/erubis.rb} +9 -9
  157. data/spec/{template → ramaze/template}/erubis/sum.rhtml +0 -0
  158. data/spec/ramaze/template/ezamar.rb +62 -0
  159. data/spec/{template → ramaze/template}/ezamar/another/long/action.zmr +0 -0
  160. data/spec/{template → ramaze/template}/ezamar/combined.zmr +0 -0
  161. data/spec/{template → ramaze/template}/ezamar/file_only.zmr +0 -0
  162. data/spec/{template → ramaze/template}/ezamar/index.zmr +0 -0
  163. data/spec/ramaze/template/ezamar/nested.zmr +1 -0
  164. data/spec/{template → ramaze/template}/ezamar/some__long__action.zmr +0 -0
  165. data/spec/{template → ramaze/template}/ezamar/sum.zmr +0 -0
  166. data/spec/{tc_template_haml.rb → ramaze/template/haml.rb} +7 -7
  167. data/spec/{template → ramaze/template}/haml/index.haml +0 -0
  168. data/spec/{template → ramaze/template}/haml/with_vars.haml +0 -0
  169. data/spec/{tc_template_liquid.rb → ramaze/template/liquid.rb} +7 -7
  170. data/spec/{template → ramaze/template}/liquid/index.liquid +0 -0
  171. data/spec/{template → ramaze/template}/liquid/products.liquid +0 -0
  172. data/spec/ramaze/template/markaby.rb +59 -0
  173. data/spec/{template → ramaze/template}/markaby/external.mab +0 -0
  174. data/spec/{template → ramaze/template}/markaby/sum.mab +0 -0
  175. data/spec/ramaze/template/ramaze/external.test +1 -0
  176. data/spec/{tc_tidy.rb → ramaze/tidy.rb} +3 -3
  177. metadata +145 -81
  178. data/examples/blog/public/screen.css +0 -106
  179. data/examples/blog/src/element.rb +0 -58
  180. data/examples/blog/template/view.xhtml +0 -15
  181. data/examples/blog/test/tc_entry.rb +0 -18
  182. data/lib/proto/public/404.jpg +0 -0
  183. data/spec/request_tc_helper.rb +0 -135
  184. data/spec/spec_all.rb +0 -118
  185. data/spec/spec_helper.rb +0 -66
  186. data/spec/tc_controller.rb +0 -49
  187. data/spec/tc_dependencies.rb +0 -13
  188. data/spec/tc_error.rb +0 -43
  189. data/spec/tc_morpher.rb +0 -88
  190. data/spec/tc_params.rb +0 -125
  191. data/spec/tc_template_ezamar.rb +0 -64
  192. data/spec/tc_template_markaby.rb +0 -72
  193. data/spec/template/ezamar/nested.zmr +0 -1
@@ -4,14 +4,24 @@
4
4
  require 'rack'
5
5
  require 'benchmark'
6
6
 
7
+ require 'ramaze/trinity'
8
+
7
9
  # for OSX compatibility
8
10
  Socket.do_not_reverse_lookup = true
9
11
 
12
+ class Rack::Request
13
+ include Ramaze::Request
14
+ end
15
+
16
+ class Rack::Response
17
+ include Ramaze::Response
18
+ end
19
+
10
20
  module Ramaze::Adapter
11
21
  class Base
12
22
  class << self
13
23
  def stop
14
- Informer.debug "Stopping #{self.class}"
24
+ Inform.debug("Stopping #{self.class}")
15
25
  end
16
26
 
17
27
  def call(env)
@@ -20,32 +30,25 @@ module Ramaze::Adapter
20
30
  end
21
31
 
22
32
  def call(env)
23
- if Ramaze::Global.inform_tags.include?(:benchmark)
33
+ if Ramaze::Global.benchmarking
24
34
  time = Benchmark.measure{ respond env }
25
- info "request took #{time.real}s"
35
+ Inform.debug("request took #{time.real}s")
26
36
  else
27
37
  respond env
28
38
  end
29
39
 
30
- @response = Thread.current[:response]
31
-
32
- [@response.status, @response.header, self]
40
+ finish
33
41
  end
34
42
 
35
- def respond env
36
- Ramaze::Dispatcher.handle(::Rack::Request.new(env), ::Rack::Response.new)
37
- end
43
+ def finish
44
+ response = Thread.current[:response]
38
45
 
39
- def each
40
- body = @response.body
46
+ response.finish
47
+ end
41
48
 
42
- if body.respond_to?(:read)
43
- until body.eof?
44
- yield body.read(1024)
45
- end
46
- else
47
- yield body
48
- end
49
+ def respond env
50
+ request, response = Rack::Request.new(env), Rack::Response.new
51
+ Ramaze::Dispatcher.handle(request, response)
49
52
  end
50
53
  end
51
54
  end
@@ -5,9 +5,6 @@ require 'ramaze/adapter'
5
5
 
6
6
  require 'mongrel'
7
7
 
8
- # for OSX compatibility
9
- Socket.do_not_reverse_lookup = true
10
-
11
8
  module Ramaze::Adapter
12
9
  class Mongrel < Base
13
10
  class << self
@@ -3,7 +3,7 @@
3
3
 
4
4
  require 'ramaze/adapter'
5
5
 
6
- require 'webrick'
6
+ require 'rack/handler/webrick'
7
7
 
8
8
  module WEBrick
9
9
  module HTTPServlet
@@ -25,16 +25,16 @@ module Ramaze::Adapter
25
25
  options = {
26
26
  :Port => port,
27
27
  :BindAddress => host,
28
- :Logger => Ramaze::Informer,
28
+ :Logger => Ramaze::Inform,
29
29
  :AccessLog => [
30
- [Ramaze::Informer, WEBrick::AccessLog::COMMON_LOG_FORMAT],
31
- [Ramaze::Informer, WEBrick::AccessLog::REFERER_LOG_FORMAT]
30
+ [Ramaze::Inform, WEBrick::AccessLog::COMMON_LOG_FORMAT],
31
+ [Ramaze::Inform, WEBrick::AccessLog::REFERER_LOG_FORMAT]
32
32
  ]
33
33
  }.merge(options)
34
34
 
35
35
  Thread.new do
36
- Thread.current[:task] = :webrick
37
- Rack::Handler::WEBrick.run(self, options)
36
+ Thread.current[:adapter] =
37
+ Rack::Handler::WEBrick.run(self, options)
38
38
  end
39
39
  end
40
40
  end
@@ -33,6 +33,9 @@ module Ramaze
33
33
 
34
34
  def method_missing(*args, &block)
35
35
  @cache.__send__(*args, &block)
36
+ rescue MemCache::MemCacheError => e
37
+ Ramaze::Inform.error e.to_s
38
+ nil
36
39
  end
37
40
 
38
41
  # out of some reason MemCache sometimes doesn't respond to
@@ -5,249 +5,292 @@ require 'ramaze/template'
5
5
 
6
6
  module Ramaze
7
7
 
8
+ class Action < Struct.new('Action', :method, :params, :template)
9
+ def to_s
10
+ %{#<Action method=#{method.inspect}, params=#{params.inspect} template=#{template.inspect}>}
11
+ end
12
+ end
13
+
8
14
  # The Controller is responsible for combining and rendering actions.
9
15
 
10
16
  class Controller
11
17
  include Ramaze::Helper
12
18
  extend Ramaze::Helper
13
19
 
14
- helper :redirect, :link
20
+ helper :redirect, :link, :file
15
21
 
16
22
  trait :template_extensions => { }
17
23
 
18
24
  # Path to the ramaze-internal public directory for error-pages and the like.
19
25
  # It acts just as a shadow.
20
- trait :public => ( ::Ramaze::BASEDIR / 'proto' / 'public' )
26
+ trait :ramaze_public => ( ::Ramaze::BASEDIR / 'proto' / 'public' )
27
+
28
+ # Whether or not to map this controller on startup automatically
29
+
30
+ trait :automap => true
31
+
32
+ # Place to map the Controller to, this is something like '/' or '/foo'
33
+
34
+ trait :map => nil
35
+
36
+ trait :exclude_action_modules => [Kernel, Object, PP::ObjectMixin]
37
+
38
+ trait :pattern_cache => Hash.new{|h,k| h[k] = Controller.pattern_for(k) }
39
+
40
+ trait :action_cache => Global.cache.new
21
41
 
22
42
  class << self
23
43
  include Ramaze::Helper
24
44
  extend Ramaze::Helper
25
45
 
46
+ def inherited controller
47
+ controller.trait :actions_cached => Set.new
48
+ Global.controllers << controller
49
+ end
50
+
51
+ def validate_sanity
52
+ if path = trait[:public]
53
+ unless File.directory?(path)
54
+ Inform.warn("#{controller} uses templating in #{path}, which does not exist")
55
+ end
56
+ end
57
+ end
58
+
59
+ def mapping
60
+ global_mapping = Global.mapping.invert[self]
61
+ return global_mapping if global_mapping
62
+ if map = class_trait[:map]
63
+ map
64
+ elsif ancestral_trait[:automap]
65
+ name = self.to_s.gsub('Controller', '').split('::').last
66
+ %w[Main Base Index].include?(name) ? '/' : "/#{name.snake_case}"
67
+ end
68
+ end
69
+
70
+ def map(*syms)
71
+ syms.each do |sym|
72
+ Global.mapping[sym.to_s] = self
73
+ end
74
+ end
75
+
76
+ def current
77
+ Thread.current[:controller]
78
+ end
79
+
26
80
  def handle path
27
- controller, action, params = *resolve_controller(path)
28
- action, params = path.gsub(/^\//, '').split('/').join('__'), [] unless action
29
- controller = self unless controller
30
- controller.render action, *params
31
- rescue Ramaze::Error::Template => ex
32
- puts ex
33
- ''
81
+ controller, action = *resolve(path)
82
+ controller.render(action)
34
83
  end
35
84
 
36
- # find out which controller should be used based on the path.
37
- # it will answer [controller, action, params] or raise an
38
- #
39
- # Ramaze::Error::NoController # if no controller is found
40
- # Ramaze::Error::NoAction # if no action but a controller is found
41
- #
42
- # It actually uses #resolve_action on almost every combination of
43
- # so-called paractions (yet unsplit but possible combination of action
44
- # and parameters for the action)
45
- #
46
- # If your templating is action-less, which means it does not depend on
47
- # methods on the controller, but rather on templates or just dynamically
48
- # calculated stuff you can set trait[:actionless] for your templating.
49
- #
50
- # Please see the documentation for Ramaze::Template::Amrita2 for an more
51
- # specific example of how it is used in practice.
52
- #
53
- # Further it uses the Global.mapping to look up the controller to be used.
54
- #
55
- # Also, the action '/' will be expanded to 'index'
85
+
86
+ # #ramaze - 9.5.2007
56
87
  #
57
- # Parameters are CGI.unescaped
88
+ # manveru | if no possible controller is found, it's a NoController error
89
+ # manveru | that would be a 404 then
90
+ # Kashia | aye
91
+ # manveru | if some controller are found but no actions on them, it's NoAction Error for the first controller found, again, 404
92
+ # manveru | everything further down is considered 500
58
93
 
59
- def resolve_controller path
60
- Informer.meth_debug :resolve_controller, path
61
- track = path.split('/')
62
- controller = false
63
- action = false
64
- tracks = []
94
+ def resolve(path)
95
+ #Inform.debug("resolve_controller('#{path}')")
96
+ mapping = Global.mapping
97
+ controllers = Global.controllers
65
98
 
66
- track.unshift '/'
99
+ raise_no_controller(path) if controllers.empty? or mapping.empty?
67
100
 
68
- track.each do |atom|
69
- tracks << (tracks.last.to_s / atom)
70
- end
101
+ patterns = Controller.trait[:pattern_cache][path]
102
+ first_controller = nil
71
103
 
72
- until controller and action or tracks.empty?
73
- current = Regexp.escape(tracks.pop.to_s)
74
- paraction = path.gsub(/^#{current}/, '').split('/').map{|e| CGI.unescape(e)}
75
- paraction.delete('')
76
- if controller = Ramaze::Global.mapping[current] and controller.respond_to?(:render)
77
- if paraction == ['error']
78
-
79
- action = paraction.shift
80
- params = paraction
81
- action = 'index' if action == nil
82
- else
83
- action, params = resolve_action controller, paraction
84
- end
104
+ patterns.each do |controller, method, params|
105
+ if controller = mapping[controller]
106
+ first_controller ||= controller
107
+
108
+ action = controller.resolve_action(method, *params)
109
+ template = action.template
110
+
111
+ action.method ||= File.basename(template, File.extname(template)) if template
112
+
113
+ return controller, action if action.method
85
114
  end
86
115
  end
87
116
 
88
- return controller, action, params
117
+ raise_no_action(first_controller, path) if first_controller
118
+ raise_no_controller(path)
89
119
  end
90
120
 
91
- # Resolve the method to be called and the number of parameters
92
- # it will receive for a specific class (the controller) given the
93
- # paraction (like 'foo/bar' => controller.call('foo', 'bar'))
94
- # in case arity is 1 and a public instance-method named foo is defined.
95
- #
96
- # TODO:
97
- # - find a solution for def x(a = :a) which has arity -1
98
- # identical to def x(*a) for some odd reason
121
+ def resolve_action(path, *parameter)
122
+ path, parameter = path.to_s, parameter.map(&:to_s)
123
+ possible_path = trait["#{path}_template".to_sym]
124
+ template = resolve(possible_path).last.template if possible_path
99
125
 
100
- def resolve_action controller, paraction
101
- Informer.meth_debug :resolve_action, controller, paraction
126
+ method, params = resolve_method(path, *parameter)
102
127
 
103
- meths =
104
- (controller.ancestors - [Kernel, Object]).inject([]) do |sum, klass|
105
- sum | (klass.is_a?(Module) ? klass.instance_methods(false) : sum)
106
- end
128
+ if method or parameter.empty?
129
+ template ||= resolve_template(path)
130
+ end
131
+
132
+ Action.new(method, params, template)
133
+ end
134
+
135
+ def resolve_template(action)
136
+ action = action.to_s
137
+ action_converted = action.split('__').inject{|s,v| s/v}
138
+ actions = [action, action_converted].compact
107
139
 
108
- track = paraction.dup
109
- tracks = []
110
- action = false
140
+ paths = template_paths.map{|pa| actions.map{|a| pa/a } }.flatten.uniq
141
+ glob = "{#{paths.join(',')}}.{#{extension_order.join(',')}}"
142
+
143
+ Dir[glob].first
144
+ end
145
+
146
+ def template_paths
147
+ klass_public = trait[:public]
148
+ ramaze_public = Controller.trait[:ramaze_public]
149
+
150
+ first_path =
151
+ if template_root = class_trait[:template_root]
152
+ template_root
153
+ else
154
+ Global.template_root / Global.mapping.invert[self]
155
+ end
156
+ [ first_path, klass_public, ramaze_public].compact
157
+ end
111
158
 
112
- track.each do |atom|
113
- atom = [tracks.last.to_s, atom]
114
- atom.delete('')
115
- tracks << atom.join('__')
159
+ def resolve_method(name, *params)
160
+ if method = action_methods.delete(name)
161
+ arity = instance_method(method).arity
162
+ if params.size == arity or arity < 0
163
+ return method, params
164
+ end
116
165
  end
166
+ return nil, []
167
+ end
168
+
169
+ def action_methods
170
+ exclude = Controller.trait[:exclude_action_modules]
171
+
172
+ ancs = (ancestors - exclude).select{|a| a.is_a?(Module)}
173
+ ancs.map{|a| a.instance_methods(false).map(&:to_s)}.flatten.uniq
174
+ end
175
+
176
+ def pattern_for(path)
177
+ atoms = path.split('/').grep(/\S/)
178
+ atoms.unshift('')
179
+ patterns, joiners = [], ['/']
180
+
181
+ atoms.size.times do |enum|
182
+ enum += 1
183
+ joiners << '__' if enum == 3
117
184
 
118
- tracks.unshift 'index'
185
+ joiners.each do |joinus|
186
+ pattern = atoms.dup
119
187
 
120
- until action or tracks.empty?
121
- current = tracks.pop
122
- if meths.include?(current) #or current = controller.ancestral_trait[:template_map][current]
123
- arity = controller.instance_method(current).arity
124
- params = (paraction - current.split('__'))
188
+ controller = pattern[0, enum].join(joinus)
189
+ controller.gsub!(/^__/, '/')
190
+ controller = "/" if controller == ""
125
191
 
126
- if params.size == arity
127
- return current, params
128
- elsif arity < 0
129
- return current, params
192
+ pattern = pattern[enum..-1]
193
+ args, temp = [], []
194
+
195
+ patterns << [controller, 'index', atoms[enum..-1]]
196
+
197
+ until pattern.empty?
198
+ args << pattern.shift
199
+ patterns << [controller, args.join( '__' ), pattern.dup]
130
200
  end
131
201
  end
132
202
  end
203
+
204
+ patterns.reverse!
133
205
  end
134
206
 
135
- # The universal #render method that has to be provided by every
136
- # prospective Controller, pass it your action and parameters.
137
- #
138
- # This is called upon by the Dispatcher, but you can use it in your
139
- # Controller/View to get the contents of another action.
140
- #
141
- # It will set the instance-variable @action in the instance of itself
142
- # to the value of the current action.
207
+ def extension_order
208
+ t_extensions = Controller.trait[:template_extensions]
209
+ engine = trait[:engine]
210
+ c_extensions = t_extensions.reject{|k,v| v != engine}.keys
211
+ all_extensions = t_extensions.keys
212
+ (c_extensions + all_extensions).uniq
213
+ end
143
214
 
144
- def render action, *parameter
145
- trait[:actions_cached] ||= Set.new
215
+ def render(action = {})
216
+ action = Action.fill(action) if action.is_a?(Hash)
217
+ Inform.debug("The Action: #{action}")
146
218
 
147
- cache_indicators = [
148
- Global.cache_all,
149
- ancestral_trait[:cache_all],
150
- ancestral_trait[:actions_cached].map{|k| k.to_s}.include?(action.to_s),
151
- ]
219
+ action.method = action.method.to_s
220
+ action.params.compact!
152
221
 
153
- if cache_indicators.any?
154
- cached_render(action, *parameter)
222
+ if cached?(action)
223
+ cached_render(action)
155
224
  else
156
- uncached_render(action, *parameter)
225
+ uncached_render(action)
157
226
  end
158
227
  end
159
228
 
160
- def uncached_render action, *parameter
161
- controller = self.new
162
- controller.instance_variable_set('@action', action)
229
+ def cached?(action)
230
+ actions_cached = trait[:actions_cached]
231
+
232
+ [ Global.cache_all,
233
+ trait[:cache_all],
234
+ actions_cached.map{|k| k.to_s}.include?(action.method),
235
+ ].any?
236
+ end
163
237
 
164
- file = find_template(action)
165
- engine = ancestral_trait[:engine] || engine_for(file)
238
+ def uncached_render(action)
239
+ controller = self.new
240
+ controller.instance_variable_set('@action', action.method)
241
+ Thread.current[:controller] = controller
166
242
 
167
243
  options = {
168
- :file => file,
169
- :binding => controller.send(:send, :binding),
170
- :action => action,
171
- :parameter => parameter,
244
+ :file => action.template,
245
+ :binding => controller.instance_eval{ binding },
246
+ :action => action.method,
247
+ :parameter => action.params,
172
248
  }
249
+
250
+ engine = select_engine(options[:file])
173
251
  engine.transform(controller, options)
174
252
  end
175
253
 
176
- def cached_render action, *parameter
177
- key = [action, parameter].inspect
178
-
179
- trait[:action_cache] ||= Global.cache.new
254
+ def cached_render action
255
+ action_cache = Controller.trait[:action_cache]
180
256
 
181
- if out = ancestral_trait[:action_cache][key]
182
- Informer.debug "Using Cached version for #{key}"
257
+ if out = action_cache[action]
258
+ Inform.debug("Using Cached version for #{action}")
183
259
  return out
184
260
  end
185
261
 
186
- Informer.debug "Compiling Action: #{action} #{parameter.join(', ')}"
187
- ancestral_trait[:action_cache][key] = uncached_render(action, *parameter)
262
+ Inform.debug("Compiling Action: #{action}")
263
+ action_cache[action] = uncached_render(action)
188
264
  end
189
265
 
190
- # This finds the template for the given action on the current controller
191
- # there are some basic ways how you can provide an alternative path:
192
- #
193
- # Global.template_root = 'default/path'
194
- #
195
- # class FooController < Controller
196
- # trait :template_root => 'another/path'
197
- # trait :index_template => :foo
198
- #
199
- # def index
200
- # end
201
- # end
202
- #
203
- # One feature also used in the above example is the custom template for
204
- # one action, in this case :index - now the template of :foo will be
205
- # used instead.
206
-
207
- def find_template action, klass = self
208
- custom_template = ancestral_trait["#{action}_template".intern]
209
- action = (custom_template ? custom_template : action).to_s
210
- action_converted = action.split('__').inject {|s,v| "#{s}/#{v}"}
211
-
212
- first_path =
213
- if template_root = klass.ancestral_trait[:template_root]
214
- template_root
215
- else
216
- Global.template_root / Global.mapping.invert[self]
217
- end
218
-
219
- extensions = [ancestral_trait[:template_extensions].values].flatten.uniq
266
+ def select_engine(file)
267
+ trait_engine = class_trait[:engine]
268
+ default = [trait_engine, Template::Ezamar].compact.first
269
+ return default unless file
220
270
 
221
- paths = [ first_path, ancestral_trait[:public], ].
222
- map{|pa| [ pa / action, pa / action_converted ] }.
223
- flatten.map{|pa| File.expand_path(pa) }.join(',')
271
+ engines = Controller.trait[:template_extensions]
272
+ return default if engines.empty?
224
273
 
225
- glob = "{#{paths}}.{#{extensions.join(',')}}"
226
-
227
- possible = Dir[glob]
228
- possible.first
229
- end
230
-
231
- # lookup the trait[:template_extensions] for the extname of the filename
232
- # you pass.
233
- #
234
- # Answers with the engine that matches the extension, Template::Ezamar
235
- # is used if none matches.
236
-
237
- def engine_for file
238
- file = file.to_s
239
- extension = File.extname(file).gsub(/^\./, '')
240
- engines = trait[:template_extensions]
241
- engines.find{|k,v| v == extension or [v].flatten.include?(extension)}.first
242
- rescue
243
- Template::Ezamar
274
+ ext = File.extname(file).gsub(/^\./, '')
275
+ ext_engine = engines[ext]
276
+ return ext_engine ? ext_engine : default
244
277
  end
245
278
 
246
279
  # This method is called by templating-engines to register themselves with
247
280
  # a list of extensions that will be looked up on #render of an action.
248
281
 
249
282
  def register_engine engine, *extensions
250
- trait[:template_extensions][engine] = [extensions].flatten.uniq
283
+ extensions.flatten.each do |ext|
284
+ trait[:template_extensions][ext] = engine
285
+ end
286
+ end
287
+
288
+ def raise_no_controller(path)
289
+ raise Ramaze::Error::NoController, "No Controller found for `#{path}'"
290
+ end
291
+
292
+ def raise_no_action(controller, path)
293
+ raise Ramaze::Error::NoAction, "No Action found for `#{path}' on #{controller}"
251
294
  end
252
295
  end
253
296
 
@@ -261,34 +304,35 @@ module Ramaze
261
304
 
262
305
  def error
263
306
  error = Thread.current[:exception]
264
- backtrace = error.backtrace[0..20]
307
+ @backtrace = error.backtrace[0..20]
265
308
  title = error.message
266
309
 
267
- colors = []
310
+ @colors = []
268
311
  min = 200
269
312
  max = 255
270
- step = -((max - min) / backtrace.size).abs
313
+ step = -((max - min) / @backtrace.size).abs
271
314
  max.step(min, step) do |color|
272
- colors << color
315
+ @colors << color
273
316
  end
274
317
 
275
- backtrace.map! do |line|
318
+ backtrace_size = Ramaze::Global.backtrace_size
319
+
320
+ @backtrace.map! do |line|
276
321
  file, lineno, meth = *Ramaze.parse_backtrace(line)
277
- backtrace_size = Ramaze::Global.inform_backtrace_size
278
322
  lines = Ramaze.caller_lines(file, lineno, backtrace_size)
279
323
 
280
324
  [ lines, lines.object_id.abs, file, lineno, meth ]
281
325
  end
282
326
 
283
- response.status = 404
284
-
285
- @backtrace = backtrace
286
- @colors = colors
287
327
  @title = CGI.escapeHTML(title)
288
328
  require 'coderay'
289
329
  @coderay = true
330
+ title
290
331
  rescue LoadError => ex
291
332
  @coderay = false
333
+ title
334
+ rescue Object => ex
335
+ Inform.error(ex)
292
336
  end
293
337
 
294
338
  private