ramaze 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. data/Rakefile +14 -29
  2. data/bin/ramaze +2 -3
  3. data/doc/AUTHORS +5 -2
  4. data/doc/CHANGELOG +262 -9
  5. data/doc/FAQ +6 -6
  6. data/doc/meta/announcement.txt +5 -19
  7. data/doc/tutorial/todolist.html +47 -57
  8. data/doc/tutorial/todolist.mkd +47 -55
  9. data/examples/memleak_detector.rb +31 -0
  10. data/examples/todolist/src/controller/main.rb +14 -13
  11. data/examples/todolist/src/element/page.rb +2 -2
  12. data/examples/todolist/src/model.rb +2 -2
  13. data/examples/todolist/todolist.db +0 -4
  14. data/examples/whywiki/main.rb +2 -2
  15. data/examples/whywiki/template/edit.xhtml +1 -1
  16. data/examples/whywiki/template/show.xhtml +3 -3
  17. data/lib/proto/src/controller/main.rb +18 -1
  18. data/lib/proto/template/index.xhtml +11 -2
  19. data/lib/ramaze.rb +1 -1
  20. data/lib/ramaze/action.rb +104 -5
  21. data/lib/ramaze/action/render.rb +54 -0
  22. data/lib/ramaze/adapter.rb +2 -1
  23. data/lib/ramaze/adapter/mongrel.rb +13 -4
  24. data/lib/ramaze/cache.rb +17 -8
  25. data/lib/ramaze/cache/memcached.rb +1 -5
  26. data/lib/ramaze/controller.rb +51 -18
  27. data/lib/ramaze/controller/resolve.rb +19 -14
  28. data/lib/ramaze/dispatcher.rb +13 -16
  29. data/lib/ramaze/dispatcher/action.rb +2 -3
  30. data/lib/ramaze/dispatcher/error.rb +8 -3
  31. data/lib/ramaze/dispatcher/file.rb +1 -4
  32. data/lib/ramaze/error.rb +5 -5
  33. data/lib/ramaze/global.rb +7 -1
  34. data/lib/ramaze/global/globalstruct.rb +1 -3
  35. data/lib/ramaze/helper/aspect.rb +8 -10
  36. data/lib/ramaze/helper/cgi.rb +21 -3
  37. data/lib/ramaze/helper/identity.rb +4 -6
  38. data/lib/ramaze/helper/link.rb +4 -4
  39. data/lib/ramaze/helper/pager.rb +316 -0
  40. data/lib/ramaze/helper/partial.rb +37 -0
  41. data/lib/ramaze/helper/stack.rb +1 -1
  42. data/lib/ramaze/inform.rb +9 -0
  43. data/lib/ramaze/inform/hub.rb +5 -0
  44. data/lib/ramaze/inform/informer.rb +12 -6
  45. data/lib/ramaze/inform/informing.rb +32 -7
  46. data/lib/ramaze/inform/knotify.rb +21 -0
  47. data/lib/ramaze/inform/xosd.rb +58 -24
  48. data/lib/ramaze/sourcereload.rb +30 -1
  49. data/lib/ramaze/template.rb +33 -12
  50. data/lib/ramaze/template/amrita2.rb +21 -20
  51. data/lib/ramaze/template/erubis.rb +18 -14
  52. data/lib/ramaze/template/ezamar.rb +15 -26
  53. data/lib/ramaze/template/ezamar/element.rb +1 -1
  54. data/lib/ramaze/template/ezamar/engine.rb +45 -36
  55. data/lib/ramaze/template/ezamar/morpher.rb +3 -3
  56. data/lib/ramaze/template/ezamar/render_partial.rb +26 -0
  57. data/lib/ramaze/template/haml.rb +23 -18
  58. data/lib/ramaze/template/liquid.rb +5 -3
  59. data/lib/ramaze/template/markaby.rb +14 -11
  60. data/lib/ramaze/template/remarkably.rb +11 -5
  61. data/lib/ramaze/tool/localize.rb +12 -4
  62. data/lib/ramaze/tool/tidy.rb +26 -23
  63. data/lib/ramaze/trinity/request.rb +11 -7
  64. data/lib/ramaze/trinity/session.rb +24 -8
  65. data/lib/ramaze/version.rb +1 -1
  66. data/rake_tasks/maintaince.rake +136 -11
  67. data/spec/examples/templates/template_liquid.rb +6 -3
  68. data/spec/examples/todolist.rb +1 -2
  69. data/spec/helper/minimal.rb +7 -7
  70. data/spec/ramaze/action/basics.rb +19 -0
  71. data/spec/ramaze/action/render.rb +18 -0
  72. data/spec/ramaze/controller.rb +1 -1
  73. data/spec/ramaze/controller/template_resolving.rb +1 -1
  74. data/spec/ramaze/dispatcher/file.rb +24 -0
  75. data/spec/ramaze/error.rb +28 -29
  76. data/spec/ramaze/helper/cgi.rb +43 -0
  77. data/spec/ramaze/helper/pager.rb +27 -0
  78. data/spec/ramaze/helper/partial.rb +38 -0
  79. data/spec/ramaze/helper/template/partial.xhtml +1 -0
  80. data/spec/ramaze/inform/informer.rb +1 -1
  81. data/spec/ramaze/localize.rb +1 -1
  82. data/spec/ramaze/morpher.rb +3 -3
  83. data/spec/ramaze/request.rb +1 -3
  84. data/spec/ramaze/template.rb +9 -7
  85. data/spec/ramaze/template/haml.rb +2 -1
  86. metadata +21 -7
  87. data/examples/todolist/public/404.jpg +0 -0
  88. data/examples/todolist/public/error.xhtml +0 -74
  89. data/lib/ramaze/controller/render.rb +0 -90
@@ -0,0 +1,31 @@
1
+ # Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
2
+ # All files in this distribution are subject to the terms of the Ruby license.
3
+
4
+ require 'ramaze'
5
+
6
+ # you can access it now with http://localhost:7000/
7
+ # This should output
8
+ # Hello, World!
9
+ # in your browser
10
+
11
+ class MainController < Ramaze::Controller
12
+ def index
13
+ "Hello, World!"
14
+ end
15
+ end
16
+
17
+ def check
18
+ os = []
19
+ ObjectSpace.each_object{|o| os << o }
20
+ p os.inject(Hash.new(0)){|s,v| s[v.class] += 1; s}.sort_by{|k,v| v}
21
+ end
22
+
23
+ Thread.new do
24
+ loop do
25
+ check
26
+ sleep 5
27
+ end
28
+ end
29
+
30
+ Ramaze::Inform.loggers.clear
31
+ Ramaze.start :adapter => :mongrel, :sourcereload => false
@@ -1,14 +1,19 @@
1
1
  # Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
2
2
  # All files in this distribution are subject to the terms of the Ruby license.
3
3
 
4
- class MainController < Controller
4
+ # Default url mappings are:
5
+ # a controller called Main is mapped on the root of the site: /
6
+ # a controller called Something is mapped on: /something
7
+ # If you want to override this, add a line like this inside the class
8
+ # map '/otherurl'
9
+ # this will force the controller to be mounted on: /otherurl
5
10
 
6
- helper :aspect
11
+ class MainController < Controller
7
12
 
8
13
  def index
9
14
  @tasks = []
10
- TodoList.original.each do |title, parameters|
11
- if parameters[:done]
15
+ TodoList.original.each do |title, value|
16
+ if value[:done]
12
17
  status = 'done'
13
18
  toggle = A('Open Task', :href => Rs(:open, title))
14
19
  else
@@ -25,7 +30,7 @@ class MainController < Controller
25
30
  if title = request['title']
26
31
  title.strip!
27
32
  if title.empty?
28
- error("Please enter a title")
33
+ failed("Please enter a title")
29
34
  redirect '/new'
30
35
  end
31
36
  TodoList[title] = {:done => false}
@@ -44,22 +49,18 @@ class MainController < Controller
44
49
  TodoList.delete title
45
50
  end
46
51
 
47
- after(:create, :open, :close, :delete){ redirect_index }
48
-
49
- def redirect_index
50
- redirect(Rs())
51
- end
52
+ helper :aspect
53
+ after(:create, :open, :close, :delete){ redirect(Rs()) }
52
54
 
53
55
  private
54
56
 
55
- def error(message)
57
+ def failed(message)
56
58
  flash[:error] = message
57
59
  end
58
60
 
59
61
  def task_status title, status
60
- p title
61
62
  unless task = TodoList[title]
62
- error "No such Task: `#{title}'"
63
+ failed "No such Task: `#{title}'"
63
64
  redirect_referer
64
65
  end
65
66
 
@@ -3,7 +3,7 @@
3
3
 
4
4
  class Page < Ezamar::Element
5
5
  def render
6
- %(
6
+ %{
7
7
  <html>
8
8
  <head>
9
9
  <title>TodoList</title>
@@ -26,6 +26,6 @@ class Page < Ezamar::Element
26
26
  #{content}
27
27
  </body>
28
28
  </html>
29
- )
29
+ }
30
30
  end
31
31
  end
@@ -9,6 +9,6 @@ TodoList = Ramaze::Store::Default.new('todolist.db')
9
9
  'Laundry' => {:done => false},
10
10
  'Wash dishes' => {:done => false},
11
11
 
12
- }.each do |task, parameters|
13
- TodoList[task] = parameters
12
+ }.each do |title, value|
13
+ TodoList[title] = value
14
14
  end
@@ -1,9 +1,5 @@
1
1
  ---
2
2
  Wash dishes:
3
3
  :done: false
4
- foobar:
5
- :done: false
6
4
  Laundry:
7
5
  :done: false
8
- implement:
9
- :done: false
@@ -16,7 +16,7 @@ class WikiController < Controller
16
16
  end
17
17
 
18
18
  def show page = 'Home'
19
- @page = page
19
+ @page = CGI.unescape(page)
20
20
  @text = Db[page].to_s
21
21
 
22
22
  @text.gsub!(/\[\[(.*?)\]\]/) do |m|
@@ -28,7 +28,7 @@ class WikiController < Controller
28
28
  end
29
29
 
30
30
  def edit page = 'Home'
31
- @page = page
31
+ @page = CGI.unescape(page)
32
32
  @text = Db[page]
33
33
  end
34
34
 
@@ -2,7 +2,7 @@
2
2
  <head>
3
3
  <title>MicroWiki Edit #{@page}</title>
4
4
  </head>
5
- #{ link(R(self), :title => "&lt; Home") }
5
+ #{ A("&lt; Home", :href => R(self)) }
6
6
  <body>
7
7
  <h1>Edit #{@page}</h1>
8
8
  <form method="POST" action="#{R(self, :save)}">
@@ -6,14 +6,14 @@
6
6
  a.nonexists{ color: #f00; }
7
7
  </style>
8
8
  </head>
9
- #{ link(R(self), :title => "&lt; Home") unless @page == "Home" }
9
+ #{ A("&lt; Home", :href => R(self)) unless @page == "Home" }
10
10
  <body>
11
11
  <h1>#{@page}</h1>
12
12
  <?r if @text.empty? ?>
13
- #{ link(R(self, :edit, CGI.escape(@page)), :title => "Create #{@page}?") }
13
+ #{ A("Create #{@page}?",:href => R(self, :edit, CGI.escape(@page))) }
14
14
  <?r else ?>
15
15
  <div>
16
- #{ link(R(self, :edit, CGI.escape(@page)), :title => "Edit #{@page}") }
16
+ #{ A("Edit #{@page}?", :href => R(self, :edit, CGI.escape(@page))) }
17
17
  #{@text}
18
18
  </div>
19
19
  <?r end ?>
@@ -1,8 +1,25 @@
1
1
  # Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
2
2
  # All files in this distribution are subject to the terms of the Ruby license.
3
3
 
4
+ # Default url mappings are:
5
+ # a controller called Main is mapped on the root of the site: /
6
+ # a controller called Something is mapped on: /something
7
+ # If you want to override this, add a line like this inside the class
8
+ # map '/otherurl'
9
+ # this will force the controller to be mounted on: /otherurl
10
+
4
11
  class MainController < Controller
12
+
13
+ # the index action is called automatically when no other action is specified
5
14
  def index
6
- "Hello, World"
15
+ @welcome = "Welcome to Ramaze!"
7
16
  end
17
+
18
+ # the string returned at the end of the function is used as the html body
19
+ # if there is no template for the action. if there is a template, the string
20
+ # is silently ignored
21
+ def notemplate
22
+ "there is no template associated with this action"
23
+ end
24
+
8
25
  end
@@ -1,6 +1,15 @@
1
1
  <Page>
2
- <h1>Welcome to Ramaze</h1>
2
+ <h1>#{@welcome}</h1>
3
+ <p>Ramaze is working correctly with this application, now you can start working</p
4
+
3
5
  <p>
4
- blah, blah, blah
6
+ To start you can modify:
7
+ <ol>
8
+ <li><code>template/index.xhtml</code>, which this text</li>
9
+ <li><code>src/elements/page.rb</code>, which is the Element around this text</li>
10
+ <li><code>src/controllers/main.rb</code>, where you can change the header of this page and the <a href="/notemplate">notemplate</a> action</li>
11
+ <li><code>src/model.rb</code>, which is the the persistent backend for your app</li>
12
+ </ol>
5
13
  </p>
14
+ <p>You can also read the tutorial in the <code>doc/</code> directory of ramaze or browse the <a href="http://ramaze.rubyforge.org/rdoc/files/doc/README.html">rdocs</a><p>
6
15
  </Page>
@@ -30,7 +30,7 @@ module Ramaze
30
30
  # Each of these classes will be called ::startup upon Ramaze.startup
31
31
 
32
32
  trait :essentials => [
33
- Global, Controller, Session, SourceReload, Adapter
33
+ Global, Cache, Controller, Session, SourceReload, Adapter
34
34
  ]
35
35
 
36
36
  class << self
@@ -5,17 +5,116 @@ module Ramaze
5
5
 
6
6
  unless defined?(Action) # prevent problems for SourceReload
7
7
 
8
+ members = %w[method params template controller path binding engine instance]
9
+
8
10
  # The Action holds information that is essential to render the action for a
9
11
  # request.
10
12
 
11
- class Action < Struct.new('Action', :controller, :method, :params, :template, :binding)
12
- def to_s
13
- %{#<Action method=#{method.inspect}, params=#{params.inspect} template=#{template.inspect}>}
13
+ class Action < Struct.new('Action', *members)
14
+ end
15
+ end
16
+
17
+ require 'ramaze/action/render'
18
+
19
+ class Action
20
+ class << self
21
+
22
+ # Instantiate with given Hash, takes both string/symbol keys.
23
+ # Only keys that match members of the Action-Struct are used.
24
+
25
+ def create(hash = {})
26
+ i = new
27
+ members.each do |key|
28
+ i.send("#{key}=", (hash[key] || hash[key.to_sym]))
29
+ end
30
+ i
14
31
  end
15
32
 
16
- def params=(*par)
17
- self[:params] = par.flatten.map{|pa| CGI.unescape(pa)}
33
+ # Thread.current[:action] returns the instance of Action you are currently in.
34
+
35
+ def current
36
+ Thread.current[:action]
18
37
  end
19
38
  end
39
+
40
+ # nicer representation of the Action
41
+
42
+ def to_s
43
+ m, p, t = method.inspect, params.inspect, template.inspect
44
+ %{#<Action method=#{m}, params=#{p} template=#{t}>}
45
+ end
46
+
47
+ # Set the method, will be converted to a string and set to nil if empty.
48
+
49
+ def method=(meth)
50
+ meth = meth.to_s
51
+ self[:method] = (meth.empty? ? nil : meth)
52
+ end
53
+
54
+ # runs all parameters assigned through flatten and CGI::unescape
55
+
56
+ def params=(*par)
57
+ self[:params] = par.flatten.compact.map{|pa| CGI.unescape(pa.to_s)}
58
+ end
59
+
60
+ # Use this as key for caches.
61
+
62
+ def relaxed_hash
63
+ [controller, method, params, template, path].hash
64
+ end
65
+
66
+ # A Hash representation of Action
67
+
68
+ def to_hash
69
+ hash = {}
70
+ members.each{|m| hash[m.to_sym] = send(m)}
71
+ hash
72
+ end
73
+
74
+ # Determines based on controller.trait[:engine] and the template extensions
75
+ # which engine has to be used.
76
+ # Defaults to Template::Ezamar
77
+
78
+ def engine
79
+ return self[:engine] if self[:engine]
80
+ default = controller.trait.fetch(:engine, Template::Ezamar)
81
+ return default unless template
82
+
83
+ engines = Template::ENGINES
84
+ return default if engines.empty?
85
+
86
+ ext = File.extname(template).gsub(/^\./, '')
87
+ ext_engine = engines.find{|e| e.last.include?(ext)}.first
88
+
89
+ self[:engine] = (ext_engine || default)
90
+ end
91
+
92
+ # Returns an instance of controller, will be cached on first access.
93
+
94
+ def instance
95
+ self[:instance] ||= controller.new
96
+ end
97
+
98
+ # Returns a binding of the instance, will be cached on first access.
99
+
100
+ def binding
101
+ self[:binding] ||= instance.instance_eval{ binding }
102
+ end
103
+
104
+ # Hook for AspectHelper
105
+
106
+ def before_process
107
+ end
108
+
109
+ # Hook for AspectHelper
110
+
111
+ def after_process
112
+ end
113
+ end
114
+
115
+ # Shortcut to create new instances of Action via Action::fill
116
+
117
+ def self.Action(hash = {})
118
+ Action.create(hash)
20
119
  end
21
120
  end
@@ -0,0 +1,54 @@
1
+ # Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
2
+ # All files in this distribution are subject to the terms of the Ruby license.
3
+
4
+ module Ramaze
5
+ class Action
6
+
7
+ # Render this instance of Action, this will (eventually) pass itself to
8
+ # Action#engine.transform
9
+ # Usage, given that Foo is a Controller and has the method/template
10
+ # for index:
11
+ # > Action(:controller => Foo).render
12
+ # #> 'bar'
13
+
14
+ def render
15
+ Inform.debug("The Action: #{self}")
16
+ Thread.current[:action] = self
17
+
18
+ if should_cache?
19
+ cached_render
20
+ else
21
+ uncached_render
22
+ end
23
+ end
24
+
25
+ def cached_render
26
+ action_cache = Cache.actions
27
+
28
+ if out = action_cache[relaxed_hash]
29
+ Inform.debug("Using Cached version")
30
+ return out
31
+ end
32
+
33
+ Inform.debug("Compiling Action")
34
+ action_cache[relaxed_hash] = uncached_render
35
+ end
36
+
37
+ def uncached_render
38
+ [ before_process,
39
+ engine.transform(self),
40
+ after_process,
41
+ ].join
42
+ end
43
+
44
+ def should_cache?
45
+ ctrait = controller.trait
46
+ actions_cached = ctrait[:actions_cached]
47
+
48
+ [ Global.cache_all,
49
+ ctrait[:cache_all],
50
+ actions_cached.map{|k| k.to_s}.include?(method),
51
+ ].any?
52
+ end
53
+ end
54
+ end
@@ -85,7 +85,8 @@ module Ramaze
85
85
  end
86
86
  end
87
87
  rescue Timeout::Error
88
- Global.adapters.list.each{|a| a.kill!}
88
+ Global.adapters.list.each{|a| a.kill! }
89
+ # Hard exit! because it won't be able to kill Webrick otherwise
89
90
  exit!
90
91
  end
91
92
 
@@ -1,11 +1,20 @@
1
1
  # Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
2
2
  # All files in this distribution are subject to the terms of the Ruby license.
3
3
 
4
- require 'ramaze/adapter'
5
- require 'mongrel'
6
- require 'rack/handler/mongrel'
7
-
8
4
  module Ramaze
5
+ if ENV['SWIFT']
6
+ require 'swiftcore/swiftiplied_mongrel'
7
+ Inform.debug "Using Swiftiplied Mongrel"
8
+ elsif ENV['EVENT']
9
+ require 'swiftcore/evented_mongrel'
10
+ Inform.debug "Using Evented Mongrel"
11
+ else
12
+ require 'mongrel'
13
+ end
14
+
15
+ require 'ramaze/adapter'
16
+ require 'rack/handler/mongrel'
17
+
9
18
  module Adapter
10
19
  class Mongrel < Base
11
20
  class << self
@@ -12,18 +12,27 @@ module Ramaze
12
12
 
13
13
  class Cache
14
14
  include Enumerable
15
- CACHES = {}
15
+ CACHES = {} unless defined?(CACHES)
16
16
 
17
- # This will define a method to access a new cache directly over
18
- # sinleton-methods on Cache
17
+ class << self
19
18
 
20
- def self.add *keys
21
- keys.each do |key|
22
- CACHES[key] = new
23
- self.class.class_eval do
24
- define_method(key){ CACHES[key] }
19
+ def startup(options)
20
+ Cache.add :compiled, :actions, :patterns, :resolved, :shield
21
+ end
22
+
23
+ # This will define a method to access a new cache directly over
24
+ # sinleton-methods on Cache
25
+
26
+ def add *keys
27
+ keys.each do |key|
28
+ CACHES[key] = new
29
+ self.class.class_eval do
30
+ define_method(key){ CACHES[key] }
31
+ end
25
32
  end
33
+ Inform.debug("Added caches for: #{keys.join(', ')}")
26
34
  end
35
+
27
36
  end
28
37
 
29
38
  def initialize(cache = Global.cache)