manveru-ramaze 2008.07 → 2008.08

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 (51) hide show
  1. data/Rakefile +31 -2
  2. data/doc/meta/announcement.txt +16 -32
  3. data/examples/app/rapaste/controller/paste.rb +7 -0
  4. data/examples/app/sourceview/public/sourceview.js +2 -2
  5. data/lib/proto/view/error.xhtml +3 -3
  6. data/lib/ramaze/action.rb +2 -2
  7. data/lib/ramaze/adapter/base.rb +10 -19
  8. data/lib/ramaze/cache/memcached.rb +3 -5
  9. data/lib/ramaze/controller/resolve.rb +14 -4
  10. data/lib/ramaze/controller.rb +15 -11
  11. data/lib/ramaze/current/request.rb +6 -3
  12. data/lib/ramaze/current/session/flash.rb +8 -0
  13. data/lib/ramaze/dispatcher/error.rb +3 -3
  14. data/lib/ramaze/dispatcher.rb +5 -5
  15. data/lib/ramaze/gestalt.rb +8 -8
  16. data/lib/ramaze/helper/cgi.rb +1 -1
  17. data/lib/ramaze/helper/formatting.rb +8 -1
  18. data/lib/ramaze/helper/thread.rb +17 -0
  19. data/lib/ramaze/helper/ultraviolet.rb +44 -0
  20. data/lib/ramaze/helper/user.rb +4 -9
  21. data/lib/ramaze/option/holder.rb +1 -11
  22. data/lib/ramaze/option.rb +3 -3
  23. data/lib/ramaze/reloader.rb +186 -0
  24. data/lib/ramaze/setup.rb +1 -1
  25. data/lib/ramaze/snippets/dictionary.rb +2 -2
  26. data/lib/ramaze/snippets/fiber.rb +63 -0
  27. data/lib/ramaze/snippets/numeric/time.rb +10 -10
  28. data/lib/ramaze/snippets/ramaze/deprecated.rb +4 -2
  29. data/lib/ramaze/snippets/ramaze/fiber.rb +24 -0
  30. data/lib/ramaze/snippets/ramaze/state.rb +86 -0
  31. data/lib/ramaze/sourcereload.rb +1 -0
  32. data/lib/ramaze/template/maruku.rb +34 -0
  33. data/lib/ramaze/template.rb +4 -1
  34. data/lib/ramaze/tool/mime.rb +11 -1
  35. data/lib/ramaze/trinity.rb +4 -1
  36. data/lib/ramaze/version.rb +1 -1
  37. data/lib/ramaze.rb +2 -2
  38. data/rake_tasks/gem.rake +6 -0
  39. data/ramaze.gemspec +11 -5
  40. data/spec/ramaze/action/file_cache.rb +22 -0
  41. data/spec/ramaze/controller/actionless_templates.rb +1 -1
  42. data/spec/ramaze/controller/subclass.rb +15 -0
  43. data/spec/ramaze/controller/template_resolving.rb +1 -1
  44. data/spec/ramaze/controller/view/bar.xhtml +1 -0
  45. data/spec/ramaze/controller/view/base/another.xhtml +1 -0
  46. data/spec/ramaze/helper/aspect.rb +26 -17
  47. data/spec/ramaze/route.rb +1 -1
  48. data/spec/ramaze/template/tagz.rb +1 -1
  49. metadata +11 -5
  50. data/lib/ramaze/snippets/object/thread_accessor.rb +0 -5
  51. data/lib/ramaze/snippets/ramaze/thread_accessor.rb +0 -58
data/lib/ramaze/option.rb CHANGED
@@ -75,7 +75,7 @@ module Ramaze
75
75
  o "Instruction for daemonize, only works with bin/ramaze for now",
76
76
  :daemonize, 'start', :cli => [:start, :stop]
77
77
 
78
- o "Turn on customized error pages.",
78
+ o "Turn on customized error pages. Use Rack::ShowException otherwise.",
79
79
  :error_page, true, :cli => true
80
80
 
81
81
  o "Caching actions to the filesystem in Global.public_root",
@@ -103,7 +103,7 @@ module Ramaze
103
103
  :mapping, {}
104
104
 
105
105
  o "Activate middleware",
106
- :middleware, false
106
+ :middleware, true
107
107
 
108
108
  o "For your own modes to decide on",
109
109
  :mode, :live, :cli => [:live, :dev]
@@ -144,7 +144,7 @@ module Ramaze
144
144
  o "What signal to trap to call Ramaze::shutdown",
145
145
  :shutdown_trap, "SIGINT"
146
146
 
147
- o "Interval in seconds of the background SourceReload",
147
+ o "Interval in seconds of the Reloader",
148
148
  :sourcereload, 3, :cli => 3
149
149
 
150
150
  o "Test before start if adapters will be able to connect",
@@ -0,0 +1,186 @@
1
+ # Copyright (c) 2008 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
+
6
+ # High performant source reloader
7
+ #
8
+ # This class acts as Rack middleware.
9
+ #
10
+ # It does not depend on Ramaze itself, but you might have to adjust the
11
+ # Reloader::Hooks module or include your own module to override the hooks.
12
+ # You also might have to set the Log constant.
13
+ #
14
+ # What makes it especially suited for use in a production environment is that
15
+ # any file will only be checked once and there will only be made one system
16
+ # call stat(2).
17
+ #
18
+ # Please note that this will not reload files in the background, it does so
19
+ # only when actively called
20
+ # In case of Ramaze it is performing a check/reload cycle at the start of
21
+ # every request, but also respects a cool down time, during which nothing will
22
+ # be done.
23
+ #
24
+ # After every reload the OPTIONS hash will be checked for changed options and
25
+ # assigned to the instance, so you may change options during the lifetime of
26
+ # your application.
27
+ #
28
+ # A number of hooks will be executed during the reload cycle, see
29
+ # Ramaze::ReloaderHooks for more information.
30
+
31
+ class Reloader
32
+ OPTIONS = {
33
+ # At most check every n seconds
34
+ # nil/false will never trigger the reload cycle
35
+ # 0 will cycle on every call
36
+ :cooldown => 2,
37
+
38
+ # Compiled files cannot be reloaded during runtime
39
+ :ignore => /\.so$/,
40
+
41
+ # Run cycle in a Thread.exclusive, by default no threads are used.
42
+ :thread => false,
43
+
44
+ # If you assign a block here it will be instance_evaled instead of
45
+ # calling cycle. This allows you to use for example EventMachine for
46
+ # well performing asynchronous cycling.
47
+ :control => nil, # lambda{ cycle },
48
+ }
49
+
50
+ def initialize(app)
51
+ @app = app
52
+ @last = Time.now
53
+ @mtimes = {}
54
+ @cache = {}
55
+ options_reload
56
+ end
57
+
58
+ def options_reload
59
+ @cooldown, @ignore, @control, @thread =
60
+ OPTIONS.values_at(:cooldown, :ignore, :control, :thread)
61
+ end
62
+
63
+ def call(env)
64
+ options_reload
65
+
66
+ if @cooldown and Time.now > @last + @cooldown
67
+ if @control
68
+ instance_eval(&@control)
69
+ elsif @thread
70
+ Thread.exclusive{ cycle }
71
+ else
72
+ cycle
73
+ end
74
+
75
+ @last = Time.now
76
+ end
77
+
78
+ @app.call(env)
79
+ end
80
+
81
+ def cycle
82
+ before_cycle
83
+
84
+ rotation do |file, stat|
85
+ if mtime = stat.mtime
86
+ if mtime > (@mtimes[file] ||= mtime)
87
+ safe_load(file)
88
+ @mtimes[file] = mtime
89
+ end
90
+ else
91
+ @cache.delete(file)
92
+ end
93
+ end
94
+
95
+ after_cycle
96
+ end
97
+
98
+ # A safe Kernel::load, issuing the hooks depending on the results
99
+ def safe_load(file)
100
+ before_safe_load(file)
101
+ load(file)
102
+ after_safe_load_succeed(file)
103
+ rescue Object => ex
104
+ Log.error(ex)
105
+ after_safe_load_failed(file, ex)
106
+ end
107
+
108
+ def rotation
109
+ files = [$0, *$LOADED_FEATURES].uniq
110
+ paths = ['./', *$LOAD_PATH].uniq
111
+
112
+ files.each do |file|
113
+ next if file =~ @ignore
114
+ path, stat = figure_path(file, paths)
115
+
116
+ if path and stat
117
+ @cache[file] = path
118
+ yield(path, stat)
119
+ else
120
+ Log::warn "Couldn't figure path for #{file}"
121
+ end
122
+ end
123
+ end
124
+
125
+ def figure_path(file, paths)
126
+ if cached = @cache[file]
127
+ stat = File.stat(cached)
128
+ return cached, stat if stat.file?
129
+ elsif Pathname.new(file).absolute?
130
+ stat = File.stat(file)
131
+ return file, stat if stat.file? # do directories really end up in $" ?
132
+ end
133
+
134
+ paths.each do |possible_path|
135
+ path = File.join(possible_path, file)
136
+
137
+ begin
138
+ stat = File.stat(path)
139
+ return path, stat if stat.file?
140
+ rescue Errno::ENOENT, Errno::ENOTDIR
141
+ end
142
+ end
143
+
144
+ return nil
145
+ end
146
+
147
+
148
+ # Holds hooks that are called before and after #cycle and #safe_load
149
+ module Hooks
150
+ # Overwrite to add actions before the reload rotation is started.
151
+ def before_cycle
152
+ end
153
+
154
+ # Overwrite to add actions after the reload rotation has ended.
155
+ def after_cycle
156
+ end
157
+
158
+ # Overwrite to add actions before a file is Kernel::load-ed
159
+ def before_safe_load(file)
160
+ Log.debug("reload #{file}")
161
+ end
162
+
163
+ # Overwrite to add actions after a file is Kernel::load-ed successfully,
164
+ # by default we clean the Cache for compiled templates and resolved actions.
165
+ def after_safe_load_succeed(file)
166
+ Ramaze::Cache.compiled.clear
167
+ Ramaze::Cache.resolved.clear
168
+ Ramaze::Cache.action_methods.clear
169
+ after_safe_load(file)
170
+ end
171
+
172
+ # Overwrite to add custom hook in addition to default Cache cleaning
173
+ def after_safe_load(file)
174
+ end
175
+
176
+ # Overwrite to add actions after a file is Kernel::load-ed unsuccessfully,
177
+ # by default we output an error-message with the exception.
178
+ def after_safe_load_failed(file, error)
179
+ Log.error(error)
180
+ end
181
+ end
182
+
183
+ include Hooks
184
+
185
+ end
186
+ end
data/lib/ramaze/setup.rb CHANGED
@@ -24,7 +24,7 @@ module Ramaze
24
24
 
25
25
  # Shortcut if you don't need specific versions but tons of gems
26
26
  def gems(*args)
27
- gems.each{|g| gem(g) }
27
+ args.each{|g| gem(g) }
28
28
  end
29
29
 
30
30
  def global(hash = nil)
@@ -362,7 +362,7 @@ module Ramaze
362
362
  reorder
363
363
  self
364
364
  end
365
- alias :merge! update
365
+ alias merge! update
366
366
 
367
367
  def merge( hsh2 )
368
368
  self.dup.update(hsh2)
@@ -390,7 +390,7 @@ module Ramaze
390
390
  def length
391
391
  @order.length
392
392
  end
393
- alias :size :length
393
+ alias size length
394
394
 
395
395
  def empty?
396
396
  @hash.empty?
@@ -0,0 +1,63 @@
1
+ unless defined? Fiber
2
+ require 'thread'
3
+
4
+ class FiberError < StandardError; end
5
+
6
+ class Fiber
7
+ def initialize
8
+ raise ArgumentError, 'new Fiber requires a block' unless block_given?
9
+
10
+ @yield = Queue.new
11
+ @resume = Queue.new
12
+
13
+ @thread = Thread.new{ @yield.push [*yield(*wait)] }
14
+ @thread.abort_on_exception = true
15
+ @thread[:fiber] = self
16
+ end
17
+ attr_reader :yield, :thread
18
+
19
+ def resume *args
20
+ raise FiberError, 'dead fiber called' unless @thread.alive?
21
+ @resume.push(args)
22
+ result = @yield.pop
23
+ result.size > 1 ? result : result.first
24
+ end
25
+
26
+ def wait
27
+ @resume.pop
28
+ end
29
+
30
+ def self.yield *args
31
+ raise FiberError, "can't yield from root fiber" unless fiber = Thread.current[:fiber]
32
+ fiber.yield.push(args)
33
+ result = fiber.wait
34
+ result.size > 1 ? result : result.first
35
+ end
36
+
37
+ def inspect
38
+ "#<#{self.class}:0x#{self.object_id.to_s(16)}>"
39
+ end
40
+ end
41
+ end
42
+
43
+ if __FILE__ == $0
44
+ f = Fiber.new{ puts 'hi'; p Fiber.yield(1); puts 'bye'; :done }
45
+ p f.resume
46
+ p f.resume(2)
47
+ end
48
+
49
+ __END__
50
+
51
+ $ ruby fbr.rb
52
+ hi
53
+ 1
54
+ 2
55
+ bye
56
+ :done
57
+
58
+ $ ruby1.9 fbr.rb
59
+ hi
60
+ 1
61
+ 2
62
+ bye
63
+ :done
@@ -3,54 +3,54 @@ class Numeric
3
3
  def seconds
4
4
  self
5
5
  end
6
- alias :second :seconds
6
+ alias second seconds
7
7
 
8
8
  # 60 seconds in a minute
9
9
  def minutes
10
10
  self * 60
11
11
  end
12
- alias :minute :minutes
12
+ alias minute minutes
13
13
 
14
14
  # 60 minutes in an hour
15
15
  def hours
16
16
  self * 3600
17
17
  end
18
- alias :hour :hours
18
+ alias hour hours
19
19
 
20
20
  # 24 hours in a day
21
21
  def days
22
22
  self * 86400
23
23
  end
24
- alias :day :days
24
+ alias day days
25
25
 
26
26
  # 7 days in a week
27
27
  def weeks
28
28
  self * 604800
29
29
  end
30
- alias :week :weeks
30
+ alias week weeks
31
31
 
32
32
  # 30 days in a month
33
33
  def months
34
34
  self * 2592000
35
35
  end
36
- alias :month :months
36
+ alias month months
37
37
 
38
38
  # 365.25 days in a year
39
39
  def years
40
40
  self * 883612800
41
41
  end
42
- alias :year :years
42
+ alias year years
43
43
 
44
44
  # Time in the past, i.e. 3.days.ago
45
45
  def ago t = Time.now
46
46
  t - self
47
47
  end
48
- alias :before :ago
48
+ alias before ago
49
49
 
50
50
  # Time in the future, i.e. 3.days.from_now
51
51
  def from_now t = Time.now
52
52
  t + self
53
53
  end
54
- alias :since :from_now
54
+ alias since from_now
55
55
 
56
- end unless 5.respond_to? :days
56
+ end unless 5.respond_to? :days
@@ -1,5 +1,7 @@
1
1
  module Ramaze
2
- DEPRECATED_CONSTANTS = {}
2
+ DEPRECATED_CONSTANTS = {
3
+ :ThreadAccessor => :StateAccessor
4
+ }
3
5
 
4
6
  def self.deprecated(from, to = nil)
5
7
  message = "%s is deprecated"
@@ -10,7 +12,7 @@ module Ramaze
10
12
  def self.const_missing(name)
11
13
  if to = DEPRECATED_CONSTANTS[name]
12
14
  Log.warn "Ramaze::#{name} is deprecated, use #{to} instead"
13
- to
15
+ constant(to)
14
16
  else
15
17
  super
16
18
  end
@@ -0,0 +1,24 @@
1
+ module Ramaze
2
+ class Fiber < ::Fiber
3
+ # initialize isn't being called, so we have to hook into ::new
4
+ def self.new(*args)
5
+ instance = super
6
+ instance.state = {}
7
+ instance
8
+ end
9
+
10
+ attr_accessor :state
11
+
12
+ def [](key)
13
+ @state[key]
14
+ end
15
+
16
+ def []=(key, value)
17
+ @state[key] = value
18
+ end
19
+
20
+ def key?(key)
21
+ @state.key?(key)
22
+ end
23
+ end if defined?(::Fiber)
24
+ end
@@ -0,0 +1,86 @@
1
+ module Ramaze
2
+ class State
3
+ def initialize
4
+ @core = detect
5
+ end
6
+
7
+ def detect
8
+ require 'fiber'
9
+ @extract = :resume
10
+ Ramaze::Fiber
11
+ rescue LoadError
12
+ @extract = :value
13
+ ::Thread
14
+ end
15
+
16
+ def [](key)
17
+ @core.current[key]
18
+ end
19
+
20
+ def []=(key, value)
21
+ @core.current[key] = value
22
+ end
23
+
24
+ def key?(key)
25
+ @core.current.key?(key)
26
+ end
27
+
28
+ def wrap(&block)
29
+ @core.new(&block).send(@extract)
30
+ end
31
+ end
32
+
33
+ module StateAccessor
34
+
35
+ # Iterate over the names and yield accordingly.
36
+ # names are either objects responding to #to_sym or hashes.
37
+ #
38
+ # It's only used within this module for abstractin-purposes.
39
+ # Usage below.
40
+ def self.each(*names)
41
+ names.each do |name|
42
+ if name.respond_to?(:to_hash)
43
+ name.to_hash.each do |key, meth|
44
+ key, meth = key.to_sym, meth.to_sym
45
+ yield key, meth
46
+ end
47
+ else
48
+ key = meth = name.to_sym
49
+ yield key, meth
50
+ end
51
+ end
52
+ end
53
+
54
+ # state_writer and state_reader, initializer is a block that may be given
55
+ # and its result will be the new value in case the reader was never called
56
+ # before or the value wasn't set before.
57
+ def state_accessor(*names, &initializer)
58
+ state_writer(*names)
59
+ state_reader(*names, &initializer)
60
+ end
61
+
62
+ # Simple writer accessor to STATE[key]=
63
+ def state_writer(*names)
64
+ StateAccessor.each(*names) do |key, meth|
65
+ define_method("#{meth}="){|obj| STATE[key] = obj }
66
+ end
67
+ end
68
+
69
+ # Reader accessor for STATE[key]
70
+ def state_reader(*names, &initializer)
71
+ StateAccessor.each(*names) do |key, meth|
72
+ if initializer
73
+ define_method(meth) do
74
+ unless STATE.key?(key)
75
+ STATE[key] = instance_eval(&initializer)
76
+ else
77
+ STATE[key]
78
+ end
79
+ end
80
+ else
81
+ define_method(meth){ STATE[key] }
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -2,6 +2,7 @@
2
2
  # All files in this distribution are subject to the terms of the Ruby license.
3
3
 
4
4
  module Ramaze
5
+ Reloader::OPTIONS[:cooldown] = nil
5
6
 
6
7
  # SourceReload provides a way to reload changed files automatically during
7
8
  # runtime. Its default behaviour in Ramaze is to check periodically for
@@ -0,0 +1,34 @@
1
+ # Copyright (c) 2008 Michael Fellinger m.fellinger@gmail.com
2
+ # All files in this distribution are subject to the terms of the Ruby license.
3
+
4
+ require 'maruku'
5
+
6
+ module Ramaze
7
+ module Template
8
+
9
+ # Is responsible for compiling a template using the Ezamar templating engine.
10
+
11
+ class Maruku < Template
12
+
13
+ ENGINES[self] = %w[ mkd ]
14
+
15
+ class << self
16
+
17
+ # Transforms an action into the XHTML code for parsing and returns
18
+ # the result
19
+ def transform(action)
20
+ maruku = wrap_compile(action)
21
+ maruku.to_html
22
+ end
23
+
24
+ # Compile a template, applying all transformations from the pipeline
25
+ # and returning an instance of ::Ezamar::Template
26
+
27
+ def compile(action, template)
28
+ ::Maruku.new(template)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+
@@ -16,7 +16,10 @@ module Ramaze
16
16
 
17
17
  ENGINES = {} unless defined?(ENGINES)
18
18
 
19
- AVAILABLE_ENGINES = %w[ Amrita2 Builder Erubis Haml Liquid Markaby Nagoro None RedCloth Remarkably Sass XSLT Tenjin Tagz ]
19
+ AVAILABLE_ENGINES = %w[
20
+ Amrita2 Builder Erubis Haml Liquid Markaby Maruku Nagoro None RedCloth
21
+ Remarkably Sass Tagz Tenjin XSLT
22
+ ]
20
23
 
21
24
  AVAILABLE_ENGINES.each do |const|
22
25
  autoload(const, "ramaze/template/#{const.downcase}")
@@ -15,10 +15,20 @@ module Ramaze
15
15
 
16
16
  # Get MIME-type for the given filename based on extension.
17
17
  # Answers with an empty string if none is found.
18
- def type_for file
18
+ def type_for(file)
19
19
  ext = File.extname(file)
20
20
  trait[:types][ext].to_s
21
21
  end
22
+
23
+ def ext_for(mime)
24
+ exts = []
25
+
26
+ trait[:types].each do |ext, mime_type|
27
+ exts << ext if mime == mime_type
28
+ end
29
+
30
+ exts.sort_by{|e| e.size }.first
31
+ end
22
32
  end
23
33
  end
24
34
  end
@@ -2,12 +2,15 @@
2
2
  # All files in this distribution are subject to the terms of the Ruby license.
3
3
 
4
4
  module Ramaze
5
+ STATE = State.new
5
6
 
6
7
  # The module to be included into the Controller it basically just provides
7
8
  # #request, #response and #session, each accessing Thread.current to
8
9
  # retrieve the demanded object
9
10
 
10
11
  module Trinity
11
- thread_accessor :request, :response, :session
12
+ extend StateAccessor
13
+
14
+ state_accessor :request, :response, :session
12
15
  end
13
16
  end
@@ -2,5 +2,5 @@
2
2
  # All files in this distribution are subject to the terms of the Ruby license.
3
3
 
4
4
  module Ramaze
5
- VERSION = "2008.06"
5
+ VERSION = "2008.08"
6
6
  end
data/lib/ramaze.rb CHANGED
@@ -39,7 +39,7 @@ Thread.abort_on_exception = true
39
39
 
40
40
  # Bootstrap
41
41
  require 'ramaze/version'
42
- require 'ramaze/sourcereload'
42
+ require 'ramaze/reloader'
43
43
  require 'ramaze/snippets'
44
44
  require 'ramaze/log'
45
45
  require 'ramaze/trinity'
@@ -63,7 +63,7 @@ module Ramaze
63
63
  # Each of these classes will be called ::startup upon Ramaze.startup
64
64
 
65
65
  trait :essentials => [
66
- Global, Cache, Contrib, Controller, Session, SourceReload, Adapter
66
+ Global, Cache, Contrib, Controller, Session, Adapter
67
67
  ]
68
68
 
69
69
  trait :started => false
data/rake_tasks/gem.rake CHANGED
@@ -65,3 +65,9 @@ end
65
65
 
66
66
  File.open("ramaze.gemspec", 'w+'){|file| file.puts(gemspec) }
67
67
  end
68
+
69
+ spec = generate_gemspec(version_today)
70
+ Rake::GemPackageTask.new(spec) do |pkg|
71
+ pkg.need_zip = true
72
+ pkg.need_tar = true
73
+ end