waves-edge 2009.03.10.13.14

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 (148) hide show
  1. data/bin/waves +30 -0
  2. data/doc/HISTORY +1 -0
  3. data/doc/LICENSE +22 -0
  4. data/doc/README +1 -0
  5. data/doc/VERSION +1 -0
  6. data/lib/caches/file.rb +48 -0
  7. data/lib/caches/memcached.rb +40 -0
  8. data/lib/caches/simple.rb +25 -0
  9. data/lib/caches/synchronized.rb +25 -0
  10. data/lib/commands/console.rb +35 -0
  11. data/lib/commands/generate.rb +52 -0
  12. data/lib/commands/help.rb +5 -0
  13. data/lib/commands/server.rb +68 -0
  14. data/lib/dispatchers/base.rb +68 -0
  15. data/lib/dispatchers/default.rb +25 -0
  16. data/lib/ext/float.rb +13 -0
  17. data/lib/ext/hash.rb +31 -0
  18. data/lib/ext/integer.rb +27 -0
  19. data/lib/ext/kernel.rb +20 -0
  20. data/lib/ext/module.rb +20 -0
  21. data/lib/ext/object.rb +33 -0
  22. data/lib/ext/string.rb +20 -0
  23. data/lib/ext/symbol.rb +11 -0
  24. data/lib/ext/tempfile.rb +5 -0
  25. data/lib/foundations/classic.rb +59 -0
  26. data/lib/foundations/compact.rb +52 -0
  27. data/lib/helpers/basic.rb +11 -0
  28. data/lib/helpers/doc_type.rb +34 -0
  29. data/lib/helpers/extended.rb +21 -0
  30. data/lib/helpers/form.rb +42 -0
  31. data/lib/helpers/formatting.rb +30 -0
  32. data/lib/helpers/layouts.rb +37 -0
  33. data/lib/helpers/model.rb +37 -0
  34. data/lib/helpers/view.rb +22 -0
  35. data/lib/layers/inflect/english.rb +35 -0
  36. data/lib/layers/mvc.rb +41 -0
  37. data/lib/layers/mvc/controllers.rb +41 -0
  38. data/lib/layers/mvc/extensions.rb +52 -0
  39. data/lib/layers/orm/migration.rb +79 -0
  40. data/lib/layers/orm/providers/active_record.rb +84 -0
  41. data/lib/layers/orm/providers/active_record/migrations/empty.rb.erb +9 -0
  42. data/lib/layers/orm/providers/active_record/tasks/generate.rb +28 -0
  43. data/lib/layers/orm/providers/active_record/tasks/schema.rb +22 -0
  44. data/lib/layers/orm/providers/data_mapper.rb +37 -0
  45. data/lib/layers/orm/providers/filebase.rb +25 -0
  46. data/lib/layers/orm/providers/sequel.rb +87 -0
  47. data/lib/layers/orm/providers/sequel/migrations/empty.rb.erb +9 -0
  48. data/lib/layers/orm/providers/sequel/tasks/generate.rb +30 -0
  49. data/lib/layers/orm/providers/sequel/tasks/schema.rb +16 -0
  50. data/lib/layers/renderers/erubis.rb +52 -0
  51. data/lib/layers/renderers/haml.rb +67 -0
  52. data/lib/layers/renderers/markaby.rb +41 -0
  53. data/lib/matchers/accept.rb +21 -0
  54. data/lib/matchers/base.rb +30 -0
  55. data/lib/matchers/content_type.rb +17 -0
  56. data/lib/matchers/path.rb +67 -0
  57. data/lib/matchers/query.rb +21 -0
  58. data/lib/matchers/request.rb +27 -0
  59. data/lib/matchers/resource.rb +19 -0
  60. data/lib/matchers/traits.rb +19 -0
  61. data/lib/matchers/uri.rb +20 -0
  62. data/lib/renderers/mixin.rb +13 -0
  63. data/lib/resources/mixin.rb +136 -0
  64. data/lib/resources/paths.rb +132 -0
  65. data/lib/runtime/configuration.rb +100 -0
  66. data/lib/runtime/console.rb +23 -0
  67. data/lib/runtime/logger.rb +35 -0
  68. data/lib/runtime/mime_types.rb +536 -0
  69. data/lib/runtime/mocks.rb +14 -0
  70. data/lib/runtime/monitor.rb +32 -0
  71. data/lib/runtime/request.rb +152 -0
  72. data/lib/runtime/response.rb +43 -0
  73. data/lib/runtime/response_mixin.rb +54 -0
  74. data/lib/runtime/runtime.rb +69 -0
  75. data/lib/runtime/server.rb +20 -0
  76. data/lib/runtime/session.rb +27 -0
  77. data/lib/runtime/worker.rb +86 -0
  78. data/lib/servers/base.rb +42 -0
  79. data/lib/servers/mongrel.rb +13 -0
  80. data/lib/servers/webrick.rb +13 -0
  81. data/lib/tasks/gem.rb +32 -0
  82. data/lib/tasks/generate.rb +85 -0
  83. data/lib/views/errors.rb +49 -0
  84. data/lib/views/mixin.rb +64 -0
  85. data/lib/waves.rb +63 -0
  86. data/samples/blog/Rakefile +25 -0
  87. data/samples/blog/configurations/default.rb +11 -0
  88. data/samples/blog/configurations/development.rb +29 -0
  89. data/samples/blog/configurations/production.rb +26 -0
  90. data/samples/blog/models/comment.rb +23 -0
  91. data/samples/blog/models/entry.rb +31 -0
  92. data/samples/blog/public/css/site.css +13 -0
  93. data/samples/blog/public/javascript/jquery-1.2.6.min.js +32 -0
  94. data/samples/blog/public/javascript/site.js +13 -0
  95. data/samples/blog/resources/entry.rb +39 -0
  96. data/samples/blog/resources/map.rb +9 -0
  97. data/samples/blog/schema/migrations/001_initial_schema.rb +17 -0
  98. data/samples/blog/schema/migrations/002_add_comments.rb +18 -0
  99. data/samples/blog/schema/migrations/templates/empty.rb.erb +9 -0
  100. data/samples/blog/startup.rb +8 -0
  101. data/samples/blog/templates/comment/add.mab +12 -0
  102. data/samples/blog/templates/comment/list.mab +6 -0
  103. data/samples/blog/templates/entry/edit.mab +14 -0
  104. data/samples/blog/templates/entry/list.mab +16 -0
  105. data/samples/blog/templates/entry/show.mab +18 -0
  106. data/samples/blog/templates/entry/summary.mab +9 -0
  107. data/samples/blog/templates/errors/not_found_404.mab +7 -0
  108. data/samples/blog/templates/errors/server_error_500.mab +2 -0
  109. data/samples/blog/templates/layouts/default.mab +19 -0
  110. data/samples/blog/templates/waves/status.mab +85 -0
  111. data/templates/classic/Rakefile +90 -0
  112. data/templates/classic/configurations/default.rb.erb +9 -0
  113. data/templates/classic/configurations/development.rb.erb +26 -0
  114. data/templates/classic/configurations/production.rb.erb +29 -0
  115. data/templates/classic/controllers/.gitignore +0 -0
  116. data/templates/classic/helpers/.gitignore +0 -0
  117. data/templates/classic/lib/tasks/.gitignore +0 -0
  118. data/templates/classic/models/.gitignore +0 -0
  119. data/templates/classic/public/css/.gitignore +0 -0
  120. data/templates/classic/public/flash/.gitignore +0 -0
  121. data/templates/classic/public/images/.gitignore +0 -0
  122. data/templates/classic/public/javascript/.gitignore +0 -0
  123. data/templates/classic/resources/.gitignore +0 -0
  124. data/templates/classic/resources/map.rb.erb +8 -0
  125. data/templates/classic/schema/migrations/.gitignore +0 -0
  126. data/templates/classic/startup.rb.erb +11 -0
  127. data/templates/classic/templates/errors/not_found_404.mab +7 -0
  128. data/templates/classic/templates/errors/server_error_500.mab +7 -0
  129. data/templates/classic/templates/layouts/default.mab +14 -0
  130. data/templates/classic/tmp/sessions/.gitignore +0 -0
  131. data/templates/classic/views/.gitignore +0 -0
  132. data/templates/compact/startup.rb.erb +11 -0
  133. data/test/ext/object.rb +55 -0
  134. data/test/ext/shortcuts.rb +73 -0
  135. data/test/helpers.rb +17 -0
  136. data/test/match/accept.rb +34 -0
  137. data/test/match/methods.rb +22 -0
  138. data/test/match/params.rb +33 -0
  139. data/test/match/path.rb +106 -0
  140. data/test/match/query.rb +40 -0
  141. data/test/process/request.rb +75 -0
  142. data/test/process/resource.rb +53 -0
  143. data/test/resources/path.rb +166 -0
  144. data/test/runtime/configurations.rb +19 -0
  145. data/test/runtime/request.rb +63 -0
  146. data/test/runtime/response.rb +55 -0
  147. data/test/views/views.rb +34 -0
  148. metadata +394 -0
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # WARNING: This strange preamble might look easy to clean-up, but it is needed
4
+ # to work with older versions of gems (< 1.2).
5
+
6
+ require 'rubygems'
7
+
8
+ WAVES = "#{File.dirname(__FILE__)}/.." unless defined? WAVES
9
+
10
+ waves = [
11
+ WAVES, ENV['WAVES'], './waves'
12
+ ].compact.map { |dir| File.join(dir, 'lib') }.find { |d|
13
+ File.exist? File.join( d, 'waves.rb' )
14
+ }
15
+ if waves
16
+ $: << waves
17
+ waves = File.join( waves, 'waves' )
18
+ else
19
+ waves = 'waves'
20
+ end
21
+
22
+ require waves
23
+
24
+ puts "** Waves #{Waves.version} **"
25
+
26
+ begin
27
+ require "commands/#{ARGV.first}"
28
+ rescue LoadError => e
29
+ require "commands/help"
30
+ end
@@ -0,0 +1 @@
1
+ See http://github.com/dyoder/waves/tree/master
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2007-8 Dan Yoder
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1 @@
1
+ To find out more about Waves, visit our Web site, http://rubywaves.com.
@@ -0,0 +1 @@
1
+ 0.8.2
@@ -0,0 +1,48 @@
1
+ require 'caches/synchronized'
2
+
3
+ module Waves
4
+ module Caches
5
+
6
+ class File < Simple
7
+
8
+ def initialize( args )
9
+ raise ArgumentError, ":directory is nil" if args[ :directory ].nil?
10
+ @directory = args[ :directory ] ; @keys = []
11
+ end
12
+
13
+ def store( key, value )
14
+ @keys << key
15
+ ::File.open( @directory / key, 'w') { |f| Marshal.dump( value, f ) }
16
+ end
17
+
18
+ def delete( key )
19
+ if @keys.include? key
20
+ ::File.delete( @directory / key )
21
+ @keys.delete( key )
22
+ end
23
+ end
24
+
25
+ def clear
26
+ @keys.each { |key| delete( key ) }
27
+ end
28
+
29
+ def fetch( key )
30
+ Marshal.load( ::File.read( @directory / key ) ) if @keys.include?( key )
31
+ rescue ArgumentError
32
+ nil
33
+ end
34
+
35
+ end
36
+
37
+ class SynchronizedFile < Synchronized
38
+
39
+ def initialize( args )
40
+ super( File.new( args ) )
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+ end
47
+
48
+
@@ -0,0 +1,40 @@
1
+ require 'memcached'
2
+ module Waves
3
+ module Caches
4
+ class Memcached < Simple
5
+
6
+ def initialize( args )
7
+ raise ArgumentError, ":servers is nil" if args[ :servers ].nil?
8
+ @cache = ::Memcached.new( args[ :servers ], args[ :options ] || {} )
9
+ end
10
+
11
+ def store( key,value, ttl = 0, marshal = true )
12
+ cache = @cache.clone; cache.add( key.to_s, value, ttl, marshal ); cache.destroy
13
+ end
14
+
15
+ def fetch( key )
16
+ cache = @cache.clone; cache.get( key.to_s ); cache.destroy
17
+ rescue ::Memcached::NotFound => e
18
+ nil
19
+ end
20
+
21
+ def delete( key )
22
+ cache = @cache.clone; cache.delete( key.to_s ); cache.destroy
23
+ end
24
+
25
+ def clear
26
+ cache = @cache.clone; cache.flush; cache.destroy
27
+ end
28
+
29
+ end
30
+
31
+ class SynchronizedMemcached < Synchronized
32
+
33
+ def initialize( args )
34
+ super( Memcached.new( args ) )
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,25 @@
1
+ module Waves
2
+
3
+ module Caches
4
+
5
+ #
6
+ # This class is more or less here to establish the basic interface for caching and for
7
+ # lightweight caching that doesn't require a dedicated caching process.
8
+ #
9
+
10
+ class Simple
11
+
12
+ def initialize( hash = {} ) ; @cache = hash ; end
13
+ def [](key) ; fetch(key) ; end
14
+ def []=( key, value ) ; store( key, value ) ; end
15
+ def exists?( key ) ; fetch(key) == nil ? false : true ; end
16
+ alias :exist? :exists?
17
+ def store( key, val ) ; @cache[ key ] = val ; end
18
+ def fetch( key ) ; @cache[ key ] ; end
19
+ def delete( key ) ; @cache.delete( key ) ; end
20
+ def clear ; @cache = {} ; end
21
+
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+
2
+ module Waves
3
+
4
+ module Caches
5
+
6
+ #
7
+ # This is just a proxy for the real cache, but adds Waves synchronization
8
+ #
9
+
10
+ class Synchronized
11
+
12
+ def initialize( cache ) ; @cache = cache ; end
13
+ def [](key) ; @cache.fetch(key) ; end
14
+ def []=( key, value ) ; @cache.store( key, value ) ; end
15
+ def exists?( key ) ; @cache.has_key?( key ) ; end
16
+ alias :exist? :exists?
17
+ def store( key, val ) ; synchronize { @cache.store( key, value ) }; end
18
+ def fetch( keys ) ; @cache.fetch( key ) ; end
19
+ def delete( key ) ; synchronize { @cache.delete( key ) } ; end
20
+ def clear ; synchronize { @cache.clear } ; end
21
+ def synchronize( &block ) ; Waves.synchronize( &block ) ; end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,35 @@
1
+ require 'choice'
2
+
3
+ Choice.options do
4
+ header 'Run waves in console mode.'
5
+ header ''
6
+ option :mode do
7
+ short '-c'
8
+ long '--config=CONFIG'
9
+ desc 'Configuration to use.'
10
+ desc 'Defaults to development.'
11
+ cast Symbol
12
+ end
13
+ separator ''
14
+ option :startup do
15
+ short '-s'
16
+ long '--startup'
17
+ desc 'Startup file to load.'
18
+ desc 'Defaults to "startup.rb"'
19
+ end
20
+ separator ''
21
+ end
22
+
23
+ require 'runtime/console'
24
+
25
+ begin
26
+ console = Waves::Console.load( Choice.choices )
27
+ Object.send(:define_method, :waves) { console }
28
+ require 'irb'
29
+ require 'irb/completion'
30
+ ARGV.clear
31
+ Waves.log.info "Runtime console starting ..."
32
+ IRB.start
33
+ rescue LoadError => e
34
+ puts e.message
35
+ end
@@ -0,0 +1,52 @@
1
+ require 'choice'
2
+ require 'rakegen'
3
+
4
+ waves = File.expand_path( File.dirname( __FILE__ ) / '..' / '..' )
5
+ orms = Dir[ waves / :lib / :layers / :orm / :providers / '*.rb' ].map { |path| File.basename( path, '.rb' )}
6
+ templates = Dir[ waves / :templates / '*' ].map { |path| File.basename( path ) }
7
+
8
+ Choice.options do
9
+
10
+ option :help do
11
+ long '--help'
12
+ desc 'Show this message'
13
+ end
14
+
15
+ option :orm do
16
+ short '-o'
17
+ long '--orm=ORM'
18
+ desc "Select an ORM (currently supported: #{orms * ', '} )"
19
+ valid orms
20
+ end
21
+
22
+ option :template do
23
+ short '-t'
24
+ long '--template=TEMPLATE'
25
+ desc "Select a template for your app (options: #{templates * ', '})."
26
+ valid templates
27
+ default 'classic'
28
+ end
29
+
30
+ option :name, :required => true do
31
+ short '-n'
32
+ long '--name'
33
+ desc "Select a name for the application. Use only letters, numbers, dashes, or underscores."
34
+ validate /^[\w\d\-]+$/
35
+ end
36
+
37
+ end
38
+
39
+ options = Choice.choices
40
+
41
+ puts "** Creating new Waves application ..."
42
+
43
+ # why do i have to do this?
44
+ FileUtils.mkdir( File.expand_path( options.name ) )
45
+
46
+ generator = Rakegen.new("generate") do |gen|
47
+ gen.source = waves / :templates / options.template
48
+ gen.target = File.expand_path( options.name )
49
+ gen.template_assigns = options.merge( :name => options.name.gsub('-','_').camel_case )
50
+ end.invoke
51
+
52
+ puts "** Application created!"
@@ -0,0 +1,5 @@
1
+ puts <<-HELP
2
+ Usage: waves [ generate | server | console ] [ options ]
3
+ Run a waves command with the given options. Use --help with any command to learn
4
+ more about that command. EXAMPLE: waves generate --help
5
+ HELP
@@ -0,0 +1,68 @@
1
+ require 'choice'
2
+
3
+ Choice.options do
4
+ header 'Run a waves application server.'
5
+ header ''
6
+ option :port do
7
+ short '-p'
8
+ long '--port=PORT'
9
+ desc 'Port to listen on.'
10
+ desc 'Defaults to value given in configuration.'
11
+ cast Integer
12
+ end
13
+ separator ''
14
+ option :host do
15
+ short '-h'
16
+ long '--host=HOST'
17
+ desc 'Host or IP address of the host to bind.'
18
+ desc 'Defaults to value given in configuration.'
19
+ end
20
+ separator ''
21
+ option :mode do
22
+ short '-c'
23
+ long '--config=CONFIG'
24
+ desc 'Configuration to use.'
25
+ desc 'Defaults to development.'
26
+ cast Symbol
27
+ end
28
+ separator ''
29
+ option :directory do
30
+ short '-D'
31
+ long '--dir=DIR'
32
+ desc 'Directory containing the application.'
33
+ desc 'Defaults to the current directory.'
34
+ end
35
+ separator ''
36
+ option :daemon do
37
+ short '-d'
38
+ long '--daemon'
39
+ desc 'Run as a daemon.'
40
+ end
41
+ separator ''
42
+ option :turbo do
43
+ short '-t'
44
+ long '--turbo'
45
+ desc 'For thread-safe applications, run without dispatch level mutex.'
46
+ end
47
+ separator ''
48
+ option :debugger do
49
+ short '-u'
50
+ long '--debugger'
51
+ desc 'Enable ruby-debug.'
52
+ end
53
+ separator ''
54
+ option :startup do
55
+ short '-s'
56
+ long '--startup=PATH'
57
+ desc 'Startup file to load.'
58
+ desc 'Defaults to "startup.rb"'
59
+ end
60
+ separator ''
61
+ end
62
+
63
+ require 'runtime/server'
64
+ begin
65
+ Waves::Server.run( Choice.choices )
66
+ rescue LoadError => e
67
+ puts e.message
68
+ end
@@ -0,0 +1,68 @@
1
+ module Waves
2
+
3
+ module Dispatchers
4
+
5
+ class NotFoundError < RuntimeError ; end
6
+ class Unauthorized < RuntimeError; end
7
+ class BadRequest < RuntimeError; end
8
+
9
+ # Redirect exceptions are rescued by the Waves dispatcher and used to set the
10
+ # response status and location.
11
+ class Redirect < SignalException
12
+ attr_reader :path, :status
13
+ def initialize( path, status = '302' )
14
+ @path = path
15
+ @status = status
16
+ end
17
+ def message
18
+ "location: #{@path} status: #{@status}"
19
+ end
20
+ end
21
+
22
+ #
23
+ # Waves::Dispatchers::Base provides the basic request processing structure
24
+ # for a Rack application. It creates a Waves request, determines whether
25
+ # to enclose the request processing in a mutex benchmarks it, logs it,
26
+ # and handles redirects. Derived classes need only process the request
27
+ # within the +safe+ method, which must take a Waves::Request and return
28
+ # a Waves::Response.
29
+ #
30
+
31
+ class Base
32
+
33
+ # As with any Rack application, a Waves dispatcher must provide a call method
34
+ # that takes an +env+ hash.
35
+ def call( env )
36
+ response = if Waves.synchronize? or Waves.debug?
37
+ Waves.synchronize { Waves.reload ; _call( env ) }
38
+ else
39
+ _call( env )
40
+ end
41
+ end
42
+
43
+ # Called by event driven servers like thin and ebb. Returns true if
44
+ # the server should run the request in a separate thread.
45
+ def deferred?( env ) ; Waves.config.resource.new( Waves::Request.new( env ) ).deferred? ; end
46
+
47
+ private
48
+
49
+ def _call( env )
50
+ request = Waves::Request.new( env )
51
+ response = request.response
52
+ t = Benchmark.realtime do
53
+ begin
54
+ safe( request )
55
+ rescue Dispatchers::Redirect => redirect
56
+ response.status = redirect.status
57
+ response.location = redirect.path
58
+ end
59
+ end
60
+ Waves::Logger.info "#{request.method}: #{request.url} handled in #{(t*1000).round} ms."
61
+ response.finish
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+
68
+ end
@@ -0,0 +1,25 @@
1
+ module Waves
2
+
3
+ module Dispatchers
4
+
5
+ class Default < Base
6
+
7
+ # Takes a Waves::Request and returns a Waves::Response
8
+ def safe( request )
9
+ # set a default content type -- this can be overridden by the resource
10
+ request.response.content_type = request.accept.default
11
+ resource = Waves.config.resource.new( request )
12
+ if request.response.body.empty?
13
+ request.response.write resource.process.to_s
14
+ else
15
+ resource.process
16
+ end
17
+ # okay, we've handled the request, now write the response unless it was already done
18
+ request.response.finish
19
+ end
20
+
21
+ end
22
+
23
+ end
24
+
25
+ end