merb-core 0.9.4 → 0.9.5
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.
- data/Rakefile +22 -13
- data/lib/merb-core/bootloader.rb +3 -2
- data/lib/merb-core/config.rb +1 -1
- data/lib/merb-core/constants.rb +3 -1
- data/lib/merb-core/controller/abstract_controller.rb +25 -39
- data/lib/merb-core/controller/exceptions.rb +14 -16
- data/lib/merb-core/controller/merb_controller.rb +2 -2
- data/lib/merb-core/controller/mime.rb +2 -1
- data/lib/merb-core/controller/mixins/render.rb +12 -0
- data/lib/merb-core/controller/mixins/responder.rb +31 -7
- data/lib/merb-core/core_ext/hash.rb +7 -0
- data/lib/merb-core/core_ext/kernel.rb +31 -34
- data/lib/merb-core/core_ext.rb +1 -0
- data/lib/merb-core/dispatch/default_exception/default_exception.rb +3 -3
- data/lib/merb-core/dispatch/dispatcher.rb +128 -135
- data/lib/merb-core/dispatch/request.rb +11 -11
- data/lib/merb-core/dispatch/router/behavior.rb +6 -6
- data/lib/merb-core/dispatch/router.rb +5 -5
- data/lib/merb-core/logger.rb +203 -202
- data/lib/merb-core/rack/application.rb +19 -5
- data/lib/merb-core/rack/middleware/conditional_get.rb +23 -0
- data/lib/merb-core/rack/middleware/content_length.rb +18 -0
- data/lib/merb-core/rack/middleware/tracer.rb +20 -0
- data/lib/merb-core/rack/middleware.rb +1 -7
- data/lib/merb-core/rack.rb +19 -16
- data/lib/merb-core/test/matchers/route_matchers.rb +1 -0
- data/lib/merb-core/test/matchers/view_matchers.rb +36 -0
- data/lib/merb-core/test/run_specs.rb +2 -1
- data/lib/merb-core/version.rb +1 -1
- data/lib/merb-core.rb +39 -33
- data/spec/private/config/merb_spec.rb +34 -0
- data/spec/private/dispatch/fixture/log/merb_test.log +372 -0
- data/spec/private/router/fixture/log/merb_test.log +42 -0
- data/spec/public/abstract_controller/controllers/filters.rb +50 -1
- data/spec/public/abstract_controller/filter_spec.rb +25 -0
- data/spec/public/controller/base_spec.rb +41 -1
- data/spec/public/controller/controllers/base.rb +16 -0
- data/spec/public/controller/controllers/views/merb/test/fixtures/controllers/class_provides/index.html.erb +1 -1
- data/spec/public/controller/dispatcher_spec.rb +24 -25
- data/spec/public/controller/responder_spec.rb +6 -0
- data/spec/public/core_ext/kernel_spec.rb +79 -0
- data/spec/public/directory_structure/directory/log/merb_test.log +245 -0
- data/spec/public/rack/conditinal_get_middleware_spec.rb +139 -0
- data/spec/public/rack/rack_middleware_spec.rb +99 -0
- data/spec/public/rack/shared_example_groups.rb +35 -0
- data/spec/public/reloading/directory/log/merb_test.log +40 -0
- data/spec/public/request/request_spec.rb +0 -5
- data/spec/public/router/fixture/log/merb_test.log +348 -0
- data/spec/public/test/route_matchers_spec.rb +4 -0
- data/spec/spec_helper.rb +7 -1
- metadata +42 -5
- data/spec/private/plugins/plugin_spec.rb +0 -166
data/lib/merb-core/logger.rb
CHANGED
@@ -1,202 +1,203 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
# Merb.logger.
|
13
|
-
# Merb.logger.
|
14
|
-
# Merb.logger.
|
15
|
-
# Merb.logger.
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
# Merb.logger.
|
20
|
-
# Merb.logger.
|
21
|
-
# Merb.logger.
|
22
|
-
# Merb.logger.
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
1
|
+
Merb::Logger = Extlib::Logger
|
2
|
+
# require "time" # httpdate
|
3
|
+
# # ==== Public Merb Logger API
|
4
|
+
# #
|
5
|
+
# # To replace an existing logger with a new one:
|
6
|
+
# # Merb::Logger.set_log(log{String, IO},level{Symbol, String})
|
7
|
+
# #
|
8
|
+
# # Available logging levels are
|
9
|
+
# # Merb::Logger::{ Fatal, Error, Warn, Info, Debug }
|
10
|
+
# #
|
11
|
+
# # Logging via:
|
12
|
+
# # Merb.logger.fatal(message<String>,&block)
|
13
|
+
# # Merb.logger.error(message<String>,&block)
|
14
|
+
# # Merb.logger.warn(message<String>,&block)
|
15
|
+
# # Merb.logger.info(message<String>,&block)
|
16
|
+
# # Merb.logger.debug(message<String>,&block)
|
17
|
+
# #
|
18
|
+
# # Logging with autoflush:
|
19
|
+
# # Merb.logger.fatal!(message<String>,&block)
|
20
|
+
# # Merb.logger.error!(message<String>,&block)
|
21
|
+
# # Merb.logger.warn!(message<String>,&block)
|
22
|
+
# # Merb.logger.info!(message<String>,&block)
|
23
|
+
# # Merb.logger.debug!(message<String>,&block)
|
24
|
+
# #
|
25
|
+
# # Flush the buffer to
|
26
|
+
# # Merb.logger.flush
|
27
|
+
# #
|
28
|
+
# # Remove the current log object
|
29
|
+
# # Merb.logger.close
|
30
|
+
# #
|
31
|
+
# # ==== Private Merb Logger API
|
32
|
+
# #
|
33
|
+
# # To initialize the logger you create a new object, proxies to set_log.
|
34
|
+
# # Merb::Logger.new(log{String, IO},level{Symbol, String})
|
35
|
+
# module Merb
|
36
|
+
#
|
37
|
+
# class << self
|
38
|
+
# attr_accessor :logger
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# class Logger
|
42
|
+
#
|
43
|
+
# attr_accessor :level
|
44
|
+
# attr_accessor :delimiter
|
45
|
+
# attr_accessor :auto_flush
|
46
|
+
# attr_reader :buffer
|
47
|
+
# attr_reader :log
|
48
|
+
# attr_reader :init_args
|
49
|
+
#
|
50
|
+
# # ==== Notes
|
51
|
+
# # Ruby (standard) logger levels:
|
52
|
+
# # :fatal:: An unhandleable error that results in a program crash
|
53
|
+
# # :error:: A handleable error condition
|
54
|
+
# # :warn:: A warning
|
55
|
+
# # :info:: generic (useful) information about system operation
|
56
|
+
# # :debug:: low-level information for developers
|
57
|
+
# Levels =
|
58
|
+
# {
|
59
|
+
# :fatal => 7,
|
60
|
+
# :error => 6,
|
61
|
+
# :warn => 4,
|
62
|
+
# :info => 3,
|
63
|
+
# :debug => 0
|
64
|
+
# } unless const_defined?(:Levels)
|
65
|
+
#
|
66
|
+
# private
|
67
|
+
#
|
68
|
+
# # Readies a log for writing.
|
69
|
+
# #
|
70
|
+
# # ==== Parameters
|
71
|
+
# # log<IO, String>:: Either an IO object or a name of a logfile.
|
72
|
+
# def initialize_log(log)
|
73
|
+
# close if @log # be sure that we don't leave open files laying around.
|
74
|
+
#
|
75
|
+
# if log.respond_to?(:write)
|
76
|
+
# @log = log
|
77
|
+
# elsif File.exist?(log)
|
78
|
+
# @log = open(log, (File::WRONLY | File::APPEND))
|
79
|
+
# @log.sync = true
|
80
|
+
# else
|
81
|
+
# FileUtils.mkdir_p(File.dirname(log)) unless File.directory?(File.dirname(log))
|
82
|
+
# @log = open(log, (File::WRONLY | File::APPEND | File::CREAT))
|
83
|
+
# @log.sync = true
|
84
|
+
# @log.write("#{Time.now.httpdate} #{delimiter} info #{delimiter} Logfile created\n")
|
85
|
+
# end
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# public
|
89
|
+
#
|
90
|
+
# # To initialize the logger you create a new object, proxies to set_log.
|
91
|
+
# #
|
92
|
+
# # ==== Parameters
|
93
|
+
# # *args:: Arguments to create the log from. See set_logs for specifics.
|
94
|
+
# def initialize(*args)
|
95
|
+
# @init_args = args
|
96
|
+
# set_log(*args)
|
97
|
+
# end
|
98
|
+
#
|
99
|
+
# # Replaces an existing logger with a new one.
|
100
|
+
# #
|
101
|
+
# # ==== Parameters
|
102
|
+
# # log<IO, String>:: Either an IO object or a name of a logfile.
|
103
|
+
# # log_level<~to_sym>::
|
104
|
+
# # The log level from, e.g. :fatal or :info. Defaults to :error in the
|
105
|
+
# # production environment and :debug otherwise.
|
106
|
+
# # delimiter<String>::
|
107
|
+
# # Delimiter to use between message sections. Defaults to " ~ ".
|
108
|
+
# # auto_flush<Boolean>::
|
109
|
+
# # Whether the log should automatically flush after new messages are
|
110
|
+
# # added. Defaults to false.
|
111
|
+
# def set_log(log, log_level = nil, delimiter = " ~ ", auto_flush = false)
|
112
|
+
# if log_level && Levels[log_level.to_sym]
|
113
|
+
# @level = Levels[log_level.to_sym]
|
114
|
+
# elsif Merb.environment == "production"
|
115
|
+
# @level = Levels[:warn]
|
116
|
+
# else
|
117
|
+
# @level = Levels[:debug]
|
118
|
+
# end
|
119
|
+
# @buffer = []
|
120
|
+
# @delimiter = delimiter
|
121
|
+
# @auto_flush = auto_flush
|
122
|
+
#
|
123
|
+
# initialize_log(log)
|
124
|
+
#
|
125
|
+
# Merb.logger = self
|
126
|
+
# end
|
127
|
+
#
|
128
|
+
# # Flush the entire buffer to the log object.
|
129
|
+
# def flush
|
130
|
+
# return unless @buffer.size > 0
|
131
|
+
# @log.write(@buffer.slice!(0..-1).to_s)
|
132
|
+
# end
|
133
|
+
#
|
134
|
+
# # Close and remove the current log object.
|
135
|
+
# def close
|
136
|
+
# flush
|
137
|
+
# @log.close if @log.respond_to?(:close) && !@log.tty?
|
138
|
+
# @log = nil
|
139
|
+
# end
|
140
|
+
#
|
141
|
+
# # Appends a message to the log. The methods yield to an optional block and
|
142
|
+
# # the output of this block will be appended to the message.
|
143
|
+
# #
|
144
|
+
# # ==== Parameters
|
145
|
+
# # string<String>:: The message to be logged. Defaults to nil.
|
146
|
+
# #
|
147
|
+
# # ==== Returns
|
148
|
+
# # String:: The resulting message added to the log file.
|
149
|
+
# def <<(string = nil)
|
150
|
+
# message = ""
|
151
|
+
# message << delimiter
|
152
|
+
# message << string if string
|
153
|
+
# message << "\n" unless message[-1] == ?\n
|
154
|
+
# @buffer << message
|
155
|
+
# flush if @auto_flush
|
156
|
+
#
|
157
|
+
# message
|
158
|
+
# end
|
159
|
+
# alias :push :<<
|
160
|
+
#
|
161
|
+
# # Generate the logging methods for Merb.logger for each log level.
|
162
|
+
# Levels.each_pair do |name, number|
|
163
|
+
# class_eval <<-LEVELMETHODS, __FILE__, __LINE__
|
164
|
+
#
|
165
|
+
# # Appends a message to the log if the log level is at least as high as
|
166
|
+
# # the log level of the logger.
|
167
|
+
# #
|
168
|
+
# # ==== Parameters
|
169
|
+
# # string<String>:: The message to be logged. Defaults to nil.
|
170
|
+
# #
|
171
|
+
# # ==== Returns
|
172
|
+
# # self:: The logger object for chaining.
|
173
|
+
# def #{name}(message = nil)
|
174
|
+
# self << message if #{number} >= level
|
175
|
+
# self
|
176
|
+
# end
|
177
|
+
#
|
178
|
+
# # Appends a message to the log if the log level is at least as high as
|
179
|
+
# # the log level of the logger. The bang! version of the method also auto
|
180
|
+
# # flushes the log buffer to disk.
|
181
|
+
# #
|
182
|
+
# # ==== Parameters
|
183
|
+
# # string<String>:: The message to be logged. Defaults to nil.
|
184
|
+
# #
|
185
|
+
# # ==== Returns
|
186
|
+
# # self:: The logger object for chaining.
|
187
|
+
# def #{name}!(message = nil)
|
188
|
+
# self << message if #{number} >= level
|
189
|
+
# flush if #{number} >= level
|
190
|
+
# self
|
191
|
+
# end
|
192
|
+
#
|
193
|
+
# # ==== Returns
|
194
|
+
# # Boolean:: True if this level will be logged by this logger.
|
195
|
+
# def #{name}?
|
196
|
+
# #{number} >= level
|
197
|
+
# end
|
198
|
+
# LEVELMETHODS
|
199
|
+
# end
|
200
|
+
#
|
201
|
+
# end
|
202
|
+
#
|
203
|
+
# end
|
@@ -6,13 +6,27 @@ module Merb
|
|
6
6
|
begin
|
7
7
|
controller = ::Merb::Dispatcher.handle(Merb::Request.new(env))
|
8
8
|
rescue Object => e
|
9
|
-
return [500, {
|
9
|
+
return [500, {Merb::Const::CONTENT_TYPE => "text/html"}, e.message + "<br/>" + e.backtrace.join("<br/>")]
|
10
10
|
end
|
11
11
|
Merb.logger.info "\n\n"
|
12
12
|
Merb.logger.flush
|
13
|
+
|
14
|
+
unless controller.headers[Merb::Const::DATE]
|
15
|
+
require "time"
|
16
|
+
controller.headers[Merb::Const::DATE] = Time.now.rfc2822.to_s
|
17
|
+
end
|
13
18
|
controller.rack_response
|
14
19
|
end
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
20
|
+
|
21
|
+
def deferred?(env)
|
22
|
+
path = env[Merb::Const::PATH_INFO] ? env[Merb::Const::PATH_INFO].chomp('/') : ""
|
23
|
+
if path =~ Merb.deferred_actions
|
24
|
+
Merb.logger.info! "Deferring Request: #{path}"
|
25
|
+
true
|
26
|
+
else
|
27
|
+
false
|
28
|
+
end
|
29
|
+
end # deferred?(env)
|
30
|
+
end # Application
|
31
|
+
end # Rack
|
32
|
+
end # Merb
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Merb
|
2
|
+
module Rack
|
3
|
+
|
4
|
+
class ConditionalGet < Merb::Rack::Middleware
|
5
|
+
def call(env)
|
6
|
+
status, headers, body = @app.call(env)
|
7
|
+
|
8
|
+
# set Date header using RFC1123 date format as specified by HTTP
|
9
|
+
# RFC2616 section 3.3.1.
|
10
|
+
if etag = headers['ETag']
|
11
|
+
status = 304 if etag == env[Merb::Const::HTTP_IF_NONE_MATCH]
|
12
|
+
end
|
13
|
+
|
14
|
+
if last_modified = headers[Merb::Const::LAST_MODIFIED]
|
15
|
+
status = 304 if last_modified == env[Merb::Const::HTTP_IF_MODIFIED_SINCE]
|
16
|
+
end
|
17
|
+
|
18
|
+
[status, headers, body]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Merb
|
2
|
+
module Rack
|
3
|
+
|
4
|
+
class ContentLength < Merb::Rack::Middleware
|
5
|
+
def call(env)
|
6
|
+
status, headers, body = @app.call(env)
|
7
|
+
|
8
|
+
# to_s is because Rack spec expects header
|
9
|
+
# values to be iterable and yield strings
|
10
|
+
header = 'Content-Length'.freeze
|
11
|
+
headers[header] = body.size.to_s unless headers.has_key?(header)
|
12
|
+
|
13
|
+
[status, headers, body]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Merb
|
2
|
+
module Rack
|
3
|
+
class Tracer < Merb::Rack::Middleware
|
4
|
+
|
5
|
+
def call(env)
|
6
|
+
|
7
|
+
Merb.logger.debug!("Rack environment:\n" + env.inspect + "\n\n")
|
8
|
+
|
9
|
+
status, headers, body = @app.call(env)
|
10
|
+
|
11
|
+
Merb.logger.debug!("Status: #{status.inspect}")
|
12
|
+
Merb.logger.debug!("Headers: #{headers.inspect}")
|
13
|
+
Merb.logger.debug!("Body: #{body.inspect}")
|
14
|
+
|
15
|
+
[status, headers, body]
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -7,13 +7,7 @@ module Merb
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def deferred?(env)
|
10
|
-
|
11
|
-
if path =~ Merb.deferred_actions
|
12
|
-
Merb.logger.info! "Deferring Request: #{path}"
|
13
|
-
true
|
14
|
-
else
|
15
|
-
false
|
16
|
-
end
|
10
|
+
@app.deferred?(env)
|
17
11
|
end
|
18
12
|
|
19
13
|
def call(env)
|
data/lib/merb-core/rack.rb
CHANGED
@@ -1,21 +1,24 @@
|
|
1
1
|
require 'rack'
|
2
2
|
module Merb
|
3
3
|
module Rack
|
4
|
-
autoload :Application, 'merb-core
|
5
|
-
autoload :Adapter, 'merb-core
|
6
|
-
autoload :Ebb, 'merb-core
|
7
|
-
autoload :EventedMongrel, 'merb-core
|
8
|
-
autoload :FastCGI, 'merb-core
|
9
|
-
autoload :Irb, 'merb-core
|
10
|
-
autoload :Middleware, 'merb-core
|
11
|
-
autoload :Mongrel, 'merb-core
|
12
|
-
autoload :Runner, 'merb-core
|
13
|
-
autoload :SwiftipliedMongrel, 'merb-core
|
14
|
-
autoload :Thin, 'merb-core
|
15
|
-
autoload :ThinTurbo, 'merb-core
|
16
|
-
autoload :WEBrick, 'merb-core
|
17
|
-
autoload :PathPrefix, 'merb-core
|
18
|
-
autoload :Static, 'merb-core
|
19
|
-
autoload :Profiler, 'merb-core
|
4
|
+
autoload :Application, 'merb-core/rack/application'
|
5
|
+
autoload :Adapter, 'merb-core/rack/adapter'
|
6
|
+
autoload :Ebb, 'merb-core/rack/adapter/ebb'
|
7
|
+
autoload :EventedMongrel, 'merb-core/rack/adapter/evented_mongrel'
|
8
|
+
autoload :FastCGI, 'merb-core/rack/adapter/fcgi'
|
9
|
+
autoload :Irb, 'merb-core/rack/adapter/irb'
|
10
|
+
autoload :Middleware, 'merb-core/rack/middleware'
|
11
|
+
autoload :Mongrel, 'merb-core/rack/adapter/mongrel'
|
12
|
+
autoload :Runner, 'merb-core/rack/adapter/runner'
|
13
|
+
autoload :SwiftipliedMongrel, 'merb-core/rack/adapter/swiftiplied_mongrel'
|
14
|
+
autoload :Thin, 'merb-core/rack/adapter/thin'
|
15
|
+
autoload :ThinTurbo, 'merb-core/rack/adapter/thin_turbo'
|
16
|
+
autoload :WEBrick, 'merb-core/rack/adapter/webrick'
|
17
|
+
autoload :PathPrefix, 'merb-core/rack/middleware/path_prefix'
|
18
|
+
autoload :Static, 'merb-core/rack/middleware/static'
|
19
|
+
autoload :Profiler, 'merb-core/rack/middleware/profiler'
|
20
|
+
autoload :Tracer, 'merb-core/rack/middleware/tracer'
|
21
|
+
autoload :ContentLength, 'merb-core/rack/middleware/content_length'
|
22
|
+
autoload :ConditionalGet, 'merb-core/rack/middleware/conditional_get'
|
20
23
|
end # Rack
|
21
24
|
end # Merb
|
@@ -99,6 +99,7 @@ module Merb::Test::Rspec::RouteMatchers
|
|
99
99
|
def matches?(parameter_hash)
|
100
100
|
@actual = parameter_hash.dup.except(:controller, :action)
|
101
101
|
|
102
|
+
return @actual.empty? if @expected.empty?
|
102
103
|
@expected.all? {|(k, v)| @actual.has_key?(k) && @actual[k] == v}
|
103
104
|
end
|
104
105
|
|
@@ -1,4 +1,34 @@
|
|
1
1
|
module Merb::Test::Rspec::ViewMatchers
|
2
|
+
class HaveXpath
|
3
|
+
def initialize(expected)
|
4
|
+
@expected = expected
|
5
|
+
end
|
6
|
+
|
7
|
+
def matches?(stringlike)
|
8
|
+
@document = case stringlike
|
9
|
+
when LibXML::XML::Document, LibXML::XML::Node
|
10
|
+
stringlike
|
11
|
+
when StringIO
|
12
|
+
LibXML::XML::HTMLParser.string(stringlike.string).parse
|
13
|
+
else
|
14
|
+
LibXML::XML::HTMLParser.string(stringlike).parse
|
15
|
+
end
|
16
|
+
!@document.find(@expected).empty?
|
17
|
+
end
|
18
|
+
|
19
|
+
# ==== Returns
|
20
|
+
# String:: The failure message.
|
21
|
+
def failure_message
|
22
|
+
"expected following text to match xpath #{@expected}:\n#{@document}"
|
23
|
+
end
|
24
|
+
|
25
|
+
# ==== Returns
|
26
|
+
# String:: The failure message to be displayed in negative matches.
|
27
|
+
def negative_failure_message
|
28
|
+
"expected following text to not match xpath #{@expected}:\n#{@document}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
2
32
|
class HaveSelector
|
3
33
|
|
4
34
|
# ==== Parameters
|
@@ -302,6 +332,12 @@ module Merb::Test::Rspec::ViewMatchers
|
|
302
332
|
end
|
303
333
|
alias_method :match_selector, :have_selector
|
304
334
|
|
335
|
+
def have_xpath(expected)
|
336
|
+
require "libxml"
|
337
|
+
HaveXpath.new(expected)
|
338
|
+
end
|
339
|
+
alias_method :match_xpath, :have_xpath
|
340
|
+
|
305
341
|
# RSpec matcher to test for the presence of tags.
|
306
342
|
#
|
307
343
|
# ==== Parameters
|
@@ -9,7 +9,7 @@ require 'benchmark'
|
|
9
9
|
# spec_cmd<~to_s>:: The spec command. Defaults to "spec".
|
10
10
|
# run_opts<String>:: Options to pass to spec commands, for instance,
|
11
11
|
# if you want to use profiling formatter.
|
12
|
-
def run_specs(globs, spec_cmd='spec', run_opts = "-c
|
12
|
+
def run_specs(globs, spec_cmd='spec', run_opts = "-c")
|
13
13
|
require "optparse"
|
14
14
|
require "spec"
|
15
15
|
globs = globs.is_a?(Array) ? globs : [globs]
|
@@ -18,6 +18,7 @@ def run_specs(globs, spec_cmd='spec', run_opts = "-c -f s")
|
|
18
18
|
time = Benchmark.measure do
|
19
19
|
globs.each do |glob|
|
20
20
|
Dir[glob].each do |spec|
|
21
|
+
STDOUT.puts "\n\nRunning #{spec}...\n"
|
21
22
|
response = Open3.popen3("#{spec_cmd} #{File.expand_path(spec)} #{run_opts}") do |i,o,e|
|
22
23
|
while out = o.gets
|
23
24
|
STDOUT.puts out
|
data/lib/merb-core/version.rb
CHANGED