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,34 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe Inflector do
4
+ it "should transform words from singular to plural" do
5
+ "post".pluralize.should == "posts"
6
+ "octopus".pluralize.should =="octopi"
7
+ "the blue mailman".pluralize.should == "the blue mailmen"
8
+ "CamelOctopus".pluralize.should == "CamelOctopi"
9
+ end
10
+
11
+ it "should transform words from plural to singular" do
12
+ "posts".singularize.should == "post"
13
+ "octopi".singularize.should == "octopus"
14
+ "the blue mailmen".singularize.should == "the blue mailman"
15
+ "CamelOctopi".singularize.should == "CamelOctopus"
16
+ end
17
+
18
+ it "should transform class names to table names" do
19
+ "RawScaledScorer".tableize.should == "raw_scaled_scorers"
20
+ "egg_and_ham".tableize.should == "egg_and_hams"
21
+ "fancyCategory".tableize.should == "fancy_categories"
22
+ end
23
+
24
+ it "should tranform table names to class names" do
25
+ "egg_and_hams".classify.should == "EggAndHam"
26
+ "post".classify.should == "Post"
27
+ end
28
+
29
+ it "should create a foreign key name from a class name" do
30
+ "Message".foreign_key.should == "message_id"
31
+ "Message".foreign_key(false).should == "messageid"
32
+ "Admin::Post".foreign_key.should == "post_id"
33
+ end
34
+ end
@@ -0,0 +1,25 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe "extracting options from arguments" do
4
+ def the_method(*args)
5
+ [extract_options_from_args!(args), args]
6
+ end
7
+
8
+ it "should extract the hash if the last item is a hash" do
9
+ opts,args = the_method(:one, :two, :key => :value)
10
+ opts.should == { :key => :value }
11
+ args.should == [:one, :two]
12
+ end
13
+
14
+ it "should return nil for the opts if no hash is provided" do
15
+ opts,args = the_method(:one, :two)
16
+ opts.should be_nil
17
+ args.should == [:one, :two]
18
+ end
19
+
20
+ it "should return two hashes" do
21
+ opts,args = the_method({ :one => :two }, { :key => :value })
22
+ opts.should == {:key => :value}
23
+ args.should == [{:one => :two}]
24
+ end
25
+ end
@@ -0,0 +1,26 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe "A Numeric object" do
4
+ it "should be able to convert to US currency" do
5
+ 1.5.to_currency.should == "$1.50"
6
+ end
7
+
8
+ it "should be able to convert to Danish currency" do
9
+ 15_000_000.5.to_currency(nil, ".", ",", "DM").should == "15.000.000,50DM"
10
+ end
11
+
12
+ {
13
+ :microsecond => Float(10 ** -6), :millisecond => Float(10 ** -3), :second => 1,
14
+ :minute => 60, :hour => 3600, :day => 86400, :week => 604800,
15
+ :month => 2592000, :year => 31536000, :decade => 315360000
16
+ }.each do |method,seconds|
17
+
18
+ it "should be able to convert to #{method}s (singular version)" do
19
+ 1.send(method).should == seconds
20
+ end
21
+
22
+ it "should be able to convert to #{method}s (plural version)" do
23
+ 2.send("#{method}s").should == seconds * 2
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,47 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ class String
4
+ def self.define_meta(meth, val)
5
+ meta_def(meth) { val }
6
+ end
7
+ end
8
+ class MyString < String; end
9
+
10
+ describe "An object" do
11
+ it "should be able to return a passed in object that is modified by a block" do
12
+ (returning({}) {|x| x.merge!(:foo => :bar)}).should == {:foo => :bar}
13
+ end
14
+
15
+ it "should be able to get a meta class" do
16
+ MyString.meta_class.to_s.should == "#<Class:MyString>"
17
+ end
18
+
19
+ it "should be able to execute code in the meta-class' context" do
20
+ (MyString.meta_eval { self }).should == MyString.meta_class
21
+ end
22
+
23
+ it "should be able to define a method on the meta-class" do
24
+ MyString.define_meta :foo, :bar
25
+ MyString.foo.should == :bar
26
+ end
27
+
28
+ it "should be able to define methods on its instances" do
29
+ MyString.class_def(:foo) { :bar }
30
+ MyString.new.foo.should == :bar
31
+ end
32
+
33
+ {[] => true,
34
+ [1] => false,
35
+ [nil] => false,
36
+ nil => true,
37
+ true => false,
38
+ false => true,
39
+ "" => true,
40
+ " " => true,
41
+ " hey " => false
42
+ }.each do |obj, expected|
43
+ it "should be able to determine whether the #{obj.class} #{obj.inspect} is blank" do
44
+ obj.blank?.should == expected
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,22 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe "A String" do
4
+ it "should convert a path/like/this to a Constant::String::Like::This" do
5
+ "path/like/this".to_const_string.should == "Path::Like::This"
6
+ "path".to_const_string.should == "Path"
7
+ "snake_case/path/with_several_parts".to_const_string.should == "SnakeCase::Path::WithSeveralParts"
8
+ end
9
+
10
+ it "should raise an error rather than freeze when trying to convert bad Paths/12Like/-this" do
11
+ Timeout::timeout(1) do
12
+ lambda do
13
+ "Paths/12Like/-this".to_const_string
14
+ end.should raise_error(String::InvalidPathConversion)
15
+ end.should_not raise_error(Timeout::Error)
16
+ end
17
+
18
+ it "should remove any indentation and add +indentation+ number of spaces" do
19
+ "foo\n bar\n".indent(3).should == " foo\n bar\n"
20
+ " foo\n bar\n".indent(3).should == " foo\n bar\n"
21
+ end
22
+ end
@@ -0,0 +1,7 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe Symbol do
4
+ it "should be able to call Symbol#to_proc" do
5
+ ['foo', 'bar'].map(&:reverse).should == ['oof', 'rab']
6
+ end
7
+ end
@@ -0,0 +1,22 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe "Kernel#dependency" do
4
+
5
+ before do
6
+ File.stub!(:directory?).with(Merb.root / "gems").and_return(true)
7
+ Gem.stub!(:use_paths)
8
+ Gem.stub!(:clear_paths)
9
+ end
10
+
11
+ it "loads in files from the local gem-cache first" do
12
+ Gem.should_receive(:activate).with("json_pure", true).and_return(true)
13
+ Kernel.dependency "json_pure"
14
+ end
15
+
16
+ it "does a require if it can't find it in either gem cache" do
17
+ Gem.stub!(:activate).twice.with("RedCloth", true).and_raise(LoadError)
18
+ Kernel.should_receive(:require).with("RedCloth")
19
+ Kernel.dependency "RedCloth"
20
+ end
21
+
22
+ end
@@ -6,22 +6,25 @@ $TESTING = true
6
6
  describe Merb::Dispatcher do
7
7
 
8
8
  before(:all) do
9
- Merb::Server.config[:allow_reloading] = false
9
+ Merb::Config[:allow_reloading] = false
10
10
  Merb::Router.prepare do |r|
11
11
  r.resource :icon
12
- r.resources :posts, :member => {:stats => [:get, :put]},
13
- :collection => {:filter => [:get]} do |post|
14
- post.resources :comments, :member => {:stats => [:get, :put]}
12
+ r.resources :posts,
13
+ :member => { :stats => [:get, :put] },
14
+ :collection => { :filter => [:get] } do |post|
15
+ post.resources :comments, :member => { :stats => [:get, :put] }
15
16
  post.resource :profile
16
- end
17
+ end
17
18
  r.resources :as do |a|
18
19
  a.resources :bs do |b|
19
20
  b.resources :cs
20
21
  end
21
22
  end
22
- r.match("/admin") do |admin|
23
+
24
+ r.match('/admin') do |admin|
23
25
  admin.resources :tags
24
26
  end
27
+
25
28
  r.default_routes
26
29
  end
27
30
  end
@@ -31,12 +34,12 @@ describe Merb::Dispatcher do
31
34
  controller.class.should == Foo
32
35
  action.should == "bar"
33
36
  controller.params[:id].should == '42'
34
- end
37
+ end
35
38
 
36
39
  it "should not allow private and protected methods to be called" do
37
40
  controller, action = request(:get, '/foo/call_filters')
38
41
  controller.status.should == Merb::ControllerExceptions::ActionNotFound::STATUS
39
- end
42
+ end
40
43
 
41
44
  it "should handle request: GET /foo/bar and return Foo#bar" do
42
45
  controller, action = request(:get, '/foo/bar')
@@ -148,7 +151,7 @@ describe Merb::Dispatcher do
148
151
  controller.params[:format].should == 'xml'
149
152
  controller.body.should == :index
150
153
  end
151
-
154
+
152
155
  it "should handle request: GET /posts and return Posts#index" do
153
156
  controller, action = request(:get, '/posts')
154
157
  controller.class.should == Posts
@@ -493,7 +496,7 @@ describe Merb::Dispatcher do
493
496
  controller, action = request(:get, '/pos-ts/1')
494
497
  controller.status.should == Merb::ControllerExceptions::NotFound::STATUS
495
498
  end
496
-
499
+
497
500
  if defined?(ParseTreeArray)
498
501
  it "should support parameterized actions with required arguments" do
499
502
  controller, action = request(:get, '/bar/foo/1')
@@ -514,7 +517,15 @@ describe Merb::Dispatcher do
514
517
  controller, action = request(:get, '/bar/baz?a=1&c=5')
515
518
  controller.body.should == "1 2 5"
516
519
  end
520
+
521
+ it "should support actionargs with false as defaults" do
522
+ controller, action = request(:get, '/bar/bat?a=1')
523
+ controller.body.should == "1 false"
524
+ end
525
+
526
+ it "should support actionargs with nil as defaults" do
527
+ controller, action = request(:get, '/bar/bam?a=1')
528
+ controller.body.should == "1 nil"
529
+ end
517
530
  end
518
-
519
-
520
531
  end
@@ -69,4 +69,12 @@ describe Merb::Test::FakeRequest, "[]=(key, value)" do
69
69
  @mock['HTTP_ACCEPT'] = 'also/credit_card'
70
70
  @mock['HTTP_ACCEPT'].should == 'also/credit_card'
71
71
  end
72
+ end
73
+
74
+ describe Merb::Test::FakeRequest, "session" do
75
+ it "should have a memory-based session" do
76
+ @mock = Merb::Test::FakeRequest.new
77
+ @mock.session[:random] = "random"
78
+ @mock.session[:random].should == "random"
79
+ end
72
80
  end
@@ -1,13 +1,23 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper'
2
2
  require File.dirname(__FILE__) + '/../spec_generator_helper'
3
3
 
4
- module Kernel
5
- undef dependency
6
- end
7
4
 
8
5
  describe "an app generator" do
9
6
  include RubiGen::GeneratorTestHelper
10
-
7
+
8
+ before :all do
9
+ module Kernel
10
+ alias_method :old_dependency, :dependency
11
+ undef dependency
12
+ end
13
+ end
14
+
15
+ after :all do
16
+ module Kernel
17
+ alias_method :dependency, :old_dependency
18
+ end
19
+ end
20
+
11
21
  before do
12
22
  @generator = build_generator('merb', [APP_ROOT], sources, {})
13
23
  end
@@ -97,33 +107,142 @@ describe "an app generator" do
97
107
  script/destroy
98
108
  }.each{|file| file_should_be_executable(file)}
99
109
  end
100
-
101
-
102
110
 
111
+ def sources
112
+ [RubiGen::PathSource.new(:test, File.join(File.dirname(__FILE__),"../../", generator_path))
113
+ ]
114
+ end
103
115
 
116
+ def generator_path
117
+ "app_generators"
118
+ end
104
119
 
105
- def directory_should_be_created(directory)
106
- File.should be_exist(File.join(APP_ROOT, directory))
107
- File.should be_directory(File.join(APP_ROOT, directory))
120
+ end
121
+
122
+ describe "a controller generator" do
123
+ include RubiGen::GeneratorTestHelper
124
+
125
+ before :all do
126
+ module Kernel
127
+ alias_method :old_dependency, :dependency
128
+ undef dependency
129
+ end
108
130
  end
109
131
 
110
- def file_should_be_created(file)
111
- File.should be_exist(File.join(APP_ROOT, file))
112
- File.should be_file(File.join(APP_ROOT, file))
132
+ after :all do
133
+ module Kernel
134
+ alias_method :dependency, :old_dependency
135
+ end
113
136
  end
114
137
 
115
- def file_should_be_executable(file)
116
- File.should be_executable(File.join(APP_ROOT, file))
138
+ before do
139
+ @generator = build_generator('controller', ["my_posts"], sources, {})
117
140
  end
118
-
119
-
141
+
142
+ after do
143
+ bare_teardown # Cleans up the temporary application directory that gets created as part of the test.
144
+ end
145
+
146
+ it "should be get created" do
147
+ @generator.should_not be_nil
148
+ end
149
+
150
+ it "should be a ControllerGenerator" do
151
+ @generator.should be_an_instance_of(ControllerGenerator)
152
+ end
153
+
154
+ it "should create directory structure" do
155
+ silence_generator do
156
+ @generator.command(:create).invoke!
157
+ end
158
+ %w{
159
+ app
160
+ app/controllers
161
+ app/helpers
162
+ app/views
163
+ app/views/my_posts
164
+ }.each{|dir| directory_should_be_created(dir)}
165
+ end
166
+
167
+ it "should create files from templates" do
168
+ silence_generator do
169
+ @generator.command(:create).invoke!
170
+ end
171
+ %w{
172
+ app/controllers/my_posts.rb
173
+ app/helpers/my_posts_helper.rb
174
+ app/views/my_posts/index.html.erb
175
+ }.each{|file| file_should_be_created(file)}
176
+ end
177
+
120
178
  def sources
121
- [RubiGen::PathSource.new(:test, File.join(File.dirname(__FILE__),"../../", generator_path))
179
+ [
180
+ RubiGen::PathSource.new(:app, File.join(File.dirname(__FILE__),"../../", "merb_generators")),
181
+ RubiGen::PathSource.new(:app, File.join(File.dirname(__FILE__),"../../", "rspec_generators"))
122
182
  ]
123
183
  end
124
-
125
- def generator_path
126
- "app_generators"
184
+ end
185
+
186
+ describe "a part_controller generator" do
187
+ include RubiGen::GeneratorTestHelper
188
+
189
+ before :all do
190
+ module Kernel
191
+ alias_method :old_dependency, :dependency
192
+ undef dependency
193
+ end
194
+ end
195
+
196
+ after :all do
197
+ module Kernel
198
+ alias_method :dependency, :old_dependency
199
+ end
200
+ end
201
+
202
+ before do
203
+ @generator = build_generator('part_controller', ["my_posts"], sources, {})
204
+ end
205
+
206
+ after do
207
+ bare_teardown # Cleans up the temporary application directory that gets created as part of the test.
208
+ end
209
+
210
+ it "should be get created" do
211
+ @generator.should_not be_nil
212
+ end
213
+
214
+ it "should be a PartControllerGenerator" do
215
+ @generator.should be_an_instance_of(PartControllerGenerator)
216
+ end
217
+
218
+ it "should create directory structure" do
219
+ silence_generator do
220
+ @generator.command(:create).invoke!
221
+ end
222
+ %w{
223
+ app
224
+ app/parts/controllers
225
+ app/parts/helpers
226
+ app/parts/views
227
+ app/parts/views/my_posts_part
228
+ }.each{|dir| directory_should_be_created(dir)}
229
+ end
230
+
231
+ it "should create files from templates" do
232
+ silence_generator do
233
+ @generator.command(:create).invoke!
234
+ end
235
+ %w{
236
+ app/parts/controllers/my_posts_part.rb
237
+ app/parts/helpers/my_posts_part_helper.rb
238
+ app/parts/views/my_posts_part/index.html.erb
239
+ }.each{|file| file_should_be_created(file)}
240
+ end
241
+
242
+ def sources
243
+ [
244
+ RubiGen::PathSource.new(:app, File.join(File.dirname(__FILE__),"../../", "merb_generators")),
245
+ RubiGen::PathSource.new(:app, File.join(File.dirname(__FILE__),"../../", "rspec_generators"))
246
+ ]
127
247
  end
128
-
129
248
  end