merb-core 0.9.3 → 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (178) hide show
  1. data/LICENSE +1 -1
  2. data/README +3 -3
  3. data/Rakefile +144 -33
  4. data/bin/merb +0 -0
  5. data/bin/merb-specs +0 -0
  6. data/docs/bootloading.dox +1 -0
  7. data/docs/merb-core-call-stack-diagram.mmap +0 -0
  8. data/docs/merb-core-call-stack-diagram.pdf +0 -0
  9. data/docs/merb-core-call-stack-diagram.png +0 -0
  10. data/lib/merb-core.rb +159 -37
  11. data/lib/merb-core/autoload.rb +1 -0
  12. data/lib/merb-core/bootloader.rb +208 -92
  13. data/lib/merb-core/config.rb +20 -6
  14. data/lib/merb-core/controller/abstract_controller.rb +113 -61
  15. data/lib/merb-core/controller/exceptions.rb +28 -13
  16. data/lib/merb-core/controller/merb_controller.rb +73 -44
  17. data/lib/merb-core/controller/mime.rb +25 -7
  18. data/lib/merb-core/controller/mixins/authentication.rb +1 -1
  19. data/lib/merb-core/controller/mixins/controller.rb +44 -8
  20. data/lib/merb-core/controller/mixins/render.rb +191 -128
  21. data/lib/merb-core/controller/mixins/responder.rb +65 -63
  22. data/lib/merb-core/controller/template.rb +103 -54
  23. data/lib/merb-core/core_ext.rb +7 -12
  24. data/lib/merb-core/core_ext/kernel.rb +128 -136
  25. data/lib/merb-core/dispatch/cookies.rb +26 -4
  26. data/lib/merb-core/dispatch/default_exception/default_exception.rb +93 -0
  27. data/lib/merb-core/dispatch/default_exception/views/_css.html.erb +198 -0
  28. data/lib/merb-core/dispatch/default_exception/views/_javascript.html.erb +73 -0
  29. data/lib/merb-core/dispatch/default_exception/views/index.html.erb +92 -0
  30. data/lib/merb-core/dispatch/dispatcher.rb +156 -224
  31. data/lib/merb-core/dispatch/request.rb +126 -25
  32. data/lib/merb-core/dispatch/router.rb +61 -6
  33. data/lib/merb-core/dispatch/router/behavior.rb +122 -41
  34. data/lib/merb-core/dispatch/router/route.rb +147 -22
  35. data/lib/merb-core/dispatch/session.rb +52 -2
  36. data/lib/merb-core/dispatch/session/cookie.rb +4 -2
  37. data/lib/merb-core/dispatch/session/memcached.rb +38 -27
  38. data/lib/merb-core/dispatch/session/memory.rb +18 -11
  39. data/lib/merb-core/dispatch/worker.rb +28 -0
  40. data/lib/merb-core/gem_ext/erubis.rb +58 -0
  41. data/lib/merb-core/logger.rb +3 -31
  42. data/lib/merb-core/plugins.rb +25 -3
  43. data/lib/merb-core/rack.rb +18 -12
  44. data/lib/merb-core/rack/adapter.rb +10 -8
  45. data/lib/merb-core/rack/adapter/ebb.rb +2 -2
  46. data/lib/merb-core/rack/adapter/irb.rb +31 -21
  47. data/lib/merb-core/rack/adapter/swiftiplied_mongrel.rb +26 -0
  48. data/lib/merb-core/rack/adapter/thin.rb +19 -9
  49. data/lib/merb-core/rack/adapter/thin_turbo.rb +24 -0
  50. data/lib/merb-core/rack/application.rb +9 -84
  51. data/lib/merb-core/rack/middleware.rb +26 -0
  52. data/lib/merb-core/rack/middleware/path_prefix.rb +31 -0
  53. data/lib/merb-core/rack/middleware/profiler.rb +19 -0
  54. data/lib/merb-core/rack/middleware/static.rb +45 -0
  55. data/lib/merb-core/server.rb +27 -9
  56. data/lib/merb-core/tasks/audit.rake +68 -0
  57. data/lib/merb-core/tasks/merb.rb +1 -0
  58. data/lib/merb-core/tasks/merb_rake_helper.rb +12 -0
  59. data/lib/merb-core/tasks/stats.rake +71 -0
  60. data/lib/merb-core/test.rb +2 -1
  61. data/lib/merb-core/test/helpers/multipart_request_helper.rb +3 -3
  62. data/lib/merb-core/test/helpers/request_helper.rb +66 -24
  63. data/lib/merb-core/test/matchers/controller_matchers.rb +36 -4
  64. data/lib/merb-core/test/matchers/route_matchers.rb +12 -3
  65. data/lib/merb-core/test/matchers/view_matchers.rb +3 -3
  66. data/lib/merb-core/test/run_specs.rb +1 -0
  67. data/lib/merb-core/test/tasks/spectasks.rb +13 -5
  68. data/lib/merb-core/test/test_ext/string.rb +14 -0
  69. data/lib/merb-core/vendor/facets/dictionary.rb +3 -3
  70. data/lib/merb-core/vendor/facets/inflect.rb +82 -37
  71. data/lib/merb-core/version.rb +2 -2
  72. data/spec/private/config/config_spec.rb +39 -4
  73. data/spec/private/core_ext/kernel_spec.rb +3 -14
  74. data/spec/private/dispatch/bootloader_spec.rb +1 -1
  75. data/spec/private/dispatch/cookies_spec.rb +181 -69
  76. data/spec/private/dispatch/fixture/app/controllers/exceptions.rb +0 -2
  77. data/spec/private/dispatch/fixture/app/controllers/foo.rb +0 -2
  78. data/spec/private/dispatch/fixture/config/rack.rb +10 -0
  79. data/spec/private/dispatch/fixture/log/merb_test.log +7054 -1802
  80. data/spec/private/dispatch/route_params_spec.rb +2 -3
  81. data/spec/private/dispatch/session_mixin_spec.rb +47 -0
  82. data/spec/private/plugins/plugin_spec.rb +73 -59
  83. data/spec/private/router/behavior_spec.rb +60 -0
  84. data/spec/private/router/fixture/log/merb_test.log +1693 -0
  85. data/spec/private/router/route_spec.rb +414 -0
  86. data/spec/private/router/router_spec.rb +175 -0
  87. data/spec/private/vendor/facets/plural_spec.rb +564 -0
  88. data/spec/private/vendor/facets/singular_spec.rb +489 -0
  89. data/spec/public/abstract_controller/controllers/cousins.rb +41 -0
  90. data/spec/public/abstract_controller/controllers/helpers.rb +12 -2
  91. data/spec/public/abstract_controller/controllers/partial.rb +17 -2
  92. data/spec/public/abstract_controller/controllers/render.rb +16 -1
  93. data/spec/public/abstract_controller/controllers/views/helpers/capture_eq/index.erb +1 -0
  94. data/spec/public/abstract_controller/controllers/views/helpers/capture_with_args/index.erb +1 -0
  95. data/spec/public/abstract_controller/controllers/views/merb/test/fixtures/abstract/render_two_throw_contents/index.erb +1 -0
  96. data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections_and_counter/_collection.erb +1 -0
  97. data/spec/public/abstract_controller/controllers/views/partial/partial_with_collections_and_counter/index.erb +1 -0
  98. data/spec/public/abstract_controller/controllers/views/partial/with_absolute_partial/_partial.erb +1 -0
  99. data/spec/public/abstract_controller/controllers/views/partial/with_absolute_partial/index.erb +1 -0
  100. data/spec/public/abstract_controller/filter_spec.rb +20 -1
  101. data/spec/public/abstract_controller/helper_spec.rb +10 -2
  102. data/spec/public/abstract_controller/partial_spec.rb +8 -0
  103. data/spec/public/abstract_controller/render_spec.rb +8 -0
  104. data/spec/public/abstract_controller/spec_helper.rb +7 -3
  105. data/spec/public/boot_loader/boot_loader_spec.rb +2 -2
  106. data/spec/public/controller/base_spec.rb +10 -2
  107. data/spec/public/controller/config/init.rb +6 -0
  108. data/spec/public/controller/controllers/authentication.rb +9 -11
  109. data/spec/public/controller/controllers/base.rb +2 -8
  110. data/spec/public/controller/controllers/cookies.rb +16 -0
  111. data/spec/public/controller/controllers/dispatcher.rb +35 -0
  112. data/spec/public/controller/controllers/display.rb +62 -14
  113. data/spec/public/controller/controllers/redirect.rb +36 -0
  114. data/spec/public/controller/controllers/responder.rb +37 -11
  115. data/spec/public/controller/controllers/views/layout/custom_arg.json.erb +1 -0
  116. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/class_and_local_provides/index.html.erb +1 -0
  117. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/class_and_local_provides/index.xml.erb +1 -0
  118. data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/display_with_template/no_layout.html.erb +1 -0
  119. data/spec/public/controller/cookies_spec.rb +23 -0
  120. data/spec/public/controller/dispatcher_spec.rb +411 -0
  121. data/spec/public/controller/display_spec.rb +43 -10
  122. data/spec/public/controller/redirect_spec.rb +33 -0
  123. data/spec/public/controller/responder_spec.rb +79 -11
  124. data/spec/public/controller/spec_helper.rb +3 -1
  125. data/spec/public/controller/url_spec.rb +10 -0
  126. data/spec/public/core/merb_core_spec.rb +11 -0
  127. data/spec/public/core_ext/fixtures/core_ext_dependency.rb +2 -0
  128. data/spec/public/core_ext/kernel_spec.rb +9 -0
  129. data/spec/public/core_ext/spec_helper.rb +1 -0
  130. data/spec/public/directory_structure/directory/log/merb_test.log +3729 -272
  131. data/spec/public/directory_structure/directory_spec.rb +3 -4
  132. data/spec/public/logger/logger_spec.rb +4 -4
  133. data/spec/public/reloading/directory/log/merb_test.log +288066 -15
  134. data/spec/public/reloading/reload_spec.rb +49 -27
  135. data/spec/public/request/multipart_spec.rb +26 -0
  136. data/spec/public/request/request_spec.rb +21 -2
  137. data/spec/public/router/fixation_spec.rb +27 -0
  138. data/spec/public/router/fixture/log/merb_test.log +30050 -0
  139. data/spec/public/router/nested_matches_spec.rb +97 -0
  140. data/spec/public/router/resource_spec.rb +1 -9
  141. data/spec/public/router/resources_spec.rb +0 -20
  142. data/spec/public/router/spec_helper.rb +27 -9
  143. data/spec/public/router/special_spec.rb +21 -8
  144. data/spec/public/template/template_spec.rb +17 -5
  145. data/spec/public/test/controller_matchers_spec.rb +10 -0
  146. data/spec/public/test/request_helper_spec.rb +29 -0
  147. data/spec/public/test/route_helper_spec.rb +18 -1
  148. data/spec/public/test/route_matchers_spec.rb +28 -1
  149. data/spec/public/test/view_matchers_spec.rb +3 -3
  150. data/spec/spec_helper.rb +56 -12
  151. metadata +89 -47
  152. data/lib/merb-core/core_ext/class.rb +0 -299
  153. data/lib/merb-core/core_ext/hash.rb +0 -426
  154. data/lib/merb-core/core_ext/mash.rb +0 -154
  155. data/lib/merb-core/core_ext/object.rb +0 -147
  156. data/lib/merb-core/core_ext/object_space.rb +0 -14
  157. data/lib/merb-core/core_ext/rubygems.rb +0 -28
  158. data/lib/merb-core/core_ext/set.rb +0 -46
  159. data/lib/merb-core/core_ext/string.rb +0 -89
  160. data/lib/merb-core/core_ext/time.rb +0 -13
  161. data/lib/merb-core/dispatch/exceptions.html.erb +0 -297
  162. data/spec/private/core_ext/class_spec.rb +0 -22
  163. data/spec/private/core_ext/hash_spec.rb +0 -522
  164. data/spec/private/core_ext/object_spec.rb +0 -121
  165. data/spec/private/core_ext/set_spec.rb +0 -26
  166. data/spec/private/core_ext/string_spec.rb +0 -167
  167. data/spec/private/core_ext/time_spec.rb +0 -16
  168. data/spec/private/dispatch/dispatch_spec.rb +0 -26
  169. data/spec/private/dispatch/fixture/log/development.log +0 -1
  170. data/spec/private/dispatch/fixture/log/merb.4000.pid +0 -1
  171. data/spec/private/dispatch/fixture/log/production.log +0 -1
  172. data/spec/private/dispatch/fixture/merb.4000.pid +0 -1
  173. data/spec/private/rack/application_spec.rb +0 -43
  174. data/spec/public/controller/log/merb.4000.pid +0 -1
  175. data/spec/public/directory_structure/directory/log/merb.4000.pid +0 -1
  176. data/spec/public/directory_structure/directory/merb.4000.pid +0 -1
  177. data/spec/public/reloading/directory/log/merb.4000.pid +0 -1
  178. data/spec/public/reloading/directory/merb.4000.pid +0 -1
@@ -0,0 +1,31 @@
1
+ module Merb
2
+ module Rack
3
+ class PathPrefix < Merb::Rack::Middleware
4
+
5
+ def initialize(app, path_prefix = nil)
6
+ super(app)
7
+ @path_prefix = /^#{Regexp.escape(path_prefix)}/
8
+ end
9
+
10
+ def deferred?(env)
11
+ strip_path_prefix(env)
12
+ @app.deferred?(env)
13
+ end
14
+
15
+ def call(env)
16
+ strip_path_prefix(env)
17
+ @app.call(env)
18
+ end
19
+
20
+ def strip_path_prefix(env)
21
+ ['PATH_INFO', 'REQUEST_URI'].each do |path_key|
22
+ if env[path_key] =~ @path_prefix
23
+ env[path_key].sub!(@path_prefix, '')
24
+ env[path_key] = '/' if env[path_key].empty?
25
+ end
26
+ end
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,19 @@
1
+ module Merb
2
+ module Rack
3
+ class Profiler < Merb::Rack::Middleware
4
+
5
+ def initialize(app, min=1, iter=1)
6
+ super(app)
7
+ @min, @iter = min, iter
8
+ end
9
+
10
+ def call(env)
11
+ __profile__("profile_output", @min, @iter) do
12
+ @app.call(env)
13
+ end
14
+ end
15
+
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,45 @@
1
+ module Merb
2
+ module Rack
3
+ class Static < Merb::Rack::Middleware
4
+
5
+ def initialize(app,directory)
6
+ super(app)
7
+ @static_server = ::Rack::File.new(directory)
8
+ end
9
+
10
+ def call(env)
11
+ path = env['PATH_INFO'] ? env['PATH_INFO'].chomp('/') : ""
12
+ cached_path = (path.empty? ? 'index' : path) + '.html'
13
+
14
+ if file_exist?(path) && env['REQUEST_METHOD'] =~ /GET|HEAD/ # Serve the file if it's there and the request method is GET or HEAD
15
+ serve_static(env)
16
+ elsif file_exist?(cached_path) && env['REQUEST_METHOD'] =~ /GET|HEAD/ # Serve the page cache if it's there and the request method is GET or HEAD
17
+ env['PATH_INFO'] = cached_path
18
+ serve_static(env)
19
+ elsif path =~ /favicon\.ico/
20
+ return [404, {"Content-Type"=>"text/html"}, "404 Not Found."]
21
+ else
22
+ @app.call(env)
23
+ end
24
+ end
25
+
26
+ # ==== Parameters
27
+ # path<String>:: The path to the file relative to the server root.
28
+ #
29
+ # ==== Returns
30
+ # Boolean:: True if file exists under the server root and is readable.
31
+ def file_exist?(path)
32
+ full_path = ::File.join(@static_server.root, ::Merb::Request.unescape(path))
33
+ ::File.file?(full_path) && ::File.readable?(full_path)
34
+ end
35
+
36
+ # ==== Parameters
37
+ # env<Hash>:: Environment variables to pass on to the server.
38
+ def serve_static(env)
39
+ env["PATH_INFO"] = ::Merb::Request.unescape(env["PATH_INFO"])
40
+ @static_server.call(env)
41
+ end
42
+
43
+ end
44
+ end
45
+ end
@@ -22,25 +22,34 @@ module Merb
22
22
  @cluster = cluster
23
23
  if @cluster
24
24
  @port.to_i.upto(@port.to_i + @cluster.to_i-1) do |port|
25
+ pidfile = pid_file(port)
26
+ pid = IO.read(pidfile).chomp.to_i if File.exist?(pidfile)
27
+
25
28
  unless alive?(port)
26
29
  remove_pid_file(port)
27
- puts "Starting merb server on port: #{port}"
30
+ puts "Starting merb server on port #{port}, pid file: #{pidfile} and process id is #{pid}" if Merb::Config[:verbose]
28
31
  daemonize(port)
29
32
  else
30
- raise "Merb is already running on port: #{port}"
33
+ raise "Merb is already running: port is #{port}, pid file: #{pidfile}, process id is #{pid}"
31
34
  end
32
35
  end
33
36
  elsif Merb::Config[:daemonize]
37
+ pidfile = pid_file(port)
38
+ pid = IO.read(pidfile).chomp.to_i if File.exist?(pidfile)
39
+
34
40
  unless alive?(@port)
35
41
  remove_pid_file(@port)
42
+ puts "Daemonizing..." if Merb::Config[:verbose]
36
43
  daemonize(@port)
37
44
  else
38
- raise "Merb is already running on port: #{port}"
45
+ raise "Merb is already running: port is #{port}, pid file: #{pidfile}, process id is #{pid}"
39
46
  end
40
47
  else
41
48
  trap('TERM') { exit }
42
49
  trap('INT') { puts "\nExiting"; exit }
50
+ puts "Running bootloaders..." if Merb::Config[:verbose]
43
51
  BootLoader.run
52
+ puts "Starting Rack adapter..." if Merb::Config[:verbose]
44
53
  Merb.adapter.start(Merb::Config.to_hash)
45
54
  end
46
55
  end
@@ -52,8 +61,11 @@ module Merb
52
61
  # Boolean::
53
62
  # True if Merb is running on the specified port.
54
63
  def alive?(port)
64
+ puts "About to check if port #{port} is alive..." if Merb::Config[:verbose]
55
65
  pidfile = pid_file(port)
66
+ puts "Pidfile is #{pidfile}..." if Merb::Config[:verbose]
56
67
  pid = IO.read(pidfile).chomp.to_i
68
+ puts "Process id is #{pid}" if Merb::Config[:verbose]
57
69
  Process.kill(0, pid)
58
70
  true
59
71
  rescue
@@ -72,8 +84,8 @@ module Merb
72
84
  begin
73
85
  pidfiles = port == "all" ?
74
86
  pid_files : [ pid_file(port) ]
75
-
76
- pidfiles.each do |f|
87
+
88
+ pidfiles.each do |f|
77
89
  pid = IO.read(f).chomp.to_i
78
90
  begin
79
91
  Process.kill(sig, pid)
@@ -98,6 +110,7 @@ module Merb
98
110
  # ==== Parameters
99
111
  # port<~to_s>:: The port of the Merb process to daemonize.
100
112
  def daemonize(port)
113
+ puts "About to fork..." if Merb::Config[:verbose]
101
114
  fork do
102
115
  Process.setsid
103
116
  exit if fork
@@ -117,13 +130,15 @@ module Merb
117
130
  def change_privilege
118
131
  if Merb::Config[:user]
119
132
  if Merb::Config[:group]
133
+ puts "About to change privilege to group #{Merb::Config[:group]} and user #{Merb::Config[:user]}" if Merb::Config[:verbose]
120
134
  _change_privilege(Merb::Config[:user], Merb::Config[:group])
121
135
  else
136
+ puts "About to change privilege to user #{Merb::Config[:user]}" if Merb::Config[:verbose]
122
137
  _change_privilege(Merb::Config[:user])
123
138
  end
124
139
  end
125
140
  end
126
-
141
+
127
142
  # Removes a PID file used by the server from the filesystem.
128
143
  # This uses :pid_file options from configuration when provided
129
144
  # or merb.<port>.pid in log directory by default.
@@ -137,6 +152,7 @@ module Merb
137
152
  # instead of the port based PID file.
138
153
  def remove_pid_file(port)
139
154
  pidfile = pid_file(port)
155
+ puts "Removing pid file #{pidfile} (port is #{port})..."
140
156
  FileUtils.rm(pidfile) if File.exist?(pidfile)
141
157
  end
142
158
 
@@ -153,10 +169,12 @@ module Merb
153
169
  # instead of the port based PID file.
154
170
  def store_pid(port)
155
171
  pidfile = pid_file(port)
172
+ puts "Storing pid file to #{pidfile}..."
156
173
  FileUtils.mkdir_p(File.dirname(pidfile)) unless File.directory?(File.dirname(pidfile))
174
+ puts "Created directory, writing process id..." if Merb::Config[:verbose]
157
175
  File.open(pidfile, 'w'){ |f| f.write("#{Process.pid}") }
158
176
  end
159
-
177
+
160
178
  # Gets the pid file for the specified port.
161
179
  #
162
180
  # ==== Parameters
@@ -202,8 +220,8 @@ module Merb
202
220
  else
203
221
  Dir[Merb.log_path / "merb.*.pid"]
204
222
  end
205
- end
206
-
223
+ end
224
+
207
225
  # Change privileges of the process to the specified user and group.
208
226
  #
209
227
  # ==== Parameters
@@ -0,0 +1,68 @@
1
+ namespace :audit do
2
+
3
+ desc "Print out the named and anonymous routes"
4
+ task :routes => :merb_env do
5
+ seen = []
6
+ unless Merb::Router.named_routes.empty?
7
+ puts "Named Routes"
8
+ Merb::Router.named_routes.each do |name,route|
9
+ puts " #{name}: #{route}"
10
+ seen << route
11
+ end
12
+ end
13
+ puts "Anonymous Routes"
14
+ (Merb::Router.routes - seen).each do |route|
15
+ puts " #{route}"
16
+ end
17
+ nil
18
+ end
19
+
20
+ desc "Print out all controllers"
21
+ task :controllers => :merb_env do
22
+ puts "\nControllers:\n\n"
23
+ abstract_controller_classes.each do |klass|
24
+ if klass.respond_to?(:subclasses_list)
25
+ puts "#{klass} < #{klass.superclass}"
26
+ subklasses = klass.subclasses_list.sort.map { |x| Object.full_const_get(x) }
27
+ unless subklasses.empty?
28
+ subklasses.each { |subklass| puts "- #{subklass}" }
29
+ else
30
+ puts "~ no subclasses"
31
+ end
32
+ puts
33
+ end
34
+ end
35
+ end
36
+
37
+ desc "Print out controllers and their actions (use CONTROLLER=Foo,Bar to be selective)"
38
+ task :actions => :merb_env do
39
+ puts "\nControllers and their actions:\n\n"
40
+ filter_controllers = ENV['CONTROLLER'] ? ENV['CONTROLLER'].split(',') : nil
41
+ abstract_controllers = abstract_controller_classes
42
+ classes = Merb::AbstractController.subclasses_list.sort.map { |x| Object.full_const_get(x) }
43
+ classes = classes.select { |k| k.name.in?(filter_controllers) } if filter_controllers
44
+ classes.each do |subklass|
45
+ next if subklass.in?(abstract_controllers) || !subklass.respond_to?(:callable_actions)
46
+ puts "#{subklass} < #{subklass.superclass}"
47
+ unless subklass.callable_actions.empty?
48
+ subklass.callable_actions.sort.each do |action, null|
49
+ if subklass.respond_to?(:action_argument_list)
50
+ arguments, defaults = subklass.action_argument_list[action]
51
+ args = arguments.map { |name, value| value ? "#{name} = #{value.inspect}" : name.to_s }.join(', ')
52
+ puts args.empty? ? "- #{action}" : "- #{action}(#{args})"
53
+ else
54
+ puts "- #{action}"
55
+ end
56
+ end
57
+ else
58
+ puts "~ no callable actions"
59
+ end
60
+ puts
61
+ end
62
+ end
63
+
64
+ def abstract_controller_classes
65
+ ObjectSpace.classes.select { |x| x.superclass == Merb::AbstractController }.sort_by { |x| x.name }
66
+ end
67
+
68
+ end
@@ -0,0 +1 @@
1
+ Dir[File.dirname(__FILE__) / '*.rake'].each { |ext| load ext }
@@ -0,0 +1,12 @@
1
+ def sudo
2
+ ENV['MERB_SUDO'] ||= "sudo"
3
+ sudo = windows? ? "" : ENV['MERB_SUDO']
4
+ end
5
+
6
+ def windows?
7
+ (PLATFORM =~ /win32|cygwin/) rescue nil
8
+ end
9
+
10
+ def install_home
11
+ ENV['GEM_HOME'] ? "-i #{ENV['GEM_HOME']}" : ""
12
+ end
@@ -0,0 +1,71 @@
1
+ def show_line(name, stats, color = nil)
2
+ ce = color ? "\033[0m" : ""
3
+ puts "| #{color}#{name.to_s.capitalize.ljust(20)}#{ce} " +
4
+ "| #{color}#{stats[:lines].to_s.rjust(7)}#{ce} " +
5
+ "| #{color}#{stats[:loc].to_s.rjust(7)}#{ce} " +
6
+ "| #{color}#{stats[:classes].to_s.rjust(7)}#{ce} " +
7
+ "| #{color}#{stats[:modules].to_s.rjust(7)}#{ce} " +
8
+ "| #{color}#{stats[:methods].to_s.rjust(7)}#{ce} |"
9
+ puts separator
10
+ end
11
+
12
+ def separator
13
+ '+----------------------+---------+---------+---------+---------+---------+'
14
+ end
15
+
16
+ def check_dir(dir)
17
+ Dir.foreach(dir) do |file_name|
18
+ if File.stat(dir / file_name).directory? and (/^\./ !~ file_name)
19
+ check_dir(dir / file_name)
20
+ end
21
+
22
+ if file_name =~ /.*\.rb$/
23
+ File.open(dir / file_name).each_line do |line|
24
+ @stats[:lines] += 1
25
+ @stats[:loc] += 1 unless line =~ /^\s*$/ || line =~ /^\s*#/
26
+ @stats[:classes] += 1 if line =~ /class [A-Z]/
27
+ @stats[:modules] += 1 if line =~ /module [A-Z]/
28
+ @stats[:methods] += 1 if line =~ /def [a-z]/
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ desc "Lines of code statistics"
35
+ task :stats do
36
+ STATISTICS_DIRS = {
37
+ :controllers => 'app/controllers',
38
+ :helpers => 'app/helpers',
39
+ :models => 'app/models',
40
+ :lib => 'lib',
41
+ :spec => 'spec'
42
+ }
43
+ EMPTY_STATS = { :lines => 0, :loc => 0, :classes => 0, :modules => 0, :methods => 0 }
44
+
45
+ @all = {}
46
+ total = EMPTY_STATS.clone
47
+ ce = "\033[0m"
48
+ cb = "\033[35m"
49
+ cg = "\033[4;32m"
50
+ cr = "\033[31m"
51
+
52
+ puts separator
53
+ puts "| #{cg}Name#{ce} | #{cg}Lines#{ce} | #{cg}LOC#{ce} | #{cg}Classes#{ce} | #{cg}Modules#{ce} | #{cg}Methods#{ce} |"
54
+ puts separator
55
+
56
+ STATISTICS_DIRS.each_pair do |name, dir|
57
+ @stats = EMPTY_STATS.clone
58
+ check_dir(dir)
59
+ @all[name] = @stats
60
+ show_line(name, @stats)
61
+ @stats.each_pair { |type, count| total[type] += count }
62
+ end
63
+
64
+ show_line('Total', total, cr)
65
+
66
+ code_loc = [:controllers, :helpers, :models].inject(0) { |sum, e| sum += @all[e][:loc] }
67
+ test_loc = @all[:spec][:loc]
68
+
69
+ puts " Code LOC: #{cb}#{code_loc}#{ce} Test LOC: #{cb}#{test_loc}#{ce} Test to code radio: #{cb}1:%0.2f#{ce}" % (test_loc.to_f / code_loc.to_f)
70
+ puts
71
+ end
@@ -2,9 +2,10 @@ require "hpricot"
2
2
 
3
3
  require 'merb-core/test/test_ext/hpricot'
4
4
  require 'merb-core/test/test_ext/object'
5
+ require 'merb-core/test/test_ext/string'
5
6
 
6
7
  module Merb; module Test; end; end
7
8
 
8
9
  require 'merb-core/test/helpers'
9
10
 
10
- require 'merb-core/test/matchers'
11
+ require 'merb-core/test/matchers'
@@ -97,8 +97,8 @@ module Merb::Test::MultipartRequestHelper
97
97
  # &blk:: The block is executed in the context of the controller.
98
98
  #
99
99
  # ==== Example
100
- # dispatch_multipart_to(MyController, :create, :my_file => @a_file ) do
101
- # self.stub!(:current_user).and_return(@user)
100
+ # dispatch_multipart_to(MyController, :create, :my_file => @a_file ) do |controller|
101
+ # controller.stub!(:current_user).and_return(@user)
102
102
  # end
103
103
  #
104
104
  # ==== Notes
@@ -172,4 +172,4 @@ module Merb::Test::MultipartRequestHelper
172
172
  :content_length => body.length), :post_body => body)
173
173
  end
174
174
  end
175
- end
175
+ end
@@ -87,8 +87,8 @@ module Merb
87
87
  # the action being dispatched.
88
88
  #
89
89
  # ==== Example
90
- # dispatch_to(MyController, :create, :name => 'Homer' ) do
91
- # self.stub!(:current_user).and_return(@user)
90
+ # dispatch_to(MyController, :create, :name => 'Homer' ) do |controller|
91
+ # controller.stub!(:current_user).and_return(@user)
92
92
  # end
93
93
  #
94
94
  # ==== Notes
@@ -97,12 +97,8 @@ module Merb
97
97
  #---
98
98
  # @public
99
99
  def dispatch_to(controller_klass, action, params = {}, env = {}, &blk)
100
- action = action.to_s
101
- request_body = { :post_body => env[:post_body], :req => env[:req] }
102
- request = fake_request(env.merge(
103
- :query_string => Merb::Request.params_to_query_string(params)), request_body)
104
-
105
- dispatch_request(request, controller_klass, action, &blk)
100
+ params = merge_controller_and_action(controller_klass, action, params)
101
+ dispatch_request(build_request(params, env), controller_klass, action.to_s, &blk)
106
102
  end
107
103
 
108
104
 
@@ -126,8 +122,8 @@ module Merb
126
122
  # the action being dispatched.
127
123
  #
128
124
  # ==== Example
129
- # dispatch_with_basic_authentication_to(MyController, :create, 'Fred', 'secret', :name => 'Homer' ) do
130
- # self.stub!(:current_user).and_return(@user)
125
+ # dispatch_with_basic_authentication_to(MyController, :create, 'Fred', 'secret', :name => 'Homer' ) do |controller|
126
+ # controller.stub!(:current_user).and_return(@user)
131
127
  # end
132
128
  #
133
129
  # ==== Notes
@@ -136,13 +132,47 @@ module Merb
136
132
  #---
137
133
  # @public
138
134
  def dispatch_with_basic_authentication_to(controller_klass, action, username, password, params = {}, env = {}, &blk)
139
- action = action.to_s
140
- request_body = { :post_body => env[:post_body], :req => env[:req] }
141
135
  env["X_HTTP_AUTHORIZATION"] = "Basic #{Base64.encode64("#{username}:#{password}")}"
142
- request = fake_request(env.merge(
143
- :query_string => Merb::Request.params_to_query_string(params)), request_body)
136
+
137
+ params = merge_controller_and_action(controller_klass, action, params)
138
+ dispatch_request(build_request(params, env), controller_klass, action.to_s, &blk)
139
+ end
140
+
141
+ def merge_controller_and_action(controller_klass, action, params)
142
+ params[:controller] = controller_klass.name.to_const_path
143
+ params[:action] = action.to_s
144
+
145
+ params
146
+ end
144
147
 
145
- dispatch_request(request, controller_klass, action, &blk)
148
+ # Prepares and returns a request suitable for dispatching with
149
+ # dispatch_request. If you don't need to modify the request
150
+ # object before dispatching (e.g. to add cookies), you probably
151
+ # want to use dispatch_to instead.
152
+ #
153
+ # ==== Parameters
154
+ # params<Hash>::
155
+ # An optional hash that will end up as params in the controller instance.
156
+ # env<Hash>::
157
+ # An optional hash that is passed to the fake request. Any request options
158
+ # should go here (see +fake_request+), including :req or :post_body
159
+ # for setting the request body itself.
160
+ #
161
+ # ==== Example
162
+ # req = build_request(:id => 1)
163
+ # req.cookies['app_cookie'] = "testing"
164
+ # dispatch_request(req, MyController, :edit)
165
+ #
166
+ # ==== Notes
167
+ # Does not use routes.
168
+ #
169
+ #---
170
+ # @public
171
+ def build_request(params = {}, env = {})
172
+ params = Merb::Request.params_to_query_string(params)
173
+ env[:query_string] = env["QUERY_STRING"] ? "#{env["QUERY_STRING"]}&#{params}" : params
174
+
175
+ fake_request(env, { :post_body => env[:post_body], :req => env[:req] })
146
176
  end
147
177
 
148
178
  # An HTTP GET request that operates through the router.
@@ -157,6 +187,8 @@ module Merb
157
187
  # &blk::
158
188
  # The controller is yielded to the block provided for actions *prior* to
159
189
  # the action being dispatched.
190
+ #---
191
+ # @public
160
192
  def get(path, params = {}, env = {}, &block)
161
193
  env[:request_method] = "GET"
162
194
  request(path, params, env, &block)
@@ -174,6 +206,8 @@ module Merb
174
206
  # &blk::
175
207
  # The controller is yielded to the block provided for actions *prior* to
176
208
  # the action being dispatched.
209
+ #---
210
+ # @public
177
211
  def post(path, params = {}, env = {}, &block)
178
212
  env[:request_method] = "POST"
179
213
  request(path, params, env, &block)
@@ -191,6 +225,8 @@ module Merb
191
225
  # &blk::
192
226
  # The controller is yielded to the block provided for actions *prior* to
193
227
  # the action being dispatched.
228
+ #---
229
+ # @public
194
230
  def put(path, params = {}, env = {}, &block)
195
231
  env[:request_method] = "PUT"
196
232
  request(path, params, env, &block)
@@ -208,6 +244,8 @@ module Merb
208
244
  # &blk::
209
245
  # The controller is yielded to the block provided for actions *prior* to
210
246
  # the action being dispatched.
247
+ #---
248
+ # @public
211
249
  def delete(path, params = {}, env = {}, &block)
212
250
  env[:request_method] = "DELETE"
213
251
  request(path, params, env, &block)
@@ -228,8 +266,8 @@ module Merb
228
266
  # the action being dispatched.
229
267
  #
230
268
  # ==== Example
231
- # request(path, { :name => 'Homer' }, { :request_method => "PUT" }) do
232
- # self.stub!(:current_user).and_return(@user)
269
+ # request(path, { :name => 'Homer' }, { :request_method => "PUT" }) do |controller|
270
+ # controller.stub!(:current_user).and_return(@user)
233
271
  # end
234
272
  #
235
273
  # ==== Notes
@@ -239,7 +277,8 @@ module Merb
239
277
  # @semi-public
240
278
  def request(path, params = {}, env= {}, &block)
241
279
  env[:request_method] ||= "GET"
242
- env[:request_uri] = path
280
+ env[:request_uri], env[:query_string] = path.split('?')
281
+
243
282
  multipart = env.delete(:test_with_multipart)
244
283
 
245
284
  request = fake_request(env)
@@ -274,7 +313,7 @@ module Merb
274
313
  # Does not use routes.
275
314
  #
276
315
  #---
277
- # @private
316
+ # @public
278
317
  def dispatch_request(request, controller_klass, action, &blk)
279
318
  controller = controller_klass.new(request)
280
319
  yield controller if block_given?
@@ -298,14 +337,17 @@ module Merb
298
337
  #
299
338
  # ==== Returns
300
339
  # Hash:: The parameters built based on the matching route.
340
+ #
341
+ #---
342
+ # @semi-public
301
343
  def check_request_for_route(request)
302
344
  match = ::Merb::Router.match(request)
303
- if match[0].nil?
345
+ if match[0].nil? && match[1].empty?
304
346
  raise ::Merb::ControllerExceptions::BadRequest, "No routes match the request"
305
347
  else
306
348
  match[1]
307
349
  end
308
- end
309
- end
310
- end
311
- end
350
+ end # check_request_for_route
351
+ end # RequestHelper
352
+ end # Test
353
+ end # Merb