merb 0.3.7 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +25 -26
- data/Rakefile +48 -36
- data/app_generators/merb/USAGE +5 -0
- data/app_generators/merb/merb_generator.rb +107 -0
- data/app_generators/merb/templates/Rakefile +99 -0
- data/{examples/skeleton/dist → app_generators/merb/templates}/app/controllers/application.rb +1 -1
- data/app_generators/merb/templates/app/controllers/exceptions.rb +13 -0
- data/{examples/skeleton/dist → app_generators/merb/templates}/app/helpers/global_helper.rb +0 -0
- data/{examples/skeleton/dist/app/mailers → app_generators/merb/templates/app/mailers/views}/layout/application.erb +0 -0
- data/app_generators/merb/templates/app/views/exceptions/internal_server_error.html.erb +207 -0
- data/app_generators/merb/templates/app/views/exceptions/not_acceptable.html.erb +38 -0
- data/app_generators/merb/templates/app/views/exceptions/not_found.html.erb +40 -0
- data/app_generators/merb/templates/app/views/layout/application.html.erb +11 -0
- data/app_generators/merb/templates/config/boot.rb +11 -0
- data/app_generators/merb/templates/config/dependencies.rb +41 -0
- data/{examples/skeleton/dist/conf → app_generators/merb/templates/config}/environments/development.rb +0 -0
- data/{examples/skeleton/dist/conf → app_generators/merb/templates/config}/environments/production.rb +0 -0
- data/{examples/skeleton/dist/conf → app_generators/merb/templates/config}/environments/test.rb +0 -0
- data/app_generators/merb/templates/config/merb.yml +64 -0
- data/app_generators/merb/templates/config/merb_init.rb +16 -0
- data/app_generators/merb/templates/config/plugins.yml +1 -0
- data/app_generators/merb/templates/config/router.rb +32 -0
- data/{lib/merb/core_ext/merb_array.rb → app_generators/merb/templates/config/upload.conf} +0 -0
- data/app_generators/merb/templates/public/images/merb.jpg +0 -0
- data/app_generators/merb/templates/public/merb.fcgi +6 -0
- data/app_generators/merb/templates/public/stylesheets/master.css +119 -0
- data/app_generators/merb/templates/script/destroy +28 -0
- data/app_generators/merb/templates/script/generate +28 -0
- data/{examples/skeleton → app_generators/merb/templates}/script/stop_merb +0 -0
- data/app_generators/merb/templates/script/win_script.cmd +1 -0
- data/app_generators/merb/templates/spec/spec.opts +6 -0
- data/app_generators/merb/templates/spec/spec_helper.rb +10 -0
- data/app_generators/merb/templates/test/test_helper.rb +13 -0
- data/app_generators/merb_plugin/USAGE +5 -0
- data/app_generators/merb_plugin/merb_plugin_generator.rb +64 -0
- data/app_generators/merb_plugin/templates/LICENSE +20 -0
- data/app_generators/merb_plugin/templates/README +4 -0
- data/app_generators/merb_plugin/templates/Rakefile +35 -0
- data/app_generators/merb_plugin/templates/TODO +5 -0
- data/app_generators/merb_plugin/templates/merbtasks.rb +6 -0
- data/app_generators/merb_plugin/templates/sampleplugin.rb +10 -0
- data/app_generators/merb_plugin/templates/sampleplugin_spec.rb +7 -0
- data/app_generators/merb_plugin/templates/spec_helper.rb +2 -0
- data/bin/merb +1 -1
- data/lib/autotest/discover.rb +3 -0
- data/lib/autotest/merb_rspec.rb +79 -0
- data/lib/merb.rb +72 -93
- data/lib/merb/{merb_abstract_controller.rb → abstract_controller.rb} +28 -5
- data/lib/merb/caching/action_cache.rb +65 -29
- data/lib/merb/caching/fragment_cache.rb +9 -4
- data/lib/merb/caching/store/file_cache.rb +22 -14
- data/lib/merb/caching/store/memory_cache.rb +26 -8
- data/lib/merb/{merb_constants.rb → constants.rb} +9 -7
- data/lib/merb/controller.rb +178 -0
- data/lib/merb/core_ext.rb +13 -11
- data/lib/merb/core_ext/array.rb +0 -0
- data/lib/merb/core_ext/{merb_class.rb → class.rb} +0 -0
- data/lib/merb/core_ext/{merb_enumerable.rb → enumerable.rb} +0 -0
- data/lib/merb/core_ext/get_args.rb +52 -0
- data/lib/merb/core_ext/{merb_hash.rb → hash.rb} +40 -11
- data/lib/merb/core_ext/{merb_inflections.rb → inflections.rb} +0 -0
- data/lib/merb/core_ext/{merb_inflector.rb → inflector.rb} +1 -1
- data/lib/merb/core_ext/{merb_kernel.rb → kernel.rb} +56 -3
- data/lib/merb/core_ext/mash.rb +88 -0
- data/lib/merb/core_ext/{merb_module.rb → module.rb} +0 -0
- data/lib/merb/core_ext/{merb_numeric.rb → numeric.rb} +0 -0
- data/lib/merb/core_ext/{merb_object.rb → object.rb} +10 -47
- data/lib/merb/core_ext/string.rb +56 -0
- data/lib/merb/core_ext/{merb_symbol.rb → symbol.rb} +0 -0
- data/lib/merb/dispatcher.rb +109 -0
- data/lib/merb/{merb_drb_server.rb → drb_server.rb} +0 -0
- data/lib/merb/erubis_ext.rb +10 -0
- data/lib/merb/exceptions.rb +173 -0
- data/lib/merb/generators/merb_app/merb_app.rb +5 -25
- data/lib/merb/generators/merb_generator_helpers.rb +317 -0
- data/lib/merb/generators/merb_plugin.rb +19 -0
- data/lib/merb/logger.rb +65 -0
- data/lib/merb/{merb_mail_controller.rb → mail_controller.rb} +102 -49
- data/lib/merb/{merb_mailer.rb → mailer.rb} +31 -27
- data/lib/merb/mixins/{basic_authentication_mixin.rb → basic_authentication.rb} +3 -3
- data/lib/merb/mixins/{controller_mixin.rb → controller.rb} +131 -112
- data/lib/merb/mixins/{erubis_capture_mixin.rb → erubis_capture.rb} +12 -21
- data/lib/merb/mixins/{form_control_mixin.rb → form_control.rb} +6 -12
- data/lib/merb/mixins/render.rb +401 -0
- data/lib/merb/mixins/responder.rb +378 -0
- data/lib/merb/mixins/{view_context_mixin.rb → view_context.rb} +65 -10
- data/lib/merb/mixins/web_controller.rb +29 -0
- data/lib/merb/{merb_handler.rb → mongrel_handler.rb} +59 -38
- data/lib/merb/part_controller.rb +19 -0
- data/lib/merb/plugins.rb +16 -0
- data/lib/merb/rack_adapter.rb +37 -0
- data/lib/merb/request.rb +421 -0
- data/lib/merb/router.rb +576 -0
- data/lib/merb/{merb_server.rb → server.rb} +275 -71
- data/lib/merb/session.rb +10 -10
- data/lib/merb/session/cookie_store.rb +125 -0
- data/lib/merb/session/{merb_mem_cache_session.rb → mem_cache_session.rb} +22 -9
- data/lib/merb/session/{merb_memory_session.rb → memory_session.rb} +15 -11
- data/lib/merb/template.rb +35 -8
- data/lib/merb/template/erubis.rb +16 -10
- data/lib/merb/template/haml.rb +33 -20
- data/lib/merb/template/markaby.rb +16 -14
- data/lib/merb/template/xml_builder.rb +8 -4
- data/lib/merb/test/{merb_fake_request.rb → fake_request.rb} +11 -5
- data/lib/merb/test/helper.rb +31 -0
- data/lib/merb/test/hpricot.rb +136 -0
- data/lib/merb/test/{merb_multipart.rb → multipart.rb} +1 -1
- data/lib/merb/test/rspec.rb +93 -0
- data/lib/merb/{merb_upload_handler.rb → upload_handler.rb} +5 -6
- data/lib/merb/{merb_upload_progress.rb → upload_progress.rb} +1 -1
- data/lib/merb/{merb_view_context.rb → view_context.rb} +27 -42
- data/lib/{merb_tasks.rb → tasks.rb} +0 -0
- data/lib/tasks/merb.rake +21 -11
- data/merb_default_generators/model/USAGE +0 -0
- data/merb_default_generators/model/model_generator.rb +16 -0
- data/merb_default_generators/model/templates/new_model_template.erb +5 -0
- data/merb_default_generators/resource_controller/USAGE +0 -0
- data/merb_default_generators/resource_controller/resource_controller_generator.rb +26 -0
- data/merb_default_generators/resource_controller/templates/controller.rb +30 -0
- data/merb_default_generators/resource_controller/templates/edit.html.erb +1 -0
- data/merb_default_generators/resource_controller/templates/helper.rb +5 -0
- data/merb_default_generators/resource_controller/templates/index.html.erb +1 -0
- data/merb_default_generators/resource_controller/templates/new.html.erb +1 -0
- data/merb_default_generators/resource_controller/templates/show.html.erb +1 -0
- data/merb_generators/controller/USAGE +5 -0
- data/merb_generators/controller/controller_generator.rb +16 -0
- data/merb_generators/controller/templates/controller.rb +8 -0
- data/merb_generators/controller/templates/helper.rb +5 -0
- data/merb_generators/controller/templates/index.html.erb +3 -0
- data/merb_generators/resource/USAGE +0 -0
- data/merb_generators/resource/resource_generator.rb +60 -0
- data/rspec_generators/merb_controller_test/merb_controller_test_generator.rb +67 -0
- data/rspec_generators/merb_controller_test/templates/controller_spec.rb +8 -0
- data/rspec_generators/merb_controller_test/templates/edit_spec.rb +12 -0
- data/rspec_generators/merb_controller_test/templates/helper_spec.rb +5 -0
- data/rspec_generators/merb_controller_test/templates/index_spec.rb +12 -0
- data/rspec_generators/merb_controller_test/templates/new_spec.rb +12 -0
- data/rspec_generators/merb_controller_test/templates/show_spec.rb +5 -0
- data/rspec_generators/merb_model_test/merb_model_test_generator.rb +26 -0
- data/rspec_generators/merb_model_test/templates/model_spec_template.erb +7 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/test_unit_generators/merb_controller_test/merb_controller_test_generator.rb +53 -0
- data/test_unit_generators/merb_controller_test/templates/functional_test.rb +17 -0
- data/test_unit_generators/merb_controller_test/templates/helper_test.rb +9 -0
- data/test_unit_generators/merb_model_test/merb_model_test_generator.rb +29 -0
- data/test_unit_generators/merb_model_test/templates/model_test_unit_template.erb +9 -0
- metadata +172 -94
- data/examples/README_EXAMPLES +0 -10
- data/examples/skeleton/Rakefile +0 -68
- data/examples/skeleton/dist/app/views/layout/application.herb +0 -12
- data/examples/skeleton/dist/conf/database.yml +0 -23
- data/examples/skeleton/dist/conf/merb.yml +0 -57
- data/examples/skeleton/dist/conf/merb_init.rb +0 -24
- data/examples/skeleton/dist/conf/router.rb +0 -22
- data/examples/skeleton/dist/conf/upload.conf +0 -5
- data/examples/skeleton/dist/schema/migrations/001_add_sessions_table.rb +0 -14
- data/examples/skeleton/script/new_migration +0 -21
- data/lib/merb/core_ext/merb_string.rb +0 -18
- data/lib/merb/merb_controller.rb +0 -206
- data/lib/merb/merb_dispatcher.rb +0 -87
- data/lib/merb/merb_exceptions.rb +0 -319
- data/lib/merb/merb_part_controller.rb +0 -42
- data/lib/merb/merb_plugins.rb +0 -293
- data/lib/merb/merb_request.rb +0 -165
- data/lib/merb/merb_router.rb +0 -309
- data/lib/merb/merb_yaml_store.rb +0 -31
- data/lib/merb/mixins/render_mixin.rb +0 -283
- data/lib/merb/mixins/responder_mixin.rb +0 -159
- data/lib/merb/session/merb_ar_session.rb +0 -131
- data/lib/merb/vendor/paginator/README.txt +0 -84
- data/lib/merb/vendor/paginator/paginator.rb +0 -124
- data/lib/tasks/db.rake +0 -55
@@ -1,7 +1,7 @@
|
|
1
|
-
require 'hpricot'
|
1
|
+
#require 'hpricot'
|
2
2
|
|
3
3
|
class Hash
|
4
|
-
|
4
|
+
|
5
5
|
class << self
|
6
6
|
# Converts valid XML into a Ruby Hash structure.
|
7
7
|
# <tt>xml</tt>:: A string representation of valid XML
|
@@ -68,6 +68,14 @@ class Hash
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
+
# convert this hash into a Mash for string or symbol key access
|
72
|
+
def to_mash
|
73
|
+
hash = Mash.new(self)
|
74
|
+
hash.default = self.default
|
75
|
+
hash
|
76
|
+
end
|
77
|
+
|
78
|
+
# convert this hash to a query string param
|
71
79
|
def to_params
|
72
80
|
result = ''
|
73
81
|
stack = []
|
@@ -104,7 +112,34 @@ class Hash
|
|
104
112
|
end
|
105
113
|
alias except block
|
106
114
|
|
107
|
-
|
115
|
+
# Converts the hash into xml attributes
|
116
|
+
# { :one => "ONE", "two"=>"TWO" }.to_xml_attributes
|
117
|
+
# #=> 'one="ONE" two="TWO"'
|
118
|
+
def to_xml_attributes
|
119
|
+
map do |k,v|
|
120
|
+
"#{k.to_s.camelize.sub(/^(.{1,1})/){|m| m.downcase}}=\"#{v}\""
|
121
|
+
end.join(" ")
|
122
|
+
end
|
123
|
+
|
124
|
+
alias_method :to_html_attributes, :to_xml_attributes
|
125
|
+
|
126
|
+
# Adds the given class symbol or string to the hash in the
|
127
|
+
# :class key. This will add a html class if there are already any existing
|
128
|
+
# or create the key and add this as the first class
|
129
|
+
#
|
130
|
+
# Example
|
131
|
+
# @hash[:class] #=> nil
|
132
|
+
# @hash.add_html_class!(:selected) #=> @hash[:class] == "selected"
|
133
|
+
#
|
134
|
+
# @hash.add_html_class!("class1 class2") #=> @hash[:class] == "selected class1 class2"
|
135
|
+
def add_html_class!(html_class)
|
136
|
+
if self[:class]
|
137
|
+
self[:class] = "#{self[:class]} #{html_class}"
|
138
|
+
else
|
139
|
+
self[:class] = html_class.to_s
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
108
143
|
# Destructively convert all keys to symbols recursively.
|
109
144
|
def symbolize_keys!
|
110
145
|
keys.each do |key|
|
@@ -221,14 +256,8 @@ class REXMLUtilityNode # :nodoc:
|
|
221
256
|
end
|
222
257
|
|
223
258
|
def to_html
|
224
|
-
"<#{name}#{
|
259
|
+
"<#{name}#{attributes.to_xml_attributes}>#{inner_html}</#{name}>"
|
225
260
|
end
|
226
|
-
|
227
|
-
def attributes_to_xml
|
228
|
-
attributes.keys.map do |key|
|
229
|
-
"#{key}='#{attributes[key]}'"
|
230
|
-
end.join
|
231
|
-
end
|
232
261
|
end
|
233
262
|
|
234
263
|
class ToHashParser # :nodoc:
|
@@ -256,4 +285,4 @@ class ToHashParser # :nodoc:
|
|
256
285
|
end
|
257
286
|
stack.pop.to_hash
|
258
287
|
end
|
259
|
-
end
|
288
|
+
end
|
File without changes
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module Kernel
|
2
2
|
# Example:
|
3
|
-
#
|
3
|
+
# acquire 'foo/bar/*'
|
4
4
|
# requires all files inside foo/bar - recursive
|
5
5
|
# can take multiple parameters
|
6
|
-
def
|
6
|
+
def acquire(*files)
|
7
7
|
files.each do |file|
|
8
8
|
require file if %w(rb so).any?{|f| File.file?("#{file}.#{f}")}
|
9
9
|
$:.each do |path|
|
@@ -22,6 +22,38 @@ module Kernel
|
|
22
22
|
puts message if message
|
23
23
|
end
|
24
24
|
|
25
|
+
def dependencies(*args)
|
26
|
+
args.each do |arg|
|
27
|
+
case arg
|
28
|
+
when String : dependency(arg)
|
29
|
+
when Hash : arg.each { |r,v| dependency(r, v) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def dependency(gem, *ver)
|
35
|
+
Gem.activate(gem, true, *ver)
|
36
|
+
end
|
37
|
+
|
38
|
+
def use_orm(orm)
|
39
|
+
raise "Don't call use_orm more than once" unless
|
40
|
+
Merb::GENERATOR_SCOPE.delete(:merb_default)
|
41
|
+
orm = orm.to_sym
|
42
|
+
orm_plugin = orm.to_s.match(/^merb_/) ? orm.to_s : "merb_#{orm}"
|
43
|
+
Merb::GENERATOR_SCOPE.unshift(orm) unless
|
44
|
+
Merb::GENERATOR_SCOPE.include?(orm)
|
45
|
+
Kernel.dependency(orm_plugin)
|
46
|
+
end
|
47
|
+
|
48
|
+
def use_test(test_framework)
|
49
|
+
test_framework = test_framework.to_sym
|
50
|
+
raise "use_test only supports :rspec and :test_unit currently" unless
|
51
|
+
[:rspec, :test_unit].include?(test_framework)
|
52
|
+
Merb::GENERATOR_SCOPE.delete(:rspec)
|
53
|
+
Merb::GENERATOR_SCOPE.delete(:test_unit)
|
54
|
+
Merb::GENERATOR_SCOPE.push(test_framework)
|
55
|
+
end
|
56
|
+
|
25
57
|
# Gives you back the file, line and method of the caller number i
|
26
58
|
# Example:
|
27
59
|
# __caller_info__(1) # -> ['/usr/lib/ruby/1.8/irb/workspace.rb', '52', 'irb_binding']
|
@@ -53,7 +85,7 @@ module Kernel
|
|
53
85
|
# [ 124, " @suspend_next = false", false ]
|
54
86
|
# ]
|
55
87
|
|
56
|
-
def __caller_lines__
|
88
|
+
def __caller_lines__(file, line, size = 4)
|
57
89
|
return [['Template Error!', "problem while rendering", false]] if file =~ /\(erubis\)/
|
58
90
|
lines = File.readlines(file)
|
59
91
|
current = line.to_i - 1
|
@@ -75,4 +107,25 @@ module Kernel
|
|
75
107
|
|
76
108
|
area
|
77
109
|
end
|
110
|
+
|
111
|
+
def __profile__(name, min=1)
|
112
|
+
require 'ruby-prof' unless defined?(RubyProf)
|
113
|
+
return_result = ''
|
114
|
+
result = RubyProf.profile do
|
115
|
+
100.times{return_result = yield}
|
116
|
+
end
|
117
|
+
printer = RubyProf::GraphHtmlPrinter.new(result)
|
118
|
+
path = File.join(MERB_ROOT, 'log', "#{name}.html")
|
119
|
+
File.open(path, 'w') do |file|
|
120
|
+
printer.print(file, {:min_percent => min,
|
121
|
+
:print_file => true})
|
122
|
+
end
|
123
|
+
return_result
|
124
|
+
end
|
125
|
+
|
126
|
+
# Extracts an options hash if it is the last item in the args array
|
127
|
+
def extract_options_from_args!(args)
|
128
|
+
args.pop if args.last.is_a?( Hash )
|
129
|
+
end
|
130
|
+
|
78
131
|
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
|
2
|
+
# This class has dubious semantics and we only have it so that
|
3
|
+
# people can write params[:key] instead of params['key']
|
4
|
+
|
5
|
+
class Mash < Hash
|
6
|
+
def initialize(constructor = {})
|
7
|
+
if constructor.is_a?(Hash)
|
8
|
+
super()
|
9
|
+
update(constructor)
|
10
|
+
else
|
11
|
+
super(constructor)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def default(key = nil)
|
16
|
+
if key.is_a?(Symbol) && include?(key = key.to_s)
|
17
|
+
self[key]
|
18
|
+
else
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
|
24
|
+
alias_method :regular_update, :update unless method_defined?(:regular_update)
|
25
|
+
|
26
|
+
def []=(key, value)
|
27
|
+
regular_writer(convert_key(key), convert_value(value))
|
28
|
+
end
|
29
|
+
|
30
|
+
def update(other_hash)
|
31
|
+
other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
alias_method :merge!, :update
|
36
|
+
|
37
|
+
def key?(key)
|
38
|
+
super(convert_key(key))
|
39
|
+
end
|
40
|
+
|
41
|
+
alias_method :include?, :key?
|
42
|
+
alias_method :has_key?, :key?
|
43
|
+
alias_method :member?, :key?
|
44
|
+
|
45
|
+
def fetch(key, *extras)
|
46
|
+
super(convert_key(key), *extras)
|
47
|
+
end
|
48
|
+
|
49
|
+
def values_at(*indices)
|
50
|
+
indices.collect {|key| self[convert_key(key)]}
|
51
|
+
end
|
52
|
+
|
53
|
+
def dup
|
54
|
+
Mash.new(self)
|
55
|
+
end
|
56
|
+
|
57
|
+
def merge(hash)
|
58
|
+
self.dup.update(hash)
|
59
|
+
end
|
60
|
+
|
61
|
+
def delete(key)
|
62
|
+
super(convert_key(key))
|
63
|
+
end
|
64
|
+
|
65
|
+
def stringify_keys!; self end
|
66
|
+
def symbolize_keys!; self end
|
67
|
+
|
68
|
+
# Convert to a Hash with String keys.
|
69
|
+
def to_hash
|
70
|
+
Hash.new(default).merge(self)
|
71
|
+
end
|
72
|
+
|
73
|
+
protected
|
74
|
+
def convert_key(key)
|
75
|
+
key.kind_of?(Symbol) ? key.to_s : key
|
76
|
+
end
|
77
|
+
|
78
|
+
def convert_value(value)
|
79
|
+
case value
|
80
|
+
when Hash
|
81
|
+
value.to_mash
|
82
|
+
when Array
|
83
|
+
value.collect { |e| e.is_a?(Hash) ? e.to_mash : e }
|
84
|
+
else
|
85
|
+
value
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
File without changes
|
File without changes
|
@@ -151,12 +151,18 @@ class Object
|
|
151
151
|
|
152
152
|
# Returns true if:
|
153
153
|
# * it's an empty array
|
154
|
+
# * it's an empty string
|
154
155
|
# * !self evaluates to true
|
155
156
|
#
|
156
|
-
# [].blank?
|
157
|
-
#
|
158
|
-
#
|
159
|
-
#
|
157
|
+
# [].blank? #=> true
|
158
|
+
# [1].blank? #=> false
|
159
|
+
# [nil].blank? #=> false
|
160
|
+
# nil.blank? #=> true
|
161
|
+
# true.blank? #=> false
|
162
|
+
# false.blank? #=> true
|
163
|
+
# "".blank? #=> true
|
164
|
+
# " ".blank? #=> true
|
165
|
+
# " hey ho ".blank? #=> false
|
160
166
|
def blank?
|
161
167
|
if respond_to?(:empty?) && respond_to?(:strip)
|
162
168
|
empty? or strip.empty?
|
@@ -173,48 +179,5 @@ class Object
|
|
173
179
|
list.each {|x| obj = obj.const_get(x) }
|
174
180
|
obj
|
175
181
|
end
|
176
|
-
|
177
|
-
# An elegant way to refactor out common options
|
178
|
-
#
|
179
|
-
# with_options :order => 'created_at', :class_name => 'Comment' do |post|
|
180
|
-
# post.has_many :comments, :conditions => ['approved = ?', true], :dependent => :delete_all
|
181
|
-
# post.has_many :unapproved_comments, :conditions => ['approved = ?', false]
|
182
|
-
# post.has_many :all_comments
|
183
|
-
# end
|
184
|
-
#
|
185
|
-
# Can also be used with an explicit reciever:
|
186
|
-
#
|
187
|
-
# map.with_options :controller => "people" do |people|
|
188
|
-
# people.connect "/people", :action => "index"
|
189
|
-
# people.connect "/people/:id", :action => "show"
|
190
|
-
# end
|
191
|
-
def with_options(options)
|
192
|
-
yield Merb::OptionMerger.new(self, options)
|
193
|
-
end
|
194
|
-
end
|
195
182
|
|
196
|
-
module Merb
|
197
|
-
class OptionMerger #:nodoc:
|
198
|
-
instance_methods.each do |method|
|
199
|
-
undef_method(method) if method !~ /^(__|instance_eval|class)/
|
200
|
-
end
|
201
|
-
|
202
|
-
def initialize(context, options)
|
203
|
-
@context, @options = context, options
|
204
|
-
end
|
205
|
-
|
206
|
-
private
|
207
|
-
def method_missing(method, *arguments, &block)
|
208
|
-
merge_argument_options! arguments
|
209
|
-
@context.send(method, *arguments, &block)
|
210
|
-
end
|
211
|
-
|
212
|
-
def merge_argument_options!(arguments)
|
213
|
-
arguments << if arguments.last.respond_to? :to_hash
|
214
|
-
@options.merge(arguments.pop)
|
215
|
-
else
|
216
|
-
@options.dup
|
217
|
-
end
|
218
|
-
end
|
219
|
-
end
|
220
183
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
|
3
|
+
class String
|
4
|
+
class InvalidPathConversion < Exception; end
|
5
|
+
|
6
|
+
def escape_regexp
|
7
|
+
Regexp.escape self
|
8
|
+
end
|
9
|
+
|
10
|
+
# "FooBar".snake_case #=> "foo_bar"
|
11
|
+
def snake_case
|
12
|
+
gsub(/\B[A-Z]/, '_\&').downcase
|
13
|
+
end
|
14
|
+
|
15
|
+
# "foo_bar".camel_case #=> "FooBar"
|
16
|
+
def camel_case
|
17
|
+
split('_').map{|e| e.capitalize}.join
|
18
|
+
end
|
19
|
+
|
20
|
+
# About 50% faster than string.split('/').map{ |s| s.camel_case }.join('::')
|
21
|
+
def to_const_string
|
22
|
+
new_string = ""
|
23
|
+
input = StringScanner.new(self.downcase)
|
24
|
+
until input.eos?
|
25
|
+
if input.scan(/([a-z][a-zA-Z\d]*)(_|$|\/)/)
|
26
|
+
new_string << input[1].capitalize
|
27
|
+
new_string << "::" if input[2] == '/'
|
28
|
+
else
|
29
|
+
raise InvalidPathConversion, self
|
30
|
+
end
|
31
|
+
end
|
32
|
+
new_string
|
33
|
+
end
|
34
|
+
|
35
|
+
# Concatenates a path
|
36
|
+
def /(o)
|
37
|
+
File.join(self, o.to_s)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Takes lines of text, removes any indentation, and
|
41
|
+
# adds +indentation+ number of spaces to each line
|
42
|
+
def indent(indentation)
|
43
|
+
lines = to_a
|
44
|
+
initial_indentation = lines.first.scan(/^(\s+)/).flatten.first
|
45
|
+
lines.map do |line|
|
46
|
+
if initial_indentation.nil?
|
47
|
+
" " * indentation + line
|
48
|
+
elsif line.index(initial_indentation) == 0
|
49
|
+
" " * indentation + line[initial_indentation.size..-1]
|
50
|
+
else
|
51
|
+
" " * indentation + line
|
52
|
+
end
|
53
|
+
end.join
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
File without changes
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Merb
|
2
|
+
class Dispatcher
|
3
|
+
|
4
|
+
DEFAULT_ERROR_TEMPLATE = Erubis::MEruby.new((File.read(
|
5
|
+
File.join(MERB_ROOT, 'app/views/exceptions/internal_server_error.html.erb')) rescue "Internal Server Error!"))
|
6
|
+
|
7
|
+
class << self
|
8
|
+
|
9
|
+
def use_mutex=(val)
|
10
|
+
@@use_mutex = val
|
11
|
+
end
|
12
|
+
|
13
|
+
@@mutex = Mutex.new
|
14
|
+
@@use_mutex = ::Merb::Server.config[:use_mutex]
|
15
|
+
# This is where we grab the incoming request REQUEST_URI and use that in
|
16
|
+
# the merb RouteMatcher to determine which controller and method to run.
|
17
|
+
# Returns a 2 element tuple of: [controller, action]
|
18
|
+
#
|
19
|
+
# ControllerExceptions are rescued here and redispatched.
|
20
|
+
# Exceptions still return [controller, action]
|
21
|
+
def handle(http_request, response)
|
22
|
+
start = Time.now
|
23
|
+
request = Merb::Request.new(http_request)
|
24
|
+
MERB_LOGGER.info("Params: #{request.params.inspect}")
|
25
|
+
MERB_LOGGER.info("Cookies: #{request.cookies.inspect}")
|
26
|
+
# user friendly error messages
|
27
|
+
if request.route_params.empty?
|
28
|
+
raise ControllerExceptions::NotFound, "No routes match the request"
|
29
|
+
elsif request.controller_name.nil?
|
30
|
+
raise ControllerExceptions::NotFound, "Route matched, but route did not specify a controller"
|
31
|
+
end
|
32
|
+
MERB_LOGGER.debug("Routed to: #{request.route_params.inspect}")
|
33
|
+
# set controller class and the action to call
|
34
|
+
klass = request.controller_class
|
35
|
+
dispatch_action(klass, request.action, request, response)
|
36
|
+
rescue => exception
|
37
|
+
MERB_LOGGER.error(Merb.exception(exception))
|
38
|
+
exception = controller_exception(exception)
|
39
|
+
dispatch_exception(request, response, exception)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# setup the controller and call the chosen action
|
45
|
+
def dispatch_action(klass, action, request, response, status=200)
|
46
|
+
# build controller
|
47
|
+
controller = klass.build(request, response, status)
|
48
|
+
# complete setup benchmarking
|
49
|
+
#controller._benchmarks[:setup_time] = Time.now - start
|
50
|
+
if @@use_mutex
|
51
|
+
@@mutex.synchronize { controller.dispatch(action) }
|
52
|
+
else
|
53
|
+
controller.dispatch(action)
|
54
|
+
end
|
55
|
+
[controller, action]
|
56
|
+
end
|
57
|
+
|
58
|
+
# Re-route the current request to the Exception controller
|
59
|
+
# if it is available, and try to render the exception nicely
|
60
|
+
# if it is not available then just render a simple text error
|
61
|
+
def dispatch_exception(request, response, exception)
|
62
|
+
klass = Exceptions rescue Controller
|
63
|
+
request.params[:original_params] = request.params.dup rescue {}
|
64
|
+
request.params[:original_session] = request.session.dup rescue {}
|
65
|
+
request.params[:original_cookies] = request.cookies.dup rescue {}
|
66
|
+
request.params[:exception] = exception
|
67
|
+
request.params[:action] = exception.name
|
68
|
+
dispatch_action(klass, exception.name, request, response, exception.class::STATUS)
|
69
|
+
rescue => dispatch_issue
|
70
|
+
dispatch_issue = controller_exception(dispatch_issue)
|
71
|
+
# when no action/template exist for an exception, or an
|
72
|
+
# exception occurs on an InternalServerError the message is
|
73
|
+
# rendered as simple text.
|
74
|
+
# ControllerExceptions raised from exception actions are
|
75
|
+
# dispatched back into the Exceptions controller
|
76
|
+
if dispatch_issue.is_a?(ControllerExceptions::NotFound)
|
77
|
+
dispatch_default_exception(klass, request, response, exception)
|
78
|
+
elsif dispatch_issue.is_a?(ControllerExceptions::InternalServerError)
|
79
|
+
dispatch_default_exception(klass, request, response, dispatch_issue)
|
80
|
+
else
|
81
|
+
exception = dispatch_issue
|
82
|
+
retry
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# if no custom actions are available to render an exception
|
87
|
+
# then the errors will end up here for processing
|
88
|
+
def dispatch_default_exception(klass, request, response, e)
|
89
|
+
controller = klass.build(request, response, e.class::STATUS)
|
90
|
+
if e.is_a? ControllerExceptions::Redirection
|
91
|
+
controller.headers.merge!('Location' => e.message)
|
92
|
+
controller.instance_variable_set("@_body", %{ }) #fix
|
93
|
+
else
|
94
|
+
@exception = e # for ERB
|
95
|
+
controller.instance_variable_set("@_body", DEFAULT_ERROR_TEMPLATE.result(binding))
|
96
|
+
end
|
97
|
+
[controller, e.name]
|
98
|
+
end
|
99
|
+
|
100
|
+
# Wraps any non-ControllerException errors in an
|
101
|
+
# InternalServerError ready for displaying over HTTP
|
102
|
+
def controller_exception(e)
|
103
|
+
e.kind_of?(ControllerExceptions::Base) ?
|
104
|
+
e : ControllerExceptions::InternalServerError.new(e)
|
105
|
+
end
|
106
|
+
|
107
|
+
end # end class << self
|
108
|
+
end
|
109
|
+
end
|