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,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ENV["ENVIRONMENT"] ||= "development"
4
+ require "lib/##>=app_name<##"
5
+
6
+ services = Harbor::Container.new
7
+ # services.register("mailer", Harbor::Mailer)
8
+ # services.register("mail_server", Harbor::SendmailServer)
9
+
10
+ # DataMapper.setup :default, "postgres://localhost/##>=app_name<##"
11
+
12
+ if $0 == __FILE__
13
+ require "harbor/console"
14
+ Harbor::Console.start
15
+ else $0['thin']
16
+ run Harbor::Cascade.new(
17
+ ENV['ENVIRONMENT'],
18
+ services,
19
+ ##>=app_class<##
20
+ )
21
+ end
@@ -0,0 +1,49 @@
1
+ require 'rubygems'
2
+
3
+ gem "harbor"
4
+ require "harbor"
5
+
6
+ Harbor::View::path.unshift(Pathname(__FILE__).dirname + "##>=app_name<##" + "views")
7
+ Harbor::View::layouts.default("layouts/application")
8
+
9
+ class ##>=app_class<## < Harbor::Application
10
+
11
+ def self.routes(services)
12
+ Harbor::Router.new do
13
+
14
+ using services, Home do
15
+ get("/") { |home| home.index }
16
+ end
17
+
18
+ end
19
+ end
20
+
21
+ @@public_path = Pathname(__FILE__).dirname.parent.expand_path + "public"
22
+ def self.public_path=(value)
23
+ @@public_path = value
24
+ end
25
+
26
+ def self.public_path
27
+ @@public_path
28
+ end
29
+
30
+ @@private_path = Pathname(__FILE__).dirname.parent.expand_path + "private"
31
+ def self.private_path=(value)
32
+ @@private_path = value
33
+ end
34
+
35
+ def self.private_path
36
+ @@private_path
37
+ end
38
+
39
+ @@tmp_path = Pathname(__FILE__).dirname.parent.expand_path + "tmp"
40
+ def self.tmp_path=(value)
41
+ @@tmp_path = value
42
+ end
43
+
44
+ def self.tmp_path
45
+ @@tmp_path
46
+ end
47
+ end
48
+
49
+ require Pathname(__FILE__).dirname + '##>=app_name<##/controllers/home'
@@ -0,0 +1,9 @@
1
+ class Home
2
+
3
+ attr_accessor :request, :response, :mailer
4
+
5
+ def index
6
+ response.render "home/index"
7
+ end
8
+
9
+ end
@@ -0,0 +1,23 @@
1
+ <h1>Welcome to Harbor <span>You're all set to go!</span></h1>
2
+
3
+ <p class="feature">Congratulations on creating your first Harbor application! Now you should be ready to dive in, and here are some resources to get you started:</p>
4
+
5
+ <h2>What Am I?</h2>
6
+ <p>I'm just a default view to help you get started. I live in <kbd>lib/views/home/index.html.erb</kbd>, and am being rendered by <kbd>lib/controllers/home.rb</kbd>. And, of course, you're being routed here by <kbd>lib/##>=app_name<##.rb</kbd>.</p>
7
+
8
+ <p>That's pretty much the default setup for Harbor applications, but if you poke around you'll see you can set me up however you like.</p>
9
+
10
+ <h2>Documentation</h2>
11
+ <p>You can access the documentation for the latest stable version of harbor <a href="http://wiecklabs.com/harbor/doc">here</a>. We're also putting together a few tutorials which can be found on our <a href="http://wiecklabs.com/blog">blog</a>:</p>
12
+ <ul>
13
+ <li><a href="http://wiecklabs.com/blog/2009/10/21/starting-a-new-harbor-project">Starting a new Harbor project</a></li>
14
+ </ul>
15
+
16
+ <h2>Samples</h2>
17
+ <p>We've open sourced a few of our own harbor applications for you to use and explore. You can check them out on <a href="http://github.com/wiecklabs">github</a>.</p>
18
+ <ul>
19
+ <li><a href="http://github.com/wiecklabs/cleat">Cleat</a> - URL Shortener</li>
20
+ <li><a href="http://github.com/wiecklabs/northstar">Northstar</a> - Wiki</li>
21
+ <li><a href="http://github.com/wiecklabs/captains_blog">Captains Blog</a> - Blog</li>
22
+ <li><a href="http://github.com/wiecklabs/port_authority">Port Authority</a> - User Management and Authentication</li>
23
+ </ul>
@@ -0,0 +1,48 @@
1
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
2
+ "http://www.w3.org/TR/html4/strict.dtd">
3
+ <html>
4
+ <head>
5
+ <title>Harbor Framework</title>
6
+ <style type="text/css" media="screen">
7
+ body { background-color: #def; color: #002; font: 12px/2em "Lucida Grande"; margin: 20px 0 0 0; }
8
+ .body { background-color: #fff; width: 700px; margin: 0 auto 20px; border: 20px solid #fff; }
9
+
10
+ a { outline: none; }
11
+
12
+ h1 {
13
+ background-color: #57b;
14
+ color: #fff;
15
+ margin: 0 0 20px;
16
+ font-family: 'geneva';
17
+ font-size: 28px;
18
+ font-weight: normal;
19
+ padding: 20px 10px;
20
+ text-align: center;
21
+ text-transform: uppercase;
22
+ }
23
+
24
+ h1 span { display: block; color: #002; font-size: 18px; margin-top: 10px; text-transform: none; }
25
+
26
+ p.feature { font-size: 16px; }
27
+
28
+ h2 { color: #833; margin-bottom: 0; font-size: 16px; }
29
+ h3 { color: #833; margin-bottom: 0; }
30
+ a { color: #383; }
31
+ p { margin: 5px 0; }
32
+ ul { margin-top: 0; }
33
+ kbd { font-family: Monaco; background-color: #eee; padding: 2px; }
34
+ code { font-family: Monaco; background-color: #eee; padding: 2px; }
35
+ pre { font-family: Monaco; background-color: #002; color: #eee; padding: 10px; display: block; }
36
+
37
+ </style>
38
+ </head>
39
+ <body>
40
+ <div class="body">
41
+
42
+ <div id="content">
43
+ <%= @content %>
44
+ </div>
45
+
46
+ </div>
47
+ </body>
48
+ </html>
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
2
+ "http://www.w3.org/TR/html4/strict.dtd">
3
+ <html>
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
6
+ </head>
7
+ <body>
8
+ <div id="content">
9
+ <h1>##>=app_name.capitalize<##</h1>
10
+ <%= @content %>
11
+ </div>
12
+ </body>
13
+ </html>
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
2
+ "http://www.w3.org/TR/html4/strict.dtd">
3
+ <html>
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
6
+ </head>
7
+ <body>
8
+ <h1>##>=app_name.capitalize<##</h1>
9
+ <%= @content %>
10
+ </body>
11
+ </html>
@@ -0,0 +1,105 @@
1
+ module Harbor
2
+ module Hooks
3
+
4
+ def self.included(target)
5
+ target.extend(ClassMethods)
6
+
7
+ target.class_eval do
8
+ @__harbor_hooked_method_added = method(:method_added) if respond_to?(:method_added)
9
+ def self.method_added(method)
10
+ if !@__harbor_binding_method && hooks.has_key?(method)
11
+ chain = hooks[method]
12
+ chain.bind!
13
+ end
14
+
15
+ @__harbor_hooked_method_added.call(method) if @__harbor_hooked_method_added
16
+ end
17
+ end
18
+
19
+ end
20
+
21
+ class Map
22
+ def initialize(target)
23
+ @map = {}
24
+ @target = target
25
+ end
26
+
27
+ def has_key?(method_name)
28
+ @map.has_key?(method_name)
29
+ end
30
+
31
+ def [](method_name)
32
+ @map[method_name] ||= Chain.new(@target, method_name)
33
+ end
34
+ end
35
+
36
+ class Chain
37
+ def initialize(target, method_name)
38
+ @target = target
39
+ @method_name = method_name
40
+ @before = []
41
+ @after = []
42
+
43
+ bind! if target.instance_methods.include?(method_name.to_s)
44
+ end
45
+
46
+ def before(block)
47
+ @before << block
48
+ end
49
+
50
+ def after(block)
51
+ @after << block
52
+ end
53
+
54
+ def call(instance, args, blk = nil)
55
+ result = nil
56
+
57
+ catch(:halt) do
58
+ @before.each do |block|
59
+ block.call instance
60
+ end
61
+
62
+ result = instance.send("__hooked_#{@method_name}", *args, &blk)
63
+
64
+ @after.each do |block|
65
+ block.call instance
66
+ end
67
+
68
+ result
69
+ end
70
+ end
71
+
72
+ def self.bind!(target, method_name)
73
+ target.send(:alias_method, "__hooked_#{method_name}", method_name)
74
+
75
+ target.send(:class_eval, <<-EOS)
76
+ instance_variable_set(:@__harbor_binding_method, true)
77
+ def #{method_name}(*args, &block)
78
+ self.class.hooks[#{method_name.inspect}].call(self, args, block)
79
+ end
80
+ remove_instance_variable(:@__harbor_binding_method)
81
+ EOS
82
+ end
83
+
84
+ def bind!
85
+ self.class.bind!(@target, @method_name)
86
+ end
87
+ end
88
+
89
+ module ClassMethods
90
+
91
+ def hooks
92
+ @hooks ||= Map.new(self)
93
+ end
94
+
95
+ def before(method_name, &block)
96
+ hooks[method_name].before(block)
97
+ end
98
+
99
+ def after(method_name, &block)
100
+ hooks[method_name].after(block)
101
+ end
102
+
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,37 @@
1
+ module Harbor
2
+ ##
3
+ # Middleware for storing data in a cookie using JSON, for later access
4
+ # via javascript.
5
+ #
6
+ # use Harbor::JsonCookies, "key_to_serialize", "other_key"
7
+ ##
8
+ class JsonCookies
9
+ def initialize(app, keys = [])
10
+ @app = app
11
+ @keys = keys
12
+ end
13
+
14
+ def call(env)
15
+ read_cookies(env)
16
+ status, headers, body = @app.call(env)
17
+ write_cookies(env, status, headers, body)
18
+ end
19
+
20
+ private
21
+
22
+ def read_cookies(env)
23
+ request = Rack::Request.new(env)
24
+ (request.cookies.keys & @keys).each do |key|
25
+ env[key] = JSON.parse(request.cookies[key]) rescue nil
26
+ end
27
+ end
28
+
29
+ def write_cookies(env, status, headers, body)
30
+ response = Rack::Response.new(body, status, headers)
31
+ @keys.each do |key|
32
+ response.set_cookie(key, :value => env[key].to_json, :path => "/")
33
+ end
34
+ response.to_a
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,61 @@
1
+ module Harbor
2
+ class Layouts
3
+
4
+ include Enumerable
5
+
6
+ def initialize
7
+ @map = []
8
+ @default = nil
9
+ end
10
+
11
+ def map(fragment, layout)
12
+ fragment = fragment.squeeze("*").squeeze("/").sub(%r{/$}, "").gsub("*", ".*")
13
+ specificity = fragment_specificity(fragment)
14
+
15
+ regexp = Regexp.new("^#{fragment}")
16
+
17
+ if previous = @map.assoc(regexp)
18
+ @map[@map.index(previous)] = [regexp, layout, specificity]
19
+ else
20
+ @map << [regexp, layout, specificity]
21
+ end
22
+
23
+ sort!
24
+ @map
25
+ end
26
+
27
+ def default(layout)
28
+ @default = layout
29
+ end
30
+
31
+ def each
32
+ @map.each { |item| yield item }
33
+ end
34
+
35
+ def sort!
36
+ @map.sort! do |a, b|
37
+ b[2] <=> a[2]
38
+ end
39
+ end
40
+
41
+ def clear
42
+ @default = nil
43
+ @map.clear
44
+ end
45
+
46
+ def match(path)
47
+ @map.each do |fragment, layout|
48
+ return layout if fragment === path
49
+ end
50
+
51
+ return @default
52
+ end
53
+
54
+ private
55
+
56
+ def fragment_specificity(fragment)
57
+ fragment.count("/") - fragment.count("*")
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,50 @@
1
+ module Harbor
2
+ class Locale
3
+
4
+ def self.[](culture_code)
5
+ unless @locales
6
+ @locales = {}
7
+
8
+ ::File.read(Pathname(__FILE__).dirname + "locales.txt").split("\n").each do |line|
9
+ next if line =~ /^\s*(\#.*)?$/
10
+ values = line.split(/\|/).map { |value| value.strip }
11
+ @locales[values[1]] = Locale.new(values[1], values[0], values[2])
12
+ end
13
+ end
14
+
15
+ @locales[culture_code]
16
+ end
17
+
18
+ def self.active_locales
19
+ @active_locales ||= []
20
+ end
21
+
22
+ def self.activate!(*culture_codes)
23
+ @active_locales = culture_codes.map { |culture_code| self[culture_code] }
24
+ end
25
+
26
+ def self.default
27
+ @default ||= self[default_culture_code]
28
+ end
29
+
30
+ def self.default_culture_code
31
+ @default_culture_code ||= "en-US"
32
+ end
33
+
34
+ def self.default_culture_code=(value)
35
+ @default_culture_code = value
36
+ end
37
+
38
+ attr_reader :culture_code, :abbreviation, :description
39
+
40
+ def initialize(culture_code, abbreviation, description)
41
+ @culture_code = culture_code
42
+ @abbreviation = abbreviation
43
+ @description = description
44
+ end
45
+
46
+ def to_s
47
+ @description
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,22 @@
1
+ # This is a pipe-delimited file with values of
2
+ # LanguageAbbreviation|CultureCode|Description
3
+
4
+ US|en-US|English (US)
5
+ AU|en-AU|English (AU)
6
+ UK|en-GB|English (UK)
7
+ JP|ja|Japanese
8
+ IN|hi-IN|Hindi (IN)
9
+ KO|ko-KR|Korean (KO)
10
+ MY|ms-MY|Malay (MY)
11
+ TH|th-TH|Thai (TH)
12
+ PK|ur-PK|Urdu (PK)
13
+ VN|vi|Vietnamese
14
+ ID|id-ID|Indonesian (ID)
15
+ HK|zh-HK|Chinese (HK)
16
+ CN|zh-CN|Chinese (CN)
17
+ FR|fr-FR|French (FR)
18
+ DE|de-DE|German (DE)
19
+ IT|it-IT|Italian (IT)
20
+ SP|es-ES|Spanish (SP)
21
+ PT|pt|Portuguese
22
+