waves 0.6.7
Sign up to get free protection for your applications and to get access to all the features.
- data/app/Rakefile +4 -0
- data/app/configurations/default.rb.erb +8 -0
- data/app/configurations/development.rb.erb +22 -0
- data/app/configurations/mapping.rb.erb +49 -0
- data/app/configurations/production.rb.erb +25 -0
- data/app/controllers/default.rb.erb +39 -0
- data/app/doc/EMTPY +0 -0
- data/app/helpers/default.rb.erb +13 -0
- data/app/lib/application.rb.erb +52 -0
- data/app/lib/startup.rb.erb +2 -0
- data/app/lib/tasks/cluster.rb +26 -0
- data/app/lib/tasks/schema.rb +28 -0
- data/app/models/default.rb.erb +13 -0
- data/app/schema/migration/templates/empty.rb.erb +9 -0
- data/app/templates/errors/not_found.mab +2 -0
- data/app/templates/errors/server_error.mab +2 -0
- data/app/templates/layouts/default.mab +14 -0
- data/app/views/default.rb.erb +13 -0
- data/bin/waves +32 -0
- data/bin/waves-console +8 -0
- data/bin/waves-server +45 -0
- data/lib/controllers/mixin.rb +62 -0
- data/lib/dispatchers/base.rb +41 -0
- data/lib/dispatchers/default.rb +33 -0
- data/lib/helpers/common.rb +22 -0
- data/lib/helpers/form.rb +22 -0
- data/lib/helpers/formatting.rb +22 -0
- data/lib/helpers/model.rb +15 -0
- data/lib/helpers/view.rb +14 -0
- data/lib/renderers/erubis.rb +38 -0
- data/lib/renderers/markaby.rb +31 -0
- data/lib/renderers/mixin.rb +41 -0
- data/lib/runtime/application.rb +43 -0
- data/lib/runtime/configuration.rb +47 -0
- data/lib/runtime/console.rb +21 -0
- data/lib/runtime/logger.rb +28 -0
- data/lib/runtime/mapping.rb +82 -0
- data/lib/runtime/mime_types.rb +18 -0
- data/lib/runtime/request.rb +43 -0
- data/lib/runtime/response.rb +26 -0
- data/lib/runtime/response_mixin.rb +53 -0
- data/lib/runtime/response_proxy.rb +29 -0
- data/lib/runtime/server.rb +58 -0
- data/lib/runtime/session.rb +43 -0
- data/lib/utilities/integer.rb +8 -0
- data/lib/utilities/kernel.rb +8 -0
- data/lib/utilities/module.rb +7 -0
- data/lib/utilities/object.rb +13 -0
- data/lib/utilities/string.rb +36 -0
- data/lib/utilities/symbol.rb +5 -0
- data/lib/views/mixin.rb +54 -0
- data/lib/waves.rb +50 -0
- metadata +189 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
module Waves
|
2
|
+
|
3
|
+
module Controllers
|
4
|
+
|
5
|
+
module Mixin
|
6
|
+
|
7
|
+
attr_reader :request
|
8
|
+
|
9
|
+
include Waves::ResponseMixin
|
10
|
+
|
11
|
+
def self.included( c )
|
12
|
+
def c.process( request, &block )
|
13
|
+
self.new( request ).instance_eval( &block )
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize( request )
|
18
|
+
@request = request
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
# override to convert 'foo.bar' to 'foo' => 'bar' => value
|
23
|
+
def params
|
24
|
+
@params ||= destructure(request.params)
|
25
|
+
end
|
26
|
+
|
27
|
+
def model_name
|
28
|
+
self.class.basename.snake_case
|
29
|
+
end
|
30
|
+
|
31
|
+
def model
|
32
|
+
Waves.application.models[ model_name.intern ]
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def destructure(hash)
|
38
|
+
rval = {}
|
39
|
+
hash.keys.map{ |key|key.split('.') }.each do |keys|
|
40
|
+
destructure_with_array_keys(hash,'',keys,rval)
|
41
|
+
end
|
42
|
+
rval
|
43
|
+
end
|
44
|
+
|
45
|
+
def destructure_with_array_keys(hash,prefix,keys,rval)
|
46
|
+
if keys.length == 1
|
47
|
+
val = hash[prefix+keys.first]
|
48
|
+
rval[keys.first.intern] = case val
|
49
|
+
when String then val.strip
|
50
|
+
when Hash then val
|
51
|
+
end
|
52
|
+
else
|
53
|
+
rval = ( rval[keys.first.intern] ||= {} )
|
54
|
+
destructure_with_array_keys(hash,(keys.shift<<'.'),keys,rval)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Waves
|
2
|
+
|
3
|
+
module Dispatchers
|
4
|
+
|
5
|
+
class NotFoundError < Exception ; end
|
6
|
+
|
7
|
+
class Redirect < Exception
|
8
|
+
attr_reader :path
|
9
|
+
def initialize( path )
|
10
|
+
@path = path
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Base
|
15
|
+
|
16
|
+
def call( env )
|
17
|
+
Waves::Server.synchronize do
|
18
|
+
request = Waves::Request.new( env )
|
19
|
+
response = request.response
|
20
|
+
begin
|
21
|
+
safe( request )
|
22
|
+
rescue Dispatchers::Redirect => redirect
|
23
|
+
response.status = '302'
|
24
|
+
response.location = redirect.path
|
25
|
+
rescue Dispatchers::NotFoundError => e
|
26
|
+
html = Waves.application.views[:errors].process( request ) do
|
27
|
+
not_found_404( :error => e )
|
28
|
+
end
|
29
|
+
response.status = '404'
|
30
|
+
response.content_type = 'text/html'
|
31
|
+
response.write( html )
|
32
|
+
end
|
33
|
+
response.finish
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Waves
|
2
|
+
|
3
|
+
module Dispatchers
|
4
|
+
|
5
|
+
class Default < Base
|
6
|
+
|
7
|
+
def safe( request )
|
8
|
+
|
9
|
+
response = request.response
|
10
|
+
|
11
|
+
Waves::Server.reset if Waves::Server.debug?
|
12
|
+
response.content_type = Waves::Server.config.mime_types[ request.path ] || 'text/html'
|
13
|
+
|
14
|
+
mapping = Waves::Server.mapping[ request ]
|
15
|
+
|
16
|
+
mapping[:before].each do | block, args |
|
17
|
+
ResponseProxy.new(request).instance_exec(*args,&block)
|
18
|
+
end
|
19
|
+
|
20
|
+
block, args = mapping[:action]
|
21
|
+
response.write( ResponseProxy.new(request).instance_exec(*args, &block) )
|
22
|
+
|
23
|
+
mapping[:after].each do | block, args |
|
24
|
+
ResponseProxy.new(request).instance_exec(*args,&block)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Waves
|
2
|
+
module Helpers
|
3
|
+
module Common
|
4
|
+
|
5
|
+
def layout( name, assigns = {}, &block )
|
6
|
+
assigns[ :content ] = yield
|
7
|
+
Blog::Views::Layouts.process( request ) do
|
8
|
+
send( name, assigns )
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def doctype(type)
|
13
|
+
case type
|
14
|
+
when :html4_strict
|
15
|
+
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" ' <<
|
16
|
+
'"http://www.w3.org/TR/html4/strict.dtd">'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/helpers/form.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'redcloth'
|
2
|
+
module Waves
|
3
|
+
module Helpers
|
4
|
+
module Formatting
|
5
|
+
|
6
|
+
# TODO: this won't work inside a erb template!
|
7
|
+
# but i hate to do a whole new Builder when I'm
|
8
|
+
# already inside one! test self === Builder?
|
9
|
+
def mab( content )
|
10
|
+
eval content
|
11
|
+
end
|
12
|
+
|
13
|
+
def textile( content )
|
14
|
+
( ::RedCloth::TEXTILE_TAGS << [ 96.chr, '&8216;'] ).each do |pat,ent|
|
15
|
+
content.gsub!( pat, ent.gsub('&','&#') )
|
16
|
+
end
|
17
|
+
::RedCloth.new( content ).to_html
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/helpers/view.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'erubis'
|
2
|
+
|
3
|
+
module Erubis
|
4
|
+
|
5
|
+
class Context
|
6
|
+
def <<(s) ; s ; end
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
module Waves
|
12
|
+
|
13
|
+
module Renderers
|
14
|
+
|
15
|
+
class Erubis
|
16
|
+
|
17
|
+
include Renderers::Mixin
|
18
|
+
|
19
|
+
extension :erb
|
20
|
+
|
21
|
+
def self.render( path, assigns )
|
22
|
+
eruby = ::Erubis::Eruby.new( template( path ) )
|
23
|
+
helper = helper( path )
|
24
|
+
context = ::Erubis::Context.new
|
25
|
+
context.meta_eval { include( helper ) ; }
|
26
|
+
context.instance_eval do
|
27
|
+
assigns.each do |key,val|
|
28
|
+
instance_variable_set("@#{key}",val)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
eruby.evaluate( context )
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'markaby'
|
2
|
+
|
3
|
+
::Markaby::Builder.set( :indent, 2 )
|
4
|
+
|
5
|
+
module Waves
|
6
|
+
|
7
|
+
module Renderers
|
8
|
+
|
9
|
+
class Markaby
|
10
|
+
|
11
|
+
include Renderers::Mixin
|
12
|
+
|
13
|
+
extension :mab
|
14
|
+
# capture needed here for content fragments, otherwise
|
15
|
+
# you'll just get the last tag's output ...
|
16
|
+
def self.capture( template )
|
17
|
+
"capture { #{template} }"
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.render( path, assigns )
|
21
|
+
builder = ::Markaby::Builder.new( assigns )
|
22
|
+
helper = helper( path )
|
23
|
+
builder.meta_eval { include( helper ) }
|
24
|
+
builder.instance_eval( capture( template( path ) ) ).to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Waves
|
2
|
+
|
3
|
+
module Renderers
|
4
|
+
|
5
|
+
extend Autoload
|
6
|
+
autoload :renderers
|
7
|
+
|
8
|
+
module Mixin
|
9
|
+
|
10
|
+
def self.included(target)
|
11
|
+
class << target
|
12
|
+
|
13
|
+
def extension(*args)
|
14
|
+
return @extension if args.length == 0
|
15
|
+
@extension = args.first
|
16
|
+
end
|
17
|
+
|
18
|
+
def filename(path)
|
19
|
+
:templates / "#{path}.#{self.extension}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def render(path,args=nil)
|
23
|
+
end
|
24
|
+
|
25
|
+
def template( path )
|
26
|
+
File.read( filename( path ) )
|
27
|
+
end
|
28
|
+
|
29
|
+
def helper( path )
|
30
|
+
Waves.application.helpers[
|
31
|
+
File.basename( File.dirname( path ) ).camel_case ]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Waves
|
2
|
+
|
3
|
+
class << self
|
4
|
+
|
5
|
+
attr_reader :application
|
6
|
+
|
7
|
+
# give us the root namespace for the application
|
8
|
+
def << ( app )
|
9
|
+
@application = app if Module === app
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
class Application
|
15
|
+
|
16
|
+
def initialize( mode = :development )
|
17
|
+
@mode = mode
|
18
|
+
end
|
19
|
+
|
20
|
+
def debug? ; @mode == :development ; end
|
21
|
+
|
22
|
+
# now we can get the configuration, based on the mode
|
23
|
+
# we must specify global scope to avoid picking up Waves::Configurations::*
|
24
|
+
# and / or Waves::Application::* ... because the configuration may be
|
25
|
+
# loaded via autoload ....
|
26
|
+
def config
|
27
|
+
Waves.application.configurations[ @mode ]
|
28
|
+
end
|
29
|
+
|
30
|
+
# and, similarly, the url mapping ...
|
31
|
+
def mapping
|
32
|
+
Waves.application.configurations[ :mapping ]
|
33
|
+
end
|
34
|
+
|
35
|
+
# the config then tells us whether to unload any namespaces
|
36
|
+
# after each request ...
|
37
|
+
def reset
|
38
|
+
config.reloadable.each { |mod| mod.reload }
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Waves
|
2
|
+
|
3
|
+
module Configurations
|
4
|
+
|
5
|
+
class Base
|
6
|
+
|
7
|
+
def self.[]=( name, val )
|
8
|
+
meta_def("_#{name}") { val }
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.[]( name ) ; send "_#{name}" ; end
|
12
|
+
|
13
|
+
def self.attribute( name )
|
14
|
+
meta_def(name) do |*args|
|
15
|
+
raise ArgumentError.new('Too many arguments.') if args.length > 1
|
16
|
+
args.length == 1 ? self[ name ] = args.first : self[ name ]
|
17
|
+
end
|
18
|
+
self[ name ] = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.mime_types
|
22
|
+
Waves::MimeTypes
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
class Default < Base
|
28
|
+
|
29
|
+
%w( host port ports log reloadable server database session ).
|
30
|
+
each { |name| attribute(name) }
|
31
|
+
|
32
|
+
def self.application( &block )
|
33
|
+
if block_given?
|
34
|
+
self['application'] = Rack::Builder.new( &block )
|
35
|
+
else
|
36
|
+
self['application']
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
session :duration => 30.minutes,
|
41
|
+
:path => :tmp / :sessions
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
|