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.
Files changed (173) hide show
  1. data/README +25 -26
  2. data/Rakefile +48 -36
  3. data/app_generators/merb/USAGE +5 -0
  4. data/app_generators/merb/merb_generator.rb +107 -0
  5. data/app_generators/merb/templates/Rakefile +99 -0
  6. data/{examples/skeleton/dist → app_generators/merb/templates}/app/controllers/application.rb +1 -1
  7. data/app_generators/merb/templates/app/controllers/exceptions.rb +13 -0
  8. data/{examples/skeleton/dist → app_generators/merb/templates}/app/helpers/global_helper.rb +0 -0
  9. data/{examples/skeleton/dist/app/mailers → app_generators/merb/templates/app/mailers/views}/layout/application.erb +0 -0
  10. data/app_generators/merb/templates/app/views/exceptions/internal_server_error.html.erb +207 -0
  11. data/app_generators/merb/templates/app/views/exceptions/not_acceptable.html.erb +38 -0
  12. data/app_generators/merb/templates/app/views/exceptions/not_found.html.erb +40 -0
  13. data/app_generators/merb/templates/app/views/layout/application.html.erb +11 -0
  14. data/app_generators/merb/templates/config/boot.rb +11 -0
  15. data/app_generators/merb/templates/config/dependencies.rb +41 -0
  16. data/{examples/skeleton/dist/conf → app_generators/merb/templates/config}/environments/development.rb +0 -0
  17. data/{examples/skeleton/dist/conf → app_generators/merb/templates/config}/environments/production.rb +0 -0
  18. data/{examples/skeleton/dist/conf → app_generators/merb/templates/config}/environments/test.rb +0 -0
  19. data/app_generators/merb/templates/config/merb.yml +64 -0
  20. data/app_generators/merb/templates/config/merb_init.rb +16 -0
  21. data/app_generators/merb/templates/config/plugins.yml +1 -0
  22. data/app_generators/merb/templates/config/router.rb +32 -0
  23. data/{lib/merb/core_ext/merb_array.rb → app_generators/merb/templates/config/upload.conf} +0 -0
  24. data/app_generators/merb/templates/public/images/merb.jpg +0 -0
  25. data/app_generators/merb/templates/public/merb.fcgi +6 -0
  26. data/app_generators/merb/templates/public/stylesheets/master.css +119 -0
  27. data/app_generators/merb/templates/script/destroy +28 -0
  28. data/app_generators/merb/templates/script/generate +28 -0
  29. data/{examples/skeleton → app_generators/merb/templates}/script/stop_merb +0 -0
  30. data/app_generators/merb/templates/script/win_script.cmd +1 -0
  31. data/app_generators/merb/templates/spec/spec.opts +6 -0
  32. data/app_generators/merb/templates/spec/spec_helper.rb +10 -0
  33. data/app_generators/merb/templates/test/test_helper.rb +13 -0
  34. data/app_generators/merb_plugin/USAGE +5 -0
  35. data/app_generators/merb_plugin/merb_plugin_generator.rb +64 -0
  36. data/app_generators/merb_plugin/templates/LICENSE +20 -0
  37. data/app_generators/merb_plugin/templates/README +4 -0
  38. data/app_generators/merb_plugin/templates/Rakefile +35 -0
  39. data/app_generators/merb_plugin/templates/TODO +5 -0
  40. data/app_generators/merb_plugin/templates/merbtasks.rb +6 -0
  41. data/app_generators/merb_plugin/templates/sampleplugin.rb +10 -0
  42. data/app_generators/merb_plugin/templates/sampleplugin_spec.rb +7 -0
  43. data/app_generators/merb_plugin/templates/spec_helper.rb +2 -0
  44. data/bin/merb +1 -1
  45. data/lib/autotest/discover.rb +3 -0
  46. data/lib/autotest/merb_rspec.rb +79 -0
  47. data/lib/merb.rb +72 -93
  48. data/lib/merb/{merb_abstract_controller.rb → abstract_controller.rb} +28 -5
  49. data/lib/merb/caching/action_cache.rb +65 -29
  50. data/lib/merb/caching/fragment_cache.rb +9 -4
  51. data/lib/merb/caching/store/file_cache.rb +22 -14
  52. data/lib/merb/caching/store/memory_cache.rb +26 -8
  53. data/lib/merb/{merb_constants.rb → constants.rb} +9 -7
  54. data/lib/merb/controller.rb +178 -0
  55. data/lib/merb/core_ext.rb +13 -11
  56. data/lib/merb/core_ext/array.rb +0 -0
  57. data/lib/merb/core_ext/{merb_class.rb → class.rb} +0 -0
  58. data/lib/merb/core_ext/{merb_enumerable.rb → enumerable.rb} +0 -0
  59. data/lib/merb/core_ext/get_args.rb +52 -0
  60. data/lib/merb/core_ext/{merb_hash.rb → hash.rb} +40 -11
  61. data/lib/merb/core_ext/{merb_inflections.rb → inflections.rb} +0 -0
  62. data/lib/merb/core_ext/{merb_inflector.rb → inflector.rb} +1 -1
  63. data/lib/merb/core_ext/{merb_kernel.rb → kernel.rb} +56 -3
  64. data/lib/merb/core_ext/mash.rb +88 -0
  65. data/lib/merb/core_ext/{merb_module.rb → module.rb} +0 -0
  66. data/lib/merb/core_ext/{merb_numeric.rb → numeric.rb} +0 -0
  67. data/lib/merb/core_ext/{merb_object.rb → object.rb} +10 -47
  68. data/lib/merb/core_ext/string.rb +56 -0
  69. data/lib/merb/core_ext/{merb_symbol.rb → symbol.rb} +0 -0
  70. data/lib/merb/dispatcher.rb +109 -0
  71. data/lib/merb/{merb_drb_server.rb → drb_server.rb} +0 -0
  72. data/lib/merb/erubis_ext.rb +10 -0
  73. data/lib/merb/exceptions.rb +173 -0
  74. data/lib/merb/generators/merb_app/merb_app.rb +5 -25
  75. data/lib/merb/generators/merb_generator_helpers.rb +317 -0
  76. data/lib/merb/generators/merb_plugin.rb +19 -0
  77. data/lib/merb/logger.rb +65 -0
  78. data/lib/merb/{merb_mail_controller.rb → mail_controller.rb} +102 -49
  79. data/lib/merb/{merb_mailer.rb → mailer.rb} +31 -27
  80. data/lib/merb/mixins/{basic_authentication_mixin.rb → basic_authentication.rb} +3 -3
  81. data/lib/merb/mixins/{controller_mixin.rb → controller.rb} +131 -112
  82. data/lib/merb/mixins/{erubis_capture_mixin.rb → erubis_capture.rb} +12 -21
  83. data/lib/merb/mixins/{form_control_mixin.rb → form_control.rb} +6 -12
  84. data/lib/merb/mixins/render.rb +401 -0
  85. data/lib/merb/mixins/responder.rb +378 -0
  86. data/lib/merb/mixins/{view_context_mixin.rb → view_context.rb} +65 -10
  87. data/lib/merb/mixins/web_controller.rb +29 -0
  88. data/lib/merb/{merb_handler.rb → mongrel_handler.rb} +59 -38
  89. data/lib/merb/part_controller.rb +19 -0
  90. data/lib/merb/plugins.rb +16 -0
  91. data/lib/merb/rack_adapter.rb +37 -0
  92. data/lib/merb/request.rb +421 -0
  93. data/lib/merb/router.rb +576 -0
  94. data/lib/merb/{merb_server.rb → server.rb} +275 -71
  95. data/lib/merb/session.rb +10 -10
  96. data/lib/merb/session/cookie_store.rb +125 -0
  97. data/lib/merb/session/{merb_mem_cache_session.rb → mem_cache_session.rb} +22 -9
  98. data/lib/merb/session/{merb_memory_session.rb → memory_session.rb} +15 -11
  99. data/lib/merb/template.rb +35 -8
  100. data/lib/merb/template/erubis.rb +16 -10
  101. data/lib/merb/template/haml.rb +33 -20
  102. data/lib/merb/template/markaby.rb +16 -14
  103. data/lib/merb/template/xml_builder.rb +8 -4
  104. data/lib/merb/test/{merb_fake_request.rb → fake_request.rb} +11 -5
  105. data/lib/merb/test/helper.rb +31 -0
  106. data/lib/merb/test/hpricot.rb +136 -0
  107. data/lib/merb/test/{merb_multipart.rb → multipart.rb} +1 -1
  108. data/lib/merb/test/rspec.rb +93 -0
  109. data/lib/merb/{merb_upload_handler.rb → upload_handler.rb} +5 -6
  110. data/lib/merb/{merb_upload_progress.rb → upload_progress.rb} +1 -1
  111. data/lib/merb/{merb_view_context.rb → view_context.rb} +27 -42
  112. data/lib/{merb_tasks.rb → tasks.rb} +0 -0
  113. data/lib/tasks/merb.rake +21 -11
  114. data/merb_default_generators/model/USAGE +0 -0
  115. data/merb_default_generators/model/model_generator.rb +16 -0
  116. data/merb_default_generators/model/templates/new_model_template.erb +5 -0
  117. data/merb_default_generators/resource_controller/USAGE +0 -0
  118. data/merb_default_generators/resource_controller/resource_controller_generator.rb +26 -0
  119. data/merb_default_generators/resource_controller/templates/controller.rb +30 -0
  120. data/merb_default_generators/resource_controller/templates/edit.html.erb +1 -0
  121. data/merb_default_generators/resource_controller/templates/helper.rb +5 -0
  122. data/merb_default_generators/resource_controller/templates/index.html.erb +1 -0
  123. data/merb_default_generators/resource_controller/templates/new.html.erb +1 -0
  124. data/merb_default_generators/resource_controller/templates/show.html.erb +1 -0
  125. data/merb_generators/controller/USAGE +5 -0
  126. data/merb_generators/controller/controller_generator.rb +16 -0
  127. data/merb_generators/controller/templates/controller.rb +8 -0
  128. data/merb_generators/controller/templates/helper.rb +5 -0
  129. data/merb_generators/controller/templates/index.html.erb +3 -0
  130. data/merb_generators/resource/USAGE +0 -0
  131. data/merb_generators/resource/resource_generator.rb +60 -0
  132. data/rspec_generators/merb_controller_test/merb_controller_test_generator.rb +67 -0
  133. data/rspec_generators/merb_controller_test/templates/controller_spec.rb +8 -0
  134. data/rspec_generators/merb_controller_test/templates/edit_spec.rb +12 -0
  135. data/rspec_generators/merb_controller_test/templates/helper_spec.rb +5 -0
  136. data/rspec_generators/merb_controller_test/templates/index_spec.rb +12 -0
  137. data/rspec_generators/merb_controller_test/templates/new_spec.rb +12 -0
  138. data/rspec_generators/merb_controller_test/templates/show_spec.rb +5 -0
  139. data/rspec_generators/merb_model_test/merb_model_test_generator.rb +26 -0
  140. data/rspec_generators/merb_model_test/templates/model_spec_template.erb +7 -0
  141. data/script/destroy +14 -0
  142. data/script/generate +14 -0
  143. data/test_unit_generators/merb_controller_test/merb_controller_test_generator.rb +53 -0
  144. data/test_unit_generators/merb_controller_test/templates/functional_test.rb +17 -0
  145. data/test_unit_generators/merb_controller_test/templates/helper_test.rb +9 -0
  146. data/test_unit_generators/merb_model_test/merb_model_test_generator.rb +29 -0
  147. data/test_unit_generators/merb_model_test/templates/model_test_unit_template.erb +9 -0
  148. metadata +172 -94
  149. data/examples/README_EXAMPLES +0 -10
  150. data/examples/skeleton/Rakefile +0 -68
  151. data/examples/skeleton/dist/app/views/layout/application.herb +0 -12
  152. data/examples/skeleton/dist/conf/database.yml +0 -23
  153. data/examples/skeleton/dist/conf/merb.yml +0 -57
  154. data/examples/skeleton/dist/conf/merb_init.rb +0 -24
  155. data/examples/skeleton/dist/conf/router.rb +0 -22
  156. data/examples/skeleton/dist/conf/upload.conf +0 -5
  157. data/examples/skeleton/dist/schema/migrations/001_add_sessions_table.rb +0 -14
  158. data/examples/skeleton/script/new_migration +0 -21
  159. data/lib/merb/core_ext/merb_string.rb +0 -18
  160. data/lib/merb/merb_controller.rb +0 -206
  161. data/lib/merb/merb_dispatcher.rb +0 -87
  162. data/lib/merb/merb_exceptions.rb +0 -319
  163. data/lib/merb/merb_part_controller.rb +0 -42
  164. data/lib/merb/merb_plugins.rb +0 -293
  165. data/lib/merb/merb_request.rb +0 -165
  166. data/lib/merb/merb_router.rb +0 -309
  167. data/lib/merb/merb_yaml_store.rb +0 -31
  168. data/lib/merb/mixins/render_mixin.rb +0 -283
  169. data/lib/merb/mixins/responder_mixin.rb +0 -159
  170. data/lib/merb/session/merb_ar_session.rb +0 -131
  171. data/lib/merb/vendor/paginator/README.txt +0 -84
  172. data/lib/merb/vendor/paginator/paginator.rb +0 -124
  173. data/lib/tasks/db.rake +0 -55
@@ -1,87 +0,0 @@
1
- module Merb
2
-
3
- class Dispatcher
4
- class << self
5
-
6
- attr_accessor :path_prefix
7
-
8
- def use_mutex=(val)
9
- @@use_mutex = val
10
- end
11
-
12
- @@mutex = Mutex.new
13
- @@use_mutex = ::Merb::Server.use_mutex
14
- # This is where we grab the incoming request REQUEST_URI and use that in
15
- # the merb RouteMatcher to determine which controller and method to run.
16
- # Returns a 2 element tuple of: [controller, action]
17
- def handle(request, response)
18
- start = Time.now
19
-
20
- request_uri = request.params[Merb::Const::REQUEST_URI]
21
- request_uri.sub!(path_prefix, '') if path_prefix
22
- route = route_path(request_uri)
23
-
24
- allowed = route.delete(:allowed)
25
- rest = route.delete(:rest)
26
- namespace = route.delete(:namespace)
27
-
28
- cont = namespace ? "#{namespace}/#{route[:controller]}" : route[:controller]
29
-
30
- klass = resolve_controller(cont)
31
- controller = klass.build(request.body, request.params, route, response)
32
-
33
- if rest
34
- method = controller.request.method
35
- if allowed.keys.include?(method) && action = allowed[method]
36
- controller.params[:action] = action
37
- else
38
- raise Merb::HTTPMethodNotAllowed.new(method, allowed)
39
- end
40
- else
41
- action = route[:action]
42
- end
43
- controller._benchmarks[:setup_time] = Time.now - start
44
- if @@use_mutex
45
- @@mutex.synchronize {
46
- controller.dispatch(action)
47
- }
48
- else
49
- controller.dispatch(action)
50
- end
51
- [controller, action]
52
- end
53
-
54
- def route_path(path)
55
- path = path.sub(/\/+/, '/').sub(/\?.*$/, '')
56
- path = path[0..-2] if (path[-1] == ?/) && path.size > 1
57
- Merb::Router.match(path)
58
- end
59
-
60
- # Take a controller class name string and reload or require the right
61
- # controller file then CamelCase it and return the class object.
62
- def resolve_controller(controller_name)
63
- segments = controller_name.split('/').map{|s| s.snake_case}
64
- path = "#{DIST_ROOT}/app/controllers/#{controller_name}.rb"
65
- cnt = segments.map{|s| s.camel_case }.join('::')
66
-
67
- if !File.exist?(path)
68
- raise "Bad controller! #{cnt}"
69
- end unless $TESTING
70
-
71
- begin
72
- if MERB_ENV == 'development'
73
- Object.send(:remove_const, cnt) rescue nil
74
- load(path)
75
- end
76
- return Object.full_const_get(cnt)
77
- rescue RuntimeError
78
- warn "Error getting instance of '#{controller_name.camel_case}': #{$!}"
79
- raise $!
80
- end
81
- end
82
-
83
- end # end class << self
84
-
85
- end
86
-
87
- end
@@ -1,319 +0,0 @@
1
- begin
2
- require 'coderay'
3
- rescue LoadError => ex
4
- end
5
-
6
- module Merb
7
-
8
- module ControllerExceptions
9
- # ControllerExceptions are a way of simplifying controller code by placing
10
- # exceptional logic elsewhere. ControllerExceptions are like
11
- # mini-controllers which have one action. The exception action is called
12
- # to render a web page when the exception is raised. Additionally all
13
- # ControllerExceptions have an HTTP status code associated with them
14
- # which is given to the browser when it's action is rendered.
15
- #
16
- # ControllerExceptions::Base is an abstract base class, it cannot be
17
- # raised. Derived from Base are many exceptions, one for each HTTP status
18
- # code. EG Unauthorized (401), PaymentRequired (402), and Forbidden (403).
19
- #
20
- # These exceptions can be raised by your controller without any further
21
- # work. For example
22
- #
23
- # def show
24
- # product = Product.find(params[:id])
25
- # raise NotFound if product.nil?
26
- # [...]
27
- # end
28
- #
29
- # By default the NotFound exception will look in for a template at
30
- # app/views/exceptions/not_found.{rhtml, haml, whatevs}
31
- # If the template is not found then a simple message will be sent.
32
- #
33
- # To extend the use of the ControllerExceptions one may derive a new
34
- # exception from one of the already defined ones. Then one must add a
35
- # special method called error_response which is like a controller action
36
- # preparing the context for rendering a template at
37
- # app/views/exceptions/my_exception_snake_cased.whatevs
38
- #
39
- # As an example we will create an exception called AdminAccessRequired.
40
- # First we decide on what HTTP status code such an error might have.
41
- # 401, Unauthorized seems to fit.
42
- #
43
- # class AdminAccessRequired < Merb::ControllerExceptions::Unauthorized
44
- # def error_response
45
- # @tried_to_access request.uri
46
- # render :layout => 'error_page'
47
- # end
48
- # end
49
- #
50
- # At app/views/exceptions/admin_access_required.rhtml we write
51
- #
52
- # <h1>You're not an administrator!</h1>
53
- # <p>You tried to access <%= @tried_to_access %> but that URL is
54
- # restricted to administrators.</p>
55
- #
56
- # The layout 'error_page' works like any other controller, it would be
57
- # looked for at app/views/layouts
58
- #
59
- # TODO: if you need to pass data to your exception use a constructor.
60
- class Base < StandardError
61
- include Merb::RenderMixin
62
- include Merb::ControllerMixin
63
- include Merb::ResponderMixin
64
-
65
- def _template_root
66
- @controller._template_root
67
- end
68
-
69
- # The filename of the exception template. usually something like
70
- # views/exceptions/not_found.rhtml
71
- def template_path
72
- _template_root / 'exceptions' / self.class.name.snake_case.split('::').last
73
- end
74
-
75
- def set_controller(controller)
76
- @controller = controller
77
- end
78
-
79
- def request; @controller.request; end
80
- def params; @controller.params; end
81
- def cookies; @controller.cookies; end
82
- def headers; @controller.headers; end
83
- def session; @controller.session; end
84
- def response; @controller.response; end
85
-
86
- def status
87
- self.class.const_get(:STATUS)
88
- end
89
-
90
- def call_action
91
- # TODO: this method is meaningless at the moment but it could call
92
- # filters
93
- # before filters?
94
- error_response
95
- # after filters?
96
- end
97
-
98
- def error_response
99
- if File.exists?(template_path)
100
- render
101
- else
102
- "Error #{status} #{self.class.name.split('::').last}!"
103
- end
104
- end
105
- end
106
- module HTTPErrors
107
- # created with:
108
- # ruby -r rubygems -e "require 'mongrel'; puts Mongrel::HTTP_STATUS_CODES.keys.sort.map {|code| %Q{class #{Mongrel::HTTP_STATUS_CODES[code].gsub /[^\w]/,''} < Merb::ControllerExceptions::Base; STATUS = #{code}; end} }.join(%Q{\n})"
109
- # we could do some magic here, but i think it's more instructive to just
110
- # have these values copied
111
- class Continue < Merb::ControllerExceptions::Base; STATUS = 100; end
112
- class SwitchingProtocols < Merb::ControllerExceptions::Base; STATUS = 101; end
113
- class OK < Merb::ControllerExceptions::Base; STATUS = 200; end
114
- class Created < Merb::ControllerExceptions::Base; STATUS = 201; end
115
- class Accepted < Merb::ControllerExceptions::Base; STATUS = 202; end
116
- class NonAuthoritativeInformation < Merb::ControllerExceptions::Base; STATUS = 203; end
117
- class NoContent < Merb::ControllerExceptions::Base; STATUS = 204; end
118
- class ResetContent < Merb::ControllerExceptions::Base; STATUS = 205; end
119
- class PartialContent < Merb::ControllerExceptions::Base; STATUS = 206; end
120
- class MultipleChoices < Merb::ControllerExceptions::Base; STATUS = 300; end
121
- class MovedPermanently < Merb::ControllerExceptions::Base; STATUS = 301; end
122
- class MovedTemporarily < Merb::ControllerExceptions::Base; STATUS = 302; end
123
- class SeeOther < Merb::ControllerExceptions::Base; STATUS = 303; end
124
- class NotModified < Merb::ControllerExceptions::Base; STATUS = 304; end
125
- class UseProxy < Merb::ControllerExceptions::Base; STATUS = 305; end
126
- class BadRequest < Merb::ControllerExceptions::Base; STATUS = 400; end
127
- class Unauthorized < Merb::ControllerExceptions::Base; STATUS = 401; end
128
- class PaymentRequired < Merb::ControllerExceptions::Base; STATUS = 402; end
129
- class Forbidden < Merb::ControllerExceptions::Base; STATUS = 403; end
130
- class NotFound < Merb::ControllerExceptions::Base; STATUS = 404; end
131
- class MethodNotAllowed < Merb::ControllerExceptions::Base; STATUS = 405; end
132
- class NotAcceptable < Merb::ControllerExceptions::Base; STATUS = 406; end
133
- class ProxyAuthenticationRequired < Merb::ControllerExceptions::Base; STATUS = 407; end
134
- class RequestTimeout < Merb::ControllerExceptions::Base; STATUS = 408; end
135
- class Conflict < Merb::ControllerExceptions::Base; STATUS = 409; end
136
- class Gone < Merb::ControllerExceptions::Base; STATUS = 410; end
137
- class LengthRequired < Merb::ControllerExceptions::Base; STATUS = 411; end
138
- class PreconditionFailed < Merb::ControllerExceptions::Base; STATUS = 412; end
139
- class RequestEntityTooLarge < Merb::ControllerExceptions::Base; STATUS = 413; end
140
- class RequestURITooLarge < Merb::ControllerExceptions::Base; STATUS = 414; end
141
- class UnsupportedMediaType < Merb::ControllerExceptions::Base; STATUS = 415; end
142
- class InternalServerError < Merb::ControllerExceptions::Base; STATUS = 500; end
143
- class NotImplemented < Merb::ControllerExceptions::Base; STATUS = 501; end
144
- class BadGateway < Merb::ControllerExceptions::Base; STATUS = 502; end
145
- class ServiceUnavailable < Merb::ControllerExceptions::Base; STATUS = 503; end
146
- class GatewayTimeout < Merb::ControllerExceptions::Base; STATUS = 504; end
147
- class HTTPVersionNotSupported < Merb::ControllerExceptions::Base; STATUS = 505; end
148
- end
149
-
150
- include HTTPErrors
151
- end
152
-
153
- class MerbError < StandardError; end
154
- class Noroutefound < MerbError; end
155
- class MissingControllerFile < MerbError; end
156
- class MerbControllerError < MerbError; end
157
- class HTTPMethodNotAllowed < MerbError
158
- def initialize(method, allowed)
159
- super("HTTPMethodNotAllowed: #{method}\n"+ "Allowed: #{allowed.keys.join(' ')})")
160
- end
161
-
162
- end
163
-
164
- # Format exception message for browser display.
165
- def self.html_exception(e)
166
- if ::Merb::Server.show_error
167
- ErrorResponse.new(e).out
168
- else
169
- IO.read(DIST_ROOT / 'public/500.html') rescue "500 Internal Server Error!"
170
- end
171
- end
172
-
173
- def self.exception(e)
174
- "#{ e.message } - (#{ e.class })\n" <<
175
- "#{(e.backtrace or []).join("\n")}"
176
- end
177
-
178
- class ErrorResponse
179
- def initialize error
180
- @error = error
181
- end
182
-
183
- def out
184
- error = @error
185
- backtrace = @error.backtrace
186
-
187
- colors = []
188
- min = 200
189
- max = 255
190
- step = -((max - min) / backtrace.size).abs
191
- max.step(min, step) do |color|
192
- colors << color
193
- end
194
-
195
- backtrace.map! do |line|
196
- file, lineno, meth = line.scan(/(.*?):(\d+)(?::in `(.*?)')?/).first
197
-
198
- # When a backtrace entry doesn't have a filepath as the first field
199
- # (e.g., "(haml):12" or "(eval):41:in `_haml_render'"), it'll cause
200
- # a second exception to be raised, masking the first. This traps it.
201
- lines = (__caller_lines__(file, lineno, 5) rescue [])
202
-
203
- [ lines, lines.object_id.abs, file, lineno, meth ]
204
- end
205
-
206
- error_page(colors, error, *backtrace)
207
- end
208
-
209
- # This method offers highlighting for the sourcecode-chunks from the
210
- # traceback. Just 'gem install coderay'.
211
- def error_page(colors, title, *backtrace)
212
- @backtrace = backtrace
213
- @colors = colors
214
- @title = title
215
- @coderay = Object.constants.include?('CodeRay')
216
-
217
-
218
- template =
219
- <<-HEREDOC
220
- <html>
221
- <head>
222
- <title><%= @title %></title>
223
- <style type="text/css">
224
- <!--
225
- table {border:0px}
226
- tr {line-height:1.3}
227
- td {font-size:.8em; padding:4px}
228
- h1 {font-size:2em}
229
- h1, td {font-family:'courier new', 'courier', monospace}
230
- td.line {color:#000; text-align:center}
231
- td.method {font-weight:bold; text-align:right}
232
- td.file a {color:#000}
233
- td.file a:hover {color:#F00}
234
- tr.clickable:hover {background:#FFA}
235
- .clickable {cursor: help }
236
- #title {float: left;}
237
- .source
238
- {
239
- border:1px #000 solid;
240
- margin:2px;
241
- padding:8px;
242
- background:#F0F0F0;
243
- }
244
-
245
- -->
246
- <% if @coderay %>
247
- <%= CodeRay::Encoders[:html]::CSS.new.stylesheet %>
248
- <% end %>
249
- </style>
250
- <script type="text/javascript">
251
- $ = function(el){
252
- if(el === null || el === undefined)
253
- throw("Argument for $() must be a domRef/domId");
254
- if( el.constructor === String )
255
- el = document.getElementById(el);
256
- if(el === null || !el.nodeType)
257
- throw("Argument for $() not found in document tree.");
258
- return el;
259
- }
260
-
261
- var toggle = function(el){
262
- el = $(el);
263
- var visible = el.style.display != 'none'; // visible? boolean
264
- if(visible){
265
- el.style.display = 'none'; // hide
266
- }else{
267
- el.style.display = ''; // unhide
268
- }
269
- }
270
- </script>
271
- </head>
272
- <body>
273
- <div>
274
- <h1><img src="data:image/jpg;base64,/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAJQAA/+4ADkFk\nb2JlAGTAAAAAAf/bAIQADQkJCQoJDQoKDRMMCwwTFhENDREWGhUVFhUVGhkU\nFhUVFhQZGR0fIB8dGScnKionJzk4ODg5QEBAQEBAQEBAQAEODAwOEA4RDw8R\nFA4RDhQVERISERUgFRUXFRUgKB0ZGRkZHSgjJiAgICYjLCwoKCwsNzc1NzdA\nQEBAQEBAQEBA/8AAEQgAJgAtAwEiAAIRAQMRAf/EAT8AAAEFAQEBAQEBAAAA\nAAAAAAMAAQIEBQYHCAkKCwEAAQUBAQEBAQEAAAAAAAAAAQACAwQFBgcICQoL\nEAABBAEDAgQCBQcGCAUDDDMBAAIRAwQhEjEFQVFhEyJxgTIGFJGhsUIjJBVS\nwWIzNHKC0UMHJZJT8OHxY3M1FqKygyZEk1RkRcKjdDYX0lXiZfKzhMPTdePz\nRieUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm9jdHV2d3h5ent8fX5/cRAAIC\nAQIEBAMEBQYHBwYFNQEAAhEDITESBEFRYXEiEwUygZEUobFCI8FS0fAzJGLh\ncoKSQ1MVY3M08SUGFqKygwcmNcLSRJNUoxdkRVU2dGXi8rOEw9N14/NGlKSF\ntJXE1OT0pbXF1eX1VmZ2hpamtsbW5vYnN0dXZ3eHl6e3x//aAAwDAQACEQMR\nAD8A9OVDK6xRQYa02axuEBvnB7x8Fm/W36x19HqoxmAvyswkMraHFwY2N7va\nCe/5Vy/Seu29RvdXaI2CW6EBw4OhGnZAk9Einrbuvn03Oaw1lvmCCP8ANXPW\n9Zz7shlrM9zKBLnN3Fmg1gnj8An61m14eCbAN9j4ZVWJJc5x2gQPivO3ZnUM\nXLtfY8by73sDmuHw9pPCZRPVNgdH13F+teJU51WbZpX9O4xpPEho4juug9Wr\n0vW3t9Lbv9SRt2xO7dxEL5+blW5I2W2FrdsSJJgdj4r0P1W/+Nf6Un1p9PZJ\nnf8AaPU2+P0fwThdVaLF3TlfXZvUsr63ZIpZY4Y9VDKTWwuIY5vqEe3uXFx+\nSn0XBupy9t+loqDXy1zTJLST7tefJbVDLsjLycwO9Sy/09ANQafUJP8A4IrG\nQGufXltEAjZYPA900kkeCRoXA+sHSeoTXn41xJxnB9bY3e4HRcTbVsfB2h7j\ntDWkkAT7jrPjC9FzCMfpJZU5wDGgN7wNI4HZcJdiNrvP2t+62SNg9vedxnRO\nj2WyQfZy2oOA5kbfGedF0jb8w/Uq2ra/25NcGD9F1dk6/BqrYNODY5rrve4+\n2rGpBcR3Mr0j9iVf83vscD1J3bZMep/NelM+Hsn5oqa3RG0uuf6b9j9dsCRI\n+lx4haGT9g1FgZ6nc0n/AKrSEkko/Kg7vO9XtsxzV+y6a8xjtxu+hWWwPY0f\npBMnv2XN52ZmbyLunYocCZNl1bpdENmS0wOdUkkPsT9rL6rfbf8AnJiPzvT+\nzfpPVrZ6ezb6Ttv0e26OTzC9U3uk+z88ACRu+hz8YSSR6q6P/9k=\n"/>
275
- <%= @title %></h1>
276
- </div>
277
-
278
- <table class="main">
279
- <thead>
280
- <tr>
281
- <td class="method">Method</td>
282
- <td class="line">Line</td>
283
- <td class="file">File</td>
284
- </tr>
285
- </thead>
286
- <% @backtrace.each do |lines, hash, file, lineno, meth| %>
287
- <tr id="line_<%= hash %>" onclick="toggle('source_<%= hash %>'); return false"; class="clickable" style="background:rgb(250,250,<%= @colors.shift %>);">
288
- <td class="method"><%= meth %></td>
289
- <td class="line"><%= lineno %></td>
290
- <td class="file"><%= file %></td>
291
- </tr>
292
- <tr id="source_<%= hash %>" <%= @coderay? " class='CodeRay' " : ''%> style="display:none;">
293
- <td colspan="3">
294
- <div class="source">
295
- <table>
296
- <tr><td colspan='2'><a href='txmt://open?url=file://<%=file%>&line=<%=lineno%>'>Open in TextMate</a></td></tr>
297
- <% lines.each do |llineno, lcode, lcurrent| %>
298
- <tr class="source"<%= 'style="background:#faa;"' if lcurrent %>>
299
- <td><%= llineno %></td>
300
- <td>
301
- <%= @coderay ? CodeRay.scan(lcode, :ruby).html : "<pre>\#{lcode}</pre>" %>
302
- </td>
303
- </tr>
304
- <% end %>
305
- </table>
306
- </div>
307
- </td>
308
- </tr>
309
- <% end %>
310
- </table>
311
- </body>
312
- </html>
313
- HEREDOC
314
- tmpl = Erubis::MEruby.new template
315
- tmpl.result(binding)
316
- end
317
- end
318
-
319
- end
@@ -1,42 +0,0 @@
1
- module Merb
2
- class PartController < AbstractController
3
- self._template_root = File.expand_path(DIST_ROOT / "app/parts/views")
4
-
5
- def initialize(web_controller)
6
- @_benchmarks = {}
7
- @web_controller = web_controller
8
- end
9
-
10
- def dispatch(action=:to_s)
11
- old_action = params[:action]
12
- params[:action] = action
13
- super(action)
14
- params[:action] = old_action
15
- @_body
16
- end
17
-
18
- def request
19
- @web_controller.request
20
- end
21
-
22
- def params
23
- @web_controller.params
24
- end
25
-
26
- def cookies
27
- @web_controller.cookies
28
- end
29
-
30
- def headers
31
- @web_controller.headers
32
- end
33
-
34
- def session
35
- @web_controller.session
36
- end
37
-
38
- def response
39
- @web_controller.response
40
- end
41
- end
42
- end
@@ -1,293 +0,0 @@
1
- # TODO: Find Merb app root so we aren't wantonly copying Rakefiles
2
- # TODO: Figure out a good way to handle the lack of install/uninstall script
3
- # TODO: Minimum versions for local gems in install
4
-
5
- require 'yaml'
6
- require 'rubygems'
7
-
8
- module Merb
9
- class PluginManager
10
-
11
- def self.gem_name
12
- @@gem_name
13
- end
14
-
15
- def self.gem_spec
16
- @@gem_spec
17
- end
18
-
19
- def self.options
20
- @@options
21
- end
22
-
23
- def self.gem_name=(val)
24
- @@gem_name = val
25
- end
26
-
27
- def self.gem_spec=(val)
28
- @@gem_spec = val
29
- end
30
-
31
- def self.options=(val)
32
- @@options = val
33
- end
34
-
35
-
36
- # Run a particular plugin action
37
- def self.action(action, gem_name = nil, opts = [])
38
- @@gem_name = gem_name
39
- @@options = opts.flatten
40
-
41
- case action
42
- when 'install':
43
- install
44
- when 'uninstall':
45
- uninstall
46
- when 'remove':
47
- remove_from_manifest
48
- when 'list':
49
- list
50
- when 'help'
51
- help
52
- when 'migrate'
53
- migrate
54
- when 'update'
55
- raise "This hasn't been implemented yet!"
56
- when 'upgrade'
57
- raise "This hasn't been implemented yet!"
58
- else
59
- raise "Invalid action: #{action}"
60
- end
61
- end
62
-
63
- # Install a new plugin named +gem_name+.
64
- def self.install
65
- raise "Plugin already installed!" if plugin_installed?
66
-
67
- self.gem_spec = find_locally or install_gem
68
-
69
- run_install_script
70
- copy_rakefile
71
- add_to_manifest
72
- rescue Exception => e
73
- puts "\n!!! Plugin installation FAILED: #{e.message}\n\n"
74
- end
75
-
76
- # Check the manifest to see if the plugin is already installed in this application.
77
- def self.plugin_installed?
78
- with_manifest do |manifest|
79
- return manifest.has_key?(gem_name)
80
- end
81
- rescue
82
- false
83
- end
84
-
85
- # Search the local Rubygems installation for the gem.
86
- def self.find_locally
87
- all_installed_gems = Gem::SourceIndex.from_installed_gems
88
- latest_gem_version = all_installed_gems.search(gem_name).sort_by {|x| x.version.version }.last
89
- require 'pp'
90
-
91
- if latest_gem_version
92
- puts "Local gem found."
93
- return latest_gem_version
94
- else
95
- puts "Can't find gem...installing."
96
- return false
97
- end
98
- end
99
-
100
- # Run the installation code in the gem.
101
- def self.run_install_script
102
- require "#{gem_name}/install"
103
- end
104
-
105
- # Copy the Rakefile from the gem to a directory in our application.
106
- def self.copy_rakefile
107
- path = gem_spec.loaded_from.split(/specifications/)[0] + "gems/#{gem_name}-#{gem_spec.version.version}/"
108
-
109
- merb_rake_file = path + "Rakefile.merb"
110
-
111
- require 'fileutils'
112
- Dir.mkdir 'plugins' if !File.exists?('plugins/')
113
- FileUtils.cp merb_rake_file, "plugins/#{gem_name}.rake"
114
-
115
- File.open('Rakefile', 'a') do |rakefile|
116
- rakefile.write("\nrequire 'plugins/#{gem_name}.rake\n")
117
- end
118
- end
119
-
120
- def self.remove_rakefile
121
- FileUtils.rm "plugins/#{gem_name}.rake"
122
-
123
- File.open('Rakefile', 'r+') do |rakefile|
124
- contents = rakefile.read
125
- contents.gsub!("\nrequire 'plugins/#{gem_name}.rake\n", "")
126
-
127
- rakefile.pos = 0
128
- rakefile.write contents
129
- rakefile.truncate rakefile.pos
130
- end
131
- end
132
-
133
- # Do a gem installation since it wasn't found in the locally installed gems.
134
- def self.install_gem
135
- require 'rubygems/installer'
136
-
137
- options = {
138
- :domain => :both,
139
- :generate_rdoc => true,
140
- :generate_ri => true,
141
- :force => false,
142
- :test => false,
143
- :wrappers => true,
144
- :version => "> 0",
145
- :install_dir => Gem.dir,
146
- :security_policy => nil }
147
-
148
-
149
-
150
- puts "Attempting local install..."
151
- local_install = Gem::Installer.new(gem_name, options).install(options[:force], options[:install_dir]) rescue false
152
-
153
- if !local_install
154
- # Do remote installation
155
- require 'rubygems/remote_installer'
156
-
157
- Gem.configuration = ConfigStub.new
158
-
159
- puts "Attempting remote installation..."
160
- installer = Gem::RemoteInstaller.new(options)
161
-
162
- @@options.each do |opt|
163
- installer.sources << opt.gsub(/source=/, '') if opt.scan(/^source=/) != []
164
- options[:version] = "> #{opt.gsub(/version=/, '')}" if opt.scan(/^version=/) != []
165
- end
166
-
167
- remote_install = installer.install(gem_name, options[:version], options[:force], options[:install_dir]) rescue false
168
- end
169
-
170
- if !remote_install && !local_install
171
- raise "That plugin can't be found in locally or in a remote repository."
172
- else
173
- find_locally
174
- end
175
- end
176
-
177
- # Method to open and load our manifest; yields the manifest data to whatever method calls it.
178
- def self.with_manifest
179
- File.open('plugins.manifest', 'r+') do |manifest_file|
180
- manifest_data = YAML::load(manifest_file.read)
181
- manifest_data = {} if !manifest_data.is_a?(Hash)
182
-
183
- yield manifest_data
184
-
185
- manifest_file.pos = 0
186
- manifest_file.write manifest_data.to_yaml
187
- manifest_file.truncate manifest_file.pos
188
- end
189
- end
190
-
191
- # Write our newly installed plugin to the application's manifest.
192
- def self.add_to_manifest
193
- with_manifest do |manifest_data|
194
- manifest_data[gem_name] = {'version' => gem_spec.version.version}
195
- end
196
- end
197
-
198
- def self.uninstall
199
- raise "That plugin isn't installed!" if !plugin_installed?
200
-
201
- require "#{gem_name}/uninstall" rescue nil
202
-
203
- remove_rakefile
204
- remove_from_manifest
205
- uninstall_gem
206
- end
207
-
208
- def self.remove_from_manifest
209
- with_manifest do |manifest|
210
- manifest.delete(gem_name)
211
- end
212
- end
213
-
214
- def self.uninstall_gem
215
- require 'rubygems/installer'
216
- require 'rubygems/doc_manager'
217
-
218
- options = {
219
- :domain => :both,
220
- :generate_rdoc => true,
221
- :generate_ri => true,
222
- :force => false,
223
- :test => false,
224
- :wrappers => true,
225
- :version => "> 0",
226
- :install_dir => Gem.dir,
227
- :security_policy => nil }
228
-
229
- Gem::Uninstaller.new(gem_name, options).uninstall
230
- end
231
-
232
- def self.list
233
- with_manifest do |manifest_data|
234
- manifest_data.each do |key, value|
235
- gem_name = key
236
- gem_spec = find_locally
237
- puts "#{key} (#{gem_spec.version.version})"
238
- puts "\t#{gem_spec.description}\n"
239
- end
240
- end
241
- end
242
-
243
- def self.migrate
244
- raise "This hasn't been implemented yet!"
245
- end
246
-
247
- def self.help
248
- puts """
249
- Merb Plugins
250
- The -P (--plugin) option fed to Merb allows you to manage plugins.
251
-
252
- Commands
253
- --------
254
- install Installs a new plugin.
255
- uninstall Uninstalls a plugin, removing its entry from the manifest and uninstalling the gem.
256
- remove Uninstalls a plugin, removing its entry from the manifest but leaving the gem installed.
257
- list Lists all installed plugins for this Merb application.
258
- upgrade Upgrades a plugin to the specified version.
259
- update Updates a plugin to the latest available version.
260
- migrate Reads the manifest for this application, installing and updating gems as needed.
261
- help Shows this help message.
262
-
263
- """
264
- end
265
- end
266
-
267
- # Class to stub out the verbose flag in Rubygems user interaction lib
268
- class ConfigStub
269
- attr_accessor :verbose
270
-
271
- def initialize
272
- @verbose = false
273
- end
274
- end
275
- end
276
-
277
- module Gem
278
- # Fixes a bug in RubyGems where the SilentProgressReporter class is
279
- # inaccurately named SilentReporter. Maybe one day we'll monkeypatch this for
280
- # our own purposes.
281
- class SilentProgressReporter
282
- attr_reader :count
283
-
284
- def initialize(out_stream, size, initial_message)
285
- end
286
-
287
- def updated(message)
288
- end
289
-
290
- def done
291
- end
292
- end
293
- end