merb 0.3.7 → 0.4.0
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.
- 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
|