ramaze 0.1.1 → 0.1.2

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