git-trip 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. data.tar.gz.sig +0 -0
  2. data/History.txt +21 -0
  3. data/Manifest.txt +89 -0
  4. data/README.txt +60 -0
  5. data/Rakefile +31 -0
  6. data/bin/git-trip +0 -0
  7. data/doc/USAGE.txt +54 -0
  8. data/lib/core_ext/hash.rb +15 -0
  9. data/lib/git-trip.rb +23 -0
  10. data/lib/git-trip/errors.rb +22 -0
  11. data/lib/git-trip/gitter.rb +10 -0
  12. data/lib/git-trip/gitter/base.rb +18 -0
  13. data/lib/git-trip/gitter/dir.rb +32 -0
  14. data/lib/git-trip/gitter/uri.rb +40 -0
  15. data/lib/git-trip/paint_mode.rb +52 -0
  16. data/lib/git-trip/painter.rb +167 -0
  17. data/spec/core_ext/hash_spec.rb +25 -0
  18. data/spec/git-trip/errors_spec.rb +43 -0
  19. data/spec/git-trip/gitter/base_spec.rb +15 -0
  20. data/spec/git-trip/gitter/dir_spec.rb +37 -0
  21. data/spec/git-trip/gitter/uri_spec.rb +25 -0
  22. data/spec/git-trip/gitter_spec.rb +11 -0
  23. data/spec/git-trip/paint_mode_spec.rb +56 -0
  24. data/spec/git-trip/painter_spec.rb +173 -0
  25. data/spec/git_trip_spec.rb +23 -0
  26. data/spec/rcov.opts +1 -0
  27. data/spec/spec.opts +4 -0
  28. data/spec/spec_helper.rb +15 -0
  29. data/tasks/ditz.rake +42 -0
  30. data/tasks/docs.rake +68 -0
  31. data/tasks/gittrip.rake +63 -0
  32. data/tasks/rspec.rake +22 -0
  33. data/tasks/site.rake +48 -0
  34. data/tasks/util.rake +44 -0
  35. data/vendor/grit/History.txt +6 -0
  36. data/vendor/grit/Manifest.txt +53 -0
  37. data/vendor/grit/README.txt +213 -0
  38. data/vendor/grit/Rakefile +29 -0
  39. data/vendor/grit/grit.gemspec +16 -0
  40. data/vendor/grit/lib/grit.rb +37 -0
  41. data/vendor/grit/lib/grit/actor.rb +36 -0
  42. data/vendor/grit/lib/grit/blob.rb +117 -0
  43. data/vendor/grit/lib/grit/commit.rb +208 -0
  44. data/vendor/grit/lib/grit/config.rb +44 -0
  45. data/vendor/grit/lib/grit/diff.rb +70 -0
  46. data/vendor/grit/lib/grit/errors.rb +7 -0
  47. data/vendor/grit/lib/grit/git.rb +116 -0
  48. data/vendor/grit/lib/grit/index.rb +77 -0
  49. data/vendor/grit/lib/grit/lazy.rb +31 -0
  50. data/vendor/grit/lib/grit/ref.rb +110 -0
  51. data/vendor/grit/lib/grit/repo.rb +318 -0
  52. data/vendor/grit/lib/grit/tree.rb +99 -0
  53. data/vendor/grit/test/fixtures/blame +131 -0
  54. data/vendor/grit/test/fixtures/cat_file_blob +1 -0
  55. data/vendor/grit/test/fixtures/cat_file_blob_size +1 -0
  56. data/vendor/grit/test/fixtures/diff_2 +54 -0
  57. data/vendor/grit/test/fixtures/diff_2f +19 -0
  58. data/vendor/grit/test/fixtures/diff_f +15 -0
  59. data/vendor/grit/test/fixtures/diff_i +201 -0
  60. data/vendor/grit/test/fixtures/diff_mode_only +1152 -0
  61. data/vendor/grit/test/fixtures/diff_new_mode +17 -0
  62. data/vendor/grit/test/fixtures/diff_p +610 -0
  63. data/vendor/grit/test/fixtures/for_each_ref +0 -0
  64. data/vendor/grit/test/fixtures/for_each_ref_remotes +0 -0
  65. data/vendor/grit/test/fixtures/for_each_ref_tags +0 -0
  66. data/vendor/grit/test/fixtures/ls_tree_a +7 -0
  67. data/vendor/grit/test/fixtures/ls_tree_b +2 -0
  68. data/vendor/grit/test/fixtures/ls_tree_commit +3 -0
  69. data/vendor/grit/test/fixtures/rev_list +26 -0
  70. data/vendor/grit/test/fixtures/rev_list_count +655 -0
  71. data/vendor/grit/test/fixtures/rev_list_single +7 -0
  72. data/vendor/grit/test/fixtures/rev_parse +1 -0
  73. data/vendor/grit/test/fixtures/show_empty_commit +6 -0
  74. data/vendor/grit/test/fixtures/simple_config +2 -0
  75. data/vendor/grit/test/helper.rb +17 -0
  76. data/vendor/grit/test/profile.rb +21 -0
  77. data/vendor/grit/test/suite.rb +6 -0
  78. data/vendor/grit/test/test_actor.rb +35 -0
  79. data/vendor/grit/test/test_blob.rb +74 -0
  80. data/vendor/grit/test/test_commit.rb +182 -0
  81. data/vendor/grit/test/test_config.rb +58 -0
  82. data/vendor/grit/test/test_diff.rb +18 -0
  83. data/vendor/grit/test/test_git.rb +52 -0
  84. data/vendor/grit/test/test_head.rb +22 -0
  85. data/vendor/grit/test/test_real.rb +19 -0
  86. data/vendor/grit/test/test_reality.rb +17 -0
  87. data/vendor/grit/test/test_remote.rb +15 -0
  88. data/vendor/grit/test/test_repo.rb +278 -0
  89. data/vendor/grit/test/test_tag.rb +29 -0
  90. data/vendor/grit/test/test_tree.rb +91 -0
  91. metadata +179 -0
  92. metadata.gz.sig +0 -0
@@ -0,0 +1 @@
1
+ Hello world
@@ -0,0 +1,54 @@
1
+ diff --git a/lib/grit/commit.rb b/lib/grit/commit.rb
2
+ index a093bb1db8e884cccf396b297259181d1caebed4..80fd3d527f269ecbd570b65b8e21fd85baedb6e9 100644
3
+ --- a/lib/grit/commit.rb
4
+ +++ b/lib/grit/commit.rb
5
+ @@ -156,12 +156,8 @@ module Grit
6
+
7
+ def diffs
8
+ if parents.empty?
9
+ - diff = @repo.git.show({:full_index => true, :pretty => 'raw'}, @id)
10
+ - if diff =~ /diff --git a/
11
+ - diff = diff.sub(/.+?(diff --git a)/m, '\1')
12
+ - else
13
+ - diff = ''
14
+ - end
15
+ + diff = @repo.git.show({:full_index => true, :pretty => 'raw'}, @id)
16
+ + diff = diff.sub(/.+?(diff --git a)/m, '\1')
17
+ Diff.list_from_string(@repo, diff)
18
+ else
19
+ self.class.diff(@repo, parents.first.id, @id)
20
+ diff --git a/test/fixtures/show_empty_commit b/test/fixtures/show_empty_commit
21
+ deleted file mode 100644
22
+ index ea25e32a409fdf74c1b9268820108d1c16dcc553..0000000000000000000000000000000000000000
23
+ --- a/test/fixtures/show_empty_commit
24
+ +++ /dev/null
25
+ @@ -1,6 +0,0 @@
26
+ -commit 1e3824339762bd48316fe87bfafc853732d43264
27
+ -tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904
28
+ -author Tom Preston-Werner <tom@mojombo.com> 1157392833 +0000
29
+ -committer Tom Preston-Werner <tom@mojombo.com> 1157392833 +0000
30
+ -
31
+ - initial directory structure
32
+ diff --git a/test/test_commit.rb b/test/test_commit.rb
33
+ index fdeb9000089b052f0b31a845e0173e9b089e06a0..bdbc450e08084d7d611e985cfa12fb424cab29b2 100644
34
+ --- a/test/test_commit.rb
35
+ +++ b/test/test_commit.rb
36
+ @@ -98,18 +98,6 @@ class TestCommit < Test::Unit::TestCase
37
+ assert_equal true, diffs[5].new_file
38
+ end
39
+
40
+ - def test_diffs_on_initial_import_with_empty_commit
41
+ - Git.any_instance.expects(:show).with(
42
+ - {:full_index => true, :pretty => 'raw'},
43
+ - '634396b2f541a9f2d58b00be1a07f0c358b999b3'
44
+ - ).returns(fixture('show_empty_commit'))
45
+ -
46
+ - @c = Commit.create(@r, :id => '634396b2f541a9f2d58b00be1a07f0c358b999b3')
47
+ - diffs = @c.diffs
48
+ -
49
+ - assert_equal [], diffs
50
+ - end
51
+ -
52
+ # to_s
53
+
54
+ def test_to_s
@@ -0,0 +1,19 @@
1
+ diff --git a/lib/grit/commit.rb b/lib/grit/commit.rb
2
+ index a093bb1db8e884cccf396b297259181d1caebed4..80fd3d527f269ecbd570b65b8e21fd85baedb6e9 100644
3
+ --- a/lib/grit/commit.rb
4
+ +++ b/lib/grit/commit.rb
5
+ @@ -156,12 +156,8 @@ module Grit
6
+
7
+ def diffs
8
+ if parents.empty?
9
+ - diff = @repo.git.show({:full_index => true, :pretty => 'raw'}, @id)
10
+ - if diff =~ /diff --git a/
11
+ - diff = diff.sub(/.+?(diff --git a)/m, '\1')
12
+ - else
13
+ - diff = ''
14
+ - end
15
+ + diff = @repo.git.show({:full_index => true, :pretty => 'raw'}, @id)
16
+ + diff = diff.sub(/.+?(diff --git a)/m, '\1')
17
+ Diff.list_from_string(@repo, diff)
18
+ else
19
+ self.class.diff(@repo, parents.first.id, @id)
@@ -0,0 +1,15 @@
1
+ diff --git a/lib/grit/diff.rb b/lib/grit/diff.rb
2
+ index 537955bb86a8ceaa19aea89e75ccbea5ce6f2698..00b0b4a67eca9242db5f8991e99625acd55f040c 100644
3
+ --- a/lib/grit/diff.rb
4
+ +++ b/lib/grit/diff.rb
5
+ @@ -27,6 +27,10 @@ module Grit
6
+ while !lines.empty?
7
+ m, a_path, b_path = *lines.shift.match(%r{^diff --git a/(\S+) b/(\S+)$})
8
+
9
+ + if lines.first =~ /^old mode/
10
+ + 2.times { lines.shift }
11
+ + end
12
+ +
13
+ new_file = false
14
+ deleted_file = false
15
+
@@ -0,0 +1,201 @@
1
+ commit 634396b2f541a9f2d58b00be1a07f0c358b999b3
2
+ Author: Tom Preston-Werner <tom@mojombo.com>
3
+ Date: Tue Oct 9 23:18:20 2007 -0700
4
+
5
+ initial grit setup
6
+
7
+ diff --git a/History.txt b/History.txt
8
+ new file mode 100644
9
+ index 0000000000000000000000000000000000000000..81d2c27608b352814cbe979a6acd678d30219678
10
+ --- /dev/null
11
+ +++ b/History.txt
12
+ @@ -0,0 +1,5 @@
13
+ +== 1.0.0 / 2007-10-09
14
+ +
15
+ +* 1 major enhancement
16
+ + * Birthday!
17
+ +
18
+ diff --git a/Manifest.txt b/Manifest.txt
19
+ new file mode 100644
20
+ index 0000000000000000000000000000000000000000..641972d82c6d1b51122274ae8f6a0ecdfb56ee22
21
+ --- /dev/null
22
+ +++ b/Manifest.txt
23
+ @@ -0,0 +1,7 @@
24
+ +History.txt
25
+ +Manifest.txt
26
+ +README.txt
27
+ +Rakefile
28
+ +bin/grit
29
+ +lib/grit.rb
30
+ +test/test_grit.rb
31
+
32
+ diff --git a/README.txt b/README.txt
33
+ new file mode 100644
34
+ index 0000000000000000000000000000000000000000..8b1e02c0fb554eed2ce2ef737a68bb369d7527df
35
+ --- /dev/null
36
+ +++ b/README.txt
37
+ @@ -0,0 +1,48 @@
38
+ +grit
39
+ + by FIX (your name)
40
+ + FIX (url)
41
+ +
42
+ +== DESCRIPTION:
43
+ +
44
+ +FIX (describe your package)
45
+ +
46
+ +== FEATURES/PROBLEMS:
47
+ +
48
+ +* FIX (list of features or problems)
49
+ +
50
+ +== SYNOPSIS:
51
+ +
52
+ + FIX (code sample of usage)
53
+ +
54
+ +== REQUIREMENTS:
55
+ +
56
+ +* FIX (list of requirements)
57
+ +
58
+ +== INSTALL:
59
+ +
60
+ +* FIX (sudo gem install, anything else)
61
+ +
62
+ +== LICENSE:
63
+ +
64
+ +(The MIT License)
65
+ +
66
+ +Copyright (c) 2007 FIX
67
+ +
68
+ +Permission is hereby granted, free of charge, to any person obtaining
69
+ +a copy of this software and associated documentation files (the
70
+ +'Software'), to deal in the Software without restriction, including
71
+ +without limitation the rights to use, copy, modify, merge, publish,
72
+ +distribute, sublicense, and/or sell copies of the Software, and to
73
+ +permit persons to whom the Software is furnished to do so, subject to
74
+ +the following conditions:
75
+ +
76
+ +The above copyright notice and this permission notice shall be
77
+ +included in all copies or substantial portions of the Software.
78
+ +
79
+ +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
80
+ +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
81
+ +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
82
+ +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
83
+ +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
84
+ +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
85
+ +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
86
+ diff --git a/Rakefile b/Rakefile
87
+ new file mode 100644
88
+ index 0000000000000000000000000000000000000000..ff69c3684a18592c741332b290492aa39d980e02
89
+ --- /dev/null
90
+ +++ b/Rakefile
91
+ @@ -0,0 +1,17 @@
92
+ +# -*- ruby -*-
93
+ +
94
+ +require 'rubygems'
95
+ +require 'hoe'
96
+ +require './lib/grit.rb'
97
+ +
98
+ +Hoe.new('grit', Grit::VERSION) do |p|
99
+ + p.rubyforge_name = 'grit'
100
+ + # p.author = 'FIX'
101
+ + # p.email = 'FIX'
102
+ + # p.summary = 'FIX'
103
+ + # p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
104
+ + # p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
105
+ + p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
106
+ +end
107
+ +
108
+ +# vim: syntax=Ruby
109
+ diff --git a/bin/grit b/bin/grit
110
+ new file mode 100644
111
+ index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
112
+ diff --git a/lib/grit.rb b/lib/grit.rb
113
+ new file mode 100644
114
+ index 0000000000000000000000000000000000000000..32cec87d1e78946a827ddf6a8776be4d81dcf1d1
115
+ --- /dev/null
116
+ +++ b/lib/grit.rb
117
+ @@ -0,0 +1,12 @@
118
+ +$:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
119
+ +
120
+ +# core
121
+ +
122
+ +# stdlib
123
+ +
124
+ +# internal requires
125
+ +require 'grit/grit'
126
+ +
127
+ +class Grit
128
+ + VERSION = '1.0.0'
129
+ +end
130
+
131
+ diff --git a/lib/grit/errors.rb b/lib/grit/errors.rb
132
+ new file mode 100644
133
+ index 0000000000000000000000000000000000000000..b3be31553741937607a89be8b6a2ab1df208852e
134
+ --- /dev/null
135
+ +++ b/lib/grit/errors.rb
136
+ @@ -0,0 +1,4 @@
137
+ +class Grit
138
+ + class InvalidGitRepositoryError < StandardError
139
+ + end
140
+ +end
141
+
142
+ diff --git a/lib/grit/grit.rb b/lib/grit/grit.rb
143
+ new file mode 100644
144
+ index 0000000000000000000000000000000000000000..48fd36e16081ec09903f7a0e2253b3d16f9efb01
145
+ --- /dev/null
146
+ +++ b/lib/grit/grit.rb
147
+ @@ -0,0 +1,24 @@
148
+ +class Grit
149
+ + attr_accessor :path
150
+ +
151
+ + # Create a new Grit instance
152
+ + # +path+ is the path to either the root git directory or the bare git repo
153
+ + #
154
+ + # Examples
155
+ + # g = Grit.new("/Users/tom/dev/grit")
156
+ + # g = Grit.new("/Users/tom/public/grit.git")
157
+ + def initialize(path)
158
+ + if File.exist?(File.join(path, '.git'))
159
+ + self.path = File.join(path, '.git')
160
+ + elsif File.exist?(path) && path =~ /\.git$/
161
+ + self.path = path
162
+ + else
163
+ + raise InvalidGitRepositoryError.new(path) unless File.exist?(path)
164
+ + end
165
+ + end
166
+ +
167
+ + # Return the project's description. Taken verbatim from REPO/description
168
+ + def description
169
+ + File.open(File.join(self.path, 'description')).read.chomp
170
+ + end
171
+ +end
172
+
173
+ diff --git a/test/helper.rb b/test/helper.rb
174
+ new file mode 100644
175
+ index 0000000000000000000000000000000000000000..56e21da6b4ce3021d2754775dfa589947a4e37e5
176
+ --- /dev/null
177
+ +++ b/test/helper.rb
178
+ @@ -0,0 +1,5 @@
179
+ +require File.join(File.dirname(__FILE__), *%w[.. lib grit])
180
+ +
181
+ +require 'test/unit'
182
+ +
183
+ +GRIT_REPO = File.join(File.dirname(__FILE__), *%w[..])
184
+ diff --git a/test/test_grit.rb b/test/test_grit.rb
185
+ new file mode 100644
186
+ index 0000000000000000000000000000000000000000..93aa481b37629797df739380306ae689e13f2855
187
+ --- /dev/null
188
+ +++ b/test/test_grit.rb
189
+ @@ -0,0 +1,11 @@
190
+ +require File.dirname(__FILE__) + '/helper'
191
+ +
192
+ +class TestGrit < Test::Unit::TestCase
193
+ + def setup
194
+ + @g = Grit.new(GRIT_REPO)
195
+ + end
196
+ +
197
+ + def test_description
198
+ + assert_equal "Grit is a ruby library for interfacing with git repositories.", @g.description
199
+ + end
200
+ +end
201
+
@@ -0,0 +1,1152 @@
1
+ diff --git a/bin/merb b/bin/merb
2
+ old mode 100644
3
+ new mode 100755
4
+ diff --git a/lib/merb.rb b/lib/merb.rb
5
+ index 76cb3e269e46fdf9b63cda7cb563c6cf40fdcb15..a2ab4ed47f9cb2ab942da5c46a2b561758a0d704 100644
6
+ --- a/lib/merb.rb
7
+ +++ b/lib/merb.rb
8
+ @@ -15,7 +15,7 @@ require 'merb_core/core_ext'
9
+ require 'merb_core/gem_ext/erubis'
10
+ require 'merb_core/logger'
11
+ require 'merb_core/version'
12
+ -
13
+ +require 'merb_core/controller/mime'
14
+
15
+ module Merb
16
+ class << self
17
+ @@ -23,6 +23,7 @@ module Merb
18
+ def start(argv=ARGV)
19
+ Merb::Config.parse_args(argv)
20
+ BootLoader.run
21
+ +
22
+ case Merb::Config[:adapter]
23
+ when "mongrel"
24
+ adapter = Merb::Rack::Mongrel
25
+ diff --git a/lib/merb_core/boot/bootloader.rb b/lib/merb_core/boot/bootloader.rb
26
+ index d873924860bf4da06ac93db5c6a188f63dd1c3cc..57da75f05e28e8a256922bf345ccd3902e0a0b02 100644
27
+ --- a/lib/merb_core/boot/bootloader.rb
28
+ +++ b/lib/merb_core/boot/bootloader.rb
29
+ @@ -20,7 +20,7 @@ module Merb
30
+ end
31
+
32
+ def run
33
+ - subclasses.each {|klass| Object.full_const_get(klass).new.run }
34
+ + subclasses.each {|klass| Object.full_const_get(klass).run }
35
+ end
36
+
37
+ def after(klass)
38
+ @@ -37,95 +37,128 @@ module Merb
39
+
40
+ end
41
+
42
+ -class Merb::BootLoader::BuildFramework < Merb::BootLoader
43
+ - def run
44
+ - build_framework
45
+ +class Merb::BootLoader::LoadInit < Merb::BootLoader
46
+ + def self.run
47
+ + if Merb::Config[:init_file]
48
+ + require Merb.root / Merb::Config[:init_file]
49
+ + elsif File.exists?(Merb.root / "config" / "merb_init.rb")
50
+ + require Merb.root / "config" / "merb_init"
51
+ + elsif File.exists?(Merb.root / "merb_init.rb")
52
+ + require Merb.root / "merb_init"
53
+ + elsif File.exists?(Merb.root / "application.rb")
54
+ + require Merb.root / "application"
55
+ + end
56
+ + end
57
+ +end
58
+ +
59
+ +class Merb::BootLoader::Environment < Merb::BootLoader
60
+ + def self.run
61
+ + Merb.environment = Merb::Config[:environment]
62
+ + end
63
+ +end
64
+ +
65
+ +class Merb::BootLoader::Logger < Merb::BootLoader
66
+ + def self.run
67
+ + Merb.logger = Merb::Logger.new(Merb.dir_for(:log) / "test_log")
68
+ + Merb.logger.level = Merb::Logger.const_get(Merb::Config[:log_level].upcase) rescue Merb::Logger::INFO
69
+ end
70
+ +end
71
+ +
72
+ +class Merb::BootLoader::BuildFramework < Merb::BootLoader
73
+ + class << self
74
+ + def run
75
+ + build_framework
76
+ + end
77
+
78
+ - # This method should be overridden in merb_init.rb before Merb.start to set up a different
79
+ - # framework structure
80
+ - def build_framework
81
+ - %[view model controller helper mailer part].each do |component|
82
+ - Merb.push_path(component.to_sym, Merb.root_path("app/#{component}s"))
83
+ + # This method should be overridden in merb_init.rb before Merb.start to set up a different
84
+ + # framework structure
85
+ + def build_framework
86
+ + %w[view model controller helper mailer part].each do |component|
87
+ + Merb.push_path(component.to_sym, Merb.root_path("app/#{component}s"))
88
+ + end
89
+ + Merb.push_path(:application, Merb.root_path("app/controllers/application.rb"))
90
+ + Merb.push_path(:config, Merb.root_path("config/router.rb"))
91
+ + Merb.push_path(:lib, Merb.root_path("lib"))
92
+ end
93
+ - Merb.push_path(:application, Merb.root_path("app/controllers/application.rb"))
94
+ - Merb.push_path(:config, Merb.root_path("config/router.rb"))
95
+ - Merb.push_path(:lib, Merb.root_path("lib"))
96
+ end
97
+ end
98
+
99
+ class Merb::BootLoader::LoadPaths < Merb::BootLoader
100
+ LOADED_CLASSES = {}
101
+
102
+ - def run
103
+ - # Add models, controllers, and lib to the load path
104
+ - $LOAD_PATH.unshift Merb.load_paths[:model].first if Merb.load_paths[:model]
105
+ - $LOAD_PATH.unshift Merb.load_paths[:controller].first if Merb.load_paths[:controller]
106
+ - $LOAD_PATH.unshift Merb.load_paths[:lib].first if Merb.load_paths[:lib]
107
+ + class << self
108
+ + def run
109
+ + # Add models, controllers, and lib to the load path
110
+ + $LOAD_PATH.unshift Merb.load_paths[:model].first if Merb.load_paths[:model]
111
+ + $LOAD_PATH.unshift Merb.load_paths[:controller].first if Merb.load_paths[:controller]
112
+ + $LOAD_PATH.unshift Merb.load_paths[:lib].first if Merb.load_paths[:lib]
113
+
114
+ - # Require all the files in the registered load paths
115
+ - puts Merb.load_paths.inspect
116
+ - Merb.load_paths.each do |name, path|
117
+ - Dir[path.first / path.last].each do |file|
118
+ - klasses = ObjectSpace.classes.dup
119
+ - require f
120
+ - LOADED_CLASSES[file] = ObjectSpace.classes - klasses
121
+ + # Require all the files in the registered load paths
122
+ + puts Merb.load_paths.inspect
123
+ + Merb.load_paths.each do |name, path|
124
+ + Dir[path.first / path.last].each do |file|
125
+ + klasses = ObjectSpace.classes.dup
126
+ + require file
127
+ + LOADED_CLASSES[file] = ObjectSpace.classes - klasses
128
+ + end
129
+ end
130
+ end
131
+ - end
132
+
133
+ - def reload(file)
134
+ - if klasses = LOADED_CLASSES[file]
135
+ - klasses.each do |klass|
136
+ - remove_constant(klass)
137
+ + def reload(file)
138
+ + if klasses = LOADED_CLASSES[file]
139
+ + klasses.each do |klass|
140
+ + remove_constant(klass)
141
+ + end
142
+ end
143
+ + load file
144
+ end
145
+ - load file
146
+ - end
147
+
148
+ - def remove_constant(const)
149
+ - # This is to support superclasses (like AbstractController) that track
150
+ - # their subclasses in a class variable. Classes that wish to use this
151
+ - # functionality are required to alias it to _subclasses_list. Plugins
152
+ - # for ORMs and other libraries should keep this in mind.
153
+ - if klass.superclass.respond_to?(:_subclasses_list)
154
+ - klass.superclass.send(:_subclasses_list).delete(klass)
155
+ - klass.superclass.send(:_subclasses_list).delete(klass.to_s)
156
+ - end
157
+ + def remove_constant(const)
158
+ + # This is to support superclasses (like AbstractController) that track
159
+ + # their subclasses in a class variable. Classes that wish to use this
160
+ + # functionality are required to alias it to _subclasses_list. Plugins
161
+ + # for ORMs and other libraries should keep this in mind.
162
+ + if klass.superclass.respond_to?(:_subclasses_list)
163
+ + klass.superclass.send(:_subclasses_list).delete(klass)
164
+ + klass.superclass.send(:_subclasses_list).delete(klass.to_s)
165
+ + end
166
+
167
+ - parts = const.to_s.split("::")
168
+ - base = parts.size == 1 ? Object : Object.full_const_get(parts[0..-2].join("::"))
169
+ - object = parts[-1].intern
170
+ - Merb.logger.debugger("Removing constant #{object} from #{base}")
171
+ - base.send(:remove_const, object) if object
172
+ + parts = const.to_s.split("::")
173
+ + base = parts.size == 1 ? Object : Object.full_const_get(parts[0..-2].join("::"))
174
+ + object = parts[-1].intern
175
+ + Merb.logger.debugger("Removing constant #{object} from #{base}")
176
+ + base.send(:remove_const, object) if object
177
+ + end
178
+ end
179
+
180
+ end
181
+
182
+ class Merb::BootLoader::Templates < Merb::BootLoader
183
+ - def run
184
+ - template_paths.each do |path|
185
+ - Merb::Template.inline_template(path)
186
+ + class << self
187
+ + def run
188
+ + template_paths.each do |path|
189
+ + Merb::Template.inline_template(path)
190
+ + end
191
+ end
192
+ - end
193
+
194
+ - def template_paths
195
+ - extension_glob = "{#{Merb::Template::EXTENSIONS.keys.join(',')}}"
196
+ + def template_paths
197
+ + extension_glob = "{#{Merb::Template::EXTENSIONS.keys.join(',')}}"
198
+
199
+ - # This gets all templates set in the controllers template roots
200
+ - # We separate the two maps because most of controllers will have
201
+ - # the same _template_root, so it's silly to be globbing the same
202
+ - # path over and over.
203
+ - template_paths = Merb::AbstractController._abstract_subclasses.map do |klass|
204
+ - Object.full_const_get(klass)._template_root
205
+ - end.uniq.map {|path| Dir["#{path}/**/*.#{extension_glob}"] }
206
+ + # This gets all templates set in the controllers template roots
207
+ + # We separate the two maps because most of controllers will have
208
+ + # the same _template_root, so it's silly to be globbing the same
209
+ + # path over and over.
210
+ + template_paths = Merb::AbstractController._abstract_subclasses.map do |klass|
211
+ + Object.full_const_get(klass)._template_root
212
+ + end.uniq.compact.map {|path| Dir["#{path}/**/*.#{extension_glob}"] }
213
+
214
+ - # This gets the templates that might be created outside controllers
215
+ - # template roots. eg app/views/shared/*
216
+ - template_paths << Dir["#{Merb.dir_for(:view)}/**/*.#{extension_glob}"] if Merb.dir_for(:view)
217
+ + # This gets the templates that might be created outside controllers
218
+ + # template roots. eg app/views/shared/*
219
+ + template_paths << Dir["#{Merb.dir_for(:view)}/**/*.#{extension_glob}"] if Merb.dir_for(:view)
220
+
221
+ - template_paths.flatten.compact.uniq
222
+ - end
223
+ + template_paths.flatten.compact.uniq
224
+ + end
225
+ + end
226
+ end
227
+
228
+ class Merb::BootLoader::Libraries < Merb::BootLoader
229
+ @@ -145,18 +178,41 @@ class Merb::BootLoader::Libraries < Merb::BootLoader
230
+ def self.add_libraries(hsh)
231
+ @@libraries.merge!(hsh)
232
+ end
233
+ -
234
+ - def run
235
+ +
236
+ + def self.run
237
+ @@libraries.each do |exclude, choices|
238
+ require_first_working(*choices) unless Merb::Config[exclude]
239
+ end
240
+ end
241
+ -
242
+ - def require_first_working(first, *rest)
243
+ +
244
+ + def self.require_first_working(first, *rest)
245
+ p first, rest
246
+ require first
247
+ rescue LoadError
248
+ raise LoadError if rest.empty?
249
+ require_first_working rest.unshift, *rest
250
+ end
251
+ +end
252
+ +
253
+ +class Merb::BootLoader::MimeTypes < Merb::BootLoader
254
+ + def self.run
255
+ + # Sets the default mime-types
256
+ + #
257
+ + # By default, the mime-types include:
258
+ + # :all:: no transform, */*
259
+ + # :yaml:: to_yaml, application/x-yaml or text/yaml
260
+ + # :text:: to_text, text/plain
261
+ + # :html:: to_html, text/html or application/xhtml+xml or application/html
262
+ + # :xml:: to_xml, application/xml or text/xml or application/x-xml, adds "Encoding: UTF-8" response header
263
+ + # :js:: to_json, text/javascript ot application/javascript or application/x-javascript
264
+ + # :json:: to_json, application/json or text/x-json
265
+ + Merb.available_mime_types.clear
266
+ + Merb.add_mime_type(:all, nil, %w[*/*])
267
+ + Merb.add_mime_type(:yaml, :to_yaml, %w[application/x-yaml text/yaml])
268
+ + Merb.add_mime_type(:text, :to_text, %w[text/plain])
269
+ + Merb.add_mime_type(:html, :to_html, %w[text/html application/xhtml+xml application/html])
270
+ + Merb.add_mime_type(:xml, :to_xml, %w[application/xml text/xml application/x-xml], :Encoding => "UTF-8")
271
+ + Merb.add_mime_type(:js, :to_json, %w[text/javascript application/javascript application/x-javascript])
272
+ + Merb.add_mime_type(:json, :to_json, %w[application/json text/x-json])
273
+ + end
274
+ end
275
+
276
+ diff --git a/lib/merb_core/config.rb b/lib/merb_core/config.rb
277
+ index c92f2e6f071c234551ecb16a4716d47fa92f6c7b..ab0864e0174b54833c758f9f22a840d3b53c7653 100644
278
+ --- a/lib/merb_core/config.rb
279
+ +++ b/lib/merb_core/config.rb
280
+ @@ -92,6 +92,10 @@ module Merb
281
+ options[:cluster] = nodes
282
+ end
283
+
284
+ + opts.on("-I", "--init-file FILE", "Name of the file to load first") do |init_file|
285
+ + options[:init_file] = init_file
286
+ + end
287
+ +
288
+ opts.on("-p", "--port PORTNUM", "Port to run merb on, defaults to 4000.") do |port|
289
+ options[:port] = port
290
+ end
291
+ @@ -261,29 +265,29 @@ module Merb
292
+
293
+ @configuration = Merb::Config.apply_configuration_from_file options, environment_merb_yml
294
+
295
+ - case Merb::Config[:environment].to_s
296
+ - when 'production'
297
+ - Merb::Config[:reloader] = Merb::Config.fetch(:reloader, false)
298
+ - Merb::Config[:exception_details] = Merb::Config.fetch(:exception_details, false)
299
+ - Merb::Config[:cache_templates] = true
300
+ - else
301
+ - Merb::Config[:reloader] = Merb::Config.fetch(:reloader, true)
302
+ - Merb::Config[:exception_details] = Merb::Config.fetch(:exception_details, true)
303
+ - end
304
+ -
305
+ - Merb::Config[:reloader_time] ||= 0.5 if Merb::Config[:reloader] == true
306
+ -
307
+ -
308
+ - if Merb::Config[:reloader]
309
+ - Thread.abort_on_exception = true
310
+ - Thread.new do
311
+ - loop do
312
+ - sleep( Merb::Config[:reloader_time] )
313
+ - ::Merb::BootLoader.reload if ::Merb::BootLoader.app_loaded?
314
+ - end
315
+ - Thread.exit
316
+ - end
317
+ - end
318
+ + # case Merb::Config[:environment].to_s
319
+ + # when 'production'
320
+ + # Merb::Config[:reloader] = Merb::Config.fetch(:reloader, false)
321
+ + # Merb::Config[:exception_details] = Merb::Config.fetch(:exception_details, false)
322
+ + # Merb::Config[:cache_templates] = true
323
+ + # else
324
+ + # Merb::Config[:reloader] = Merb::Config.fetch(:reloader, true)
325
+ + # Merb::Config[:exception_details] = Merb::Config.fetch(:exception_details, true)
326
+ + # end
327
+ + #
328
+ + # Merb::Config[:reloader_time] ||= 0.5 if Merb::Config[:reloader] == true
329
+ + #
330
+ + #
331
+ + # if Merb::Config[:reloader]
332
+ + # Thread.abort_on_exception = true
333
+ + # Thread.new do
334
+ + # loop do
335
+ + # sleep( Merb::Config[:reloader_time] )
336
+ + # ::Merb::BootLoader.reload if ::Merb::BootLoader.app_loaded?
337
+ + # end
338
+ + # Thread.exit
339
+ + # end
340
+ + # end
341
+ @configuration
342
+ end
343
+
344
+ diff --git a/lib/merb_core/controller/abstract_controller.rb b/lib/merb_core/controller/abstract_controller.rb
345
+ index fbf83372793da6da4b803b799994f0e341fddf88..f5e9a59057d67a6d56377a516a726cf51aa03d6f 100644
346
+ --- a/lib/merb_core/controller/abstract_controller.rb
347
+ +++ b/lib/merb_core/controller/abstract_controller.rb
348
+ @@ -96,7 +96,7 @@ class Merb::AbstractController
349
+ # the superclass.
350
+ #---
351
+ # @public
352
+ - def _template_location(action, controller = controller_name, type = nil)
353
+ + def _template_location(action, type = nil, controller = controller_name)
354
+ "#{controller}/#{action}"
355
+ end
356
+
357
+ @@ -106,6 +106,8 @@ class Merb::AbstractController
358
+ # own subclasses. We're using a Set so we don't have to worry about
359
+ # uniqueness.
360
+ self._abstract_subclasses = Set.new
361
+ + self._template_root = Merb.dir_for(:view)
362
+ +
363
+ def self.subclasses_list() _abstract_subclasses end
364
+
365
+ class << self
366
+ @@ -114,7 +116,6 @@ class Merb::AbstractController
367
+ # The controller that is being inherited from Merb::AbstractController
368
+ def inherited(klass)
369
+ _abstract_subclasses << klass.to_s
370
+ - klass._template_root ||= Merb.dir_for(:view)
371
+ super
372
+ end
373
+
374
+ diff --git a/lib/merb_core/controller/merb_controller.rb b/lib/merb_core/controller/merb_controller.rb
375
+ index 7283f006bb0501b29f825da129600cf045264b62..98af6ef3330a6b3f46d7bb1f8643261e28155ae5 100644
376
+ --- a/lib/merb_core/controller/merb_controller.rb
377
+ +++ b/lib/merb_core/controller/merb_controller.rb
378
+ @@ -71,6 +71,10 @@ class Merb::Controller < Merb::AbstractController
379
+ end
380
+ end
381
+
382
+ + def _template_location(action, type = nil, controller = controller_name)
383
+ + "#{controller}/#{action}.#{type}"
384
+ + end
385
+ +
386
+ # Sets the variables that came in through the dispatch as available to
387
+ # the controller. This is called by .build, so see it for more
388
+ # information.
389
+ @@ -107,9 +111,7 @@ class Merb::Controller < Merb::AbstractController
390
+ request.cookies[_session_id_key] = request.params[_session_id_key]
391
+ end
392
+ end
393
+ - @_request, @_response, @_status, @_headers =
394
+ - request, response, status, headers
395
+ -
396
+ + @request, @response, @status, @headers = request, response, status, headers
397
+ nil
398
+ end
399
+
400
+ @@ -135,7 +137,8 @@ class Merb::Controller < Merb::AbstractController
401
+ @_benchmarks[:action_time] = Time.now - start
402
+ end
403
+
404
+ - _attr_reader :request, :response, :status, :headers
405
+ + attr_reader :request, :response, :headers
406
+ + attr_accessor :status
407
+ def params() request.params end
408
+ def cookies() request.cookies end
409
+ def session() request.session end
410
+ diff --git a/lib/merb_core/controller/mime.rb b/lib/merb_core/controller/mime.rb
411
+ index d17570786ca318cff7201c4b1e947ae229b01de8..ff9abe4d1c452aeabfcf5f7dc7a2c7cdd3f67035 100644
412
+ --- a/lib/merb_core/controller/mime.rb
413
+ +++ b/lib/merb_core/controller/mime.rb
414
+ @@ -8,7 +8,7 @@ module Merb
415
+
416
+ # Any specific outgoing headers should be included here. These are not
417
+ # the content-type header but anything in addition to it.
418
+ - # +tranform_method+ should be set to a symbol of the method used to
419
+ + # +transform_method+ should be set to a symbol of the method used to
420
+ # transform a resource into this mime type.
421
+ # For example for the :xml mime type an object might be transformed by
422
+ # calling :to_xml, or for the :js mime type, :to_json.
423
+ @@ -71,27 +71,6 @@ module Merb
424
+ def mime_by_request_header(header)
425
+ available_mime_types.find {|key,info| info[request_headers].include?(header)}.first
426
+ end
427
+ -
428
+ - # Resets the default mime-types
429
+ - #
430
+ - # By default, the mime-types include:
431
+ - # :all:: no transform, */*
432
+ - # :yaml:: to_yaml, application/x-yaml or text/yaml
433
+ - # :text:: to_text, text/plain
434
+ - # :html:: to_html, text/html or application/xhtml+xml or application/html
435
+ - # :xml:: to_xml, application/xml or text/xml or application/x-xml, adds "Encoding: UTF-8" response header
436
+ - # :js:: to_json, text/javascript ot application/javascript or application/x-javascript
437
+ - # :json:: to_json, application/json or text/x-json
438
+ - def reset_default_mime_types!
439
+ - available_mime_types.clear
440
+ - Merb.add_mime_type(:all, nil, %w[*/*])
441
+ - Merb.add_mime_type(:yaml, :to_yaml, %w[application/x-yaml text/yaml])
442
+ - Merb.add_mime_type(:text, :to_text, %w[text/plain])
443
+ - Merb.add_mime_type(:html, :to_html, %w[text/html application/xhtml+xml application/html])
444
+ - Merb.add_mime_type(:xml, :to_xml, %w[application/xml text/xml application/x-xml], :Encoding => "UTF-8")
445
+ - Merb.add_mime_type(:js, :to_json, %w[text/javascript application/javascript application/x-javascript])
446
+ - Merb.add_mime_type(:json, :to_json, %w[application/json text/x-json])
447
+ - end
448
+
449
+ end
450
+ end
451
+
452
+ diff --git a/lib/merb_core/controller/mixins/render.rb b/lib/merb_core/controller/mixins/render.rb
453
+ index 8e096546d4647bb597ab2e00a4b15d09db35e9c9..a298263af7d655d9ce43007554f3827046831287 100644
454
+ --- a/lib/merb_core/controller/mixins/render.rb
455
+ +++ b/lib/merb_core/controller/mixins/render.rb
456
+ @@ -51,21 +51,22 @@ module Merb::RenderMixin
457
+
458
+ # If you don't specify a thing to render, assume they want to render the current action
459
+ thing ||= action_name.to_sym
460
+ -
461
+ +
462
+ # Content negotiation
463
+ opts[:format] ? (self.content_type = opts[:format]) : content_type
464
+
465
+ # Do we have a template to try to render?
466
+ if thing.is_a?(Symbol) || opts[:template]
467
+ -
468
+ +
469
+ # Find a template path to look up (_template_location adds flexibility here)
470
+ - template_location = _template_root / (opts[:template] || _template_location(thing))
471
+ + template_location = _template_root / (opts[:template] || _template_location(thing, content_type))
472
+ +
473
+ # Get the method name from the previously inlined list
474
+ template_method = Merb::Template.template_for(template_location)
475
+
476
+ # Raise an error if there's no template
477
+ raise TemplateNotFound, "No template found at #{template_location}" unless
478
+ - self.respond_to?(template_method)
479
+ + template_method && self.respond_to?(template_method)
480
+
481
+ # Call the method in question and throw the content for later consumption by the layout
482
+ throw_content(:for_layout, self.send(template_method))
483
+ diff --git a/lib/merb_core/controller/mixins/responder.rb b/lib/merb_core/controller/mixins/responder.rb
484
+ index e910b2b32c844ab51cf2a10d0ad26c314dbb3631..5ac67fb907aaf9f95effc7eb3cbb07b8963ce022 100644
485
+ --- a/lib/merb_core/controller/mixins/responder.rb
486
+ +++ b/lib/merb_core/controller/mixins/responder.rb
487
+ @@ -97,6 +97,8 @@ module Merb
488
+ # and none of the provides methods can be used.
489
+ module ResponderMixin
490
+
491
+ + TYPES = {}
492
+ +
493
+ class ContentTypeAlreadySet < StandardError; end
494
+
495
+ # ==== Parameters
496
+ @@ -105,6 +107,7 @@ module Merb
497
+ base.extend(ClassMethods)
498
+ base.class_eval do
499
+ class_inheritable_accessor :class_provided_formats
500
+ + self.class_provided_formats = []
501
+ end
502
+ base.reset_provides
503
+ end
504
+ @@ -178,171 +181,253 @@ module Merb
505
+ def reset_provides
506
+ only_provides(:html)
507
+ end
508
+ -
509
+ - # ==== Returns
510
+ - # The current list of formats provided for this instance of the controller.
511
+ - # It starts with what has been set in the controller (or :html by default)
512
+ - # but can be modifed on a per-action basis.
513
+ - def _provided_formats
514
+ - @_provided_formats ||= class_provided_formats.dup
515
+ + end
516
+ +
517
+ + # ==== Returns
518
+ + # The current list of formats provided for this instance of the controller.
519
+ + # It starts with what has been set in the controller (or :html by default)
520
+ + # but can be modifed on a per-action basis.
521
+ + def _provided_formats
522
+ + @_provided_formats ||= class_provided_formats.dup
523
+ + end
524
+ +
525
+ + # Sets the provided formats for this action. Usually, you would
526
+ + # use a combination of +provides+, +only_provides+ and +does_not_provide+
527
+ + # to manage this, but you can set it directly.
528
+ + #
529
+ + # ==== Parameters
530
+ + # *formats<Symbol>:: A list of formats to be passed to provides
531
+ + #
532
+ + # ==== Raises
533
+ + # Merb::ResponderMixin::ContentTypeAlreadySet::
534
+ + # Content negotiation already occured, and the content_type is set.
535
+ + #
536
+ + # ==== Returns
537
+ + # Array:: List of formats passed in
538
+ + def _set_provided_formats(*formats)
539
+ + if @_content_type
540
+ + raise ContentTypeAlreadySet, "Cannot modify provided_formats because content_type has already been set"
541
+ end
542
+ -
543
+ - # Sets the provided formats for this action. Usually, you would
544
+ - # use a combination of +provides+, +only_provides+ and +does_not_provide+
545
+ - # to manage this, but you can set it directly.
546
+ - #
547
+ - # ==== Parameters
548
+ - # *formats<Symbol>:: A list of formats to be passed to provides
549
+ - #
550
+ - # ==== Raises
551
+ - # Merb::ResponderMixin::ContentTypeAlreadySet::
552
+ - # Content negotiation already occured, and the content_type is set.
553
+ - #
554
+ - # ==== Returns
555
+ - # Array:: List of formats passed in
556
+ - def _set_provided_formats(*formats)
557
+ - if @_content_type
558
+ - raise ContentTypeAlreadySet, "Cannot modify provided_formats because content_type has already been set"
559
+ - end
560
+ - @_provided_formats = []
561
+ - provides(*formats)
562
+ + @_provided_formats = []
563
+ + provides(*formats)
564
+ + end
565
+ + alias :_provided_formats= :_set_provided_formats
566
+ +
567
+ + # Adds formats to the list of provided formats for this particular
568
+ + # request. Usually used to add formats to a single action. See also
569
+ + # the controller-level provides that affects all actions in a controller.
570
+ + #
571
+ + # ==== Parameters
572
+ + # *formats<Symbol>:: A list of formats to add to the per-action list
573
+ + # of provided formats
574
+ + #
575
+ + # ==== Raises
576
+ + # Merb::ResponderMixin::ContentTypeAlreadySet::
577
+ + # Content negotiation already occured, and the content_type is set.
578
+ + #
579
+ + # ==== Returns
580
+ + # Array:: List of formats passed in
581
+ + #
582
+ + #---
583
+ + # @public
584
+ + def provides(*formats)
585
+ + if @_content_type
586
+ + raise ContentTypeAlreadySet, "Cannot modify provided_formats because content_type has already been set"
587
+ end
588
+ - alias :_provided_formats= :_set_provided_formats
589
+ -
590
+ - # Adds formats to the list of provided formats for this particular
591
+ - # request. Usually used to add formats to a single action. See also
592
+ - # the controller-level provides that affects all actions in a controller.
593
+ - #
594
+ - # ==== Parameters
595
+ - # *formats<Symbol>:: A list of formats to add to the per-action list
596
+ - # of provided formats
597
+ - #
598
+ - # ==== Raises
599
+ - # Merb::ResponderMixin::ContentTypeAlreadySet::
600
+ - # Content negotiation already occured, and the content_type is set.
601
+ - #
602
+ - # ==== Returns
603
+ - # Array:: List of formats passed in
604
+ - #
605
+ - #---
606
+ - # @public
607
+ - def provides(*formats)
608
+ - if @_content_type
609
+ - raise ContentTypeAlreadySet, "Cannot modify provided_formats because content_type has already been set"
610
+ - end
611
+ - formats.each do |fmt|
612
+ - _provided_formats << fmt unless _provided_formats.include?(fmt)
613
+ - end
614
+ + formats.each do |fmt|
615
+ + _provided_formats << fmt unless _provided_formats.include?(fmt)
616
+ end
617
+ + end
618
+
619
+ - # Sets list of provided formats for this particular
620
+ - # request. Usually used to limit formats to a single action. See also
621
+ - # the controller-level only_provides that affects all actions
622
+ - # in a controller.
623
+ - #
624
+ - # ==== Parameters
625
+ - # *formats<Symbol>:: A list of formats to use as the per-action list
626
+ - # of provided formats
627
+ - #
628
+ - # ==== Returns
629
+ - # Array:: List of formats passed in
630
+ - #
631
+ - #---
632
+ - # @public
633
+ - def only_provides(*formats)
634
+ - self._provided_formats = *formats
635
+ - end
636
+ -
637
+ - # Removes formats from the list of provided formats for this particular
638
+ - # request. Usually used to remove formats from a single action. See
639
+ - # also the controller-level does_not_provide that affects all actions in a
640
+ - # controller.
641
+ - #
642
+ - # ==== Parameters
643
+ - # *formats<Symbol>:: Registered mime-type
644
+ - #
645
+ - # ==== Returns
646
+ - # Array:: List of formats that remain after removing the ones not to provide
647
+ - #
648
+ - #---
649
+ - # @public
650
+ - def does_not_provide(*formats)
651
+ - formats.flatten!
652
+ - self._provided_formats -= formats
653
+ - end
654
+ -
655
+ - # Do the content negotiation:
656
+ - # 1. if params[:format] is there, and provided, use it
657
+ - # 2. Parse the Accept header
658
+ - # 3. If it's */*, use the first provided format
659
+ - # 4. Look for one that is provided, in order of request
660
+ - # 5. Raise 406 if none found
661
+ - def _perform_content_negotiation # :nodoc:
662
+ - raise Merb::ControllerExceptions::NotAcceptable if provided_formats.empty?
663
+ - if fmt = params[:format]
664
+ - return fmt.to_sym if provided_formats.include?(fmt.to_sym)
665
+ - else
666
+ - accepts = Responder.parse(request.accept).map {|t| t.to_sym}
667
+ - return provided_formats.first if accepts.include?(:all)
668
+ - return accepts.each { |type| break type if provided_formats.include?(type) }
669
+ - end
670
+ - raise Merb::ControllerExceptions::NotAcceptable
671
+ + # Sets list of provided formats for this particular
672
+ + # request. Usually used to limit formats to a single action. See also
673
+ + # the controller-level only_provides that affects all actions
674
+ + # in a controller.
675
+ + #
676
+ + # ==== Parameters
677
+ + # *formats<Symbol>:: A list of formats to use as the per-action list
678
+ + # of provided formats
679
+ + #
680
+ + # ==== Returns
681
+ + # Array:: List of formats passed in
682
+ + #
683
+ + #---
684
+ + # @public
685
+ + def only_provides(*formats)
686
+ + self._provided_formats = *formats
687
+ + end
688
+ +
689
+ + # Removes formats from the list of provided formats for this particular
690
+ + # request. Usually used to remove formats from a single action. See
691
+ + # also the controller-level does_not_provide that affects all actions in a
692
+ + # controller.
693
+ + #
694
+ + # ==== Parameters
695
+ + # *formats<Symbol>:: Registered mime-type
696
+ + #
697
+ + # ==== Returns
698
+ + # Array:: List of formats that remain after removing the ones not to provide
699
+ + #
700
+ + #---
701
+ + # @public
702
+ + def does_not_provide(*formats)
703
+ + formats.flatten!
704
+ + self._provided_formats -= formats
705
+ + end
706
+ +
707
+ + # Do the content negotiation:
708
+ + # 1. if params[:format] is there, and provided, use it
709
+ + # 2. Parse the Accept header
710
+ + # 3. If it's */*, use the first provided format
711
+ + # 4. Look for one that is provided, in order of request
712
+ + # 5. Raise 406 if none found
713
+ + def _perform_content_negotiation # :nodoc:
714
+ + raise Merb::ControllerExceptions::NotAcceptable if _provided_formats.empty?
715
+ + if fmt = params[:format] && _provided_formats.include?(fmt.to_sym)
716
+ + return fmt.to_sym
717
+ end
718
+ + accepts = Responder.parse(request.accept).map {|t| t.to_sym}
719
+ + return _provided_formats.first if accepts.include?(:all)
720
+ + (accepts & _provided_formats).first || (raise Merb::ControllerExceptions::NotAcceptable)
721
+ + end
722
+
723
+ - # Returns the output format for this request, based on the
724
+ - # provided formats, <tt>params[:format]</tt> and the client's HTTP
725
+ - # Accept header.
726
+ - #
727
+ - # The first time this is called, it triggers content negotiation
728
+ - # and caches the value. Once you call +content_type+ you can
729
+ - # not set or change the list of provided formats.
730
+ - #
731
+ - # Called automatically by +render+, so you should only call it if
732
+ - # you need the value, not to trigger content negotiation.
733
+ - #
734
+ - # ==== Parameters
735
+ - # fmt<String?>::
736
+ - # An optional format to use instead of performing content negotiation.
737
+ - # This can be used to pass in the values of opts[:format] from the
738
+ - # render function to short-circuit content-negotiation when it's not
739
+ - # necessary. This optional parameter should not be considered part
740
+ - # of the public API.
741
+ - #
742
+ - # ==== Returns
743
+ - # Symbol:: The content-type that will be used for this controller.
744
+ - #
745
+ - #---
746
+ - # @public
747
+ - def content_type(fmt = nil)
748
+ - self.content_type = (fmt || _perform_content_negotiation) unless @_content_type
749
+ - @_content_type
750
+ + # Returns the output format for this request, based on the
751
+ + # provided formats, <tt>params[:format]</tt> and the client's HTTP
752
+ + # Accept header.
753
+ + #
754
+ + # The first time this is called, it triggers content negotiation
755
+ + # and caches the value. Once you call +content_type+ you can
756
+ + # not set or change the list of provided formats.
757
+ + #
758
+ + # Called automatically by +render+, so you should only call it if
759
+ + # you need the value, not to trigger content negotiation.
760
+ + #
761
+ + # ==== Parameters
762
+ + # fmt<String?>::
763
+ + # An optional format to use instead of performing content negotiation.
764
+ + # This can be used to pass in the values of opts[:format] from the
765
+ + # render function to short-circuit content-negotiation when it's not
766
+ + # necessary. This optional parameter should not be considered part
767
+ + # of the public API.
768
+ + #
769
+ + # ==== Returns
770
+ + # Symbol:: The content-type that will be used for this controller.
771
+ + #
772
+ + #---
773
+ + # @public
774
+ + def content_type(fmt = nil)
775
+ + @_content_type = (fmt || _perform_content_negotiation) unless @_content_type
776
+ + @_content_type
777
+ + end
778
+ +
779
+ + # Sets the content type of the current response to a value based on
780
+ + # a passed in key. The Content-Type header will be set to the first
781
+ + # registered header for the mime-type.
782
+ + #
783
+ + # ==== Parameters
784
+ + # type<Symbol>:: A type that is in the list of registered mime-types.
785
+ + #
786
+ + # ==== Raises
787
+ + # ArgumentError:: "type" is not in the list of registered mime-types.
788
+ + #
789
+ + # ==== Returns
790
+ + # Symbol:: The content-type that was passed in.
791
+ + #
792
+ + #---
793
+ + # @semipublic
794
+ + def content_type=(type)
795
+ + unless Merb.available_mime_types.has_key?(type)
796
+ + raise Merb::ControllerExceptions::NotAcceptable.new("Unknown content_type for response: #{type}")
797
+ + end
798
+ + headers['Content-Type'] = Merb.available_mime_types[type].first
799
+ + @_content_type = type
800
+ + end
801
+ +
802
+ + end
803
+ +
804
+ + class Responder
805
+ +
806
+ + protected
807
+ + def self.parse(accept_header)
808
+ + # parse the raw accept header into a unique, sorted array of AcceptType objects
809
+ + list = accept_header.to_s.split(/,/).enum_for(:each_with_index).map do |entry,index|
810
+ + AcceptType.new(entry,index += 1)
811
+ + end.sort.uniq
812
+ + # firefox (and possibly other browsers) send broken default accept headers.
813
+ + # fix them up by sorting alternate xml forms (namely application/xhtml+xml)
814
+ + # ahead of pure xml types (application/xml,text/xml).
815
+ + if app_xml = list.detect{|e| e.super_range == 'application/xml'}
816
+ + list.select{|e| e.to_s =~ /\+xml/}.each { |acc_type|
817
+ + list[list.index(acc_type)],list[list.index(app_xml)] =
818
+ + list[list.index(app_xml)],list[list.index(acc_type)] }
819
+ end
820
+ -
821
+ - # Sets the content type of the current response to a value based on
822
+ - # a passed in key. The Content-Type header will be set to the first
823
+ - # registered header for the mime-type.
824
+ - #
825
+ - # ==== Parameters
826
+ - # type<Symbol>:: A type that is in the list of registered mime-types.
827
+ - #
828
+ - # ==== Raises
829
+ - # ArgumentError:: "type" is not in the list of registered mime-types.
830
+ - #
831
+ - # ==== Returns
832
+ - # Symbol:: The content-type that was passed in.
833
+ - #
834
+ - #---
835
+ - # @semipublic
836
+ - def content_type=(type)
837
+ - unless Merb.available_mime_types.has_key?(type)
838
+ - raise Merb::ControllerExceptions::NotAcceptable.new("Unknown content_type for response: #{type}")
839
+ - end
840
+ - headers['Content-Type'] = Merb.available_mime_types[type].first
841
+ - @_content_type = type
842
+ + list
843
+ + end
844
+ +
845
+ + public
846
+ + def self.params_to_query_string(value, prefix = nil)
847
+ + case value
848
+ + when Array
849
+ + value.map { |v|
850
+ + params_to_query_string(v, "#{prefix}[]")
851
+ + } * "&"
852
+ + when Hash
853
+ + value.map { |k, v|
854
+ + params_to_query_string(v, prefix ? "#{prefix}[#{Merb::Request.escape(k)}]" : Merb::Request.escape(k))
855
+ + } * "&"
856
+ + else
857
+ + "#{prefix}=#{Merb::Request.escape(value)}"
858
+ end
859
+ + end
860
+
861
+ - end
862
+ + end
863
+ +
864
+ + class AcceptType
865
+ +
866
+ + attr_reader :media_range, :quality, :index, :type, :sub_type
867
+
868
+ + def initialize(entry,index)
869
+ + @index = index
870
+ + @media_range, quality = entry.split(/;\s*q=/).map{|a| a.strip }
871
+ + @type, @sub_type = @media_range.split(/\//)
872
+ + quality ||= 0.0 if @media_range == '*/*'
873
+ + @quality = ((quality || 1.0).to_f * 100).to_i
874
+ + end
875
+ +
876
+ + def <=>(entry)
877
+ + c = entry.quality <=> quality
878
+ + c = index <=> entry.index if c == 0
879
+ + c
880
+ + end
881
+ +
882
+ + def eql?(entry)
883
+ + synonyms.include?(entry.media_range)
884
+ + end
885
+ +
886
+ + def ==(entry); eql?(entry); end
887
+ +
888
+ + def hash; super_range.hash; end
889
+ +
890
+ + def synonyms
891
+ + @syns ||= Merb.available_mime_types.values.map do |e|
892
+ + e[:request_headers] if e[:request_headers].include?(@media_range)
893
+ + end.compact.flatten
894
+ + end
895
+ +
896
+ + def super_range
897
+ + synonyms.first || @media_range
898
+ + end
899
+ +
900
+ + def to_sym
901
+ + Merb.available_mime_types.select{|k,v|
902
+ + v[:request_headers] == synonyms || v[:request_headers][0] == synonyms[0]}.flatten.first
903
+ + end
904
+ +
905
+ + def to_s
906
+ + @media_range
907
+ + end
908
+ +
909
+ end
910
+ +
911
+
912
+ end
913
+
914
+ diff --git a/lib/merb_core/dispatch/dispatcher.rb b/lib/merb_core/dispatch/dispatcher.rb
915
+ index c458c9f9ad454d3b0c3055d6b2a8e88b17712b44..f7fed0f539a20f9cce08b72c551725ad0563bf37 100644
916
+ --- a/lib/merb_core/dispatch/dispatcher.rb
917
+ +++ b/lib/merb_core/dispatch/dispatcher.rb
918
+ @@ -33,10 +33,10 @@ class Merb::Dispatcher
919
+
920
+ # this is the custom dispatch_exception; it allows failures to still be dispatched
921
+ # to the error controller
922
+ - rescue => exception
923
+ - Merb.logger.error(Merb.exception(exception))
924
+ - exception = controller_exception(exception)
925
+ - dispatch_exception(request, response, exception)
926
+ + # rescue => exception
927
+ + # Merb.logger.error(Merb.exception(exception))
928
+ + # exception = controller_exception(exception)
929
+ + # dispatch_exception(request, response, exception)
930
+ end
931
+
932
+ private
933
+ @@ -49,10 +49,10 @@ class Merb::Dispatcher
934
+ def dispatch_action(klass, action, request, response, status=200)
935
+ # build controller
936
+ controller = klass.build(request, response, status)
937
+ - if @@use_mutex
938
+ - @@mutex.synchronize { controller.dispatch(action) }
939
+ + if use_mutex
940
+ + @@mutex.synchronize { controller._dispatch(action) }
941
+ else
942
+ - controller.dispatch(action)
943
+ + controller._dispatch(action)
944
+ end
945
+ [controller, action]
946
+ end
947
+ diff --git a/lib/merb_core/rack/adapter.rb b/lib/merb_core/rack/adapter.rb
948
+ index ffc7117e9733e83b0567bbe4a43fac7663800b7d..217399a5382d0b3878aaea3d3e302173c5b5f119 100644
949
+ --- a/lib/merb_core/rack/adapter.rb
950
+ +++ b/lib/merb_core/rack/adapter.rb
951
+ @@ -40,7 +40,7 @@ module Merb
952
+ begin
953
+ controller, action = ::Merb::Dispatcher.handle(request, response)
954
+ rescue Object => e
955
+ - return [500, {"Content-Type"=>"text/html"}, "Internal Server Error"]
956
+ + return [500, {"Content-Type"=>"text/html"}, e.message + "<br/>" + e.backtrace.join("<br/>")]
957
+ end
958
+ [controller.status, controller.headers, controller.body]
959
+ end
960
+ diff --git a/lib/merb_core/test/request_helper.rb b/lib/merb_core/test/request_helper.rb
961
+ index 10a9fb3ace56eaf1db0fa300df3fb2ab88a7118a..f302a3b71539182ba142cd208fe6d6aae171b1a1 100644
962
+ --- a/lib/merb_core/test/request_helper.rb
963
+ +++ b/lib/merb_core/test/request_helper.rb
964
+ @@ -26,8 +26,10 @@ module Merb::Test::RequestHelper
965
+ Merb::Test::FakeRequest.new(env, StringIO.new(req))
966
+ end
967
+
968
+ - def dispatch_to(controller_klass, action, env = {}, opt = {}, &blk)
969
+ - request = fake_request(env, opt)
970
+ + def dispatch_to(controller_klass, action, params = {}, env = {}, &blk)
971
+ + request = fake_request(env,
972
+ + :query_string => Merb::Responder.params_to_query_string(params))
973
+ +
974
+ controller = controller_klass.build(request)
975
+ controller.instance_eval(&blk) if block_given?
976
+ controller._dispatch(action)
977
+ diff --git a/spec/public/abstract_controller/spec_helper.rb b/spec/public/abstract_controller/spec_helper.rb
978
+ index df759008d14e7572b5c44de24f77f828f83f1682..694cee2592a210a5c1fa40ca7846beeaa09725fe 100644
979
+ --- a/spec/public/abstract_controller/spec_helper.rb
980
+ +++ b/spec/public/abstract_controller/spec_helper.rb
981
+ @@ -1,12 +1,10 @@
982
+ __DIR__ = File.dirname(__FILE__)
983
+ require File.join(__DIR__, "..", "..", "spec_helper")
984
+
985
+ -# The framework structure *must* be set up before loading in framework
986
+ -# files.
987
+ require File.join(__DIR__, "controllers", "filters")
988
+ require File.join(__DIR__, "controllers", "render")
989
+
990
+ -Merb::BootLoader::Templates.new.run
991
+ +Merb::BootLoader::Templates.run
992
+
993
+ module Merb::Test::Behaviors
994
+ def dispatch_should_make_body(klass, body, action = :index)
995
+ diff --git a/spec/public/controller/base_spec.rb b/spec/public/controller/base_spec.rb
996
+ index 1709e612629ed2c2b6af4579a8b89684aca9aa3c..5bcdb59948cc22592639b1aee9bd233ff2c306fa 100644
997
+ --- a/spec/public/controller/base_spec.rb
998
+ +++ b/spec/public/controller/base_spec.rb
999
+ @@ -10,11 +10,11 @@ describe Merb::Controller, " callable actions" do
1000
+ end
1001
+
1002
+ it "should dispatch to callable actions" do
1003
+ - dispatch_to(Merb::Test::Fixtures::TestFoo, :index).body.should == "index"
1004
+ + dispatch_to(Merb::Test::Fixtures::TestBase, :index).body.should == "index"
1005
+ end
1006
+
1007
+ it "should not dispatch to hidden actions" do
1008
+ - calling { dispatch_to(Merb::Test::Fixtures::TestFoo, :hidden) }.
1009
+ + calling { dispatch_to(Merb::Test::Fixtures::TestBase, :hidden) }.
1010
+ should raise_error(Merb::ControllerExceptions::ActionNotFound)
1011
+ end
1012
+
1013
+ diff --git a/spec/public/controller/controllers/base.rb b/spec/public/controller/controllers/base.rb
1014
+ index a1b3beb27899df781d943427d9b23945f02e14de..c4b69a440a9da3c3486208d2cb95ccb8bdb974b9 100644
1015
+ --- a/spec/public/controller/controllers/base.rb
1016
+ +++ b/spec/public/controller/controllers/base.rb
1017
+ @@ -3,7 +3,7 @@ module Merb::Test::Fixtures
1018
+ self._template_root = File.dirname(__FILE__) / "views"
1019
+ end
1020
+
1021
+ - class TestFoo < ControllerTesting
1022
+ + class TestBase < ControllerTesting
1023
+ def index
1024
+ "index"
1025
+ end
1026
+ diff --git a/spec/public/controller/controllers/responder.rb b/spec/public/controller/controllers/responder.rb
1027
+ new file mode 100644
1028
+ index 0000000000000000000000000000000000000000..867192e8f6e995a43fd5cd3daffa0ec11b3d31e5
1029
+ --- /dev/null
1030
+ +++ b/spec/public/controller/controllers/responder.rb
1031
+ @@ -0,0 +1,25 @@
1032
+ +module Merb::Test::Fixtures
1033
+ + class ControllerTesting < Merb::Controller
1034
+ + self._template_root = File.dirname(__FILE__) / "views"
1035
+ + end
1036
+ +
1037
+ + class TestResponder < ControllerTesting
1038
+ + def index
1039
+ + render
1040
+ + end
1041
+ + end
1042
+ +
1043
+ + class TestHtmlDefault < TestResponder; end
1044
+ +
1045
+ + class TestClassProvides < TestResponder;
1046
+ + provides :xml
1047
+ + end
1048
+ +
1049
+ + class TestLocalProvides < TestResponder;
1050
+ + def index
1051
+ + provides :xml
1052
+ + render
1053
+ + end
1054
+ + end
1055
+ +
1056
+ +end
1057
+
1058
+ diff --git a/spec/public/controller/controllers/views/merb/test/fixtures/test_class_provides/index.html.erb b/spec/public/controller/controllers/views/merb/test/fixtures/test_class_provides/index.html.erb
1059
+ new file mode 100644
1060
+ index 0000000000000000000000000000000000000000..1bfb77d4a44c444bba6888ae7740f7df4b074c58
1061
+ --- /dev/null
1062
+ +++ b/spec/public/controller/controllers/views/merb/test/fixtures/test_class_provides/index.html.erb
1063
+ @@ -0,0 +1 @@
1064
+ +This should not be rendered
1065
+
1066
+ diff --git a/spec/public/controller/controllers/views/merb/test/fixtures/test_class_provides/index.xml.erb b/spec/public/controller/controllers/views/merb/test/fixtures/test_class_provides/index.xml.erb
1067
+ new file mode 100644
1068
+ index 0000000000000000000000000000000000000000..7c91f633987348e87e5e34e1d9e87d9dd0e5100c
1069
+ --- /dev/null
1070
+ +++ b/spec/public/controller/controllers/views/merb/test/fixtures/test_class_provides/index.xml.erb
1071
+ @@ -0,0 +1 @@
1072
+ +<XML:Class provides='true' />
1073
+
1074
+ diff --git a/spec/public/controller/controllers/views/merb/test/fixtures/test_html_default/index.html.erb b/spec/public/controller/controllers/views/merb/test/fixtures/test_html_default/index.html.erb
1075
+ new file mode 100644
1076
+ index 0000000000000000000000000000000000000000..eb4b52bf5a7aaba8f1706de419f42789c05684a2
1077
+ --- /dev/null
1078
+ +++ b/spec/public/controller/controllers/views/merb/test/fixtures/test_html_default/index.html.erb
1079
+ @@ -0,0 +1 @@
1080
+ +HTML: Default
1081
+
1082
+ diff --git a/spec/public/controller/controllers/views/merb/test/fixtures/test_local_provides/index.html.erb b/spec/public/controller/controllers/views/merb/test/fixtures/test_local_provides/index.html.erb
1083
+ new file mode 100644
1084
+ index 0000000000000000000000000000000000000000..a3a841a89c62e6174038935a42da9cd24ff54413
1085
+ --- /dev/null
1086
+ +++ b/spec/public/controller/controllers/views/merb/test/fixtures/test_local_provides/index.html.erb
1087
+ @@ -0,0 +1 @@
1088
+ +This should not render
1089
+
1090
+ diff --git a/spec/public/controller/controllers/views/merb/test/fixtures/test_local_provides/index.xml.erb b/spec/public/controller/controllers/views/merb/test/fixtures/test_local_provides/index.xml.erb
1091
+ new file mode 100644
1092
+ index 0000000000000000000000000000000000000000..c1384ec6af0357b585cc367035d1bc3a30347ade
1093
+ --- /dev/null
1094
+ +++ b/spec/public/controller/controllers/views/merb/test/fixtures/test_local_provides/index.xml.erb
1095
+ @@ -0,0 +1 @@
1096
+ +<XML:Local provides='true' />
1097
+
1098
+ diff --git a/spec/public/controller/responder_spec.rb b/spec/public/controller/responder_spec.rb
1099
+ index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..bcf18532442e5965cf6ca8501770d7b7a1eb2429 100644
1100
+ --- a/spec/public/controller/responder_spec.rb
1101
+ +++ b/spec/public/controller/responder_spec.rb
1102
+ @@ -0,0 +1,31 @@
1103
+ +require File.join(File.dirname(__FILE__), "spec_helper")
1104
+ +
1105
+ +describe Merb::Controller, " responds" do
1106
+ +
1107
+ + before do
1108
+ + Merb.push_path(:layout, File.dirname(__FILE__) / "controllers" / "views" / "layouts")
1109
+ + Merb::Router.prepare do |r|
1110
+ + r.default_routes
1111
+ + end
1112
+ + end
1113
+ +
1114
+ + it "should default the mime-type to HTML" do
1115
+ + dispatch_to(Merb::Test::Fixtures::TestHtmlDefault, :index).body.should == "HTML: Default"
1116
+ + end
1117
+ +
1118
+ + it "should use other mime-types if they are provided on the class level" do
1119
+ + controller = dispatch_to(Merb::Test::Fixtures::TestClassProvides, :index, {}, :http_accept => "application/xml")
1120
+ + controller.body.should == "<XML:Class provides='true' />"
1121
+ + end
1122
+ +
1123
+ + it "should fail if none of the acceptable mime-types are available" do
1124
+ + calling { dispatch_to(Merb::Test::Fixtures::TestClassProvides, :index, {}, :http_accept => "application/json") }.
1125
+ + should raise_error(Merb::ControllerExceptions::NotAcceptable)
1126
+ + end
1127
+ +
1128
+ + it "should use mime-types that are provided at the local level" do
1129
+ + controller = dispatch_to(Merb::Test::Fixtures::TestLocalProvides, :index, {}, :http_accept => "application/xml")
1130
+ + controller.body.should == "<XML:Local provides='true' />"
1131
+ + end
1132
+ +
1133
+ +end
1134
+
1135
+ diff --git a/spec/public/controller/spec_helper.rb b/spec/public/controller/spec_helper.rb
1136
+ index f68628a63740f4ce0235a15d71c5889e55ecaf78..e360194c1fbaf72c3298c61543c2d3a19b512b41 100644
1137
+ --- a/spec/public/controller/spec_helper.rb
1138
+ +++ b/spec/public/controller/spec_helper.rb
1139
+ @@ -1,4 +1,10 @@
1140
+ __DIR__ = File.dirname(__FILE__)
1141
+ +require 'ruby-debug'
1142
+ +
1143
+ require File.join(__DIR__, "..", "..", "spec_helper")
1144
+
1145
+ -require File.join(__DIR__, "controllers", "base")
1146
+
1147
+ +require File.join(__DIR__, "controllers", "base")
1148
+ +require File.join(__DIR__, "controllers", "responder")
1149
+ +
1150
+ +Merb::BootLoader::Templates.run
1151
+ +Merb::BootLoader::MimeTypes.run
1152
+