merb 0.4.2 → 0.5.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 (108) hide show
  1. data/README +21 -14
  2. data/Rakefile +157 -108
  3. data/SVN_REVISION +1 -0
  4. data/app_generators/merb/templates/Rakefile +20 -4
  5. data/app_generators/merb/templates/app/views/exceptions/internal_server_error.html.erb +1 -1
  6. data/app_generators/merb/templates/config/boot.rb +1 -1
  7. data/app_generators/merb/templates/config/dependencies.rb +3 -3
  8. data/app_generators/merb/templates/config/merb.yml +5 -0
  9. data/app_generators/merb/templates/config/merb_init.rb +3 -3
  10. data/app_generators/merb/templates/script/destroy +3 -0
  11. data/app_generators/merb/templates/script/generate +1 -1
  12. data/app_generators/merb/templates/spec/spec_helper.rb +2 -2
  13. data/app_generators/merb/templates/test/test_helper.rb +1 -1
  14. data/app_generators/merb_plugin/merb_plugin_generator.rb +4 -0
  15. data/bin/merb +1 -3
  16. data/lib/merb.rb +144 -76
  17. data/lib/merb/abstract_controller.rb +6 -5
  18. data/lib/merb/assets.rb +119 -0
  19. data/lib/merb/boot_loader.rb +217 -0
  20. data/lib/merb/caching.rb +1 -1
  21. data/lib/merb/caching/action_cache.rb +1 -1
  22. data/lib/merb/caching/fragment_cache.rb +1 -1
  23. data/lib/merb/caching/store/file_cache.rb +1 -1
  24. data/lib/merb/config.rb +290 -0
  25. data/lib/merb/controller.rb +5 -5
  26. data/lib/merb/core_ext/get_args.rb +1 -0
  27. data/lib/merb/core_ext/hash.rb +182 -169
  28. data/lib/merb/core_ext/kernel.rb +57 -26
  29. data/lib/merb/dispatcher.rb +6 -6
  30. data/lib/merb/drb_server.rb +1 -1
  31. data/lib/merb/generators/merb_generator_helpers.rb +7 -6
  32. data/lib/merb/logger.rb +1 -1
  33. data/lib/merb/mail_controller.rb +3 -4
  34. data/lib/merb/mailer.rb +2 -2
  35. data/lib/merb/mixins/basic_authentication.rb +2 -2
  36. data/lib/merb/mixins/controller.rb +1 -1
  37. data/lib/merb/mixins/general_controller.rb +13 -20
  38. data/lib/merb/mixins/inline_partial.rb +32 -0
  39. data/lib/merb/mixins/render.rb +3 -3
  40. data/lib/merb/mixins/responder.rb +1 -1
  41. data/lib/merb/mixins/view_context.rb +159 -33
  42. data/lib/merb/mongrel_handler.rb +9 -9
  43. data/lib/merb/plugins.rb +1 -1
  44. data/lib/merb/request.rb +25 -1
  45. data/lib/merb/router.rb +264 -226
  46. data/lib/merb/server.rb +66 -560
  47. data/lib/merb/session/cookie_store.rb +14 -13
  48. data/lib/merb/session/mem_cache_session.rb +20 -10
  49. data/lib/merb/session/memory_session.rb +21 -11
  50. data/lib/merb/template.rb +2 -2
  51. data/lib/merb/template/erubis.rb +3 -33
  52. data/lib/merb/template/haml.rb +8 -3
  53. data/lib/merb/test/fake_request.rb +8 -3
  54. data/lib/merb/test/helper.rb +66 -22
  55. data/lib/merb/test/rspec.rb +9 -155
  56. data/lib/merb/test/rspec_matchers/controller_matchers.rb +117 -0
  57. data/lib/merb/test/rspec_matchers/markup_matchers.rb +98 -0
  58. data/lib/merb/upload_handler.rb +2 -1
  59. data/lib/merb/version.rb +38 -3
  60. data/lib/merb/view_context.rb +1 -2
  61. data/lib/tasks/merb.rake +11 -11
  62. data/merb_generators/part_controller/USAGE +5 -0
  63. data/merb_generators/part_controller/part_controller_generator.rb +27 -0
  64. data/merb_generators/part_controller/templates/controller.rb +8 -0
  65. data/merb_generators/part_controller/templates/helper.rb +5 -0
  66. data/merb_generators/part_controller/templates/index.html.erb +3 -0
  67. data/rspec_generators/merb_controller_test/merb_controller_test_generator.rb +1 -1
  68. data/script/destroy +14 -0
  69. data/script/generate +14 -0
  70. data/spec/fixtures/controllers/dispatch_spec_controllers.rb +9 -1
  71. data/spec/fixtures/controllers/render_spec_controllers.rb +5 -5
  72. data/spec/fixtures/models/router_spec_models.rb +10 -0
  73. data/spec/merb/abstract_controller_spec.rb +2 -2
  74. data/spec/merb/assets_spec.rb +207 -0
  75. data/spec/merb/caching_spec.rb +2 -2
  76. data/spec/merb/controller_spec.rb +7 -2
  77. data/spec/merb/cookie_store_spec.rb +1 -1
  78. data/spec/merb/core_ext/class_spec.rb +97 -0
  79. data/spec/merb/core_ext/enumerable_spec.rb +27 -0
  80. data/spec/merb/core_ext/hash_spec.rb +251 -0
  81. data/spec/merb/core_ext/inflector_spec.rb +34 -0
  82. data/spec/merb/core_ext/kernel_spec.rb +25 -0
  83. data/spec/merb/core_ext/numeric_spec.rb +26 -0
  84. data/spec/merb/core_ext/object_spec.rb +47 -0
  85. data/spec/merb/core_ext/string_spec.rb +22 -0
  86. data/spec/merb/core_ext/symbol_spec.rb +7 -0
  87. data/spec/merb/dependency_spec.rb +22 -0
  88. data/spec/merb/dispatch_spec.rb +23 -12
  89. data/spec/merb/fake_request_spec.rb +8 -0
  90. data/spec/merb/generator_spec.rb +140 -21
  91. data/spec/merb/handler_spec.rb +5 -5
  92. data/spec/merb/mail_controller_spec.rb +3 -3
  93. data/spec/merb/render_spec.rb +1 -1
  94. data/spec/merb/responder_spec.rb +3 -3
  95. data/spec/merb/router_spec.rb +260 -191
  96. data/spec/merb/server_spec.rb +5 -5
  97. data/spec/merb/upload_handler_spec.rb +7 -0
  98. data/spec/merb/version_spec.rb +33 -0
  99. data/spec/merb/view_context_spec.rb +217 -59
  100. data/spec/spec_generator_helper.rb +15 -0
  101. data/spec/spec_helper.rb +5 -3
  102. data/spec/spec_helpers/url_shared_behaviour.rb +5 -7
  103. metadata +32 -7
  104. data/lib/merb/caching/store/memcache.rb +0 -20
  105. data/lib/merb/mixins/form_control.rb +0 -332
  106. data/lib/patch +0 -69
  107. data/spec/merb/core_ext_spec.rb +0 -464
  108. data/spec/merb/form_control_mixin_spec.rb +0 -431
@@ -0,0 +1,117 @@
1
+ module Merb
2
+ module Test
3
+ module ControllerMatchers
4
+
5
+ class BeRedirect
6
+ def matches?(target)
7
+ @target = target
8
+ target == 302
9
+ end
10
+ def failure_message
11
+ "expected to redirect"
12
+ end
13
+ def negative_failure_message
14
+ "expected not to redirect"
15
+ end
16
+ end
17
+
18
+ class Redirect
19
+ def matches?(target)
20
+ @target = target
21
+ BeRedirect.new.matches?(target.status)
22
+ end
23
+ def failure_message
24
+ "expected #{@target.inspect} to redirect"
25
+ end
26
+ def negative_failure_message
27
+ "expected #{@target.inspect} not to redirect"
28
+ end
29
+ end
30
+
31
+ class RedirectTo
32
+ def initialize(expected)
33
+ @expected = expected
34
+ end
35
+
36
+ def matches?(target)
37
+ @target = target.headers['Location']
38
+ @redirected = BeRedirect.new.matches?(target.status)
39
+ @target == @expected
40
+ end
41
+
42
+ def failure_message
43
+ msg = "expected a redirect to <#{@expected}>, but "
44
+ if @redirected
45
+ msg << "found one to <#{@target}>"
46
+ else
47
+ msg << "there was no redirect"
48
+ end
49
+ end
50
+
51
+ def negative_failure_message
52
+ "expected not to redirect to <#{@expected}>, but did anyway"
53
+ end
54
+ end
55
+
56
+ class BeSuccess
57
+
58
+ def matches?(target)
59
+ @target = target.status
60
+ (200..299).include?(@target)
61
+ end
62
+
63
+ def failure_message
64
+ "expected #{@target} to be successful but was #{@target.status}"
65
+ end
66
+
67
+ def negative_failure_message
68
+ "expected #{@target} not to be successful but it was"
69
+ end
70
+ end
71
+
72
+ class BeMissing
73
+ def matches?(target)
74
+ @target = target
75
+ (400..499).include?(@target.status)
76
+ end
77
+
78
+ def failurs_message
79
+ "expected #{@target} to be missing but was #{@target.status}"
80
+ end
81
+
82
+ def negative_failure_message
83
+ "expected #{@target} not to be missing but it was"
84
+ end
85
+ end
86
+
87
+
88
+ def be_redirect
89
+ BeRedirect.new
90
+ end
91
+
92
+ def redirect
93
+ Redirect.new
94
+ end
95
+
96
+ def redirect_to(expected)
97
+ RedirectTo.new(expected)
98
+ end
99
+
100
+ def be_success
101
+ BeSuccess.new
102
+ end
103
+
104
+ def be_successful
105
+ BeSuccess.new
106
+ end
107
+
108
+ def respond_successfully
109
+ BeSuccess.new
110
+ end
111
+
112
+ def be_missing
113
+ BeMissing.new
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,98 @@
1
+ module Merb
2
+ module Test
3
+ module MarkupMatchers
4
+ class HaveSelector
5
+ def initialize(expected)
6
+ @expected = expected
7
+ end
8
+
9
+ def matches?(stringlike)
10
+ @document = case stringlike
11
+ when Hpricot::Elem
12
+ stringlike
13
+ when StringIO
14
+ Hpricot.parse(stringlike.string)
15
+ else
16
+ Hpricot.parse(stringlike)
17
+ end
18
+ !@document.search(@expected).empty?
19
+ end
20
+
21
+ def failure_message
22
+ "expected following text to match selector #{@expected}:\n#{@document}"
23
+ end
24
+
25
+ def negative_failure_message
26
+ "expected following text to not match selector #{@expected}:\n#{@document}"
27
+ end
28
+ end
29
+
30
+ class MatchTag
31
+ def initialize(name, attrs)
32
+ @name, @attrs = name, attrs
33
+ @content = @attrs.delete(:content)
34
+ end
35
+
36
+ def matches?(target)
37
+ @errors = []
38
+ unless target.include?("<#{@name}")
39
+ @errors << "Expected a <#{@name}>, but was #{target}"
40
+ end
41
+ @attrs.each do |attr, val|
42
+ unless target.include?("#{attr}=\"#{val}\"")
43
+ @errors << "Expected #{attr}=\"#{val}\", but was #{target}"
44
+ end
45
+ end
46
+ if @content
47
+ unless target.include?(">#{@content}<")
48
+ @errors << "Expected #{target} to include #{@content}"
49
+ end
50
+ end
51
+ @errors.size == 0
52
+ end
53
+
54
+ def failure_message
55
+ @errors[0]
56
+ end
57
+
58
+ def negative_failure_message
59
+ "Expected not to match against <#{@name} #{@attrs.map{ |a,v| "#{a}=\"#{v}\"" }.join(" ")}> tag, but it matched"
60
+ end
61
+ end
62
+
63
+ class NotMatchTag
64
+ def initialize(attrs)
65
+ @attrs = attrs
66
+ end
67
+
68
+ def matches?(target)
69
+ @errors = []
70
+ @attrs.each do |attr, val|
71
+ if target.include?("#{attr}=\"#{val}\"")
72
+ @errors << "Should not include #{attr}=\"#{val}\", but was #{target}"
73
+ end
74
+ end
75
+ @errors.size == 0
76
+ end
77
+
78
+ def failure_message
79
+ @errors[0]
80
+ end
81
+ end
82
+
83
+ def match_tag(name, attrs={})
84
+ MatchTag.new(name, attrs)
85
+ end
86
+ def not_match_tag(attrs)
87
+ NotMatchTag.new(attrs)
88
+ end
89
+
90
+ def have_selector(expected)
91
+ HaveSelector.new(expected)
92
+ end
93
+ alias_method :match_selector, :have_selector
94
+
95
+
96
+ end
97
+ end
98
+ end
@@ -56,7 +56,8 @@ class MerbUploadHandler < Mongrel::HttpHandler
56
56
  def request_aborted(params)
57
57
  return unless upload_id = valid_upload?(params)
58
58
  Mongrel::Uploads.finish(upload_id)
59
- puts "request aborted!"
59
+ Merb.logger.info "#{self.class.name} - request aborted for " <<
60
+ "id: #{upload_id.inspect}, params: #{params.inspect}"
60
61
  end
61
62
 
62
63
  private
@@ -1,5 +1,38 @@
1
1
  module Merb
2
- VERSION='0.4.2' unless defined?(::Merb::VERSION)
2
+ VERSION = '0.5.0' unless defined?(::Merb::VERSION)
3
+
4
+ class << self
5
+ def svn_revision
6
+ rev = if File.directory?('.git')
7
+ `git log -1`[/git-svn-id.+@(\d+)/, 1]
8
+ elsif File.directory?('.svn')
9
+ `svn info`[/Revision: (\d+)/, 1]
10
+ end
11
+ rev = rev.to_i if rev
12
+ end
13
+
14
+ def svn_revision_filename
15
+ 'SVN_REVISION'
16
+ end
17
+
18
+ def svn_revision_from_file
19
+ begin
20
+ File.open svn_revision_file_path, 'w' do |f|
21
+ f.print svn_revision
22
+ end
23
+ # catch permissions error when packaged as gem
24
+ rescue Errno::EACCES
25
+ end
26
+
27
+ unless (rev = File.read(svn_revision_file_path).strip).empty?
28
+ rev.to_i
29
+ end
30
+ end
31
+
32
+ def svn_revision_file_path
33
+ File.expand_path File.join(File.dirname(__FILE__), '..', '..', svn_revision_filename)
34
+ end
35
+ end
3
36
 
4
37
  # Merb::RELEASE meanings:
5
38
  # 'svn' : unreleased
@@ -7,5 +40,7 @@ module Merb
7
40
  # nil : released
8
41
  # You should never check in to trunk with this changed. It should
9
42
  # stay 'svn'. Change it to nil in release tags.
10
- RELEASE='svn' unless defined?(::Merb::RELEASE)
11
- end
43
+ unless defined?(::Merb::RELEASE)
44
+ RELEASE = "svn#{" r#{svn_revision_from_file}" if svn_revision_from_file}"
45
+ end
46
+ end
@@ -33,7 +33,6 @@ module Merb
33
33
  # the context object passed to Erubis when evaluating the templates.
34
34
  class ViewContext
35
35
  include Merb::ViewContextMixin
36
- include Merb::FormControls
37
36
  include Merb::WebControllerMixin
38
37
 
39
38
  def initialize(controller)
@@ -45,7 +44,7 @@ module Merb
45
44
  begin
46
45
  self.class.class_eval(" include Merb::GlobalHelper; include Merb::#{@web_controller.class.name}Helper")
47
46
  rescue NameError
48
- MERB_LOGGER.debug("Missing Helper: Merb::#{@web_controller.class.name}Helper")
47
+ Merb.logger. debug("Missing Helper: Merb::#{@web_controller.class.name}Helper")
49
48
  end
50
49
  end
51
50
 
@@ -1,5 +1,5 @@
1
1
  def install_merb_script
2
- script_filepath = MERB_ROOT / 'script/merb'
2
+ script_filepath = Merb.root / 'script/merb'
3
3
  FileUtils.rm script_filepath if File.exist? script_filepath
4
4
  tmpl = "#!/usr/bin/env ruby\nrequire File.expand_path(File.dirname(__FILE__)+'/../framework/merb/server')\nMerb::Server.run\n"
5
5
  File.open(script_filepath, 'wb') {|f|
@@ -11,8 +11,8 @@ end
11
11
  namespace :merb do
12
12
  desc "freeze the merb framework into merb for portability"
13
13
  task :freeze do
14
- FileUtils.rm_rf MERB_ROOT / 'framework'
15
- FileUtils.cp_r MERB_FRAMEWORK_ROOT, (MERB_ROOT / 'framework')
14
+ FileUtils.rm_rf Merb.root / 'framework'
15
+ FileUtils.cp_r Merb::framework_root, (Merb.root / 'framework')
16
16
  install_merb_script
17
17
 
18
18
  puts " Freezing Merb Framework into framework"
@@ -20,17 +20,17 @@ namespace :merb do
20
20
  end
21
21
  desc "unfreeze this app from the framework and use system gem."
22
22
  task :unfreeze do
23
- FileUtils.rm_rf MERB_ROOT / 'framework'
24
- FileUtils.rm MERB_ROOT / 'script/merb'
23
+ FileUtils.rm_rf Merb.root / 'framework'
24
+ FileUtils.rm Merb.root / 'script/merb'
25
25
 
26
26
  puts " Removed: "
27
- puts " - #{MERB_ROOT / 'framework'} (recursive) "
28
- puts " - #{MERB_ROOT / 'script/merb'}"
27
+ puts " - #{Merb.root / 'framework'} (recursive) "
28
+ puts " - #{Merb.root / 'script/merb'}"
29
29
  end
30
30
 
31
31
  desc "freeze the merb framework from svn, use REVISION=# to freeze a specific revision"
32
32
  task :freeze_from_svn do
33
- install_path = MERB_ROOT / 'framework'
33
+ install_path = Merb.root / 'framework'
34
34
  revision = ENV['REVISION'] || 'HEAD'
35
35
  puts " Removing old framework" if File.exist? install_path
36
36
  FileUtils.rm_rf install_path
@@ -48,7 +48,7 @@ desc "Setup the Merb Environment by requiring merb and loading your merb_init.rb
48
48
  task :merb_env do
49
49
  require 'rubygems'
50
50
  require 'merb'
51
- Merb::Server.config[:environment] = ENV['MERB_ENV'] if ENV['MERB_ENV']
52
- MERB_ENV = Merb::Server.config[:environment].nil? ? 'development' : Merb::Server.config[:environment]
53
- load MERB_ROOT+'/config/merb_init.rb'
51
+ Merb::Config[:environment] = ENV['Merb.environment'] if ENV['Merb.environment']
52
+ Merb.environment = Merb::Config[:environment].nil? ? 'development' : Merb::Config[:environment]
53
+ load Merb.root+'/config/merb_init.rb'
54
54
  end
@@ -0,0 +1,5 @@
1
+ Description:
2
+ Generates a PartController
3
+
4
+ Usage:
5
+ script/generate part_controller name
@@ -0,0 +1,27 @@
1
+ require 'merb/generators/merb_generator_helpers'
2
+
3
+ class PartControllerGenerator < Merb::GeneratorHelpers::ControllerGeneratorBase
4
+
5
+ def initialize(*args)
6
+ runtime_options = args.last.is_a?(Hash) ? args.pop : {}
7
+ name, *actions = args.flatten
8
+ name += "_part"
9
+
10
+ runtime_options[:actions] = actions.empty? ? %w[index] : actions
11
+ runtime_options[:base_dest_folder] = "app/parts"
12
+ super( [name], runtime_options )
13
+ end
14
+
15
+ def self.superclass
16
+ RubiGen::Base
17
+ end
18
+
19
+ protected
20
+ def banner
21
+ <<-EOS
22
+ Creates a Merb part_controller
23
+
24
+ USAGE: #{$0} #{spec.name} name"
25
+ EOS
26
+ end
27
+ end
@@ -0,0 +1,8 @@
1
+ class <%= class_name %>Part < Merb::PartController
2
+ <% actions.each do |action| -%>
3
+
4
+ def <%= action %>
5
+ render
6
+ end
7
+ <% end -%>
8
+ end
@@ -0,0 +1,5 @@
1
+ module Merb
2
+ module <%= class_name %>PartHelper
3
+
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ <h1><%= class_name %>Part controller, index action</h1>
2
+
3
+ <p>Edit this file in <tt>app/parts/views/<%= file_name %>/index.html.erb</tt></p>
@@ -27,7 +27,7 @@ class MerbControllerTestGenerator < RubiGen::Base
27
27
  # Setup the view stubs for each view
28
28
  @template_actions.each do |the_action|
29
29
  template_name = "#{the_action}.html.#{@engine}"
30
- if File.exists?(File.join(MERB_ROOT, "app", "views", file_name, template_name))
30
+ if File.exists?(File.join(Merb.root, "app", "views", file_name, template_name))
31
31
  m.template "#{the_action}_spec.rb", "spec/views/#{file_name}/#{the_action}_html_spec.rb"
32
32
  end
33
33
  end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.join(File.dirname(__FILE__), '..')
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :rspec]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.join(File.dirname(__FILE__), '..')
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :rspec]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -32,6 +32,14 @@ class Bar < Merb::Controller
32
32
  "#{a} #{b} #{c}"
33
33
  end
34
34
 
35
+ def bat(a, b = false)
36
+ "#{a} #{b}"
37
+ end
38
+
39
+ def bam(a, b = nil)
40
+ "#{a} #{b.inspect}"
41
+ end
42
+
35
43
  end
36
44
 
37
45
  class Baz < Merb::Controller
@@ -224,4 +232,4 @@ class Profile < Merb::Controller
224
232
  end
225
233
 
226
234
  # If this throws an error, it's because parameterized args are somehow borked
227
- Merb::Server.load_application
235
+ Merb::BootLoader.load_application