wycats-merb-core 0.9.8 → 0.9.9
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/CHANGELOG +136 -2
- data/CONTRIBUTORS +6 -0
- data/PUBLIC_CHANGELOG +15 -0
- data/Rakefile +12 -14
- data/lib/merb-core.rb +82 -43
- data/lib/merb-core/bootloader.rb +268 -60
- data/lib/merb-core/config.rb +119 -34
- data/lib/merb-core/controller/abstract_controller.rb +58 -18
- data/lib/merb-core/controller/exceptions.rb +2 -15
- data/lib/merb-core/controller/merb_controller.rb +28 -1
- data/lib/merb-core/controller/mime.rb +4 -0
- data/lib/merb-core/controller/mixins/controller.rb +14 -17
- data/lib/merb-core/controller/mixins/render.rb +23 -28
- data/lib/merb-core/controller/mixins/responder.rb +0 -1
- data/lib/merb-core/controller/template.rb +44 -20
- data/lib/merb-core/core_ext/kernel.rb +8 -3
- data/lib/merb-core/dispatch/default_exception/default_exception.rb +1 -1
- data/lib/merb-core/dispatch/default_exception/views/_css.html.erb +3 -1
- data/lib/merb-core/dispatch/default_exception/views/_javascript.html.erb +71 -67
- data/lib/merb-core/dispatch/default_exception/views/index.html.erb +6 -2
- data/lib/merb-core/dispatch/dispatcher.rb +5 -9
- data/lib/merb-core/dispatch/request.rb +46 -57
- data/lib/merb-core/dispatch/router.rb +83 -6
- data/lib/merb-core/dispatch/router/behavior.rb +87 -27
- data/lib/merb-core/dispatch/router/resources.rb +281 -167
- data/lib/merb-core/dispatch/router/route.rb +141 -27
- data/lib/merb-core/logger.rb +213 -202
- data/lib/merb-core/rack.rb +3 -1
- data/lib/merb-core/rack/adapter.rb +7 -4
- data/lib/merb-core/rack/adapter/ebb.rb +12 -13
- data/lib/merb-core/rack/adapter/evented_mongrel.rb +2 -15
- data/lib/merb-core/rack/adapter/irb.rb +3 -2
- data/lib/merb-core/rack/adapter/mongrel.rb +22 -15
- data/lib/merb-core/rack/adapter/swiftiplied_mongrel.rb +4 -16
- data/lib/merb-core/rack/adapter/thin.rb +21 -22
- data/lib/merb-core/rack/adapter/thin_turbo.rb +4 -11
- data/lib/merb-core/rack/adapter/webrick.rb +54 -18
- data/lib/merb-core/rack/handler/mongrel.rb +12 -13
- data/lib/merb-core/rack/middleware/csrf.rb +1 -1
- data/lib/merb-core/server.rb +135 -98
- data/lib/merb-core/tasks/gem_management.rb +50 -12
- data/lib/merb-core/tasks/merb.rb +1 -0
- data/lib/merb-core/tasks/merb_rake_helper.rb +9 -38
- data/lib/merb-core/tasks/stats.rake +2 -2
- data/lib/merb-core/test.rb +9 -3
- data/lib/merb-core/test/helpers.rb +1 -0
- data/lib/merb-core/test/helpers/multipart_request_helper.rb +3 -2
- data/lib/merb-core/test/helpers/request_helper.rb +40 -372
- data/lib/merb-core/test/helpers/route_helper.rb +15 -7
- data/lib/merb-core/test/matchers.rb +1 -0
- data/lib/merb-core/test/matchers/controller_matchers.rb +4 -247
- data/lib/merb-core/test/matchers/view_matchers.rb +22 -4
- data/lib/merb-core/test/run_specs.rb +117 -25
- data/lib/merb-core/version.rb +1 -1
- metadata +1 -1
- data/lib/merb-core/vendor/facets.rb +0 -2
- data/lib/merb-core/vendor/facets/dictionary.rb +0 -433
- data/lib/merb-core/vendor/facets/inflect.rb +0 -342
@@ -12,10 +12,9 @@ module Merb
|
|
12
12
|
|
13
13
|
attr_reader :conditions, :params, :segments
|
14
14
|
attr_reader :index, :variables, :name
|
15
|
-
attr_reader :redirect_status, :redirect_url
|
16
15
|
attr_accessor :fixation
|
17
16
|
|
18
|
-
def initialize(conditions, params, options = {}
|
17
|
+
def initialize(conditions, params, deferred_procs, options = {})
|
19
18
|
@conditions, @params = conditions, params
|
20
19
|
|
21
20
|
if options[:redirects]
|
@@ -25,10 +24,12 @@ module Merb
|
|
25
24
|
@defaults = {}
|
26
25
|
else
|
27
26
|
@defaults = options[:defaults] || {}
|
28
|
-
@conditional_block = conditional_block
|
29
27
|
end
|
28
|
+
|
29
|
+
# @conditional_block = conditional_block
|
30
30
|
|
31
31
|
@identifiers = options[:identifiers]
|
32
|
+
@deferred_procs = deferred_procs
|
32
33
|
@segments = []
|
33
34
|
@symbol_conditions = {}
|
34
35
|
@placeholders = {}
|
@@ -42,10 +43,6 @@ module Merb
|
|
42
43
|
def allow_fixation?
|
43
44
|
@fixation
|
44
45
|
end
|
45
|
-
|
46
|
-
def redirects?
|
47
|
-
@redirects
|
48
|
-
end
|
49
46
|
|
50
47
|
def to_s
|
51
48
|
regexp? ?
|
@@ -55,30 +52,75 @@ module Merb
|
|
55
52
|
|
56
53
|
alias_method :inspect, :to_s
|
57
54
|
|
55
|
+
# Appends self to Merb::Router.routes
|
58
56
|
def register
|
59
57
|
@index = Merb::Router.routes.size
|
60
58
|
Merb::Router.routes << self
|
61
59
|
self
|
62
60
|
end
|
63
61
|
|
62
|
+
# Inserts self to Merb::Router.routes at the specified index.
|
63
|
+
def register_at(index)
|
64
|
+
@index = index
|
65
|
+
Merb::Router.routes.insert(index, self)
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
# Sets the route as a resource route with the given key as the
|
70
|
+
# lookup key.
|
71
|
+
def resource=(key)
|
72
|
+
Router.resource_routes[key] = self
|
73
|
+
key
|
74
|
+
end
|
75
|
+
|
64
76
|
def name=(name)
|
65
77
|
@name = name.to_sym
|
66
78
|
Router.named_routes[@name] = self
|
67
79
|
@name
|
68
80
|
end
|
69
81
|
|
70
|
-
#
|
82
|
+
# Generates the URL for the route given the passed arguments. The
|
83
|
+
# method will first match the anonymous parameters to route params
|
84
|
+
# and will convert all the parameters according to the specifed
|
85
|
+
# object identifiers.
|
86
|
+
#
|
87
|
+
# Then the named parameters are passed to a compiled generation proc.
|
88
|
+
#
|
89
|
+
# ==== Parameters
|
90
|
+
# args<Array>::
|
91
|
+
# The arguments passed to the public #url method with the name
|
92
|
+
# of the route removed. This is an array of the anonymous parameters
|
93
|
+
# followed by a hash containing the named parameters.
|
94
|
+
#
|
95
|
+
# defaults<Hash>::
|
96
|
+
# A hash of parameters to use to generate the route if there are
|
97
|
+
# any missing required parameters. This is usually the parameters
|
98
|
+
# for the current request
|
99
|
+
#
|
100
|
+
# ==== Returns
|
101
|
+
# String:: The generated URL.
|
71
102
|
def generate(args = [], defaults = {})
|
72
103
|
raise GenerationError, "Cannot generate regexp Routes" if regexp?
|
73
104
|
|
74
105
|
params = extract_options_from_args!(args) || { }
|
75
106
|
|
107
|
+
params.each do |k, v|
|
108
|
+
params[k] = identify(v, k)
|
109
|
+
end
|
110
|
+
|
76
111
|
# Support for anonymous params
|
77
112
|
unless args.empty?
|
78
|
-
|
113
|
+
# First, let's determine which variables are missing
|
114
|
+
variables = @variables - params.keys
|
79
115
|
|
80
|
-
args.
|
81
|
-
|
116
|
+
args.each do |param|
|
117
|
+
raise GenerationError, "The route has #{@variables.length} variables: #{@variables.inspect}" if variables.empty?
|
118
|
+
|
119
|
+
if identifier = identifier_for(param) and identifier.is_a?(Array)
|
120
|
+
identifier.each { |ident| params[variables.shift] = param.send(ident) }
|
121
|
+
else
|
122
|
+
params[variables.shift] ||= identify(param)
|
123
|
+
end
|
82
124
|
end
|
83
125
|
end
|
84
126
|
|
@@ -86,13 +128,63 @@ module Merb
|
|
86
128
|
uri = Merb::Config[:path_prefix] + uri if Merb::Config[:path_prefix]
|
87
129
|
uri
|
88
130
|
end
|
131
|
+
|
132
|
+
# Identifies the object according to the identifiers set while building
|
133
|
+
# the routes. Identifying an object means picking an instance method to
|
134
|
+
# call on the object that will return a string representation of the
|
135
|
+
# object for the route being generated. If the identifier is an array,
|
136
|
+
# then a param_key must be present and match one of the elements of the
|
137
|
+
# identifier array.
|
138
|
+
#
|
139
|
+
# param_keys that end in _id are treated slightly differently in order
|
140
|
+
# to get nested resources to work correctly.
|
141
|
+
def identify(obj, param_key = nil)
|
142
|
+
identifier = identifier_for(obj)
|
143
|
+
if identifier.is_a?(Array)
|
144
|
+
# First check if the param_key exists as an identifier
|
145
|
+
return obj.send(param_key) if identifier.include?(param_key)
|
146
|
+
# If the param_key ends in _id, just return the object id
|
147
|
+
return obj.id if "#{param_key}" =~ /_id$/
|
148
|
+
# Otherwise, raise an error
|
149
|
+
raise GenerationError, "The object #{obj.inspect} cannot be identified with #{identifier.inspect} for #{param_key}"
|
150
|
+
else
|
151
|
+
identifier ? obj.send(identifier) : obj
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# Returns the identifier for the passed object. Built in core ruby classes are
|
156
|
+
# always identified with to_s. The method will return nil in that case (since
|
157
|
+
# to_s is the default for objects that do not have identifiers.)
|
158
|
+
def identifier_for(obj)
|
159
|
+
return if obj.is_a?(String) || obj.is_a?(Symbol) || obj.is_a?(Numeric) ||
|
160
|
+
obj.is_a?(TrueClass) || obj.is_a?(FalseClass) || obj.is_a?(NilClass) ||
|
161
|
+
obj.is_a?(Array) || obj.is_a?(Hash)
|
162
|
+
|
163
|
+
@identifiers.each do |klass, identifier|
|
164
|
+
return identifier if obj.is_a?(klass)
|
165
|
+
end
|
166
|
+
|
167
|
+
return nil
|
168
|
+
end
|
89
169
|
|
170
|
+
# Returns the if statement and return value for for the main
|
171
|
+
# Router.match compiled method.
|
90
172
|
def compiled_statement(first)
|
91
173
|
els_if = first ? ' if ' : ' elsif '
|
92
174
|
|
93
175
|
code = ""
|
94
176
|
code << els_if << condition_statements.join(" && ") << "\n"
|
95
|
-
|
177
|
+
|
178
|
+
# First, we need to always return the value of the
|
179
|
+
# deferred block if it explicitly matched the route
|
180
|
+
if @redirects && @deferred_procs.any?
|
181
|
+
code << " return [#{@index.inspect}, block_result] if request.matched?" << "\n"
|
182
|
+
code << " request.redirects!" << "\n"
|
183
|
+
code << " [#{@index.inspect}, { :url => #{@redirect_url.inspect}, :status => #{@redirect_status.inspect} }]" << "\n"
|
184
|
+
elsif @redirects
|
185
|
+
code << " request.redirects!" << "\n"
|
186
|
+
code << " [#{@index.inspect}, { :url => #{@redirect_url.inspect}, :status => #{@redirect_status.inspect} }]" << "\n"
|
187
|
+
elsif @deferred_procs.any?
|
96
188
|
code << " [#{@index.inspect}, block_result]" << "\n"
|
97
189
|
else
|
98
190
|
code << " [#{@index.inspect}, #{params_as_string}]" << "\n"
|
@@ -233,7 +325,7 @@ module Merb
|
|
233
325
|
segments.each_with_index do |segment, i|
|
234
326
|
bits << case
|
235
327
|
when segment.is_a?(String) then segment
|
236
|
-
when segment.is_a?(Symbol) then '#{
|
328
|
+
when segment.is_a?(Symbol) then '#{cached_' + segment.to_s + '}'
|
237
329
|
when segment.is_a?(Array) && segment.any? { |s| !s.is_a?(String) } then "\#{#{@opt_segment_stack.last.shift}}"
|
238
330
|
else ""
|
239
331
|
end
|
@@ -242,16 +334,6 @@ module Merb
|
|
242
334
|
bits
|
243
335
|
end
|
244
336
|
|
245
|
-
def param_for_route(param)
|
246
|
-
case param
|
247
|
-
when String, Symbol, Numeric, TrueClass, FalseClass, NilClass
|
248
|
-
param
|
249
|
-
else
|
250
|
-
_, identifier = @identifiers.find { |klass, _| param.is_a?(klass) }
|
251
|
-
identifier ? param.send(identifier) : param
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
337
|
end
|
256
338
|
|
257
339
|
# === Conditions ===
|
@@ -300,7 +382,11 @@ module Merb
|
|
300
382
|
end
|
301
383
|
end
|
302
384
|
|
303
|
-
|
385
|
+
unless regexp?
|
386
|
+
@variables = @segments.flatten.select { |s| s.is_a?(Symbol) }
|
387
|
+
compiled.gsub!(%r[/+], '/')
|
388
|
+
compiled.gsub!(%r[(.+)/$], '\1')
|
389
|
+
end
|
304
390
|
|
305
391
|
compiled
|
306
392
|
end
|
@@ -441,6 +527,7 @@ module Merb
|
|
441
527
|
def condition_statements
|
442
528
|
statements = []
|
443
529
|
|
530
|
+
# First, let's build the conditions for the regular
|
444
531
|
conditions.each_pair do |key, value|
|
445
532
|
statements << case value
|
446
533
|
when Regexp
|
@@ -460,13 +547,40 @@ module Merb
|
|
460
547
|
%{(cached_#{key} == #{value.inspect})}
|
461
548
|
end
|
462
549
|
end
|
463
|
-
|
464
|
-
|
465
|
-
|
550
|
+
|
551
|
+
# The first one is special, so let's extract it
|
552
|
+
if first = @deferred_procs.first
|
553
|
+
deferred = ""
|
554
|
+
deferred << "(block_result = "
|
555
|
+
deferred << "request._process_block_return("
|
556
|
+
deferred << "#{first}.call(request, #{params_as_string})"
|
557
|
+
deferred << ")"
|
558
|
+
deferred << ")"
|
559
|
+
|
560
|
+
# Let's build the rest of them now
|
561
|
+
if @deferred_procs.length > 1
|
562
|
+
deferred << deferred_condition_statement(@deferred_procs[1..-1])
|
563
|
+
end
|
564
|
+
|
565
|
+
statements << deferred
|
466
566
|
end
|
467
567
|
|
468
568
|
statements
|
469
569
|
end
|
570
|
+
|
571
|
+
# (request.matched? || ((block_result = process(proc.call))))
|
572
|
+
def deferred_condition_statement(deferred)
|
573
|
+
if current = deferred.first
|
574
|
+
html = " && (request.matched? || ("
|
575
|
+
html << "(block_result = "
|
576
|
+
html << "request._process_block_return("
|
577
|
+
html << "#{current}.call(request, block_result)"
|
578
|
+
html << ")"
|
579
|
+
html << ")"
|
580
|
+
html << "#{deferred_condition_statement(deferred[1..-1])}"
|
581
|
+
html << "))"
|
582
|
+
end
|
583
|
+
end
|
470
584
|
|
471
585
|
def params_as_string
|
472
586
|
elements = params.keys.map do |k|
|
data/lib/merb-core/logger.rb
CHANGED
@@ -1,203 +1,214 @@
|
|
1
|
-
Merb::Logger = Extlib::Logger
|
1
|
+
# Merb::Logger = Extlib::Logger
|
2
|
+
|
3
|
+
class Merb::Logger < Extlib::Logger
|
4
|
+
def verbose!(message, level = :warn)
|
5
|
+
send("#{level}!", message) if Merb::Config[:verbose]
|
6
|
+
end
|
7
|
+
|
8
|
+
def verbose(message, level = :warn)
|
9
|
+
send(level, message) if Merb::Config[:verbose]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
2
13
|
# require "time" # httpdate
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
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
|
-
|
203
|
-
|
14
|
+
# ==== Public Merb Logger API
|
15
|
+
#
|
16
|
+
# To replace an existing logger with a new one:
|
17
|
+
# Merb::Logger.set_log(log{String, IO},level{Symbol, String})
|
18
|
+
#
|
19
|
+
# Available logging levels are
|
20
|
+
# Merb::Logger::{ Fatal, Error, Warn, Info, Debug }
|
21
|
+
#
|
22
|
+
# Logging via:
|
23
|
+
# Merb.logger.fatal(message<String>,&block)
|
24
|
+
# Merb.logger.error(message<String>,&block)
|
25
|
+
# Merb.logger.warn(message<String>,&block)
|
26
|
+
# Merb.logger.info(message<String>,&block)
|
27
|
+
# Merb.logger.debug(message<String>,&block)
|
28
|
+
#
|
29
|
+
# Logging with autoflush:
|
30
|
+
# Merb.logger.fatal!(message<String>,&block)
|
31
|
+
# Merb.logger.error!(message<String>,&block)
|
32
|
+
# Merb.logger.warn!(message<String>,&block)
|
33
|
+
# Merb.logger.info!(message<String>,&block)
|
34
|
+
# Merb.logger.debug!(message<String>,&block)
|
35
|
+
#
|
36
|
+
# Flush the buffer to
|
37
|
+
# Merb.logger.flush
|
38
|
+
#
|
39
|
+
# Remove the current log object
|
40
|
+
# Merb.logger.close
|
41
|
+
#
|
42
|
+
# ==== Private Merb Logger API
|
43
|
+
#
|
44
|
+
# To initialize the logger you create a new object, proxies to set_log.
|
45
|
+
# Merb::Logger.new(log{String, IO},level{Symbol, String})
|
46
|
+
module Merb
|
47
|
+
|
48
|
+
class Logger
|
49
|
+
|
50
|
+
attr_accessor :level
|
51
|
+
attr_accessor :delimiter
|
52
|
+
attr_accessor :auto_flush
|
53
|
+
attr_reader :buffer
|
54
|
+
attr_reader :log
|
55
|
+
attr_reader :init_args
|
56
|
+
|
57
|
+
# ==== Notes
|
58
|
+
# Ruby (standard) logger levels:
|
59
|
+
# :fatal:: An unhandleable error that results in a program crash
|
60
|
+
# :error:: A handleable error condition
|
61
|
+
# :warn:: A warning
|
62
|
+
# :info:: generic (useful) information about system operation
|
63
|
+
# :debug:: low-level information for developers
|
64
|
+
Levels = Mash.new({
|
65
|
+
:fatal => 7,
|
66
|
+
:error => 6,
|
67
|
+
:warn => 4,
|
68
|
+
:info => 3,
|
69
|
+
:debug => 0
|
70
|
+
}) unless const_defined?(:Levels)
|
71
|
+
|
72
|
+
@@mutex = {}
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
# Readies a log for writing.
|
77
|
+
#
|
78
|
+
# ==== Parameters
|
79
|
+
# log<IO, String>:: Either an IO object or a name of a logfile.
|
80
|
+
def initialize_log(log)
|
81
|
+
close if @log # be sure that we don't leave open files laying around.
|
82
|
+
|
83
|
+
if log.respond_to?(:write)
|
84
|
+
@log = log
|
85
|
+
elsif File.exist?(log)
|
86
|
+
@log = open(log, (File::WRONLY | File::APPEND))
|
87
|
+
@log.sync = true
|
88
|
+
else
|
89
|
+
FileUtils.mkdir_p(File.dirname(log)) unless File.directory?(File.dirname(log))
|
90
|
+
@log = open(log, (File::WRONLY | File::APPEND | File::CREAT))
|
91
|
+
@log.sync = true
|
92
|
+
@log.write("#{Time.now.httpdate} #{delimiter} info #{delimiter} Logfile created\n")
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
public
|
97
|
+
|
98
|
+
# To initialize the logger you create a new object, proxies to set_log.
|
99
|
+
#
|
100
|
+
# ==== Parameters
|
101
|
+
# *args:: Arguments to create the log from. See set_logs for specifics.
|
102
|
+
def initialize(*args)
|
103
|
+
set_log(*args)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Replaces an existing logger with a new one.
|
107
|
+
#
|
108
|
+
# ==== Parameters
|
109
|
+
# log<IO, String>:: Either an IO object or a name of a logfile.
|
110
|
+
# log_level<~to_sym>::
|
111
|
+
# The log level from, e.g. :fatal or :info. Defaults to :error in the
|
112
|
+
# production environment and :debug otherwise.
|
113
|
+
# delimiter<String>::
|
114
|
+
# Delimiter to use between message sections. Defaults to " ~ ".
|
115
|
+
# auto_flush<Boolean>::
|
116
|
+
# Whether the log should automatically flush after new messages are
|
117
|
+
# added. Defaults to false.
|
118
|
+
def set_log(stream = Merb::Config[:log_stream],
|
119
|
+
log_level = Merb::Config[:log_level],
|
120
|
+
delimiter = Merb::Config[:log_delimiter],
|
121
|
+
auto_flush = Merb::Config[:log_auto_flush])
|
122
|
+
|
123
|
+
@buffer = []
|
124
|
+
@delimiter = delimiter
|
125
|
+
@auto_flush = auto_flush
|
126
|
+
|
127
|
+
if Levels[log_level]
|
128
|
+
@level = Levels[log_level]
|
129
|
+
else
|
130
|
+
@level = log_level
|
131
|
+
end
|
132
|
+
|
133
|
+
@log = stream
|
134
|
+
@mutex = (@@mutex[@log] ||= Mutex.new)
|
135
|
+
end
|
136
|
+
|
137
|
+
# Flush the entire buffer to the log object.
|
138
|
+
def flush
|
139
|
+
return unless @buffer.size > 0
|
140
|
+
@mutex.synchronize do
|
141
|
+
@log.write(@buffer.slice!(0..-1).to_s)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# Close and remove the current log object.
|
146
|
+
def close
|
147
|
+
flush
|
148
|
+
@log.close if @log.respond_to?(:close) && !@log.tty?
|
149
|
+
@log = nil
|
150
|
+
end
|
151
|
+
|
152
|
+
# Appends a message to the log. The methods yield to an optional block and
|
153
|
+
# the output of this block will be appended to the message.
|
154
|
+
#
|
155
|
+
# ==== Parameters
|
156
|
+
# string<String>:: The message to be logged. Defaults to nil.
|
157
|
+
#
|
158
|
+
# ==== Returns
|
159
|
+
# String:: The resulting message added to the log file.
|
160
|
+
def <<(string = nil)
|
161
|
+
message = ""
|
162
|
+
message << delimiter
|
163
|
+
message << string if string
|
164
|
+
message << "\n" unless message[-1] == ?\n
|
165
|
+
@buffer << message
|
166
|
+
flush if @auto_flush
|
167
|
+
|
168
|
+
message
|
169
|
+
end
|
170
|
+
alias :push :<<
|
171
|
+
|
172
|
+
# Generate the logging methods for Merb.logger for each log level.
|
173
|
+
Levels.each_pair do |name, number|
|
174
|
+
class_eval <<-LEVELMETHODS, __FILE__, __LINE__
|
175
|
+
|
176
|
+
# Appends a message to the log if the log level is at least as high as
|
177
|
+
# the log level of the logger.
|
178
|
+
#
|
179
|
+
# ==== Parameters
|
180
|
+
# string<String>:: The message to be logged. Defaults to nil.
|
181
|
+
#
|
182
|
+
# ==== Returns
|
183
|
+
# self:: The logger object for chaining.
|
184
|
+
def #{name}(message = nil)
|
185
|
+
self << message if #{number} >= level
|
186
|
+
self
|
187
|
+
end
|
188
|
+
|
189
|
+
# Appends a message to the log if the log level is at least as high as
|
190
|
+
# the log level of the logger. The bang! version of the method also auto
|
191
|
+
# flushes the log buffer to disk.
|
192
|
+
#
|
193
|
+
# ==== Parameters
|
194
|
+
# string<String>:: The message to be logged. Defaults to nil.
|
195
|
+
#
|
196
|
+
# ==== Returns
|
197
|
+
# self:: The logger object for chaining.
|
198
|
+
def #{name}!(message = nil)
|
199
|
+
self << message if #{number} >= level
|
200
|
+
flush if #{number} >= level
|
201
|
+
self
|
202
|
+
end
|
203
|
+
|
204
|
+
# ==== Returns
|
205
|
+
# Boolean:: True if this level will be logged by this logger.
|
206
|
+
def #{name}?
|
207
|
+
#{number} >= level
|
208
|
+
end
|
209
|
+
LEVELMETHODS
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|