merb 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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