innate 2009.04
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +2981 -0
- data/COPYING +18 -0
- data/MANIFEST +127 -0
- data/README.md +563 -0
- data/Rakefile +35 -0
- data/example/app/retro_games.rb +60 -0
- data/example/app/todo/layout/default.xhtml +11 -0
- data/example/app/todo/spec/todo.rb +63 -0
- data/example/app/todo/start.rb +51 -0
- data/example/app/todo/view/index.xhtml +39 -0
- data/example/app/whywiki_erb/layout/wiki.html.erb +15 -0
- data/example/app/whywiki_erb/spec/wiki.rb +19 -0
- data/example/app/whywiki_erb/start.rb +42 -0
- data/example/app/whywiki_erb/view/edit.erb +6 -0
- data/example/app/whywiki_erb/view/index.erb +12 -0
- data/example/custom_middleware.rb +35 -0
- data/example/hello.rb +11 -0
- data/example/howto_spec.rb +35 -0
- data/example/link.rb +27 -0
- data/example/provides.rb +31 -0
- data/example/session.rb +38 -0
- data/innate.gemspec +29 -0
- data/lib/innate.rb +269 -0
- data/lib/innate/action.rb +150 -0
- data/lib/innate/adapter.rb +76 -0
- data/lib/innate/cache.rb +134 -0
- data/lib/innate/cache/api.rb +128 -0
- data/lib/innate/cache/drb.rb +58 -0
- data/lib/innate/cache/file_based.rb +41 -0
- data/lib/innate/cache/marshal.rb +17 -0
- data/lib/innate/cache/memory.rb +22 -0
- data/lib/innate/cache/yaml.rb +17 -0
- data/lib/innate/current.rb +37 -0
- data/lib/innate/dynamap.rb +96 -0
- data/lib/innate/helper.rb +183 -0
- data/lib/innate/helper/aspect.rb +124 -0
- data/lib/innate/helper/cgi.rb +54 -0
- data/lib/innate/helper/flash.rb +36 -0
- data/lib/innate/helper/link.rb +94 -0
- data/lib/innate/helper/redirect.rb +85 -0
- data/lib/innate/helper/render.rb +87 -0
- data/lib/innate/helper/send_file.rb +26 -0
- data/lib/innate/log.rb +20 -0
- data/lib/innate/log/color_formatter.rb +43 -0
- data/lib/innate/log/hub.rb +73 -0
- data/lib/innate/middleware_compiler.rb +65 -0
- data/lib/innate/mock.rb +49 -0
- data/lib/innate/node.rb +1025 -0
- data/lib/innate/options.rb +37 -0
- data/lib/innate/options/dsl.rb +202 -0
- data/lib/innate/options/stub.rb +7 -0
- data/lib/innate/request.rb +141 -0
- data/lib/innate/response.rb +23 -0
- data/lib/innate/route.rb +110 -0
- data/lib/innate/session.rb +121 -0
- data/lib/innate/session/flash.rb +94 -0
- data/lib/innate/spec.rb +23 -0
- data/lib/innate/state.rb +27 -0
- data/lib/innate/state/accessor.rb +130 -0
- data/lib/innate/state/fiber.rb +74 -0
- data/lib/innate/state/thread.rb +47 -0
- data/lib/innate/traited.rb +85 -0
- data/lib/innate/trinity.rb +18 -0
- data/lib/innate/version.rb +3 -0
- data/lib/innate/view.rb +60 -0
- data/lib/innate/view/erb.rb +15 -0
- data/lib/innate/view/etanni.rb +36 -0
- data/lib/innate/view/none.rb +9 -0
- data/spec/example/app/retro_games.rb +30 -0
- data/spec/example/hello.rb +13 -0
- data/spec/example/link.rb +25 -0
- data/spec/example/provides.rb +16 -0
- data/spec/example/session.rb +22 -0
- data/spec/helper.rb +10 -0
- data/spec/innate/action/layout.rb +107 -0
- data/spec/innate/action/layout/file_layout.xhtml +1 -0
- data/spec/innate/cache/common.rb +47 -0
- data/spec/innate/cache/marshal.rb +5 -0
- data/spec/innate/cache/memory.rb +5 -0
- data/spec/innate/cache/yaml.rb +5 -0
- data/spec/innate/dynamap.rb +22 -0
- data/spec/innate/helper.rb +86 -0
- data/spec/innate/helper/aspect.rb +75 -0
- data/spec/innate/helper/cgi.rb +37 -0
- data/spec/innate/helper/flash.rb +118 -0
- data/spec/innate/helper/link.rb +139 -0
- data/spec/innate/helper/redirect.rb +160 -0
- data/spec/innate/helper/render.rb +133 -0
- data/spec/innate/helper/send_file.rb +21 -0
- data/spec/innate/helper/view/aspect_hello.xhtml +1 -0
- data/spec/innate/helper/view/locals.xhtml +1 -0
- data/spec/innate/helper/view/loop.xhtml +4 -0
- data/spec/innate/helper/view/num.xhtml +1 -0
- data/spec/innate/helper/view/partial.xhtml +1 -0
- data/spec/innate/helper/view/recursive.xhtml +7 -0
- data/spec/innate/mock.rb +84 -0
- data/spec/innate/node/mapping.rb +37 -0
- data/spec/innate/node/node.rb +134 -0
- data/spec/innate/node/resolve.rb +82 -0
- data/spec/innate/node/view/another_layout/another_layout.xhtml +3 -0
- data/spec/innate/node/view/bar.xhtml +1 -0
- data/spec/innate/node/view/foo.html.xhtml +1 -0
- data/spec/innate/node/view/only_view.xhtml +1 -0
- data/spec/innate/node/view/with_layout.xhtml +1 -0
- data/spec/innate/node/wrap_action_call.rb +83 -0
- data/spec/innate/options.rb +115 -0
- data/spec/innate/parameter.rb +154 -0
- data/spec/innate/provides.rb +99 -0
- data/spec/innate/provides/list.html.xhtml +1 -0
- data/spec/innate/provides/list.txt.xhtml +1 -0
- data/spec/innate/request.rb +77 -0
- data/spec/innate/route.rb +135 -0
- data/spec/innate/session.rb +54 -0
- data/spec/innate/state/fiber.rb +58 -0
- data/spec/innate/state/thread.rb +40 -0
- data/spec/innate/traited.rb +55 -0
- data/tasks/bacon.rake +66 -0
- data/tasks/changelog.rake +18 -0
- data/tasks/gem.rake +22 -0
- data/tasks/gem_installer.rake +76 -0
- data/tasks/grancher.rake +12 -0
- data/tasks/install_dependencies.rake +4 -0
- data/tasks/manifest.rake +4 -0
- data/tasks/rcov.rake +19 -0
- data/tasks/release.rake +51 -0
- data/tasks/reversion.rake +8 -0
- data/tasks/setup.rake +28 -0
- metadata +181 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
autoload(:CGI, 'cgi') # in case you want to use html_unescape
|
2
|
+
|
3
|
+
module Innate
|
4
|
+
|
5
|
+
# Shortcuts to some CGI methods
|
6
|
+
|
7
|
+
module Helper
|
8
|
+
module CGI
|
9
|
+
module_function
|
10
|
+
|
11
|
+
# Shortcut for Rack::Utils.escape
|
12
|
+
#
|
13
|
+
# @param [#to_s] input
|
14
|
+
# @return [String] URI-encoded representation of +input+
|
15
|
+
def url_encode(input)
|
16
|
+
Rack::Utils.escape(input.to_s)
|
17
|
+
end
|
18
|
+
alias u url_encode
|
19
|
+
|
20
|
+
# Shortcut for Rack::Utils.unescape
|
21
|
+
#
|
22
|
+
# @param [#to_s] input
|
23
|
+
# @return [String] URI-decoded representation of +input+
|
24
|
+
def url_decode(input)
|
25
|
+
Rack::Utils.unescape(input.to_s)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Shortcut for Rack::Utils.escape_html
|
29
|
+
#
|
30
|
+
# @param [#to_s] input
|
31
|
+
# @return [String]
|
32
|
+
def html_escape(input)
|
33
|
+
Rack::Utils.escape_html(input.to_s)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Shortcut for CGI.unescapeHTML
|
37
|
+
#
|
38
|
+
# @param [#to_s] input
|
39
|
+
# @return [String]
|
40
|
+
def html_unescape(input)
|
41
|
+
::CGI.unescapeHTML(input.to_s)
|
42
|
+
end
|
43
|
+
|
44
|
+
# safely escape all HTML and code
|
45
|
+
def html_and_code_escape(input)
|
46
|
+
Rack::Utils.escape_html(input.to_s).gsub(/#([{@$]@?)/, '#\1')
|
47
|
+
end
|
48
|
+
alias h html_and_code_escape
|
49
|
+
|
50
|
+
# aliases are ignored by module_function...
|
51
|
+
module_function :u, :h
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Innate
|
2
|
+
module Helper
|
3
|
+
# Simple access to session.flash.
|
4
|
+
#
|
5
|
+
# Flash is a mechanism using sessions to provide a rotating holder of
|
6
|
+
# key/value pairs.
|
7
|
+
#
|
8
|
+
# Every request that is made will rotate one step, dropping contents stored
|
9
|
+
# two requests ago.
|
10
|
+
#
|
11
|
+
# The purpose of this class is to provide an easy way of setting/retrieving
|
12
|
+
# from the current flash.
|
13
|
+
#
|
14
|
+
# Flash is a way to keep a temporary pairs of keys and values for the duration
|
15
|
+
# of two requests, the current and following.
|
16
|
+
#
|
17
|
+
# Very vague Example:
|
18
|
+
#
|
19
|
+
# On the first request, for example on registering:
|
20
|
+
#
|
21
|
+
# flash[:error] = "You should reconsider your username, it's taken already"
|
22
|
+
# redirect R(self, :register)
|
23
|
+
#
|
24
|
+
# This is the request from the redirect:
|
25
|
+
#
|
26
|
+
# do_stuff if flash[:error]
|
27
|
+
#
|
28
|
+
# On the request after this, flash[:error] is gone.
|
29
|
+
module Flash
|
30
|
+
# Just for convenience
|
31
|
+
def flash
|
32
|
+
session.flash
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Innate
|
2
|
+
module Helper
|
3
|
+
module Link
|
4
|
+
def self.included(into)
|
5
|
+
into.extend(self)
|
6
|
+
end
|
7
|
+
|
8
|
+
# Provide the path to given Node and actions.
|
9
|
+
# Escapes GET parameters.
|
10
|
+
#
|
11
|
+
# Usage, mapping is Pages => '/', Users => '/users':
|
12
|
+
#
|
13
|
+
# Pages.r # => URI('/')
|
14
|
+
# Pages.r(:foo) # => URI('/foo')
|
15
|
+
# Pages.r(:foo, :bar) # => URI('/foo/bar')
|
16
|
+
# Pages.r(:foo, :a => :b) # => URI('/foo?a=b')
|
17
|
+
# Pages.r(:foo, :bar, :a => :b) # => URI('/foo/bar?a=b')
|
18
|
+
#
|
19
|
+
# Users.r # => URI('/users/')
|
20
|
+
# Users.r(:foo) # => URI('/users/foo')
|
21
|
+
# Users.r(:foo, :bar) # => URI('/users/foo/bar')
|
22
|
+
# Users.r(:foo, :a => :b) # => URI('/users/foo?a=b')
|
23
|
+
# Users.r(:foo, :bar, :a => :b) # => URI('/users/foo/bar?a=b')
|
24
|
+
#
|
25
|
+
# @return [URI] to the location
|
26
|
+
def route(name = '/', *args)
|
27
|
+
hash = {}
|
28
|
+
hashes, names = args.partition{|arg| arg.respond_to?(:merge!) }
|
29
|
+
hashes.each{|to_merge| hash.merge!(to_merge) }
|
30
|
+
|
31
|
+
escape = Rack::Utils.method(:escape)
|
32
|
+
location = route_location(self)
|
33
|
+
front = Array[location, name, *names.map{|n| escape[n]}].join('/').squeeze('/')
|
34
|
+
|
35
|
+
return URI(front) if hash.empty?
|
36
|
+
|
37
|
+
query = hash.map{|k, v| "#{escape[k]}=#{escape[v]}" }.join(';')
|
38
|
+
URI("#{front}?#{query}")
|
39
|
+
end
|
40
|
+
alias r route
|
41
|
+
|
42
|
+
def route_location(klass)
|
43
|
+
prefix = Innate.options.prefix
|
44
|
+
location = Innate.to(klass) || Innate.to(klass.class)
|
45
|
+
[prefix, location].join('/')
|
46
|
+
end
|
47
|
+
|
48
|
+
# Create a route to the currently active Node.
|
49
|
+
#
|
50
|
+
# This method is mostly here in case you include this helper elsewhere
|
51
|
+
# and don't want (or can't) type SomeNode.r all the time.
|
52
|
+
#
|
53
|
+
# The usage is identical with {route}.
|
54
|
+
#
|
55
|
+
# @param [#to_s] name
|
56
|
+
# @return [URI] to the location
|
57
|
+
# @see Ramaze::Helper::Link#route
|
58
|
+
# @author manveru
|
59
|
+
def route_self(name = '/', *args)
|
60
|
+
Current.action.node.route(name, *args)
|
61
|
+
end
|
62
|
+
alias rs route_self
|
63
|
+
|
64
|
+
# Create a link tag
|
65
|
+
#
|
66
|
+
# Usage, given Wiki is mapped to `/wiki`:
|
67
|
+
#
|
68
|
+
# Wiki.a(:home) # => '<a href="/wiki/home">home</a>'
|
69
|
+
# Wiki.a('home', :home) # => '<a href="/wiki/home">home</a>'
|
70
|
+
# Wiki.a('home', :/) # => '<a href="/wiki/">home</a>'
|
71
|
+
# Wiki.a('foo', :/, :foo => :bar) # => '<a href="/wiki/?foo=bar">foo</a>'
|
72
|
+
# Wiki.a('example', 'http://example.com')
|
73
|
+
# # => '<a href="http://example.com">example</a>'
|
74
|
+
#
|
75
|
+
# @return [String]
|
76
|
+
def anchor(text, *args)
|
77
|
+
case first = (args.first || text)
|
78
|
+
when URI
|
79
|
+
href = first.to_s
|
80
|
+
when /^\w+:\/\//
|
81
|
+
uri = URI(first)
|
82
|
+
uri.query = Rack::Utils.escape_html(uri.query)
|
83
|
+
href = uri.to_s
|
84
|
+
else
|
85
|
+
href = args.empty? ? r(text) : r(*args)
|
86
|
+
end
|
87
|
+
|
88
|
+
text = Rack::Utils.escape_html(text)
|
89
|
+
%(<a href="#{href}">#{text}</a>)
|
90
|
+
end
|
91
|
+
alias a anchor
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Innate
|
2
|
+
module Helper
|
3
|
+
module Redirect
|
4
|
+
def respond(body, status = 200, header = {})
|
5
|
+
response.write body
|
6
|
+
response.status = status
|
7
|
+
header['Content-Type'] ||= 'text/html'
|
8
|
+
header.each{|k,v| response[k] = v }
|
9
|
+
|
10
|
+
throw(:respond, response)
|
11
|
+
end
|
12
|
+
|
13
|
+
def respond!(body, status = 200, header = {})
|
14
|
+
header['Content-Type'] ||= 'text/html'
|
15
|
+
throw(:respond, Response.new(body, status, header))
|
16
|
+
end
|
17
|
+
|
18
|
+
# +target+ should be anything responding to #to_s.
|
19
|
+
# To check or modify the URI the redirect will go to you may pass a
|
20
|
+
# block, the result value of the block is ignored:
|
21
|
+
#
|
22
|
+
# redirect("/"){|uri| uri.scheme = 'http' }
|
23
|
+
# redirect("/"){|uri| uri.host = 'secure.com' if uri.scheme =~ /s/ }
|
24
|
+
#
|
25
|
+
# +options+ may contain:
|
26
|
+
#
|
27
|
+
# :scheme => "http" | "https" | "ftp" | ...
|
28
|
+
# :host => "localhost" | "foo.com" | "123.123.123.123" | ...
|
29
|
+
# :port => 7000 | "80" | 80 | ...
|
30
|
+
#
|
31
|
+
# :status => 302 | 300 | 303 | ...
|
32
|
+
# :body => "This is a redirect, hold on while we teleport" | ...
|
33
|
+
#
|
34
|
+
# :raw! => true | false | nil | ...
|
35
|
+
#
|
36
|
+
# Note that all options are optional and you may just pass a +target+.
|
37
|
+
|
38
|
+
def redirect(target, options = {})
|
39
|
+
target = target.to_s
|
40
|
+
|
41
|
+
case target
|
42
|
+
when /^http/, /^\//
|
43
|
+
uri = URI(target)
|
44
|
+
else
|
45
|
+
uri = URI("/#{target}")
|
46
|
+
end
|
47
|
+
|
48
|
+
uri.scheme ||= options[:scheme] || request.scheme
|
49
|
+
uri.host ||= options[:host] || request.host
|
50
|
+
uri.port ||= options[:port] || request.port
|
51
|
+
|
52
|
+
uri = URI(uri.to_s)
|
53
|
+
|
54
|
+
yield(uri) if block_given?
|
55
|
+
|
56
|
+
raw_redirect(uri, options)
|
57
|
+
end
|
58
|
+
|
59
|
+
def raw_redirect(target, options = {}, &block)
|
60
|
+
header = response.header.merge('Location' => target.to_s)
|
61
|
+
status = options[:status] || 302
|
62
|
+
body = options[:body] || redirect_body(target)
|
63
|
+
|
64
|
+
Log.debug "Redirect to: #{target}"
|
65
|
+
throw(:redirect, Response.new(body, status, header, &block))
|
66
|
+
end
|
67
|
+
|
68
|
+
def redirect_body(target)
|
69
|
+
"You are being redirected, please follow this link to: " +
|
70
|
+
"<a href='#{target}'>#{h target}</a>!"
|
71
|
+
end
|
72
|
+
|
73
|
+
def redirect_referrer(fallback = '/')
|
74
|
+
if referer = request.referer and url = request.url
|
75
|
+
referer_uri, request_uri = URI(referer), URI(url)
|
76
|
+
|
77
|
+
redirect(referer) unless referer_uri == request_uri
|
78
|
+
end
|
79
|
+
|
80
|
+
redirect(fallback)
|
81
|
+
end
|
82
|
+
alias redirect_referer redirect_referrer
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Innate
|
2
|
+
module Helper
|
3
|
+
module Render
|
4
|
+
# Enables you to simply call:
|
5
|
+
#
|
6
|
+
# @example of added functionality
|
7
|
+
# YourController.render_partial(:foo, :x => 42)
|
8
|
+
#
|
9
|
+
def self.included(into)
|
10
|
+
into.extend(self)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Renders the full action in the way a real request would.
|
14
|
+
#
|
15
|
+
# Please be aware that, if this is the first request from a client, you
|
16
|
+
# will not have access to the session in the action being rendered, as no
|
17
|
+
# actual session has been put into place yet.
|
18
|
+
#
|
19
|
+
# It should work as expected on any subsequent requests.
|
20
|
+
#
|
21
|
+
# As usual, patches welcome.
|
22
|
+
#
|
23
|
+
# @api external
|
24
|
+
# @see Mock.session
|
25
|
+
# @author manveru
|
26
|
+
def render_full(path, query = {})
|
27
|
+
uri = URI(path.to_s)
|
28
|
+
uri.query = Rack::Utils.build_query(query)
|
29
|
+
|
30
|
+
if cookie = request.env['HTTP_COOKIE']
|
31
|
+
Mock.session do |mock|
|
32
|
+
mock.cookie = cookie
|
33
|
+
return mock.get(uri.to_s).body
|
34
|
+
end
|
35
|
+
else
|
36
|
+
Mock.get(uri.to_s).body
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Renders an action without any layout.
|
41
|
+
# You can further tweak the action to be rendered by passing a block.
|
42
|
+
#
|
43
|
+
# @api external
|
44
|
+
# @see render_custom
|
45
|
+
# @author manveru
|
46
|
+
def render_partial(action_name, variables = {})
|
47
|
+
render_custom(action_name, variables) do |action|
|
48
|
+
action.layout = nil
|
49
|
+
yield(action) if block_given?
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Renders an action view, doesn't execute any methods and won't wrap it
|
54
|
+
# into a layout.
|
55
|
+
# You can further tweak the action to be rendered by passing a block.
|
56
|
+
#
|
57
|
+
# @api external
|
58
|
+
# @see render_custom
|
59
|
+
# @author manveru
|
60
|
+
def render_view(action_name, variables = {})
|
61
|
+
render_custom(action_name, variables) do |action|
|
62
|
+
action.layout = nil
|
63
|
+
action.method = nil
|
64
|
+
yield(action) if block_given?
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def render_custom(action_name, variables = {})
|
69
|
+
unless action = resolve(action_name.to_s)
|
70
|
+
raise(ArgumentError, "No Action %p on #{self}" % action_name)
|
71
|
+
end
|
72
|
+
|
73
|
+
action.sync_variables(self.action)
|
74
|
+
action.instance = action.node.new
|
75
|
+
action.variables = action.variables.merge(variables)
|
76
|
+
|
77
|
+
yield(action) if block_given?
|
78
|
+
|
79
|
+
if action.valid?
|
80
|
+
action.render
|
81
|
+
else
|
82
|
+
Log.warn("Invalid action: %p" % action)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Innate
|
2
|
+
module Helper
|
3
|
+
module SendFile
|
4
|
+
# Not optimally performing but convenient way to send files by their
|
5
|
+
# filename.
|
6
|
+
#
|
7
|
+
# I think we should remove this from the default helpers and move it into
|
8
|
+
# Ramaze, the functionality is almost never used, the naming is ambigous,
|
9
|
+
# and it doesn't use the send_file capabilities of frontend servers.
|
10
|
+
#
|
11
|
+
# So for now, I'll mark it for deprecation
|
12
|
+
def send_file(filename, content_type = nil, content_disposition = nil)
|
13
|
+
content_type ||= Rack::Mime.mime_type(::File.extname(filename))
|
14
|
+
content_disposition ||= File.basename(filename)
|
15
|
+
|
16
|
+
response.body = ::File.readlines(filename, 'rb')
|
17
|
+
response['Content-Length'] = ::File.size(filename).to_s
|
18
|
+
response['Content-Type'] = content_type
|
19
|
+
response['Content-Disposition'] = content_disposition
|
20
|
+
response.status = 200
|
21
|
+
|
22
|
+
throw(:respond, response)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/innate/log.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'innate/log/hub'
|
2
|
+
require 'innate/log/color_formatter'
|
3
|
+
|
4
|
+
module Innate
|
5
|
+
logdev = $stderr
|
6
|
+
logger = Logger.new(logdev)
|
7
|
+
|
8
|
+
if Logger::ColorFormatter.color?(logdev)
|
9
|
+
begin
|
10
|
+
require 'win32console' if RUBY_PLATFORM =~ /win32/i
|
11
|
+
|
12
|
+
logger.formatter = Logger::ColorFormatter.new
|
13
|
+
|
14
|
+
rescue LoadError
|
15
|
+
logger.debug "For colors on windows, please `gem install win32console`"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
Log = LogHub.new(logger)
|
20
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class Logger
|
2
|
+
# Extended Formatter that supports ANSI colors.
|
3
|
+
class ColorFormatter < Formatter
|
4
|
+
LEVEL_COLOR = {
|
5
|
+
'DEBUG' => :blue,
|
6
|
+
'INFO' => :white,
|
7
|
+
'WARN' => :yellow,
|
8
|
+
'ERROR' => :red,
|
9
|
+
'FATAL' => :red,
|
10
|
+
'UNKNOWN' => :green,
|
11
|
+
}
|
12
|
+
|
13
|
+
COLOR_CODE = {
|
14
|
+
:reset => 0, :bold => 1, :dark => 2, :underline => 4, :blink => 5,
|
15
|
+
:negative => 7, :black => 30, :red => 31, :green => 32, :yellow => 33,
|
16
|
+
:blue => 34, :magenta => 35, :cyan => 36, :white => 37,
|
17
|
+
}
|
18
|
+
|
19
|
+
FORMAT_TIME = "%Y-%m-%d %H:%M:%S"
|
20
|
+
FORMAT_LINE = "%s [%s $%d] %5s | %s: %s\n"
|
21
|
+
|
22
|
+
def call(severity, time, program, message)
|
23
|
+
hint = severity[0,1]
|
24
|
+
time = format_time(time)
|
25
|
+
pid = $$
|
26
|
+
string = colorize(msg2str(message), severity)
|
27
|
+
|
28
|
+
FORMAT_LINE % [hint, time, pid, severity, program, string]
|
29
|
+
end
|
30
|
+
|
31
|
+
def format_time(time)
|
32
|
+
time.strftime(FORMAT_TIME)
|
33
|
+
end
|
34
|
+
|
35
|
+
def colorize(string, severity)
|
36
|
+
"\e[#{COLOR_CODE[LEVEL_COLOR[severity]]}m#{string}\e[0m"
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.color?(logdev)
|
40
|
+
logdev.respond_to?(:tty?) and logdev.tty?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|