strelka 0.0.1.pre148 → 0.0.1.pre177
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 +1294 -0
- data/IDEAS.rdoc +6 -0
- data/Manifest.txt +20 -0
- data/README.rdoc +8 -2
- data/Rakefile +9 -7
- data/examples/auth-demo.rb +32 -0
- data/examples/auth-demo2.rb +37 -0
- data/examples/auth-form.tmpl +10 -0
- data/examples/auth-success.tmpl +3 -0
- data/examples/config.yml +12 -0
- data/examples/examples.css +4 -0
- data/examples/examples.html +31 -0
- data/examples/gen-config.rb +5 -2
- data/examples/layout.tmpl +31 -0
- data/lib/strelka/app/auth.rb +480 -0
- data/lib/strelka/app/sessions.rb +8 -6
- data/lib/strelka/app/templating.rb +78 -17
- data/lib/strelka/app.rb +13 -5
- data/lib/strelka/authprovider/basic.rb +134 -0
- data/lib/strelka/authprovider/hostaccess.rb +91 -0
- data/lib/strelka/authprovider.rb +122 -0
- data/lib/strelka/cookie.rb +1 -1
- data/lib/strelka/cookieset.rb +1 -1
- data/lib/strelka/httprequest/auth.rb +31 -0
- data/lib/strelka/logging.rb +69 -14
- data/lib/strelka/mixins.rb +35 -65
- data/lib/strelka/session/db.rb +115 -0
- data/lib/strelka/session/default.rb +38 -49
- data/lib/strelka/session.rb +1 -1
- data/lib/strelka.rb +4 -1
- data/spec/lib/helpers.rb +8 -3
- data/spec/strelka/app/auth_spec.rb +367 -0
- data/spec/strelka/authprovider/basic_spec.rb +192 -0
- data/spec/strelka/authprovider/hostaccess_spec.rb +70 -0
- data/spec/strelka/authprovider_spec.rb +99 -0
- data/spec/strelka/cookie_spec.rb +1 -1
- data/spec/strelka/httprequest/auth_spec.rb +55 -0
- data/spec/strelka/httprequest/session_spec.rb +63 -3
- data/spec/strelka/session/db_spec.rb +85 -0
- data/spec/strelka/session/default_spec.rb +5 -51
- data.tar.gz.sig +0 -0
- metadata +88 -57
- metadata.gz.sig +0 -0
@@ -0,0 +1,134 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
|
4
|
+
require 'configurability'
|
5
|
+
|
6
|
+
require 'strelka' unless defined?( Strelka )
|
7
|
+
require 'strelka/app' unless defined?( Strelka::App )
|
8
|
+
require 'strelka/authprovider'
|
9
|
+
require 'strelka/mixins'
|
10
|
+
|
11
|
+
# HTTP Basic AuthProvider class -- a base class for RFC2617 Basic HTTP Authentication
|
12
|
+
# providers for {the Streka :auth plugin}[rdoc-ref:Strelka::App::Auth].
|
13
|
+
#
|
14
|
+
# == Configuration
|
15
|
+
#
|
16
|
+
# The configuration for this provider is read from the 'auth' section of the config, and
|
17
|
+
# may contain the following keys:
|
18
|
+
#
|
19
|
+
# [realm]:: the HTTP Basic realm. Defaults to the app's application ID
|
20
|
+
# [users]:: a Hash of username: SHA1+Base64'ed passwords
|
21
|
+
#
|
22
|
+
# An example:
|
23
|
+
#
|
24
|
+
# --
|
25
|
+
# auth:
|
26
|
+
# realm: Acme Admin Console
|
27
|
+
# users:
|
28
|
+
# mgranger: "9d5lIumnMJXmVT/34QrMuyj+p0E="
|
29
|
+
# jblack: "1pAnQNSVtpL1z88QwXV4sG8NMP8="
|
30
|
+
# kmurgen: "MZj9+VhZ8C9+aJhmwp+kWBL76Vs="
|
31
|
+
#
|
32
|
+
class Strelka::AuthProvider::Basic < Strelka::AuthProvider
|
33
|
+
extend Configurability,
|
34
|
+
Strelka::MethodUtilities
|
35
|
+
include Strelka::Constants,
|
36
|
+
Strelka::Loggable
|
37
|
+
|
38
|
+
# Configurability API - set the section of the config
|
39
|
+
config_key :auth
|
40
|
+
|
41
|
+
|
42
|
+
@users = nil
|
43
|
+
@realm = nil
|
44
|
+
|
45
|
+
##
|
46
|
+
# The Hash of users and their SHA1+Base64'ed passwords
|
47
|
+
singleton_attr_accessor :users
|
48
|
+
|
49
|
+
##
|
50
|
+
# The authentication realm
|
51
|
+
singleton_attr_accessor :realm
|
52
|
+
|
53
|
+
|
54
|
+
### Configurability API -- configure the auth provider instance.
|
55
|
+
def self::configure( config=nil )
|
56
|
+
if config
|
57
|
+
Strelka.log.debug "Configuring Basic authprovider: %p" % [ config ]
|
58
|
+
self.realm = config['realm'] if config['realm']
|
59
|
+
self.users = config['users'] if config['users']
|
60
|
+
else
|
61
|
+
self.realm = nil
|
62
|
+
self.users = {}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
#################################################################
|
68
|
+
### I N S T A N C E M E T H O D S
|
69
|
+
#################################################################
|
70
|
+
|
71
|
+
### Create a new Default AuthProvider.
|
72
|
+
def initialize( * )
|
73
|
+
super
|
74
|
+
|
75
|
+
# Default the authentication realm to the application's ID
|
76
|
+
unless self.class.realm
|
77
|
+
self.log.warn "No realm configured -- using the app id"
|
78
|
+
self.class.realm = self.app.conn.app_id
|
79
|
+
end
|
80
|
+
|
81
|
+
unless self.class.users
|
82
|
+
self.log.warn "No users configured -- using an empty user list"
|
83
|
+
self.class.users = {}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
######
|
89
|
+
public
|
90
|
+
######
|
91
|
+
|
92
|
+
# Check the authentication present in +request+ (if any) for validity, returning the
|
93
|
+
# authenticating user's name if authentication succeeds.
|
94
|
+
def authenticate( request )
|
95
|
+
authheader = request.header.authorization or
|
96
|
+
self.log_failure "No authorization header in the request."
|
97
|
+
|
98
|
+
# Extract the credentials bit
|
99
|
+
base64_userpass = authheader[ /^\s*Basic\s+(\S+)$/i, 1 ] or
|
100
|
+
self.log_failure "Invalid Basic Authorization header (%p)" % [ authheader ]
|
101
|
+
|
102
|
+
# Unpack the username and password
|
103
|
+
credentials = base64_userpass.unpack( 'm' ).first
|
104
|
+
self.log_failure "Malformed credentials %p" % [ credentials ] unless
|
105
|
+
credentials.index(':')
|
106
|
+
|
107
|
+
# Split the credentials, check for valid user
|
108
|
+
username, password = credentials.split( ':', 2 )
|
109
|
+
digest = self.class.users[ username ] or
|
110
|
+
self.log_failure "No such user %p." % [ username ]
|
111
|
+
|
112
|
+
# Fail if the password's hash doesn't match
|
113
|
+
self.log_failure "Password mismatch." unless
|
114
|
+
digest == Digest::SHA1.base64digest( password )
|
115
|
+
|
116
|
+
# Success!
|
117
|
+
self.log.info "Authentication for %p succeeded." % [ username ]
|
118
|
+
return username
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
#########
|
123
|
+
protected
|
124
|
+
#########
|
125
|
+
|
126
|
+
### Syntax sugar to allow returning 'false' while logging a reason for doing so.
|
127
|
+
### Log a message at 'info' level and return false.
|
128
|
+
def log_failure( reason )
|
129
|
+
self.log.warn "Auth failure: %s" % [ reason ]
|
130
|
+
header = "Basic realm=%s" % [ self.class.realm ]
|
131
|
+
finish_with( HTTP::AUTH_REQUIRED, "Requires authentication.", www_authenticate: header )
|
132
|
+
end
|
133
|
+
|
134
|
+
end # class Strelka::AuthProvider::Basic
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
|
4
|
+
require 'ipaddr'
|
5
|
+
require 'configurability'
|
6
|
+
|
7
|
+
require 'strelka' unless defined?( Strelka )
|
8
|
+
require 'strelka/app' unless defined?( Strelka::App )
|
9
|
+
require 'strelka/authprovider'
|
10
|
+
require 'strelka/mixins'
|
11
|
+
|
12
|
+
# HostAccess AuthProvider class -- restricts access to requests coming from a list of
|
13
|
+
# netblocks.
|
14
|
+
#
|
15
|
+
# You can configure which ones from the +auth+ section of the config:
|
16
|
+
#
|
17
|
+
# auth:
|
18
|
+
# allowed_netblocks:
|
19
|
+
# - 127.0.0.0/8
|
20
|
+
# - 10.5.3.0/22
|
21
|
+
class Strelka::AuthProvider::HostAccess < Strelka::AuthProvider
|
22
|
+
include Configurability,
|
23
|
+
Strelka::Constants,
|
24
|
+
Strelka::Loggable,
|
25
|
+
Strelka::MethodUtilities
|
26
|
+
|
27
|
+
|
28
|
+
# The default list of netblocks to allow
|
29
|
+
DEFAULT_ALLOWED_NETBLOCKS = %w[127.0.0.0/8]
|
30
|
+
|
31
|
+
|
32
|
+
#################################################################
|
33
|
+
### I N S T A N C E M E T H O D S
|
34
|
+
#################################################################
|
35
|
+
|
36
|
+
### Create a new Default AuthProvider.
|
37
|
+
def initialize( * )
|
38
|
+
super
|
39
|
+
|
40
|
+
self.allowed_netblocks = DEFAULT_ALLOWED_NETBLOCKS
|
41
|
+
|
42
|
+
# Register this instance with Configurability
|
43
|
+
config_key :auth
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
######
|
48
|
+
public
|
49
|
+
######
|
50
|
+
|
51
|
+
# An Array of IPAddr objects that represent the netblocks that will be allowed
|
52
|
+
# access to the protected resources
|
53
|
+
attr_reader :allowed_netblocks
|
54
|
+
|
55
|
+
|
56
|
+
### Set the list of allowed netblocks to +newblocks+.
|
57
|
+
def allowed_netblocks=( newblocks )
|
58
|
+
@allowed_netblocks = Array( newblocks ).map {|addr| IPAddr.new(addr) }
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
### Configurability API -- configure the auth provider instance.
|
63
|
+
def configure( config=nil )
|
64
|
+
self.log.debug "Configuring %p with config: %p" % [ self, config ]
|
65
|
+
if config && config['allowed_netblocks']
|
66
|
+
self.allowed_netblocks = config['allowed_netblocks']
|
67
|
+
else
|
68
|
+
self.allowed_netblocks = DEFAULT_ALLOWED_NETBLOCKS
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
### Check authorization for the specified +request+ by testing its the IP in its
|
74
|
+
### X-forwarded-for header against the allowed_netblocks.
|
75
|
+
def authorize( _, request )
|
76
|
+
client_ip = request.header.x_forwarded_for or
|
77
|
+
raise "No X-Forwarded-For header?!"
|
78
|
+
addr = IPAddr.new( client_ip )
|
79
|
+
|
80
|
+
return true if self.in_allowed_netblocks?( addr )
|
81
|
+
|
82
|
+
return false
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
### Returns +true+ if the given +ipaddr+ is in the #allowed_netblocks.
|
87
|
+
def in_allowed_netblocks?( ipaddr )
|
88
|
+
return self.allowed_netblocks.any? {|nb| nb.include?(ipaddr) }
|
89
|
+
end
|
90
|
+
|
91
|
+
end # class Strelka::AuthProvider::HostAccess
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# vim: set nosta noet ts=4 sw=4:
|
3
|
+
# encoding: utf-8
|
4
|
+
|
5
|
+
require 'pluginfactory'
|
6
|
+
|
7
|
+
require 'strelka' unless defined?( Strelka )
|
8
|
+
require 'strelka/mixins'
|
9
|
+
|
10
|
+
|
11
|
+
# This is the abstract base class for authentication and/or authorization providers
|
12
|
+
# for the {:auth plugin}[Strelka::App::Auth].
|
13
|
+
#
|
14
|
+
# To define your own session type, you'll need to inherit this class (either
|
15
|
+
# directly or via a subclass), name it <tt>Strelka::AuthProvider::{Something}</tt>,
|
16
|
+
# save it in a file named <tt>strelka/authprovider/{something}.rb</tt>, and
|
17
|
+
# override the required methods.
|
18
|
+
#
|
19
|
+
# Which methods you'll need to provide implementations for depends on whether
|
20
|
+
# your provider provides *authentication*, *authorization*, or both.
|
21
|
+
#
|
22
|
+
# == Authentication Providers
|
23
|
+
#
|
24
|
+
# Authentication providers should override either one or both of the following methods,
|
25
|
+
# depending on whether they will provide
|
26
|
+
#
|
27
|
+
# * #[]
|
28
|
+
# * #[]=
|
29
|
+
# * #save
|
30
|
+
# * #delete
|
31
|
+
# * #key?
|
32
|
+
# * #namespace=
|
33
|
+
# * #namespace
|
34
|
+
#
|
35
|
+
# These methods provide basic functionality, but you might find it more efficient
|
36
|
+
# to override them:
|
37
|
+
#
|
38
|
+
# * self.load_or_create
|
39
|
+
# * self.load
|
40
|
+
#
|
41
|
+
#
|
42
|
+
class Strelka::AuthProvider
|
43
|
+
extend Strelka::Delegation
|
44
|
+
include PluginFactory,
|
45
|
+
Strelka::Loggable,
|
46
|
+
Strelka::Constants,
|
47
|
+
Strelka::AbstractClass
|
48
|
+
|
49
|
+
|
50
|
+
### PluginFactory API -- return the Array of directories to search for concrete
|
51
|
+
### AuthProvider classes.
|
52
|
+
def self::derivative_dirs
|
53
|
+
return ['strelka/authprovider']
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
#################################################################
|
58
|
+
### I N S T A N C E M E T H O D S
|
59
|
+
#################################################################
|
60
|
+
|
61
|
+
### Create a new AuthProvider for the given +app+.
|
62
|
+
def initialize( app )
|
63
|
+
@app = app
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
######
|
68
|
+
public
|
69
|
+
######
|
70
|
+
|
71
|
+
##
|
72
|
+
# The Strelka::App that the AuthProvider belongs to.
|
73
|
+
attr_reader :app
|
74
|
+
|
75
|
+
|
76
|
+
### You should override this method if you want to authenticate the +request+. It should
|
77
|
+
### return a credentials object if authentication is successful, or throw an auth_required
|
78
|
+
### response if it fails.
|
79
|
+
def authenticate( request )
|
80
|
+
self.log.debug "No authentication provided, returning anonymous credentials."
|
81
|
+
return 'anonymous'
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
### If the +callback+ is set, call it with the specified +credentials+, and +request. Override this in
|
86
|
+
### your own AuthProvider to provide +additional_arguments+ to the +callback+, and/or to provide
|
87
|
+
### additional generic authorization.
|
88
|
+
def authorize( credentials, request, *additional_arguments, &callback )
|
89
|
+
return true unless callback
|
90
|
+
return true if callback.call( credentials, request, *additional_arguments )
|
91
|
+
self.require_authorization
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
#########
|
96
|
+
protected
|
97
|
+
#########
|
98
|
+
|
99
|
+
### Throw a 401 (Unauthorized) response with the specified +challenge+ as the
|
100
|
+
### www-Authenticate header.
|
101
|
+
def require_authentication( challenge )
|
102
|
+
finish_with( HTTP::AUTH_REQUIRED, "Requires authentication.", www_authenticate: challenge )
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
### Throw a 403 (Forbidden) response with the specified +message+.
|
107
|
+
def require_authorization( message="You are not authorized to access this resource." )
|
108
|
+
finish_with( HTTP::FORBIDDEN, message )
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
### Abort the current execution and return a response with the specified
|
113
|
+
### http_status code immediately. The specified +message+ will be logged,
|
114
|
+
### and will be included in any message that is returned as part of the
|
115
|
+
### response. The +headers+ hash will be used to set response headers.
|
116
|
+
def finish_with( http_status, message, headers={} )
|
117
|
+
status_info = { :status => http_status, :message => message, :headers => headers }
|
118
|
+
throw :finish, status_info
|
119
|
+
end
|
120
|
+
|
121
|
+
end # class Strelka::AuthProvider
|
122
|
+
|
data/lib/strelka/cookie.rb
CHANGED
@@ -24,7 +24,7 @@ class Strelka::Cookie
|
|
24
24
|
include Strelka::Loggable
|
25
25
|
|
26
26
|
# The format of the date field
|
27
|
-
COOKIE_DATE_FORMAT = '%a, %d
|
27
|
+
COOKIE_DATE_FORMAT = '%a, %d %b %Y %H:%M:%S GMT'
|
28
28
|
|
29
29
|
### RFC 2109: HTTP State Management Mechanism
|
30
30
|
# When it sends a request to an origin server, the user agent sends a
|
data/lib/strelka/cookieset.rb
CHANGED
@@ -82,7 +82,7 @@ class Strelka::CookieSet
|
|
82
82
|
|
83
83
|
|
84
84
|
### Index set operator method: set the cookie that corresponds to the given +name+
|
85
|
-
### to +value+. If +value+ is not an Strelka::Cookie, one
|
85
|
+
### to +value+. If +value+ is not an Strelka::Cookie, one is created and its
|
86
86
|
### value set to +value+.
|
87
87
|
def []=( name, value )
|
88
88
|
value = Strelka::Cookie.new( name.to_s, value ) unless value.is_a?( Strelka::Cookie )
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'strelka/constants'
|
4
|
+
require 'strelka/httprequest' unless defined?( Strelka::HTTPRequest )
|
5
|
+
|
6
|
+
|
7
|
+
# The mixin that adds methods to Strelka::HTTPRequest for
|
8
|
+
# authentication/authorization.
|
9
|
+
module Strelka::HTTPRequest::Auth
|
10
|
+
include Strelka::Constants
|
11
|
+
|
12
|
+
|
13
|
+
### Extension callback -- add instance variables to extended objects.
|
14
|
+
def initialize( * )
|
15
|
+
super
|
16
|
+
@authenticated_user = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
######
|
21
|
+
public
|
22
|
+
######
|
23
|
+
|
24
|
+
# The current session namespace
|
25
|
+
attr_accessor :authenticated_user
|
26
|
+
alias_method :authenticated?, :authenticated_user
|
27
|
+
|
28
|
+
|
29
|
+
end # module Strelka::HTTPRequest::Auth
|
30
|
+
|
31
|
+
|
data/lib/strelka/logging.rb
CHANGED
@@ -117,12 +117,68 @@ module Strelka::Logging
|
|
117
117
|
return self.format % args
|
118
118
|
end
|
119
119
|
end
|
120
|
-
end # class
|
120
|
+
end # class Formatter
|
121
121
|
|
122
122
|
|
123
123
|
# A ANSI-colorized formatter for Logger instances.
|
124
124
|
class ColorFormatter < Logger::Formatter
|
125
|
-
|
125
|
+
|
126
|
+
# Set some ANSI escape code constants (Shamelessly stolen from Perl's
|
127
|
+
# Term::ANSIColor by Russ Allbery <rra@stanford.edu> and Zenin <zenin@best.com>
|
128
|
+
ANSI_ATTRIBUTES = {
|
129
|
+
'clear' => 0,
|
130
|
+
'reset' => 0,
|
131
|
+
'bold' => 1,
|
132
|
+
'dark' => 2,
|
133
|
+
'underline' => 4,
|
134
|
+
'underscore' => 4,
|
135
|
+
'blink' => 5,
|
136
|
+
'reverse' => 7,
|
137
|
+
'concealed' => 8,
|
138
|
+
|
139
|
+
'black' => 30, 'on_black' => 40,
|
140
|
+
'red' => 31, 'on_red' => 41,
|
141
|
+
'green' => 32, 'on_green' => 42,
|
142
|
+
'yellow' => 33, 'on_yellow' => 43,
|
143
|
+
'blue' => 34, 'on_blue' => 44,
|
144
|
+
'magenta' => 35, 'on_magenta' => 45,
|
145
|
+
'cyan' => 36, 'on_cyan' => 46,
|
146
|
+
'white' => 37, 'on_white' => 47
|
147
|
+
}
|
148
|
+
|
149
|
+
|
150
|
+
### Create a string that contains the ANSI codes specified and return it
|
151
|
+
def self::ansi_code( *attributes )
|
152
|
+
attributes.flatten!
|
153
|
+
attributes.collect! {|at| at.to_s }
|
154
|
+
return '' unless /(?:vt10[03]|xterm(?:-color)?|linux|screen)/i =~ ENV['TERM']
|
155
|
+
attributes = ANSI_ATTRIBUTES.values_at( *attributes ).compact.join(';')
|
156
|
+
|
157
|
+
if attributes.empty?
|
158
|
+
return ''
|
159
|
+
else
|
160
|
+
return "\e[%sm" % attributes
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
### Colorize the given +string+ with the specified +attributes+ and
|
166
|
+
### return it, handling line-endings, color reset, etc.
|
167
|
+
def self::colorize( *args )
|
168
|
+
string = ''
|
169
|
+
|
170
|
+
if block_given?
|
171
|
+
string = yield
|
172
|
+
else
|
173
|
+
string = args.shift
|
174
|
+
end
|
175
|
+
|
176
|
+
ending = string[/(\s)$/] || ''
|
177
|
+
string = string.rstrip
|
178
|
+
|
179
|
+
return self.ansi_code( args.flatten ) + string + self.ansi_code( 'reset' ) + ending
|
180
|
+
end
|
181
|
+
|
126
182
|
|
127
183
|
# Color settings
|
128
184
|
LEVEL_FORMATS = {
|
@@ -169,7 +225,8 @@ module Strelka::Logging
|
|
169
225
|
|
170
226
|
return self.settings[ severity.downcase.to_sym ] % args
|
171
227
|
end
|
172
|
-
|
228
|
+
|
229
|
+
end # class Formatter
|
173
230
|
|
174
231
|
|
175
232
|
# An alternate formatter for Logger instances that outputs +div+ HTML
|
@@ -216,9 +273,9 @@ module Strelka::Logging
|
|
216
273
|
time.usec, # %2$d
|
217
274
|
Process.pid, # %3$d
|
218
275
|
Thread.current == Thread.main ? 'main' : Thread.object_id, # %4$s
|
219
|
-
severity.downcase,
|
276
|
+
severity.downcase, # %5$s
|
220
277
|
progname, # %6$s
|
221
|
-
|
278
|
+
escape_html( msg ).gsub(/\n/, '<br />') # %7$s
|
222
279
|
]
|
223
280
|
|
224
281
|
return self.format % args
|
@@ -229,18 +286,16 @@ module Strelka::Logging
|
|
229
286
|
private
|
230
287
|
#######
|
231
288
|
|
232
|
-
###
|
233
|
-
|
234
|
-
def html_escape( string )
|
289
|
+
### Escape any HTML special characters in +string+.
|
290
|
+
def escape_html( string )
|
235
291
|
return string.
|
236
|
-
gsub(
|
237
|
-
gsub(
|
238
|
-
gsub(
|
292
|
+
gsub( '&', '&' ).
|
293
|
+
gsub( '<', '<' ).
|
294
|
+
gsub( '>', '>' )
|
239
295
|
end
|
240
296
|
|
241
|
-
end # class
|
297
|
+
end # class HtmlFormatter
|
242
298
|
|
243
|
-
end # module Strelka
|
244
299
|
|
245
|
-
#
|
300
|
+
end # module Strelka
|
246
301
|
|
data/lib/strelka/mixins.rb
CHANGED
@@ -10,7 +10,17 @@ require 'strelka/constants'
|
|
10
10
|
|
11
11
|
module Strelka
|
12
12
|
|
13
|
-
# Add logging to a Strelka class. Including classes get #log and
|
13
|
+
# Add logging to a Strelka class. Including classes get #log and
|
14
|
+
# #log_debug methods.
|
15
|
+
#
|
16
|
+
# class MyClass
|
17
|
+
# include Inversion::Loggable
|
18
|
+
#
|
19
|
+
# def a_method
|
20
|
+
# self.log.debug "Doing a_method stuff..."
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
#
|
14
24
|
module Loggable
|
15
25
|
|
16
26
|
# A logging proxy class that wraps calls to the logger into calls that include
|
@@ -75,70 +85,6 @@ module Strelka
|
|
75
85
|
|
76
86
|
end # module Loggable
|
77
87
|
|
78
|
-
# A collection of ANSI color utility functions
|
79
|
-
module ANSIColorUtilities
|
80
|
-
|
81
|
-
# Set some ANSI escape code constants (Shamelessly stolen from Perl's
|
82
|
-
# Term::ANSIColor by Russ Allbery <rra@stanford.edu> and Zenin <zenin@best.com>
|
83
|
-
ANSI_ATTRIBUTES = {
|
84
|
-
'clear' => 0,
|
85
|
-
'reset' => 0,
|
86
|
-
'bold' => 1,
|
87
|
-
'dark' => 2,
|
88
|
-
'underline' => 4,
|
89
|
-
'underscore' => 4,
|
90
|
-
'blink' => 5,
|
91
|
-
'reverse' => 7,
|
92
|
-
'concealed' => 8,
|
93
|
-
|
94
|
-
'black' => 30, 'on_black' => 40,
|
95
|
-
'red' => 31, 'on_red' => 41,
|
96
|
-
'green' => 32, 'on_green' => 42,
|
97
|
-
'yellow' => 33, 'on_yellow' => 43,
|
98
|
-
'blue' => 34, 'on_blue' => 44,
|
99
|
-
'magenta' => 35, 'on_magenta' => 45,
|
100
|
-
'cyan' => 36, 'on_cyan' => 46,
|
101
|
-
'white' => 37, 'on_white' => 47
|
102
|
-
}
|
103
|
-
|
104
|
-
###############
|
105
|
-
module_function
|
106
|
-
###############
|
107
|
-
|
108
|
-
### Create a string that contains the ANSI codes specified and return it
|
109
|
-
def ansi_code( *attributes )
|
110
|
-
attributes.flatten!
|
111
|
-
attributes.collect! {|at| at.to_s }
|
112
|
-
return '' unless /(?:vt10[03]|xterm(?:-color)?|linux|screen)/i =~ ENV['TERM']
|
113
|
-
attributes = ANSI_ATTRIBUTES.values_at( *attributes ).compact.join(';')
|
114
|
-
|
115
|
-
if attributes.empty?
|
116
|
-
return ''
|
117
|
-
else
|
118
|
-
return "\e[%sm" % attributes
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
|
123
|
-
### Colorize the given +string+ with the specified +attributes+ and return it, handling
|
124
|
-
### line-endings, color reset, etc.
|
125
|
-
def colorize( *args )
|
126
|
-
string = ''
|
127
|
-
|
128
|
-
if block_given?
|
129
|
-
string = yield
|
130
|
-
else
|
131
|
-
string = args.shift
|
132
|
-
end
|
133
|
-
|
134
|
-
ending = string[/(\s)$/] || ''
|
135
|
-
string = string.rstrip
|
136
|
-
|
137
|
-
return ansi_code( args.flatten ) + string + ansi_code( 'reset' ) + ending
|
138
|
-
end
|
139
|
-
|
140
|
-
end # module ANSIColorUtilities
|
141
|
-
|
142
88
|
|
143
89
|
# Hides your class's ::new method and adds a +pure_virtual+ method generator for
|
144
90
|
# defining API methods. If subclasses of your class don't provide implementations of
|
@@ -244,6 +190,17 @@ module Strelka
|
|
244
190
|
end
|
245
191
|
|
246
192
|
|
193
|
+
### Define the given +delegated_methods+ as delegators to the like-named class
|
194
|
+
### method.
|
195
|
+
def def_class_delegators( *delegated_methods )
|
196
|
+
delegated_methods.each do |name|
|
197
|
+
define_method( name ) do |*args|
|
198
|
+
self.class.__send__( name, *args )
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
|
247
204
|
#######
|
248
205
|
private
|
249
206
|
#######
|
@@ -296,6 +253,10 @@ module Strelka
|
|
296
253
|
|
297
254
|
# A collection of miscellaneous functions that are useful for manipulating
|
298
255
|
# complex data structures.
|
256
|
+
#
|
257
|
+
# include Strelka::DataUtilities
|
258
|
+
# newhash = deep_copy( oldhash )
|
259
|
+
#
|
299
260
|
module DataUtilities
|
300
261
|
|
301
262
|
###############
|
@@ -331,6 +292,15 @@ module Strelka
|
|
331
292
|
|
332
293
|
|
333
294
|
# A collection of methods for declaring other methods.
|
295
|
+
#
|
296
|
+
# class MyClass
|
297
|
+
# include Strelka::MethodUtilities
|
298
|
+
#
|
299
|
+
# singleton_attr_accessor :types
|
300
|
+
# end
|
301
|
+
#
|
302
|
+
# MyClass.types = [ :pheno, :proto, :stereo ]
|
303
|
+
#
|
334
304
|
module MethodUtilities
|
335
305
|
|
336
306
|
### Creates instance variables and corresponding methods that return their
|