harbor 0.16.1

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.
Files changed (84) hide show
  1. data/Rakefile +76 -0
  2. data/bin/harbor +7 -0
  3. data/lib/harbor.rb +17 -0
  4. data/lib/harbor/accessor_injector.rb +30 -0
  5. data/lib/harbor/application.rb +172 -0
  6. data/lib/harbor/auth/basic.rb +51 -0
  7. data/lib/harbor/block_io.rb +63 -0
  8. data/lib/harbor/cache.rb +90 -0
  9. data/lib/harbor/cache/disk.rb +99 -0
  10. data/lib/harbor/cache/item.rb +48 -0
  11. data/lib/harbor/cache/memory.rb +35 -0
  12. data/lib/harbor/cascade.rb +75 -0
  13. data/lib/harbor/console.rb +34 -0
  14. data/lib/harbor/container.rb +134 -0
  15. data/lib/harbor/contrib/debug.rb +236 -0
  16. data/lib/harbor/contrib/session/data_mapper.rb +74 -0
  17. data/lib/harbor/daemon.rb +105 -0
  18. data/lib/harbor/errors.rb +49 -0
  19. data/lib/harbor/events.rb +45 -0
  20. data/lib/harbor/exception_notifier.rb +59 -0
  21. data/lib/harbor/file.rb +66 -0
  22. data/lib/harbor/file_store.rb +69 -0
  23. data/lib/harbor/file_store/file.rb +100 -0
  24. data/lib/harbor/file_store/local.rb +71 -0
  25. data/lib/harbor/file_store/mosso.rb +154 -0
  26. data/lib/harbor/file_store/mosso/private.rb +8 -0
  27. data/lib/harbor/generator.rb +56 -0
  28. data/lib/harbor/generator/help.rb +34 -0
  29. data/lib/harbor/generator/setup.rb +82 -0
  30. data/lib/harbor/generator/skeletons/basic/config.ru.skel +21 -0
  31. data/lib/harbor/generator/skeletons/basic/lib/appname.rb.skel +49 -0
  32. data/lib/harbor/generator/skeletons/basic/lib/appname/controllers/home.rb +9 -0
  33. data/lib/harbor/generator/skeletons/basic/lib/appname/views/home/index.html.erb.skel +23 -0
  34. data/lib/harbor/generator/skeletons/basic/lib/appname/views/layouts/application.html.erb.skel +48 -0
  35. data/lib/harbor/generator/skeletons/basic/lib/appname/views/layouts/exception.html.erb.skel +13 -0
  36. data/lib/harbor/generator/skeletons/basic/lib/appname/views/layouts/login.html.erb.skel +11 -0
  37. data/lib/harbor/generator/skeletons/basic/log/development.log +0 -0
  38. data/lib/harbor/hooks.rb +105 -0
  39. data/lib/harbor/json_cookies.rb +37 -0
  40. data/lib/harbor/layouts.rb +61 -0
  41. data/lib/harbor/locale.rb +50 -0
  42. data/lib/harbor/locales.txt +22 -0
  43. data/lib/harbor/logging.rb +39 -0
  44. data/lib/harbor/logging/appenders/email.rb +84 -0
  45. data/lib/harbor/logging/request_logger.rb +34 -0
  46. data/lib/harbor/mail_servers/abstract.rb +12 -0
  47. data/lib/harbor/mail_servers/sendmail.rb +19 -0
  48. data/lib/harbor/mail_servers/smtp.rb +25 -0
  49. data/lib/harbor/mail_servers/test.rb +17 -0
  50. data/lib/harbor/mailer.rb +96 -0
  51. data/lib/harbor/messages.rb +17 -0
  52. data/lib/harbor/mime.rb +206 -0
  53. data/lib/harbor/plugin.rb +52 -0
  54. data/lib/harbor/plugin_list.rb +38 -0
  55. data/lib/harbor/request.rb +138 -0
  56. data/lib/harbor/response.rb +281 -0
  57. data/lib/harbor/router.rb +112 -0
  58. data/lib/harbor/script.rb +155 -0
  59. data/lib/harbor/session.rb +75 -0
  60. data/lib/harbor/session/abstract.rb +27 -0
  61. data/lib/harbor/session/cookie.rb +17 -0
  62. data/lib/harbor/shellwords.rb +26 -0
  63. data/lib/harbor/test/mailer.rb +10 -0
  64. data/lib/harbor/test/request.rb +28 -0
  65. data/lib/harbor/test/response.rb +17 -0
  66. data/lib/harbor/test/session.rb +11 -0
  67. data/lib/harbor/test/test.rb +22 -0
  68. data/lib/harbor/version.rb +3 -0
  69. data/lib/harbor/view.rb +89 -0
  70. data/lib/harbor/view_context.rb +134 -0
  71. data/lib/harbor/view_context/helpers.rb +7 -0
  72. data/lib/harbor/view_context/helpers/cache.rb +77 -0
  73. data/lib/harbor/view_context/helpers/form.rb +34 -0
  74. data/lib/harbor/view_context/helpers/html.rb +26 -0
  75. data/lib/harbor/view_context/helpers/text.rb +120 -0
  76. data/lib/harbor/view_context/helpers/url.rb +11 -0
  77. data/lib/harbor/xml_view.rb +57 -0
  78. data/lib/harbor/zipped_io.rb +203 -0
  79. data/lib/vendor/cloudfiles-1.3.0/cloudfiles.rb +77 -0
  80. data/lib/vendor/cloudfiles-1.3.0/cloudfiles/authentication.rb +46 -0
  81. data/lib/vendor/cloudfiles-1.3.0/cloudfiles/connection.rb +280 -0
  82. data/lib/vendor/cloudfiles-1.3.0/cloudfiles/container.rb +260 -0
  83. data/lib/vendor/cloudfiles-1.3.0/cloudfiles/storage_object.rb +253 -0
  84. metadata +155 -0
@@ -0,0 +1,112 @@
1
+ module Harbor
2
+ class Router
3
+
4
+ URI_CHAR = '[^/?:,&#\.\[\]]'.freeze unless defined?(URI_CHAR)
5
+ PARAM = /(:(#{URI_CHAR}+))/.freeze unless defined?(PARAM)
6
+
7
+ attr_accessor :routes
8
+
9
+ def initialize(&routes)
10
+ @routes = []
11
+ @route_match_cache = {}
12
+ instance_eval(&routes) if block_given?
13
+ end
14
+
15
+ def merge!(other)
16
+ self.routes |= other.routes
17
+ end
18
+
19
+ # Matches a GET request
20
+ def get(matcher, &handler)
21
+ register(:get, matcher, &handler)
22
+ end
23
+
24
+ # Matches a POST (create) request
25
+ def post(matcher, &handler)
26
+ register(:post, matcher, &handler)
27
+ end
28
+
29
+ # Matches a PUT (update) request
30
+ def put(matcher, &handler)
31
+ register(:put, matcher, &handler)
32
+ end
33
+
34
+ # Matches a DELETE request
35
+ def delete(matcher, &handler)
36
+ register(:delete, matcher, &handler)
37
+ end
38
+
39
+ def using(container, klass, initializer = nil, &block)
40
+ self.class::Using.new(self, container, klass, initializer).instance_eval(&block)
41
+ end
42
+
43
+ class Using
44
+ def initialize(router, container, klass, initializer)
45
+ @router = router
46
+ @container = container
47
+
48
+ if klass.is_a?(String)
49
+ @service_name = klass
50
+ else
51
+ @service_name = klass.to_s
52
+ @container.register(@service_name, klass, &initializer)
53
+ end
54
+ end
55
+
56
+ %w(get post put delete).each do |verb|
57
+ class_eval <<-EOS
58
+ def #{verb}(matcher, &handler)
59
+ @router.send(#{verb.inspect}, matcher) do |request, response|
60
+ service = @container.get(@service_name, :request => request, :response => response)
61
+
62
+ handler.arity == 2 ? handler[service, request] : handler[service]
63
+ end
64
+ end
65
+ EOS
66
+ end
67
+ end
68
+
69
+ def register(request_method, matcher, &handler)
70
+ matcher, param_keys = transform(matcher)
71
+ route = [request_method.to_s.upcase, matcher, param_keys, handler]
72
+ @routes << route
73
+ route
74
+ end
75
+
76
+ def clear
77
+ @routes = []
78
+ end
79
+
80
+ def match(request)
81
+ @routes.each do |request_method, matcher, param_keys, handler|
82
+ next unless request.request_method == request_method
83
+
84
+ # Strip trailing forward-slash on request path before matching
85
+ request_path = (request.path_info[-1] == ?/) ? request.path_info[0..-2] : request.path_info
86
+
87
+ next unless request_path =~ matcher
88
+
89
+ request.params.update(Hash[*param_keys.zip($~.captures).flatten])
90
+ return handler
91
+ end
92
+
93
+ # No routes matched, so return false
94
+ false
95
+ end
96
+
97
+ private
98
+
99
+ def transform(matcher)
100
+ param_keys = []
101
+
102
+ if matcher.is_a?(String)
103
+ # Strip trailing forward-slash on routes
104
+ matcher = matcher[0..-2] if (matcher[-1] == ?/)
105
+ matcher = /^#{matcher.gsub('.', '[\.]').gsub(PARAM) { param_keys << $2; "(#{URI_CHAR}+)" }}$/
106
+ end
107
+
108
+ [matcher, param_keys]
109
+ end
110
+
111
+ end
112
+ end
@@ -0,0 +1,155 @@
1
+ require "harbor/logging"
2
+
3
+ gem "thin"
4
+ require 'thin/version'
5
+ require 'thin/daemonizing'
6
+
7
+ module Logging #:nodoc:
8
+ def log(message)
9
+ Harbor::Script.logger << message + "\n"
10
+ end
11
+ module_function :log
12
+ end
13
+
14
+ module Harbor
15
+ ##
16
+ # Class for defining and running daemonizable scripts.
17
+ #
18
+ # services = Harbor::Container.new
19
+ # services.register("mailer", Harbor::Mailer)
20
+ #
21
+ # class Processor < Harbor::Script
22
+ #
23
+ # attr_accessor :mailer
24
+ #
25
+ # def self.pid_file
26
+ # "tmp/processor.pid"
27
+ # end
28
+ #
29
+ # def self.log_file
30
+ # "log/processor.log"
31
+ # end
32
+ #
33
+ # def self.run!
34
+ # loop do
35
+ # # processing code
36
+ # end
37
+ # end
38
+ # end
39
+ #
40
+ # Harbor::Script::Runner.new(ARGV, services, Processor).run!
41
+ ##
42
+ class Script
43
+ include Thin::Daemonizable
44
+
45
+ attr_accessor :options, :services
46
+
47
+ def self.logger
48
+ @logger ||= begin
49
+ logger = Logging::Logger[self]
50
+ logger.additive = false
51
+ logger.level = :info
52
+ logger.add_appenders(Logging::Appenders::Stdout.new)
53
+ logger
54
+ end
55
+ end
56
+
57
+ def logger
58
+ self.class.logger
59
+ end
60
+
61
+ def self.pid_file
62
+ raise NotImplementedError.new("#{self}#pid_file must be defined.")
63
+ end
64
+
65
+ def self.log_file
66
+ raise NotImplementedError.new("#{self}#log_file must be defined.")
67
+ end
68
+
69
+ def initialize
70
+ @on_restart = lambda do
71
+ exec("#{$0} #{'--daemonize' if @options[:daemonize]} start")
72
+ end
73
+
74
+ @pid_file = self.class.pid_file
75
+ @log_file = self.class.log_file
76
+ end
77
+
78
+ def log(message)
79
+ if @options[:daemonize]
80
+ self.class.logger << message + "\n"
81
+ else
82
+ puts message
83
+ end
84
+ end
85
+
86
+ def name
87
+ $0
88
+ end
89
+
90
+ def stop
91
+ log ">> Stopping"
92
+ end
93
+
94
+ def run!
95
+ raise NotImplementedError.new("#{self}.run! must be defined.")
96
+ end
97
+
98
+ class Runner
99
+
100
+ COMMANDS = %w(start stop restart)
101
+
102
+ def initialize(argv, services, script)
103
+ raise ArgumentError.new("services must be a Harbor::Container but was #{services.inspect}") unless services.is_a?(Harbor::Container)
104
+
105
+ @argv = argv
106
+ @script = script
107
+ @script_name = @script.to_s
108
+ @services = services
109
+
110
+ @services.register(@script_name, @script) unless services.registered?(@script_name)
111
+
112
+ parse!
113
+ end
114
+
115
+ def parse!
116
+ @options = {
117
+ :daemonize => false
118
+ }
119
+
120
+ parser = OptionParser.new do |opts|
121
+ opts.on("-d", "--daemonize", "Daemonize process") { @options[:daemonize] = true }
122
+ end
123
+
124
+ parser.parse!(@argv)
125
+ @command = @argv.shift
126
+ end
127
+
128
+ def run!
129
+ unless COMMANDS.include?(@command)
130
+ puts "#{@command.inspect} is not a valid command. Commands are: #{COMMANDS.join(", ")}"
131
+ exit 1
132
+ end
133
+
134
+ send(@command)
135
+ end
136
+
137
+ def start
138
+ script = @services.get(@script_name, :options => @options, :services => @services)
139
+
140
+ script.daemonize if @options[:daemonize]
141
+
142
+ @argv.empty? ? script.run! : script.run!(*@argv)
143
+ end
144
+
145
+ def restart
146
+ Harbor::Script.restart(@script.pid_file)
147
+ end
148
+
149
+ def stop
150
+ Harbor::Script.kill(@script.pid_file)
151
+ end
152
+ end
153
+
154
+ end
155
+ end
@@ -0,0 +1,75 @@
1
+ require Pathname(__FILE__).dirname + 'session/abstract'
2
+ require Pathname(__FILE__).dirname + 'session/cookie'
3
+
4
+ module Harbor
5
+
6
+ class Session
7
+ DEFAULT_OPTIONS = {
8
+ :key => "harbor.session",
9
+ :domain => nil,
10
+ :path => "/",
11
+ :expire_after => nil,
12
+ :store => Cookie
13
+ }
14
+
15
+ ##
16
+ # Configures non-default session settings.
17
+ #
18
+ # Harbor::Session.configure do |session|
19
+ # session[:domain] = "*.domain.com"
20
+ # session[:store] = Custom::Session::Store
21
+ # end
22
+ ##
23
+ def self.configure #:yields: default_options
24
+ @options = DEFAULT_OPTIONS.dup
25
+ yield(@options)
26
+ @options
27
+ end
28
+
29
+ def self.options
30
+ @options ||= DEFAULT_OPTIONS.dup
31
+ @options
32
+ end
33
+
34
+ def initialize(request)
35
+ @options = self.class.options.dup
36
+ @cookie = request.cookies[@options[:key]]
37
+ @store = self.class.options[:store]
38
+
39
+ @data ||= @store.load_session(@cookie)
40
+ end
41
+
42
+ def key
43
+ @options[:key]
44
+ end
45
+
46
+ def []=(key, value)
47
+ @data[key] = value
48
+ end
49
+
50
+ def [](key)
51
+ @data[key]
52
+ end
53
+
54
+ def data
55
+ @data
56
+ end
57
+
58
+ def id
59
+ @data[:session_id]
60
+ end
61
+
62
+ def save
63
+ cookie = {}
64
+ cookie[:domain] = @options[:domain]
65
+ cookie[:path] = @options[:path]
66
+ cookie[:expires] = Time.now + @options[:expire_after] unless @options[:expire_after].nil?
67
+ cookie[:value] = @store.commit_session(@data)
68
+ cookie
69
+ end
70
+
71
+ def destroy
72
+ @data.clear
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,27 @@
1
+ module Harbor
2
+ class Session
3
+
4
+ ##
5
+ # Defines the API and default behavior for session stores. See Cookie, and
6
+ # contrib/session/data_mapper for examples of usage.
7
+ ##
8
+ class Abstract
9
+ ##
10
+ # Receives the raw cookie data, and should return a hash
11
+ # of the data for the session.
12
+ ##
13
+ def self.load_session(cookie)
14
+ Marshal.load(cookie.unpack("m*")[0]) rescue {}
15
+ end
16
+
17
+ ##
18
+ # Receives the session data hash, and should return the data
19
+ # to be set for the cookie's value
20
+ ##
21
+ def self.commit_session(data)
22
+ [Marshal.dump(data)].pack("m*")
23
+ end
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,17 @@
1
+ module Harbor
2
+ class Session
3
+
4
+ ##
5
+ # Basic enhancement to Abstract session to automatically generate
6
+ # session_id's.
7
+ ##
8
+ class Cookie < Abstract
9
+ def self.load_session(cookie)
10
+ cookie = super
11
+ cookie[:session_id] ||= `uuidgen`.chomp
12
+ cookie
13
+ end
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,26 @@
1
+ require 'shellwords'
2
+
3
+ ##
4
+ # This is a backport of ruby-1.8.7's Shellwords.escape function to 1.8.6
5
+ # for safely escaping filenames to be passed directly to the shell.
6
+ ##
7
+ module Shellwords #:nodoc:
8
+ def escape(str)
9
+ # An empty argument will be skipped, so return empty quotes.
10
+ return "''" if str.empty?
11
+
12
+ str = str.dup
13
+
14
+ # Process as a single byte sequence because not all shell
15
+ # implementations are multibyte aware.
16
+ str.gsub!(/([^A-Za-z0-9_\-.,:\/@\n])/n, "\\\\\\1")
17
+
18
+ # A LF cannot be escaped with a backslash because a backslash + LF
19
+ # combo is regarded as line continuation and simply ignored.
20
+ str.gsub!(/\n/, "'\n'")
21
+
22
+ return str
23
+ end
24
+
25
+ module_function :escape
26
+ end
@@ -0,0 +1,10 @@
1
+ module Harbor
2
+ module Test
3
+ class Mailer < Harbor::Mailer
4
+
5
+ def send!
6
+ end
7
+
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,28 @@
1
+ module Harbor
2
+ module Test
3
+ class Request < Harbor::Request
4
+
5
+ attr_accessor :session, :env, :params
6
+
7
+ def params
8
+ @params ||= {}
9
+ end
10
+
11
+ ##
12
+ # Rack::Response defines self.new(env, *args), which means we can't initialize
13
+ # a new request via a container without replacing this method.
14
+ ##
15
+ def self.new(*args)
16
+ super(nil, {})
17
+ end
18
+
19
+ def session
20
+ @session || Session.new
21
+ end
22
+
23
+ def session=(session)
24
+ @session = Session.new(session)
25
+ end
26
+ end
27
+ end
28
+ end