dyoder-waves 0.7.3 → 0.7.6
Sign up to get free protection for your applications and to get access to all the features.
- data/app/bin/waves-console +1 -0
- data/app/bin/waves-server +1 -0
- data/app/configurations/development.rb.erb +5 -6
- data/app/configurations/mapping.rb.erb +1 -2
- data/app/configurations/production.rb.erb +2 -2
- data/app/controllers/.gitignore +0 -0
- data/app/doc/.gitignore +0 -0
- data/app/helpers/.gitignore +0 -0
- data/app/lib/application.rb.erb +4 -2
- data/app/lib/tasks/.gitignore +0 -0
- data/app/log/.gitignore +0 -0
- data/app/models/.gitignore +0 -0
- data/app/public/css/.gitignore +0 -0
- data/app/public/flash/.gitignore +0 -0
- data/app/public/images/.gitignore +0 -0
- data/app/public/javascript/.gitignore +0 -0
- data/app/schema/migrations/.gitignore +0 -0
- data/app/tmp/sessions/.gitignore +0 -0
- data/app/views/.gitignore +0 -0
- data/bin/waves +29 -46
- data/bin/waves-console +1 -1
- data/bin/waves-server +1 -1
- data/lib/commands/waves-console.rb +0 -3
- data/lib/controllers/base.rb +11 -0
- data/lib/controllers/mixin.rb +39 -32
- data/lib/dispatchers/base.rb +37 -22
- data/lib/dispatchers/default.rb +25 -11
- data/lib/foundations/default.rb +6 -8
- data/lib/foundations/simple.rb +13 -0
- data/lib/helpers/asset_helper.rb +67 -0
- data/lib/helpers/common.rb +4 -0
- data/lib/helpers/default.rb +13 -0
- data/lib/helpers/form.rb +1 -0
- data/lib/helpers/number_helper.rb +25 -0
- data/lib/helpers/tag_helper.rb +58 -0
- data/lib/helpers/url_helper.rb +77 -0
- data/lib/layers/default_errors.rb +7 -5
- data/lib/layers/mvc.rb +54 -0
- data/lib/layers/orm/active_record.rb +93 -0
- data/lib/layers/orm/active_record/migrations/empty.rb.erb +9 -0
- data/lib/layers/orm/active_record/tasks/generate.rb +28 -0
- data/lib/layers/orm/active_record/tasks/schema.rb +22 -0
- data/lib/layers/orm/data_mapper.rb +38 -0
- data/lib/layers/orm/filebase.rb +22 -0
- data/lib/layers/orm/migration.rb +79 -0
- data/lib/layers/orm/sequel.rb +86 -0
- data/lib/layers/orm/sequel/migrations/empty.rb.erb +9 -0
- data/lib/layers/orm/sequel/tasks/generate.rb +28 -0
- data/lib/layers/orm/sequel/tasks/schema.rb +16 -0
- data/lib/layers/simple.rb +35 -0
- data/lib/layers/simple_errors.rb +11 -5
- data/lib/mapping/mapping.rb +61 -24
- data/lib/mapping/pretty_urls.rb +5 -3
- data/lib/renderers/erubis.rb +3 -1
- data/lib/renderers/mixin.rb +1 -4
- data/lib/runtime/application.rb +12 -8
- data/lib/runtime/blackboard.rb +57 -0
- data/lib/runtime/configuration.rb +60 -55
- data/lib/runtime/logger.rb +8 -1
- data/lib/runtime/request.rb +5 -4
- data/lib/runtime/response.rb +3 -3
- data/lib/runtime/response_mixin.rb +3 -0
- data/lib/runtime/response_proxy.rb +4 -1
- data/lib/runtime/server.rb +18 -5
- data/lib/runtime/session.rb +20 -10
- data/lib/tasks/cluster.rb +2 -1
- data/lib/tasks/generate.rb +76 -11
- data/lib/utilities/hash.rb +31 -0
- data/lib/utilities/inflect.rb +86 -170
- data/lib/utilities/inflect/english.rb +84 -0
- data/lib/utilities/integer.rb +23 -16
- data/lib/utilities/module.rb +19 -15
- data/lib/utilities/object.rb +22 -14
- data/lib/utilities/proc.rb +13 -6
- data/lib/utilities/string.rb +58 -44
- data/lib/utilities/symbol.rb +4 -1
- data/lib/views/base.rb +9 -0
- data/lib/views/mixin.rb +3 -1
- data/lib/waves.rb +15 -13
- metadata +50 -25
- data/lib/utilities/kernel.rb +0 -34
- data/lib/verify/mapping.rb +0 -29
- data/lib/verify/request.rb +0 -40
data/app/bin/waves-console
CHANGED
data/app/bin/waves-server
CHANGED
@@ -1,13 +1,12 @@
|
|
1
|
-
module <%= name %>
|
1
|
+
module <%= @name %>
|
2
2
|
|
3
3
|
module Configurations
|
4
4
|
|
5
|
-
class Development
|
5
|
+
class Development < Default
|
6
6
|
|
7
|
-
database :
|
8
|
-
:user => 'root', :password => ''
|
7
|
+
database :adapter => 'sqlite', :database => '<%= @name.downcase %>'
|
9
8
|
|
10
|
-
reloadable [ <%= name %> ]
|
9
|
+
reloadable [ <%= @name %> ]
|
11
10
|
|
12
11
|
log :level => :debug
|
13
12
|
|
@@ -15,7 +14,7 @@ module <%= name %>
|
|
15
14
|
|
16
15
|
port 3000
|
17
16
|
|
18
|
-
|
17
|
+
handler ::Rack::Handler::Mongrel, :Host => host, :Port => port
|
19
18
|
# handler ::Rack::Handler::WEBrick, :BindAddress => host, :Port => port
|
20
19
|
# handler ::Rack::Handler::Thin, :Host => host, :Port => port
|
21
20
|
|
@@ -1,10 +1,10 @@
|
|
1
|
-
module <%= name %>
|
1
|
+
module <%= @name %>
|
2
2
|
|
3
3
|
module Configurations
|
4
4
|
|
5
5
|
class Production < Default
|
6
6
|
|
7
|
-
database :host => 'localhost', :adapter => 'mysql', :database => '<%= name.downcase %>',
|
7
|
+
database :host => 'localhost', :adapter => 'mysql', :database => '<%= @name.downcase %>',
|
8
8
|
:user => 'root', :password => ''
|
9
9
|
|
10
10
|
reloadable []
|
File without changes
|
data/app/doc/.gitignore
ADDED
File without changes
|
File without changes
|
data/app/lib/application.rb.erb
CHANGED
File without changes
|
data/app/log/.gitignore
ADDED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/bin/waves
CHANGED
@@ -1,10 +1,26 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'choice'
|
4
|
+
require 'rakegen'
|
5
|
+
|
6
|
+
# if we're in the waves source, prepend it to the load path
|
7
|
+
waves_lib = File.expand_path( "#{File.dirname(__FILE__)}/../../waves/lib" )
|
8
|
+
$:.unshift waves_lib if File.exist?(waves_lib)
|
9
|
+
require 'waves'
|
10
|
+
|
11
|
+
begin
|
12
|
+
require 'utilities/string'
|
13
|
+
rescue LoadError
|
14
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'utilities', 'string')
|
15
|
+
end
|
2
16
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
17
|
+
Choice.options do
|
18
|
+
banner 'Usage: waves path/to/app [-h]'
|
19
|
+
option :help do
|
20
|
+
long '--help'
|
21
|
+
desc 'Show this message'
|
22
|
+
end
|
23
|
+
|
8
24
|
end
|
9
25
|
|
10
26
|
app_path = ARGV[0]
|
@@ -16,51 +32,18 @@ if app_name =~ /[^\w\d_]/
|
|
16
32
|
TEXT
|
17
33
|
end
|
18
34
|
|
35
|
+
template = "#{WAVES}/app"
|
19
36
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
rescue LoadError
|
26
|
-
require File.join(File.dirname(__FILE__), '..', 'lib', 'utilities', 'string')
|
37
|
+
generator = Rakegen.new("waves:app") do |gen|
|
38
|
+
gen.source = template
|
39
|
+
gen.target = app_path
|
40
|
+
gen.template_assigns = {:name => app_name.camel_case}
|
41
|
+
gen.executables = %w{ bin/waves-console bin/waves-server}
|
27
42
|
end
|
28
43
|
|
29
|
-
require 'fileutils'
|
30
|
-
include FileUtils
|
31
|
-
|
32
|
-
# are we calling this script from within the waves framework source?
|
33
|
-
script_path = File.expand_path(__FILE__)
|
34
|
-
WAVES_SRC = File.dirname(File.dirname(script_path))
|
35
|
-
IN_WAVES_SRC = Dir.pwd.match(WAVES_SRC) ? true : false
|
36
|
-
|
37
|
-
|
38
44
|
puts "** Creating new Waves application ..."
|
39
|
-
template = begin
|
40
|
-
File.join File.dirname(File.readlink(__FILE__)), '..', 'app'
|
41
|
-
rescue Exception
|
42
|
-
File.join( File.dirname(__FILE__),'..','app')
|
43
|
-
end
|
44
|
-
mkdir(app_path)
|
45
|
-
cp_r Dir["#{template}/*"], app_path
|
46
45
|
|
47
|
-
|
48
|
-
Dir["#{app_path}/**/EMPTY"].each { |path| rm path }
|
49
|
-
# Dir["#{app_path}/**/EMPTY"].each { |path| system "rm #{path}" }
|
50
|
-
|
51
|
-
# next, process all template files ...
|
52
|
-
Dir["#{app_path}/**/*.erb"].each do |path|
|
53
|
-
unless path =~ %r{^#{app_path}/(schema/migrations/templates|templates)}
|
54
|
-
name = app_name.camel_case
|
55
|
-
File.write( path.gsub(/\.erb$/,''),
|
56
|
-
Erubis::Eruby.new( File.read( path ) ).result( binding ) )
|
57
|
-
rm path
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
unless RUBY_PLATFORM =~ /mswin32/
|
62
|
-
# make the scripts executable
|
63
|
-
system "chmod ug+x #{app_path}/bin/waves-*"
|
64
|
-
end
|
46
|
+
Rake::Task["waves:app"].invoke
|
65
47
|
|
66
48
|
puts "** Application created!"
|
49
|
+
|
data/bin/waves-console
CHANGED
data/bin/waves-server
CHANGED
data/lib/controllers/mixin.rb
CHANGED
@@ -7,7 +7,7 @@ module Waves
|
|
7
7
|
# a request. For example, a controller updates a model instance using
|
8
8
|
# parameters from the request.
|
9
9
|
#
|
10
|
-
#
|
10
|
+
# Public controller methods simply return data (a resource), if necessary, that
|
11
11
|
# can be then used by views to determine how to render that data.
|
12
12
|
# Controllers do not determine which view will be invoked. They are
|
13
13
|
# independent of the view; one controller method might be suitable for
|
@@ -76,13 +76,12 @@ module Waves
|
|
76
76
|
module Controllers
|
77
77
|
|
78
78
|
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
79
|
+
# Waves::Controllers::Mixin adapts a controller class for use in mappings and provides utility methods.
|
80
|
+
# It is included in controllers autocreated by the Default foundation, so you do not need to include
|
81
|
+
# it in subclasses of the same.
|
82
82
|
#
|
83
|
-
#
|
84
|
-
#
|
85
|
-
# to be written generically (i.e., without reference to a specific model); and provide
|
83
|
+
# The utility methods include simple reflection to allow controller methods
|
84
|
+
# to be written generically (i.e., without reference to a specific model) and
|
86
85
|
# parameter destructuring for the request parameters.
|
87
86
|
#
|
88
87
|
|
@@ -92,18 +91,20 @@ module Waves
|
|
92
91
|
|
93
92
|
include Waves::ResponseMixin
|
94
93
|
|
95
|
-
# When
|
96
|
-
# which accepts a request object and a block. The
|
97
|
-
# the
|
98
|
-
# controller to be used within a mapping
|
94
|
+
# When this mixin is included it adds a class method named +process+,
|
95
|
+
# which accepts a request object and a block. The +process+ method initializes the
|
96
|
+
# controller with the request, then evaluates the block using +instance_eval+. This allows the
|
97
|
+
# controller to be used from within a mapping lambda (i.e. a ResponseProxy).
|
99
98
|
|
100
|
-
def self.included(
|
101
|
-
def
|
99
|
+
def self.included( mod )
|
100
|
+
def mod.process( request, &block )
|
102
101
|
self.new( request ).instance_eval( &block )
|
103
102
|
end
|
104
103
|
end
|
105
104
|
|
106
|
-
def initialize( request )
|
105
|
+
def initialize( request )
|
106
|
+
@request = request
|
107
|
+
end
|
107
108
|
|
108
109
|
# The params variable is taken from the request object and "destructured", so that
|
109
110
|
# a parameter named 'blog.title' becomes:
|
@@ -111,16 +112,16 @@ module Waves
|
|
111
112
|
# params['blog']['title']
|
112
113
|
#
|
113
114
|
# If you want to access the original parameters object, you can still do so using
|
114
|
-
# +request.
|
115
|
+
# +request.params+ instead of simply +params+.
|
115
116
|
def params; @params ||= destructure(request.params); end
|
116
117
|
|
117
|
-
#
|
118
|
-
#
|
119
|
-
#
|
118
|
+
# Returns the name of the model corresponding to this controller by taking the basename
|
119
|
+
# of the module and converting it to snake case. If the model plurality is different than
|
120
|
+
# the controller, this will not, in fact, be the model name.
|
120
121
|
def model_name; self.class.basename.snake_case; end
|
121
122
|
|
122
|
-
#
|
123
|
-
#
|
123
|
+
# Returns the model corresponding to this controller by naively assuming that
|
124
|
+
# +model_name+ must be correct. This allows you to write generic controller methods such as:
|
124
125
|
#
|
125
126
|
# model.find( name )
|
126
127
|
#
|
@@ -130,24 +131,30 @@ module Waves
|
|
130
131
|
|
131
132
|
private
|
132
133
|
|
133
|
-
def destructure(hash)
|
134
|
-
|
135
|
-
hash.keys.map{ |key|key.split('.') }.each do |keys|
|
136
|
-
destructure_with_array_keys(hash,'',keys,
|
134
|
+
def destructure( hash )
|
135
|
+
destructured = {}
|
136
|
+
hash.keys.map { |key| key.split('.') }.each do |keys|
|
137
|
+
destructure_with_array_keys(hash, '', keys, destructured)
|
137
138
|
end
|
138
|
-
|
139
|
+
destructured
|
139
140
|
end
|
140
141
|
|
141
|
-
def destructure_with_array_keys(hash,prefix,keys,
|
142
|
+
def destructure_with_array_keys( hash, prefix, keys, destructured )
|
142
143
|
if keys.length == 1
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
when
|
144
|
+
key = "#{prefix}#{keys.first}"
|
145
|
+
val = hash[key]
|
146
|
+
destructured[keys.first.intern] = case val
|
147
|
+
when String
|
148
|
+
val.strip
|
149
|
+
when Hash
|
150
|
+
val
|
151
|
+
when nil
|
152
|
+
raise key.inspect
|
147
153
|
end
|
148
154
|
else
|
149
|
-
|
150
|
-
|
155
|
+
destructured = ( destructured[keys.first.intern] ||= {} )
|
156
|
+
new_prefix = "#{prefix}#{keys.shift}."
|
157
|
+
destructure_with_array_keys( hash, new_prefix, keys, destructured )
|
151
158
|
end
|
152
159
|
end
|
153
160
|
|
data/lib/dispatchers/base.rb
CHANGED
@@ -2,8 +2,14 @@ module Waves
|
|
2
2
|
|
3
3
|
module Dispatchers
|
4
4
|
|
5
|
+
# A NotFoundError means what you think it means. The dispatchers included with Waves do not
|
6
|
+
# natively intercept this exception. Instead an exception handler must be registered in the application
|
7
|
+
# mappings. The Simple foundation registers a minimal handler, while the Default foundation registers
|
8
|
+
# a slightly fleshier one.
|
5
9
|
class NotFoundError < Exception ; end
|
6
10
|
|
11
|
+
# Redirect exceptions are rescued by the Waves dispatcher and used to set the
|
12
|
+
# response status and location.
|
7
13
|
class Redirect < Exception
|
8
14
|
attr_reader :path, :status
|
9
15
|
def initialize( path, status = '302' )
|
@@ -12,38 +18,47 @@ module Waves
|
|
12
18
|
end
|
13
19
|
end
|
14
20
|
|
15
|
-
#
|
16
|
-
# from it.
|
17
|
-
#
|
18
|
-
# exceptions and redirects. Derived classes need only
|
19
|
-
#
|
21
|
+
# Waves::Dispatchers::Base provides the basic request processing structure.
|
22
|
+
# All other Waves dispatchers should inherit from it. It creates a Waves request,
|
23
|
+
# determines whether to enclose the request processing in a mutex, benchmarks it,
|
24
|
+
# logs it, and handles common exceptions and redirects. Derived classes need only
|
25
|
+
# process the request within the +safe+ method, which must take a Waves::Request and return a Waves::Response.
|
20
26
|
|
21
27
|
class Base
|
22
28
|
|
23
|
-
#
|
24
|
-
#
|
29
|
+
# As with any Rack application, a Waves dispatcher must provide a call method
|
30
|
+
# that takes an +env+ parameter.
|
25
31
|
def call( env )
|
26
|
-
Waves
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
begin
|
31
|
-
safe( request )
|
32
|
-
rescue Dispatchers::Redirect => redirect
|
33
|
-
response.status = redirect.status
|
34
|
-
response.location = redirect.path
|
35
|
-
end
|
36
|
-
end
|
37
|
-
Waves::Logger.info "#{request.method}: #{request.url} handled in #{(t*1000).round} ms."
|
38
|
-
response.finish
|
32
|
+
if Waves.config.synchronize?
|
33
|
+
Waves::Application.instance.synchronize { _call( env ) }
|
34
|
+
else
|
35
|
+
_call( env )
|
39
36
|
end
|
40
37
|
end
|
41
38
|
|
42
|
-
# Called by event driven servers like thin and ebb.
|
43
|
-
# the server should run the request in a separate thread
|
39
|
+
# Called by event driven servers like thin and ebb. Returns true if
|
40
|
+
# the server should run the request in a separate thread, as determined by
|
41
|
+
# Configurations::Mapping#threaded?
|
44
42
|
def deferred?( env )
|
45
43
|
Waves::Application.instance.mapping.threaded?( env )
|
46
44
|
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def _call( env )
|
49
|
+
request = Waves::Request.new( env )
|
50
|
+
response = request.response
|
51
|
+
t = Benchmark.realtime do
|
52
|
+
begin
|
53
|
+
safe( request )
|
54
|
+
rescue Dispatchers::Redirect => redirect
|
55
|
+
response.status = redirect.status
|
56
|
+
response.location = redirect.path
|
57
|
+
end
|
58
|
+
end
|
59
|
+
Waves::Logger.info "#{request.method}: #{request.url} handled in #{(t*1000).round} ms."
|
60
|
+
response.finish
|
61
|
+
end
|
47
62
|
|
48
63
|
end
|
49
64
|
|
data/lib/dispatchers/default.rb
CHANGED
@@ -3,13 +3,14 @@ module Waves
|
|
3
3
|
module Dispatchers
|
4
4
|
|
5
5
|
#
|
6
|
-
#
|
7
|
-
# what
|
8
|
-
#
|
6
|
+
# Waves::Dispatchers::Default matches requests against an application's mappings to
|
7
|
+
# determine what main action to take, as well as what before, after, always, and exception-handling
|
8
|
+
# blocks must run.
|
9
9
|
#
|
10
10
|
# The default dispatcher also attempts to set the content type based on the
|
11
|
-
#
|
12
|
-
#
|
11
|
+
# file extension used in the request URL. It does this using the class defined in
|
12
|
+
# the current configuration's +mime_types+ attribute, which defaults to Mongrel's
|
13
|
+
# MIME type handler.
|
13
14
|
#
|
14
15
|
# You can write your own dispatcher and use it in your application's configuration
|
15
16
|
# file. By default, they use the default dispatcher, like this:
|
@@ -27,13 +28,14 @@ module Waves
|
|
27
28
|
# Takes a Waves::Request and returns a Waves::Reponse
|
28
29
|
def safe( request )
|
29
30
|
|
30
|
-
|
31
|
-
|
31
|
+
response = request.response
|
32
|
+
|
33
|
+
Waves::Application.instance.reload if Waves::Application.instance.debug?
|
34
|
+
response.content_type = Waves::Application.instance.config.mime_types[ request.path ] || 'text/html'
|
32
35
|
|
33
|
-
|
34
|
-
response.content_type = Waves::Application.instance.config.mime_types[ request.path ] || 'text/html'
|
36
|
+
mapping = Waves::Application.instance.mapping[ request ]
|
35
37
|
|
36
|
-
|
38
|
+
begin
|
37
39
|
|
38
40
|
mapping[:before].each do | block, args |
|
39
41
|
ResponseProxy.new(request).instance_exec(*args,&block)
|
@@ -43,11 +45,13 @@ module Waves
|
|
43
45
|
|
44
46
|
block, args = mapping[:action]
|
45
47
|
response.write( ResponseProxy.new(request).instance_exec(*args, &block) )
|
46
|
-
|
48
|
+
|
47
49
|
mapping[:after].each do | block, args |
|
48
50
|
ResponseProxy.new(request).instance_exec(*args,&block)
|
49
51
|
end
|
52
|
+
|
50
53
|
rescue Exception => e
|
54
|
+
|
51
55
|
handler = mapping[:handlers].detect do | exception, block, args |
|
52
56
|
e.is_a? exception
|
53
57
|
end
|
@@ -56,6 +60,16 @@ module Waves
|
|
56
60
|
else
|
57
61
|
raise e
|
58
62
|
end
|
63
|
+
|
64
|
+
ensure
|
65
|
+
mapping[:always].each do | block, args |
|
66
|
+
begin
|
67
|
+
ResponseProxy.new(request).instance_exec(*args,&block)
|
68
|
+
rescue Exception => e
|
69
|
+
Waves::Logger.info e.to_s
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
59
73
|
end
|
60
74
|
|
61
75
|
end
|