ramaze 2009.06.12 → 2009.07

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. data/MANIFEST +10 -0
  2. data/README.md +4 -9
  3. data/Rakefile +30 -21
  4. data/doc/AUTHORS +1 -1
  5. data/doc/CHANGELOG +144 -0
  6. data/doc/meta/announcement.txt +47 -76
  7. data/examples/misc/css.rb +6 -12
  8. data/lib/proto/app.rb +4 -5
  9. data/lib/proto/controller/init.rb +1 -1
  10. data/lib/proto/spec/main.rb +3 -4
  11. data/lib/ramaze.rb +0 -2
  12. data/lib/ramaze/app.rb +4 -3
  13. data/lib/ramaze/cache.rb +1 -0
  14. data/lib/ramaze/cache/lru.rb +42 -0
  15. data/lib/ramaze/contrib/addressable_route.rb +10 -9
  16. data/lib/ramaze/controller.rb +1 -3
  17. data/lib/ramaze/helper/blue_form.rb +214 -0
  18. data/lib/ramaze/helper/cache.rb +44 -9
  19. data/lib/ramaze/helper/formatting.rb +5 -2
  20. data/lib/ramaze/helper/layout.rb +2 -2
  21. data/lib/ramaze/helper/paginate.rb +28 -33
  22. data/lib/ramaze/request.rb +1 -1
  23. data/lib/ramaze/snippets/ramaze/lru_hash.rb +248 -0
  24. data/lib/ramaze/spec/bacon.rb +5 -0
  25. data/lib/ramaze/spec/helper/template_examples.rb +4 -1
  26. data/lib/ramaze/version.rb +1 -1
  27. data/lib/ramaze/view.rb +4 -3
  28. data/lib/ramaze/view/less.rb +12 -0
  29. data/ramaze.gemspec +27 -24
  30. data/spec/contrib/addressable_route.rb +3 -5
  31. data/spec/contrib/rest.rb +1 -1
  32. data/spec/examples/caching.rb +2 -2
  33. data/spec/examples/css.rb +2 -2
  34. data/spec/examples/element.rb +2 -2
  35. data/spec/examples/hello.rb +2 -2
  36. data/spec/examples/helpers/httpdigest.rb +2 -2
  37. data/spec/examples/linking.rb +2 -2
  38. data/spec/examples/simple.rb +2 -2
  39. data/spec/examples/templates/template_erubis.rb +5 -2
  40. data/spec/examples/templates/template_ezamar.rb +5 -2
  41. data/spec/examples/templates/template_haml.rb +5 -2
  42. data/spec/examples/templates/template_liquid.rb +5 -2
  43. data/spec/examples/templates/template_markaby.rb +5 -2
  44. data/spec/examples/templates/template_nagoro.rb +5 -2
  45. data/spec/examples/templates/template_redcloth.rb +5 -2
  46. data/spec/examples/templates/template_remarkably.rb +5 -2
  47. data/spec/examples/templates/template_tenjin.rb +5 -2
  48. data/spec/ramaze/action/render.rb +4 -1
  49. data/spec/ramaze/app.rb +4 -1
  50. data/spec/ramaze/app/location.rb +43 -0
  51. data/spec/ramaze/bin/ramaze.rb +7 -2
  52. data/spec/ramaze/cache/localmemcache.rb +1 -1
  53. data/spec/ramaze/cache/lru.rb +48 -0
  54. data/spec/ramaze/cache/memcache.rb +1 -1
  55. data/spec/ramaze/cache/sequel.rb +1 -1
  56. data/spec/ramaze/controller/actionless_templates.rb +1 -1
  57. data/spec/ramaze/controller/lonely_mapping.rb +3 -1
  58. data/spec/ramaze/controller/mapping.rb +4 -1
  59. data/spec/ramaze/controller/provide_inheritance.rb +4 -1
  60. data/spec/ramaze/controller/resolve.rb +1 -1
  61. data/spec/ramaze/controller/subclass.rb +1 -1
  62. data/spec/ramaze/controller/template_resolving.rb +1 -1
  63. data/spec/ramaze/dispatcher/directory.rb +4 -1
  64. data/spec/ramaze/dispatcher/file.rb +8 -8
  65. data/spec/ramaze/error.rb +1 -1
  66. data/spec/ramaze/files.rb +4 -1
  67. data/spec/ramaze/gestalt.rb +4 -1
  68. data/spec/ramaze/helper/auth.rb +1 -1
  69. data/spec/ramaze/helper/bench.rb +4 -1
  70. data/spec/ramaze/helper/blue_form.rb +433 -0
  71. data/spec/ramaze/helper/cache.rb +2 -2
  72. data/spec/ramaze/helper/flash.rb +1 -1
  73. data/spec/ramaze/helper/form.rb +4 -1
  74. data/spec/ramaze/helper/formatting.rb +4 -1
  75. data/spec/ramaze/helper/gestalt.rb +4 -1
  76. data/spec/ramaze/helper/gravatar.rb +4 -1
  77. data/spec/ramaze/helper/httpdigest.rb +4 -1
  78. data/spec/ramaze/helper/layout.rb +1 -1
  79. data/spec/ramaze/helper/link.rb +1 -1
  80. data/spec/ramaze/helper/localize.rb +4 -1
  81. data/spec/ramaze/helper/maruku.rb +4 -1
  82. data/spec/ramaze/helper/pager.rb +1 -1
  83. data/spec/ramaze/helper/paginate.rb +4 -1
  84. data/spec/ramaze/helper/request_accessor.rb +4 -1
  85. data/spec/ramaze/helper/sequel_form.rb +4 -1
  86. data/spec/ramaze/helper/simple_captcha.rb +1 -1
  87. data/spec/ramaze/helper/stack.rb +1 -1
  88. data/spec/ramaze/helper/user.rb +4 -1
  89. data/spec/ramaze/helper/xhtml.rb +4 -1
  90. data/spec/ramaze/log/informer.rb +1 -1
  91. data/spec/ramaze/log/logging.rb +4 -1
  92. data/spec/ramaze/log/syslog.rb +6 -6
  93. data/spec/ramaze/params.rb +1 -1
  94. data/spec/ramaze/request.rb +4 -1
  95. data/spec/ramaze/session/memcache.rb +1 -1
  96. data/spec/ramaze/struct.rb +4 -1
  97. data/spec/ramaze/view.rb +1 -1
  98. data/spec/ramaze/view/erubis.rb +1 -1
  99. data/spec/ramaze/view/ezamar.rb +1 -1
  100. data/spec/ramaze/view/gestalt.rb +2 -2
  101. data/spec/ramaze/view/haml.rb +1 -1
  102. data/spec/ramaze/view/less.rb +60 -0
  103. data/spec/ramaze/view/less/file.css.less +8 -0
  104. data/spec/ramaze/view/liquid.rb +1 -1
  105. data/spec/ramaze/view/nagoro.rb +1 -1
  106. data/spec/ramaze/view/redcloth.rb +1 -1
  107. data/spec/ramaze/view/remarkably.rb +1 -1
  108. data/spec/ramaze/view/sass.rb +1 -1
  109. data/spec/ramaze/view/tagz.rb +1 -1
  110. data/spec/ramaze/view/tenjin.rb +1 -1
  111. data/spec/snippets/array/put_within.rb +30 -25
  112. data/spec/snippets/binding/locals.rb +4 -1
  113. data/spec/snippets/numeric/filesize_format.rb +4 -1
  114. data/spec/snippets/numeric/time.rb +5 -2
  115. data/spec/snippets/object/__dir__.rb +4 -1
  116. data/spec/snippets/ordered_set.rb +4 -1
  117. data/spec/snippets/ramaze/acquire.rb +4 -1
  118. data/spec/snippets/ramaze/dictionary.rb +4 -1
  119. data/spec/snippets/ramaze/lru_hash.rb +88 -0
  120. data/spec/snippets/ramaze/struct.rb +4 -1
  121. data/spec/snippets/string/camel_case.rb +4 -1
  122. data/spec/snippets/string/color.rb +4 -1
  123. data/spec/snippets/string/snake_case.rb +4 -1
  124. data/spec/snippets/string/unindent.rb +4 -1
  125. data/spec/snippets/thread/into.rb +4 -1
  126. data/tasks/bacon.rake +8 -2
  127. data/tasks/gem_setup.rake +21 -8
  128. data/tasks/setup.rake +8 -2
  129. metadata +29 -9
@@ -10,15 +10,10 @@ module Ramaze::SourceReloadHooks
10
10
  end
11
11
 
12
12
  class CSSController < Ramaze::Controller
13
- engine :Sass
14
-
15
- helper :aspect
16
- before_all do
17
- response['Content-Type'] = 'text/css'
18
- nil
19
- end
13
+ helper :cache
14
+ provide :css, :type => 'text/css', :engine => :Sass
20
15
 
21
- define_method('style.css') do
16
+ def style
22
17
  %(
23
18
  body
24
19
  font:
@@ -29,9 +24,8 @@ body
29
24
  )
30
25
  end
31
26
 
32
- helper :cache
33
- cache 'style.css'
27
+ cache_action :method => 'style'
34
28
  end
35
29
 
36
- # http://localhost:81/css/style.css
37
- Ramaze.start :adapter => :mongrel, :port => 81
30
+ # http://localhost:7000/css/style.css
31
+ Ramaze.start :adapter => :mongrel, :port => 7000
@@ -6,10 +6,9 @@
6
6
  require 'rubygems'
7
7
  require 'ramaze'
8
8
 
9
- # Add the directory this file resides in to the load path, so you can run the
10
- # app from any other working directory
11
- $LOAD_PATH.unshift(__DIR__)
9
+ # Make sure that Ramaze knows where you are
10
+ Ramaze.options.roots = [__DIR__]
12
11
 
13
12
  # Initialize controllers and models
14
- require 'model/init'
15
- require 'controller/init'
13
+ require __DIR__('model/init')
14
+ require __DIR__('controller/init')
@@ -8,4 +8,4 @@ class Controller < Ramaze::Controller
8
8
  end
9
9
 
10
10
  # Here go your requires for subclasses of Controller:
11
- require 'controller/main'
11
+ require __DIR__('main')
@@ -1,11 +1,10 @@
1
1
  require 'ramaze'
2
- require 'ramaze/spec'
2
+ require 'ramaze/spec/bacon'
3
3
 
4
- require __DIR__('../start')
5
- Ramaze.options.roots = __DIR__('../')
4
+ require __DIR__('../app')
6
5
 
7
6
  describe MainController do
8
- behaves_like :mock
7
+ behaves_like :rack_test
9
8
 
10
9
  should 'show start page' do
11
10
  get('/').status.should == 200
@@ -66,7 +66,6 @@ module Ramaze
66
66
  m.use Rack::ShowExceptions
67
67
  m.use Rack::ShowStatus
68
68
  m.use Rack::RouteExceptions
69
- m.use Rack::ContentLength
70
69
  m.use Rack::ConditionalGet
71
70
  m.use Rack::ETag
72
71
  m.use Rack::Head
@@ -78,7 +77,6 @@ module Ramaze
78
77
  m.use Rack::CommonLogger, Ramaze::Log
79
78
  m.use Rack::RouteExceptions
80
79
  m.use Rack::ShowStatus
81
- m.use Rack::ContentLength
82
80
  m.use Rack::ConditionalGet
83
81
  m.use Rack::ETag
84
82
  m.use Rack::Head
@@ -70,10 +70,10 @@ module Ramaze
70
70
 
71
71
  attr_reader :name, :location, :url_map, :options
72
72
 
73
- def initialize(name, location)
73
+ def initialize(name, location = nil)
74
74
  @name = name.to_sym
75
75
  @url_map = Innate::URLMap.new
76
- self.location = location
76
+ self.location = location if location
77
77
 
78
78
  APP_LIST[@name] = self
79
79
 
@@ -113,7 +113,8 @@ module Ramaze
113
113
  roots.map{|root| publics.map{|public| ::File.join(root, public) }}.flatten
114
114
  end
115
115
 
116
- def self.find_or_create(name, location = '/')
116
+ def self.find_or_create(name, location = nil)
117
+ location = '/' if location.nil? && name == :pristine
117
118
  self[name] || new(name, location)
118
119
  end
119
120
 
@@ -7,6 +7,7 @@ module Ramaze
7
7
  Cache = Innate::Cache
8
8
 
9
9
  class Cache
10
+ autoload :LRU, 'ramaze/cache/lru'
10
11
  autoload :LocalMemCache, 'ramaze/cache/localmemcache'
11
12
  autoload :MemCache, 'ramaze/cache/memcache'
12
13
  autoload :Sequel, 'ramaze/cache/sequel'
@@ -0,0 +1,42 @@
1
+ # Copyright (c) 2009 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 Cache
6
+ class LRU
7
+ include Cache::API
8
+
9
+ OPTIONS = {
10
+ # expiration in seconds
11
+ :expiration => nil,
12
+ # maximum elements in the cache
13
+ :max_count => 10000,
14
+ # maximum total memory usage of the cache
15
+ :max_total => nil,
16
+ # maximum memory usage of an element of the cache
17
+ :max_value => nil,
18
+ }
19
+
20
+ # Connect to localmemcache
21
+ def cache_setup(host, user, app, name)
22
+ @store = Ramaze::LRUHash.new(OPTIONS)
23
+ end
24
+
25
+ def cache_clear
26
+ @store.clear
27
+ end
28
+
29
+ def cache_store(*args)
30
+ super{|key, value| @store[key] = value }
31
+ end
32
+
33
+ def cache_fetch(*args)
34
+ super{|key| @store[key] }
35
+ end
36
+
37
+ def cache_delete(*args)
38
+ super{|key| @store.delete(key) }
39
+ end
40
+ end
41
+ end
42
+ end
@@ -18,25 +18,22 @@ module Ramaze
18
18
  # @example output of request.params at '/order/show'
19
19
  #
20
20
  # {'customer_id => '12', 'order_id' => '15'}
21
- #
21
+ #
22
22
  # I haven't explored the full capabilities of the templates yet, but the
23
23
  # specs of Addressable::Template suggest that there is a lot to be
24
24
  # discovered.
25
25
  class AddressableRoute
26
- ROUTES = {}
27
-
28
- def self.map(from, to)
29
- ROUTES[Addressable::Template.new(from)] = to
30
- end
31
-
32
- def initialize(app)
26
+ def initialize(app, routes = {})
33
27
  @app = app
28
+ @routes = {}
29
+
30
+ routes.each{|from, to| map(from, to) }
34
31
  end
35
32
 
36
33
  def call(env)
37
34
  path_info = env['PATH_INFO']
38
35
 
39
- ROUTES.each do |template, target|
36
+ @routes.each do |template, target|
40
37
  extracted = template.extract(path_info)
41
38
  return dispatch(env, target, extracted) if extracted
42
39
  end
@@ -44,6 +41,10 @@ module Ramaze
44
41
  @app.call(env)
45
42
  end
46
43
 
44
+ def map(from, to)
45
+ @routes[Addressable::Template.new(from)] = to
46
+ end
47
+
47
48
  def dispatch(env, target, extracted)
48
49
  env['PATH_INFO'] = target
49
50
  original = Rack::Utils.parse_query(env['QUERY_STRING'])
@@ -51,9 +51,7 @@ module Ramaze
51
51
  trait(:provide_set => false)
52
52
  end
53
53
 
54
- return if trait[:skip_controller_map]
55
-
56
- map(generate_mapping(name))
54
+ map(generate_mapping(name)) unless trait[:skip_controller_map]
57
55
  end
58
56
 
59
57
  def self.engine(name)
@@ -0,0 +1,214 @@
1
+ require 'ramaze'
2
+ require 'ramaze/gestalt'
3
+
4
+ module Ramaze
5
+ module Helper
6
+ # This helper tries to be an even better way to build forms
7
+ # programmatically, see the specs for lots of examples.
8
+ module BlueForm
9
+ def form(options = {}, &block)
10
+ form = Form.new(options)
11
+ form.build(form_errors, &block)
12
+ form
13
+ end
14
+
15
+ def form_error(name, message)
16
+ if respond_to?(:flash)
17
+ old = flash[:form_errors] || {}
18
+ flash[:form_errors] = old.merge(name.to_s => message.to_s)
19
+ else
20
+ form_errors[name.to_s] = message.to_s
21
+ end
22
+ end
23
+
24
+ def form_errors
25
+ if respond_to?(:flash)
26
+ flash[:form_errors] ||= {}
27
+ else
28
+ @form_errors ||= {}
29
+ end
30
+ end
31
+
32
+ def form_errors_from_model(obj)
33
+ obj.errors.each do |key, value|
34
+ form_error(key.to_s, value.first % key)
35
+ end
36
+ end
37
+
38
+ # Note that an instance of this class is not thread-safe, so you should
39
+ # modify it only within one thread of execution
40
+ class Form
41
+ attr_reader :g
42
+
43
+ def initialize(options)
44
+ @form_args = options.dup
45
+ @g = Gestalt.new
46
+ end
47
+
48
+ def build(form_errors = {})
49
+ @form_errors = form_errors
50
+
51
+ @g.form(@form_args) do
52
+ if block_given?
53
+ @g.fieldset do
54
+ yield self
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ def legend(text)
61
+ @g.legend(text)
62
+ end
63
+
64
+ def input_text(label, name, value = nil, args = {})
65
+ id = id_for(name)
66
+ args = args.merge(:type => :text, :name => name, :class => 'text', :id => id)
67
+ args[:value] = value unless value.nil?
68
+
69
+ @g.p do
70
+ label_for(id, label, name)
71
+ @g.input(args)
72
+ end
73
+ end
74
+ alias text input_text
75
+
76
+ def input_password(label, name)
77
+ id = id_for(name)
78
+ args = {:type => :password, :name => name, :class => 'text', :id => id}
79
+
80
+ @g.p do
81
+ label_for(id, label, name)
82
+ @g.input(args)
83
+ end
84
+ end
85
+ alias password input_password
86
+
87
+ def input_submit(value = nil)
88
+ args = {:type => :submit, :class => 'button submit'}
89
+ args[:value] = value unless value.nil?
90
+
91
+ @g.p do
92
+ @g.input(args)
93
+ end
94
+ end
95
+ alias submit input_submit
96
+
97
+ def input_checkbox(label, name, checked = false)
98
+ id = id_for(name)
99
+ args = {:type => :checkbox, :name => name, :class => 'checkbox', :id => id}
100
+ args[:checked] = 'checked' if checked
101
+
102
+ @g.p do
103
+ label_for(id, label, name)
104
+ @g.input(args)
105
+ end
106
+ end
107
+ alias checkbox input_checkbox
108
+
109
+ def input_radio(label, name, values, options = {})
110
+ has_checked, checked = options.key?(:checked), options[:checked]
111
+
112
+ @g.p do
113
+ values.each_with_index do |(value, o_name), index|
114
+ o_name ||= value
115
+ id = id_for("#{name}-#{index}")
116
+
117
+ o_args = {:type => :radio, :value => value, :id => id, :name => name}
118
+ o_args[:checked] = 'checked' if has_checked && value == checked
119
+
120
+ if error = @form_errors.delete(name.to_s)
121
+ @g.label(:for => id){
122
+ @g.span(:class => :error){ error }
123
+ @g.input(o_args)
124
+ @g.out << o_name
125
+ }
126
+ else
127
+ @g.label(:for => id){
128
+ @g.input(o_args)
129
+ @g.out << o_name
130
+ }
131
+ end
132
+ end
133
+ end
134
+ end
135
+ alias radio input_radio
136
+
137
+ def input_file(label, name)
138
+ id = id_for(name)
139
+ args = {:type => :file, :name => name, :class => 'file', :id => id}
140
+
141
+ @g.p do
142
+ label_for(id, label, name)
143
+ @g.input(args)
144
+ end
145
+ end
146
+ alias file input_file
147
+
148
+ def input_hidden(name, value = nil)
149
+ args = {:type => :hidden, :name => name}
150
+ args[:value] = value.to_s unless value.nil?
151
+
152
+ @g.input(args)
153
+ end
154
+ alias hidden input_hidden
155
+
156
+ def textarea(label, name, value = nil)
157
+ id = id_for(name)
158
+ args = {:name => name, :id => id}
159
+
160
+ @g.p do
161
+ label_for(id, label, name)
162
+ @g.textarea(args){ value }
163
+ end
164
+ end
165
+
166
+ def select(label, name, values, options = {})
167
+ id = id_for(name)
168
+ multiple, size = options.values_at(:multiple, :size)
169
+
170
+ args = {:id => id}
171
+ args[:multiple] = 'multiple' if multiple
172
+ args[:size] = (size || multiple || 1).to_i
173
+ args[:name] = multiple ? "#{name}[]" : name
174
+
175
+ has_selected, selected = options.key?(:selected), options[:selected]
176
+
177
+ @g.p do
178
+ label_for(id, label, name)
179
+ @g.select args do
180
+ values.each do |value, o_name|
181
+ o_name ||= value
182
+ o_args = {:value => value}
183
+ o_args[:selected] = 'selected' if has_selected && value == selected
184
+ @g.option(o_args){ o_name }
185
+ end
186
+ end
187
+ end
188
+ end
189
+
190
+ def to_s
191
+ @g.to_s
192
+ end
193
+
194
+ private
195
+
196
+ def label_for(id, value, name)
197
+ if error = @form_errors.delete(name.to_s)
198
+ @g.label("#{value} ", :for => id){ @g.span(:class => :error){ error } }
199
+ else
200
+ @g.label(value, :for => id)
201
+ end
202
+ end
203
+
204
+ def id_for(field_name)
205
+ if name = @form_args[:name]
206
+ "#{name}-#{field_name}".downcase.gsub(/_/, '-')
207
+ else
208
+ "form-#{field_name}".downcase.gsub(/_/, '-')
209
+ end
210
+ end
211
+ end
212
+ end
213
+ end
214
+ end
@@ -16,7 +16,7 @@ module Ramaze
16
16
  into.extend(SingletonMethods)
17
17
  into.add_action_wrapper(6.0, :cache_wrap)
18
18
  into.trait[:cache_action] ||= Set.new
19
- Ramaze::Cache.add(:action, :action_value)
19
+ Ramaze::Cache.add(:action, :cache_helper_value)
20
20
  end
21
21
 
22
22
  # @param [Action] action The currently wrapped action
@@ -58,19 +58,54 @@ module Ramaze
58
58
  yield
59
59
  end
60
60
 
61
- # @return [Object] The cache wrapper assigned for :action_value
61
+ # This method is used to access Ramaze::Cache.cache_helper_value.
62
+ # It provides an easy way to cache long-running computations, gathering
63
+ # external resources like RSS feeds or DB queries that are the same for
64
+ # every user of an application.
65
+ # This method changes behaviour if a block is passed, which can be used
66
+ # to do lazy computation of the cached value conveniently when using a
67
+ # custom TTL or longer expressions that don't fit on one line with ||=.
68
+ #
69
+ # @usage Example to get the cache object directly
70
+ #
71
+ # count = cache_value[:count] ||= Article.count
72
+ #
73
+ # @usage Example with block
74
+ #
75
+ # count = cache_value(:count){ Article.count }
76
+ # count = cache_value(:count, :ttl => 60){ Article.count }
77
+ #
78
+ # @return [Object] The cache wrapper assigned for :cache_helper_value
62
79
  # @see Innate::Cache
63
80
  # @author manveru
64
- def cache_value
65
- Ramaze::Cache.action_value
66
- end
81
+ def cache_value(key = nil, options = {})
82
+ cache = Ramaze::Cache.cache_helper_value
67
83
 
68
- module SingletonMethods
69
- def cache(name, hash = {})
70
- Ramaze.deprecated('Helper::Cache::cache', 'Helper::Cache::cache_action')
71
- cache_action(hash.merge(:method => name))
84
+ if key and block_given?
85
+ if found = cache[key]
86
+ found
87
+ else
88
+ cache.store(key, yield, options)
89
+ end
90
+ else
91
+ cache
72
92
  end
93
+ end
73
94
 
95
+ module SingletonMethods
96
+ # This method allows you to cache whole actions.
97
+ #
98
+ # @example Basic usage
99
+ #
100
+ # class Foo < Ramaze::Controller
101
+ # helper :cache
102
+ # cache_action :method => :bar
103
+ #
104
+ # def bar
105
+ # rand
106
+ # end
107
+ # end
108
+ #
74
109
  def cache_action(hash, &block)
75
110
  hash[:key] = block if block_given?
76
111
  hash[:method] = hash[:method].to_s